综合和推断 ROM 存储器设计中的 quartus prime 问题 - Verilog

问题描述 投票:0回答:1

当我尝试按照 quartus prime 模板建议为我的项目编写定制 ROM 时,我最终得到了这个模块:

// Quartus Prime Verilog Template
// Single Port ROM

module memory
#(parameter DATA_WIDTH=256, parameter ADDR_WIDTH=12, parameter OUT_WIDTH=4)
(
    input wire [(ADDR_WIDTH-1):0] addr,
    input wire clk, 
    input wire [7:0] index,
    output reg [(OUT_WIDTH-1):0] q
);

    // Declare the ROM variable
    reg [DATA_WIDTH-1:0] rom[2**ADDR_WIDTH-1:0];

    initial
    begin
        $readmemb("test.txt", rom);
    end
    
    
    always @ (posedge clk)
    begin
        q <= {rom[addr+3][index], rom[addr+2][index], rom[addr+1][index], rom[addr][index]};
    end

endmodule

但出乎意料的是,quartus 无法合成和推断

ROM
,而且还编译了很长时间然后崩溃并给出以下消息:

crash message

我确信问题不是来自我的设备,我在不同的设备上尝试过

然后我尝试简化

always block
进行调试和测试,所以我将索引输入替换为常量0,然后它正常工作,没有问题,几分钟内编译完成,并且内存正确推断,请参阅修改:

// Quartus Prime Verilog Template
// Single Port ROM

module memory
#(parameter DATA_WIDTH=256, parameter ADDR_WIDTH=12, parameter OUT_WIDTH=4)
(
    input wire [(ADDR_WIDTH-1):0] addr,
    input wire clk, 
    output reg [(OUT_WIDTH-1):0] q
);

    // Declare the ROM variable
    reg [DATA_WIDTH-1:0] rom[2**ADDR_WIDTH-1:0];

    // Initialize the ROM with $readmemb.  Put the memory contents
    // in the file single_port_rom_init.txt.  Without this file,
    // this design will not compile.

    // See Verilog LRM 1364-2001 Section 17.2.8 for details on the
    // format of this file, or see the "Using $readmemb and $readmemh"
    // template later in this section.

    initial
    begin
        $readmemb("test.txt", rom);
    end
    
    
    always @ (posedge clk)
    begin
        q <= {rom[addr+3][0], rom[addr+2][0], rom[addr+1][0], rom[addr][0]};
    end

endmodule

但我想在我的模块中使用索引,因为我每次都读不同的位,怎么办?

memory verilog quartus
1个回答
0
投票

您对数据结构感到困惑。

您建模的不是ROM。
ROM 和 RAM 一次访问一个地址。 您正在尝试一次访问四个地址:

q <= {rom[addr+3][0], rom[addr+2][0], rom[addr+1][0], rom[addr][0]};

这是一个同步 Verilog ROM 模型

module my_rom
#(parameter DATA_WIDTH=256, parameter ADDR_WIDTH=12, parameter OUT_WIDTH=4)
(
    input wire [(ADDR_WIDTH-1):0] addr,
    input wire clk, 
    input wire [7:0] index,
    output reg [(OUT_WIDTH-1):0] q
);

    // Declare the ROM variable
    reg [DATA_WIDTH-1:0] rom[2**ADDR_WIDTH-1:0];

    initial
    begin
        $readmemb("test.txt", rom);
    end
    
    
    always @ (posedge clk)
    begin
      q <= rom[addr];
    end

endmodule

它一次访问一个地址。

以下是一些指导您思考数据结构的想法:

如果需要一次访问4条数据,则需要将它们存储为4条数据的串联,然后将4条数据一起访问。 将 ROM 的宽度设为您之前想象的 4 倍。

您可以使用状态机读取四个地址并以这种方式创建连接,但是需要 4 个时钟才能完成。

如果您确实需要同时随机访问一堆数据位置,请使用寄存器数组,并编写逻辑来获取您想要的内容。 但是,您将无法使用像

$readmemb("test.txt", rom)
这样的单行代码来初始化它。 您需要在重置期间使用一堆分配或使用状态机动态初始化它。

© www.soinside.com 2019 - 2024. All rights reserved.