Skip to content

Commit df00d02

Browse files
committed
qemu-arm: Rework to provide a REPL and run tests via a pty serial port.
Signed-off-by: Damien George <damien@micropython.org>
1 parent 2b62ee8 commit df00d02

File tree

15 files changed

+184
-155
lines changed

15 files changed

+184
-155
lines changed

.github/workflows/ports_qemu-arm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ jobs:
2929
run: source tools/ci.sh && ci_qemu_arm_build
3030
- name: Print failures
3131
if: failure()
32-
run: grep --before-context=100 --text "FAIL" ports/qemu-arm/build/console.out
32+
run: tests/run-tests.py --print-failures

ports/qemu-arm/Makefile

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ QSTR_DEFS = qstrdefsport.h
1111

1212
# MicroPython feature configurations
1313
MICROPY_ROM_TEXT_COMPRESSION ?= 1
14+
FROZEN_MANIFEST ?= "freeze('test-frzmpy')"
1415

1516
# include py core make definitions
1617
include $(TOP)/py/py.mk
1718
include $(TOP)/extmod/extmod.mk
1819

20+
CFLAGS += -DMICROPY_HW_BOARD_NAME='"$(BOARD)"'
21+
1922
ifeq ($(BOARD),netduino2)
2023
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
2124
CFLAGS += -DQEMU_SOC_STM32
25+
CFLAGS += -DMICROPY_HW_MCU_NAME='"STM32"'
2226
LDSCRIPT = stm32.ld
2327
SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb2.o
2428
MPY_CROSS_FLAGS += -march=armv7m
@@ -27,6 +31,7 @@ endif
2731
ifeq ($(BOARD),microbit)
2832
CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft
2933
CFLAGS += -DQEMU_SOC_NRF51
34+
CFLAGS += -DMICROPY_HW_MCU_NAME='"nRF51"'
3035
LDSCRIPT = nrf51.ld
3136
QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144
3237
SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb1.o
@@ -36,6 +41,7 @@ endif
3641
ifeq ($(BOARD),mps2-an385)
3742
CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
3843
CFLAGS += -DQEMU_SOC_MPS2
44+
CFLAGS += -DMICROPY_HW_MCU_NAME='"Cortex-M3"'
3945
LDSCRIPT = mps2.ld
4046
SRC_BOARD_O = shared/runtime/gchelper_native.o shared/runtime/gchelper_thumb2.o
4147
MPY_CROSS_FLAGS += -march=armv7m
@@ -44,11 +50,16 @@ endif
4450
ifeq ($(BOARD),sabrelite)
4551
CFLAGS += -mcpu=cortex-a9
4652
CFLAGS += -DQEMU_SOC_IMX6
53+
CFLAGS += -DMICROPY_HW_MCU_NAME='"Cortex-A9"'
4754
LDSCRIPT = imx6.ld
4855
QEMU_EXTRA = -m 128M
4956
SRC_BOARD_O = shared/runtime/gchelper_generic.o
5057
# It's really armv7a but closest supported value is armv6.
5158
MPY_CROSS_FLAGS += -march=armv6
59+
# Cortex-A9 should support unaligned-access, but qemu doesn't seem to.
60+
CFLAGS += -mno-unaligned-access
61+
# These don't work on Cortex-A9.
62+
TESTS_EXCLUDE = --exclude '(asmdiv|asmspecialregs).py'
5263
endif
5364

5465
CROSS_COMPILE ?= arm-none-eabi-
@@ -81,16 +92,18 @@ LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
8192
SRC_COMMON_C = \
8293
startup.c \
8394
uart.c \
95+
mphalport.c \
8496
shared/libc/string0.c \
97+
shared/readline/readline.c \
98+
shared/runtime/interrupt_char.c \
99+
shared/runtime/pyexec.c \
100+
shared/runtime/semihosting_arm.c \
101+
shared/runtime/stdout_helpers.c \
85102
shared/runtime/sys_stdio_mphal.c \
86103

87104
SRC_RUN_C = \
88105
main.c \
89106

90-
SRC_TEST_C = \
91-
test_main.c \
92-
lib/tinytest/tinytest.c \
93-
94107
LIB_SRC_C += $(SRC_LIB_LIBM_C)
95108
LIB_SRC_C += $(SRC_LIB_LIBM_SQRT_SW_C)
96109

@@ -116,10 +129,21 @@ OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST)
116129
# List of sources for qstr extraction
117130
SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
118131

119-
all: run
132+
all: $(BUILD)/firmware.elf
120133

134+
.PHONY: repl
135+
repl: $(BUILD)/firmware.elf
136+
$(ECHO) "Use machine.reset() to exit"
137+
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial mon:stdio -kernel $<
138+
139+
.PHONY: run
121140
run: $(BUILD)/firmware.elf
122-
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $<
141+
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial pty -kernel $<
142+
143+
.PHONY: test
144+
test: $(BUILD)/firmware.elf
145+
$(eval DIRNAME=ports/$(notdir $(CURDIR)))
146+
cd $(TOP)/tests && ./run-tests.py --target qemu-arm --device execpty:"qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -serial pty -kernel ../$(DIRNAME)/$<" $(TESTS_EXCLUDE)
123147

124148
## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here.
125149
$(BUILD)/firmware.elf: $(LDSCRIPT) $(ALL_OBJ_RUN)

ports/qemu-arm/Makefile.test

Lines changed: 0 additions & 33 deletions
This file was deleted.

ports/qemu-arm/README.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,3 @@ The purposes of this port are to enable:
1414
- no need for JTAG or even an MCU chip itself
1515
- no need to use OpenOCD or anything else that might slow down the
1616
process in terms of plugging things together, pressing buttons, etc.
17-
18-
This port will only work with the [GNU ARM Embedded Toolchain](
19-
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
20-
and not with CodeSourcery toolchain. You will need to modify
21-
`LDFLAGS` if you want to use CodeSourcery's version of `arm-none-eabi`.
22-
The difference is that CodeSourcery needs `-T generic-m-hosted.ld` while
23-
ARM's version requires `--specs=nano.specs --specs=rdimon.specs` to be
24-
passed to the linker.
25-
26-
To build and run image with builtin testsuite:
27-
28-
make -f Makefile.test test

ports/qemu-arm/main.c

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,48 +25,57 @@
2525
*/
2626

2727
#include <stdlib.h>
28-
#include <stdio.h>
2928

3029
#include "py/compile.h"
3130
#include "py/runtime.h"
3231
#include "py/stackctrl.h"
3332
#include "py/gc.h"
3433
#include "py/mperrno.h"
34+
#include "shared/runtime/gchelper.h"
35+
#include "shared/runtime/pyexec.h"
3536

36-
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
37-
nlr_buf_t nlr;
38-
if (nlr_push(&nlr) == 0) {
39-
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
40-
qstr source_name = lex->source_name;
41-
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
42-
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
43-
mp_call_function_0(module_fun);
44-
nlr_pop();
45-
} else {
46-
// uncaught exception
47-
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
48-
}
49-
}
37+
#define HEAP_SIZE (100 * 1024)
38+
39+
static uint32_t gc_heap[HEAP_SIZE / sizeof(uint32_t)];
5040

5141
int main(int argc, char **argv) {
5242
mp_stack_ctrl_init();
5343
mp_stack_set_limit(10240);
54-
uint32_t heap[16 * 1024 / 4];
55-
gc_init(heap, (char *)heap + 16 * 1024);
56-
mp_init();
57-
do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT);
58-
mp_deinit();
59-
return 0;
44+
gc_init(gc_heap, (char *)gc_heap + HEAP_SIZE);
45+
46+
for (;;) {
47+
mp_init();
48+
49+
for (;;) {
50+
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
51+
if (pyexec_raw_repl() != 0) {
52+
break;
53+
}
54+
} else {
55+
if (pyexec_friendly_repl() != 0) {
56+
break;
57+
}
58+
}
59+
}
60+
61+
mp_printf(&mp_plat_print, "MPY: soft reboot\n");
62+
63+
gc_sweep_all();
64+
mp_deinit();
65+
}
6066
}
6167

6268
void gc_collect(void) {
69+
gc_collect_start();
70+
gc_helper_collect_regs_and_stack();
71+
gc_collect_end();
6372
}
6473

6574
mp_lexer_t *mp_lexer_new_from_file(qstr filename) {
6675
mp_raise_OSError(MP_ENOENT);
6776
}
6877

6978
void nlr_jump_fail(void *val) {
70-
printf("uncaught NLR\n");
79+
mp_printf(&mp_plat_print, "uncaught NLR\n");
7180
exit(1);
7281
}

ports/qemu-arm/modmachine.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@
2727
// This file is never compiled standalone, it's included directly from
2828
// extmod/modmachine.c via MICROPY_PY_MACHINE_INCLUDEFILE.
2929

30+
#include <stdlib.h>
31+
3032
static void mp_machine_idle(void) {
3133
// Do nothing.
3234
}
35+
36+
#if MICROPY_PY_MACHINE_RESET
37+
38+
static void mp_machine_reset(void) {
39+
// Exit qemu (via semihosting call).
40+
exit(0);
41+
}
42+
43+
static mp_int_t mp_machine_reset_cause(void) {
44+
// Not implemented.
45+
return 0;
46+
}
47+
48+
#endif

ports/qemu-arm/mpconfigport.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,19 @@
4242
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
4343
#define MICROPY_MEM_STATS (1)
4444
#define MICROPY_ENABLE_GC (1)
45-
#define MICROPY_KBD_EXCEPTION (0)
46-
#define MICROPY_HELPER_REPL (0)
45+
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
4746
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
4847
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
4948
#define MICROPY_WARNINGS (1)
50-
#define MICROPY_PY_BUILTINS_INPUT (0)
51-
#define MICROPY_PY_BUILTINS_HELP (0)
5249
#define MICROPY_PY_IO_IOBASE (0)
5350
#define MICROPY_PY_SYS_PLATFORM "qemu-arm"
54-
#define MICROPY_PY_SYS_STDFILES (0)
5551
#define MICROPY_PY_SYS_STDIO_BUFFER (0)
5652
#define MICROPY_PY_SELECT (0)
5753
#define MICROPY_PY_TIME (0)
5854
#define MICROPY_PY_ASYNCIO (0)
5955
#define MICROPY_PY_MACHINE (1)
6056
#define MICROPY_PY_MACHINE_INCLUDEFILE "ports/qemu-arm/modmachine.c"
57+
#define MICROPY_PY_MACHINE_RESET (1)
6158
#define MICROPY_PY_MACHINE_PIN_BASE (1)
6259
#define MICROPY_VFS (1)
6360

@@ -78,8 +75,4 @@ typedef long mp_off_t;
7875
// We need an implementation of the log2 function which is not a macro.
7976
#define MP_NEED_LOG2 (1)
8077

81-
#ifdef TEST
82-
#include "shared/upytesthelper/upytesthelper.h"
83-
#undef MP_PLAT_PRINT_STRN
84-
#define MP_PLAT_PRINT_STRN(str, len) upytest_output(str, len)
85-
#endif
78+
#define MP_STATE_PORT MP_STATE_VM

ports/qemu-arm/mphalport.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2024 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "py/mphal.h"
28+
#include "shared/runtime/semihosting_arm.h"
29+
#include "uart.h"
30+
31+
// UART is better behaved with redirection under qemu-system-arm, so prefer that for stdio.
32+
#define USE_UART (1)
33+
#define USE_SEMIHOSTING (0)
34+
35+
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
36+
// Not implemented.
37+
return 0;
38+
}
39+
40+
int mp_hal_stdin_rx_chr(void) {
41+
for (;;) {
42+
#if USE_UART
43+
int c = uart_rx_chr();
44+
if (c >= 0) {
45+
return c;
46+
}
47+
#endif
48+
#if USE_SEMIHOSTING
49+
char str[1];
50+
int ret = mp_semihosting_rx_chars(str, 1);
51+
if (ret == 0) {
52+
return str[0];
53+
}
54+
#endif
55+
}
56+
}
57+
58+
mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
59+
#if USE_UART
60+
uart_tx_strn(str, len);
61+
#endif
62+
#if USE_SEMIHOSTING
63+
mp_semihosting_tx_strn(str, len);
64+
#endif
65+
return len;
66+
}

ports/qemu-arm/mphalport.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,4 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
#include "uart.h"
28-
29-
#define mp_hal_stdin_rx_chr() (0)
30-
#define mp_hal_stdout_tx_strn_cooked(s, l) uart_tx_strn((s), (l))
27+
#include "shared/runtime/interrupt_char.h"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy