Skip to content

Commit 40ba74d

Browse files
committed
tests/run-tests, ports/qemu-riscv, README: Add QEMU RV32 port.
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. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent d7d77d9 commit 40ba74d

File tree

16 files changed

+1051
-1
lines changed

16 files changed

+1051
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ In addition, the following ports are provided in this repository:
114114
- [nrf](ports/nrf) -- Nordic Semiconductor nRF51 and nRF52.
115115
- [pic16bit](ports/pic16bit) -- Microchip PIC 16-bit.
116116
- [powerpc](ports/powerpc) -- IBM PowerPC (including Microwatt)
117-
- [qemu-arm](ports/qemu-arm) -- QEMU-based emulated target, for testing)
117+
- [qemu-arm](ports/qemu-arm) -- QEMU-based Arm emulated target (for testing)
118+
- [qemu-riscv](ports/qemu-riscv) -- QEMU-based RISC-V emulated target (for testing)
118119
- [renesas-ra](ports/renesas-ra) -- Renesas RA family.
119120
- [rp2](ports/rp2) -- Raspberry Pi RP2040 (including Pico and Pico W).
120121
- [samd](ports/samd) -- Microchip (formerly Atmel) SAMD21 and SAMD51.

ports/qemu-riscv/Makefile

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
include ../../py/mkenv.mk
2+
-include mpconfigport.mk
3+
4+
# qstr definitions (must come before including py.mk)
5+
QSTR_DEFS = qstrdefsport.h
6+
7+
# MicroPython feature configurations
8+
MICROPY_ROM_TEXT_COMPRESSION ?= 1
9+
10+
# include py core make definitions
11+
include $(TOP)/py/py.mk
12+
include $(TOP)/extmod/extmod.mk
13+
14+
BOARD ?= virt
15+
16+
CROSS_COMPILE ?= riscv64-unknown-elf-
17+
18+
GCC_VERSION = $(word 1, $(subst ., , $(shell $(CC) -dumpversion)))
19+
20+
# If Picolibc is available then select it explicitly. Ubuntu 22.04 ships its
21+
# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default
22+
# is "nosys" so a value must be provided. To avoid having per-distro
23+
# workarounds, always select Picolibc if available.
24+
PICOLIBC_SPECS = $(shell $(CC) --print-file-name=picolibc.specs)
25+
ifeq ($(PICOLIBC_SPECS),picolibc.specs)
26+
# Picolibc was not found.
27+
SPECS_FRAGMENT =
28+
else
29+
SPECS_FRAGMENT = --specs=$(PICOLIBC_SPECS)
30+
CFLAGS += $(SPECS_FRAGMENT)
31+
endif
32+
33+
ifeq ($(BOARD),virt)
34+
ABI = ilp32
35+
# GCC 10 and lower do not recognise the Zicsr extension in the
36+
# architecture name. "Make" unfortunately does not provide any simple way
37+
# to perform numeric comparisons, so to keep things simple we assume that
38+
# GCC is at least version 10 for the time being.
39+
ifeq ($(GCC_VERSION),10)
40+
ARCH ?= rv32imac
41+
else
42+
# Recent GCC versions explicitly require to declare extensions.
43+
ARCH ?= rv32imac_zicsr
44+
ARCH_LD ?= rv32imac_zicsr
45+
endif
46+
AFLAGS = -mabi=$(ABI) -march=$(ARCH)
47+
CFLAGS += $(AFLAGS)
48+
CFLAGS += -DQEMU_SOC_VIRT
49+
ARCH_LD ?= $(ARCH)
50+
LDSCRIPT = virt.ld
51+
LDFLAGS += -mabi=$(ABI) -march=$(ARCH_LD) -T $(LDSCRIPT) -Wl,-EL
52+
SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_rv32i.o
53+
SRC_BOARD_O += entrypoint.o
54+
endif
55+
56+
INC += -I.
57+
INC += -I$(TOP)
58+
INC += -I$(BUILD)
59+
60+
CFLAGS += $(INC) -Wall -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Werror -std=gnu99 $(COPT) \
61+
-ffunction-sections -fdata-sections
62+
CFLAGS += $(CFLAGS_EXTRA)
63+
64+
LD = $(CC)
65+
66+
# Debugging/Optimization
67+
ifeq ($(DEBUG), 1)
68+
CFLAGS += -g
69+
COPT = -O0
70+
else
71+
COPT += -Os -DNDEBUG
72+
endif
73+
74+
LDFLAGS += $(SPECS_FRAGMENT) -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map)
75+
76+
SRC_COMMON_C = \
77+
interrupts.c \
78+
startup.c \
79+
uart.c \
80+
shared/libc/string0.c \
81+
shared/runtime/sys_stdio_mphal.c \
82+
83+
SRC_RUN_C = \
84+
ports/qemu-arm/main.c \
85+
86+
SRC_TEST_C = \
87+
test_main.c \
88+
lib/tinytest/tinytest.c \
89+
90+
LIB_SRC_C += $(SRC_LIB_LIBM_C)
91+
LIB_SRC_C += $(SRC_LIB_LIBM_SQRT_SW_C)
92+
93+
OBJ_COMMON =
94+
OBJ_COMMON += $(PY_O)
95+
OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_COMMON_C:.c=.o))
96+
OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_BOARD_O))
97+
OBJ_COMMON += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
98+
99+
OBJ_RUN =
100+
OBJ_RUN += $(addprefix $(BUILD)/, $(SRC_RUN_C:.c=.o))
101+
102+
ALL_OBJ_RUN = $(OBJ_COMMON) $(OBJ_RUN)
103+
104+
OBJ_TEST =
105+
OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o))
106+
107+
ALL_OBJ_TEST = $(OBJ_COMMON) $(OBJ_TEST)
108+
109+
# All object files, needed to get dependencies correct
110+
OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST)
111+
112+
# List of sources for qstr extraction
113+
SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
114+
115+
all: run
116+
117+
# `make debug` will block QEMU until a debugger is connected to port 1234.
118+
debug: $(BUILD)/firmware.elf
119+
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial mon:stdio -S -s -kernel $<
120+
121+
run: $(BUILD)/firmware.elf
122+
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $<
123+
124+
$(BUILD)/firmware.elf: $(LDSCRIPT) $(ALL_OBJ_RUN)
125+
$(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_RUN) $(LIBS)
126+
$(Q)$(SIZE) $@
127+
128+
include $(TOP)/py/mkrules.mk

ports/qemu-riscv/Makefile.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
LIB_SRC_C = shared/upytesthelper/upytesthelper.c
2+
3+
include Makefile
4+
5+
CFLAGS += -DTEST
6+
7+
.PHONY: $(BUILD)/genhdr/tests.h
8+
9+
TESTS_PROFILE = $(dir $(abspath $(firstword $(MAKEFILE_LIST))))/tests_profile.txt
10+
11+
$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
12+
$(BUILD)/genhdr/tests.h:
13+
(cd $(TOP)/tests; ./run-tests.py --target=qemu-riscv --write-exp)
14+
$(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py --profile $(TESTS_PROFILE) $(addprefix --exclude ,$(TESTS_EXCLUDE))) > $@
15+
16+
$(BUILD)/lib/tinytest/tinytest.o: CFLAGS += -DNO_FORKING
17+
18+
$(BUILD)/firmware-test.elf: $(LDSCRIPT) $(ALL_OBJ_TEST)
19+
$(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_TEST) $(LIBS)
20+
$(Q)$(SIZE) $@
21+
22+
# Note: Using timeout(1) to handle cases where qemu hangs (e.g. this can happen with alignment errors).
23+
test: $(BUILD)/firmware-test.elf
24+
timeout --foreground -k 5s 60s qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out
25+
$(Q)tail -n2 $(BUILD)/console.out
26+
$(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
27+
28+
# `make debugtest` will block QEMU until a debugger is connected to port 1234.
29+
30+
debugtest: $(BUILD)/firmware-test.elf
31+
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial mon:stdio -S -s -kernel $<

ports/qemu-riscv/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
This is an experimental, community-supported port for RISC-V RV32IMC emulation
2+
as provided by QEMU (http://qemu.org).
3+
4+
The purposes of this port are to enable:
5+
6+
1. Continuous integration
7+
- run tests against architecture-specific parts of code base
8+
2. Experimentation
9+
- simulation & prototyping of anything that has architecture-specific
10+
code
11+
- exploring instruction set in terms of optimising some part of
12+
MicroPython or a module
13+
3. Streamlined debugging
14+
- no need for JTAG or even an MCU chip itself
15+
- no need to use OpenOCD or anything else that might slow down the
16+
process in terms of plugging things together, pressing buttons, etc.
17+
18+
This port requires a bare metal RISC-V toolchain with GCC 10 or later, either
19+
with multilib support or 32 bits specific (M, C, and Zicsr extensions must be
20+
supported, along with ilp32 ABI). Both newlib and picolibc are supported,
21+
with the latter having precedence if found.
22+
23+
Most pre-built toolchains should work out of the box, either coming from your
24+
Linux distribution's package manager, or independently packaged ones like
25+
[xPack](https://xpack.github.io/dev-tools/riscv-none-elf-gcc/).
26+
27+
To build and run the image with builtin testsuite:
28+
29+
make -f Makefile.test test

ports/qemu-riscv/entrypoint.s

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2023 Alessandro Gatti
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
.section .start
28+
.option norvc /* Do not emit compressed instructions. */
29+
.type start, @function
30+
.global start
31+
32+
start:
33+
.cfi_startproc
34+
35+
.option push
36+
.option norelax
37+
la gp, _global_pointer /* Load global pointer register. */
38+
.option pop
39+
40+
csrw satp, zero /* Disable supervisor mode. */
41+
42+
/* Fill stack with a canary value. */
43+
44+
li t0, 0xBBBBBBBB /* Load canary value. */
45+
la t1, _sstack /* Load stack area start address. */
46+
la t2, _estack /* Load stack area end address. */
47+
1:
48+
sw t0, (t1) /* Write canary. */
49+
addi t1, t1, 4 /* Next word. */
50+
bltu t1, t2, 1b /* Loop until stack is filled. */
51+
52+
la sp, _estack /* Load stack pointer. */
53+
54+
/* Clear BSS area. */
55+
56+
la t1, _sbss /* Load BSS area start address. */
57+
la t2, _ebss /* Load BSS area end address. */
58+
1:
59+
sw zero, (t1) /* Clear word. */
60+
addi t1, t1, 4 /* Next word. */
61+
bltu t1, t2, 1b /* Loop until BSS is cleared. */
62+
63+
/* Set program counter. */
64+
65+
la t0, _entry_point /* Load program counter address. */
66+
csrw mepc, t0 /* Store it into machine exception PC. */
67+
tail _entry_point /* Jump to entry point. */
68+
69+
.cfi_endproc
70+
.end

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy