Skip to content

Commit

Permalink
[image_generator] add *.mif memory initialization file format (#949)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed Jul 12, 2024
2 parents 792cc45 + 412f3c2 commit 4ae5948
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ __pycache__
*.bin
*.coe
*.mem
*.mif
*.o
*.elf
*.asm
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ This overview provides some *quick links* to the most important sections of the
* [Software Framework Documentation](https://stnolting.github.io/neorv32/sw/files.html) - _doxygen_-based
* [Application Makefile](https://stnolting.github.io/neorv32/#_application_makefile) - turning _your_ application into an executable
* [Bootloader](https://stnolting.github.io/neorv32/#_bootloader) - the build-in NEORV32 bootloader
* [Image Generator](https://stnolting.github.io/neorv32/#_executable_image_format) - create (FPGA) memory initialization files from your application

### :rocket: [User Guide](https://stnolting.github.io/neorv32/ug/) - Getting Started!

Expand Down
46 changes: 28 additions & 18 deletions docs/datasheet/software.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,12 @@ Targets:
gdb - run GNU debugging session
asm - compile and generate <main.asm> assembly listing file for manual debugging
elf - compile and generate <main.elf> ELF file
bin - compile and generate <neorv32_raw_exe.bin> RAW executable file (binary file, no header)
hex - compile and generate <neorv32_raw_exe.hex> RAW executable file (hex char file, no header)
coe - compile and generate <neorv32_raw_exe.coe>> RAW executable file (COE file, no header)
mem - compile and generate <neorv32_raw_exe.mem>> RAW executable file (MEM file, no header)
exe - compile and generate <neorv32_exe.bin> executable image file for upload via default bootloader (binary file)
bin - compile and generate <neorv32_raw_exe.bin> RAW executable memory image (binary file)
hex - compile and generate <neorv32_raw_exe.hex> RAW executable memory image (hex char file)
coe - compile and generate <neorv32_raw_exe.coe> RAW executable memory image (COE file)
mem - compile and generate <neorv32_raw_exe.mem> RAW executable memory image (MEM file)
mif - compile and generate <neorv32_raw_exe.mif> RAW executable memory image (MIF file)
image - compile and generate VHDL IMEM boot image (for application, no header) in local folder
install - compile, generate and install VHDL IMEM boot image (for application, no header)
sim - in-console simulation using default/simple testbench and GHDL
Expand Down Expand Up @@ -288,7 +290,7 @@ The makefile's `CC_OPTS` is exported as **define** to be available within a C pr
| `-g` | Include debugging information/symbols in ELF.
| `-mstrict-align` | Unaligned memory accesses cannot be resolved by the hardware and require emulation.
| `-mbranch-cost=10` | Branching costs a lot of cycles.
| `-ffp-contract=off` | Do not allow contraction of floatind-point operations (no fused operations as they are not supported).
| `-ffp-contract=off` | Do not allow contraction of floating-point operations (no fused operations as they are not supported).
|=======================
:sectnums:
Expand Down Expand Up @@ -321,15 +323,23 @@ override USER_FLAGS += "-g -Wl,--__neorv32_heap_size,__heap_size=4096"
=== Executable Image Format

In order to generate an executable for the processors all source files have to be compiled, linked
and packed into a final executable.
and packed into a final executable. This executable can be further converted into several image formats.

.Memory Image Formats
[TIP]
The NEORV32 software framework includes an <<_executable_image_generator>> than can convert an application
into several different file formats. These include raw hex files, a proprietary format for uploading via the
default <<_bootloader>> as well as several standard FPGA memory initialization file types (e.g. `*.coe`,
`*.mem` and `*.mif`). These image file formats are generated by the according <<_makefile_targets>>.


:sectnums:
==== Linker Script

After all the application sources have been compiled, they need to be _linked_.
For this purpose the makefile uses the NEORV32-specific linker scThe linker script defines several sections
For this purpose the makefile uses the NEORV32-specific linker script. This linker script defines several sections
for the final executable (compare with <<_address_space>>). However, only the `ram` and `rom` sections are
relevant for the executable itself; the raining sections are just listed fro completeness.
relevant for the executable itself; the remaining sections are just listed for completeness.

.Linker script - memory sections
[cols="<2,<8"]
Expand Down Expand Up @@ -486,21 +496,21 @@ The image generator can generate several types of executable file formats select
[cols="<2,<8"]
[grid="none"]
|=======================
| `-app_bin` | Generates an executable binary file `neorv32_exe.bin` (including header) for UART uploading via the bootloader.
| `-app_img` | Generates an executable VHDL memory initialization image (no header) for the processor-internal IMEM. This option generates the `rtl/core/neorv32_application_image.vhd` file.
| `-bld_img` | Generates an executable VHDL memory initialization image (no header) for the processor-internal BOOT ROM. This option generates the `rtl/core/neorv32_bootloader_image.vhd` file.
| `-raw_hex` | Generates a plain 8x ASCII hex-char file `neorv32_raw_exe.hex` (no header) for custom purpose.
| `-raw_bin` | Generates a plain binary file `neorv32_raw_exe.bin` (no header) for custom purpose.
| `-raw_coe` | Generates a COE file `neorv32_raw_exe.coe` (no header) for FPGA memory initialization.
| `-raw_mem` | Generates a MEM file `neorv32_raw_exe.mem` (no header) for FPGA memory initialization.
| `-app_bin` | Generates an executable binary file `neorv32_exe.bin` (including bootloader header) for uploading via the bootloader.
| `-app_img` | Generates an executable VHDL memory initialization image for the processor-internal IMEM. This option regenerates the `rtl/core/neorv32_application_image.vhd` file.
| `-bld_img` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM. This option regenerates the `rtl/core/neorv32_bootloader_image.vhd` file.
| `-raw_hex` | Generates a raw 8x ASCII hex-char file `neorv32_raw_exe.hex` for custom purpose.
| `-raw_bin` | Generates a raw binary file `neorv32_raw_exe.bin` for custom purpose.
| `-raw_coe` | Generates a raw COE file `neorv32_raw_exe.coe` for FPGA memory initialization.
| `-raw_mem` | Generates a raw MEM file `neorv32_raw_exe.mem` for FPGA memory initialization.
| `-raw_mif` | Generates a raw MIF file `neorv32_raw_exe.mif` for FPGA memory initialization.
|=======================
All these options are managed by the makefile. The normal application compilation flow will generate the `neorv32_exe.bin`
executable designated for uploading via the default NEORV32 bootloader.
**All these options are managed by the makefile (see <<_makefile_targets>>).**
.Image Generator Compilation
[NOTE]
The sources of the image generator are automatically compiled when invoking the makefile (requiring a native GCC installation).
The sources of the image generator are automatically compiled when invoking the makefile (requiring a _native_ GCC installation).

.Executable Header
[NOTE]
Expand Down
22 changes: 15 additions & 7 deletions sw/common/common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ APP_HEX = neorv32_raw_exe.hex
APP_BIN = neorv32_raw_exe.bin
APP_COE = neorv32_raw_exe.coe
APP_MEM = neorv32_raw_exe.mem
APP_MIF = neorv32_raw_exe.mif
APP_ASM = main.asm
APP_IMG = neorv32_application_image.vhd
BOOT_IMG = neorv32_bootloader_image.vhd
Expand Down Expand Up @@ -142,9 +143,10 @@ hex: $(APP_HEX)
bin: $(APP_BIN)
coe: $(APP_COE)
mem: $(APP_MEM)
mif: $(APP_MIF)
image: $(APP_IMG)
install: image install-$(APP_IMG)
all: $(APP_ASM) $(APP_EXE) $(APP_HEX) $(APP_BIN) $(APP_COE) $(APP_MEM) $(APP_IMG) install hex bin
all: $(APP_ASM) $(APP_EXE) $(APP_HEX) $(APP_BIN) $(APP_COE) $(APP_MEM) $(APP_MIF) $(APP_IMG) install hex bin

# Check if making bootloader
# Use different base address and length for instruction memory/"rom" (BOOTROM instead of IMEM)
Expand Down Expand Up @@ -236,6 +238,11 @@ $(APP_COE): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -raw_coe $< $@ $(shell basename $(CURDIR))

# Generate NEORV32 RAW executable image in MIF format
$(APP_MIF): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -raw_mif $< $@ $(shell basename $(CURDIR))

# Generate NEORV32 RAW executable image in MEM format
$(APP_MEM): main.bin $(IMAGE_GEN)
@set -e
Expand Down Expand Up @@ -314,7 +321,7 @@ gdb:
# Clean up
# -----------------------------------------------------------------------------
clean:
@rm -f *.elf *.o *.bin *.coe *.mem *.out *.asm *.vhd *.hex .gdb_history
@rm -f *.elf *.o *.bin *.coe *.mem *.mif *.out *.asm *.vhd *.hex .gdb_history

clean_all: clean
@rm -f $(OBJ) $(IMAGE_GEN)
Expand Down Expand Up @@ -372,11 +379,12 @@ help:
@echo " gdb - run GNU debugging session"
@echo " asm - compile and generate <$(APP_ASM)> assembly listing file for manual debugging"
@echo " elf - compile and generate <$(APP_ELF)> ELF file"
@echo " exe - compile and generate <$(APP_EXE)> executable for upload via default bootloader (binary file, with header)"
@echo " bin - compile and generate <$(APP_BIN)> RAW executable file (binary file, no header)"
@echo " hex - compile and generate <$(APP_HEX)> RAW executable file (hex char file, no header)"
@echo " coe - compile and generate <$(APP_COE)> RAW executable file (COE file, no header)"
@echo " mem - compile and generate <$(APP_MEM)> RAW executable file (MEM file, no header)"
@echo " exe - compile and generate <$(APP_EXE)> executable image file for upload via default bootloader (binary file)"
@echo " bin - compile and generate <$(APP_BIN)> RAW executable memory image (binary file)"
@echo " hex - compile and generate <$(APP_HEX)> RAW executable memory image (hex char file)"
@echo " coe - compile and generate <$(APP_COE)> RAW executable memory image (COE file)"
@echo " mem - compile and generate <$(APP_MEM)> RAW executable memory image (MEM file)"
@echo " mif - compile and generate <$(APP_MIF)> RAW executable memory image (MIF file)"
@echo " image - compile and generate VHDL IMEM boot image (for application, no header) in local folder"
@echo " install - compile, generate and install VHDL IMEM boot image (for application, no header)"
@echo " sim - in-console simulation using default/simple testbench and GHDL"
Expand Down
68 changes: 57 additions & 11 deletions sw/image_gen/image_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@
// executable signature ("magic word")
const uint32_t signature = 0x4788CAFE;

enum operation_enum {OP_APP_BIN, OP_APP_IMG, OP_BLD_IMG, OP_RAW_HEX, OP_RAW_BIN, OP_RAW_COE, OP_RAW_MEM};
// output file types (operation select)
enum operation_enum {
OP_APP_BIN,
OP_APP_IMG,
OP_BLD_IMG,
OP_RAW_HEX,
OP_RAW_BIN,
OP_RAW_COE,
OP_RAW_MEM,
OP_RAW_MIF
};

int main(int argc, char *argv[]) {

Expand All @@ -32,6 +42,7 @@ int main(int argc, char *argv[]) {
" -raw_bin : Generate application raw executable (binary file, no header)\n"
" -raw_coe : Generate application raw executable (COE file, no header)\n"
" -raw_mem : Generate application raw executable (MEM file, no header)\n"
" -raw_mif : Generate application raw executable (MIF file, no header)\n"
"2nd: Input file (raw binary image)\n"
"3rd: Output file\n"
"4th: Project name or folder (optional)\n");
Expand All @@ -53,6 +64,7 @@ int main(int argc, char *argv[]) {
else if (strcmp(argv[1], "-raw_bin") == 0) { operation = OP_RAW_BIN; }
else if (strcmp(argv[1], "-raw_coe") == 0) { operation = OP_RAW_COE; }
else if (strcmp(argv[1], "-raw_mem") == 0) { operation = OP_RAW_MEM; }
else if (strcmp(argv[1], "-raw_mif") == 0) { operation = OP_RAW_MIF; }
else {
printf("Invalid operation!");
return -1;
Expand Down Expand Up @@ -87,8 +99,7 @@ int main(int argc, char *argv[]) {
}

// --------------------------------------------------------------------------
// Try to find out targeted CPU configuration
// via MARCH environment variable
// Try to find out targeted CPU configuration via MARCH environment variable
// --------------------------------------------------------------------------
char string_march[64] = "default";
char *envvar_march = "MARCH";
Expand Down Expand Up @@ -130,7 +141,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate BINARY executable (with header) for bootloader upload
// Generate BINARY executable for bootloader upload (with header)
// --------------------------------------------------------------------------
if (operation == OP_APP_BIN) {

Expand Down Expand Up @@ -189,7 +200,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate APPLICATION's executable memory initialization file (no header)
// Generate RAW APPLICATION's executable memory initialization file
// -> VHDL package body
// --------------------------------------------------------------------------
else if (operation == OP_APP_IMG) {
Expand Down Expand Up @@ -246,7 +257,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate BOOTLOADER's executable memory initialization file (no header)
// Generate RAW BOOTLOADER's executable memory initialization file
// -> VHDL package body
// --------------------------------------------------------------------------
else if (operation == OP_BLD_IMG) {
Expand Down Expand Up @@ -303,7 +314,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate raw APPLICATION's executable ASCII hex file (no header)
// Generate RAW APPLICATION's executable ASCII hex file
// --------------------------------------------------------------------------
else if (operation == OP_RAW_HEX) {

Expand All @@ -319,7 +330,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate raw APPLICATION's executable binary file (no header)
// Generate RAW APPLICATION's executable binary file
// --------------------------------------------------------------------------
else if (operation == OP_RAW_BIN) {

Expand All @@ -330,7 +341,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate raw APPLICATION's executable COE file (no header)
// Generate RAW APPLICATION's executable COE file
// --------------------------------------------------------------------------
else if (operation == OP_RAW_COE) {

Expand Down Expand Up @@ -363,7 +374,7 @@ int main(int argc, char *argv[]) {


// --------------------------------------------------------------------------
// Generate raw APPLICATION's executable MEM file (no header)
// Generate RAW APPLICATION's executable MEM file
// --------------------------------------------------------------------------
else if (operation == OP_RAW_MEM) {

Expand All @@ -380,6 +391,42 @@ int main(int argc, char *argv[]) {
}


// --------------------------------------------------------------------------
// Generate RAW APPLICATION's executable MIF file
// --------------------------------------------------------------------------
else if (operation == OP_RAW_MIF) {

// header
sprintf(tmp_string, "DEPTH = %lu;\n", raw_exe_size/4); // memory depth in words
fputs(tmp_string, output);
sprintf(tmp_string, "WIDTH = 32;\n"); // bits per data word
fputs(tmp_string, output);
sprintf(tmp_string, "ADDRESS_RADIX = HEX;\n"); // hexadecimal address format
fputs(tmp_string, output);
sprintf(tmp_string, "DATA_RADIX = HEX;\n"); // hexadecimal data format
fputs(tmp_string, output);

sprintf(tmp_string, "CONTENT\n");
fputs(tmp_string, output);
sprintf(tmp_string, "BEGIN\n");
fputs(tmp_string, output);
i = 0;
while(fread(&buffer, sizeof(unsigned char), 4, input) != 0) {
tmp = (uint32_t)(buffer[0] << 0);
tmp |= (uint32_t)(buffer[1] << 8);
tmp |= (uint32_t)(buffer[2] << 16);
tmp |= (uint32_t)(buffer[3] << 24);
sprintf(tmp_string, "%08x : %08x;\n", (unsigned int)i, (unsigned int)tmp);
fputs(tmp_string, output);
i++;
}

// footer
sprintf(tmp_string, "END;\n");
fputs(tmp_string, output);
}


// --------------------------------------------------------------------------
// Invalid operation
// --------------------------------------------------------------------------
Expand All @@ -394,7 +441,6 @@ int main(int argc, char *argv[]) {
// --------------------------------------------------------------------------
// Done, clean up
// --------------------------------------------------------------------------

fclose(input);
fclose(output);

Expand Down

0 comments on commit 4ae5948

Please sign in to comment.