Как инициализировать содержимое логического блока RAM (BRAM) в Verilog

У меня проблемы с инициализацией содержимого предполагаемого барана в Verilog. Код для оперативной памяти, как показано ниже:

module ram(
        input clock, // System clock
        input we, // When high RAM sets data in input lines to given address
        input [13:0] data_in, // Data lines to write to memory
        input [10:0] addr_in, // Address lines for saving data to memory
        input [10:0] addr_out, // Address for reading from ram
        output reg data_out // Data out
);

reg [13:0] ram[2047:0];

// Initialize RAM from file
// WHAT SHOULD GO HERE?

always @(posedge clock) begin
    // Save data to RAM
    if (we) begin
        ram[addr_in] <= data_in;
    end

    // Place data from RAM
    data_out <= ram[addr_out];
end        
endmodule

Я столкнулся с командой $ readmemh. Тем не менее, документация для этого кажется скудной. Как мне отформатировать файл, содержащий данные? Кроме того, как я могу передать файл в качестве аргумента при создании экземпляра этого модуля, чтобы иметь возможность загружать разные экземпляры этого модуля из разных файлов?

Я хочу, чтобы инициализированный контент был доступен как для моделирования, так и для фактической реализации. Так что FPGA уже загружается с этим содержимым в оперативной памяти.

Я использую Vivado 2015.4 для программирования FPGA Kintex xc7k70.

3 ответа

Решение

Вы правы, что вы должны использовать $readmemh внутри начального блока. Чтобы сделать так, чтобы разные экземпляры модуля могли иметь разные файлы инициализации, вы должны использовать такой параметр:

parameter MEM_INIT_FILE = "";
...
initial begin
  if (MEM_INIT_FILE != "") begin
    $readmemh(MEM_INIT_FILE, ram);
  end
end

Формат описан в разделе 21.4 спецификации IEEE1800-2012; обычно файл представляет собой просто набор строк, содержащих шестнадцатеричные числа правильной битовой длины, например:

0001
1234
3FFF
1B34
...

Обратите внимание, что префикса "0x" нет, и каждая строка представляет соседний адрес (или любой разделяющий пробел). В приведенном выше примере $readmemh поставил бы 14'h0001 в ram[0], 14'h1234 в ram[1], 14'h3FFF в ram[2] и так далее. Вы также можете включить комментарии в шестнадцатеричный файл, используя // или же /* */, Наконец, вы можете использовать @ символ для обозначения адреса для следующих номеров, например:

@0002
0101
0A0A
...

В приведенном выше файле ram[0] а также ram[1] будет неинициализирован и ram[2] мог получить 14'h0101, Это все основные конструкции формата шестнадцатеричного файла, хотя вы также можете использовать _, x а также z как и в других номерах Verilog, есть еще несколько правил, которые вы можете прочитать в разделе выше.

Помимо превосходных ответов @Unn, я хочу добавить это, если вы просто хотите инициализировать вашу память со всеми битами в 1'b1 или же 1'b0тогда вы можете просто поставить следующий код,

integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = {WIDTH{MEM_INIT_VAL}};

Для вашего случая WIDTH=14, а MEM_INIT_VAL может быть 1'b1 или же 1'b0,

Поскольку в вашем вопросе цитируются теги #xilinx и #vivado, я хотел бы предложить вам также использовать xpm_memoryсемейство примитивов для создания экземпляра параметризованной памяти. Преимущества такого подхода:

  1. Экспортирует в точности аппаратные возможности ресурсов памяти FPGA (т. Е. Заставляет вас четко задуматься об ограничениях, таких как порты памяти).

  2. Гарантирует правильное идентичное поведение в симуляции и на рабочем столе для примитивов памяти.

  3. Вы можете разрешить Vivado выбрать наиболее эффективную реализацию памяти (BRAM, UltraRAM, распределенную RAM, flops) во время синтеза в соответствии с вашими конструктивными ограничениями.

  4. Легко настраивается (включает или отключает внутренние этапы конвейера и т. Д.).

С учетом сказанного, чисто предполагаемые воспоминания часто легче кодировать. Но все же стоит ознакомиться с примитивами памяти, предоставляемыми Xilinx, чтобы вы имели более четкое представление о том, что Vivado может легко синтезировать, а что нет.

Для получения дополнительной информации см. UG573, Руководство пользователя ресурсов памяти Vivado:

https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf

integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = j;

Это может быть легко в случае отладки, где значением местоположения является номер его местоположения.

Также я бы предложил не инициализировать ОЗУ. Это поможет вам в обнаружении ошибок, если таковые имеются, в симуляции, поскольку управляемые данные будут равны x, если оперативная память не инициализирована и может быть легко обнаружена.

Другие вопросы по тегам