ZYNQ_project:ram_dual_port

文章描述了一个伪双端口RAM的设计,包括写入和读取模块,支持100MHz高速时钟到50MHz低速时钟的数据转换。改进部分着重于只读取偶数地址的数据。代码展示了如何控制地址和数据传输以及读取使能的逻辑。
摘要由CSDN通过智能技术生成

伪双端口ram:写端口:clk_w,en_A,we_A,addr_A,din_A;读端口:clk_r,en_B,addr_B;dout_B.

设计读写模块,写入256个数据,再读出256个数据。

输入时钟100Mhz,输出时钟50Mhz。

多bit数据,高速时钟域到低速时钟域处理。

模块框图:

代码:

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   ; // 用来产生写地�?与写数据�?
    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 && we_A && (cnt_w == WR_NUM - 1))
            cnt_w <= 8'd0 ;
        else if(en_A && 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 && (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 && (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    
);
    // 例化间连�?
	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 && 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

改进一下,使得只读出偶数地址内的数据:

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   ; // 用来产生写地�?与写数据�?
    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 && we_A && (cnt_w == WR_NUM - 1))
            cnt_w <= 8'd0 ;
        else if(en_A && 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 && (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) 
    //         en_B <= 1'b0 ;
    //     else if(~flag_wr) begin
    //         if(cnt_r[0]) // 奇数赋值1,读使能有效,偶数读使能无效。
    //             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) 
            en_B <= 1'b0 ;
        else if(~flag_wr && (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 && (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

 

仿真图:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值