FIFO系列(二):同步FIFO的verilog设计

2020-06-29 15:27:09 浏览数 (1)

本系列分为以下部分:

1、FIFO深度计算

2、同步fifo设计

3、fifo与格雷码

4、异步fifo设计(新增)

计划分三次更新完毕,本次为同步FIFO设计。

由于本次过于简单,第四次增加异步FIFO设计,异常有趣!

同步FIFO设计

关于同步fifo的设计疑惑了半天,本以为这个代码是错的,后来自己又写了一遍,但是写到最后又觉得这个是正确的,主要是wr_cnt和rd_cnt的理解。

在本实例中,wr_cnt并非读写数据的计数器,不是说fifo中写入了多少个数据,而是指的写数据指针,在每次写入数据后写指针自动加一,写入16个数据后fifo写指针数值为4'b1111。

同样,rd_cnt也不是指的读了多少个数据,指的是读取数据的读指针,每读完一次后,改指针自动加一,即指向下一个要读取的地址。

没什么好讲的,异步fifo的设计才是有趣,异步fifo的设计代码在第三节格雷码更新完毕后更新。

代码:

代码语言:javascript复制
module SYN_FIFO
#(
parameter DATA_WIDTH=8,
parameter ADDR_WIDTH=4,
parameter DATA_DEPTH=1<<ADDR_WIDTH
)
(
input clk,                      //时钟 
input rst_n,                    //复位信号输入
input rd_en,                   //读取使能信号
input wr_en,                   //写使能信号
input [DATA_WIDTH-1'b1:0]data_w,       //写入数据
output reg [DATA_WIDTH-1:0]data_r,  //读出数据
output reg [ADDR_WIDTH-1:0] wr_cnt,     //写计数器
output reg [ADDR_WIDTH-1:0] rd_cnt,    //读计数器
output fifo_full,                     //fifo满
output reg [ADDR_WIDTH-1'b1:0]status_cnt,
output fifo_empty                //fifo空标志
);  
reg [DATA_WIDTH-1:0]data_ram;

//--------------
assign fifo_full  = (status_cnt==DATA_DEPTH-1);
assign fifo_empty = (status_cnt==0);
//读取使能寄存
reg rd_en_r;
always@(posedge clk or negedge rst_n)
if(~rst_n)
rd_en_r<=1'b0;
else 
 rd_en_r<=rd_en;
//写入数据计数器
always@(posedge clk or negedge rst_n)
if(~rst_n)
 wr_cnt<=4'hf;
else if(wr_cnt==DATA_DEPTH-1'b1)
 wr_cnt<=0;
else if(wr_en)
 wr_cnt<=wr_cnt 1'b1;
//读取计数器
always@(posedge clk or negedge rst_n)
if(~rst_n)
 rd_cnt<=0;
else if(rd_cnt==DATA_DEPTH-1'b1)
 rd_cnt<=0;
else if(rd_en)
 rd_cnt<=rd_cnt 1'b1;

always@(posedge clk or negedge rst_n)
if(~rst_n)
 data_r<=4'hf;
else if(rd_en_r)
 data_r<=data_ram;
 
 
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
status_cnt <= 0;
end
else if(rd_en && !wr_en && (status_cnt != 0))begin
status_cnt <= status_cnt - 1;
end
else if(wr_en && !rd_en && (status_cnt != DATA_DEPTH-1))
status_cnt <= status_cnt   1;
else
status_cnt <= status_cnt;
end
//Syn_Dual_Port_RAM
integer i;
reg [DATA_WIDTH-1:0] register[DATA_DEPTH-1:0];
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
for(i = 0; i < DATA_DEPTH; i = i   1)
register[i] <= 0;
end
else if(wr_en == 1'b1)
register[wr_cnt] <= data_w;
end

always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
data_ram <= 0;
end
else if(rd_en == 1'b1)
data_ram <= register[rd_cnt];
else
data_ram <= data_ram;
end
endmodule

仿真:

代码语言:javascript复制
`timescale 1ns/1ps
module fifo_tb; 
parameter DATA_WIDTH=8;
parameter ADDR_WIDTH=4;
parameter DATA_DEPTH=1<<ADDR_WIDTH;

reg clk, rst_n,rd_en,  wr_en;
reg [15:0]data_w;     //写入数据
wire [DATA_WIDTH-1:0]data_r;  //读出数据
wire [ADDR_WIDTH-1:0] wr_cnt;     //写计数器
wire [ADDR_WIDTH-1:0] rd_cnt;    //读计数器
wire fifo_full;
wire[ADDR_WIDTH-1'b1:0]ptr;
wire  fifo_empty ;

SYN_FIFO u0(
 clk,                      //时钟 
 rst_n,                    //复位信号输入
 rd_en,                   //读取使能信号
 wr_en,                   //写使能信号
   data_w,       //写入数据
   data_r,  //读出数据
   wr_cnt,     //写计数器
   rd_cnt,    //读计数器
  fifo_full,                     //fifo满
  ptr,
  fifo_empty                //fifo空标志
);
initial begin 
clk=0;
forever #10 clk=~clk;
end 
initial begin
 rst_n=0;
 data_w=16'd0;
 rd_en=0;
 wr_en=0;
 #20;
 rst_n=1;
 #20;
 wr(0); wr(1); wr(2); wr(3); wr(4); wr(5); wr(6); wr(7);
 wr(8); wr(9); wr(10); wr(11); wr(12); wr(13); wr(14); wr(15);
 #20;
 rd; 
 #20;
 $stop;
end 

task wr;
 input[3:0] i;
begin
 wr_en=1'b1;
 data_w=i;
 #20;
 wr_en=1'b0;
end  
endtask
task rd; 
begin
 rd_en=1'b1; 
 #(20*17);
 rd_en=1'b0;
end  
endtask
endmodule

~~感谢阅读~~周末愉快

0 人点赞