• FIFO有一个读口和一个写口,读写时钟一致是同步FIFO,时钟不一致就是异步FIFO
  • IP设计中通常使用的是同步FIFO
  • 异步FIFO通常使用在跨时钟域设计中

RAM(Random Access Memory)的设计

FIFO中的数据可以存储在寄存器中或者SRAM中,FIFO的容量比较小的时候,使用register,FIFO容量比较大的时候使用的是SRAM

  • SRAM通常是Memory Compiler进行产生的
  • SRAM不需要手动写仿真模型
  • RAM在时钟的驱动下,可以从两个端口同时进行读写操作
  • 写操作:写数据、写地址、写使能
  • 读操作:读地址、读使能,读取完成之后,会返回读数据

双端口RAM的Verilog代码(仿真模型)



  • 将RAM的位宽、深度进行参数化设计,方便后续进行修改

  • 首先要定义一个存储空间,用于存储数据
  • SRAM是已经综合好的block,其中布局布线已经完成

  • 在进行DC综合的时候,会将定义的存储体综合为寄存器或者sram(如果有相应的库文件),使用sram,面效比会比较好;register作为存储体的时候,容量小的时候,面积比较小,并且在下一个周期读出其中的值
  • 使用register作为存储体,使用组合逻辑在当拍就可以得到数据
//1.
always@ (posedge clk) begin
if(read_en)
read_data <= memory[read_addr];
end //2.
// 当拍就可以得到memory的值
wire [DATA_WIDTH-1:0] read_data_next;
assign read_data_next = memory[read_addr]; always @(posedge clk) begin
if(read_en)
read_data <= read_data_next;
end

同步FIFO设计

  • FIFO包含两部分,一部分是存储体,另一部分是fifo ctrl
  • fifo是不会存在根据地址取值的,fifo - 先入先出,所以端口没有地址,地址通过其中的fifo ctrl进行控制
  • 没有读地址和写地址
  • fifo满了之后,不能写入数据,fifo为空的时候,不能向外读取数据,关键是full和empty信号的产生
  • fifo上下游模块看到fifo的状态之后,满不写,空不读;在fifo内部也需要进行控制

方法1

  • 需要维护读指针和写指针

  • 产生一个写使能,需要给一个地址给到写使能,写指针加1;产生一个读使能,读指针加1
  • 产生空满信号:用一个计数器,表示当前fifo中一共存有多少数据,写使能来的时候,计数器加1,读使能来的时候,计数器减1,写使能和读使能同时来的时候,计数器不变
  • 当counter为容量减一的时候,来了一个写使能,会变为满
  • 当counter为1的时候,来了一个读使能,会变为空





// 满信号产生
if((!write_allow) && (Fcounter == 9'b0))
empty <= 1;
else if((!write_allow) && (Fcounter == 9'b1 && (read_allow))
empty <=1;
else
empty <= 1'b0;



  • counter的值要覆盖所有的RAM地址范围
parameter COUNTER_WIDTH = 9;
reg Fcounter [COUNTER_WDITH-1:0]; // 只能表示0-511,表示不了512这个数
reg Fcounter [COUNTER_WDITH:0]; // 9bit可以表示512这个数
module syncfifo(
fifo_rst,
fifo_clk, read_enable,
write_enable, read_data,
write_data, full,
empty, fcounter
); parameter DATA_WIDTH = 8;
parameter ADDR_WIDTH = 9; input fifo_clk;
input fifo_rst; input read_enable;
input write_enable; input [DATA_WIDTH-1:0] write_data;
input [DATA_WIDTH-1:0] read_data; output full;
output empty; reg [ADDR_WIDTH:0] fcounter; reg [DATA_WIDTH-1:0] read_addr;
reg [DATA_WIDTH-1:0] write_addr; DUALRAM_RAM(
read_clk (fifo_clk),
write_clk (fifo_clk), read_allow (read_allow),
write_allow (write_allow), read_addr (read_addr),
write_addr (write_addr), read_data (read_data),
write_data (write_data)
); wire read_allow = (read_enable && !empty);
wire write_allow = (write_enable && !full); always @(posedge fifo_clk or negedge fifo_rst) begin
if(fifo_rst)
empty <= 1'b1;
else
empty <= (!write_allow) && (fcounter[8:0] == 8'h0) && ((fcounter[0]==0)||read_allow);
end always @(posedge fifo_clk or negedge fifo_rst) begin
if(fifo_rst)
full <= 1'b0;
else
full <= (!read_allow) && (fcounter[8:1] == 8'hff) && (fcounter[0]==1 || write_allow);
end always @(posedge fifo_clk or negedge fifo_rst) begin
if(fifo_rst)
read_addr <= 'h0
esle if(read_allow)
read_addr <= read_addr + 1'b1;
end always @(posedge fifo_clk or negedge fifo_rst) begin
if(fifo_rst)
write_addr <= 'h0
esle if(read_allow)
write_addr <= read_addr + 1'b1;
end always @(posedge fifo_clk or negedge fifo_rst) begin
if(fifo_rst)
fcounter <= 'h0;
else if((!read_allow && write_allow) || (read_allow && !write_allow))
if(write_allow)
fcounter <= fcounter + 1'b1;
else
fcounter <= fcounter - 1'b1;
end endmodule

方法2

方法1多例化了一个计数器,计数器需要占据一定的资源和面积





  • 读写指针的空间扩大一倍,使用除最高位之外的其他位寻址sram

module sync_fifo
#(
parameter ADDR_WIDTH = 4,
parameter RAM_WIDTH = 8,
parameter RAM_DEPTH = 16
)
(
input wire fifo_clk,
input wire fifo_rst_n,
input wire read_en,
input wire write_en,
input wire [RAM_WIDTH-1:0] w_data,
output reg [RAM_WIDTH-1:0] r_data,
output wire empty,
output wire full
); // 指针
reg [ADDR_WIDTH:0] write_addr;
reg [ADDR_WIDTH:0] read_addr;
wire [ADDR_WIDTH-1:0] w_addr;
wire [ADDR_WIDTH-1:0] r_addr; wire write_allow = write_en && (!empty);
wire read_allow = read_en && (!full); reg [RAM_WIDTH-1:0] mem [RAM_DEPTH-1:0]; always @(posedge fifo_clk or negedge fifo_rst_n) begin
if(!fifo_rst_n)
read_addr <= {ADDR_WIDTH{1'b0}};
else if(read_allow) begin
r_data <= mem[read_addr];
read_addr <= read_addr + 1;
end
end always @(posedge fifo_clk or negedge fifo_rst_n) begin
if(!fifo_rst_n)
write_addr <= {ADDR_WIDTH{1'b0}};
else if(write_allow) begin
mem[write_addr] <= w_data;
write_addr <= write_addr + 1;
end
end assign empty = read_addr == write_addr ? 1 : 0;
assign full = (read_addr[ADDR_WIDTH]!=write_addr[ADDR_WIDTH]) &&
(read_addr[ADDR_WIDTH-1:0] == write_addr[ADDR_WIDTH-1:0]); assign r_addr = read_addr[ADDR_WIDTH-1:0];
assign w_addr = write_addr[ADDR_WIDTH-1:0];
endmodule

同步FIFO设计的更多相关文章

  1. 同步fifo的verilogHDL设计实例

    原创 设计一个fifo,输入16bit,输出16bit的data,寻址宽度5bit,有空满标志. top 层如下所示: /* date : 2014/10/14 version : modelsim ...

  2. Verilog学习笔记简单功能实现(八)...............同步FIFO

    Part 1,功能定义: 用16*8 RAM实现一个同步先进先出(FIFO)队列设计.由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出.写入和读出的操作(高电平有效)由时钟的上 ...

  3. FPGA Asynchronous FIFO设计思路

    FPGA Asynchronous FIFO设计思路 将一个多位宽,且在不停变化的数据从一个时钟域传递到另一个时钟域是比较困难的. 同步FIFO的指针比较好确定,当FIFO counter达到上限值时 ...

  4. 怎么用Verilog语言描述同步FIFO和异步FIFO

    感谢 知乎龚大佬 打杂大佬 网上几个nice的博客(忘了是哪个了....) 前言 虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻. 什么是FIFO? Fist in first out ...

  5. 同步fifo的Verilog实现

    FIFO是一种先进先出的数据缓存器,他与普通存储器相比: 优点:没有外部读写地址线,这样使用起来非常简单: 缺点:只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存 ...

  6. 基于FPGA的异步FIFO设计

    今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域.由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出).这里的读写指针是异步的, ...

  7. 同步FIFO学习

    在网上找的一个经典同步FIFO例子. 一.前言 FIFO (First-In-First-Out) 是一种先进先出的数据交互方式,在数字ASIC设计中常常被使用.FIFO按工作时钟域的不同又可以分为: ...

  8. FIFO设计思考之一

    不管同步FIFO还是异步FIFO,设计难点是full/empty状态flag的正确性. 要保证任何情况 FULL时NO WRITE,EMPTY时NO READ.overflow / underflow ...

  9. 同步FIFO design and IP level verification

    一.前言 应聘IC前端相关岗位时,FIFO是最常考也是最基本的题目.FIFO经常用于数据缓存.位宽转换.异步时钟域处理.随着芯片规模的快速增长,灵活的system verilog成为设计/验证人员的基 ...

  10. 同步fifo与异步fifo

    参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...

随机推荐

  1. Cesium最简单的视效升级方案,无需修改代码即可实现

    Cesium依靠其开源免费的特点基本上完全垄断了GIS这一块,并且其中99%的用户都是使用的CesiumJS,然而,对于一些使用Cesium的项目来说,要想升级视效可能需要进行繁琐的代码修改,增加了开 ...

  2. 用CloudDrive将阿里云、天翼云、115挂载为电脑本地硬盘

    用CloudDrive将阿里云.天翼云.115挂载为电脑本地硬盘 写在前面 它可以把各大在线网盘,直接变成电脑本地硬盘,俗称"网盘挂载".这在一定程度上,确实能缓解存储紧张问题,瞬 ...

  3. 使用gradle的方式进行Springboot3的web开发(微服务版)

    简要: 最近看了很多的Springboot3的项目,但是发现很多都是用maven来进行版本管理的,很少有用gradle来管理的,通过网上查找资料,看视频,终于自己写一个gradle管理的Springb ...

  4. 面试官喜欢问Nacos原理?直接把这篇文章甩给他!

    大家好,我是三友~~ 今天就应某位小伙伴的要求,来讲一讲Nacos作为服务注册中心底层的实现原理 不知你是否跟我一样,在使用Nacos时有以下几点疑问: 临时实例和永久实例是什么?有什么区别? 服务实 ...

  5. android ProgressBar样式

    实现进度条由浅黄(#ffff33)到深黄色(#ff6600)的渐变样式. 与进度条自动从0加载到99,进度条每次加1 android:max:进度条的最大值. android:progressDraw ...

  6. GaussDB技术解读系列之应用无损透明(ALT)

    本文作者 :华为云GaussDB研发高级工程师 藏琦 1.背景 GaussDB作为一款企业级分布式数据库,提供了"同城跨AZ双活.两地三中心.双集群强一致"等极致的高可用容灾能力. ...

  7. 华为云张昆:支持全场景全业务,GaussDB加速企业数字化转型

    云.AI.5G等技术驱动,数据库行业迎来新的需求,云数据库也在不断演进升级.依托华为云与华为云Stack,通过全栈软硬件优化,华为云GaussDB进行了进阶与革新,以统一的架构,支持关系型与非关系型的 ...

  8. 一通百通,带你一次性全理解Spring 中的Template

    摘要:Template定义了问题的边界,子类定义了具体的实现,只要在模板的范围内玩耍就可以了. 本文分享自华为云社区<Spring 中的Template一次全理解,解析问题的本质>,作者: ...

  9. Kubernetes(K8S) yaml 介绍

    使用空格做为缩进 缩进的空格数目不重要, 只要相同层级的元素左侧对齐即可 低版本缩进时不允许使用 Tab 键, 只允许使用空格 使用#标识注释, 从这个字符一直到行尾, 都会被解释器忽略 --- 使用 ...

  10. Django rest_framework使用自定义异常

    完整代码 https://gitee.com/mom925/django-system 在settings.py中配置 REST_FRAMEWORK = { "EXCEPTION_HANDL ...