一、概念
真双端口RAM有两个独立的读写端口,每个端口都可以独立发起读或者写。
二、IP示例
quartus平台:
vivado平台:
IP的使用配置几乎相同,设置好参数后即可调试。
注意:
1、读和写冲突:如果读和写同时有效,且读和写是同一个地址时,发生RAM读写冲突,此时会把最新的写数据直接赋给读数据,称为写穿通到读;
2、写和写冲突:表示两个端口写使能同时有效且写地址相同,此时需要关断一个写,把两个写端口都需要更新的值处理到一个写端口上面,任何的DP RAM 都不支持写和写冲突。
三、真双口RAM读写代码
//ram的读写信号
reg his_wea,his_enb;
reg [7:0] his_addra,his_addrb;
reg [31:0] his_dina;
wire [31:0] his_doutb;
his_ge0 his_get_inst(
.clka(clk), // input wire clka
.wea(his_wea), // input wire [0 : 0] wea
.addra(his_addra), // input wire [7 : 0] addra
.dina(his_dina), // input wire [31 : 0] dina
.clkb(clk), // input wire clkb
.enb(his_enb), // input wire enb
.addrb(his_addrb), // input wire [7 : 0] addrb
.doutb(his_doutb) // output wire [31 : 0] doutb
);
//控制RAM的A端口(写端口)
always @(*) begin
if(state_1 == CLEAR) begin
his_wea = clear_flag;
his_addra = clear_cnt;
his_dina = 32'd0;
end
else if(state_1 == CUL) begin
his_wea = pix_same_flag;
his_addra = per_img_8bit_dly2;
his_dina = cul_data;
end
else begin
his_wea = 1'b0;
his_addra = 8'd0;
his_dina = 32'd0;
end
end
//控制RAM的B端口(读端口)
always @(*) begin
if(state_1 == CUL) begin
his_enb = per_frame_clken;
his_addrb = per_img_8bit;
end
else if(state_1 == GET) begin
his_enb = state_1 == GET;
his_addrb = get_cnt;
end
else begin
his_enb = 1'b0;
his_addrb = 8'd0;
end
end
以上述直方图统计使用为例,博主在仿真过程中发现,vivado真双口RAM--B端口读写延迟2个clk;故统计时需要将数据提前两个时钟写入,如下图:
图上可以看出,addr_b 为2时,data_b才开始输出;
但Quartus平台上的真双口RAM--B端口读写却只延迟1个clk;故统计时只需要提前一个时钟写入即可,如下图:
所以,在使用时尤其是算法实现的过程中一定要仔细注意这类问题,写这篇文章提醒自己也分享给大家!!!