RAM
1、ram三种模式
单端口:一个端口 用于读写 不能同时进行
伪双端口(SDP):两个端口 一个用于读 一个用于写
双端口:两个端口 都可以用于读写
当要同时读写一个地址时 应提前配置读优先/写优先
当然要尽量避免同时访问一个地址
配置成:单端口只读模式 则相当于 ROM(可以调用coe文件提前写入)
2、工程源码、仿真效果
添加ip核并配置:
ram ip核 数据和地址 以及使能、读写信号的产生(generate the data)
`timescale 1ns / 1ps
module ram_rw(
input clk,
input rst_n,
output reg ram_en,//ram enable high level is useful
output reg rw, //Determines whether to be in write mode or read mode
output reg[4:0] ram_addr,
output reg [7:0] ram_wr_data
);
reg [5:0] rw_cnt;
// prepare for the read/write mode
always@(posedge clk or negedge rst_n)begin
if (!rst_n)
rw_cnt <= 6'd0;
else if(rw_cnt==6'd63)
rw_cnt <= 0;
else
rw_cnt <= rw_cnt +6'd1;
end
// rw at high level,the ram is in write mode
always@(posedge clk or negedge rst_n)begin
if (!rst_n)
rw <= 1'b1;
else if(rw_cnt<=6'd31)
rw <= 1'b1;
else
rw <= 1'b0;
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n)
ram_en = 1'b0;
else
ram_en = 1'b1;
end
//prepare the data
always@(posedge clk or negedge rst_n)begin
if (!rst_n)
ram_wr_data <= 8'd0;
else if((rw_cnt<6'd31)&&ram_en)
ram_wr_data <= ram_wr_data + 1'b1;
else
ram_wr_data <= ram_wr_data;
end
always@(posedge clk or negedge rst_n)begin
if (!rst_n)
ram_addr <= 5'd0;
else
ram_addr <= rw_cnt[4:0];//0-31
end
endmodule
信号如下:
对module的例化 类似c语言中的 main.c文件
`timescale 1ns / 1ps
module ip_ram_test(
input sys_clk,
input sys_rst_n
//output [7:0] douta
);
wire ram_en;
wire rw;
wire[4:0] ram_addr;
wire[7:0]ram_wr_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_wr_data(ram_wr_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 read/wirte change
.addra(ram_addr), // input wire [4 : 0] addra
.dina(ram_wr_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_wr_data), // input wire [7:0] probe3
.probe4(douta) // input wire [7:0] probe4
);
endmodule
添加tb仿真文件
`timescale 1ns / 1ps //仿真单位/仿真精度
//本实验我们只有系统时钟和系统复位这两个输入信号,
//所以仿真文件也只需要编写这两个信号的激励即可。
module tb_ram();
//parameter define
parameter CLK_PERIOD = 20; //50MHz系统时钟(一个周期是20ns:1/50MHz=0.02us=20ns)
//200MHz系统时钟(一个周期是5ns:1/200MHz=0.005us=5ns)
//reg define
reg sys_clk;
reg sys_rst_n;
//信号初始化
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
#200
sys_rst_n = 1'b1;
end
//产生时钟
always #(CLK_PERIOD/2) sys_clk = ~sys_clk;
ip_ram_test u_ip_ram_test(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n )
);
endmodule
整个工程就算完成
进行仿真:
3、心得体会
1、由于以前都是利用block_design 进行 也是跟着视频来 对于module、例化、仿真文件这些文件的关系没多想 以下是我的一些理解:
关于module: 类似特别编写一个文件 作为一个函数 供例化使用
关于例化: 类似c语言的主函数 其中利用各个编写好的module、ip核等(可以查看上面代码)
关于仿真:最重要的就是提供一个时钟 也是编写一个module 提供一些最底层的节拍(时钟),接着接入例化的module
2、对于ip核的调用 可以看 ip source 的.evo文件 里面提供例化的模板 并且有一些说明 很像stm32hal库开发的库函数说明;(工程开发还是有很多相似之处的)
4、剩余问题
在开发过程本来不想软件仿真 想直接上板测试 所以添加了ila逻辑分析仪 但是上板不出波形
sys_clk没接上还是啥问题 没有找到解决方案(很烦)
下面是约束文件 按理说不应该有问题
create_clock -period 20 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_clk}]
set_property PACKAGE_PIN K17 [get_ports {sys_clk}]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_rst_n}]
set_property PACKAGE_PIN K18 [get_ports {sys_rst_n}]
逻辑没问题的话 估计是晶振时钟没有产生 继续学 学到后面向下兼容 估计就能找到这个可恶的问题;