前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FIFO系列(二):同步FIFO的verilog设计

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

作者头像
根究FPGA
发布2020-06-29 15:27:09
3.3K0
发布2020-06-29 15:27:09
举报
文章被收录于专栏:根究FPGA

本系列分为以下部分:

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 根究FPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 同步FIFO设计
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档