FPGA教程系列-双口RAM的读写实验
RAM的IP核已经在其他文章里讲过了,就不再做过多的赘述。
本仿真采用的RAM参数如图:



其他默认。
由于只有一个例化的IP核,再封装一次的意义不大,所以就步编写top文件了,直接在testbench中调用ip核就可以了
Testbench
`timescale 1ns / 1ps
module tb_dual_port_ram;
localparam DATA_WIDTH = 16;
localparam ADDR_WIDTH = 9;
localparam MEM_DEPTH = 2**ADDR_WIDTH; // 512
//==========================================================================
// Testbench Signals
//==========================================================================
// Port A (Write Port)
reg tb_clka;
reg tb_wea;
reg [ADDR_WIDTH-1:0] tb_addra;
reg [DATA_WIDTH-1:0] tb_dina;
// Port B (Read Port)
reg tb_clkb;
reg tb_rstb;
reg tb_enb;
reg [ADDR_WIDTH-1:0] tb_addrb;
wire [DATA_WIDTH-1:0] tb_doutb;
// Status signals (optional to monitor)
wire tb_rsta_busy;
wire tb_rstb_busy;
//==========================================================================
// Clock Generation
// Using two different clocks to demonstrate port independence.
//==========================================================================
initial begin
tb_clka = 0;
forever #5 tb_clka = ~tb_clka; // 100 MHz clock (10ns period)
end
initial begin
tb_clkb = 0;
forever #6 tb_clkb = ~tb_clkb; // ~83.3 MHz clock (12ns period)
end
//==========================================================================
// DUT (Design Under Test) Instantiation
//==========================================================================
blk_mem_gen_0 your_instance_name (
.clka (tb_clka),
.wea (tb_wea),
.addra (tb_addra),
.dina (tb_dina),
.clkb (tb_clkb),
.rstb (tb_rstb),
.enb (tb_enb),
.addrb (tb_addrb),
.doutb (tb_doutb),
.rsta_busy (tb_rsta_busy),
.rstb_busy (tb_rstb_busy)
);
//==========================================================================
// Test Sequence
//==========================================================================
initial begin
// 1. Initialize Inputs
tb_wea = 1'b0;
tb_addra = {ADDR_WIDTH{1'b0}};
tb_dina = {DATA_WIDTH{1'b0}};
tb_rstb = 1'b1; // Start with reset active
tb_enb = 1'b0;
tb_addrb = {ADDR_WIDTH{1'b0}};
// Wait for global reset to propagate
$display("--- Test Started at time %0t ---", $time);
#20;
tb_rstb = 1'b0; // De-assert reset
$display("[%0t] Port B reset released.", $time);
// Monitor signals for easy debugging
$monitor("Time=%0t | A(wea=%b, addr=%0d, din=0x%h) | B(en=%b, addr=%0d, dout=0x%h)",
$time, tb_wea, tb_addra, tb_dina, tb_enb, tb_addrb, tb_doutb);
//================================================
// Test 1: Write data to RAM via Port A
//================================================
$display("\n--- Test 1: Writing 10 data items via Port A ---");
for (integer i = 0; i < 10; i++) begin
@(posedge tb_clka);
#1; // Small delay to avoid race conditions
tb_addra = i;
tb_dina = 16'hA000 + i; // Write a predictable pattern
tb_wea = 1'b1;
$display("[%0t] Writing to address %0d: data 0x%h", $time, tb_addra, tb_dina);
end
@(posedge tb_clka);
tb_wea = 1'b0; // De-assert write enable
$display("[%0t] Finished writing.", $time);
//================================================
// Test 2: Read data from RAM via Port B and verify
//================================================
$display("\n--- Test 2: Reading and verifying 10 data items via Port B ---");
tb_enb = 1'b1; // Enable read port
for (integer i = 0; i < 10; i++) begin
@(posedge tb_clkb);
#1;
tb_addrb = i;
$display("[%0t] Reading from address %0d...", $time, tb_addrb);
// Data is available on the next clock edge
@(posedge tb_clkb);
#1;
if (tb_doutb === (16'hA000 + i)) begin
$display("[%0t] SUCCESS: Read data 0x%h matches expected 0x%h", $time, tb_doutb, (16'hA000 + i));
end else begin
$error("[%0t] FAILURE: Read data 0x%h does NOT match expected 0x%h", $time, tb_doutb, (16'hA000 + i));
end
end
tb_enb = 1'b0; // Disable read port
//================================================
// Test 3: Simultaneous Read/Write on different addresses
//================================================
$display("\n--- Test 3: Simultaneous Read/Write ---");
// Start a write operation on Port A
@(posedge tb_clka);
tb_addra = 100;
tb_dina = 16'hBEEF;
tb_wea = 1'b1;
$display("[%0t] Writing 0x%h to address 100 via Port A.", $time, tb_dina);
// Start a read operation on Port B
@(posedge tb_clkb);
tb_enb = 1'b1;
tb_addrb = 50; // Read a different address
$display("[%0t] Reading from address 50 via Port B.", $time);
// Finish the write operation
@(posedge tb_clka);
tb_wea = 1'b0;
// Check the read result
@(posedge tb_clkb);
#1;
if (tb_doutb === 16'hA032) begin // 16'hA000 + 50
$display("[%0t] SUCCESS: Simultaneous R/W test passed. Read 0x%h from addr 50.", $time, tb_doutb);
end else begin
$error("[%0t] FAILURE: Simultaneous R/W test failed. Read 0x%h from addr 50, expected 0x%h.", $time, tb_doutb, 16'hA032);
end
tb_enb = 1'b0;
//================================================
// End of Test
//================================================
#20;
$display("\n--- All Tests Finished ---");
$finish;
end
endmodule
例行仿真:


可以看到数据的正常写入与读取。
工程文件:https://download.youkuaiyun.com/download/fantasygwh2015/92292033

2615

被折叠的 条评论
为什么被折叠?



