-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
ports: Add RISC-V 32 bit QEMU port. #12853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Code size report:
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #12853 +/- ##
=======================================
Coverage 98.42% 98.42%
=======================================
Files 161 161
Lines 21204 21204
=======================================
Hits 20870 20870
Misses 334 334 ☔ View full report in Codecov by Sentry. |
Thanks @agatti -- very helpful to add this as a first step!
See pyproject.toml
I think the way to solve this would be to move the improvements to tinytest/run-tests into their own commits. e.g.
|
Thanks @jimmo, I'll split this PR up using your suggestion as a template. In the meantime I'll mark this PR as draft as it isn't ready for merging until all bits are merged first. |
Thanks @agatti -- splitting it into separate PRs wasn't actually necessary, just into separate commits in this PR would have been fine. But all good, thanks for doing it! |
No worries, this also gives me the chance to decouple the various bits from the RISC-V port whenever possible and polish them up before merges. |
In the meantime I cleaned up a few other things, like adding compressed instructions support, a proper CPU exception handler, and fixing the setvbuf crash when running tests without changing tinytest. After that I looked into re-enabling failing tests from Incidentally this is the gdb backtrace for this case, is there anything special in the configuration I should look into (UTF8 validity checks aren't being done, but neither are in the Arm port...)?
|
It looks like the above null-dereference bug was introduced in 64c79a5, which added the call to According to the C standard, one should never pass NULL to We could either add logic to handle the case of |
Those PRs have now been merged. |
Thanks @dpgeorge, I rebased the PR accordingly. Right now the Apparently, building the same code more than once with no changes will generate different binaries as (I guess) the test directories are not iterated in order, and different runs will generate different
at this point of the test:
Now, since rebuilding toolchains takes a fair bit of time (and my laptop isn't the fastest out there either) it'll take me some time to bisect this, but at least all other tests work fine. |
8d67c36
to
b876428
Compare
The
It's strange it fails with a MemoryError... I thought each tests starts with a fresh heap and hence the same amount of free memory regardless of the order. Does the test always pass if you double the amount of available heap? What about halving the heap? |
Well, I was lucky and the first toolchain rebuild yielded a working compiler. There must be a bug in the optimiser for GCC 13.2, as GCC 12.2.0 works reliably (although builds still have different size depending on the tests order). I've updated the port's README file to reflect that. If you have the chance to try this out yourselves let me know if you have any issues in setting the compiler up. A quick start guide on Linux (and I guess WSL too) is: git clone https://github.com/riscv-collab/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git checkout 2023.10.06
# "rv32imc_zicsr-ilp32--" only builds a compiler for just one arch/abi combination, the one used in the port makefile. Not really needed but it takes less time overall. Pick any path you want for the prefix, as long as the user that builds the toolchain can write into the new location.
./configure --with-multilib-generator="rv32imc_zicsr-ilp32--" --prefix=$HOME/riscv-gcc12 --enable-multilib
make -j `nproc`
make install
export PATH=$HOME/riscv-gcc12/bin:$PATH
cd $MICROPYTHON/ports/qemu-riscv
make -f Makefile.test test |
I can come up with a PR for that.
Heap size changes did not change anything, neither stack did - however debug builds always worked. Anyway, that's now sorted, thanks for the pointer - I got the notification whilst I was typing the toolchain build instructions :) |
PR for sorted test generation sent: #12906. |
ports/qemu-riscv/main.c
Outdated
@@ -0,0 +1,51 @@ | |||
#include <stdint.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a license header comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, that is the exact same file as qemu-arm
's and it doesn't have a licence header either. That file was added in 5130b81 but then it was worked on by quite a few people. Whose copyright attribution shall I use for that, the author of the commit I mentioned before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's the exact same as qemu-arm
then I would suggest to remove this file and just refer to the one in qemu-arm
in the Makefile here. That way there is no duplication of code, and we can fix the licensing header separately.
Same thing for test_main.c
, if that's exactly the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long term maybe we can add shared/qemu-common
or a single ports/qemu
?
(However agree for now that if most of the duplicate code is 100% the same, can simply refer to its current location from here.)
I managed to get this running (at least the basic hello world) using the default toolchain on Arch Linux, This new port will (eventually) need CI. Do you feel like adding that now? |
If you don't mind I'll look into this once the other review points have been addressed. Whether that is going to be a further commit to this PR or a whole new PR for me is the same, as long as it's convenient for you. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for submitting this, @agatti! It'll be invaluable to have a way to run tests against a RISC-V target on the host.
I left some comments inline, mostly about the toolchain setup and the fiddly details of gcc multilib.
The only other significant thing a new port will need is to build in CI, and preferably also test in CI (see tools/ci.sh
and .github/workflows/ports_qemu-arm.yml
for reference) . Hopefully that will become pretty straightforward if prebuilt toolchains can be supported without any niggles. If this becomes a sticking point then let me know and one of us can probably help out.
ports/qemu-riscv/main.c
Outdated
@@ -0,0 +1,51 @@ | |||
#include <stdint.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long term maybe we can add shared/qemu-common
or a single ports/qemu
?
(However agree for now that if most of the duplicate code is 100% the same, can simply refer to its current location from here.)
Thank you @projectgus for taking the time to look at this. I'll answer your concerns inline, then once those are sorted out, I'll force push something that can build under CI. |
Broken force push aside, I'm wondering why there's a test failure:
That test did pass back when it was still part of a bigger test file, and the code on my end is the same - including the compiler. Is there anything special I should look into to see what's going on? |
Ok, I've figured out how to dump the rules as they are parsed for the single statement They diverge at line 137: --- arm.txt 2024-05-31 16:58:09.741802105 +0200
+++ riscv.txt 2024-05-31 16:58:31.433929684 +0200
@@ -134,6 +134,6 @@
depth=37 trailer_bracket n=3 i=0 bt=0
depth=36 trailer n=3 i=2 bt=1
depth=36 trailer_period n=2 i=0 bt=0
-depth=35 atom_expr_trailers n=2 i=1 bt=0
+depth=35 atom_expr_trailers n=2 i=1 bt=1 I wonder why it backtracks on RISC-V, but I can't look at this any further until tomorrow. |
The parser failure was due to port configuration flags that were no longer relevant since when the files were created, and that has been sorted out. However, updating the makefiles to properly include libm brought up another incompatibility with Picolibc. I've filed #15183, as I thought that was the least intrusive fix to this issue. With that applied the whole lot builds and passes tests on an Ubuntu 22.04 VM. |
So here it is in its final form (hopefully). I've also enabled native NLR and GC support as well, following the QEMU Arm port. All tests pass, and my CI integration seems to be working :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really great, thanks @agatti! I left a couple of comments but they're about relatively minor things.
I do have a niggling thought about whether the CI should build and test both a newlib variant and a picolibc variant, in case of unexpected regression in one or the other. I'm not sure how likely that kind of bug is though, what do you think?
That makes a lot of sense, but I believe that can be added as a separate PR after this is merged. Right now the known incompatibilities between picolibc and newlib on RISC-V are restricted to niche math functions (picolibc's Ideally, adding a new RV32/newlibc target can be done at the same time as Arm/picolibc (and optionally ESP8266/picolibc)? |
23afa27
to
c3e950b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really interesting addition to MicroPython. 👍🏻
* | ||
* The MIT License (MIT) | ||
* | ||
* Copyright (c) 2014 Ilya Dmitrichenko |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be a copy of qemu-arm/test_main.c
- which is fine. But perhaps a comment (in both files?) to mention the other in case a change should affect both?
Or maybe finding somewhere common to store it would be worthwhile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not an exact copy, the test heap size is doubled. Or rather, having a common location for common QEMU port files that can be tweaked via #defines
in a place like ports/qemu-base/
or shared/qemu/
would be nice, but right now I had to duplicate that file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually we would like to make some common code to share among the qemu ports, but for now this copy is OK.
* | ||
* The MIT License (MIT) | ||
* | ||
* Copyright (c) 2023 Alessandro Gatti |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Very minor!) 2024. In a number of files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The files were created in 2023, so I think they're correct. Otherwise every year every file in the repo should have its copyright notice updated accordingly, which isn't the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if it was written in 2023 then the date can stay as 2023 (it could also be updated to 2023-2024 but that's not critical).
This adds a QEMU-based bare metal RISC-V 32 bits port. For the time being only QEMU's "virt" 32 bits board is supported, using the ilp32 ABI and the RV32IMC architecture. The top-level README and the run-tests.py files are updated for this new port. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
Merged! I made the following very minor changes during the merge:
Thank you @agatti for your work on this new port, it's a great addition for testing the RV32 platform. |
This adds a QEMU-based bare metal RISC-V 32 bits port. For the time being only QEMU's "virt" 32 bits board is supported, using the ilp32 ABI and the RV32IM architecture.
Tests run and pass except for two instances I'll debug and fix shortly, and the test generator framework was modified to remove hardcoded references to the "qemu-arm" port. If you want to test this on your machine I suggest you build your own toolchain from RISC-V's reference toolchain following these instructions. In my experience pre-built toolchains' support for 32 bits target is a hit and miss situation, ranging from missing headers to mismatched ABIs and more.
I'm not sure on whether this PR title (and commit message) is ok being prefixed with just "ports", as it touches several places and the list would be too long. If that's not ok let me know what to change that into to follow the repo's conventions.
This is part of the RISC-V work I'm doing on MicroPython; so instead of coming up with a very large and complicated patch to merge I'm splitting things up in more manageable chunks (the ESP32 Xtensa/RISC-V build changes in #12839 is part of this).
If this gets merged then the changes related to NLR/Native GC and the native code emitter (including compressed instructions support - RISC-V's equivalent of Arm's Thumb-2) can be tested on something more manageable than an ESP32-C3, and can also help for future RISC-V microcontroller ports. Plus if needed I can help to provide a PR to bring this into the CI as a build target.
The changes in
tinytest.c
are due to the fact that referencingstdout
without libc being linked sort of confuses the compiler. The test framework isn't impacted otherwise.By the way, is there any way to let the CI spellchecker know that certain words are not misspelled? Right now it complains about a register name in an
__asm volatile
block, for example.