单端口RAM实现FIFO

2023-11-10

RAM分类
单口ram:
在这里插入图片描述
单端口RAM只有一组数据线和一组地址线,只有一个时钟,读写共用地址线。输出只有一个端口。所以单端口RAM的读写操作不能同时进行。当wea拉高时,会将数据写入对应的地址,同时douta输出的数据与此时写入的数据是一致的,因此在读的时候需要重新生成对应的读地址给addra,并且disable掉wea。

module single_ram
(	
	input clk,
	input rstn,
	input enable_wr,
	input [7:0] addr,
	input [7:0]data,
	output reg[7:0]data_out
);
reg [7:0] mem [255:0];
always @(posedge clk, negedge rstn) begin
	if(!rst) begin
		data_out<='b0;
	end
	else if(enable_wr)begin
		data_out<=mem[addr];
	end
end

always @(posedge clk, negedge rstn) begin
	if(!enable_wr)begin
		mem[addr]<=data;
	end
end
endmodule

伪双口RAM
在这里插入图片描述
输入只有一组数据线,两组地址线,两个时钟。
所以一个端口只读,一个端口只写,但是写入和读取的时钟可以不同,且位宽比可以不是1:1。即允许写A的同时读B,且速率可以不相同。

module single_ram
(	
	input wrclk,
	input rstn,
	input wr,
	input [7:0] wr_addr,
	input [7:0]data,
	input rd_clk,
	input [7:0] rd_addr,
	input rd_en,
	output reg[7:0]data_out
);
reg [7:0] mem [255:0];
reg [7:0] i;
always @(posedge wr_clk, negedge rstn) begin
	if(!rstn) begin
		for(i='b0;i<256;i=i+1'b1)
			mem[i]<='b0;
	end
	else if(enable_wr)begin
		mem[wr_addr]<=data;
	end
end

always @(posedge rd_clk, negedge rstn) begin
	if(!rstn) begin
		data_out<='b0;
	end
	else if(rd_en)begin
		data_out<=mem[rd_addr];
	end
	else 
		data_out<=data_out;
end
endmodule

**真双口RAM:**有两组地址线和数据线,两个时钟。
输出有两个分别的数据线。
所以双口RAM两个端口都分别带有读写端口,可以在没有干扰的情况下进行读写,彼此互不干扰。
在这里插入图片描述

module double_ram(
	rst_n,
	cs_n,//片选信号,低有效
	//A port write signals 
	clk_a,
	wrdata_a,
	wraddr_a,
	wrena_n,
	//B port read signals 
	clk_b,
	rdaddr_b,
	rdenb_n,
	rddata_b);

parameter ADDR_WIDTH=7;
parameter DATA_WIDTH=16;
parameter DATA_DEPTH=128;
input clk_a;     // input signal  default type wire 
input clk_b;
input rst_n;
input cs_n;

input [DATA_WIDTH-1:0]wrdata_a;
input [ADDR_WIDTH-1:0]wraddr_a;
input wrena_n;

input [ADDR_WIDTH-1:0]rdaddr_b;
input rdenb_n;
output [DATA_WIDTH-1:0]rddata_b;

reg    [DATA_WIDTH-1:0]rddata;
integer i;
reg [DATA_WIDTH-1:0] mem [DATA_DEPTH-1:0];// 定义一个位宽为DATA_WIDTH,深度为DATA_DEPTH的存储器
always@(posedge clk_a or negedge rst_n) begin 
	if(~rst_n) begin 
		for(i=0;i<DATA_DEPTH;i=i+1)
		mem[i]<=0;
	end 
	else if(cs_n==1'b0 & wrena_n==1'b0 )//片选和写信号均低有效
	mem[wraddr_a]<=wrdata_a; //写入
end 
always@(posedge clk_b or negedge rst_n)begin 
	if(~rst_n)begin 
	rddata<=0;
	end 
	else if(cs_n==1'b0 & rdenb_n==1'b0)begin 
	rddata<=mem[rdaddr_b];
	end
	else 
	rddata<=rddata;
end 
assign rddata_b=rddata;
endmodule

单口RAM实现异步FIFO:
重点区分出同时读写。
第一种办法:采用两个单口RAM,两个单口RAM分开奇偶,相当于乒乓意思,然后再加一个REG,这样就把REG分开了。我的思路是遇到同时读写的时候就对写打一拍这个时候是对奇ram写入,然后下一拍在遇到同时读写那么同样打一拍后对偶ram写入
那么可能分为以下几种情况:
①同时读写:读写同时为奇,这种情况就是在当前一拍,将写数据存入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的情况。
————————————————
版权声明:本文为CSDN博主「Brad.Ji」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Bradji/article/details/124717180

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@(*) begin
    if(rd_en_odd_r)
        data_out = datao_odd;
    else if(rd_en_even_r)
        data_out = datao_even;
    else
        data_out = data_out;
    end
    always@(posedge clk or negedge rstn)begin
    if(~rstn) begin
        wr_cnt <= 9'b0;
        data_reg <= {WIDTH{1'b0}};
        reg_valid <= 1'b0;
        wr_cnt_r <= 9'b0;
        end
    else if(wr_ram)
        begin
        wr_cnt <= wr_cnt + 1'b1;
        data_reg <= data;
        reg_valid <= 1'b1;
        wr_cnt_r <= wr_cnt;
        end
    else if(!rd_en_odd & reg_valid & (~wr_flag))
        begin
        reg_valid <= 1'b0;
        end
	else if(!rd_en_even & reg_valid & (~wr_flag))
        begin
        reg_valid <= 1'b0;
        end
	
    end
    always@(posedge clk or negedge rstn)begin
    if(~rstn)
        rd_cnt <= 9'b0;
    else if(rd_ram)
        rd_cnt <= rd_cnt + 1'b1;
    end
 
    //------------------------读写奇偶判断----------------------
    always@(posedge clk or negedge rstn) begin
    if(~rstn)
        wr_flag <= 1'b0;
    else if(reg_valid)
        wr_flag <=wr_flag + 1'b1; //往里面写数据的同时奇偶改变
    else 
        wr_flag <= wr_flag ; //往里面读数据的同时奇偶改变
    end
    always@(posedge clk or negedge rstn) begin
    if(~rstn)
        rd_flag <= 1'b0;
    else if(rd_ram)
        rd_flag <= rd_flag + 1'b1; //往里面读数据的同时奇偶改变
    else
        rd_flag <= rd_flag;
    end
    //--------------------RAM读写使能控制 分为奇偶两种类型
    always@(posedge clk or negedge rstn) begin
    if(~rstn)begin
        rd_en_odd_r <= 1'b0;
        rd_en_even_r <= 1'b0;
        end
    else
    begin
        rd_en_odd_r <= rd_en_odd;
        rd_en_even_r<=rd_en_even;
    end
    end
    
	assign rd_en_odd = rd_ram & (~rd_flag);
    assign rd_en_even = rd_ram & (rd_flag);
    assign 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));

    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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单端口RAM实现FIFO 的相关文章

  • FPGA零基础学习之Vivado-ROM使用教程

    FPGA零基础学习之Vivado ROM使用教程 本系列将带来FPGA的系统性学习 从最基本的数字电路基础开始 最详细操作步骤 最直白的言语描述 手把手的 傻瓜式 讲解 让电子 信息 通信类专业学生 初入职场小白及打算进阶提升的职业开发者都
  • 数字IC手撕代码-兆易创新笔试真题

    前言 本专栏旨在记录高频笔面试手撕代码题 以备数字前端秋招 本专栏所有文章提供原理分析 代码及波形 所有代码均经过本人验证 目录如下 1 数字IC手撕代码 分频器 任意偶数分频 2 数字IC手撕代码 分频器 任意奇数分频 3 数字IC手撕代
  • 数字芯片流程

    芯片设计分为前端设计和后端设计 前端设计 逻辑设计 和后端设计 物理设计 并没有同意严格的界限 这个过程中涉及到了与工艺有关的设计就是后端设计 一 需求分析 产品需要解决的问题 预测3 5年的趋向和走势 确保前瞻性 确保芯片是有卖点的 客户
  • 平头哥(T-Head )开源RISCV处理器OpenC906 RTL仿真

    在过去的几年里 阿里集团平头哥陆续推出了几款RISCV处理器 有些处理器已经在产业界得到了应用 比如在某志的D1处理器中 就嵌入了平头哥的玄铁C906内核为 芯 RISCV虽然是一个开放标准 并且网络上也不乏一些开源核的RTL实现 但是商用
  • DDR的VTT有源端接和无源端接(slua886a笔记)

    DDR的VTT有源端接和无源端接 slua886a笔记 背景 对于DDR的VTT端接 一直有说法是有源端接可降低功耗 之前一直没仔细理解其中原因 现在找了些相关的资料来介绍和对比有源和无源端接 理解有源端接的优点和降低功耗的原理 主要基于读
  • modelsim 关联 notepad++

    modelsim 控制窗口敲入 1 proc external editor filename linenumber exec I notepad notepad exe filename 2 set PrefSource altEdito
  • 手把手教你Modelsim仿真【2020.4版本】

    首先新建一个文件夹 test5 打开Modelsim 依次选择 File gt Change Directory 把目录选择到创建的 test5 文件夹 创建库 依次选择 File gt New gt Library 一般我们选择第三个 库
  • 数码管电子时钟

    文章目录 前言 一 回顾数码管 二 任务描述 三 系统框图 四 模块调用 五 模块原理图 六 工程源码 6 2 时钟计数模块代码 6 2 数码管驱动模块代码 6 3 顶层模块代码 七 仿真测试 7 1 测试代码 7 2 仿真结果 八 管脚信
  • FIFO读写控制

    如果在两个模块之间传输数据 两个模块之间的处理速率不同 会导致采集数据的遗漏或错误 在他们之间加一个数据缓存器 所有数据先经过缓存器缓存 再输入数据接送模块 创建两个模块 一个 作为发送模块 一个作为接受模块 发送模块检测到 fifo为空开
  • 小梅哥Xilinx FPGA学习笔记9——语法(阻塞与非阻塞赋值)

    阻塞赋值与非阻塞赋值详解 注意 阻塞赋值 1 设计文件 2 激励文件 3 原理图 4 仿真图 非阻塞赋值 1 设计文件 2 激励文件 3 原理图 4 仿真图 注意 阻塞赋值与非阻塞赋值 只有在时序逻辑中才有 不是阻塞赋值 也不是非阻塞赋值
  • FPGA硬件工程师Verilog面试题(基础篇二)

    作者简介 大家好我是 嵌入式基地 是一名嵌入式工程师 希望一起努力 一起进步 个人主页 嵌入式基地 系列专栏 FPGA Verilog 习题专栏 微信公众号 嵌入式基地 FPGA硬件工程师Verilog面试题 二 习题一 多功能数据处理器
  • xilinx xdma PCIe中断bug

    xilinx xdma PCIe中断存在bug bug1 此中断虽然是msi或者msx中断 但是不中断cpu bug2 此中断不是边沿中断 而是电平中断 在驱动层需要不断地轮训查询中断事件 bug3 此中断持续时间必须长 而且在收到中断应答
  • BUCK电路分析(二)

    BUCK电路分析 二 PSIM仿真同步BUCK电路 在上片文章中 初步的分析了BUCK电路的工作原理 本章使用PSIM软件仿真BUCK电路 观察分析BUCK电路器件关键波形 图1是同步BUCK电路图 开关频率设置为200K 固定占空比 在仿
  • 使用七牛云进行文件上传

    目录 一 七牛云入门测试 1 注册七牛云账号 完成后选择对象存储 2 在里面创建空间 一个空间相当于一个文件夹 就是将对象上传到的地方 3 查看个人秘钥 注册完成账号后 会有一个秘钥 上传文件的时候进行授权和认证 4 文件上传测试 二 封装
  • ALLEGRO等长时如何将PIN DELAY和VIA长度计算在内

    在PCB设计中 对于时序要求严格的线路 Via和IC pin delay的长度必须得到重视 通过下面的操作 可将Via和Pin delay加入到线路长度的计算中 1st 计算Pin delay 打开Constraint Manager 选择
  • 【FPGA多周期时序约束详解】- 解读FPGA多周期时序约束的全过程

    FPGA多周期时序约束详解 解读FPGA多周期时序约束的全过程 FPGA作为数字电路设计的常见工具 其设计中必然会遇到时序约束的问题 而多周期时序约束更是FPGA设计中不可避免的难点之一 本文将详细介绍FPGA多周期时序约束的全过程 并结合
  • 【FMC141】基于VITA57.4标准的4通道2.8GSPS 16位DA播放子卡(2片DAC39J84)

    FMC141是一款基于VITA57 4标准的4通道2 8GSPS 2 5GSPS 1 6GSPS采样率16位DA播放FMC子卡 该板卡为FMC 标准 符合VITA57 4与VITA57 1规范 16通道的JESD204B接口通过FMC 连接
  • [Verilog] Verilog 基本格式和语法

    主页 元存储博客 全文 3000 字 文章目录 1 声明格式 1 1 模块声明 1 2 输入输出声明 1 3 内部信号声明 1 4 内部逻辑声明
  • Matlab图像处理系列——图像复原之噪声模型仿真

    微信公众号上线 搜索公众号 小灰灰的FPGA 关注可获取相关源码 定期更新有关FPGA的项目以及开源项目源码 包括但不限于各类检测芯片驱动 低速接口驱动 高速接口驱动 数据信号处理 图像处理以及AXI总线等 本节目录 一 图像复原的模型 二
  • MINI-UTDE 10 BASE-T 集成控制器

    MINI UTDE 10 BASE T 集成控制器 MINI UTDE 10 BASE T 拥有多达三个本地I O板和远程I OS总线通信 为用户提供了一系列生产单元功能的单一控制点 包括诸如夹头 反馈器和辅助机器等外围生产设备 支持所有主

随机推荐

  • 个人笔记篇-SpringBoot集成Socket

    前言 在我的另一篇文章中 有简单介绍过Socket的相关概念链接 SpringBoot简单集成WebSocket 初步了解后 本次再进行一个深入通俗的理解 Socket作为一种通信机制 通常也被称为 套接字 它类似于人们之间的 打电话行为
  • golang学习笔记

    目录 golang学习笔记 golang知识点 go打开本地文档方法 fmt 打印占位符特殊作用 slice本质 strings包 Stringer Interface golang学习笔记 go官方学习内容是最好最权威的入门go语言的资料
  • 2021最新Java笔试题及答案,Java面试真题精选

    二 回顾整理阿里面试题 基本就这样了 还有一些零星的问题想不起来了 答案也整理出来了 自我介绍 JVM如何加载一个类的过程 双亲委派模型中有哪些方法 HashMap如何实现的 HashMap和ConcurrentHashMap区别 Conc
  • 【安全开发】python—基于正则表达式的爬虫

    0x00 前置 1 搜索引擎 百度 谷歌 企业内部知识库 2 互联网 公网 无需授权 深网 需要授权 暗网 非正式渠道 无法使用常规手段访问 友情提醒 没事别看 3 规则 爬取互联网公开的信息 但正常情况也需要遵守robots协议 网络爬虫
  • 【华为OD机试 2023 B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • Qt Graphics View Framework 图形视图框架

    QT的2D绘图我们使用QPainter实现少量绘图是很理想的 但是如果是要绘制大量的2D图形并且需要能够控制管理时就会显得力不从心 好在QT视图体系提供了QGraphics View Framework的框架 使用这个框架可以将各图形项进行
  • MySQL 8.0用户管理

    1 禁止root用户远程访问 1 在安装MySQL数据库软件时 我们已经设置了禁止root远程登录 参见 https blog csdn net chengyuqiang article details 121282247 2 root用户
  • Kubernetes (k8s 1.23) 安装与卸载

    镜像下载 域名解析 时间同步请点击 阿里云开源镜像站 请注意k8s在1 24版本不支持docker容器 本文使用kubeadm进行搭建 1 查看系统版本信息以及修改配置信息 1 1 安装k8s时 临时关闭swap 如果不关闭在执行kubea
  • MySQL的sum函数优化

    有一张表 结构如下 Field Type Null Key Default Extra ID bigint 20 NO PRI NULL auto increment
  • 51单片机开发问题之不能直接对端口管脚输出高低点电平

    在做51单片机点亮一个了led的时候遇到一个问题 不能直接用P0 0 0 对单片机管脚输出高低电平 Keil编译器会报错 如图 用sbit定义一个变量来控制管脚就行
  • 网络安全学习路线是怎样的?从入门到入坟,看这篇就够了

    为什么要学习安全 近几年网络安全事件层出不穷 相信大家哪怕没遇到过 但也听过不少了吧 如服务器遭受入侵被黑 用户帐号被盗 被钓鱼 勒索病毒等 这些一旦发生 对企业而言都是不小的打击 因此 网络安全不容忽视 同时随着时代的不断发展 公司对于运
  • DOM0和DOM2

    DOM事件绑定 DOM0级事件 特点 所有的浏览器都支持 事件只能注册一次 后面的会覆盖旧的 注册方式 1 在html上添加 div div 其中this指向自身 2 匿名函数d nclick function 其中 this 指向自身 3
  • 美国科技大佬成功之前混得都有多惨

    摘要 超过三分之一在美国成立的顶尖高科技公司是由在国外出生的人创立的 他们的成功经验带动许多移民来到美国实现美国梦的希望 id cproIframe u1503021 2 width 250 height 250 src http pos
  • 使用DBN实现风速预测matlab代码

    使用DBN实现风速预测matlab代码 风速预测在实际生产生活中有着广泛的应用 对于风电场 农业灌溉 城市规划等领域都有着重要的意义 本文将介绍如何使用深度信念网络 Deep Belief Networks DBN 来实现风速预测 并提供相
  • Mysql数据库的导入和导出

    Mysql数据库的导入和导出 1 导入 2 导出 Mysql数据库的可移植性是比较好的 在命令行状态下可用仅仅一行的代码就实现数据库的导入和导出 不论是在Windows操作系统还是Linux操作系统下的命令行 命令基本上完全一致 1 导入
  • QT主窗口与子窗口互相传值笔记

    1 主窗口向子窗口传值 将子窗口定义为主窗口的成员变量 在子窗口中定义接受数据的成员变量 主窗口中可以使用子窗口成员变量来访问他的成员变量 于是就能直接赋值了 void Main wgt test son wgt num 18 2 子窗口向
  • PAT 1015 德才论 (25分) C语言实现

    1015 德才论 25分 宋代史学家司马光在 资治通鉴 中有一段著名的 德才论 是故才德全尽谓之圣人 才德兼亡谓之愚人 德胜才谓之君子 才胜德谓之小人 凡取人之术 苟不得圣人 君子而与之 与其得小人 不若得愚人 现给出一批考生的德才分数 请
  • 将文件或目录移动到另外的目录

    File or directory to be moved File file new File filename Destination directory File dir new File directoryname Move fil
  • Flutter编译卡在Running Gradle task ‘assembleDebug‘

    为什么卡在这一步 把网络断开 发现了问题 卡在了下载运行环境和依赖库的步骤 jcenter 下载速度太慢 知道原因就好办了 需要修改3个地方 1 首先找到fultter sdk所在文件夹的位置 依次进入 flutter packages f
  • 单端口RAM实现FIFO

    RAM分类 单口ram 单端口RAM只有一组数据线和一组地址线 只有一个时钟 读写共用地址线 输出只有一个端口 所以单端口RAM的读写操作不能同时进行 当wea拉高时 会将数据写入对应的地址 同时douta输出的数据与此时写入的数据是一致的