《硬件架构的艺术》学习笔记(3.2)---同步FIFO设计
发布日期:2021-05-06 19:13:42 浏览次数:19 分类:技术文章

本文共 2562 字,大约阅读时间需要 8 分钟。

同步FIFO设计

对于跨时钟域的数据传输,同步FIFO并不是好选择,异步FIFO才是最好的选择,这是由于同步FIFO的读写时钟相同。那么为什么还要介绍同步FIFO呢???通过学习《硬件架构的艺术》之后,对同步FIFO的“空”“满”标志的生成有了更加深刻的认识,在这里和大家分享、交流一下。

同步FIFO的架构

在这里插入图片描述

我们不必被这一个框一个框的吓唬到,没有什么玄虚的,都可以用verilog硬件语言将其分别描述。主要分为三部分:1)FIFO存储器、2)读/写指针生成、3)状态模块(即空/满信号生成 ---- 重点讨论 ----)。

1)FIFO存储器

**实现功能:**对外部写入数据进行存储;

**verilog实现:**通过一个二维数组来抽象描述, reg [WIDTH:0] mem [DEPTH:0];

2)读/写指针

**实现功能:**产生FIFO存储器的读/写地址;

**verilog实现:**读/写指针分别通过2个计数器来实现。
在这里插入图片描述

3)状态模块(空/满信号生成)

1. reg寄存器形式输出“empty”、“full”信号

在这里插入图片描述
对于深度为4的FIFO出现满时的情况。当wr_ptr指向“3”(DEPTH - 1)时,随后的时钟下wr_ptr指向0等于rd_ptr,此时FIFO满。同理,当读操作使两个指针在下一个时钟相等时,FIFO空。

**verilog实现:**生成的信号为reg寄存器类型,没有毛刺。

在这里插入图片描述

2. wire线网形式输出“empty”、“full”信号

在这里插入图片描述
另一种方式通过指针的形式来直接判断“empty”、“full”信号(指针便是在地址前面多加一位,如上图所示)。首先我们确定一点:写指针是恒领先于读指针的。当读写指针完全相同的情况下,FIFO空;当写指针领先读指针一圈的时候,FIFO满。

**verilog实现:**生成的信号为wire线网类型,有毛刺的风险。

在这里插入图片描述

3. 上述两种生成“empty”、“full”信号的对比

在这里插入图片描述

代码实例 8 * 16同步FIFO

module sync_fifo(  input    wire      clk,  input    wire      rstn,  input    wire      wen,  input    wire      ren,  input    wire[7:0] data_in,  output   wire      empty,  output   wire      full,  output   reg [7:0] data_out);reg[7:0] mem[15:0];    wire      w_wen;wire      r_ren;wire[3:0] waddr;wire[3:0] raddr;reg [4:0] wpoint;reg [4:0] rpoint;assign waddr = wpoint[3:0];assign raddr = rpoint[3:0];assign w_wen = wen & !full;    assign r_ren = ren & !empty;// generate wpoint 5bitalways @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    wpoint <= 5'd0;	else if(w_wen == 1)	    wpoint <= wpoint + 1;end// generate rpoint 5bitalways @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    rpoint <= 5'd0;	else if(r_ren == 1)	    rpoint <= rpoint + 1;endalways @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    mem[waddr] <= 8'h00;	else if(w_wen == 1)	    mem[waddr] <= data_in;endalways @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    data_out <= 8'h00;	else if(r_ren == 1)	    data_out <= mem[raddr];end// the first methodreg src_full;always @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    src_full <= 0;	else if(ren == 1)	    src_full <= 0;	else if((wen == 1) && (raddr == waddr + 1'b1))	    src_full <= 1;endreg src_empty;always @ (posedge clk or negedge rstn) begin    if(rstn == 0)	    src_empty <= 1;	else if(wen == 1)        src_empty <= 0;		else if((ren == 1) && (waddr == raddr + 1'b1))	    src_empty <= 1;endassign full = src_full;assign empty = src_empty;// the second method/* assign empty = (wpoint[4] == rpoint[4]) ? ((wpoint[3:0] == rpoint[3:0]) ? 1 : 0) : 0; assign full =  (wpoint[4] == rpoint[4]) ? 0 : ((wpoint[3:0] == rpoint[3:0]) ? 1 : 0); */endmodule
上一篇:《硬件架构的艺术》学习笔记(4)---时钟分频设计
下一篇:《硬件架构的艺术》学习笔记(3.1)---跨时钟域设计

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年03月09日 22时45分32秒