添加number_of_lines <= ram[0]后Vivado未综合BRAM生成LUT,求改写方案
解决Verilog双端口RAM无法综合为BRAM的问题
问题根源
原代码中双端口RAM的B时钟域(clkb)在同一周期内存在两次读操作:
- 当
new_addr==0时,读取ram[0]赋值给number_of_lines - 同时读取
ram[new_addr]赋值给dob
BRAM的双端口特性要求每个时钟端口单周期内仅支持一次读/写操作,B端口的两次读违反了这个约束,导致Vivado无法将寄存器数组映射为BRAM,只能用LUT实现。
改写方案
核心思路是让B端口单周期内仅执行一次读操作,通过缓存读出的数据来同时满足dob和number_of_lines的赋值需求,同时保持原有逻辑功能不变。
改写后的代码
module bram3 (clka,clkb,ena,enb,wea,web,addra,dia,dib,doa,dob,rst); input clka,clkb,ena,enb,wea,web,rst; input [11:0] addra; input [63:0] dia,dib; output [63:0] dob, doa; reg [32:0] ram [254:0]; reg [32:0] dob, doa; reg [11:0] new_addr=0; reg [11:0] number_of_lines=0; reg [32:0] ram_read_b; // 缓存B端口单次读出的数据 always @(posedge clka) begin if (ena) begin if (wea) ram[addra] <= dia; doa <= ram[addra]; end end always @(posedge clkb or negedge rst) begin if (!rst) begin new_addr <= 0; number_of_lines <= 0; dob <= 0; ram_read_b <= 0; end else if (enb) begin // 单周期仅执行一次RAM读操作 ram_read_b <= ram[new_addr]; // 用缓存的读数据给目标寄存器赋值 dob <= ram_read_b; if (new_addr == 0) begin number_of_lines <= ram_read_b; end // 重构地址更新逻辑,避免时序冲突 if (new_addr == number_of_lines) begin new_addr <= 0; end else begin new_addr <= new_addr + 1; end end end endmodule
关键修改点
- 新增
ram_read_b寄存器,缓存B端口每个周期读出的单份数据,确保单周期仅对RAM执行一次读操作。 - 调整赋值顺序:先完成RAM读操作,再将缓存的数据分发给
dob和number_of_lines(当new_addr==0时),消除重复读操作。 - 重构
new_addr的更新逻辑,使用分支替代原顺序赋值,避免时序冲突,同时保留原有循环功能。
额外说明
如果ram[0]会被A端口(clka)写入,需注意跨时钟域数据同步问题。若需要严格一致性,可以在A端口写入ram[0]时,添加同步寄存器将数据传递到B时钟域,触发number_of_lines的更新。
内容的提问来源于stack exchange,提问作者dduy_le
相关产品推荐
相关产品推荐

