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/extreme_exc.py")
|
||||||
skip_tests.add("micropython/heapalloc_exc_compressed_emg_exc.py")
|
skip_tests.add("micropython/heapalloc_exc_compressed_emg_exc.py")
|
||||||
skip_tests.add("micropython/import_mpy_invalid.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
|
# Some tests are known to fail on 64-bit machines
|
||||||
if pyb is None and platform.architecture()[0] == "64bit":
|
if pyb is None and platform.architecture()[0] == "64bit":
|
||||||
|
@ -1039,6 +1041,7 @@ the last matching regex is used:
|
||||||
"unix",
|
"unix",
|
||||||
"qemu-arm",
|
"qemu-arm",
|
||||||
"webassembly",
|
"webassembly",
|
||||||
|
"qemu-riscv",
|
||||||
)
|
)
|
||||||
EXTERNAL_TARGETS = (
|
EXTERNAL_TARGETS = (
|
||||||
"pyboard",
|
"pyboard",
|
||||||
|
@ -1143,6 +1146,12 @@ the last matching regex is used:
|
||||||
)
|
)
|
||||||
elif args.target == "webassembly":
|
elif args.target == "webassembly":
|
||||||
test_dirs += ("float", "ports/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:
|
else:
|
||||||
# run tests from these directories
|
# run tests from these directories
|
||||||
test_dirs = args.test_dirs
|
test_dirs = args.test_dirs
|
||||||
|
|
Ładowanie…
Reference in New Issue