A user-level emulator for RISC-V 64bit linux userspace. Made to be ran on x86-64 Linux.
A user-level emulator for RISC-V 64bit linux userspace. Made to be ran on x86-64 Linux.
on commit 4f3ebba:
Added a README, should have done this some time ago, but only now the project is starting to get usable. I’ll finish implementing the base ISA, perhaps add some system calls, and then release the version one.
Log in to leave a comment
on commit 1883f67:
RvRun can now interpret arguments, this might have been a bit late, but there are actual things to be set as arguments now. The currently added ones are:
Log in to leave a comment
on commit74aaa7b :
I Added all the W-type instructions, some other ones I had forgotten, and added support for file descriptor related system calls, like openat(), close(), read(), and write(). There is no open() system call on RISC-V, it is only a libc wrapper around open() (no __NR_open macro in include/uapi/asm-generic/unitsd.h under the linux kernel source code).
I am working on passing options to the emulator, writing a README, and making some examples, I’ll probably do that over the weekend. After that, there shouldn’t be that much work other than simple repetitive stuff (aka adding more instructions and more system calls)
I forgot to do the devlog earlier, so about one hour of the time being logged was actually spent adding flag support, haha.
Log in to leave a comment
on commit 1eb5f81:
I implemented ECALL, and can now emulate both exit(2) and exit_group(2) (they are both the same, as I don’t have thread support yet), with now a proper way to decide when a process exits and when it doesn’t, I implemented an actual Von Neumann cycle too.
I am going to iterate back between finishing the implementation of all Rv64I instructions, and supporting more system calls (most likely, file descriptor related ones). My objective is to support all the instructions from Rv64IMFD, and a handful of system calls, in about 2 weeks and a half.
Log in to leave a comment
on commit b264055:
I am finally back! I did some refactoring on src/proc.c yesterday, and implemented the I-type from Rv32I instructions today, I am ignoring the W variations that Rv64I adds for simplicity, I’d like to cover the most important instructions first.
I will probably start basic work on ecall next, so that I can do a real von neumann execution cycle by having an exit system call, after that, I’ll go on with the U-type, B-type, and J-type instructions, before going back to the things I ignored, and continuing with all the system calls.
I will probably change the license to GPLv2, too, and perhaps make some artwork.
Log in to leave a comment
on commit 6423204:
I can now execute all R instructions from Rv64I, except for the “*W” ones. I am downloading and building https://github.com/riscv/riscv-opcodes.git at compile time, setting this in the Makefile was a bit of a pain but I eventually got it. I will now work on some logging/debugging functions, so that I can test the instructions I add properly, and then work on the Register-Immediate instructions.
I’m not sure if I’m going to “speedrun” a hello-world, or try to support most instructions from the base ISA first, but they should both lead to the same outcome.
All of this is being done while I read the specification, and while it can get quite tedious, I feel way better in RISC-V now, I might even write my next project in raw assembly.
Log in to leave a comment
on commit 9611fd6:
I can now load and store values into memory, it respects the permissions set when loading the ELF binary, and fail gracefully both when trying to access out of bound memory or when doing invalid operations (aka writing to a read-only address). Unaligned memory access is also supported, as RISC-V allows that, even if the host machine does not support it. I decided to use C11 to allow for the _Generic macro, and enabled the _GNU_SOURCE macro to use some extensions (they weren’t needed, but I’ll be using other ones further down the road anyways).
I will now implement instruction fetching, and later the decoding
Log in to leave a comment
on commit 0e626b8:
I ended up spending the whole day thinking about how to support both 32bit and 64bit applications, I went over C11’s _Generic, void pointers, wider types + type casts, etc, but ended up realizing the best choice was to only support one. Some time was thrown away, but at the very least, I think I made a really good and important design decision, one I could not go back later.
Log in to leave a comment
on commit d7c2c71:
Finished implementing the loading of ELF segments, it felt a bit tricky at first but it turns out the format is beautifully designed.
I am using a linked list to represent the segments, it saves the RISC-V addresses it maps, a pointer to the memory that represents it, and the flags (Read/Write/Exec). I might change this design by using mmap, but I’m not sure how I would mark the address space as executable or not (since it should be executable by the emulator, not by the host OS itself). But it seems to work now, therefore I’ll leave this to a future refactor when I have a better idea of how the project as a whole should be designed.
Log in to leave a comment
Started working on my project, created the directory structure, added a license, and a Makefile. Will add README further down the road.
Had some problems making GNU Make automatically deduce prerequisites, but it eventually worked.
Log in to leave a comment