FPGA逻辑设计回顾(12)RAM以及ROM的RTL设计及其验证
前言
本文首发:FPGA逻辑设计回顾(12)RAM以及ROM的RTL设计及其验证
RAM以及ROM在FPGA中的实现大体有两种方式,一种是使用IP核定制,一种是RTL设计。
也许有人会反驳,那原语呢?
我不喜欢讨论这个问题,原语你去使用吗?如果你真的喜欢,请自便。
下面我们讨论这两种实现方式:
首先是RTL的设计,这种方式中,我们重点在于实现逻辑设计。
在IP核的定制中,我们将分别定制一种简单的RAM和ROM的IP核,并讨论它们使用中的一些参数注意事项。(这种方式,下一节讨论)
RAM的RTL设计
RAM的实现分类
在RAM的实现中,我们根据数据是否与时钟同步,分为同步RAM以及异步RAM,如果继续细分地话,我们可以将RAM分为同步读同步写,同步读异步写,异步读,异步写等等组合,但这就没什么意思了,我会给出同步以及异步示例。
同步RAM
我们这里的同步RAM,就是RAM的读写和时钟同步,为了和后面使用IP核定制的方式尽量一致,我们本篇文章统统使用一种位宽,一种深度,端口信号也尽量一致(这包括数量以及命名)。
双端口同步读写
`timescale 1ns / 1ps
//
// Engineer: 李锐博恩
// Create Date: 2021/01/31 02:46:06
// Module Name: dual_ram
//module dual_ram#(parameter WIDTH = 16,parameter DEPTH = 4)(//ainput wire clka,input wire rst,input wire ena,input wire wea,input wire [DEPTH - 1 : 0] addra,input wire [WIDTH - 1 : 0] dina,output reg [WIDTH - 1 : 0] douta,//binput wire clkb,input wire enb,input wire web,input wire [DEPTH - 1 : 0] addrb,input wire [WIDTH - 1 : 0] dinb,output reg [WIDTH - 1 : 0] doutb );//双端口RAMreg [WIDTH - 1 : 0] dual_ram[DEPTH - 1 : 0];//写integer i;always@(posedge clka or posedge rst) beginif(rst) beginfor(i = 0; i <= DEPTH - 1; i = i + 1) begin: initial_adual_ram[i] <= 'd0;endendelse if(ena && wea) begindual_ram[addra] <= dina;endelse if(enb && web) begindual_ram[addrb] <= dinb;endelse begin//保持endend//a端口读always@(posedge clka) beginif(ena && ~wea) begindouta <= dual_ram[addra];endelse begindouta <= 'd0;endendalways@(posedge clkb) beginif(enb && ~web) begindoutb <= dual_ram[addrb];endelse begindoutb <= 'd0;endendendmodule
这种写法简单易懂,且在平时练习的过程中尽量使用参数化的方式,养成习惯,不要怕麻烦,这样会让你在以后的工作中受益!
验证则尽量简单化:
`timescale 1ns / 1ps
//
// Engineer: 李锐博恩
// Create Date: 2021/01/31 02:46:06
// Module Name: dual_ram_tb
//module dual_ram_tb();parameter WIDTH = 16;parameter DEPTH = 4;parameter PERIOD_A = 4;parameter PERIOD_B = 5;reg clka;reg rst;reg ena;reg wea;reg [DEPTH - 1 : 0] addra;reg [WIDTH - 1 : 0] dina;wire [WIDTH - 1 : 0] douta;//breg clkb;reg enb;reg web;reg [DEPTH - 1 : 0] addrb;reg [WIDTH - 1 : 0] dinb;wire [WIDTH - 1 : 0] doutb;initial beginclka = 0;forever begin# (PERIOD_A/2) clka = ~clka;endend initial beginclkb = 0;forever begin# (PERIOD_B/2) clkb = ~clkb;endendinitial beginrst = 1;ena = 0;enb = 0;wea = 0;web = 0;addra = 0;addrb = 0;dina = 0;dinb = 0; repeat(15);@(posedge clka);rst = #(0.1 * PERIOD_A) 0;//a端口连续写两个数据repeat(10);@(posedge clka);addra = #(0.1 * PERIOD_A) 'd0;dina = #(0.1 * PERIOD_A) $random; @(posedge clka);ena = #(0.1 * PERIOD_A) 1;wea = #(0.1 * PERIOD_A) 1;@(posedge clka);addra = #(0.1 * PERIOD_A) 'd1;dina = #(0.1 * PERIOD_A) $random;@(posedge clka);//b端口读两个数据repeat(10);@(posedge clkb);addrb = #(0.1 * PERIOD_B) 'd0; @(posedge clkb);enb = #(0.1 * PERIOD_B) 1;web = #(0.1 * PERIOD_B) 0;@(posedge clkb);addrb = #(0.1 * PERIOD_B) 'd1;enddual_ram#(.WIDTH ( WIDTH ),.DEPTH ( DEPTH ))u_dual_ram(.clka ( clka ),.rst ( rst ),.ena ( ena ),.wea ( wea ),.addra ( addra ),.dina ( dina ),.douta ( douta ),.clkb ( clkb ),.enb ( enb ),.web ( web ),.addrb ( addrb ),.dinb ( dinb ),.doutb ( doutb ));endmodule
如下是仿真时序图:
RTL原理图:
综合原理图:
表明可综合设计。
异步RAM
异步RAM,意思就是不需要时钟同步的RAM,给出RTL设计:
`timescale 1ns / 1ps
//
// Engineer: 李锐博恩
// Create Date: 2021/01/31 02:46:06
// Module Name: asy_ram
//module asy_ram#(parameter DATA_WIDTH = 16,
parameter RAM_DEPTH = 4)(//ainput wire ena,input wire wea,input wire [RAM_DEPTH - 1 : 0] addra,input wire [DATA_WIDTH - 1 : 0] dina,output reg [DATA_WIDTH - 1 : 0] douta,//binput wire enb,input wire web,input wire [RAM_DEPTH - 1 : 0] addrb,input wire [DATA_WIDTH - 1 : 0] dinb,output reg [DATA_WIDTH - 1 : 0] doutb );//--------------Internal variables---------------- reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];//initialization// synopsys_translate_off
integer i;
initial beginfor(i=0; i < RAM_DEPTH; i = i + 1) beginmem[i] = 8'h00;end
end
// synopsys_translate_on//--------------Code Starts Here------------------
// Memory Write Block
// Write Operation : When we_0 = 1, cs_0 = 1
always @ (*)
begin : MEM_WRITEif ( ena && wea ) beginmem[addra] = dina;end else if (enb && web) beginmem[addrb] = dinb;end
end// Memory Read Block
// Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
always @ (*)
begin : MEM_READ_aif (ena && ~wea) begindouta = mem[addra]; end else begindouta = 0; end
end //Second Port of RAM
always @ (*)
begin : MEM_READ_bif (enb && ~web) begindoutb = mem[addrb]; end else begindoutb = 0; end
end endmodule
综合后的原理图:
表明可综合。
仿真就利用同步RAM的仿真,改下例化,时钟只是一个时间尺度,可以不拉出来:
`timescale 1ns / 1ps
//
// Engineer: 李锐博恩
// Create Date: 2021/01/31 02:46:06
// Module Name: dual_ram_tb
//module dual_ram_tb();parameter WIDTH = 16;parameter DEPTH = 4;parameter PERIOD_A = 4;parameter PERIOD_B = 5;reg clka;reg rst;reg ena;reg wea;reg [DEPTH - 1 : 0] addra;reg [WIDTH - 1 : 0] dina;wire [WIDTH - 1 : 0] douta;//breg clkb;reg enb;reg web;reg [DEPTH - 1 : 0] addrb;reg [WIDTH - 1 : 0] dinb;wire [WIDTH - 1 : 0] doutb;initial beginclka = 0;forever begin# (PERIOD_A/2) clka = ~clka;endend initial beginclkb = 0;forever begin# (PERIOD_B/2) clkb = ~clkb;endendinitial beginrst = 1;ena = 0;enb = 0;wea = 0;web = 0;addra = 0;addrb = 0;dina = 0;dinb = 0; repeat(15);@(posedge clka);rst = #(0.1 * PERIOD_A) 0;//a端口连续写两个数据repeat(10);@(posedge clka);addra = #(0.1 * PERIOD_A) 'd0;dina = #(0.1 * PERIOD_A) $random; @(posedge clka);ena = #(0.1 * PERIOD_A) 1;wea = #(0.1 * PERIOD_A) 1;@(posedge clka);addra = #(0.1 * PERIOD_A) 'd1;dina = #(0.1 * PERIOD_A) $random;@(posedge clka);//b端口读两个数据repeat(10);@(posedge clkb);addrb = #(0.1 * PERIOD_B) 'd0; @(posedge clkb);enb = #(0.1 * PERIOD_B) 1;web = #(0.1 * PERIOD_B) 0;@(posedge clkb);addrb = #(0.1 * PERIOD_B) 'd1;endasy_ram#(.DATA_WIDTH ( 16 ),.RAM_DEPTH ( 4 ))u_asy_ram(.ena ( ena ),.wea ( wea ),.addra ( addra ),.dina ( dina ),.douta ( douta ),.enb ( enb ),.web ( web ),.addrb ( addrb ),.dinb ( dinb ),.doutb ( doutb ));endmodule
仿真波形图:
ROM的RTL设计
ROM的设计就更简单了,不用考虑写,一次性写入,剩下的都是读的问题了。
给出RTL设计:
module Rom_RTL(input [7:0] address , // Address inputoutput [7:0] data , // Data outputinput read_en , // Read Enable input ce // Chip Enable);reg [7:0] mem [0:255] ; assign data = (ce && read_en) ? mem[address] : 8'b0;initial begin$readmemb("F:/Prj_blog/vivado_csdn/prj_mem/prj_mem.srcs/sources_1/new/memory.list", mem); // memory_list is memory fileendendmodule
仿真平台:
`timescale 1ns / 1psmodule rom_using_file_tb;reg [7:0] address;reg read_en, ce;wire [7:0] data;integer i;initial beginaddress = 0;read_en = 0;ce = 0;//#10 $monitor ("address = %h, data = %h, read_en = %b, ce = %b", address, data, read_en, ce);for (i = 0; i < 256; i = i + 1 )begin#5 address = i;read_en = 1;ce = 1;#5read_en = 0;ce = 0;address = 0;endendRom_RTL u_Rom_RTL(.address ( address ),.data ( data ),.read_en ( read_en ),.ce ( ce )
);endmodule
由于,memory.list文件内容是0,1,2,3,…
因此,仿真内容也符合预期。
给出综合后的原理图:
证明可综合!
最后,大家可能会有疑问?说ROM的设计中用到了一个系统函数:readmemb,这东西能综合?
其实,这还真是要取决于综合工具,我找出了一个解释:
Altera的“推荐的HDL编码样式”指南包括示例10-31(第10-38页),该示例演示了从中推断出的ROM $readmemb(如下所示):
module dual_port_rom (input [(addr_width-1):0] addr_a, addr_b,input clk, output reg [(data_width-1):0] q_a, q_b
);parameter data_width = 8;parameter addr_width = 8;reg [data_width-1:0] rom[2**addr_width-1:0];initial // Read the memory contents in the file// dual_port_rom_init.txt. begin$readmemb("dual_port_rom_init.txt", rom);endalways @ (posedge clk)beginq_a <= rom[addr_a];q_b <= rom[addr_b];end
endmodule
同样,Xilinx的XST用户指南指出:
该readmemb和readmemh系统任务可以用来初始化块存储器。有关更多信息,请参见:
从外部文件初始化RAM的示例
使用readmemb二进制和readmemh十六进制表示。为了避免XST和模拟器行为之间可能的差异,Xilinx®建议您在这些系统任务中使用索引参数。请参见以下编码示例。
$readmemb("rams_20c.data",ram, 0, 7);
因此,对于存储器的初始化,这样做是没问题的。
FPGA逻辑设计回顾(12)RAM以及ROM的RTL设计及其验证相关推荐
- FPGA逻辑设计回顾(11)FPGA以及PC中的RAM与ROM
文章目录 前言 RAM以及ROM在计算机中的应用 什么是存储器? 什么是硬盘驱动器? 其他类型的存储器 什么是RAM? RAM的类型 SRAM DRAM 什么是ROM? ROM的类型 掩膜ROM PR ...
- 经典网页设计:12个优秀的电子商务网站设计案例
现在越来越多的人喜欢在网上购物,像美容护肤,数码,电器,品牌服饰,家居生活,健康保健等各种生活用品都可以轻松网购.对于电子商务网站来说,让用户在购物过程中简单快捷是最重要的,其次是要有精美的页面设计以 ...
- 【架构设计】————12、网购秒杀系统架构设计案例分析
12.1 秒杀活动的技术挑战 12.2. 秒杀系统的应对策略 参见:<网站设计架构:核心原理与案例分析>
- UI(1)---手机界面设计中12种常用布局
手机界面设计中12种常用布局 手机界面设计中12种常用布局 转载自: 手机界面设计中12种常用布局 - 轩枫阁 总结下手机界面改版要考虑的布局,主要的分为以下2大类 主导航 列表式 陈列馆式 九宫馆式 ...
- 12个学习 CSS3 网站布局设计的优秀案例
网络上有很多的 CSS 画廊站点供大家对各类网站作品进行打分和评论,每天有数以百计的优秀网站被推荐上面,这对于网页设计师来说是很好的灵感来源.今天,我们选择了15赢得 CSS 设计大奖的优秀作品,帮助 ...
- FPGA逻辑设计回顾(13)RAM以及ROM的IP核定制以及关键参数
文章目录 前言 RAM IP的定制 Xilinx的IP定制位置 Block RAM的定制过程 第一页 第二页 第三页 第四页 第五页 Block RAM的延迟讨论 ROM IP核的定制 总结 前言 本 ...
- FPGA逻辑设计回顾(9)DDR的前世今生以及演变过程中的技术差异
文章目录 前言 DDR的前世SDRAM DDR的今生以及演变版本:DDR/DDR2/DDR3 DDR/DDR2/DDR3/DDR4之间简单对比 速度对比 电压对比 延迟对比 预取差异 电阻端接对比 物 ...
- FPGA逻辑设计回顾(1)新手易犯的逻辑综合错误之always块
前言 注:本文首发自FPGA逻辑设计回顾(1)新手易犯的逻辑综合错误之always块 本文中用到了如下的小标题: "心中有路"与综合推断 "心中无路"与无从推断 ...
- FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之Toggle同步器
文章目录 前言 脉冲反馈展宽同步器技术补充说明 RTL代码 行为仿真 低电平脉冲的展宽处理 切换同步器的原理与实现 RTL实现 前言 本文首发自:FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之 ...
最新文章
- RAID 与 LVM 磁盘阵列技术
- 4-30 HTML 细节摘录
- anaconda在安装依赖包时出现报错提示 ‘requests‘ is a dependency of conda and cannot be remove from conda‘s operatin
- RMI原理一记远程调用
- 重新学习c++--理解引用、智能指针、虚函数、模板、容器
- Java : ServiceLoader详解
- python画图渐变颜色的代号_plt绘图颜色渐变以及colormap
- scp命令报错-bash: scp: command not found
- Java面试题总结(二)
- PHP中文分词扩展 SCWS
- 最大连续区间和算法详解+代码
- WINDOWS下获取目录环境变量的C代码
- Docker Centos安装Openssh
- STM32F072单片机的低功耗实验/STOP模式低功耗调试
- AndroidStudio选中代码后,光标自动变粗,自动变成ins模式的解决方法
- caffe入门学习(5):绘制网络结构图
- python如何设计系统界面教程_python图形化界面设计tkinter!python用户界面设计教程...
- android禁止录屏后键盘,怎样取消华为按键录屏功能 | 手游网游页游攻略大全
- HPE 3PAR StoreServ存储系统连接解决方案
- 安卓电子书格式_进阶能力 | 了解常见的电子书格式
热门文章
- 初学java之JFrame窗口模式
- 转:AIX rcp跨主机远程拷贝数据
- typedef、setw()
- html h 不换行,css 强制不换行
- 插入排序 链表 java_Java实现 LeetCode 147 对链表进行插入排序
- 五元一次方程组计算器_人教版初中数学七年级下册列一元一次不等式解实际问题公开课优质课课件教案视频...
- matlab选择激发波长,【求助】怎么确定一个物质的激发波长和发射波长?
- autohold有什么弊端吗_自动驻车真的好用吗?很多车主不敢用,实车演示正确用法很简单...
- 第十六届全国大学生智能汽车竞赛 讯飞智慧餐厅组别 全国选拔赛成绩公布说明
- 2021年春季学期-信号与系统-第十五次作业参考答案