第二讲:FIFO核心信号解析
各位同学,上一讲我们聊了FIFO的基本概念。今天咱们来点实在的——把FIFO的每个信号掰开揉碎,看看它们到底在干什么。
说实话,我刚开始学FIFO时,看着满屏的wclk、rclk、full、empty,头都大了。后来在项目里被坑过几次,才真正理解这些信号的重要性。嗯,今天就把这些经验分享给你们。
2.1 时钟域信号:wclk与rclk
FIFO最核心的特点就是跨时钟域。说白了,就是写和读各用各的时钟。
- wclk(写时钟):数据写入时的时钟。所有写操作都同步在这个时钟上。
- rclk(读时钟):数据读出时的时钟。所有读操作都同步在这个时钟上。
这两个时钟可以是同频的,也可以是不同频的。我在项目中遇到过wclk=100MHz、rclk=50MHz的情况,也遇到过反过来rclk更快的情况。你想想看,如果读比写快,FIFO很容易就空了;如果写比读快,FIFO很容易就满了。
关键点:wclk和rclk是异步的,它们之间没有任何相位关系。这就是为什么FIFO内部需要做同步处理。
2.2 控制信号:wen与ren
这两个信号决定了什么时候写、什么时候读。
- wen(写使能):高电平时,在wclk的上升沿将wdata写入FIFO。
- ren(读使能):高电平时,在rclk的上升沿从FIFO读出数据到rdata。
我个人习惯把wen和ren想象成两个开关。wen打开,数据才能进去;ren打开,数据才能出来。但要注意——
我曾经踩过的坑:wen和ren不能乱拉。FIFO满的时候拉wen,数据会丢失;FIFO空的时候拉ren,读出来的是无效数据。所以一定要配合full和empty信号使用。
2.3 数据信号:wdata与rdata
这两个信号是FIFO的"货物"。
- wdata(写数据):要存入FIFO的数据,在wclk上升沿且wen有效时被写入。
- rdata(读数据):从FIFO读出的数据,在rclk上升沿且ren有效时更新。
这里有个细节:rdata在ren有效后的下一个时钟周期才有效。为什么?因为读操作需要时间。我记得第一次调试时,以为ren一拉高rdata就变了,结果抓了半天的波形才发现问题。
小技巧:看波形时,重点关注ren和rdata的时序关系。通常ren拉高后,rdata会在下一个时钟沿更新。如果rdata提前变了,那可能是组合逻辑输出,要小心。
2.4 状态信号:full与empty
这两个信号是FIFO的"晴雨表"。
- full(满标志):FIFO已满,不能再写。此时wen必须为低。
- empty(空标志):FIFO已空,不能再读。此时ren必须为低。
full和empty是怎么产生的?简单说,就是比较写指针和读指针的位置。但因为是异步时钟域,比较起来没那么简单。这里先不展开,后面会专门讲。
避坑指南:full和empty信号本身也有延迟。比如FIFO已经满了,但full信号可能还要等几个时钟周期才拉高。所以设计时一定要留余量,别卡着极限值用。
2.5 信号关系总览
为了让大家看得更清楚,我画了一张图,把各个信号的关系串起来:
从这张图可以清楚看到:写信号在左边,读信号在右边,中间是FIFO存储体。full和empty是FIFO的状态输出,告诉外部现在能不能读写。
2.6 信号时序示例
光说理论不够,咱们来看一段简单的Verilog代码,模拟FIFO的写操作:
// 写操作示例
always @(posedge wclk) begin
if (wen && !full) begin
mem[wr_ptr] <= wdata; // 写入数据
wr_ptr <= wr_ptr + 1; // 写指针加1
end
end
// 读操作示例
always @(posedge rclk) begin
if (ren && !empty) begin
rdata <= mem[rd_ptr]; // 读出数据
rd_ptr <= rd_ptr + 1; // 读指针加1
end
end
注意看,写操作的条件是wen有效且FIFO未满。读操作的条件是ren有效且FIFO非空。这两个条件缺一不可。
我的经验:调试FIFO时,先看full和empty对不对,再看wen和ren有没有乱拉。很多时候问题就出在这几个信号上。
2.7 信号总结
| 信号名 | 方向 | 所属时钟域 | 作用 |
|---|---|---|---|
| wclk | 输入 | 写时钟域 | 写操作的时钟基准 |
| rclk | 输入 | 读时钟域 | 读操作的时钟基准 |
| wen | 输入 | 写时钟域 | 写使能,高电平有效 |
| ren | 输入 | 读时钟域 | 读使能,高电平有效 |
| wdata | 输入 | 写时钟域 | 写入的数据 |
| rdata | 输出 | 读时钟域 | 读出的数据 |
| full | 输出 | 写时钟域 | FIFO已满,禁止写入 |
| empty | 输出 | 读时钟域 | FIFO已空,禁止读出 |
这张表建议大家收藏。每次看FIFO波形时,对照着检查,能帮你快速定位问题。
好了,这一讲就到这里。记住这些信号的名字和作用,下一讲我们会用实际波形来演示它们是怎么配合工作的。