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