伪双端口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
仿真图: