From 8c8d49d08db37b889ca93aaf219a813874500603 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Wed, 5 Jun 2019 00:02:42 +0200
Subject: [PATCH] WIP: Add basic files

Signed-off-by: Rahix <rahix@rahix.de>
---
 ports/card10/Makefile       | 50 +++++++++++++++++++
 ports/card10/README.md      | 47 ++++++++++++++++++
 ports/card10/main.c         | 86 ++++++++++++++++++++++++++++++++
 ports/card10/mpconfigport.h | 98 +++++++++++++++++++++++++++++++++++++
 ports/card10/mphalport.h    |  3 ++
 ports/card10/uart_core.c    | 34 +++++++++++++
 6 files changed, 318 insertions(+)
 create mode 100644 ports/card10/Makefile
 create mode 100644 ports/card10/README.md
 create mode 100644 ports/card10/main.c
 create mode 100644 ports/card10/mpconfigport.h
 create mode 100644 ports/card10/mphalport.h
 create mode 100644 ports/card10/uart_core.c

diff --git a/ports/card10/Makefile b/ports/card10/Makefile
new file mode 100644
index 000000000..33b364014
--- /dev/null
+++ b/ports/card10/Makefile
@@ -0,0 +1,50 @@
+include ../../py/mkenv.mk
+
+# qstr definitions (must come before including py.mk)
+# QSTR_DEFS = qstrdefsport.h
+
+# include py core make definitions
+include $(TOP)/py/py.mk
+
+CROSS_COMPILE = arm-none-eabi-
+
+INC += -I.
+INC += -I$(TOP)
+INC += -I$(BUILD)
+
+CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
+CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
+LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections
+
+# Tune for Debugging or Optimization
+ifeq ($(DEBUG), 1)
+CFLAGS += -O0 -ggdb
+else
+CFLAGS += -Os -DNDEBUG
+CFLAGS += -fdata-sections -ffunction-sections
+endif
+
+LIBS =
+
+SRC_C = \
+	main.c \
+	uart_core.c \
+	lib/utils/printf.c \
+	lib/utils/stdout_helpers.c \
+	lib/utils/pyexec.c \
+	lib/libc/string0.c \
+	lib/mp-readline/readline.c \
+
+OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+
+all: $(BUILD)/firmware.elf
+
+$(BUILD)/firmware.elf: $(OBJ)
+	$(ECHO) "LINK $@"
+	$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+	$(Q)$(SIZE) $@
+
+# $(BUILD)/firmware.bin: $(BUILD)/firmware.elf
+# 	$(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
+
+include $(TOP)/py/mkrules.mk
diff --git a/ports/card10/README.md b/ports/card10/README.md
new file mode 100644
index 000000000..356fc4b3e
--- /dev/null
+++ b/ports/card10/README.md
@@ -0,0 +1,47 @@
+# The minimal port
+
+This port is intended to be a minimal MicroPython port that actually runs.
+It can run under Linux (or similar) and on any STM32F4xx MCU (eg the pyboard).
+
+## Building and running Linux version
+
+By default the port will be built for the host machine:
+
+    $ make
+
+To run the executable and get a basic working REPL do:
+
+    $ make run
+
+## Building for an STM32 MCU
+
+The Makefile has the ability to build for a Cortex-M CPU, and by default
+includes some start-up code for an STM32F4xx MCU and also enables a UART
+for communication.  To build:
+
+    $ make CROSS=1
+
+If you previously built the Linux version, you will need to first run
+`make clean` to get rid of incompatible object files.
+
+Building will produce the build/firmware.dfu file which can be programmed
+to an MCU using:
+
+    $ make CROSS=1 deploy
+
+This version of the build will work out-of-the-box on a pyboard (and
+anything similar), and will give you a MicroPython REPL on UART1 at 9600
+baud.  Pin PA13 will also be driven high, and this turns on the red LED on
+the pyboard.
+
+## Building without the built-in MicroPython compiler
+
+This minimal port can be built with the built-in MicroPython compiler
+disabled.  This will reduce the firmware by about 20k on a Thumb2 machine,
+and by about 40k on 32-bit x86.  Without the compiler the REPL will be
+disabled, but pre-compiled scripts can still be executed.
+
+To test out this feature, change the `MICROPY_ENABLE_COMPILER` config
+option to "0" in the mpconfigport.h file in this directory.  Then
+recompile and run the firmware and it will execute the frozentest.py
+file.
diff --git a/ports/card10/main.c b/ports/card10/main.c
new file mode 100644
index 000000000..38b5c947d
--- /dev/null
+++ b/ports/card10/main.c
@@ -0,0 +1,86 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "py/compile.h"
+#include "py/runtime.h"
+#include "py/repl.h"
+#include "py/gc.h"
+#include "py/mperrno.h"
+#include "lib/utils/pyexec.h"
+
+static char *stack_top;
+
+#if MICROPY_ENABLE_GC
+static char heap[2048];
+#endif
+
+int mp_hal_stdin_rx_chr(void);
+
+int main(int argc, char **argv) {
+    int stack_dummy;
+    stack_top = (char*)&stack_dummy;
+
+    #if MICROPY_ENABLE_GC
+    gc_init(heap, heap + sizeof(heap));
+    #endif
+
+    mp_init();
+    #if MICROPY_REPL_EVENT_DRIVEN
+    pyexec_event_repl_init();
+    for (;;) {
+        int c = mp_hal_stdin_rx_chr();
+        if (pyexec_event_repl_process_char(c)) {
+            break;
+        }
+    }
+    #else
+    // pyexec_friendly_repl();
+    #error TODO friendly_repl
+    #endif
+
+    mp_deinit();
+    return 0;
+}
+
+void gc_collect(void) {
+    // WARNING: This gc_collect implementation doesn't try to get root
+    // pointers from CPU registers, and thus may function incorrectly.
+    void *dummy;
+    gc_collect_start();
+    gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
+    gc_collect_end();
+    gc_dump_info();
+}
+
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
+    mp_raise_OSError(MP_ENOENT);
+}
+
+mp_import_stat_t mp_import_stat(const char *path) {
+    return MP_IMPORT_STAT_NO_EXIST;
+}
+
+mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
+
+void nlr_jump_fail(void *val) {
+    while (1);
+}
+
+void NORETURN __fatal_error(const char *msg) {
+    while (1);
+}
+
+#ifndef NDEBUG
+void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
+    printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
+    __fatal_error("Assertion failed");
+}
+#endif
+
+#if MICROPY_MIN_USE_CORTEX_CPU
+// TODO
+#endif
diff --git a/ports/card10/mpconfigport.h b/ports/card10/mpconfigport.h
new file mode 100644
index 000000000..14d3833cc
--- /dev/null
+++ b/ports/card10/mpconfigport.h
@@ -0,0 +1,98 @@
+#include <stdint.h>
+
+// options to control how MicroPython is built
+
+// You can disable the built-in MicroPython compiler by setting the following
+// config option to 0.  If you do this then you won't get a REPL prompt, but you
+// will still be able to execute pre-compiled scripts, compiled with mpy-cross.
+#define MICROPY_ENABLE_COMPILER     (1)
+
+#define MICROPY_QSTR_BYTES_IN_HASH  (1)
+#define MICROPY_QSTR_EXTRA_POOL     mp_qstr_frozen_const_pool
+#define MICROPY_ALLOC_PATH_MAX      (256)
+#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
+#define MICROPY_EMIT_X64            (0)
+#define MICROPY_EMIT_THUMB          (0)
+#define MICROPY_EMIT_INLINE_THUMB   (0)
+#define MICROPY_COMP_MODULE_CONST   (0)
+#define MICROPY_COMP_CONST          (0)
+#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
+#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
+#define MICROPY_MEM_STATS           (0)
+#define MICROPY_DEBUG_PRINTERS      (0)
+#define MICROPY_ENABLE_GC           (1)
+#define MICROPY_GC_ALLOC_THRESHOLD  (0)
+// TODO What value do we want
+#define MICROPY_REPL_EVENT_DRIVEN   (1)
+#define MICROPY_HELPER_REPL         (1)
+#define MICROPY_HELPER_LEXER_UNIX   (0)
+#define MICROPY_ENABLE_SOURCE_LINE  (0)
+#define MICROPY_ENABLE_DOC_STRING   (0)
+#define MICROPY_ERROR_REPORTING     (MICROPY_ERROR_REPORTING_TERSE)
+#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
+#define MICROPY_PY_ASYNC_AWAIT      (0)
+#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
+#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0)
+#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
+#define MICROPY_PY_BUILTINS_ENUMERATE (0)
+#define MICROPY_PY_BUILTINS_FILTER  (0)
+#define MICROPY_PY_BUILTINS_FROZENSET (0)
+#define MICROPY_PY_BUILTINS_REVERSED (0)
+#define MICROPY_PY_BUILTINS_SET     (0)
+#define MICROPY_PY_BUILTINS_SLICE   (0)
+#define MICROPY_PY_BUILTINS_PROPERTY (0)
+#define MICROPY_PY_BUILTINS_MIN_MAX (0)
+#define MICROPY_PY_BUILTINS_STR_COUNT (0)
+#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0)
+#define MICROPY_PY___FILE__         (0)
+#define MICROPY_PY_GC               (0)
+#define MICROPY_PY_ARRAY            (0)
+#define MICROPY_PY_ATTRTUPLE        (0)
+#define MICROPY_PY_COLLECTIONS      (0)
+#define MICROPY_PY_MATH             (0)
+#define MICROPY_PY_CMATH            (0)
+#define MICROPY_PY_IO               (0)
+#define MICROPY_PY_STRUCT           (0)
+#define MICROPY_PY_SYS              (0)
+#define MICROPY_MODULE_FROZEN_MPY   (1)
+#define MICROPY_CPYTHON_COMPAT      (0)
+#define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_NONE)
+#define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_NONE)
+
+// type definitions for the specific machine
+
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
+
+// This port is intended to be 32-bit, but unfortunately, int32_t for
+// different targets may be defined in different ways - either as int
+// or as long. This requires different printf formatting specifiers
+// to print such value. So, we avoid int32_t and use int directly.
+#define UINT_FMT "%u"
+#define INT_FMT "%d"
+typedef int mp_int_t; // must be pointer size
+typedef unsigned mp_uint_t; // must be pointer size
+
+typedef long mp_off_t;
+
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(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) },
+
+// We need to provide a declaration/definition of alloca()
+#include <alloca.h>
+
+#define MICROPY_HW_BOARD_NAME "minimal"
+#define MICROPY_HW_MCU_NAME "unknown-cpu"
+
+// TODO remove
+#ifdef __thumb__
+#define MICROPY_MIN_USE_CORTEX_CPU (1)
+#define MICROPY_MIN_USE_STM32_MCU (1)
+#endif
+
+#define MP_STATE_PORT MP_STATE_VM
+
+#define MICROPY_PORT_ROOT_POINTERS \
+    const char *readline_hist[8];
diff --git a/ports/card10/mphalport.h b/ports/card10/mphalport.h
new file mode 100644
index 000000000..a02cf83e1
--- /dev/null
+++ b/ports/card10/mphalport.h
@@ -0,0 +1,3 @@
+// TODO what is this
+static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; }
+static inline void mp_hal_set_interrupt_char(char c) {}
diff --git a/ports/card10/uart_core.c b/ports/card10/uart_core.c
new file mode 100644
index 000000000..f985e04b8
--- /dev/null
+++ b/ports/card10/uart_core.c
@@ -0,0 +1,34 @@
+#include <unistd.h>
+#include "py/mpconfig.h"
+#include "uart.h"
+
+/*
+ * Core UART functions to implement for a port
+ */
+
+mxc_uart_regs_t * ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);
+
+const uart_cfg_t uart_cfg = {
+	.parity = UART_PARITY_DISABLE,
+	.size   = UART_DATA_SIZE_8_BITS,
+	.stop   = UART_STOP_1,
+	.flow   = UART_FLOW_CTRL_DIS,
+	.pol    = UART_FLOW_POL_DIS,
+	.baud   = CONSOLE_BAUD,
+	.clksel = UART_CLKSEL_SYSTEM
+};
+
+const sys_cfg_uart_t uart_sys_cfg = {
+    .map = MAP_A,
+    .flow = Disable
+};
+
+// Receive single character
+int mp_hal_stdin_rx_chr(void) {
+	return UART_ReadByte(ConsoleUart);
+}
+
+// Send string of given length
+void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
+	UART_Write(ConsoleUart, str, len);
+}
-- 
GitLab