Alessandro Gatti 2024-04-27 14:02:55 +10:00 zatwierdzone przez GitHub
commit 0a0c037a63
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
18 zmienionych plików z 1205 dodań i 0 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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 $<

Wyświetl plik

@ -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
```

Wyświetl plik

@ -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

Wyświetl plik

@ -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"
);
}

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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))

Wyświetl plik

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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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",
)
)

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,2 @@
void uart_init(void);
void uart_tx_strn(const char *buf, size_t len);

Wyświetl plik

@ -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
}

Wyświetl plik

@ -703,6 +703,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":
@ -1050,6 +1052,7 @@ the last matching regex is used:
"unix",
"qemu-arm",
"webassembly",
"qemu-riscv",
)
EXTERNAL_TARGETS = (
"pyboard",
@ -1154,6 +1157,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