summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-09-24 12:09:28 +1000
committerDamien George <damien.p.george@gmail.com>2019-02-12 13:50:01 +1100
commite7332b05841549a41614e522285639dcaa7bd526 (patch)
tree339ca8a643891c44fb3fbcec2c4ba1fb765bc21e
parent775c7b86f017b81d31c3d463aec1b18088dbcdab (diff)
downloadmicropython-e7332b05841549a41614e522285639dcaa7bd526.tar.gz
micropython-e7332b05841549a41614e522285639dcaa7bd526.zip
qemu-arm: Rework to run bare-metal on boards with Cortex-M CPUs.
Adds support for 3 Cortex-M boards, selectable via "BOARD" in the Makefile: - microbit, Cortex-M0 via nRF51822 - netduino2, Cortex-M3 via STM32F205 - mps2-an385, Cortex-M3 via FPGA netduino2 is the default board because it's supported by older qemu versions (down to at least 2.5.0).
-rw-r--r--ports/qemu-arm/Makefile34
-rw-r--r--ports/qemu-arm/Makefile.test4
-rw-r--r--ports/qemu-arm/main.c2
-rw-r--r--ports/qemu-arm/mpconfigport.h5
-rw-r--r--ports/qemu-arm/mphalport.h5
-rw-r--r--ports/qemu-arm/mps2.ld38
-rw-r--r--ports/qemu-arm/nrf51.ld39
-rw-r--r--ports/qemu-arm/startup.c84
-rw-r--r--ports/qemu-arm/stm32.ld39
-rw-r--r--ports/qemu-arm/test_main.c8
-rw-r--r--ports/qemu-arm/uart.c78
-rw-r--r--ports/qemu-arm/uart.h2
12 files changed, 320 insertions, 18 deletions
diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile
index 95f349beba..b3d9cdf566 100644
--- a/ports/qemu-arm/Makefile
+++ b/ports/qemu-arm/Makefile
@@ -7,6 +7,27 @@ QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include $(TOP)/py/py.mk
+BOARD ?= netduino2
+
+ifeq ($(BOARD),netduino2)
+CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
+CFLAGS += -DQEMU_SOC_STM32
+LDSCRIPT = stm32.ld
+endif
+
+ifeq ($(BOARD),microbit)
+CFLAGS += -mthumb -mcpu=cortex-m0 -mfloat-abi=soft
+CFLAGS += -DQEMU_SOC_NRF51
+LDSCRIPT = nrf51.ld
+QEMU_EXTRA = -global nrf51-soc.flash-size=1048576 -global nrf51-soc.sram-size=262144
+endif
+
+ifeq ($(BOARD),mps2-an385)
+CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
+CFLAGS += -DQEMU_SOC_MPS2
+LDSCRIPT = mps2.ld
+endif
+
CROSS_COMPILE = arm-none-eabi-
TINYTEST = $(TOP)/lib/tinytest
@@ -16,8 +37,7 @@ INC += -I$(TOP)
INC += -I$(BUILD)
INC += -I$(TINYTEST)
-CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
-CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \
+CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(COPT) \
-ffunction-sections -fdata-sections
#Debugging/Optimization
@@ -34,9 +54,12 @@ endif
## else instead and according to the following files, this is what we need to pass to `$(CC).
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/makefile.conf
## - gcc-arm-none-eabi-4_8-2014q1/share/gcc-arm-none-eabi/samples/src/qemu/Makefile
-LDFLAGS= --specs=nano.specs --specs=rdimon.specs -Wl,--gc-sections -Wl,-Map=$(@:.elf=.map)
+LDFLAGS= -T $(LDSCRIPT) --gc-sections -Map=$(@:.elf=.map)
+LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
SRC_COMMON_C = \
+ startup.c \
+ uart.c \
moduos.c \
modmachine.c \
@@ -47,6 +70,7 @@ SRC_TEST_C = \
test_main.c \
LIB_SRC_C += $(addprefix lib/,\
+ libc/string0.c \
libm/math.c \
libm/fmodf.c \
libm/nearbyintf.c \
@@ -89,11 +113,11 @@ SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
all: run
run: $(BUILD)/firmware.elf
- qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware.elf
+ qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $<
## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here.
$(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN)
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
include $(TOP)/py/mkrules.mk
diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test
index a9aace6d07..347c2fefd3 100644
--- a/ports/qemu-arm/Makefile.test
+++ b/ports/qemu-arm/Makefile.test
@@ -15,10 +15,10 @@ $(BUILD)/tinytest.o:
$(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c
$(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
- $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
test: $(BUILD)/firmware-test.elf
- qemu-system-arm -machine integratorcp -cpu cortex-m3 -nographic -monitor null -serial null -semihosting -kernel $(BUILD)/firmware-test.elf > $(BUILD)/console.out
+ qemu-system-arm -machine $(BOARD) $(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"
diff --git a/ports/qemu-arm/main.c b/ports/qemu-arm/main.c
index d23ef576f9..4cdd148287 100644
--- a/ports/qemu-arm/main.c
+++ b/ports/qemu-arm/main.c
@@ -30,7 +30,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
int main(int argc, char **argv) {
mp_stack_ctrl_init();
mp_stack_set_limit(10240);
- void *heap = malloc(16 * 1024);
+ uint32_t heap[16*1024 / 4];
gc_init(heap, (char*)heap + 16 * 1024);
mp_init();
do_str("print('hello world!')", MP_PARSE_SINGLE_INPUT);
diff --git a/ports/qemu-arm/mpconfigport.h b/ports/qemu-arm/mpconfigport.h
index 5d86191988..3d4abd52ff 100644
--- a/ports/qemu-arm/mpconfigport.h
+++ b/ports/qemu-arm/mpconfigport.h
@@ -38,7 +38,7 @@
#define MICROPY_PY_UHASHLIB (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
-#define MICROPY_USE_INTERNAL_PRINTF (0)
+#define MICROPY_USE_INTERNAL_PRINTF (1)
#define MICROPY_VFS (1)
// type definitions for the specific machine
@@ -54,9 +54,6 @@ 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;
-#include <unistd.h>
-#define MP_PLAT_PRINT_STRN(str, len) write(1, str, len)
-
// extra built in names to add to the global namespace
#define MICROPY_PORT_BUILTINS \
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
diff --git a/ports/qemu-arm/mphalport.h b/ports/qemu-arm/mphalport.h
index d996402ae4..29f080805f 100644
--- a/ports/qemu-arm/mphalport.h
+++ b/ports/qemu-arm/mphalport.h
@@ -1,2 +1,5 @@
+#include <stddef.h>
+#include "uart.h"
+
#define mp_hal_stdin_rx_chr() (0)
-#define mp_hal_stdout_tx_strn_cooked(s, l) write(1, (s), (l))
+#define mp_hal_stdout_tx_strn_cooked(s, l) uart_tx_strn((s), (l))
diff --git a/ports/qemu-arm/mps2.ld b/ports/qemu-arm/mps2.ld
new file mode 100644
index 0000000000..5c1aa21ca2
--- /dev/null
+++ b/ports/qemu-arm/mps2.ld
@@ -0,0 +1,38 @@
+MEMORY
+{
+ RAM : ORIGIN = 0x00000000, LENGTH = 4M
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+ .text : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ _sidata = _etext;
+ } > RAM
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >RAM
+}
diff --git a/ports/qemu-arm/nrf51.ld b/ports/qemu-arm/nrf51.ld
new file mode 100644
index 0000000000..70269773cb
--- /dev/null
+++ b/ports/qemu-arm/nrf51.ld
@@ -0,0 +1,39 @@
+MEMORY
+{
+ ROM : ORIGIN = 0x00000000, LENGTH = 1M
+ RAM : ORIGIN = 0x20000000, LENGTH = 256K
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+ .text : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ _sidata = _etext;
+ } > ROM
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >RAM
+}
diff --git a/ports/qemu-arm/startup.c b/ports/qemu-arm/startup.c
new file mode 100644
index 0000000000..5198d089f9
--- /dev/null
+++ b/ports/qemu-arm/startup.c
@@ -0,0 +1,84 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "uart.h"
+
+extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
+
+__attribute__((naked)) void Reset_Handler(void) {
+ // set stack pointer
+ __asm volatile ("ldr r0, =_estack");
+ __asm volatile ("mov sp, r0");
+ // copy .data section from flash to RAM
+ for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) {
+ *dest++ = *src++;
+ }
+ // zero out .bss section
+ for (uint32_t *dest = &_sbss; dest < &_ebss;) {
+ *dest++ = 0;
+ }
+ // jump to board initialisation
+ void _start(void);
+ _start();
+}
+
+void Default_Handler(void) {
+ for (;;) {
+ }
+}
+
+const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
+ (uint32_t)&_estack,
+ (uint32_t)&Reset_Handler,
+ (uint32_t)&Default_Handler, // NMI_Handler
+ (uint32_t)&Default_Handler, // HardFault_Handler
+ (uint32_t)&Default_Handler, // MemManage_Handler
+ (uint32_t)&Default_Handler, // BusFault_Handler
+ (uint32_t)&Default_Handler, // UsageFault_Handler
+ 0,
+ 0,
+ 0,
+ 0,
+ (uint32_t)&Default_Handler, // SVC_Handler
+ (uint32_t)&Default_Handler, // DebugMon_Handler
+ 0,
+ (uint32_t)&Default_Handler, // PendSV_Handler
+ (uint32_t)&Default_Handler, // SysTick_Handler
+};
+
+void _start(void) {
+ // Enable the UART
+ uart_init();
+
+ // Now that we have a basic system up and running we can call main
+ extern int main();
+ main(0, 0);
+
+ // Finished
+ exit(0);
+}
+
+__attribute__((naked)) void exit(int status) {
+ // Force qemu to exit using ARM Semihosting
+ __asm volatile (
+ "mov r1, r0\n"
+ "cmp r1, #0\n"
+ "bne .notclean\n"
+ "ldr r1, =0x20026\n" // ADP_Stopped_ApplicationExit, a clean exit
+ ".notclean:\n"
+ "movs r0, #0x18\n" // SYS_EXIT
+ "bkpt 0xab\n"
+ );
+ for (;;) {
+ }
+}
+
+// The following are needed for tinytest
+
+#include <stdio.h>
+
+int setvbuf(FILE *stream, char *buf, int mode, size_t size) {
+ return 0;
+}
+
+struct _reent *_impure_ptr;
diff --git a/ports/qemu-arm/stm32.ld b/ports/qemu-arm/stm32.ld
new file mode 100644
index 0000000000..4e541526b7
--- /dev/null
+++ b/ports/qemu-arm/stm32.ld
@@ -0,0 +1,39 @@
+MEMORY
+{
+ ROM : ORIGIN = 0x00000000, LENGTH = 1M
+ RAM : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+ .text : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ _sidata = _etext;
+ } > ROM
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >RAM
+}
diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c
index adbdf04e18..2cb9e73859 100644
--- a/ports/qemu-arm/test_main.c
+++ b/ports/qemu-arm/test_main.c
@@ -15,15 +15,14 @@
#include "tinytest.h"
#include "tinytest_macros.h"
-#define HEAP_SIZE (128 * 1024)
-STATIC void *heap;
+#define HEAP_SIZE (100 * 1024)
#include "genhdr/tests.h"
int main() {
mp_stack_ctrl_init();
mp_stack_set_limit(10240);
- heap = malloc(HEAP_SIZE);
+ 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);
@@ -34,8 +33,7 @@ void gc_collect(void) {
gc_collect_start();
// get the registers and the sp
- jmp_buf env;
- setjmp(env);
+ // TODO get registers
volatile mp_uint_t dummy;
void *sp = (void*)&dummy;
diff --git a/ports/qemu-arm/uart.c b/ports/qemu-arm/uart.c
new file mode 100644
index 0000000000..a0ce737c06
--- /dev/null
+++ b/ports/qemu-arm/uart.c
@@ -0,0 +1,78 @@
+#include <stdint.h>
+#include <stddef.h>
+
+#include "uart.h"
+
+#if defined(QEMU_SOC_STM32)
+
+typedef struct _UART_t {
+ volatile uint32_t SR;
+ volatile uint32_t DR;
+} UART_t;
+
+#define UART0 ((UART_t*)(0x40011000))
+
+void uart_init(void) {
+}
+
+void uart_tx_strn(const char *buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ UART0->DR = buf[i];
+ }
+}
+
+#elif defined(QEMU_SOC_NRF51)
+
+typedef struct _UART_t {
+ volatile uint32_t r0[2];
+ volatile uint32_t STARTTX; // 0x008
+ volatile uint32_t r1[(0x500 - 0x008) / 4 - 1];
+ volatile uint32_t ENABLE; // 0x500
+ volatile uint32_t r2[(0x51c - 0x500) / 4 - 1];
+ volatile uint32_t TXD; // 0x51c
+} UART_t;
+
+#define UART0 ((UART_t*)(0x40002000))
+
+void uart_init(void) {
+ UART0->ENABLE = 4;
+ UART0->STARTTX = 1;
+}
+
+void uart_tx_strn(const char *buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ UART0->TXD = buf[i];
+ }
+}
+
+#elif defined(QEMU_SOC_MPS2)
+
+#define UART_STATE_TXFULL (1 << 0)
+
+#define UART_CTRL_TX_EN (1 << 0)
+#define UART_CTRL_RX_EN (1 << 1)
+
+typedef struct _UART_t {
+ volatile uint32_t DATA;
+ volatile uint32_t STATE;
+ volatile uint32_t CTRL;
+ volatile uint32_t INTSTATUS;
+ volatile uint32_t BAUDDIV;
+} UART_t;
+
+#define UART0 ((UART_t*)(0x40004000))
+
+void uart_init(void) {
+ UART0->BAUDDIV = 16;
+ UART0->CTRL = UART_CTRL_TX_EN;
+}
+
+void uart_tx_strn(const char *buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ while (UART0->STATE & UART_STATE_TXFULL) {
+ }
+ UART0->DATA = buf[i];
+ }
+}
+
+#endif
diff --git a/ports/qemu-arm/uart.h b/ports/qemu-arm/uart.h
new file mode 100644
index 0000000000..a89e3f26e2
--- /dev/null
+++ b/ports/qemu-arm/uart.h
@@ -0,0 +1,2 @@
+void uart_init(void);
+void uart_tx_strn(const char *buf, size_t len);