You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 22:37:35