Как инициализировать содержимое логического блока 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
семейство примитивов для создания экземпляра параметризованной памяти. Преимущества такого подхода:
Экспортирует в точности аппаратные возможности ресурсов памяти FPGA (т. Е. Заставляет вас четко задуматься об ограничениях, таких как порты памяти).
Гарантирует правильное идентичное поведение в симуляции и на рабочем столе для примитивов памяти.
Вы можете разрешить Vivado выбрать наиболее эффективную реализацию памяти (BRAM, UltraRAM, распределенную RAM, flops) во время синтеза в соответствии с вашими конструктивными ограничениями.
Легко настраивается (включает или отключает внутренние этапы конвейера и т. Д.).
С учетом сказанного, чисто предполагаемые воспоминания часто легче кодировать. Но все же стоит ознакомиться с примитивами памяти, предоставляемыми 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, если оперативная память не инициализирована и может быть легко обнаружена.