娄底建设局官方网站,一个新产品策划方案,网站建设合同应注意什么,有哪些网站可以做全景效果图一、前言 在之前的文章中#xff0c;我们介绍了同步FIFO的verilog的一种实现方法#xff1a;计数法。其核心在于#xff1a;在同步FIFO中#xff0c;我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据#xff0c;从而可以判断空、满。 关于计数法实现同步FIFO的详…一、前言 在之前的文章中我们介绍了同步FIFO的verilog的一种实现方法计数法。其核心在于在同步FIFO中我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据从而可以判断空、满。 关于计数法实现同步FIFO的详细内容请参考同步FIFO的verilog实现1——计数法
二、高位扩展法原理 我们知道对于FIFO的设计来说其核心在于设计读写指针并且生成可靠的空、满信号。 当读/写地址指针在复位操作期间被置为零时或者当读指针在从FIFO中读取了最后一个字之后追上了写指针此时读指针和写指针相等代表着FIFO为空状态。而当写指针再次追上读指针时此时读指针和写指针相等代表着FIFO为写满。也就是说当读写指针相等时FIFO要么为空要么为满。 因此我们可以将地址位扩展一位用最高位来判断空满其余低位还是正常用于读写地址索引。当写指针递增超过FIFO的最大地址时写指针的MSB位将置为1同时将其余低位设置回零。读指针也是如此。如果读指针和写指针的MSB不同则意味着写指针比读指针多绕了一次表示FIFO写满。如果两个指针的MSB相同则表示两个指针的回绕次数相同表示FIFO读空。如下图所示 当最高位不同且其他位相同则表示读指针或者写指针多跑了一圈这显然不可能发生情况只能是写指针多跑了一圈与就意味着FIFO被写满了。 当最高位相同且其他位相同则表示读指针追到了写指针或者写指针追到了读指针而显然不会让写指针追读指针这种情况只能是写指针超过读指针一圈所以可能出现的情况只能是读指针追到了写指针也就意味着FIFO被读空了。
三、同步FIFO的verilog实现 理解了原理我们就能很快设计出相应的verilog代码
//------------------------高位扩展法设计同步FIFO----------------------------
module sync_fifo1#(
//-----------------------------参数定义---------------------------------parameter FIFO_WIDTH 16, //FIFO宽度parameter FIFO_DEPTH 16 //FIFO深度
)(
//-----------------------------接口定义---------------------------------input clk, //时钟信号input rst, //复位信号input [FIFO_WIDTH-1:0] din, //FIFO输入数据写数据input rd_en, //读使能信号 input wr_en, //写使能信号output reg [FIFO_WIDTH-1:0] dout, //FIFO输出数据读数据 output empty, //FIFO空标志 output full //FIFO满标志
); //-----------------------------reg定义---------------------------------reg [FIFO_WIDTH-1:0] fifo_buffer[FIFO_DEPTH-1:0]; //用二维数组实现RAM reg [$clog2(FIFO_DEPTH):0] wr_addr; //写地址写指针位宽要多出一位reg [$clog2(FIFO_DEPTH):0] rd_addr; //读地址读指针位宽要多出一位//-----------------------------wire定义--------------------------------- wire [$clog2(FIFO_DEPTH) - 1 : 0] wr_addr_true; //真实写地址指针wire [$clog2(FIFO_DEPTH) - 1 : 0] rd_addr_true; //真实读地址指针wire wr_addr_msb; //写地址指针地址最高位wire rd_addr_msb; //读地址指针地址最高位assign {wr_addr_msb,wr_addr_true} wr_addr; //将最高位与其他位拼接assign {rd_addr_msb,rd_addr_true} rd_addr; //将最高位与其他位拼接 //-----------------------------读操作-----------------------------------
always(posedge clk or posedge rst)begin if(rst)rd_addr 0;else if(rd_en !empty)begin //读使能有效且FIFO非空rd_addr rd_addr 1d1; //读指针递增dout fifo_buffer[rd_addr_true]; //fifo读出数据endelse beginrd_addr rd_addr; dout dout;end
end//-----------------------------写操作-----------------------------------
always(posedge clk or posedge rst)begin if(rst)wr_addr 0;else if(wr_en !full)begin //写使能有效且FIFO非满wr_addr wr_addr 1d1; //读指针递增fifo_buffer[wr_addr_true] din; //数据写入fifoendelse beginwr_addr wr_addr; end
end//-----------------------------通过地址扩展位更新空/满信号-----------------------------------
assign empty ( wr_addr rd_addr ) ? 1b1 : 1b0; //当所有位相等时读指针追到了写指针FIFO被读空
assign full ((wr_addr_msb ! rd_addr_msb ) ( wr_addr_true rd_addr_true )) ? 1b1 : 1b0; //当最高位不同但是其他位相等时写指针超过读指针一圈FIFO被写满endmodule
四、测试代码 给出如下的测试代码
timescale 1ns/1ns
//-----------------------------高位扩展法同步FIFO测试---------------------------------
module tb_sync_fifo1();parameter WIDTH 8;parameter DEPTH 8;reg clk ;reg rst ;reg [WIDTH-1:0] din ;reg wr_en ;reg rd_en ;wire [WIDTH-1:0] dout ;wire full ;wire empty ;//-----------------------------测试模块例化---------------------------------
sync_fifo1 #(.FIFO_WIDTH (WIDTH), //FIFO宽度.FIFO_DEPTH (DEPTH) //FIFO深度
)
sync_fifo_u1(.clk (clk ),.rst (rst ),.din (din ),.rd_en (rd_en ),.wr_en (wr_en ),.dout (dout ), .empty (empty ), .full (full )
);//-----------------------------模块测试---------------------------------
initial beginclk 1b0; //初始时钟为0rst 1b0; //初始复位din d0; wr_en 1b0; rd_en 1b0;
#10rst 1b1;
#10 rst 1b0;repeat(10)#10 beginwr_en 1b1;rd_en 1b0;din $random; //生成8位的随机数endrepeat(10)#10 beginwr_en 1b0;rd_en 1b1;end
$finish;
end//------------------------------设置时钟----------------------------------------
always #5 clk ~clk; endmodule
五、结果