ZYNQ_project:ram_dual_port

Pseudo dual-port ram: write port: clk_w,en_A,we_A,addr_A,din_A; read port: clk_r,en_B,addr_B;dout_B.

Design a read-write module to write 256 data and read 256 data.

The input clock is 100Mhz and the output clock is 50Mhz.

Multi-bit data is processed from high-speed clock domain to low-speed clock domain.

Module block diagram:

Code:

module ram_real_wr(
    input wire clk_w ,
    input wire clk_r,
    input wire sys_rst_n ,

    output reg en_A ,
    output reg we_A ,
    output wire [7:0] addr_A ,
    output wire [7:0] din_A ,

    output reg en_B ,
    output wire [7:0] addr_B
);
    // parameter
    parameter WR_NUM = 256,
                RD_NUM = 256;

    reg [7:0] cnt_w; // Used to generate write location and write data
    reg flag_wr;
    reg done;
    reg [7:0] cnt_r;
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_w <= 8'd0;
        else if(en_A & amp; & amp; we_A & amp; & amp; (cnt_w == WR_NUM - 1))
            cnt_w <= 8'd0;
        else if(en_A & amp; & amp; we_A)
            cnt_w <= cnt_w + 1'b1;
        else
            cnt_w <= cnt_w;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            flag_wr <= 1'b1;
        else if(cnt_w == WR_NUM - 2)
            flag_wr <= 1'b0;
        else
            flag_wr <= flag_wr ;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            en_A <= 1'b0;
        else
            en_A <= 1'b1;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            we_A <= 1'b0;
        else
            we_A <= flag_wr;
    end
    assign addr_A = (we_A) ? cnt_w : 8'd0;
    assign din_A = (we_A) ? cnt_w : 8'd0;

    always @(posedge clk_r or negedge sys_rst_n) begin
        if(~sys_rst_n)
            done <= 1'b0;
        else if(en_B & amp; & amp; (cnt_r == RD_NUM - 2))
            done <= 1'b1;
        else
            done <= done ;
    end
    always @(posedge clk_r or negedge sys_rst_n) begin
        if(~sys_rst_n)
            en_B <= 1'b0;
        else if(~done) begin
            if(~flag_wr)
                en_B <= 1'b1;
            else
                en_B <= 1'b0;
        end
        else
            en_B <= 1'b0;
    end
    always @(posedge clk_r or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_r <= 8'd0;
        else if(en_B & amp; & amp; (cnt_r == RD_NUM - 1))
            cnt_r <= 8'd0;
        else if(en_B)
            cnt_r <= cnt_r + 1'b1;
        else
            cnt_r <= 8'd0;
    end
    assign addr_B = (en_B) ? cnt_r : 8'd0;

endmodule
module top(
    input wire sys_clk,
    input wire sys_rst_n ,
    
    output wire [7:0] data_out
);
    // Instantiate the connection
wire clk_100Mhz;
wire clk_50Mhz;
wire locked;
wire rst_n;
wire en_A ;
wire we_A ;
wire [7:0] addr_A ;
wire [7:0] din_A ;
wire en_B;
wire [7:0] addr_B ;
pll_clk pll_clk_inst(
.resetn (sys_rst_n),
.clk_in1 (sys_clk),

  .clk_out1 ( clk_100Mhz ) ,
  .clk_out2 ( clk_50Mhz ) ,
  .locked ( locked )
 );
assign rst_n = sys_rst_n & amp; & amp; locked ;
    
ram_real_wr ram_real_wr_inst(
    .clk_w ( clk_100Mhz ) ,
    .clk_r ( clk_50Mhz ) ,
    .sys_rst_n (rst_n),

    .en_A ( en_A ) ,
    .we_A ( we_A ) ,
    .addr_A ( addr_A ) ,
    .din_A ( din_A ) ,

    .en_B ( en_B ) ,
    .addr_B ( addr_B )
);
    
blk_mem_gen_0 blk_mem_gen_0_inst(
    .clka ( clk_100Mhz ) ,
    .ena ( en_A ) ,
    .wea ( we_A ) ,
    .addra(addr_A),
    .dina(din_A),

    .clkb ( clk_50Mhz ) ,
    .enb ( en_B ) ,
    .addrb ( addr_B ) ,

    .doutb(data_out)
);

endmodule

Improve it so that only the data in even addresses can be read:

module ram_real_wr(
    input wire clk_w ,
    input wire clk_r,
    input wire sys_rst_n ,

    output reg en_A ,
    output reg we_A ,
    output wire [7:0] addr_A ,
    output wire [7:0] din_A ,

    output reg en_B ,
    output wire [7:0] addr_B
);
    // parameter
    parameter WR_NUM = 256,
                RD_NUM = 256;

    reg [7:0] cnt_w; // Used to generate write location and write data
    reg flag_wr;
//reg done;
    reg [7:0] cnt_r;
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_w <= 8'd0;
        else if(en_A & amp; & amp; we_A & amp; & amp; (cnt_w == WR_NUM - 1))
            cnt_w <= 8'd0;
        else if(en_A & amp; & amp; we_A)
            cnt_w <= cnt_w + 1'b1;
        else
            cnt_w <= cnt_w;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            flag_wr <= 1'b1;
        else if(cnt_w == WR_NUM - 2)
            flag_wr <= 1'b0;
        else
            flag_wr <= flag_wr ;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            en_A <= 1'b0;
        else
            en_A <= 1'b1;
    end
    always @(posedge clk_w or negedge sys_rst_n) begin
        if(~sys_rst_n)
            we_A <= 1'b0;
        else if(cnt_w == WR_NUM - 2)
            we_A <= 1'b0;
        else
            we_A <= flag_wr;
    end
    assign addr_A = (we_A) ? cnt_w : 8'd0;
    assign din_A = (we_A) ? cnt_w : 8'd0;

    // always @(posedge clk_r or negedge sys_rst_n) begin
    // if(~sys_rst_n)
    // done <= 1'b0 ;
    // else if(en_B & amp; & amp; (cnt_r == RD_NUM - 2))
    // done <= 1'b1 ;
    //else
    // done <= done ;
    //end
    // always @(posedge clk_r or negedge sys_rst_n) begin
    // if(~sys_rst_n)
    // en_B <= 1'b0;
    // else if(~done) begin
    // if(~flag_wr)
    // en_B <= 1'b1;
    //else
    // en_B <= 1'b0;
    // end
    //else
    // en_B <= 1'b0;
    //end
    // always @(posedge clk_r or negedge sys_rst_n) begin//Only read data from even addresses.
    // if(~sys_rst_n)
    // en_B <= 1'b0;
    // else if(~flag_wr) begin
    // if(cnt_r[0]) // Odd numbers are assigned 1, the read enable is valid, and even numbers read enable is invalid.
    // en_B <= 1'b1;
    //else
    // en_B <= 1'b0;
    // end
    //else
    // en_B <= 1'b0;
    //end
    always @(posedge clk_r or negedge sys_rst_n) begin//Only read data from even addresses.
        if(~sys_rst_n)
            en_B <= 1'b0;
        else if(~flag_wr & amp; & amp; (cnt_r[0]))
            en_B <= 1'b1;
        else
            en_B <= 1'b0;
    end
    always @(posedge clk_r or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_r <= 8'd0;
        else if(~flag_wr & amp; & amp; (cnt_r == RD_NUM - 1))
            cnt_r <= 8'd0;
        else if(~flag_wr)
            cnt_r <= cnt_r + 1'b1;
        else
            cnt_r <= 8'd0;
    end
    assign addr_B = (en_B) ? cnt_r : 8'd0;

endmodule

Simulation diagram: