三个最常见基础模块:FIFO、仲裁器、握手,几乎每个 SoC 都有
更新时间:2026-09-05。本文是「集成电路大类 · 芯片设计」**入门层(beginner)**第三十二篇新正文。微架构入门 提到数据通路里反复出现缓冲和控制。有三个小模块几乎在每颗 SoC、每条总线、每个数据流里都会出现:FIFO、仲裁器、握手逻辑。它们是数字设计师的「三板斧」,也是面试和实战的高频基本功。
本文要回答的问题
- FIFO 是什么,空/满标志怎么来,为什么能跨时钟域?
- 多个模块抢同一资源时谁先用?仲裁器怎么裁决?
- valid/ready 握手为什么能天然防丢数据、实现反压?
- 这三者在真实数据通路里怎么配合?
一、FIFO:先进先出的缓冲队列
FIFO(First-In First-Out)就是一个排队缓冲区:数据从一头写进去、从另一头按顺序读出来。内部是一组存储单元(寄存器或 SRAM)加写指针和读指针:写指针指向下一个空位,读指针指向下一个要读的数据,两指针的关系给出 **空(empty)和满(full)**标志。
- 空了不能读(没有数据)、满了不能写(会覆盖/丢失);
- 作用一:缓冲突发。上游一下子来一串数据、下游来不及处理,先在 FIFO 里排队,削峰填谷;
- 作用二:解耦速率。两边可以不同吞吐,甚至——
- 作用三:跨时钟域(CDC)。异步 FIFO 用格雷码(Gray code)传递指针,让数据安全地从一个时钟域传到另一个时钟域(见 时钟树与复位网络)。
二、仲裁器(arbiter):多个请求谁先用
当多个主设备(CPU、DMA、多个 DMA 通道)同时想访问同一个共享资源(总线、一块存储器、一个端口)时,必须有个「裁判」决定这一周期让谁用,这就是仲裁器(见 片上总线 AMBA 的互连)。常见策略:
| 策略 | 规则 | 特点 |
|---|---|---|
| 固定优先级 | 高优先级请求永远先被服务 | 简单,但低优先级可能「饿死」 |
| 轮询 round-robin | 大家轮流、机会均等 | 公平,最常用 |
| 加权/公平仲裁 | 按带宽配额分配 | 复杂,用于 QoS |
仲裁器输出「grant(授权)」信号,被授权的主设备这一周期获得总线/资源使用权。
三、握手(valid/ready):一句话防丢数据
模块间传数据最通用的规则是 valid/ready 握手(AXI-Stream、无数流式接口都用它):
- 发送方把数据放好后置 valid=1(「数据有效」);
- 接收方准备好接收时置 ready=1(「我能收」);
- 只有当 valid 和 ready 同时为 1 的那个周期,传输才算完成,数据才被真正采走。
这套规则的妙处是天然反压(back-pressure):接收方来不及处理时把 ready 拉低,发送方就保持 valid 和数据不动、等它,数据不会丢——不需要额外的「停」命令。这比「发出去就不管」的简单接口健壮得多,是流水线和数据流的标准握手机制(见 微架构流水线)。
四、三者怎么配合
一条典型数据通路(如网络包从接口进、经处理、到内存):数据用 valid/ready 握手逐站传递;每站之间插一个 FIFO 缓冲突发、必要时跨时钟域;多个数据源汇聚到一个出口时,用仲裁器决定谁先过。握手管「一次传不传得成」、FIFO 管「存得下存不下」、仲裁器管「谁先用」——三者一组合,就构成了 SoC 里绝大多数数据搬运和互连的骨架。
五、往里看一层:指针、空满到底怎么判
空和满时读写指针其实「相等」,光看指针相等分不清是空还是满,这是 FIFO 设计第一个真正的坑。常用两种判据:
- 额外位法(最常用):指针比寻址位宽多 1 bit。n 个地址用 log₂n 位寻址,再加 1 个「折返位」。写指针绕一圈折返位翻转、读指针还没绕时,两者低位相同而折返位不同 → 判满;两者连折返位都相同 → 判空。即 wptr==rptr 为空,低位相同但最高折返位相反为满。
- 计数器法:维护一个在写时加一、读时减一的
count,count==0空、count==DEPTH满。直观但 count 要同时处理读写、时钟频率高时时序紧张,所以深 FIFO/高速 FIFO 更爱用指针法。
// 宽度多 1 bit 的指针(DEPTH 为 2 的幂)
localparam AW = 4; // 16 深
reg [AW:0] wptr, rptr; // 最高位是折返位
wire full = (wptr[AW]!=rptr[AW]) &&
(wptr[AW-1:0]==rptr[AW-1:0]);
wire empty = (wptr==rptr);
always @(posedge wclk or negedge wrst_n) // 写指针只在写时钟域动
if (!wrst_n) wptr <= '0;
else if (wen && !full) wptr <= wptr + 1'b1;存储体浅时用一排寄存器(regfile),深时用 SRAM macro;容量不是 2 的幂或要 almost full/almost empty 等水位线时,比较逻辑相应调整。同步 FIFO读写同一时钟,指针直接比即可;异步 FIFO两指针分属不同时钟域,必须把指针转成格雷码(相邻只变 1 bit)再打两拍同步过去比较,否则指针多位同时跳变会被采成错误值——这正是 异步 FIFO 与 CDC 的核心。深度该开多大不是拍脑袋,由突发长度、读写速率差和允许的丢包/反压决定,进阶有专门的深度计算。
六、仲裁器与握手再往里看一点
固定优先级仲裁器用一条级联的优先级链实现:从最高优先级到最低,每级「若我请求且没有更高者被授权,则 grant 我,并屏蔽所有更低者」,本质是一长串 MUX/与门(和 74x148 优先级编码器同构)。简单,但高优先级持续请求时低优先级永远拿不到 grant——饿死(starvation)。
轮询 round-robin保证公平:记住「上一个被服务的是谁」,下次从它的下一个开始找请求。实现上常用「温度计码掩码 + 找第一个 1(leading-one detector,可用优先编码器)」:把当前优先级以下的请求屏蔽后找最高,没有再回头从头找。被授权者随即更新优先级到自己的下一位,于是各主设备机会轮转。要防「同一拍请求又被授权」组合环,授权和优先级更新通常隔一拍。加权/QoS 仲裁则在轮询基础上按配额发令牌。
valid/ready 还有几个工程细节值得现在就立好规矩:①valid 一旦拉高、数据一旦放上,在握手完成(ready&valid)前不许撤回或改变,否则接收方可能采到半路数据;②ready 可以依赖也可以不依赖 valid,但不要让 valid 依赖当拍 ready形成组合环,稳妥做法是 valid 用寄存器拍出;③「同拍既能收又能发」的流水线站,ready 常写成 ready = !valid_q || out_ready(站内无货、或下游能接走时我才能收),即经典 skid/fire 规则。这套规则在 valid/ready 握手 里有逐波形的展开。
七、这一篇在知识体系里的位置
- 想看这些模块背后的微结构(流水线/状态机/缓冲)→ 微架构入门;
- 想看 valid/ready 和仲裁在总线上的位置 → 片上总线 AMBA 入门、片上总线实战;
- 想看 DMA 怎么靠仲裁和握手搬数据 → 中断与 DMA;
- 想把它们写成 Verilog 并仿真 → 从代码到门电路、Verilog 语法速览、仿真是什么。
总结
一句话总结:FIFO、仲裁器、握手是数字设计复用率最高的三块积木——FIFO 是用存储单元加读写指针构成的先进先出队列,靠指针关系产生空/满标志(空不读、满不写),用来缓冲突发数据、削峰填谷、解耦上下游速率,异步 FIFO 更用格雷码传指针实现跨时钟域安全传递;仲裁器在多个主设备(CPU/DMA)同时请求总线或内存等共享资源时充当裁判,按固定优先级(简单但可能饿死低优先级)、轮询 round-robin(公平最常用)或加权配额策略输出 grant 决定谁先用;valid/ready 握手则规定发送方置 valid 表示数据有效、接收方置 ready 表示能收、仅二者同时为高的周期传输才成立,从而天然实现反压——接收方来不及就拉低 ready,发送方保持数据等待而不丢数;真实数据通路里三者协同:valid/ready 管「一次传不传得成」、FIFO 管「突发存不存得下」、仲裁器管「多个来源谁先用」,共同构成 SoC 数据搬运与互连的骨架。
专题进阶:异步FIFO设计全景:从格雷码到综合时序的完整路径——支柱页 + 综合实测 + 坑点排查 + 面试问答,配可一键仿真的独立工程包。