架构设计:芯片的“骨架”——模块划分、总线架构选择、数据流与控制流设计

做芯片设计这么多年,我越来越觉得架构设计就像盖房子时的结构图纸。图纸画歪了,后面装修再漂亮也白搭。今天咱们就来聊聊这个“骨架”该怎么搭。

模块划分:别把功能揉成一团

模块划分这事儿,说白了就是“分而治之”。我见过不少新手,恨不得把所有逻辑塞进一个模块里。结果呢?仿真跑不动,调试想撞墙。

我个人习惯遵循几个原则:

  • 功能内聚:一个模块只干一件事。比如DMA控制器,就管数据搬运,别掺和中断管理。
  • 接口清晰:模块之间的握手信号要简单。我建议用valid-ready这种标准握手机制,别自己发明协议。
  • 规模可控:单个模块的代码量控制在2000行以内。超过这个数,综合工具会抱怨,人也容易看花眼。

重要提醒:模块划分时,一定要考虑复用性。我在项目中吃过亏——为了赶进度,把特定功能写死在模块里。结果下一款芯片想复用,改得比重新写还痛苦。

总线架构:AHB、APB、AXI怎么选?

总线选型这事儿,其实没那么玄乎。你想想看,不同总线就像不同规格的马路:

总线类型 典型场景 带宽需求 复杂度
APB 寄存器配置、低功耗外设 低(< 100MHz) 极低
AHB 中等带宽数据通路 中(100-500MHz) 中等
AXI 高性能数据搬运、DDR控制器 高(> 500MHz) 较高

我记得有个项目,团队非要给一个简单的UART配AXI总线。结果呢?面积大了30%,功耗也上去了。其实APB完全够用,何必杀鸡用牛刀?

我的经验:系统里至少保留一个APB总线域,专门挂配置寄存器。这样调试时可以直接通过JTAG写寄存器,不用走复杂的数据通路。

数据流与控制流:两条腿走路

架构设计里最容易犯的错,就是把数据流和控制流混在一起。我刚开始做设计时也犯过这毛病——一个状态机既管数据搬运,又管协议解析。结果状态图画得跟蜘蛛网似的。

正确的做法是:

  • 数据流:用FIFO或乒乓缓冲处理,保证吞吐率。控制信号尽量少介入数据通路。
  • 控制流:用状态机或微序列器,只负责发命令、收状态。别碰数据本身。

举个例子,一个简单的DMA传输:

// 控制流:状态机
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) state <= IDLE;
  else case (state)
    IDLE: if (start) state <= READ_ADDR;
    READ_ADDR: state <= READ_DATA;
    READ_DATA: state <= WRITE_DATA;
    WRITE_DATA: if (done) state <= IDLE;
  endcase
end

// 数据流:FIFO直通
assign fifo_wr_en = (state == READ_DATA) & src_valid;
assign fifo_rd_en = (state == WRITE_DATA) & dst_ready;

看到了吗?控制流只管“什么时候做”,数据流只管“怎么做”。这样分开后,调试时定位问题快得多。

避坑指南:我曾经在一个项目里,把数据通路上的握手信号直接连到状态机的组合逻辑上。结果时序收敛不了,最后不得不重写。记住:数据通路和控制通路之间,一定要加寄存器打拍隔离。

架构图:一图胜千言

下面这张图是我做架构设计时常用的模板。它把模块、总线、数据流、控制流都画清楚了。

芯片架构示意图 CPU Core AXI 总线 (高性能数据通路) AHB 总线 (中等带宽外设) APB 总线 (低功耗配置接口) DMA UART SPI GPIO Timer 数据流 控制流 数据流方向 控制流方向 AXI总线 AHB总线 APB总线

这张图里,CPU通过AXI总线访问DMA和DDR控制器(数据流),通过APB总线配置UART、SPI等外设的寄存器(控制流)。两条路径互不干扰,调试时一目了然。

总结一下

架构设计这事儿,说白了就是三个字:分、选、隔

  • :模块划分要功能内聚、接口清晰。
  • :总线选型要匹配带宽,别大材小用。
  • :数据流和控制流要物理隔离,别混在一起。

嗯,做到这三点,你的芯片架构至少不会跑偏。剩下的细节,咱们后面章节慢慢聊。