FPGA教程系列-双口RAM的读写实验

FPGA教程系列-双口RAM的读写实验

RAM的IP核已经在其他文章里讲过了,就不再做过多的赘述。

本仿真采用的RAM参数如图:

image

image

image

其他默认。

由于只有一个例化的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

例行仿真:

image

image

可以看到数据的正常写入与读取。

工程文件:https://download.youkuaiyun.com/download/fantasygwh2015/92292033

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值