打工人日报#20251009
打工人日报#20251009
知识点
RAM IP 核
Vivado 软件自带的 Block Memory Generator IP 核(缩写为 BMG,中文名为块 RAM 生成器),可以用
来配置生成 RAM 或者 ROM
如何将 BMG IP 核配置成 RAM
将 Xilinx BMG IP 核配置成一个单端口的 RAM 并对其进行读写操作,然后通过仿真观
察波形是否正确,最后将设计下载到 FPGA 开发板中,并通过在线调试工具对实验结果进行验证。
在“IP Catalog”窗口的搜索栏中输入“Block Memory”关键字后,出现唯一匹配的“Block Memory
Generator”
“Component Name”一栏可以设置该 IP 元件的名称
到“Basic”选项卡
“lnterface Type(接口模式)”:有两种接口模式可选,分别为 Native(常规)接口和 AXI4
接口。AXI4 模式一般是在处理器中的数据需要和 BRAM 交互(如 ZYNQ 中的 PS 和 PL 交互)时才会使用
“Generate address interface with 32 bits”选项为是否生成位宽为 32 的地址接口,勾选后内存的
数据位宽必须设置成 32 的整数倍,在实际应用中,我们一般不做勾选。
“Memory Type(存储类型)”:有五种类型可选,分别为“Single Port RAM(单端口 RAM)”、
“Simple Dual Port RAM(伪双端口 RAM)”、“True Dual Port RAM(真双端口 RAM)”、“Single Port
ROM(单端口 ROM)”和“Dual Port ROM(双端口 ROM)”
“Common Clock”选项为是否启用同步时钟
“ECC(全称 Error Correcting Code,即纠错码) Options”,纠错码选项只有在伪双端口 RAM
类型下才可以进行配置。
“Write Enable(写使能)”:可以选择是否使用字节写使能功能,启用后可设置字节大小为 8
位(无奇偶校验)或 9 位(包括奇偶校验),需要注意的是启用后内存的数据位宽必须设置为所选字节大
小的整数倍。
“Algorithm Options(算法选项)”:算法选项主要用于决定 BRAM 的拼接的方式,一般在
BRAM 深度、宽度较大的时候起作用,有三种算法可选,分别为“Minimum Area(最小面积算法)”、“Low
Power(低功耗算法)”和“Fixed Primitives(固定单元算法)”
对“Port A Options”选项
“Memory Size(内存大小)”,用于指定端口读/写宽度和深度、运行模式和使能端口类型
Write Width:写数据位宽,单位 bit,本次实验我们设置成 8,可设置的位宽范围为 1~4608。
Read Width:读数据位宽,其位宽设置必须与写数据位宽存在倍数关系(倍数比仅支持 1:1、1:2、1:
4、1:8、2:1、4:1、8:1 和 16:1),通常情况下读/写数据位宽保持一致,
Write Depth:写深度,这里设置成 32,即 RAM 所能访问的地址范围为 0~31。这里有一点需要大家注
意,那就是写深度和写位宽的乘积不要超过器件本身的 ram 资源的大小
Read Depth:读深度,当写数据位宽、读数据位宽和写深度的值确定后,读深度的值就会自动确定。
Operating Mode:RAM 运作模式。该选项决定了我们在进行写操作期间,DOUT(读数据线)上的数据
变化,有三种模式可选,
• Write First(写优先模式):当我们在对某个地址进行写操作时,则会将写入的数据传递到读数据线上。
• Read First(读优先模式):当我们在对某个地址进行写操作时,则会将上次写入该地址的数据递到读
数据线上。
• No Change(不变模式):在该模式下,进行写操作时,读数据线上的数据保持不变。
Enable Port Type:使能端口类型。有两种可选,分别为 Use ENA pin(添加使能端口 A 信号)和 Always
Enabled(取消使能信号,端口 A 一直处于使能状态),
“Port A Optional Output Register”用于为 RAM 的输出端添加寄存器。其作用是提高 BRAM 的
运行频率和改善时序,当然为此付出的代价就是每勾选一个寄存器,输出就会延迟一拍。
• Primitives Output Register,使用 BRAM 内部的寄存器打拍输出。
• Core Output Register,使用 SLICE 的寄存器打拍输出。
• SoftECC Input Register,当使用软 ECC 的时候,用 SLICE 的寄存器打拍。
• REGCEA,当使用 Primitives Output Register 或者 Core Output Register 时,可以用 REGCEA 来使能相
应的输出。
“Port A Output Reset Options”用于设置端口的复位信号,可以添加一个复位信号(RSTA Pin)、
设置复位时 ram 输出总线上的数据值(Output Reset Value)、设置是否复位内置锁存器(Reset Memory Latch)
和设置复位信号与时钟使能之间的优先级(Reset Priority)
“READ Address Change A”用于更改端口的读地址,这个功能只在 UltraScale 设备上使用,一
般在某些低功耗场景中会应用到。
“Other Options”选项卡
“Pipeline Stages within Mux”输出端 Mux 选择器的流水线级数。在大位宽、大深度的 BRAM
拼接场景中,我们会用 MUX 来选择输出地址所对应的数据,勾选该选项后可以使输出数据具有更好的时序。
“Memory Initialization(初始化文件)”,选择是否使用本地初始化文件(.coe 文件)来对存
储空间进行初始化。
“Structural/UniSim Simulation Model Options”,用于选择结构仿真模型发生碰撞时生成的警告
消息和输出的类型。
“Behavioral Simulation Model Options”,用于关闭仿真时的冲突告警和超出范围告警。
“Summary”选项卡,该界面显示了我们配置的存储器的类型,消耗的 BRAM 资源等信息,
我们直接点击“OK”按钮完成 BMG IP 核的配置,
ip_1port_ram.v
module ip_1port_ram(
input sys_clk , //系统时钟
input sys_rst_n //系统复位,低电平有效
);//wire define
wire ram_en ; //RAM 使能
wire ram_we ; //ram 读写使能信号,高电平写�?,低电平读�?
wire [4:0] ram_addr ; //ram 读写地址wire [7:0] ram_wr_data ; //ram 写数�? wire [7:0] ram_rd_data ; //ram 读数�? //*****************************************************//** main code//*****************************************************//ram 读写模块ram_rw u_ram_rw(.clk (sys_clk ),.rst_n (sys_rst_n ),//RAM.ram_en (ram_en ),.ram_we (ram_we ),.ram_addr (ram_addr ),.ram_wr_data (ram_wr_data ),.ram_rd_data (ram_rd_data ));//ram ip �?blk_mem_gen_0 blk_mem_gen_0 (.clka (sys_clk ), // input wire clka.ena (ram_en ), // input wire ena .wea (ram_we ), // input wire [0 : 0] wea.addra (ram_addr ), // input wire [4 : 0] addra.dina (ram_wr_data ), // input wire [7 : 0] dina.douta (ram_rd_data ) // output wire [7 : 0] douta);ila_0 your_instance_name (.clk(sys_clk), // input wire clk.probe0(ram_en), // input wire [0:0] probe0 .probe1(ram_we), // input wire [0:0] probe1 .probe2(ram_addr), // input wire [4:0] probe2 .probe3(ram_wr_data), // input wire [7:0] probe3 .probe4(ram_rd_data) // input wire [7:0] probe4
);endmodule
ram_rw.v
module ram_rw(
input clk , //时钟信号
input rst_n , //复位信号,低电平有效output reg ram_en , //ram 使能信号
output ram_we , //ram 读写选择
output reg [4:0] ram_addr , //ram 读写地址
output reg [7:0] ram_wr_data, //ram 写数据
input [7:0] ram_rd_data //ram 读数据 );//reg definereg [5:0] rw_cnt ; //读写控制计数器//*****************************************************//** main code//*****************************************************//rw_cnt 计数范围在 0~31,写入数据;32~63 时,读出数据assign ram_we = (rw_cnt <= 6'd31 && ram_en == 1'b1) ? 1'b1 : 1'b0;//控制 RAM 使能信号always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)ram_en <= 1'b0; elseram_en <= 1'b1; end//读写控制计数器,计数器范围 0~63always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)rw_cnt <= 6'b0; else if(rw_cnt == 6'd63 && ram_en)rw_cnt <= 6'b0;else if(ram_en)rw_cnt <= rw_cnt + 1'b1;elserw_cnt <= 6'b0; end //读写地址信号 范围:0~31always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)ram_addr <= 5'b0;else if(ram_addr == 5'd31 && ram_en)ram_addr <= 5'b0;else if (ram_en) ram_addr <= ram_addr + 1'b1;elseram_addr <= 5'b0; end//在 WE 拉高期间产生 RAM 写数据,变化范围是 0~31always @(posedge clk or negedge rst_n) beginif(rst_n == 1'b0)ram_wr_data <= 8'b0; else if(ram_wr_data < 8'd31 && ram_we)ram_wr_data <= ram_wr_data + 1'b1;elseram_wr_data <= 8'b0 ; end endmodule
tb_ip_1port_ram.v
`timescale 1ns / 1ps //锟斤拷锟芥单位/锟斤拷锟芥精锟斤拷module tb_ip_1port_ram();//parameter define
parameter CLK_PERIOD = 20; //时锟斤拷锟斤拷锟斤拷 20ns//reg define
reg sys_clk;reg sys_rst_n;//锟脚号筹拷始锟斤拷initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;end//锟斤拷锟斤拷时锟斤拷always #(CLK_PERIOD/2) sys_clk = ~sys_clk;ip_1port_ram u_ip_1port_ram(.sys_clk (sys_clk ),.sys_rst_n (sys_rst_n ));endmodule
ram_wea 信号拉高,对 ram 进行写操作
ram_wea 信号拉低,是对 ram 进行读操作
数据为 0、1、2……30、31
阅读
《杀死一只知更鸟》
第十二章
一个人没有必要把自己懂的都展示出来