rems-project / sail

Sail architecture definition language
Other
617 stars 112 forks source link

Reading binary files. #650

Open kodyvajjha opened 3 months ago

kodyvajjha commented 3 months ago

Is there a sail module to parse and read instructions from a compiled binary file? If so, are there examples of usage which I can follow from somewhere?

Timmmm commented 3 months ago

Not really, that's something you'd normally do outside Sail (i.e. in C). If you give more details about what you're trying to do exactly I could point you in the right direction.

kodyvajjha commented 3 months ago

Thanks for the reply! I'm trying to specify the 6502 ISA in Sail. I have a few instructions specified and have implemented a basic instruction decoder and a top-level fetch and execute loop function. I wanted to test it out on actual assembled binaries.

I noticed that the REPL has a :bin command which allows you to load a binary at a memory location. I thought that I could use that command to populate memory with an assembled ROM file and start fetching instructions from the loaded memory, but perhaps I'm missing something.

Timmmm commented 3 months ago

Yeah you're right - the way this is done in RISC-V is that you load the binary into memory, set the PC to your entry point and then call your step() function in a loop. I haven't really used the REPL much tbh, just the compiled C output.

Basically you would do this:

  1. Make a step function like:
register pc : bits(32)

function step() -> unit = {
   let instruction = mem_read(pc);
   ...
}

To implement mem_read there is built in memory support - see this. Tbh I'm not too sure about lots of that. E.g. instantiate seems new and undocumented. :-D A lot of it is related to the "concurrency model" which you don't need to care about if you are just doing a basic emulator.

  1. Compile to C and use --c-preserve=step so it doesn't dead-code eliminate the step function. In the generated C code it will be called zstep because the name mangling system basically prepends a z and doubles existing z's (i.e. doze -> zdozze).

  2. Load the binary into memory from C, either by calling load_elf() (I dunno if your binary is an ELF file), or you can do it manually with write_mem().

Btw when you compile your C program you have to compile the C files in that directory - at least rts.c and sail.c.

Probably would be good if there was a minimal example for this, but... there isn't, sorry!

I guess if the REPL lets you load a binary you could skip most of that. You just need to make sure your step() function loads the instruction from memory using the built-in memory functions (sail_mem_write() and sail_mem_read()).

Good luck!