E203 同步fifo
1. 输入端,
输入信号, i_vld,表示输入请求写同步fifo,如果fifo不满,则fifo发送i_rdy 到输入端,开始写fifo。i_vld和i_rdy是写握手信号。
2.输出端
o_rdy表示接受端已经准备好了,可以读取fifo,o_vld表示fifo准备好了,不为空,可以输出到接收端。o_rdy和o_vld是握手信号。
3.如果fifo是深度为0,则是bypass模式,只要请求写,就直接准备输出,所以
assign o_vld = i_vld;
assign i_rdy = o_rdy;
assign o_dat = i_dat;
可以立即发送数据 o_dat=idat, 对于深度为n的情况, i_rdy = ~full, o_vld=~empty, 就是i_rdy和o_vld是满空标志取反。
4.如果深度为n,假设为4, 我们设置i_vld=1,但是o_rdy 总是0,则输入端写fifo,直到fifo满。
testbench代码如下:


module sirv_gnrl_dffs_tb; reg clk=0,rst_n;
reg i_vld, o_rdy;
reg [31:0] i_dat; wire i_rdy, o_vld;
wire [31:0] o_dat; sirv_gnrl_fifo #(.CUT_READY(1),.DP(4),.DW(32)) mybuf(.i_vld(i_vld),.i_rdy(i_rdy),.i_dat(i_dat),.o_vld(o_vld),.o_rdy(o_rdy),.o_dat(o_dat),.clk(clk),.rst_n(rst_n)); always #10 clk=~clk; initial
begin
rst_n=1'b1;
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = 32'h12345678;
#20
rst_n=1'b0;
#80
rst_n=1'b1;
#80
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%32;
#80
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%32;
#20
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = $random()%32;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%32;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%32;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%32;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%1024;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%1024;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%1024;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%1024;
#20
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = $random()%1024;
#500 $finish;
end initial
$monitor($time,,,"clk=%b,rst_n=%b,i_vld=%b,o_rdy=%b, i_rdy=%b, o_vld=%b,",clk,rst_n,i_vld,o_rdy,i_rdy,o_vld);
initial
begin
//$dumpfile("dump.vcd");
//$dumpvars;
$fsdbDumpfile("dump.fsdb");
$fsdbDumpvars("+all");
end endmodule
初始时刻,同步fifo各个信号都是x,直到复位信号rst_n的下降沿到来时候,复位读写指针触发器和向量寄存器触发器,向量寄存器主要用于空满判断。
读写指针都被初始化为1,如果fifo深度(DP)=1,则读写指针rptr_vec_r,wptr_vec_r总是1。下一个读写指针rptr_vec_nxt/wptr_vec_nxt 等于当前指针左移一位,假设DP=4,则指针为0001,0010,0100,1000, 1000的下一个是0001,首尾相接。这种表示法是用独热码的方式表示读写指针。
////////////////
///////// Read-Pointer and Write-Pointer
// if ith is 1, then means read/write ith value of fifo
wire [DP-1:0] rptr_vec_nxt;
wire [DP-1:0] rptr_vec_r;
wire [DP-1:0] wptr_vec_nxt;
wire [DP-1:0] wptr_vec_r;
//read pointer dynamic process,
// always is 1
if(DP == 1) begin:rptr_dp_1
assign rptr_vec_nxt = 1'b1;
end
else begin:rptr_dp_not_1 // 0001,0010,0100,1000,0001, ring buffer,
assign rptr_vec_nxt =
rptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
(rptr_vec_r << 1);
end if(DP == 1) begin:wptr_dp_1
assign wptr_vec_nxt = 1'b1;
end
else begin:wptr_dp_not_1
assign wptr_vec_nxt =
wptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
(wptr_vec_r << 1);
end
向量寄存器触发器为DP+1位。复位下降沿道来时候,vec_r=1, 如果读和写有一个工作的时候,则vec_en=1。
如果写enable的时候,vec_nxt = {vec_r[DP-1:0],1’b1},
vec_r, vec_nxt:
1, 11
11,111
111, 1111
1111, 1_1111
i_rdy = (~i_vec[DP-1]);如果i_vec[DP-1]=1,则表示fifo满了, i_rdy=0,此时不能写fifo了。
///////// Vec register to easy full and empty and the o_vld generation with flop-clean
wire [DP:0] i_vec;
wire [DP:0] o_vec;
wire [DP:0] vec_nxt;
wire [DP:0] vec_r; wire vec_en = (ren ^ wen );//ren not same as wen set to 1
assign vec_nxt = wen ? {vec_r[DP-1:0], 1'b1} : (vec_r >> 1); sirv_gnrl_dfflrs #(1) vec_0_dfflrs (vec_en, vec_nxt[0] , vec_r[0] , clk, rst_n);
sirv_gnrl_dfflr #(DP) vec_31_dfflr (vec_en, vec_nxt[DP:1], vec_r[DP:1], clk, rst_n); assign i_vec = {1'b0,vec_r[DP:1]};
assign o_vec = {1'b0,vec_r[DP:1]};
会根据wen和写指针wptr_vec_r,把i_dat写入到指定的位置,因为是读热码,所以只有一位为1,为1的位置正好是fifo中最上面空的位置。
///////// write fifo
for (i=0; i<DP; i=i+1) begin:fifo_rf//{
assign fifo_rf_en[i] = wen & wptr_vec_r[i];
// Write the FIFO registers
sirv_gnrl_dffl #(DW) fifo_rf_dffl (fifo_rf_en[i], i_dat, fifo_rf_r[i], clk);
end//}
对于这个test,会在连续的4个时钟上升沿写入i_dat,因为此时i_dat都为4,所以会写入四个4。
我们修改testbench,增加enable o_rdy


module sirv_gnrl_dffs_tb; reg clk=0,rst_n;
reg i_vld, o_rdy;
reg [31:0] i_dat; wire i_rdy, o_vld;
wire [31:0] o_dat; sirv_gnrl_fifo #(.CUT_READY(1),.DP(4),.DW(32)) mybuf(.i_vld(i_vld),.i_rdy(i_rdy),.i_dat(i_dat),.o_vld(o_vld),.o_rdy(o_rdy),.o_dat(o_dat),.clk(clk),.rst_n(rst_n)); always #10 clk=~clk; initial
begin
rst_n=1'b1;
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = 32'h12345678;
#20
rst_n=1'b0;
#80
rst_n=1'b1;
#80
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = 32'h8;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = 32'h12;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = 32'h2;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = 32'h11;
#20
i_vld = 1'b1;
o_rdy = 1'b0;
i_dat = 32'h13;
#20
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = 32'h6;
#20
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = 32'h22;
#20
i_vld = 1'b0;
o_rdy = 1'b0;
i_dat = 32'h99;
#20
i_vld = 1'b0;
o_rdy = 1'b1;
i_dat = 32'h33;
#20
i_vld = 1'b0;
o_rdy = 1'b1;
i_dat = 32'h17;
#20
i_vld = 1'b0;
o_rdy = 1'b1;
i_dat = 32'h3;
#500 $finish;
end initial
$monitor($time,,,"clk=%b,rst_n=%b,i_vld=%b,o_rdy=%b, i_rdy=%b, o_vld=%b,",clk,rst_n,i_vld,o_rdy,i_rdy,o_vld);
initial
begin
//$dumpfile("dump.vcd");
//$dumpvars;
$fsdbDumpfile("dump.fsdb");
$fsdbDumpvars("+all");
end endmodule
// o_vld as flop-clean
assign o_vld = (o_vec[0]);
根据o_vec[0]判断是否为空,如果不为空,则enable o_vld,开始读fifo。
根据当前的读指针,从fifo中取出数据,并赋值给o_dat, 如果设置了mask out,会把数据初始值中的x mask掉。默认设置这个值。
/////////One-Hot Mux as the read path
integer j;
reg [DW-1:0] mux_rdat;
always @*
begin : rd_port_PROC//{
mux_rdat = {DW{1'b0}};
for(j=0; j<DP; j=j+1) begin
mux_rdat = mux_rdat | ({DW{rptr_vec_r[j]}} & fifo_rf_r[j]);
end
end//} if(MSKO == 1) begin:mask_output//{
// Mask the data with valid since the FIFO register is not reset and as X
assign o_dat = {DW{o_vld}} & mux_rdat;
end//} else begin:no_mask_output//{
// Not Mask the data with valid since no care with X for datapth
assign o_dat = mux_rdat;
end//}
再看下CUT_READY, 当fifo深度为1的时候,ready和下一个阶段的ready信号相关,变成了逻辑链。我们可以通过CUT_READY来控制它。
如果设置了CUT_READY,仅当fifo不为空的时候,才能设置i_rdy信号,可以切断反压信号,阻止它传递到上一级,这时候2个周期传输一个数据。如果设置CUT_READY=0,则变成一个popping操作,同一个周期放入弹出。
if(DP == 1) begin:cut_dp_eq1//{
if(CUT_READY == 1) begin:cut_ready//{
// If cut ready, then only accept when fifo is not full
assign i_rdy = (~i_vec[DP-1]);
end//}
else begin:no_cut_ready//{
// If not cut ready, then can accept when fifo is not full or it is popping
assign i_rdy = (~i_vec[DP-1]) | ren;
end//}
end//}
else begin : no_cut_dp_gt1//}{
assign i_rdy = (~i_vec[DP-1]);
end//}
下面是DP=1,设置CUT_READY=1 和0的波形。
CUT_READY=1
CUT_READY=0
E203 同步fifo的更多相关文章
- Verilog学习笔记简单功能实现(八)...............同步FIFO
Part 1,功能定义: 用16*8 RAM实现一个同步先进先出(FIFO)队列设计.由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出.写入和读出的操作(高电平有效)由时钟的上 ...
- 同步fifo的verilogHDL设计实例
原创 设计一个fifo,输入16bit,输出16bit的data,寻址宽度5bit,有空满标志. top 层如下所示: /* date : 2014/10/14 version : modelsim ...
- 怎么用Verilog语言描述同步FIFO和异步FIFO
感谢 知乎龚大佬 打杂大佬 网上几个nice的博客(忘了是哪个了....) 前言 虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻. 什么是FIFO? Fist in first out ...
- 同步fifo的Verilog实现
FIFO是一种先进先出的数据缓存器,他与普通存储器相比: 优点:没有外部读写地址线,这样使用起来非常简单: 缺点:只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存 ...
- 同步FIFO学习
在网上找的一个经典同步FIFO例子. 一.前言 FIFO (First-In-First-Out) 是一种先进先出的数据交互方式,在数字ASIC设计中常常被使用.FIFO按工作时钟域的不同又可以分为: ...
- 同步FIFO design and IP level verification
一.前言 应聘IC前端相关岗位时,FIFO是最常考也是最基本的题目.FIFO经常用于数据缓存.位宽转换.异步时钟域处理.随着芯片规模的快速增长,灵活的system verilog成为设计/验证人员的基 ...
- 同步fifo与异步fifo
参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...
- CYPEESS USB3.0程序解读之---同步FIFO(slaveFifoSync)
上一篇文章解读了CYPRESS FX3的GPIO的操作过程,下面解读同步FIFO的一个例子(slaveFifoSync). *生产者,消费者. 1.首先看DMA的回调函数(cyu3dma.h): ty ...
- 同步FIFO的设计
module scfifo #( , ) ( input clk, input rst_n, input wren, input rden, :] din, :] dout, output full, ...
随机推荐
- gradle使用基础
说明 介绍gradle使用基础,gradle基础脚本结构和常规使用方法,以及一个简单的gradle示例.主要是为了简单的介绍gradle使用. gradle环境配置 gradle可以通过两种方式运行g ...
- thinkPHP中怎么访问域名直接跳到后台登录页面
问题: 我想只访问域名就跳到后台登录页面,怎么把地址栏里的路径隐藏掉 答案: 修改配置Common里的conf文件夹里,把默认模块改成“Admin”,默认控制器改成“login”系统默认的默认模块式h ...
- zip unzip 压缩解压缩命令
直接上例子: mkdir test1 touch test1/1.txt touch test1/2.txt zip -r test1.zip test1 #-r 参数是包含文件夹下的文件 un ...
- UGUI Manual
以Unity 5.5 的官方文档为例 Canvas UI元素的前后顺序:SetAsFirstSibling, SetAsLastSibling, and SetSiblingIndex BasicLa ...
- 01-day-什么是webpack
.sass后缀的文件名 比较老了 现在它的后缀名是.scss 其实他们是同一个东西 只是 后缀名发生了变化 以 .sass写的文件的内容是 他没有括号 没有分号 有点怪 它跟新为了.scss 就有了花 ...
- **目录找出最后一次修改的文件(html结果),发送报告到指定qq邮箱
import unittest,HTMLTestRunnerimport osdef runa(): path=os.getcwd() print(path) a=unittest.defaultTe ...
- BASIC合集
握手包 给你握手包,flag是Flag_is_here这个AP的密码,自己看着办吧. 提交格式:flag{WIFI密码} 破解wifi密码 丢到kali,用aircrack-ng kali有一个包含常 ...
- MongoDB高级知识(六)
1. document的关系 多个文档之间在逻辑上可以相互联系,可以通过嵌入和引用来建立联系. 文档之间的关系可以有: 1对1 1对多 多对1 多对多 一个用户可以有多个地址,所以是一对多的关系. # ...
- 消息队列的使用<二>:ActiveMQ的基本使用(Java)
目录 ActiveMQ 介绍 下载.安装和初次运行 Java上初次使用activeMQ 设置请求属性: 可靠性机制 事务 消息消费方式 receive 监听器: 消息类型 发布/订阅模式 非持久订阅 ...
- linux jdk1.8 32位下载永久地址,ubuntu,centos,java
链接: https://pan.baidu.com/s/16zSC0HZGFjrTAXrW6eyHzg 提取码: cj7m 复制这段内容后打开百度网盘手机App,操作更方便哦