使用单口RAM实现FIFO,其实很简单,其中的重点就是区分出读写,

读写如果同时启动,你肯定会思考单口RAM肯定会出问题,毕竟单口RAM只有一个口,肯定不能实现同时读写,那么怎么解决这个问题呢。

有两种办法:

第一种办法就是采用两个单口RAM,这样就可以了,两个单口RAM分开奇偶,相当于乒乓的意思,然后再加一个REG,这就相当于把读写分开了

那么就可能分为以下几种情况:

①同时读写:读写同时为奇,这种情况就是在当前一拍,将写数据存入REG中,并将REG_VALID拉高告诉FIFO我下一拍要写数据,并在当前拍从奇数的FIFO中读取数据,那么下一拍如果再此发生同时读写,那么此时的同时读写就为偶,这一拍发生的情况就是将前一拍REG中的数据写入FIFO,然后将REG中数据更新新数据,然后将REG_VALID再拉高,告诉偶数FIFO下一拍要写数据了,并同时从偶数FIFO中取出要读的数据。

其实核心观点就是用两个单口RAM一个REG,用来区分最难的读写同时发生的情况,通过将RAM分为奇偶再加一个REG寄存器用来缓存,这就使不能同时读写的情况给解决了。

如果同时读写,且奇偶不同,那这种情况就更容易解决了,当前拍写数据的模块将数据写入REG,读模块的读出数据,然后下一拍将REG再写入单口RAM,和之前同时读写同时为奇偶的情况很相似。

②不同时读写:这种情况就是你只要写就先将数据写入REG,然后拉高VALID下一拍将REG中的数据写入单口RAM,如果读就直接读出数据。

通过这种方式就完美的解决了单口RAM没办法同时操作RAM的情况。

代码如下

`timescale 1ns / 1ps
//
// Company:
// Engineer: Brad
//
// Create Date: 2022/05/11 19:38:41
// Design Name:
// Module Name: FIFO_single_ram
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module FIFO_single_ram
#( parameter WIDTH = 8,parameter DEEPTH= 256
)
(input clk ,input rstn ,input [WIDTH-1:0] data,input wr,input rd,output reg [WIDTH-1:0] data_out,output full,output empty);//-------------下面是FIFO的操作------------------//reg [8:0] rd_cnt;  //多一位用来回卷判断空满reg [8:0] wr_cnt;reg [8:0] wr_cnt_r;wire [7:0] rd_addr;wire [7:0] wr_addr;wire [7:0] addr_odd;wire [7:0] addr_even;reg [WIDTH-1:0] data_reg;reg       reg_valid;reg       wr_flag; //用来判断读写的奇偶 0代表奇 1代表偶数reg       rd_flag;wire      wr_ram;  //用来判断是否可以写wire      rd_ram;  //用来判断是否可以读wire      wr_en_odd; //奇数写wire      wr_en_even;//偶数写wire      rd_en_odd; //奇数写wire      rd_en_even;//偶数写reg      rd_en_odd_r; //奇数写reg      rd_en_even_r;//偶数写wire [7:0] datao_odd;wire [7:0] datao_even;assign rd_addr = rd_cnt [7:0];assign wr_addr = wr_cnt_r [7:0];assign full = (wr_cnt[8]^rd_cnt[8])&&(wr_cnt[7:0]==rd_cnt[7:0]); //最高位不同 低位相同;assign empty= (wr_cnt == rd_cnt); //全等assign wr_ram = (~full)&(wr);assign rd_ram = (~empty)&(rd);
//    assign data_out = (rd_en_odd_r)? datao_odd:datao_even;always@(*) beginif(rd_en_odd_r)data_out = datao_odd;else if(rd_en_even_r)data_out = datao_even;elsedata_out = data_out;endalways@(posedge clk or negedge rstn)beginif(~rstn) beginwr_cnt <= 9'b0;data_reg <= {WIDTH{1'b0}};reg_valid <= 1'b0;wr_cnt_r <= 9'b0;endelse if(wr_ram)beginwr_cnt <= wr_cnt + 1'b1;data_reg <= data;reg_valid <= 1'b1;wr_cnt_r <= wr_cnt;endelsebeginreg_valid <= 1'b0;endendalways@(posedge clk or negedge rstn)beginif(~rstn)rd_cnt <= 9'b0;else if(rd_ram)rd_cnt <= rd_cnt + 1'b1;end//------------------------读写奇偶判断----------------------always@(posedge clk or negedge rstn) beginif(~rstn)wr_flag <= 1'b0;else if(reg_valid)wr_flag <=wr_flag + 1'b1; //往里面写数据的同时奇偶改变else wr_flag <= wr_flag ; //往里面读数据的同时奇偶改变endalways@(posedge clk or negedge rstn) beginif(~rstn)rd_flag <= 1'b0;else if(rd_ram)rd_flag <= rd_flag + 1'b1; //往里面读数据的同时奇偶改变elserd_flag <= rd_flag;end//--------------------RAM读写使能控制 分为奇偶两种类型always@(posedge clk or negedge rstn) beginif(~rstn)beginrd_en_odd_r <= 1'b0;rd_en_even_r <= 1'b0;endelsebeginrd_en_odd_r <= rd_en_odd;rd_en_even_r<=rd_en_even;endendassign wr_en_odd =(rd_en_odd)? 1'b0:( reg_valid & (~wr_flag));assign wr_en_even =(rd_en_even)? 1'b0:( reg_valid & (wr_flag));assign rd_en_odd = rd_ram & (~rd_flag);assign rd_en_even = rd_ram & (rd_flag);wire ena_odd = wr_en_odd | rd_en_odd;wire ena_even = wr_en_even | rd_en_even;assign addr_odd= (wr_en_odd)? wr_addr:rd_addr;assign addr_even= (wr_en_even)?wr_addr:rd_addr;SINGLE_RAM odd_ram (.clka(clk),    // input wire clka.ena(ena_odd),      // input wire ena.wea(wr_en_odd),      // input wire [0 : 0] wea.addra(addr_odd),  // input wire [7 : 0] addra.dina(data_reg),    // input wire [7 : 0] dina.douta(datao_odd)  // output wire [7 : 0] douta);SINGLE_RAM even_ram (.clka(clk),    // input wire clka.ena(ena_even),      // input wire ena.wea(wr_en_even),      // input wire [0 : 0] wea.addra(addr_even),  // input wire [7 : 0] addra.dina(data_reg),    // input wire [7 : 0] dina.douta(datao_even)  // output wire [7 : 0] douta);
endmodule

我这个代码没有做仔细的仿真,经过各位网友的提醒,改了几处,首先针对读写的时候对奇偶不同时操作,通过加了一个直通路解决,以防止下一拍写的时候漏掉数据。

并对这个代码进行了详细仿真,仿真代码如下:

第二种情况就是针对单口RAM的位宽进行变化,比如FIFO的读写数据位宽为8Bit,那么就针对RAM的位宽设置为FIFO位宽的两倍,外部加两个同等位宽的读写寄存器,通过将读写寄存器与外界读写和读写寄存器与RAM的交互实现FIFO的功能,比如对于同时读写的情况,在时钟上按2拍完成一次寄存器与RAM数据的交互,比如第一拍完成读,第二拍完成写,对于外界的接口而言数据是源源不断的从寄存器出来的,从而实现了单口RAM实现FIFO的功能,这种情况我仔细想了想只适用于 对FIFO连续读写的情况下才能使用,不连续读写总有一次会把其置成同时读写的情况。

FIFO专题之单口RAM实现FIFO(同步)相关推荐

  1. 基于 FPGA 的高级数字电路设计(7)单口 RAM、同步 FIFO、异步 FIFO 设计

    一.单口 RAM 设计 module BRAM_PORTA( input clka, input ena, input wea, input [3:0] addra, input [15:0] din ...

  2. 单口RAM、双口RAM、FIFO

    单口RAM.双口RAM.FIFO 单口与双口 单口与双口的区别在于,单口只有一组数据线与地址线,因此读写不能同时进行:而双口有两组数据线与地址线,读写可同时进行:FIFO读写可同时进行,可以看作是双口 ...

  3. FIFO、单口RAM、双口RAM的区别

    FPGA设计中,经常需要用存储器来存储数据,目前常用的存储器有FIFO和RAM,其中RAM又分单口RAM与双口RAM,那么它们各自有什么区别呢? 双口RAM:双口RAM 是在一个SRAM 存储器上具有 ...

  4. 单口RAM,双口RAM,FIFO的区别

    总结:单口ram只有一组数据线.地址线,不能同时读写:双口ram有两组数据线.地址线. 在电路上的区别就是在latch的两边有几个开关管. 单口与双口的区别在于,单口只有一组数据线与地址线,因此读写不 ...

  5. 伪双口ram工作原理单口及RAM、伪双口RAM、双口RAM与FIFO的区别

    FPGA时序时序分析中的基本概念 FPGA设计中,常用到的数据缓存IP有FIFO和RAM,其中RAM又分单口RAM.伪双口RAM.双口RAM. 伪双口ram的工作原理,开始的时候以为有两个wea使能信 ...

  6. 单口RAM、伪双口RAM、双口RAM与FIFO的区别

    单口RAM.伪双口RAM.双口RAM与FIFO的区别 FPGA设计中,常用到的数据缓存IP有FIFO和RAM,其中RAM又分单口RAM.伪双口RAM.双口RAM.        单口与双口的区别在于, ...

  7. 单口RAM、双口RAM、FIFO三者的关系

    单口与双口 单口与双口的区别在于,单口只有一组数据线与地址线,因此读写不能同时进行:而双口有两组数据线与地址线,读写可同时进行:FIFO读写可同时进行,可以看作是双口: 简单双口RAM与真双口RAM ...

  8. 单口RAM、伪双口RAM、真双口RAM、单口ROM、双口ROM的区别

    单口RAM与伪双口RAM.真双口RAM的区别在于: 单口RAM只有一个时钟(clka)(时钟上升沿到来时对数据进行写入或读出).一组输入输出数据线(dina&douta).一组地址线(addr ...

  9. 循环卷积和周期卷积的关系_基于单口RAM读写的卷积电路(下)

    这是迟到很久的卷积电路verilog设计的下篇...你看我还有机会吗... 上回我们给出系统的层次结构.卷积计算模块以及用于数据缓存的fifo模块,今天我们首先回顾一下上一次的关键内容. 系统结构回顾 ...

最新文章

  1. st-link和jlink调试stm32接线注意事项
  2. 蓝桥杯java第七届决赛第四题--路径之谜
  3. adf检验代码 python_第22期:向量自回归(VAR)模型预测——Python实现
  4. MapReduce源代码浅析
  5. 揭秘:美国警方监控技术大曝光
  6. WHENEVER SQLERROR EXIT SQL.SQLCODE
  7. 光端机与光纤收发器的应用
  8. servlet中用out.print输出中文为“乱码”如何解决
  9. web开发方法_确保进入Web开发的最快方法
  10. 华为 MateBook 笔记本 Linux 版正式开售
  11. mysql math.max_Math.max.apply()用法
  12. 排列(permutation)的末尾 0 的个数
  13. Atitit 开发效率大法 v0 t025.docx Atitit 提升开发效率几大策略 目录 1. 提升效率三原则 3 1.1. 更少的代码量简化 3 1.2. 优化配置减少等待 3 1.3.
  14. 计算机毕业论文性能测试怎么写,计算机专业毕业论文写作指导方法
  15. (6)微信运动点赞(下)-JsDroid引流脚本混合式开发技术系列教程By飞云脚本学院
  16. Xcode隐藏SDK C、C++、Objective-C符号
  17. cad.net 块裁剪边界反向修剪
  18. mysql_帮助命令/通配搜索/help help用法(official doc)
  19. 速看四川省企业技术中心拟认定名单已发布,共181家
  20. SASL - 简单认证和安全层

热门文章

  1. 金融智能监管,将会是人工智能应用的风口?
  2. 【PHP+微信开发】之微信扫码登录
  3. KingbaseES共享集群中crm_mon命令失效原因分析
  4. 惊呆了!被公司辞退拿了 22 万补偿金,原东家称每月涨薪 7000,只要退还 22 万...
  5. 零基础JavaScript入门(第三天)
  6. python学生信息管理系统-增删改查-根据姓名查询
  7. Java实现——华容道数字小游戏
  8. HTML-CSS小知识——box-shadow的使用
  9. Excel2016中如何取消设置的筛选条件
  10. setTabBarBadge在非tabBar页面设置