1.Block RAM设置
2.Design source
ram_test.v
`timescale 1ns / 1ps
module ram_test(
clk, //50MHz时钟
rst_n,
w_addr,
w_data,
wea,
r_addr,
r_data //复位信号,低电平有效
);
input clk;
input rst_n;
output reg [8:0] w_addr; //RAM PORTA写地址
output reg [15:0] w_data; //RAM PORTA写数据
output reg wea; //RAM PORTA使能
output reg [8:0] r_addr; //RAM PORTB读地址
output wire [15:0] r_data; //RAM PORTB读数据
//产生RAM PORTB读地址
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
r_addr <= 9'd0;
/*
这里是为了让读地址比写地址延迟一个周期
你可能会想,当w_addr=1不等于9'd0的时候,r_addr不是也加1变成1了吗?
怎么就实现了延迟一个时钟周期了呢?
那是因为r_addr是寄存器类型的变量,只有在下一个时钟周期才能采集到此时的值。
*/
else if (|w_addr) //w_addr位或,不等于0
r_addr <= r_addr+1'b1;
else
r_addr <= 9'd0;
end
//产生RAM PORTA写使能信号
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
wea <= 1'b0;
else
begin
if(&w_addr) //w_addr的bit位全为1,共写入512个数据,写入完成
wea <= 1'b0;
else
wea <= 1'b1; //ram写使能
end
end
//产生RAM PORTA写入的地址及数据
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
w_addr <= 9'd0;
w_data <= 16'd0;
end
else
begin
if(wea)//ram写使能有效
begin
//当写地址全为1的时候,说明已经写够512个数据,就可以不用写使能了。
if (&w_addr)
begin
w_addr <= w_addr ; //将地址和数据的值保持住,只写一次RAM
w_data <= w_data ;
end
else
begin
w_addr <= w_addr + 1'b1;
w_data <= w_data + 1'b1;
end
end
end
end
//实例化RAM
ram_ip ram_ip_inst (
.clka (clk ), // input clka
.wea (wea ), // input [0 : 0] wea
.addra (w_addr ), // input [8 : 0] addra
.dina (w_data ), // input [15 : 0] dina
.clkb (clk ), // input clkb
.addrb (r_addr ), // input [8 : 0] addrb
.doutb (r_data ) // output [15 : 0] doutb
);
endmodule
3.Simulation source
vtf_ram_tb.v
`timescale 1ns / 1ps
module vtf_ram_tb;
// Inputs
reg clk;
reg rst_n;
wire [8:0] w_addr;
wire [15:0] w_data;
wire wea;
wire [8:0] r_addr;
wire [15:0] r_data;
// Instantiate the Unit Under Test (UUT)
ram_test uut (
.clk (clk),
.rst_n (rst_n),
.w_addr(w_addr) ,
.w_data(w_data) ,
.wea (wea) ,
.r_addr(r_addr) ,
.r_data(r_data)
);
initial
begin
// Initialize Inputs
clk = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
end
always #10 clk = ~ clk; //20ns一个周期,产生50MHz时钟源
endmodule