From b84406f3133a36a703a1506d754fc046dd955922 Mon Sep 17 00:00:00 2001
From: Damien George <damien@micropython.org>
Date: Tue, 25 May 2021 22:16:08 +1000
Subject: [PATCH] qemu-arm: Add support for Cortex-A9 via sabrelite board.

Signed-off-by: Damien George <damien@micropython.org>
---
 ports/qemu-arm/Makefile       | 21 ++++++++++++----
 ports/qemu-arm/Makefile.test  |  7 +++++-
 ports/qemu-arm/imx6.ld        | 47 +++++++++++++++++++++++++++++++++++
 ports/qemu-arm/mpconfigport.h | 11 +++++---
 ports/qemu-arm/startup.c      | 27 ++++++++++++++++++++
 ports/qemu-arm/uart.c         | 27 ++++++++++++++++++++
 6 files changed, 131 insertions(+), 9 deletions(-)
 create mode 100644 ports/qemu-arm/imx6.ld

diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile
index aebc5afaeb..22d0bf39cd 100644
--- a/ports/qemu-arm/Makefile
+++ b/ports/qemu-arm/Makefile
@@ -16,7 +16,8 @@ ifeq ($(BOARD),netduino2)
 CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
 CFLAGS += -DQEMU_SOC_STM32
 LDSCRIPT = stm32.ld
-SRC_BOARD_O = lib/utils/gchelper_m3.o
+SRC_BOARD_O = lib/utils/gchelper_native.o lib/utils/gchelper_m3.o
+MPY_CROSS_FLAGS += -march=armv7m
 endif
 
 ifeq ($(BOARD),microbit)
@@ -24,14 +25,26 @@ 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
-SRC_BOARD_O = lib/utils/gchelper_m0.o
+SRC_BOARD_O = lib/utils/gchelper_native.o lib/utils/gchelper_m0.o
+MPY_CROSS_FLAGS += -march=armv7m
 endif
 
 ifeq ($(BOARD),mps2-an385)
 CFLAGS += -mthumb -mcpu=cortex-m3 -mfloat-abi=soft
 CFLAGS += -DQEMU_SOC_MPS2
 LDSCRIPT = mps2.ld
-SRC_BOARD_O = lib/utils/gchelper_m3.o
+SRC_BOARD_O = lib/utils/gchelper_native.o lib/utils/gchelper_m3.o
+MPY_CROSS_FLAGS += -march=armv7m
+endif
+
+ifeq ($(BOARD),sabrelite)
+CFLAGS += -mcpu=cortex-a9
+CFLAGS += -DQEMU_SOC_IMX6
+LDSCRIPT = imx6.ld
+QEMU_EXTRA = -m 128M
+SRC_BOARD_O = lib/utils/gchelper_generic.o
+# It's really armv7a but closest supported value is armv6.
+MPY_CROSS_FLAGS += -march=armv6
 endif
 
 CROSS_COMPILE ?= arm-none-eabi-
@@ -95,7 +108,6 @@ LIB_SRC_C += $(addprefix lib/,\
 	libm/atanf.c \
 	libm/atan2f.c \
 	libm/roundf.c \
-	utils/gchelper_native.c \
 	utils/sys_stdio_mphal.c \
 	)
 
@@ -125,7 +137,6 @@ ifneq ($(FROZEN_MANIFEST),)
 CFLAGS += -DMICROPY_MODULE_FROZEN_STR
 CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
 CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-MPY_CROSS_FLAGS += -march=armv7m
 endif
 
 all: run
diff --git a/ports/qemu-arm/Makefile.test b/ports/qemu-arm/Makefile.test
index 6b7f1dc7ab..b4ad6114b8 100644
--- a/ports/qemu-arm/Makefile.test
+++ b/ports/qemu-arm/Makefile.test
@@ -4,6 +4,11 @@ FROZEN_MANIFEST ?= "freeze('test-frzmpy')"
 
 include Makefile
 
+ifeq ($(BOARD),sabrelite)
+# These don't work on Cortex-A9.
+TESTS_EXCLUDE = inlineasm/asmdiv.py inlineasm/asmspecialregs.py
+endif
+
 CFLAGS += -DTEST
 
 .PHONY: $(BUILD)/genhdr/tests.h
@@ -11,7 +16,7 @@ CFLAGS += -DTEST
 $(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
 $(BUILD)/genhdr/tests.h:
 	(cd $(TOP)/tests; ./run-tests.py --target=qemu-arm --write-exp)
-	$(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@
+	$(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py $(addprefix --exclude ,$(TESTS_EXCLUDE))) > $@
 
 $(BUILD)/lib/tinytest/tinytest.o: CFLAGS += -DNO_FORKING
 
diff --git a/ports/qemu-arm/imx6.ld b/ports/qemu-arm/imx6.ld
new file mode 100644
index 0000000000..7155956f15
--- /dev/null
+++ b/ports/qemu-arm/imx6.ld
@@ -0,0 +1,47 @@
+/* Vector table is at 0x00000000, entry point is 0x10000000. */
+
+MEMORY
+{
+    ROM : ORIGIN = 0x00000000, LENGTH = 96K
+    RAM : ORIGIN = 0x10000000, LENGTH = 128M
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+    .rom : {
+        . = ALIGN(4);
+        KEEP(*(.isr_vector))
+        . = ALIGN(4);
+    } > ROM
+
+    .text : {
+        . = ALIGN(4);
+        *(.text.Reset_Handler)
+        *(.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/mpconfigport.h b/ports/qemu-arm/mpconfigport.h
index 498ab3ed2c..1f05719caa 100644
--- a/ports/qemu-arm/mpconfigport.h
+++ b/ports/qemu-arm/mpconfigport.h
@@ -3,9 +3,16 @@
 // options to control how MicroPython is built
 
 #define MICROPY_ALLOC_PATH_MAX      (512)
-#define MICROPY_EMIT_X64            (0)
+
+#if defined(__ARM_ARCH_ISA_ARM)
+#define MICROPY_EMIT_ARM            (1)
+#define MICROPY_EMIT_INLINE_THUMB   (1)
+#elif defined(__ARM_ARCH_ISA_THUMB)
 #define MICROPY_EMIT_THUMB          (1)
 #define MICROPY_EMIT_INLINE_THUMB   (1)
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
+#endif
+
 #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
 #define MICROPY_MEM_STATS           (1)
 #define MICROPY_DEBUG_PRINTERS      (0)
@@ -43,8 +50,6 @@
 
 // type definitions for the specific machine
 
-#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
-
 #define MP_SSIZE_MAX (0x7fffffff)
 
 #define UINT_FMT "%lu"
diff --git a/ports/qemu-arm/startup.c b/ports/qemu-arm/startup.c
index 58bdf7af9e..a52b068c33 100644
--- a/ports/qemu-arm/startup.c
+++ b/ports/qemu-arm/startup.c
@@ -28,6 +28,27 @@ void Default_Handler(void) {
     }
 }
 
+#if defined(__ARM_ARCH_ISA_ARM)
+
+// ARM architecture with standard ARM ISA.
+
+__attribute__((naked, section(".isr_vector"))) void isr_vector(void) {
+    __asm volatile (
+        "b Reset_Handler\n"
+        "b Default_Handler\n"
+        "b Default_Handler\n"
+        "b Default_Handler\n"
+        "b Default_Handler\n"
+        "nop\n"
+        "b Default_Handler\n"
+        "b Default_Handler\n"
+        );
+}
+
+#elif defined(__ARM_ARCH_ISA_THUMB)
+
+// ARM architecture with Thumb-only ISA.
+
 const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
     (uint32_t)&_estack,
     (uint32_t)&Reset_Handler,
@@ -47,6 +68,8 @@ const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
     (uint32_t)&Default_Handler, // SysTick_Handler
 };
 
+#endif
+
 void _start(void) {
     // Enable the UART
     uart_init();
@@ -68,7 +91,11 @@ __attribute__((naked)) void exit(int status) {
         "ldr r1, =0x20026\n" // ADP_Stopped_ApplicationExit, a clean exit
         ".notclean:\n"
         "movs r0, #0x18\n" // SYS_EXIT
+        #if defined(__ARM_ARCH_ISA_ARM)
+        "svc 0x00123456\n"
+        #elif defined(__ARM_ARCH_ISA_THUMB)
         "bkpt 0xab\n"
+        #endif
         );
     for (;;) {
     }
diff --git a/ports/qemu-arm/uart.c b/ports/qemu-arm/uart.c
index 8710e9e9f6..828398cd17 100644
--- a/ports/qemu-arm/uart.c
+++ b/ports/qemu-arm/uart.c
@@ -75,4 +75,31 @@ void uart_tx_strn(const char *buf, size_t len) {
     }
 }
 
+#elif defined(QEMU_SOC_IMX6)
+
+#define UART_UCR1_UARTEN (1 << 0)
+#define UART_UCR2_TXEN (1 << 2)
+
+typedef struct _UART_t {
+    volatile uint32_t URXD; // 0x00
+    volatile uint32_t r0[15];
+    volatile uint32_t UTXD; // 0x40
+    volatile uint32_t r1[15];
+    volatile uint32_t UCR1; // 0x80
+    volatile uint32_t UCR2; // 0x84
+} UART_t;
+
+#define UART1 ((UART_t *)(0x02020000))
+
+void uart_init(void) {
+    UART1->UCR1 = UART_UCR1_UARTEN;
+    UART1->UCR2 = UART_UCR2_TXEN;
+}
+
+void uart_tx_strn(const char *buf, size_t len) {
+    for (size_t i = 0; i < len; ++i) {
+        UART1->UTXD = buf[i];
+    }
+}
+
 #endif