qemu-riscv: Add new 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.

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>
This commit is contained in:
Alessandro Gatti 2023-10-31 21:55:07 +01:00 committed by Damien George
parent d7d77d91be
commit 2d69aab7b3
16 changed files with 1052 additions and 1 deletions

View file

@ -114,7 +114,8 @@ In addition, the following ports are provided in this repository:
- [nrf](ports/nrf) -- Nordic Semiconductor nRF51 and nRF52.
- [pic16bit](ports/pic16bit) -- Microchip PIC 16-bit.
- [powerpc](ports/powerpc) -- IBM PowerPC (including Microwatt)
- [qemu-arm](ports/qemu-arm) -- QEMU-based emulated target, for testing)
- [qemu-arm](ports/qemu-arm) -- QEMU-based Arm emulated target (for testing)
- [qemu-riscv](ports/qemu-riscv) -- QEMU-based RISC-V emulated target (for testing)
- [renesas-ra](ports/renesas-ra) -- Renesas RA family.
- [rp2](ports/rp2) -- Raspberry Pi RP2040 (including Pico and Pico W).
- [samd](ports/samd) -- Microchip (formerly Atmel) SAMD21 and SAMD51.

128
ports/qemu-riscv/Makefile Normal file
View file

@ -0,0 +1,128 @@
include ../../py/mkenv.mk
-include mpconfigport.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# MicroPython feature configurations
MICROPY_ROM_TEXT_COMPRESSION ?= 1
# include py core make definitions
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
BOARD ?= virt
CROSS_COMPILE ?= riscv64-unknown-elf-
GCC_VERSION = $(word 1, $(subst ., , $(shell $(CC) -dumpversion)))
# If Picolibc is available then select it explicitly. Ubuntu 22.04 ships its
# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default
# is "nosys" so a value must be provided. To avoid having per-distro
# workarounds, always select Picolibc if available.
PICOLIBC_SPECS = $(shell $(CC) --print-file-name=picolibc.specs)
ifeq ($(PICOLIBC_SPECS),picolibc.specs)
# Picolibc was not found.
SPECS_FRAGMENT =
else
SPECS_FRAGMENT = --specs=$(PICOLIBC_SPECS)
CFLAGS += $(SPECS_FRAGMENT)
endif
ifeq ($(BOARD),virt)
ABI = ilp32
# GCC 10 and lower do not recognise the Zicsr extension in the
# architecture name. "Make" unfortunately does not provide any simple way
# to perform numeric comparisons, so to keep things simple we assume that
# GCC is at least version 10 for the time being.
ifeq ($(GCC_VERSION),10)
ARCH ?= rv32imac
else
# Recent GCC versions explicitly require to declare extensions.
ARCH ?= rv32imac_zicsr
ARCH_LD ?= rv32imac_zicsr
endif
AFLAGS = -mabi=$(ABI) -march=$(ARCH)
CFLAGS += $(AFLAGS)
CFLAGS += -DQEMU_SOC_VIRT
ARCH_LD ?= $(ARCH)
LDSCRIPT = virt.ld
LDFLAGS += -mabi=$(ABI) -march=$(ARCH_LD) -T $(LDSCRIPT) -Wl,-EL
SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_rv32i.o
SRC_BOARD_O += entrypoint.o
endif
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
CFLAGS += $(INC) -Wall -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Werror -std=gnu99 $(COPT) \
-ffunction-sections -fdata-sections
CFLAGS += $(CFLAGS_EXTRA)
LD = $(CC)
# Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -g
COPT = -O0
else
COPT += -Os -DNDEBUG
endif
LDFLAGS += $(SPECS_FRAGMENT) -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map)
SRC_COMMON_C = \
interrupts.c \
startup.c \
uart.c \
shared/libc/string0.c \
shared/runtime/sys_stdio_mphal.c \
SRC_RUN_C = \
ports/qemu-arm/main.c \
SRC_TEST_C = \
test_main.c \
lib/tinytest/tinytest.c \
LIB_SRC_C += $(SRC_LIB_LIBM_C)
LIB_SRC_C += $(SRC_LIB_LIBM_SQRT_SW_C)
OBJ_COMMON =
OBJ_COMMON += $(PY_O)
OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_COMMON_C:.c=.o))
OBJ_COMMON += $(addprefix $(BUILD)/, $(SRC_BOARD_O))
OBJ_COMMON += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ_RUN =
OBJ_RUN += $(addprefix $(BUILD)/, $(SRC_RUN_C:.c=.o))
ALL_OBJ_RUN = $(OBJ_COMMON) $(OBJ_RUN)
OBJ_TEST =
OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o))
ALL_OBJ_TEST = $(OBJ_COMMON) $(OBJ_TEST)
# All object files, needed to get dependencies correct
OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST)
# List of sources for qstr extraction
SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
all: run
# `make debug` will block QEMU until a debugger is connected to port 1234.
debug: $(BUILD)/firmware.elf
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial mon:stdio -S -s -kernel $<
run: $(BUILD)/firmware.elf
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $<
$(BUILD)/firmware.elf: $(LDSCRIPT) $(ALL_OBJ_RUN)
$(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_RUN) $(LIBS)
$(Q)$(SIZE) $@
include $(TOP)/py/mkrules.mk

View file

@ -0,0 +1,31 @@
LIB_SRC_C = shared/upytesthelper/upytesthelper.c
include Makefile
CFLAGS += -DTEST
.PHONY: $(BUILD)/genhdr/tests.h
TESTS_PROFILE = $(dir $(abspath $(firstword $(MAKEFILE_LIST))))/tests_profile.txt
$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
$(BUILD)/genhdr/tests.h:
(cd $(TOP)/tests; ./run-tests.py --target=qemu-riscv --write-exp)
$(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py --profile $(TESTS_PROFILE) $(addprefix --exclude ,$(TESTS_EXCLUDE))) > $@
$(BUILD)/lib/tinytest/tinytest.o: CFLAGS += -DNO_FORKING
$(BUILD)/firmware-test.elf: $(LDSCRIPT) $(ALL_OBJ_TEST)
$(Q)$(LD) $(LDFLAGS) -o $@ $(ALL_OBJ_TEST) $(LIBS)
$(Q)$(SIZE) $@
# Note: Using timeout(1) to handle cases where qemu hangs (e.g. this can happen with alignment errors).
test: $(BUILD)/firmware-test.elf
timeout --foreground -k 5s 60s qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out
$(Q)tail -n2 $(BUILD)/console.out
$(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
# `make debugtest` will block QEMU until a debugger is connected to port 1234.
debugtest: $(BUILD)/firmware-test.elf
qemu-system-riscv32 -machine $(BOARD) -bios none $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial mon:stdio -S -s -kernel $<

View file

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

View file

@ -0,0 +1,70 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Alessandro Gatti
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
.section .start
.option norvc /* Do not emit compressed instructions. */
.type start, @function
.global start
start:
.cfi_startproc
.option push
.option norelax
la gp, _global_pointer /* Load global pointer register. */
.option pop
csrw satp, zero /* Disable supervisor mode. */
/* Fill stack with a canary value. */
li t0, 0xBBBBBBBB /* Load canary value. */
la t1, _sstack /* Load stack area start address. */
la t2, _estack /* Load stack area end address. */
1:
sw t0, (t1) /* Write canary. */
addi t1, t1, 4 /* Next word. */
bltu t1, t2, 1b /* Loop until stack is filled. */
la sp, _estack /* Load stack pointer. */
/* Clear BSS area. */
la t1, _sbss /* Load BSS area start address. */
la t2, _ebss /* Load BSS area end address. */
1:
sw zero, (t1) /* Clear word. */
addi t1, t1, 4 /* Next word. */
bltu t1, t2, 1b /* Loop until BSS is cleared. */
/* Set program counter. */
la t0, _entry_point /* Load program counter address. */
csrw mepc, t0 /* Store it into machine exception PC. */
tail _entry_point /* Jump to entry point. */
.cfi_endproc
.end

View file

@ -0,0 +1,292 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Alessandro Gatti
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// Vector table
void mtvec_table(void) __attribute__((naked, section(".text.mtvec"), aligned(256)));
// Default interrupts
#define ASSIGN_EMPTY_MACHINE_INTERRUPT(interrupt_name) \
void interrupt_name(void) __attribute__((alias("mtvec_nop")))
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_ssi);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_msi);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_sti);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_mti);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_sei);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_mei);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq0);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq1);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq2);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq3);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq4);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq5);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq6);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq7);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq8);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq9);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq10);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq11);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq12);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq13);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq14);
ASSIGN_EMPTY_MACHINE_INTERRUPT(mtvec_plat_irq15);
void mtvec_table(void) {
__asm volatile (
".org mtvec_table + 0 \n"
"jal zero, mtvec_exception \n" // Exception Handler
".org mtvec_table + 4 \n"
"jal zero, mtvec_ssi \n" // Supervisor Software Interrupt
".org mtvec_table + 12 \n"
"jal zero, mtvec_msi \n" // Machine Software Interrupt
".org mtvec_table + 20 \n"
"jal zero, mtvec_sti \n" // Supervisor Timer Interrupt
".org mtvec_table + 28 \n"
"jal zero, mtvec_mti \n" // Machine Timer Interrupt
".org mtvec_table + 36 \n"
"jal zero, mtvec_sei \n" // Supervisor External Interrupt
".org mtvec_table + 44 \n"
"jal zero, mtvec_mei \n" // Machine External Interrupt
// Not sure how many platform interrupts QEMU handles...
".org mtvec_table + 48 \n"
"jal mtvec_plat_irq0 \n" // Platform Interrupt #0
"jal mtvec_plat_irq1 \n" // Platform Interrupt #1
"jal mtvec_plat_irq2 \n" // Platform Interrupt #2
"jal mtvec_plat_irq3 \n" // Platform Interrupt #3
"jal mtvec_plat_irq4 \n" // Platform Interrupt #4
"jal mtvec_plat_irq5 \n" // Platform Interrupt #5
"jal mtvec_plat_irq6 \n" // Platform Interrupt #6
"jal mtvec_plat_irq7 \n" // Platform Interrupt #7
"jal mtvec_plat_irq8 \n" // Platform Interrupt #8
"jal mtvec_plat_irq9 \n" // Platform Interrupt #9
"jal mtvec_plat_irq10 \n" // Platform Interrupt #10
"jal mtvec_plat_irq11 \n" // Platform Interrupt #11
"jal mtvec_plat_irq12 \n" // Platform Interrupt #12
"jal mtvec_plat_irq13 \n" // Platform Interrupt #13
"jal mtvec_plat_irq14 \n" // Platform Interrupt #14
"jal mtvec_plat_irq15 \n" // Platform Interrupt #15
:
:
: "memory"
);
}
volatile uint32_t registers_copy[35] = { 0 };
const char *exception_causes[] = {
"Reserved", // 0
"Supervisor software interrupt", // 1
"Machine software interrupt", // 2
"Supervisor timer interrupt", // 3
"Machine timer interrupt", // 4
"Supervisor external interrupt", // 5
"Machine external interrupt", // 6
"Designated for platform use", // 7
"Instruction address misaligned", // 8
"Instruction address fault", // 9
"Illegal instruction", // 10
"Breakpoint", // 11
"Load address misaligned", // 12
"Load address fault", // 13
"Store/AMO address misaligned", // 14
"Store/AMO access fault", // 15
"Environment call from U-mode", // 16
"Environment call from S-mode", // 17
"Environment call from M-mode", // 18
"Instruction page fault", // 19
"Load page fault", // 20
"Store/AMO page fault", // 21
"Designated for custom use" // 22
};
const char *lookup_cause(uint32_t mcause) {
if (mcause & 0x80000000) {
switch (mcause & 0x7FFFFFFF) {
case 1:
return exception_causes[1];
case 3:
return exception_causes[2];
case 5:
return exception_causes[3];
case 7:
return exception_causes[4];
case 9:
return exception_causes[5];
case 11:
return exception_causes[6];
default:
return (mcause >= 16) ?
exception_causes[7] :
exception_causes[0];
}
}
switch (mcause) {
case 0:
return exception_causes[8];
case 1:
return exception_causes[9];
case 2:
return exception_causes[10];
case 3:
return exception_causes[11];
case 4:
return exception_causes[12];
case 5:
return exception_causes[13];
case 6:
return exception_causes[14];
case 7:
return exception_causes[15];
case 8:
return exception_causes[16];
case 9:
return exception_causes[17];
case 11:
return exception_causes[18];
case 12:
return exception_causes[19];
case 13:
return exception_causes[20];
case 15:
return exception_causes[21];
default: {
if ((mcause >= 24 && mcause <= 31) ||
(mcause >= 48 && mcause <= 63)) {
return exception_causes[22];
}
return exception_causes[0];
}
}
}
#pragma GCC push_options
#pragma GCC optimize ("align-functions=4")
__attribute__((interrupt("machine"), weak)) void mtvec_nop(void) {
}
__attribute__((interrupt("machine"), weak)) void mtvec_exception(void) {
__asm volatile (
"csrrw x31, mscratch, x31 \n" // Save X31
"la x31, registers_copy \n" // Load target address
"sw x1, 0(x31) \n" // Save X1
"sw x2, 4(x31) \n" // Save X2
"sw x3, 8(x31) \n" // Save X3
"sw x4, 12(x31) \n" // Save X4
"sw x5, 16(x31) \n" // Save X5
"sw x6, 20(x31) \n" // Save X6
"sw x7, 24(x31) \n" // Save X7
"sw x8, 28(x31) \n" // Save X8
"sw x9, 32(x31) \n" // Save X9
"sw x10, 36(x31) \n" // Save X10
"sw x11, 40(x31) \n" // Save X11
"sw x12, 44(x31) \n" // Save X12
"sw x13, 48(x31) \n" // Save X13
"sw x14, 52(x31) \n" // Save X14
"sw x15, 56(x31) \n" // Save X15
"sw x16, 60(x31) \n" // Save X16
"sw x17, 64(x31) \n" // Save X17
"sw x18, 68(x31) \n" // Save X18
"sw x19, 72(x31) \n" // Save X19
"sw x20, 76(x31) \n" // Save X20
"sw x21, 80(x31) \n" // Save X21
"sw x22, 84(x31) \n" // Save X22
"sw x23, 88(x31) \n" // Save X23
"sw x24, 92(x31) \n" // Save X24
"sw x25, 98(x31) \n" // Save X25
"sw x26, 100(x31) \n" // Save X26
"sw x27, 104(x31) \n" // Save X27
"sw x28, 108(x31) \n" // Save X28
"sw x29, 112(x31) \n" // Save X29
"sw x30, 116(x31) \n" // Save X30
"csrr x30, mscratch \n" // Restore X31
"sw x30, 120(x31) \n" // Save X31
"csrr x30, mepc \n" // Load MEPC
"sw x30, 124(x31) \n" // Save MEPC
"csrr x30, mcause \n" // Load MCAUSE
"sw x30, 128(x31) \n" // Save MCAUSE
"csrr x30, mtval \n" // Load MTVAL
"sw x30, 132(x31) \n" // Save MTVAL
"csrr x30, mstatus \n" // Load MSTATUS
"sw x30, 138(x31) \n" // Save MSTATUS
"lw x30, 116(x31) \n" // Restore X30
"lw x31, 120(x31) \n" // Restore X31
:
:
: "memory"
);
printf("\nMACHINE EXCEPTION CAUGHT:\n\n");
printf(" RA=%08lX SP=%08lX GP=%08lX TP=%08lX T0=%08lX T1=%08lX\n",
registers_copy[0], registers_copy[1], registers_copy[2],
registers_copy[3], registers_copy[4], registers_copy[5]);
printf(" T2=%08lX S0=%08lX S1=%08lX A0=%08lX A1=%08lX A2=%08lX\n",
registers_copy[6], registers_copy[7], registers_copy[8],
registers_copy[9], registers_copy[10], registers_copy[11]);
printf(" A3=%08lX A4=%08lX A5=%08lX A6=%08lX A7=%08lX S2=%08lX\n",
registers_copy[12], registers_copy[13], registers_copy[14],
registers_copy[15], registers_copy[16], registers_copy[17]);
printf(" S3=%08lX S4=%08lX S5=%08lX S6=%08lX S7=%08lX S8=%08lX\n",
registers_copy[18], registers_copy[19], registers_copy[20],
registers_copy[21], registers_copy[22], registers_copy[23]);
printf(" S9=%08lX S10=%08lX S11=%08lX T3=%08lX T4=%08lX T5=%08lX\n",
registers_copy[24], registers_copy[25], registers_copy[26],
registers_copy[27], registers_copy[28], registers_copy[29]);
printf(" T6=%08lX\n\n", registers_copy[30]);
printf(" MEPC=%08lX MTVAL=%08lX MSTATUS=%08lx MCAUSE=%08lx (%s)\n",
registers_copy[31], registers_copy[33], registers_copy[34],
registers_copy[32], lookup_cause(registers_copy[32]));
exit(-1);
}
#pragma GCC pop_options
void set_interrupt_table(void) {
__asm volatile (
"csrrci s0, mstatus, 8 \n" // S0 = MSTATUS & ~MIE
"csrw mstatus, s0 \n" // Global machine interrupts are disabled
"csrw mie, zero \n" // Disable machine interrupts
"csrw mip, zero \n" // Clear pending machine interrupts
"addi s0, %0, 1 \n" // Vectored machine interrupts enabled
"csrw mtvec, s0 \n" // Set new machine vector table
"csrrsi s0, mstatus, 8 \n" // S0 = MSTATUS | MIE
"csrw mstatus, s0 \n" // Global machine interrupts are enabled
:
: "r" (mtvec_table)
: "memory"
);
}

View file

@ -0,0 +1,76 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2024 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
// options to control how MicroPython is built
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
#define MICROPY_MEM_STATS (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_KBD_EXCEPTION (0)
#define MICROPY_HELPER_REPL (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_WARNINGS (1)
#define MICROPY_PY_BUILTINS_INPUT (0)
#define MICROPY_PY_BUILTINS_HELP (0)
#define MICROPY_PY_IO_IOBASE (0)
#define MICROPY_PY_SYS_PLATFORM "qemu-riscv32"
#define MICROPY_PY_SYS_STDFILES (0)
#define MICROPY_PY_SYS_STDIO_BUFFER (0)
#define MICROPY_PY_SELECT (0)
#define MICROPY_PY_TIME (0)
#define MICROPY_PY_ASYNCIO (0)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_INCLUDEFILE "ports/qemu-arm/modmachine.c"
#define MICROPY_PY_MACHINE_PIN_BASE (1)
#define MICROPY_VFS (1)
// type definitions for the specific machine
#define MP_SSIZE_MAX (0x7fffffff)
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
typedef int32_t mp_int_t; // must be pointer size
typedef uint32_t mp_uint_t; // must be pointer size
typedef long mp_off_t;
// We need an implementation of the log2 function which is not a macro.
#define MP_NEED_LOG2 (1)
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
#ifdef TEST
#include "shared/upytesthelper/upytesthelper.h"
#undef MP_PLAT_PRINT_STRN
#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
#endif

View file

@ -0,0 +1,32 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stddef.h>
#include "uart.h"
#define mp_hal_stdin_rx_chr() (0)
#define mp_hal_stdout_tx_strn_cooked(s, l) uart_tx_strn((s), (l))

View file

@ -0,0 +1,2 @@
// qstrs specific to this port
// *FORMAT-OFF*

View file

@ -0,0 +1,86 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Alessandro Gatti
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "uart.h"
extern void set_interrupt_table(void);
extern int main(int argc, char **argv);
void _entry_point(void) {
// Set interrupt table
set_interrupt_table();
// Enable UART
uart_init();
// Now that we have a basic system up and running we can call main
main(0, 0);
// Finished
exit(0);
}
void exit(int status) {
uint32_t semihosting_arguments[2] = { 0 };
// Exit via QEMU's RISC-V semihosting support.
__asm volatile (
".option push \n" // Transient options
".option norvc \n" // Do not emit compressed instructions
".align 4 \n" // 16 bytes alignment
"mv a1, %0 \n" // Load buffer
"li t0, 0x20026 \n" // ADP_Stopped_ApplicationExit
"sw t0, 0(a1) \n" // ADP_Stopped_ApplicationExit
"sw %1, 4(a1) \n" // Exit code
"addi a0, zero, 0x20 \n" // TARGET_SYS_EXIT_EXTENDED
"slli zero, zero, 0x1F \n" // Entry NOP
"ebreak \n" // Give control to the debugger
"srai zero, zero, 7 \n" // Semihosting call
".option pop \n" // Restore previous options set
:
: "r" (semihosting_arguments), "r" (status)
: "memory"
);
// Should never reach here.
for (;;) {
}
}
#ifndef NDEBUG
void __assert_func(const char *file, int line, const char *func, const char *expr) {
(void)func;
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
exit(1);
}
#endif
// Picolibc requires `stdout` to be explicitly defined.
#ifdef _PICOLIBC__
FILE *const stdout;
#endif

View file

@ -0,0 +1,66 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Ilya Dmitrichenko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include "py/compile.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "shared/runtime/gchelper.h"
#include "lib/tinytest/tinytest.h"
#include "lib/tinytest/tinytest_macros.h"
#define HEAP_SIZE (200 * 1024)
#include "genhdr/tests.h"
int main() {
mp_stack_ctrl_init();
mp_stack_set_limit(10240);
static uint32_t heap[HEAP_SIZE / sizeof(uint32_t)];
upytest_set_heap(heap, (char *)heap + HEAP_SIZE);
int r = tinytest_main(0, NULL, groups);
printf("status: %d\n", r);
return r;
}
void gc_collect(void) {
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
}
mp_lexer_t *mp_lexer_new_from_file(qstr filename) {
mp_raise_OSError(MP_ENOENT);
}
void nlr_jump_fail(void *val) {
printf("uncaught NLR\n");
exit(1);
}

View file

@ -0,0 +1,53 @@
# Port-specific tests exclusion list.
exclude_tests = exclude_tests.union(
(
# Native code generation is not yet supported.
"micropython/native_closure.py",
"micropython/native_const.py",
"micropython/native_const_intbig.py",
"micropython/native_for.py",
"micropython/native_fun_attrs.py",
"micropython/native_gen.py",
"micropython/native_misc.py",
"micropython/native_try.py",
"micropython/native_try_deep.py",
"micropython/native_while.py",
"micropython/native_with.py",
# Viper code generator is not yet supported.
"micropython/viper_addr.py",
"micropython/viper_args.py",
"micropython/viper_binop_arith.py",
"micropython/viper_binop_arith_uint.py",
"micropython/viper_binop_bitwise_uint.py",
"micropython/viper_binop_comp.py",
"micropython/viper_binop_comp_imm.py",
"micropython/viper_binop_comp_uint.py",
"micropython/viper_binop_divmod.py",
"micropython/viper_binop_multi_comp.py",
"micropython/viper_cond.py",
"micropython/viper_const.py",
"micropython/viper_const_intbig.py",
"micropython/viper_error.py",
"micropython/viper_globals.py",
"micropython/viper_import.py",
"micropython/viper_misc.py",
"micropython/viper_misc2.py",
"micropython/viper_misc3.py",
"micropython/viper_misc_intbig.py",
"micropython/viper_ptr16_load.py",
"micropython/viper_ptr16_store.py",
"micropython/viper_ptr32_load.py",
"micropython/viper_ptr32_store.py",
"micropython/viper_ptr8_load.py",
"micropython/viper_ptr8_store.py",
"micropython/viper_storeattr.py",
"micropython/viper_subscr.py",
"micropython/viper_subscr_multi.py",
"micropython/viper_try.py",
"micropython/viper_types.py",
"micropython/viper_unop.py",
"micropython/viper_with.py",
)
)

45
ports/qemu-riscv/uart.c Normal file
View file

@ -0,0 +1,45 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Alessandro Gatti
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stddef.h>
#include "uart.h"
#if defined(QEMU_SOC_VIRT)
volatile unsigned char *uart_buffer = (volatile unsigned char *)0x10000000;
void uart_init(void) {
}
void uart_tx_strn(const char *buffer, size_t length) {
for (size_t index = 0; index < length; index++) {
*uart_buffer = buffer[index];
}
}
#endif // QEMU_SOC_VIRT

33
ports/qemu-riscv/uart.h Normal file
View file

@ -0,0 +1,33 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_QEMU_RISCV_UART_H
#define MICROPY_INCLUDED_QEMU_RISCV_UART_H
void uart_init(void);
void uart_tx_strn(const char *buf, size_t len);
#endif // MICROPY_INCLUDED_QEMU_RISCV_UART_H

98
ports/qemu-riscv/virt.ld Normal file
View file

@ -0,0 +1,98 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2023 Alessandro Gatti
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* Output format is 32 bits little endian. */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv");
/*
* Memory layout:
*
* 0x8000_0000: .text
* .........: .rodata
* 0x8040_0000: .data
* .........: _global_pointer
* .........: .bss
* 0x8060_0000: .stack
* 0x8060_0000: _sstack
* 0x8060_FFFF: _estack
*/
MEMORY
{
ROM (xr) : ORIGIN = 0x80000000, LENGTH = 4M
RAM (xrw) : ORIGIN = ORIGIN(ROM) + LENGTH(ROM), LENGTH = 2M
STACK (rw) : ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 64K
}
SECTIONS
{
/* Code + Read-Only data segment */
.text : ALIGN (4K)
{
*(.start)
*(.text)
. = ALIGN (4K);
*(.rodata)
_sirodata = .;
} > ROM
.rodata : AT (_sirodata) ALIGN (4K)
{
*(.rodata)
} > ROM
/* Data + BSS segment */
.data : ALIGN (4K)
{
*(.data)
_sibss = .;
} > RAM
.bss : AT (_sibss) ALIGN (4K)
{
/* Mark global pointer address. */
_global_pointer = .;
/* Mark BSS start. */
. = . + 4;
_sbss = .;
*(.bss)
/* Mark BSS end. */
_ebss = .;
} > RAM
/* Isolated stack segment. */
.stack : ALIGN(4K)
{
/* Mark stack start. */
_sstack = .;
. = LENGTH(STACK);
/* Mark stack end. */
_estack = .;
} > STACK
}

View file

@ -678,6 +678,8 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
) # RA fsp rtc function doesn't support nano sec info
elif args.target == "qemu-arm":
skip_tests.add("misc/print_exception.py") # requires sys stdfiles
elif args.target == "qemu-riscv":
skip_tests.add("misc/print_exception.py") # requires sys stdfiles
elif args.target == "webassembly":
skip_tests.add("basics/string_format_modulo.py") # can't print nulls to stdout
skip_tests.add("basics/string_strip.py") # can't print nulls to stdout
@ -1048,6 +1050,7 @@ the last matching regex is used:
LOCAL_TARGETS = (
"unix",
"qemu-arm",
"qemu-riscv",
"webassembly",
)
EXTERNAL_TARGETS = (
@ -1151,6 +1154,12 @@ the last matching regex is used:
"inlineasm",
"ports/qemu-arm",
)
elif args.target == "qemu-riscv":
if not args.write_exp:
raise ValueError("--target=qemu-riscv must be used with --write-exp")
# Generate expected output files for qemu run.
# This list should match the test_dirs tuple in tinytest-codegen.py.
test_dirs += ("float",)
elif args.target == "webassembly":
test_dirs += ("float", "ports/webassembly")
else: