【问题标题】:How to infer block RAM in Verilog如何在 Verilog 中推断块 RAM
【发布时间】:2013-12-18 05:12:57
【问题描述】:

我在一个项目中遇到了一个非常具体的问题,这几天一直困扰着我。我有以下用于 RAM 模块的 Verilog 代码:

module RAM_param(clk, addr, read_write, clear, data_in, data_out);
    parameter n = 4;
    parameter w = 8;

    input clk, read_write, clear;
    input [n-1:0] addr;
    input [w-1:0] data_in;
    output reg [w-1:0] data_out;

    reg [w-1:0] reg_array [2**n-1:0];

    integer i;
    initial begin
        for( i = 0; i < 2**n; i = i + 1 ) begin
            reg_array[i] <= 0;
        end
    end

    always @(negedge(clk)) begin
        if( read_write == 1 )
            reg_array[addr] <= data_in;
        if( clear == 1 ) begin
            for( i = 0; i < 2**n; i = i + 1 ) begin
                reg_array[i] <= 0;
            end
        end
        data_out = reg_array[addr];
    end
endmodule

它的行为完全符合预期,但是当我去合成时,我得到以下信息:

Synthesizing Unit <RAM_param_1>.
    Related source file is "C:\Users\stevendesu\---\RAM_param.v".
        n = 11
        w = 16
    Found 32768-bit register for signal <n2059[32767:0]>.
    Found 16-bit 2048-to-1 multiplexer for signal <data_out> created at line 19.
    Summary:
    inferred 32768 D-type flip-flop(s).
    inferred 2049 Multiplexer(s).
Unit <RAM_param_1> synthesized.

32768 人字拖!为什么它不只是推断块 RAM?这个 RAM 模块非常大(我有两个——一个用于指令存储器,一个用于数据存储器),它占用了 FPGA 的整个可用区域...... 2.4 倍

我一直在尝试一切来强制它推断块 RAM 而不是 33k 触发器,但除非我能很快弄清楚,否则我可能不得不大大减小内存的大小以适应芯片。

【问题讨论】:

  • 您是否查看过 FPGA 的数据表以了解它提供的 RAM 类型?可能还有关于从您的 FPGA 供应商处推断 ram 的应用说明。在我的脑海中,我认为大多数公羊可能没有擦除整个公羊的“清晰”功能,所以也许你可以尝试删除它。
  • 合成器无法“推断”一个在您的 FPGA 上实际不存在的结构,并且不同的 FPGA 具有不同的 RAM。这不是 Verilog 问题,您需要阅读 FPGA 手册。
  • 对不起,我更新了新答案,这是 BRAM ,而不是分布式 RAM。真的很抱歉。

标签: verilog type-inference ram


【解决方案1】:

我只是删除了一些你的代码,结果是这样的:

 module RAM_param(clk, addr, read_write, clear, data_in, data_out);
parameter n = 4;
parameter w = 8;

input clk, read_write, clear;
input [n-1:0] addr;
input [w-1:0] data_in;
output reg [w-1:0] data_out;

// Start module here!
reg [w-1:0] reg_array [2**n-1:0];

integer i;
initial begin
    for( i = 0; i < 2**n; i = i + 1 ) begin
        reg_array[i] <= 0;
    end
end

always @(negedge(clk)) begin
    if( read_write == 1 )
        reg_array[addr] <= data_in;
    //if( clear == 1 ) begin
        //for( i = 0; i < 2**n; i = i + 1 ) begin
            //reg_array[i] <= 0;
        //end
    //end
    data_out = reg_array[addr];
end
endmodule  

初始化全零可能不需要代码,如果你想初始化,就这样做:

initial
begin
    $readmemb("data.dat", mem);
end

然后是我从 ISE 13.1 得到的结果

Synthesizing (advanced) Unit <RAM_param>.
INFO:Xst:3231 - The small RAM <Mram_reg_array> will be implemented on LUTs in order to maximize performance and save block RAM resources. If you want to force its implementation on block, use option/constraint ram_style.

    -----------------------------------------------------------------------
    | ram_type           | Distributed                         |          |
    -----------------------------------------------------------------------
    | Port A                                                              |
    |     aspect ratio   | 16-word x 8-bit                     |          |
    |     clkA           | connected to signal <clk>           | fall     |
    |     weA            | connected to signal <read_write>    | high     |
    |     addrA          | connected to signal <addr>          |          |
    |     diA            | connected to signal <data_in>       |          |
    |     doA            | connected to internal node          |         

在此更新!:非常感谢 mcleod_ideafix 抱歉忘记了您的问题:它是块 RAM,不是分布式的。对于块 RAM,您必须强制它:综合 - XST -> 过程属性 -> HDL 选项 -> RAM 样式 -> 从自动更改为块。结果将是这样的:

Synthesizing (advanced) Unit <RAM_param>.
INFO:Xst:3226 - The RAM <Mram_reg_array> will be implemented as a BLOCK RAM, absorbing the following register(s): <data_out>
    -----------------------------------------------------------------------
    | ram_type           | Block                               |          |
    -----------------------------------------------------------------------
    | Port A                                                              |
    |     aspect ratio   | 16-word x 8-bit                     |          |
    |     mode           | read-first                          |          |
    |     clkA           | connected to signal <clk>           | fall     |
    |     weA            | connected to signal <read_write>    | high     |
    |     addrA          | connected to signal <addr>          |          |
    |     diA            | connected to signal <data_in>       |          |
    |     doA            | connected to signal <data_out>      |          |
    -----------------------------------------------------------------------
    | optimization       | speed                               |          |
    -----------------------------------------------------------------------
Unit <RAM_param> synthesized (advanced).

更新结束

我建议您阅读 xst 用户指南以获取 RAM 示例代码和器件数据表。例如,在某些 FPGA LUT RAM 中:复位信号无效。如果您尝试重置它,则必须集成更多要重置的逻辑模块。它导致 D-FF 而不是 RAM。复位信号将自动分配给系统复位。

对于 Block RAM(不是 LUT RAM),我更喜欢特定深度/数据宽度或核心生成,或者直接从库中调用它。 更多通用源代码(ASIC/FPGA)可以在这里找到:http://asic-world.com/examples/verilog/ram_dp_sr_sw.html

【讨论】:

  • 我只是想指出您已经用 RAM 的运行时负载替换了硬件重置。我认为这完全是正确的做法,因为通用 RAM 通常不允许异步重置所有单元,并且 initial 块通常不可合成。
  • 这解决了一切!清晰位实际上是我们教授的示例代码中的内容。我必须让他知道它破坏了一切。
  • 如果有“清除”,一般实现为if (clear==1'b1) begin ... end else if (read_write==1'b1) begin ... end else begin ... end。另外,negedge(clk) 通常写成negedge clk
  • @JoeHass:我知道初始值是不可合成的,但是在 RAM 设计中,零的初始值并不是更多的东西,它只是用于 ROM init 。我只是想让它更短:D。我尝试进行重置,但它没有合成为 RAM(只是 FF 数组)。据我了解,RAM 使用系统重置,而不是用户定义,因为我们不需要在运行时清除 RAM。如果系统这样做,我将其定义为寄存器。
  • 您从 ISE 获得的结果表明已使用分布式 RAM,而不是块 RAM!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多