Jump to content
    

Инициализация памяти содержимым hex-файла

Всем привет.

Пишу для Cyclone 3 на SV простенький RISC-V МК с однотактным процессором. За основу взял пример неполной реализации базового набора команд из книжки Харрисов.

В примере есть память команд, представляющая собой массив 32-р слов.

Инициализируется память так: $readmemh("Program.txt", RAM)

В текстовом файле лежат подряд 32-р команды в шестнадцатеричном формате:

00000093

00108093

4000а113

....

Для пробы я написал на ассемблере небольшую программу, перевел ее в коды и записал коды в столбик, как в примере выше, но дальше  хочу писать прошивки в какой-нибудь IDE и использовать для инициализации hex-файлы

Вопрос: как инициализировать содержимое памяти hex-файлом?  

 

Edited by Zuse

Share this post


Link to post
Share on other sites

а чем корка ROM не устраивает? она же может инициализироваться из хекса

Share this post


Link to post
Share on other sites

11 minutes ago, des00 said:

а чем корка ROM не устраивает? она же может инициализироваться из хекса

Я признаться новичок в теме и не владею сленгом. Что такое "корка" ?

Share this post


Link to post
Share on other sites

13 минут назад, des00 сказал:

а чем корка ROM не устраивает? она же может инициализироваться из хекса

И каждый раз проект заново компилить?

Share this post


Link to post
Share on other sites

2 часа назад, Zuse сказал:

 использовать для инициализации hex-файлы

Вопрос: как инициализировать содержимое памяти hex-файлом?  

Hex2mif

A script to convert hex instructions to Quartus .mif files · GitHub

 

Share this post


Link to post
Share on other sites

1 hour ago, Zuse said:

Что такое "корка"

IP core.

 

Share this post


Link to post
Share on other sites

3 часа назад, Lmx2315 сказал:

И каждый раз проект заново компилить?

Для симуляции вроде не надо,,,

Для релиза есть два стандартных пути:

1 сделать память двухпортовой и внешним автоматом из порта грузить команды

2 сделать программу загрузчик и по сбросу из порта грузить память команд

3 сделать монитор-загрузчик и вообще все отлаживать в программном режиме...т.е например при шаговой отладке переходить на теневое пзу и выдавать на хост содержание всех ресурсов процессора

Share this post


Link to post
Share on other sites

7 hours ago, Zuse said:

но дальше  хочу писать прошивки в какой-нибудь IDE и использовать для инициализации hex-файлы

eclipse + gcc + objcopy

Share this post


Link to post
Share on other sites

4 часа назад, iosifk сказал:

Для симуляции вроде не надо,,,

Для релиза есть два стандартных пути:

1 сделать память двухпортовой и внешним автоматом из порта грузить команды

2 сделать программу загрузчик и по сбросу из порта грузить память команд

3 сделать монитор-загрузчик и вообще все отлаживать в программном режиме...т.е например при шаговой отладке переходить на теневое пзу и выдавать на хост содержание всех ресурсов процессора

Ну а если "раскинуть остатками", то задается вопрос: а не хотите ли симулировать вообще без пзу?

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

Вычитали команду, посунули ее процессору и дали ему клок.., вот так точно проект каждый раз компилить не придется. Меняется только файл команд, а не сам процессор...

Share this post


Link to post
Share on other sites

13 hours ago, Lmx2315 said:

И каждый раз проект заново компилить?

зачем? через житаг же можно залить. Например в том же пикоблейзе все есть, даже загрузка ПО на горячую. Сорцы доступны)

Share this post


Link to post
Share on other sites

17 hours ago, iosifk said:

Hex2mif

A script to convert hex instructions to Quartus .mif files · GitHub

 

А разве $readmem переваривает .mif файлы?

Но идея понятна - должен быть конвертер hex'а в формат, который понимает $readmem

Edited by Zuse

Share this post


Link to post
Share on other sites

Только пока не удается нагуглить подходящий конвертер. Может, кто знает подходящий?

UPD. Для истории: нужно гуглить "Intel HEX to Verilog converter"

Edited by Zuse

Share this post


Link to post
Share on other sites

1 hour ago, Zuse said:

Но идея понятна - должен быть конвертер hex'а в формат, который понимает $readmem

Так есть же $readmemh  который сразу  читает в hex.   

Share this post


Link to post
Share on other sites

49 minutes ago, RobFPGA said:

Так есть же $readmemh  который сразу  читает в hex.   

Насколько понимаю, он читает не Intel-Hex, а файл шестнадцатеричных констант, разделенных пробелами/табами/энтерами

Конвертер я таки нашел:

https://github.com/dev-board-tech/intel-hex-to-rtl-mem

Edited by Zuse

Share this post


Link to post
Share on other sites

On 5/19/2023 at 11:23 AM, RobFPGA said:

$readmemh

Функции из Verilog позволяют инициализировать содержимое памяти, но в отсинтезированном проекте при их использовании нельзя обновлять содержимое памяти без пересборки всего проекта целиком - используйте готовый IP для RAM/ROM или мегафункцию altsyncram и сможете обновлять содержимое памяти всего парой команд: Processing->Update Memory Initialization File, Processing->Start->Start Assembler.

Вот пример:

`timescale 1 ns / 1 ps

module picorv32_prog_wrapper
#(
	parameter DATA_SIZE     = 8192,
	parameter DATA_WIDTH    =   32,
	parameter INIT_FILE     = "picorv32_fw.mem",
	parameter FPGA_VENDOR   = "SIM",
	parameter DEVICE_FAMILY = "SIM",
	parameter SIM_INIT      = "FALSE"
)
(
	input clock,
	input [$clog2(DATA_SIZE)-1:0] address,
	input [DATA_WIDTH-1:0] data,
	input wren,
	output [DATA_WIDTH-1:0] q
) ;


generate
if ((FPGA_VENDOR == "ALTERA") | (FPGA_VENDOR == "INTEL")) begin


altsyncram		#(
				.clock_enable_input_a   ("BYPASS"),
				.clock_enable_output_a  ("BYPASS"),
				.init_file              (INIT_FILE),
				.intended_device_family (DEVICE_FAMILY),
				.lpm_type               ("altsyncram"),
				.numwords_a             (DATA_SIZE),
				.operation_mode         ("SINGLE_PORT"),
				.outdata_aclr_a         ("NONE"),
				.outdata_reg_a          ("CLOCK0"),
				.power_up_uninitialized ("FALSE"),
				.widthad_a              ($clog2(DATA_SIZE)),
				.width_a                (DATA_WIDTH),
				.width_byteena_a        (1)
				)
				
				program_ram (
				.clock0                 (clock),
				.clock1                 (1'b1),
				.address_a              (address),
				.address_b              ({$clog2(DATA_SIZE){1'b0}}),
				.data_a                 (data),
				.data_b                 ({DATA_WIDTH{1'b0}}),
				.wren_a                 (wren),
				.wren_b                 (1'b0),
				.q_a                    (q),
				.q_b                    (),
				.aclr0                  (1'b0),
				.aclr1                  (1'b0),
				.byteena_a              (1'b1),
				.byteena_b              (1'b1),
				.addressstall_a         (1'b0),
				.addressstall_b         (1'b0),
				.clocken0               (1'b1),
				.clocken1               (1'b1),
				.clocken2               (1'b1),
				.clocken3               (1'b1),
				.rden_a                 (1'b1),
				.rden_b                 (1'b1),
				.eccstatus              ()
				) ;


end
else if (FPGA_VENDOR == "XILINX") begin


xpm_memory_spram #(
				.ADDR_WIDTH_A           ($clog2(DATA_SIZE)),
				.AUTO_SLEEP_TIME        (0),
				.BYTE_WRITE_WIDTH_A     (DATA_WIDTH),
				.CASCADE_HEIGHT         (0),
				.ECC_MODE               ("no_ecc"),
				.MEMORY_INIT_FILE       (INIT_FILE),
				.MEMORY_INIT_PARAM      ("0"),
				.MEMORY_OPTIMIZATION    ("false"),
				.MEMORY_PRIMITIVE       ("block"),
				.MEMORY_SIZE            (DATA_WIDTH*DATA_SIZE),
				.MESSAGE_CONTROL        (0),
				.READ_DATA_WIDTH_A      (DATA_WIDTH),
				.READ_LATENCY_A         (2),
				.READ_RESET_VALUE_A     ("0"),
				.RST_MODE_A             ("ASYNC"),
				.SIM_ASSERT_CHK         (0),
				.USE_MEM_INIT           (1),
				.WAKEUP_TIME            ("disable_sleep"),
				.WRITE_DATA_WIDTH_A     (DATA_WIDTH),
				.WRITE_MODE_A           ("no_change")
				)
				
				program_ram (
				.dbiterra               (),
				.douta                  (q),
				.sbiterra               (),
				.addra                  (address),
				.clka                   (clock),
				.dina                   (data),
				.ena                    (1'b1),
				.injectdbiterra         (1'b0),
				.injectsbiterra         (1'b0),
				.regcea                 (1'b1),
				.rsta                   (1'b0),
				.sleep                  (1'b0),
				.wea                    (wren)
				) ;


end
else if (FPGA_VENDOR == "LATTICE") begin


pmi_ram_dq		#(
				.pmi_addr_width         ($clog2(DATA_SIZE)),
				.pmi_addr_depth         (DATA_SIZE),
				.pmi_data_width         (DATA_WIDTH),
				.pmi_regmode            ("reg"),
				.pmi_gsr                ("disable"),
				.pmi_resetmode          ("async"),
				.pmi_optimization       ("speed"),
				.pmi_init_file          (INIT_FILE),
				.pmi_init_file_format   ("hex"),
				.pmi_write_mode         ("normal"),
				.pmi_family             (DEVICE_FAMILY)
				)
				
				program_ram (
				.Reset                  (1'b0),
				.Clock                  (clock),
				.ClockEn                (1'b1),
				.Address                (address),
				.Data                   (data),
				.WE                     (wren),
				.Q                      (q)
				) ;


end
else begin


end
endgenerate


endmodule

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...