diff --git a/.travis.yml b/.travis.yml index 077fca20a..5923cb2b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -232,3 +232,12 @@ jobs: - sudo apt-get install libnewlib-arm-none-eabi script: - make ${MAKEOPTS} -C ports/teensy + + # powerpc port + - stage: test + env: NAME="powerpc port build" + install: + - sudo apt-get install gcc-powerpc64le-linux-gnu + - sudo apt-get install libc6-dev-ppc64el-cross + script: + - make ${MAKEOPTS} -C ports/powerpc CROSS_COMPILE=powerpc64le-linux-gnu- diff --git a/ports/powerpc/Makefile b/ports/powerpc/Makefile new file mode 100644 index 000000000..30474df1d --- /dev/null +++ b/ports/powerpc/Makefile @@ -0,0 +1,64 @@ +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 + +ARCH = $(shell uname -m) +ifneq ("$(ARCH)", "ppc64") +ifneq ("$(ARCH)", "ppc64le") + CROSS_COMPILE = powerpc64le-linux- +endif +endif + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) + +CFLAGS = $(INC) -g -Wall -std=c99 $(COPT) +CFLAGS += -mno-string -mno-multiple -mno-vsx -mno-altivec -nostdlib +CFLAGS += -mlittle-endian -mstrict-align -msoft-float +CFLAGS += -Os +CFLAGS += -fdata-sections -ffunction-sections -fno-stack-protector -ffreestanding +CFLAGS += -U_FORTIFY_SOURCE + +LDFLAGS = -N -T powerpc.lds -nostdlib + +LIBS = + +SRC_C = \ + main.c \ + uart_core.c \ + uart_potato.c \ + uart_lpc_serial.c \ + lib/utils/printf.c \ + lib/utils/stdout_helpers.c \ + lib/utils/pyexec.c \ + lib/libc/string0.c \ + lib/mp-readline/readline.c \ + $(BUILD)/_frozen_mpy.c \ + +OBJ = $(PY_CORE_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(BUILD)/head.o + +all: $(BUILD)/firmware.elf $(BUILD)/firmware.map $(BUILD)/firmware.bin + +$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h + $(ECHO) "MISC freezing bytecode" + $(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=mpz $< > $@ + +$(BUILD)/firmware.elf: $(OBJ) powerpc.lds + $(ECHO) "LINK $@" + $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(Q)$(OBJCOPY) -O binary $^ $(BUILD)/firmware.bin + +$(BUILD)/firmware.map: $(BUILD)/firmware.elf + $(Q)nm $^ | sort > $(BUILD)/firmware.map + +include $(TOP)/py/mkrules.mk diff --git a/ports/powerpc/README.md b/ports/powerpc/README.md new file mode 100644 index 000000000..862bfcd3c --- /dev/null +++ b/ports/powerpc/README.md @@ -0,0 +1,40 @@ +# The PowerPC port that runs on microwatt and qemu + +This port is intended to be a minimal MicroPython port that runs in +QEMU, microwatt simulator with ghdl or microwatt on Xilinx FPGA with +potato UART. + +## Building + +By default the port will be built for the host machine: + + $ make + +## Cross compilation for POWERPC + +If you need to cross compilers you'll want to grab a powerpc64le +compiler (not powerpc or powerpc64). + +On Ubuntu (18.04) you'll want: + + $ apt install gcc-powerpc64le-linux-gnu + +*(Use CROSS_COMPILE=powerpc64le-linux-gnu-)* + +If your distro doesn't have cross compilers, you can get cross compilers here: +- https://toolchains.bootlin.com/ +*(use CROSS_COMPILE=powerpc64le-buildroot-linux-gnu-)* + +(Avoid musl libc as it defines __assert_fail() differently to glibc +which breaks the micropython powerpc code) + +Then do: + + $ make CROSS_COMPILE= + +Building will produce the build/firmware.bin file which can be used +QEMU or [microwatt](https://github.com/antonblanchard/microwatt). + +To run in QEMU use: + + $ ./qemu-system-ppc64 -M powernv -cpu POWER9 -nographic -bios build/firmware.bin diff --git a/ports/powerpc/frozentest.mpy b/ports/powerpc/frozentest.mpy new file mode 100644 index 000000000..8a89194a1 Binary files /dev/null and b/ports/powerpc/frozentest.mpy differ diff --git a/ports/powerpc/frozentest.py b/ports/powerpc/frozentest.py new file mode 100644 index 000000000..0f99b7429 --- /dev/null +++ b/ports/powerpc/frozentest.py @@ -0,0 +1,7 @@ +print('uPy') +print('a long string that is not interned') +print('a string that has unicode αβγ chars') +print(b'bytes 1234\x01') +print(123456789) +for i in range(4): + print(i) diff --git a/ports/powerpc/head.S b/ports/powerpc/head.S new file mode 100644 index 000000000..09aa62e59 --- /dev/null +++ b/ports/powerpc/head.S @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +#define STACK_TOP 0x60000 + +#define FIXUP_ENDIAN \ + tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \ + b 191f; /* Skip trampoline if endian is good */ \ + .long 0xa600607d; /* mfmsr r11 */ \ + .long 0x01006b69; /* xori r11,r11,1 */ \ + .long 0x05009f42; /* bcl 20,31,$+4 */ \ + .long 0xa602487d; /* mflr r10 */ \ + .long 0x14004a39; /* addi r10,r10,20 */ \ + .long 0xa64b5a7d; /* mthsrr0 r10 */ \ + .long 0xa64b7b7d; /* mthsrr1 r11 */ \ + .long 0x2402004c; /* hrfid */ \ + 191: + +/* Load an immediate 64-bit value into a register */ +#define LOAD_IMM64(r, e) \ + lis r,(e)@highest; \ + ori r,r,(e)@higher; \ + rldicr r,r, 32, 31; \ + oris r,r, (e)@h; \ + ori r,r, (e)@l; + +.section ".head","ax" + +/* + * Microwatt comes in at 0 as little endian so we do not need to worry up + * FIXUP_ENDIAN. + */ + . = 0 + .global _start +_start: + b boot_entry + +/* QEMU comes in at 0x10. Put a value in argc/r3 to distingush from + * microwatt. */ + . = 0x10 + FIXUP_ENDIAN + LOAD_IMM64(%r3, 1) + b boot_entry + + .global boot_entry + boot_entry: + /* Save R3 to non-volatile register */ + mr %r14, %r3 + restart: + /* + * setup stack with a safety gap, since we might write to the + * previous frame. + */ + LOAD_IMM64(%r1, STACK_TOP - 0x100) + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl + + /* On exit, restart */ + mr %r3, %r14 + b restart + +#define EXCEPTION(nr) \ + .= nr; \ +b . + + /* More exception stubs */ + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) + EXCEPTION(0x1000) + EXCEPTION(0x1100) + EXCEPTION(0x1200) + EXCEPTION(0x1300) + EXCEPTION(0x1400) + EXCEPTION(0x1500) + EXCEPTION(0x1600) diff --git a/ports/powerpc/main.c b/ports/powerpc/main.c new file mode 100644 index 000000000..9b164ac18 --- /dev/null +++ b/ports/powerpc/main.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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 + +#include "py/compile.h" +#include "py/runtime.h" +#include "py/repl.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/stackctrl.h" +#include "lib/utils/pyexec.h" + +void __stack_chk_fail(void); +void __stack_chk_fail(void) { + static bool failed_once; + + if (failed_once) { + return; + } + failed_once = true; + printf("Stack corruption detected !\n"); + assert(0); +} + +/* fill in __assert_fail for libc */ +void __assert_fail(const char *__assertion, const char *__file, + unsigned int __line, const char *__function) { + printf("Assert at %s:%d:%s() \"%s\" failed\n", __file, __line, __function, __assertion); + for (;;) ; +} + +static char *stack_top; +#if MICROPY_ENABLE_GC +static char heap[32 * 1024]; +#endif + +extern void uart_init_ppc(int qemu); + +int main(int argc, char **argv) { + int stack_dummy; + stack_top = (char*)&stack_dummy; + + // microwatt has argc/r3 = 0 whereas QEMU has r3 set in head.S + uart_init_ppc(argc); + + #if MICROPY_ENABLE_PYSTACK + static mp_obj_t pystack[1024]; + mp_pystack_init(pystack, &pystack[1024]); + #endif + + #if MICROPY_STACK_CHECK + mp_stack_ctrl_init(); + mp_stack_set_limit(48 * 1024); + #endif + + #if MICROPY_ENABLE_GC + gc_init(heap, heap + sizeof(heap)); + #endif + mp_init(); + #if MICROPY_ENABLE_COMPILER + #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(); + #endif + #else + pyexec_frozen_module("frozentest.py"); + #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 diff --git a/ports/powerpc/mpconfigport.h b/ports/powerpc/mpconfigport.h new file mode 100644 index 000000000..93ef699ad --- /dev/null +++ b/ports/powerpc/mpconfigport.h @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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 + +// 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_DEBUG_VERBOSE (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 (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_STACK_CHECK (1) +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_REPL_EVENT_DRIVEN (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_HELPER_LEXER_UNIX (0) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#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_MODULE_BUILTIN_INIT (1) +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_BUILTINS_ENUMERATE (1) +#define MICROPY_PY_BUILTINS_FILTER (1) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_BUILTINS_REVERSED (1) +#define MICROPY_PY_BUILTINS_SET (1) +#define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_PROPERTY (1) +#define MICROPY_PY_BUILTINS_MIN_MAX (1) +#define MICROPY_PY_BUILTINS_STR_COUNT (1) +#define MICROPY_PY_BUILTINS_STR_OP_MODULO (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_BUILTINS_HELP_MODULES (1) +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_GC (1) +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_COLLECTIONS (1) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (1) +#define MICROPY_PY_SYS (1) +#define MICROPY_MODULE_FROZEN_MPY (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_ENABLE_PYSTACK (1) +#define MICROPY_USE_INTERNAL_PRINTF (1) + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1)) + +// This port is 64-bit +#define UINT_FMT "%lu" +#define INT_FMT "%ld" +typedef signed long mp_int_t; // must be pointer size +typedef unsigned long 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) }, + +#define MICROPY_HW_BOARD_NAME "bare-metal" +#define MICROPY_HW_MCU_NAME "POWERPC" + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; + +// powerpc64 gcc doesn't seem to define these +// These are pointers, so make them 64 bit types +typedef long intptr_t; +typedef unsigned long uintptr_t; diff --git a/ports/powerpc/mphalport.h b/ports/powerpc/mphalport.h new file mode 100644 index 000000000..c6bf94007 --- /dev/null +++ b/ports/powerpc/mphalport.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +#define mftb() ({unsigned long rval; \ + __asm__ volatile("mftb %0" : "=r" (rval)); rval;}) + +#define TBFREQ 512000000 + +static inline mp_uint_t mp_hal_ticks_ms(void) { + unsigned long tb = mftb(); + + return tb * 1000 / TBFREQ; +} + +static inline mp_uint_t mp_hal_ticks_us(void) { + unsigned long tb = mftb(); + + return tb * 1000000 / TBFREQ; +} + +static inline void mp_hal_set_interrupt_char(char c) { +} diff --git a/ports/powerpc/powerpc.lds b/ports/powerpc/powerpc.lds new file mode 100644 index 000000000..93bd8a605 --- /dev/null +++ b/ports/powerpc/powerpc.lds @@ -0,0 +1,13 @@ +SECTIONS +{ + . = 0; + _start = .; + .head : { + KEEP(*(.head)) + } + + /* Put this at 0x1700 which is right after our execption + * vectors in head.S. + */ + . = 0x1700; +} diff --git a/ports/powerpc/qstrdefsport.h b/ports/powerpc/qstrdefsport.h new file mode 100644 index 000000000..3ba897069 --- /dev/null +++ b/ports/powerpc/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/powerpc/uart_core.c b/ports/powerpc/uart_core.c new file mode 100644 index 000000000..b0dcd031a --- /dev/null +++ b/ports/powerpc/uart_core.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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 +#include + +#include "py/mpconfig.h" +#include "uart_potato.h" +#include "uart_lpc_serial.h" + +static int lpc_console; +static int potato_console; + +void uart_init_ppc(int lpc) { + lpc_console = lpc; + + if (!lpc_console) { + potato_console = 1; + + potato_uart_init(); + } else { + lpc_uart_init(); + } +} + +// Receive single character +int mp_hal_stdin_rx_chr(void) { + unsigned char c = 0; + if (lpc_console) { + c = lpc_uart_read(); + } else if (potato_console) { + c = potato_uart_read(); + } + return c; +} + +// Send string of given length +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + if (lpc_console) { + int i; + for (i = 0; i < len; i++) { + lpc_uart_write(str[i]); + } + } else if (potato_console) { + int i; + for (i = 0; i < len; i++) { + potato_uart_write(str[i]); + } + } +} diff --git a/ports/powerpc/uart_lpc_serial.c b/ports/powerpc/uart_lpc_serial.c new file mode 100644 index 000000000..51a55cb1e --- /dev/null +++ b/ports/powerpc/uart_lpc_serial.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +/* + * This is the LPC serial UART used by POWER9 boxes. This is modelled + * in the qemu POWER9 machine. + */ + +#include +#include +#include "py/mpconfig.h" + +#define PROC_FREQ 50000000 +#define UART_FREQ 115200 +#define UART_BASE 0xc0002000 +#define LPC_UART_BASE 0x60300d00103f8 + +/* Taken from skiboot */ +#define REG_RBR 0 +#define REG_THR 0 +#define REG_DLL 0 +#define REG_IER 1 +#define REG_DLM 1 +#define REG_FCR 2 +#define REG_IIR 2 +#define REG_LCR 3 +#define REG_MCR 4 +#define REG_LSR 5 +#define REG_MSR 6 +#define REG_SCR 7 + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +#define LCR_DLAB 0x80 /* DLL access */ + +#define IER_RX 0x01 +#define IER_THRE 0x02 +#define IER_ALL 0x0f + +static uint64_t lpc_uart_base; + +static void lpc_uart_reg_write(uint64_t offset, uint8_t val) { + uint64_t addr; + + addr = lpc_uart_base + offset; + + *(volatile uint8_t *)addr = val; +} + +static uint8_t lpc_uart_reg_read(uint64_t offset) { + uint64_t addr; + uint8_t val; + + addr = lpc_uart_base + offset; + + val = *(volatile uint8_t *)addr; + + return val; +} + +static int lpc_uart_tx_full(void) { + return !(lpc_uart_reg_read(REG_LSR) & LSR_THRE); +} + +static int lpc_uart_rx_empty(void) { + return !(lpc_uart_reg_read(REG_LSR) & LSR_DR); +} + +void lpc_uart_init(void) { + lpc_uart_base = LPC_UART_BASE; +} + +char lpc_uart_read(void) { + while (lpc_uart_rx_empty()) ; + return lpc_uart_reg_read(REG_THR); +} + +void lpc_uart_write(char c) { + while (lpc_uart_tx_full()); + lpc_uart_reg_write(REG_RBR, c); +} diff --git a/ports/powerpc/uart_lpc_serial.h b/ports/powerpc/uart_lpc_serial.h new file mode 100644 index 000000000..d0e35ca32 --- /dev/null +++ b/ports/powerpc/uart_lpc_serial.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +void lpc_uart_init(void); +char lpc_uart_read(void); +void lpc_uart_write(char c); diff --git a/ports/powerpc/uart_potato.c b/ports/powerpc/uart_potato.c new file mode 100644 index 000000000..18f89d463 --- /dev/null +++ b/ports/powerpc/uart_potato.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +/* + * This is a driver for the potato UART used by the microwatt core. + * The original potato UART came from here + * https://github.com/skordal/potato + */ + +#include +#include +#include "py/mpconfig.h" + +#define PROC_FREQ 50000000 +#define UART_FREQ 115200 +#define POTATO_UART_BASE 0xc0002000 +uint64_t potato_uart_base; + +#define POTATO_CONSOLE_TX 0x00 +#define POTATO_CONSOLE_RX 0x08 +#define POTATO_CONSOLE_STATUS 0x10 +#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x01 +#define POTATO_CONSOLE_STATUS_TX_EMPTY 0x02 +#define POTATO_CONSOLE_STATUS_RX_FULL 0x04 +#define POTATO_CONSOLE_STATUS_TX_FULL 0x08 +#define POTATO_CONSOLE_CLOCK_DIV 0x18 +#define POTATO_CONSOLE_IRQ_EN 0x20 + +static uint64_t potato_uart_reg_read(int offset) { + uint64_t addr; + uint64_t val; + + addr = potato_uart_base + offset; + + val = *(volatile uint64_t *)addr; + + return val; +} + +void potato_uart_reg_write(int offset, uint64_t val) { + uint64_t addr; + + addr = potato_uart_base + offset; + + *(volatile uint64_t *)addr = val; +} + +static int potato_uart_rx_empty(void) { + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_RX_EMPTY) { + return 1; + } + + return 0; +} + +static int potato_uart_tx_full(void) { + uint64_t val; + + val = potato_uart_reg_read(POTATO_CONSOLE_STATUS); + + if (val & POTATO_CONSOLE_STATUS_TX_FULL) { + return 1; + } + + return 0; +} + +static unsigned long potato_uart_divisor(unsigned long proc_freq, unsigned long uart_freq) { + return proc_freq / (uart_freq * 16) - 1; +} + +void potato_uart_init(void) { + potato_uart_base = POTATO_UART_BASE; + potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, potato_uart_divisor(PROC_FREQ, UART_FREQ)); + +} + +char potato_uart_read(void) { + uint64_t val; + + while (potato_uart_rx_empty()); + val = potato_uart_reg_read(POTATO_CONSOLE_RX); + + return (char)(val & 0x000000ff); +} + +void potato_uart_write(char c) { + uint64_t val; + + val = c; + + while (potato_uart_tx_full()); + potato_uart_reg_write(POTATO_CONSOLE_TX, val); +} diff --git a/ports/powerpc/uart_potato.h b/ports/powerpc/uart_potato.h new file mode 100644 index 000000000..d6bd93aa4 --- /dev/null +++ b/ports/powerpc/uart_potato.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ + +void potato_uart_init(void); +char potato_uart_read(void); +void potato_uart_write(char c); diff --git a/ports/powerpc/unistd.h b/ports/powerpc/unistd.h new file mode 100644 index 000000000..88e3b2721 --- /dev/null +++ b/ports/powerpc/unistd.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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. + */ +#ifndef MICROPY_INCLUDED_POWERPC_UNISTD_H +#define MICROPY_INCLUDED_POWERPC_UNISTD_H + +// powerpc gcc compiler doesn't seem to have unistd.h file + +#define SEEK_SET 0 +#define SEEK_CUR 1 + +typedef int ssize_t; + +#endif // MICROPY_INCLUDED_POWERPC_UNISTD_H diff --git a/py/nlr.h b/py/nlr.h index f2453bc46..3be3eb58c 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -73,6 +73,10 @@ #elif defined(__xtensa__) #define MICROPY_NLR_XTENSA (1) #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA) +#elif defined(__powerpc__) + #define MICROPY_NLR_POWERPC (1) + // this could be less but using 128 for safety + #define MICROPY_NLR_NUM_REGS (128) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" diff --git a/py/nlrpowerpc.c b/py/nlrpowerpc.c new file mode 100644 index 000000000..b40382381 --- /dev/null +++ b/py/nlrpowerpc.c @@ -0,0 +1,121 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019, Michael Neuling, IBM Corporation. + * + * 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 "py/mpstate.h" + +#if MICROPY_NLR_POWERPC + +#undef nlr_push + +// Saving all ABI non-vol registers here + +unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm__ volatile( + "li 4, 0x4eed ; " // Store canary + "std 4, 0x00(%0) ;" + "std 0, 0x08(%0) ;" + "std 1, 0x10(%0) ;" + "std 2, 0x18(%0) ;" + "std 14, 0x20(%0) ;" + "std 15, 0x28(%0) ;" + "std 16, 0x30(%0) ;" + "std 17, 0x38(%0) ;" + "std 18, 0x40(%0) ;" + "std 19, 0x48(%0) ;" + "std 20, 0x50(%0) ;" + "std 21, 0x58(%0) ;" + "std 22, 0x60(%0) ;" + "std 23, 0x68(%0) ;" + "std 24, 0x70(%0) ;" + "std 25, 0x78(%0) ;" + "std 26, 0x80(%0) ;" + "std 27, 0x88(%0) ;" + "std 28, 0x90(%0) ;" + "std 29, 0x98(%0) ;" + "std 30, 0xA0(%0) ;" + "std 31, 0xA8(%0) ;" + + "mfcr 4 ; " + "std 4, 0xB0(%0) ;" + "mflr 4 ;" + "std 4, 0xB8(%0) ;" + "li 4, nlr_push_tail@l ;" + "oris 4, 4, nlr_push_tail@h ;" + "mtctr 4 ;" + "mr 3, %1 ; " + "bctr ;" + : + : "r"(&nlr->regs), "r"(nlr) + : + ); + + return 0; +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + __asm__ volatile( + "ld 3, 0x0(%0) ;" + "cmpdi 3, 0x4eed ; " // Check canary + "bne . ; " + "ld 0, 0x08(%0) ;" + "ld 1, 0x10(%0) ;" + "ld 2, 0x18(%0) ;" + "ld 14, 0x20(%0) ;" + "ld 15, 0x28(%0) ;" + "ld 16, 0x30(%0) ;" + "ld 17, 0x38(%0) ;" + "ld 18, 0x40(%0) ;" + "ld 19, 0x48(%0) ;" + "ld 20, 0x50(%0) ;" + "ld 21, 0x58(%0) ;" + "ld 22, 0x60(%0) ;" + "ld 23, 0x68(%0) ;" + "ld 24, 0x70(%0) ;" + "ld 25, 0x78(%0) ;" + "ld 26, 0x80(%0) ;" + "ld 27, 0x88(%0) ;" + "ld 28, 0x90(%0) ;" + "ld 29, 0x98(%0) ;" + "ld 30, 0xA0(%0) ;" + "ld 31, 0xA8(%0) ;" + "ld 3, 0xB0(%0) ;" + "mtcr 3 ;" + "ld 3, 0xB8(%0) ;" + "mtlr 3 ; " + "li 3, 1;" + "blr ;" + : + : "r"(&top->regs) + : + ); + + MP_UNREACHABLE; +} + +#endif // MICROPY_NLR_POWERPC diff --git a/py/py.mk b/py/py.mk index 514a0e405..d7021d326 100644 --- a/py/py.mk +++ b/py/py.mk @@ -46,6 +46,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrx86.o \ nlrx64.o \ nlrthumb.o \ + nlrpowerpc.o \ nlrxtensa.o \ nlrsetjmp.o \ malloc.o \