官方文档:ZYNQ 存储资源指导手册 (DS109)
RAM 全称 Random Access Memory,随机存取存储器。
随时将数据写入任意指定地址的存储单元,或从任意地址读出数据。读写的速度是由时钟频率决定的。
RAM主要用于存放程序运行的中间数据、运算结果等
资源简介:
- Zynq-7000系列都有很多独立的双端口RAM,每一片RAM有36kb
- 数据位宽的配置(32K1, 16K2,…);每个RAM可以被分为两个独立的18Kb的RAMs;两个临近的RAM也可以合并成一个64K的RAM
端口配置
- 单端口:只有一个端口,读写数据不同时进行,共用一个数据通道
- 伪双端口:拥有两个数据通道,一个写一个读
- 真双端口:拥有两个数据通道,每个通道既可以写也可以读
创建顶层模块 ip_ram
前0-31写,后32-63读
创建一个设计源文件:
选择RAM IP Core
双击设置
设置读写位宽和深度
veo文件是例化模板
读写模块 ram_rw
我们需要一个读写控制模块去驱动RAM IP Core
新建一个设计文件ram_rw
module ram_rw(
input clk,
input rst_n,
output reg ram_en, // 写使能
output reg rw, // 写还是读
output reg[4:0] ram_addr,// 写还是读的地址
output reg[7:0] ram_wr_data // 写或读的数据
);
endmodule
设置端口控制逻辑:
// 使能端口
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_en <= 1'b0;
else
ram_en <= 1'b1;
end
// 计数器64, 前32写后32读
reg[0:5] rw_cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
rw_cnt<=6'd0;
else
if(rw_cnt == 6'd63)
rw_cnt <= 6'd0;
else
rw_cnt <= rw_cnt + 6'd1;
end
// 设置写的数据
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_rw_data <= 8'd0;
else
if(ram_en && (rw_cnt <= 6'd31)) // 写使能打开 且 计数器在写范围内
ram_rw_data <= ram_rw_data + 8'd1;
else
ram_rw_data <= ram_rw_data;
end
// 设置读写状态
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
rw <= 1'b1; // 默认为写状态
else
if(ram_en && (rw_cnt <= 6'd31)) // 写使能打开 且 计数器在写范围内
rw <= 1'b1;
else
rw <= 1'b0;
end
// 设置写地址
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ram_addr <= 5'd0;
else
// 把计数器当作地址, 只取前31
ram_addr <= rw_cnt[4:0];
end
例化ram ip和读写模块ram_rw
module ip_ram(
input sys_clk,
input sys_rst_n
);
wire ram_en;
wire rw;
wire[4:0] ram_addr;
wire[7:0] ram_rw_data;
wire[7:0] douta;
// 例化读写模块
ram_rw ram_rw_u(
.clk (sys_clk),
.rst_n (sys_rst_n),
.ram_en (ram_en),
.rw (rw),
.ram_addr (ram_addr),
.ram_rw_data(ram_rw_data)
);
blk_mem_gen_0 your_instance_name (
.clka (sys_clk), // input wire clka
.ena (ram_en), // input wire ena
.wea (rw), // input wire [0 : 0] wea
.addra (ram_addr), // input wire [4 : 0] addra
.dina (ram_rw_data), // input wire [7 : 0] dina
.douta (douta) // output wire [7 : 0] douta
);
endmodule
Run Synthesis后打开Schematic原理图
约束
set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sys_clk }]; #IO_L11P_T1_SRCC_35 Sch=sysclk
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { sys_rst_n }];
ILA
设置探针数和深度
设置探针位宽
copy例化的模板到顶层模块ip_ram:
接入需要探测的信号:
ip_ram.v:
module ip_ram(
input sys_clk,
input sys_rst_n
);
wire ram_en;
wire rw;
wire[4:0] ram_addr;
wire[7:0] ram_rw_data;
wire[7:0] douta;
// 例化读写模块
ram_rw ram_rw_u(
.clk (sys_clk),
.rst_n (!sys_rst_n),
.ram_en (ram_en),
.rw (rw),
.ram_addr (ram_addr),
.ram_rw_data(ram_rw_data)
);
blk_mem_gen_0 blk_mem_gen_0_u (
.clka (sys_clk), // input wire clka
.ena (ram_en), // input wire ena
.wea (rw), // input wire [0 : 0] wea
.addra (ram_addr), // input wire [4 : 0] addra
.dina (ram_rw_data), // input wire [7 : 0] dina
.douta (douta) // output wire [7 : 0] douta
);
ila_0 ila_0_u (
.clk(sys_clk), // input wire clk
.probe0(ram_en), // input wire [0:0] probe0
.probe1(rw), // input wire [0:0] probe1
.probe2(ram_addr), // input wire [4:0] probe2
.probe3(ram_rw_data), // input wire [7:0] probe3
.probe4(douta) // input wire [7:0] probe4
);
endmodule
下载验证
生成bitstream,连接开发板,点击Program Device
点击运行:
写的数据设置:
0-31,写数据从0增加到31
32-63,读数据,数据不增加保持在31,douta依次将0-31读出来
64-95,写数据,数据从31增加到63,douta保持31不变