kopia lustrzana https://github.com/micropython/micropython
tests/run-tests, ports/qemu-riscv: 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>pull/12853/head
rodzic
35b2edfc24
commit
ecd4b759d2
|
@ -0,0 +1,140 @@
|
|||
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-
|
||||
|
||||
# The GCC version string starts like this:
|
||||
# <target>-gcc (<optional git hash>) <major>.<minor>.<patch>
|
||||
GCC_VERSION = $(subst ., , $(word 3, $(shell $(CC) --version)))
|
||||
GCC_MAJOR = $(word 1, $(GCC_VERSION))
|
||||
GCC_MINOR = $(word 2, $(GCC_VERSION))
|
||||
GCC_PATCH = $(word 3, $(GCC_VERSION))
|
||||
|
||||
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_MAJOR),10)
|
||||
ARCH=rv32imac
|
||||
else
|
||||
# Recent GCC versions explicitly require to declare extensions.
|
||||
ARCH=rv32imac_zicsr
|
||||
endif
|
||||
AFLAGS = -mabi=$(ABI) -march=$(ARCH)
|
||||
CFLAGS += -mabi=$(ABI) -march=$(ARCH) -mcmodel=medany
|
||||
CFLAGS += -DQEMU_SOC_VIRT
|
||||
ifeq ($(PICOLIBC),1)
|
||||
CFLAGS += -DUSE_PICOLIBC -D__TMP_FLT_EVAL_METHOD
|
||||
endif
|
||||
LDSCRIPT = virt.ld
|
||||
LDFLAGS += -T $(LDSCRIPT) -EL
|
||||
SRC_BOARD_O = shared/runtime/gchelper_generic.o setjmp.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)
|
||||
|
||||
# Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g
|
||||
COPT = -O0
|
||||
else
|
||||
COPT += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS += --gc-sections -Map=$(@:.elf=.map)
|
||||
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
SRC_COMMON_C = \
|
||||
interrupts.c \
|
||||
startup.c \
|
||||
uart.c \
|
||||
modmachine.c \
|
||||
shared/libc/string0.c \
|
||||
shared/runtime/sys_stdio_mphal.c \
|
||||
|
||||
SRC_RUN_C = \
|
||||
../qemu-arm/main.c \
|
||||
|
||||
SRC_TEST_C = \
|
||||
test_main.c \
|
||||
lib/tinytest/tinytest.c \
|
||||
|
||||
LIB_SRC_C += $(addprefix lib/,\
|
||||
libm/math.c \
|
||||
libm/fmodf.c \
|
||||
libm/nearbyintf.c \
|
||||
libm/ef_sqrt.c \
|
||||
libm/kf_rem_pio2.c \
|
||||
libm/kf_sin.c \
|
||||
libm/kf_cos.c \
|
||||
libm/kf_tan.c \
|
||||
libm/ef_rem_pio2.c \
|
||||
libm/sf_sin.c \
|
||||
libm/sf_cos.c \
|
||||
libm/sf_tan.c \
|
||||
libm/sf_frexp.c \
|
||||
libm/sf_modf.c \
|
||||
libm/sf_ldexp.c \
|
||||
libm/asinfacosf.c \
|
||||
libm/atanf.c \
|
||||
libm/atan2f.c \
|
||||
libm/roundf.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
|
|
@ -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 $<
|
|
@ -0,0 +1,73 @@
|
|||
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 newlib based bare metal/ELF RISC-V toolchain, either
|
||||
with multilib support or 32 bits specific (M, C, and Zicsr extensions must
|
||||
be supported, along with ilp32 ABI).
|
||||
|
||||
If your toolchain does not support the above requirements, either download
|
||||
a pre-built toolchain (and that's a hit or miss situation in its own right)
|
||||
or follow the instructions on [RISC-V's reference toolchain Github repo](https://github.com/riscv-collab/riscv-gnu-toolchain)
|
||||
to get a newlib-based multilib toolchain (the target will be
|
||||
`riscv64-unknown-elf` but said toolchain will be able to generate 32 bits
|
||||
code as well).
|
||||
|
||||
That said, when in doubt, build your own toolchain - it's the fastest way to
|
||||
get things going for sure. To build toolchain that will work with this port
|
||||
on a recent Linux installation after the necessary
|
||||
[prerequisites](https://github.com/riscv-collab/riscv-gnu-toolchain#prerequisites)
|
||||
are installed:
|
||||
|
||||
```bash
|
||||
# Check out the bootstrap source code for the toolchain.
|
||||
git clone -b 2023.10.18 https://github.com/riscv-collab/riscv-gnu-toolchain
|
||||
cd riscv-gnu-toolchain
|
||||
# Configure the toolchain.
|
||||
# NOTE 1: The toolchain that will be built will only generate code for one
|
||||
# single ABI/Architecture combination, which is the one that this
|
||||
# port supports. If you want a generic RISC-V toolchain, omit the
|
||||
# `--with-multilib-generator` parameter.
|
||||
# NOTE 2: Pick a prefix that is writable by the user that is building the
|
||||
# toolchain, or installation will fail.
|
||||
./configure \
|
||||
--with-multilib-generator="rv32imc_zicsr-ilp32--" \
|
||||
--prefix=$TARGETDIR \
|
||||
--enable-multilib
|
||||
# Build the toolchain using all available CPU cores.
|
||||
make -j `nproc`
|
||||
# The toolchain is going to be available in $TARGETDIR, just remember to
|
||||
# add $TARGETDIR/bin to the $PATH environment variable, or it won't be made
|
||||
# available to the system.
|
||||
```
|
||||
|
||||
To build and run image with builtin testsuite:
|
||||
|
||||
make -f Makefile.test test
|
||||
|
||||
However, if your toolchain comes with picolibc rather than newlib (like the
|
||||
one available on Ubuntu 22.04, where the libc headers are not shipped with
|
||||
the toolchain), you must pass `PICOLIBC=1` to make and make sure the picolibc
|
||||
headers are visible to the compiler. The headers location can also be
|
||||
provided via a compiler argument in the CFLAGS environment variable. So, for
|
||||
example, if you want to run the test suite on Ubuntu 22.04 where picolibc must
|
||||
be explicitly installed and the headers are not visible to the compiler, your
|
||||
command line should look like this:
|
||||
|
||||
```bash
|
||||
CFLAGS="-I/usr/lib/picolibc/riscv64-unknown-elf/include" \
|
||||
make -f Makefile.test test PICOLIBC=1
|
||||
```
|
|
@ -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, 0x12345678 /* Load upper 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
|
|
@ -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" // Retrieve 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"
|
||||
);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/repl.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
// uncaught exception
|
||||
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
mp_stack_ctrl_init();
|
||||
mp_stack_set_limit(10240);
|
||||
uint32_t heap[16 * 1024 / 4];
|
||||
gc_init(heap, (char *)heap + 16 * 1024);
|
||||
mp_init();
|
||||
do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT);
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gc_collect(void) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 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 "extmod/modmachine.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
static const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_PinBase), MP_ROM_PTR(&machine_pinbase_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_machine = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&machine_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE
|
|
@ -0,0 +1,69 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// options to control how MicroPython is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
|
||||
#define MICROPY_MEM_STATS (1)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_WARNINGS (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
#define MICROPY_PY_BUILTINS_BYTES_HEX (1)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_POW3 (1)
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_SYS_EXIT (1)
|
||||
#define MICROPY_PY_SYS_MAXSIZE (1)
|
||||
#define MICROPY_PY_SYS_PLATFORM "qemu-riscv32"
|
||||
#define MICROPY_PY_ERRNO (1)
|
||||
#define MICROPY_PY_BINASCII (1)
|
||||
#define MICROPY_PY_RANDOM (1)
|
||||
#define MICROPY_PY_UCTYPES (1)
|
||||
#define MICROPY_PY_DEFLATE (1)
|
||||
#define MICROPY_PY_JSON (1)
|
||||
#define MICROPY_PY_OS (1)
|
||||
#define MICROPY_PY_RE (1)
|
||||
#define MICROPY_PY_HEAPQ (1)
|
||||
#define MICROPY_PY_HASHLIB (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
||||
#define MICROPY_USE_INTERNAL_PRINTF (1)
|
||||
#define MICROPY_VFS (1)
|
||||
#define MICROPY_GCREGS_SETJMP (1)
|
||||
#define MICROPY_NLR_SETJMP (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 to provide a declaration/definition of alloca()
|
||||
#if (USE_PICOLIBC)
|
||||
#include <stddef.h>
|
||||
void *alloca(size_t size);
|
||||
#else
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
#include "shared/upytesthelper/upytesthelper.h"
|
||||
#undef MP_PLAT_PRINT_STRN
|
||||
#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
#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))
|
|
@ -0,0 +1,2 @@
|
|||
// qstrs specific to this port
|
||||
// *FORMAT-OFF*
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Provide a base setjmp/longjmp implementation to not link libc in. */
|
||||
|
||||
.globl setjmp
|
||||
.type setjmp, @function
|
||||
|
||||
setjmp:
|
||||
sw ra, 0(a0)
|
||||
sw s0, 4(a0)
|
||||
sw s1, 8(a0)
|
||||
sw s2, 12(a0)
|
||||
sw s3, 16(a0)
|
||||
sw s4, 20(a0)
|
||||
sw s5, 24(a0)
|
||||
sw s6, 28(a0)
|
||||
sw s7, 32(a0)
|
||||
sw s8, 36(a0)
|
||||
sw s9, 40(a0)
|
||||
sw s10, 44(a0)
|
||||
sw s11, 48(a0)
|
||||
sw sp, 52(a0)
|
||||
addi a0, zero, 0
|
||||
jalr zero, ra, 0
|
||||
|
||||
.size setjmp, .-setjmp
|
||||
|
||||
.globl longjmp
|
||||
.type longjmp, @function
|
||||
|
||||
longjmp:
|
||||
lw ra, 0(a0)
|
||||
lw s0, 4(a0)
|
||||
lw s1, 8(a0)
|
||||
lw s2, 12(a0)
|
||||
lw s3, 16(a0)
|
||||
lw s4, 20(a0)
|
||||
lw s5, 24(a0)
|
||||
lw s6, 28(a0)
|
||||
lw s7, 32(a0)
|
||||
lw s8, 36(a0)
|
||||
lw s9, 40(a0)
|
||||
lw s10, 44(a0)
|
||||
lw s11, 48(a0)
|
||||
lw sp, 52(a0)
|
||||
sltiu a0, a1, 1
|
||||
add a0, a0, a1
|
||||
jalr zero, ra, 0
|
||||
|
||||
.size longjmp, .-longjmp
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
// The following are needed for tinytest
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int setvbuf(FILE *stream, char *buf, int mode, size_t size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (USE_PICOLIBC)
|
||||
FILE *const stdout;
|
||||
#else
|
||||
struct _reent _port_impure_data;
|
||||
struct _reent *_impure_ptr = &_port_impure_data;
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <setjmp.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);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
# 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_with.py",
|
||||
)
|
||||
)
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
void uart_init(void);
|
||||
void uart_tx_strn(const char *buf, size_t len);
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
|
|
@ -692,6 +692,8 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
|
|||
skip_tests.add("micropython/extreme_exc.py")
|
||||
skip_tests.add("micropython/heapalloc_exc_compressed_emg_exc.py")
|
||||
skip_tests.add("micropython/import_mpy_invalid.py")
|
||||
elif args.target == "qemu-riscv":
|
||||
skip_tests.add("misc/print_exception.py") # requires sys stdfiles
|
||||
|
||||
# Some tests are known to fail on 64-bit machines
|
||||
if pyb is None and platform.architecture()[0] == "64bit":
|
||||
|
@ -1039,6 +1041,7 @@ the last matching regex is used:
|
|||
"unix",
|
||||
"qemu-arm",
|
||||
"webassembly",
|
||||
"qemu-riscv",
|
||||
)
|
||||
EXTERNAL_TARGETS = (
|
||||
"pyboard",
|
||||
|
@ -1143,6 +1146,12 @@ the last matching regex is used:
|
|||
)
|
||||
elif args.target == "webassembly":
|
||||
test_dirs += ("float", "ports/webassembly")
|
||||
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",)
|
||||
else:
|
||||
# run tests from these directories
|
||||
test_dirs = args.test_dirs
|
||||
|
|
Ładowanie…
Reference in New Issue