读写指针的时序是一样的,我们就以读指针为例:
首先看到 CLK 的上升沿为有效沿,每当 clk 的上升沿我们去看 read_en 信号(读使能信
号),当此信号为高的时候有效,此时 read_ptr(读指针)加一,同时 read_data 数据总线
上出现了在此时钟沿寄存器采到的 000 地址上的数据(为啥是 000 地址上的数据呢?这个需
要你从 D 触发器的特点去考虑,他是一个听话的乖宝宝,每当时钟有效沿到来就把上个时
钟沿采到的 D 值【即此时锁存在 D 触发器中的数据】发送给 Q 端,同时采集此时出现在 D
端的新数据并锁存住),(https://www.cnblogs.com/IClearner/p/6443539.html 读过这篇博客
的同学一定能看懂我刚才在鬼扯些什么)。
我们还发现当 read_en 信号无效的时候,读指针不发生变化,此时也不会读取数据。
同时读指针也不是无限制的递增的,当他遍历了所有的 FIFO 地址之后应当回零,以便下一
次的遍历。
写指针与读指针相同。知道了以上的信息,就可以完成读写指针的控制逻辑的设计了。
在后面会放出代码。
3.蓝色小矩形是各种控制信号的生成模块,这个图是从网上找的,所以一些具体的信号名字
可能会与我的代码有出入,有些信号我没有涉及到,但是最主要的空和满的判断是必要的;
我们通过一个计数器来计数 FIFO 中被占用的地址的数目,然后通过这个来判断空满。
以代码的形式展示更容易理解:
Always@(*)begin
Num_add_nxt = num_add; //当读写使能信号无效时,占用地址计数不变
If(write_en&&read_en)begin
Num_add_nxt = num_add; //读写使能都有效的时候,占用地址计数不变
end
else if(write_en)begin
num_add_nxt = num_add +1’b1; //写入了一个数据当然就会占用一个空间
end
else if(read_en)begin
num_add_nxt = num_add - 1’b1; //读走一个数据当让就会释放一个空间
end
End
Assign FIFO_FUL_nxt = (num_add_nxt == FIFO_DEPTH ); //占用空间数目等于 FIFO_DEPTH 那么
就是满了 没毛病
Assign FIFO_EMP_nxt =(num_add_nxt == ‘b 0);//空逻辑同上,好理解
Assign data_ava_nxt = num_add_nxt; //可用数据的数目就是等于占用地址的数目的嘛
Assign room_ava_nxt = FIFO_DEPTH - num_add_nxt; //可用空间数目
always@(posdge clk,negedge rst_n) begin //一堆寄存器,把上面组合逻辑生成的信号寄存
//起来 这种写法一开始比较难适应,理解之后