diff --git a/.gitmodules b/.gitmodules index c152e9e7747fa..ee1b2bd61c2a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,3 +36,6 @@ [submodule "lib/nxp_driver"] path = lib/nxp_driver url = https://github.com/hathach/nxp_driver.git +[submodule "ports/gd32vf103/gd32vf103inator"] + path = ports/gd32vf103/gd32vf103inator + url = https://github.com/esmil/gd32vf103inator.git diff --git a/.travis.yml b/.travis.yml index c9fcc21336efd..8d1320ba5e2c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -157,7 +157,7 @@ jobs: - MICROPYPATH=examples/natmod/features2 ./ports/unix/micropython-coverage -m features2 - (cd tests && ./run-natmodtests.py extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py) # run coveralls coverage analysis (try to, even if some builds/tests failed) - - (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod) + - '[ "x$NOCOVERALLS" != x ] || (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options ''\-o build-coverage/'' --include py --include extmod)' after_failure: - tests/run-tests --print-failures @@ -394,3 +394,15 @@ jobs: script: - make ${MAKEOPTS} -C ports/powerpc UART=potato - make ${MAKEOPTS} -C ports/powerpc UART=lpc_serial + + # gd32vf103 port + - stage: test + name: "gd32vf103 port build" + os: linux + dist: focal + install: + - sudo apt-get install gcc-riscv64-unknown-elf gcc-riscv64-linux-gnu + script: + - make ${MAKEOPTS} -C ports/gd32vf103 submodules + - make ${MAKEOPTS} -C ports/gd32vf103 BUILD=build-baremetal + - make ${MAKEOPTS} -C ports/gd32vf103 BUILD=build-linux CROSS_COMPILE=riscv64-linux-gnu- diff --git a/extmod/extmod.mk b/extmod/extmod.mk index e312acba86db4..b000b058d7bd4 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -37,6 +37,8 @@ SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\ lfs2.c \ lfs2_util.c \ ) + +$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-missing-field-initializers endif ################################################################################ diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index 9203f16f6d785..12c9abbcbaece 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -311,8 +311,8 @@ STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 57f69433a1a97..a8b8089ca96cb 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -36,6 +36,7 @@ #include "py/runtime.h" #include "extmod/modbluetooth.h" #include +#include #if MICROPY_PY_BLUETOOTH diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 1d557a6a84b5a..7a73b4ee92419 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -28,6 +28,7 @@ #include #include +#include #include "py/objlist.h" #include "py/runtime.h" diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 811258424a3bf..c5fbf12e42b9d 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -506,6 +506,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset); } // Fall thru to return uctypes struct object + MP_FALLTHROUGH } case PTR: { mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); @@ -627,7 +628,7 @@ STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) { return mp_obj_new_int((mp_int_t)(uintptr_t)p); } } - /* fallthru */ + MP_FALLTHROUGH default: return MP_OBJ_NULL; // op not supported diff --git a/extmod/moduselect.c b/extmod/moduselect.c index 80beb8e09b8aa..de704b28f9f55 100644 --- a/extmod/moduselect.c +++ b/extmod/moduselect.c @@ -29,6 +29,7 @@ #if MICROPY_PY_USELECT #include +#include #include "py/runtime.h" #include "py/obj.h" diff --git a/extmod/moduwebsocket.c b/extmod/moduwebsocket.c index 34b520f33706a..ee5493f76f8c4 100644 --- a/extmod/moduwebsocket.c +++ b/extmod/moduwebsocket.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "py/runtime.h" #include "py/stream.h" diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index a8430bafb3c8e..6173f809d61e4 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "py/runtime.h" #include "py/stream.h" diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c index 3f54b3993fd36..c4d12af87a32e 100644 --- a/extmod/re1.5/compilecode.c +++ b/extmod/re1.5/compilecode.c @@ -29,6 +29,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode) prog->len++; break; } + MP_FALLTHROUGH default: term = PC; EMIT(PC++, Char); diff --git a/extmod/re1.5/recursiveloop.c b/extmod/re1.5/recursiveloop.c index bb337decfbc95..f8cb92629200a 100644 --- a/extmod/re1.5/recursiveloop.c +++ b/extmod/re1.5/recursiveloop.c @@ -22,6 +22,7 @@ recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int n case Char: if(*sp != *pc++) return 0; + MP_FALLTHROUGH case Any: sp++; continue; diff --git a/extmod/vfs.c b/extmod/vfs.c index 3cb7af1b434f9..1be1c006b2426 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -26,6 +26,7 @@ #include #include +#include #include "py/runtime.h" #include "py/objstr.h" diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 95b7ad9944116..8f1af2f99218b 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -33,6 +33,7 @@ #endif #include +#include #include "py/runtime.h" #include "py/mperrno.h" #include "lib/oofatfs/ff.h" diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 537101d00f406..10d9ef2a08861 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -28,6 +28,7 @@ #if MICROPY_VFS && MICROPY_VFS_FAT #include +#include #include "py/runtime.h" #include "py/stream.h" diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c index 9cf3eb11083cf..dd78269a460ab 100644 --- a/extmod/vfs_lfs.c +++ b/extmod/vfs_lfs.c @@ -35,7 +35,7 @@ enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime }; static const mp_arg_t lfs_make_allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 2c8ca2de0cecc..cc8f059082c8e 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include #include diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index f80ee761b7bcf..971f2f81aa593 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -18,7 +18,7 @@ INC += -I$(TOP) # compiler settings CWARN = -Wall -Werror -CWARN += -Wpointer-arith -Wuninitialized +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith CFLAGS = $(INC) $(CWARN) -std=gnu99 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables diff --git a/ports/gd32vf103/Makefile b/ports/gd32vf103/Makefile new file mode 100644 index 0000000000000..2939bcb44001f --- /dev/null +++ b/ports/gd32vf103/Makefile @@ -0,0 +1,104 @@ +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 + +GIT_SUBMODULES = ports/gd32vf103/gd32vf103inator + +CROSS_COMPILE = riscv64-unknown-elf- +OBJDUMP = $(CROSS_COMPILE)objdump + +DFU_UTIL = dfu-util +DFU_DEVICE = 1d50:613e + +INC += -I. +INC += -I$(TOP) +INC += -I$(BUILD) +INC += -Igd32vf103inator/include +INC += -Igd32vf103inator/std + +ARCH = rv32imac +ABI = ilp32 +CODEMODEL = medlow + +BOOTLOADER = 4*1024 +FLASH_SIZE = 128*1024 +RAM_SIZE = 32*1024 + +CORECLOCK = 96000000 +HXTAL = 8000000 + +ARCHFLAGS = -march=$(ARCH) -mabi=$(ABI) -mcmodel=$(CODEMODEL) -fno-pie +WARNINGS = -Wall -Wextra -Wshadow -Wformat=2 -Wformat-truncation=2 -Wno-unused-parameter +DIMENSIONS = -DBOOTLOADER=$(BOOTLOADER) -DFLASH_SIZE=$(FLASH_SIZE) -DRAM_SIZE=$(RAM_SIZE) +CLOCKS = -DHXTAL=$(HXTAL) -DCORECLOCK=$(CORECLOCK) + +CFLAGS = $(COPT) -std=c99 $(ARCHFLAGS) $(WARNINGS) +CFLAGS += $(INC) $(DIMENSIONS) $(CLOCKS) -D_LIBC_LIMITS_H_ +CFLAGS += -ffreestanding #-ftls-model=local-exec +LDFLAGS = $(COPT) $(ARCHFLAGS) -static -nostdlib -Tgd32vf103inator/gd32vf103.ld +LDFLAGS += -Wl,-O1,--gc-sections,--relax,--build-id=none,-Map=$@.map,--cref + +CSUPEROPT = -Os # save some code space + +# Tune for Debugging or Optimization +ifeq ($(DEBUG), 1) +COPT = -Os -ggdb +else +COPT = -Os -flto -DNDEBUG +CFLAGS += -fno-common -ffunction-sections -fdata-sections +endif + + +LIBS = -lgcc + +SRC_C = \ + main.c \ + usbacm.c \ + mphalport.c \ + modutime.c \ + modmachine.c \ + pin.c \ + gd32vf103inator/lib/rcu.c \ + gd32vf103inator/lib/eclic.c \ + gd32vf103inator/lib/mtimer.c \ + gd32vf103inator/lib/gpio.c \ + lib/utils/printf.c \ + lib/utils/stdout_helpers.c \ + lib/utils/pyexec.c \ + lib/mp-readline/readline.c \ + lib/libc/string0.c + +# List of sources for qstr extraction +SRC_QSTR += modutime.c pin.c modmachine.c + +OBJ = $(BUILD)/gd32vf103inator/start.o \ + $(PY_O) \ + $(patsubst %.c,$(BUILD)/%.o,$(SRC_C)) + +.PHONY: all dump dfu romdfu + +all: $(BUILD)/firmware.bin + +$(BUILD)/firmware.elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf + $(ECHO) "OBJCOPY $@" + $(Q)$(OBJCOPY) -O binary $^ $@ + +dump: $(BUILD)/firmware.elf + $(OBJDUMP) -x -d -j .init -j .text -j .data $< | $(PAGER) + +dfu: $(BUILD)/firmware.bin + $(Q)$(DFU_UTIL) -d $(DFU_DEVICE) -D $< -R + +romdfu: $(BUILD)/firmware.bin + $(Q)$(DFU_UTIL) -d 28e9:0189 -a 0 --dfuse-address 0x08000000:leave -D $< + +include $(TOP)/py/mkrules.mk diff --git a/ports/gd32vf103/README.md b/ports/gd32vf103/README.md new file mode 100644 index 0000000000000..356fc4b3effc1 --- /dev/null +++ b/ports/gd32vf103/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/gd32vf103/gd32vf103inator b/ports/gd32vf103/gd32vf103inator new file mode 160000 index 0000000000000..e6b1384d0c160 --- /dev/null +++ b/ports/gd32vf103/gd32vf103inator @@ -0,0 +1 @@ +Subproject commit e6b1384d0c1607ab6b902f15e55745ac9ebd8547 diff --git a/ports/gd32vf103/main.c b/ports/gd32vf103/main.c new file mode 100644 index 0000000000000..9349c71caff1c --- /dev/null +++ b/ports/gd32vf103/main.c @@ -0,0 +1,170 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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 + +#include "py/compile.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/stackctrl.h" +#include "py/mphal.h" +#include "lib/mp-readline/readline.h" +#include "lib/utils/pyexec.h" + +#include "lib/rcu.h" +#include "lib/eclic.h" +#include "lib/gpio.h" + +#include "usbacm.h" + +static void **stack_top; +static char heap[16384]; + +#ifdef __interrupt +void trap_entry(void) { + printf("TRAP!\n"); + while (1) { + /* forever */ + } +} +#endif + +int main(void) { + rcu_sysclk_init(); + eclic_init(); + eclic_global_interrupt_enable(); + + #if 0 + /* turn on power to GPIOA */ + RCU->APB2EN |= RCU_APB2EN_PAEN; + + gpio_pin_set(GPIO_PA1); + gpio_pin_config(GPIO_PA1, GPIO_MODE_PP_50MHZ); + gpio_pin_set(GPIO_PA2); + gpio_pin_config(GPIO_PA2, GPIO_MODE_PP_50MHZ); + #endif + + usbacm_init(); + + (void)mp_hal_stdin_rx_chr(); + + /* save current stack pointer to stack_top */ + __asm("sw sp, %0\n" : "=m" (stack_top)); + +soft_reset: + mp_stack_set_top(stack_top); + mp_stack_set_limit(1024); + + gc_init(heap, heap + sizeof(heap)); + + mp_init(); + /* sys.path = [''] */ + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0); + mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); + /* sys.argv = [] */ + mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0); + + readline_init0(); + + while (1) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl()) { + break; + } + } else { + if (pyexec_friendly_repl()) { + break; + } + } + } + gc_sweep_all(); + printf("soft reboot\n"); + goto soft_reset; +} + +void gc_collect(void) { + void *sregs[12]; + void **sp; + + gc_collect_start(); + + /* push callee-save registers to + * stack before sweeping it */ + __asm( + "sw s0, 0+%1 \n" + "sw s1, 4+%1 \n" + "sw s2, 8+%1 \n" + "sw s3, 12+%1 \n" + "sw s4, 16+%1 \n" + "sw s5, 20+%1 \n" + "sw s6, 24+%1 \n" + "sw s7, 28+%1 \n" + "sw s8, 32+%1 \n" + "sw s9, 36+%1 \n" + "sw s10, 40+%1 \n" + "sw s11, 44+%1 \n" + "mv %0, sp \n" + : "=r" (sp), "=o" (sregs) + ); + + gc_collect_root(sp, stack_top - sp); + gc_collect_end(); +} + +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) { + /* forever */ + } +} + +void NORETURN __fatal_error(const char *msg) { + printf("%s\n", msg); + while (1) { + /* forever */ + } +} + +#ifndef NDEBUG +void __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/gd32vf103/modmachine.c b/ports/gd32vf103/modmachine.c new file mode 100644 index 0000000000000..4939b4608c440 --- /dev/null +++ b/ports/gd32vf103/modmachine.c @@ -0,0 +1,108 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019,2020 Emil Renner Berthing + * + * 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 "riscv/bits.h" +#include "gd32vf103/info.h" +#include "gd32vf103/dbg.h" +#include "lib/eclic.h" + +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "lib/utils/pyexec.h" + +#include "pin.h" + +STATIC mp_obj_t machine_freq(void) { + return MP_OBJ_NEW_SMALL_INT(CORECLOCK); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq); + +STATIC mp_obj_t machine_unique_id(void) { + byte *id = (byte *)INFO->ID; + return mp_obj_new_bytes(id, 12); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); + +STATIC mp_obj_t machine_reset(void) { + DBG->KEY = DBG_KEY_UNLOCK; + DBG->CMD = DBG_CMD_RESET; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + mp_raise_type(&mp_type_SystemExit); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + +STATIC mp_obj_t machine_idle(void) { + wait_for_interrupt(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle); + +STATIC mp_obj_t machine_disable_irq(void) { + unsigned long mstatus = eclic_global_interrupt_disable_save(); + return mp_obj_new_bool(mstatus & CSR_MSTATUS_MIE); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq); + +STATIC mp_obj_t machine_enable_irq(uint n_args, const mp_obj_t *arg) { + if (n_args == 0 || mp_obj_is_true(arg[0])) { + eclic_global_interrupt_enable(); + } else { + eclic_global_interrupt_disable(); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_enable_irq_obj, 0, 1, machine_enable_irq); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) }, + { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) }, + + { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) }, + + { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) }, + { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&machine_module_globals, +}; + +/* vim: set ts=4 sw=4 et: */ diff --git a/ports/gd32vf103/modutime.c b/ports/gd32vf103/modutime.c new file mode 100644 index 0000000000000..8d6a4059446f6 --- /dev/null +++ b/ports/gd32vf103/modutime.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * 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 "extmod/utime_mphal.h" + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&time_module_globals, +}; diff --git a/ports/gd32vf103/mpconfigport.h b/ports/gd32vf103/mpconfigport.h new file mode 100644 index 0000000000000..896b4ca9c0dfb --- /dev/null +++ b/ports/gd32vf103/mpconfigport.h @@ -0,0 +1,90 @@ +#include + +#define MICROPY_ENABLE_COMPILER (1) + +#define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_USE_INTERNAL_PRINTF (1) + +#ifdef __GNUC__ +#define MICROPY_OPT_COMPUTED_GOTO (1) +#else +#define MICROPY_OPT_COMPUTED_GOTO (0) +#endif +#define MICROPY_OPT_MPZ_BITWISE (1) + +#define MICROPY_ALLOC_PATH_MAX (256) +#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16) +#define MICRAPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) + +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) + +#define MICROPY_ENABLE_GC (1) +#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t +#define MICROPY_GC_ALLOC_THRESHOLD (0) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) + +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_BUILTINS_HELP (1) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +#define MICROPY_PY_UTIME_TICKS_PERIOD (1U << 30) + +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) + +#if 0 // for tests +#include +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1) +#define MICROPY_PY_BUILTINS_MEMORYVIEW (1) +#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) +#define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MP_SSIZE_MAX INT_MAX +#undef MICROPY_ERROR_REPORTING +#endif + +// type definitions for the specific machine + +#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)(p)) + +#define INT_FMT "%d" +#define UINT_FMT "%u" +typedef int mp_int_t; // must be pointer size +typedef unsigned int 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) }, + +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_utime; + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \ + { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, + +// We need to provide a declaration/definition of alloca() +#include + +#define MICROPY_HW_BOARD_NAME "LonganNano" +#define MICROPY_HW_MCU_NAME "gd32vf103" + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[8]; diff --git a/ports/gd32vf103/mphalport.c b/ports/gd32vf103/mphalport.c new file mode 100644 index 0000000000000..e8bfe3c0aafe7 --- /dev/null +++ b/ports/gd32vf103/mphalport.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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/mphal.h" + +#include "lib/mtimer.h" + +/* sanity check */ +#if MICROPY_PY_UTIME_TICKS_PERIOD != (1U << 30) +#error This implementation is only correct for MICROPY_PY_UTIME_TICKS_PERIOD == 2^30 +#endif + +void mp_hal_delay_ms(mp_uint_t ms) { + mtimer_delay(ms * (MTIMER_FREQ / 1000)); +} + +void mp_hal_delay_us(mp_uint_t us) { + mtimer_delay(us * (MTIMER_FREQ / 1000000)); +} + +mp_uint_t mp_hal_ticks_ms(void) { + uint64_t mtime = mtimer_mtime(); + + /* return (mtime / (CORECLOCK/4000)) % 2^30 + * using a / b = a * (2^34 / b) / 2^34 + */ + mtime *= ((4000ULL << 34) - 1) / CORECLOCK + 1; + return mtime >> 34; +} + +mp_uint_t mp_hal_ticks_us(void) { + uint64_t mtime = mtimer_mtime(); + + /* return (mtime / (CORECLOCK/4000000)) % 2^30 + * using a / b = a * (2^34 / b) / 2^34 + */ + mtime *= ((4000000ULL << 34) - 1) / CORECLOCK + 1; + return mtime >> 34; +} + +mp_uint_t mp_hal_ticks_cpu(void) { + return MTIMER->mtime_lo % MICROPY_PY_UTIME_TICKS_PERIOD; +} + +/* vim: set ts=4 sw=4 et: */ diff --git a/ports/gd32vf103/mphalport.h b/ports/gd32vf103/mphalport.h new file mode 100644 index 0000000000000..5b48fea72c2a8 --- /dev/null +++ b/ports/gd32vf103/mphalport.h @@ -0,0 +1,2 @@ +static inline void mp_hal_set_interrupt_char(char c) { +} diff --git a/ports/gd32vf103/pin.c b/ports/gd32vf103/pin.c new file mode 100644 index 0000000000000..41e9fdb363173 --- /dev/null +++ b/ports/gd32vf103/pin.c @@ -0,0 +1,312 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Emil Renner Berthing + * + * 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/runtime.h" +#include "extmod/virtpin.h" + +#include "pin.h" + +const pin_obj_t pin_base[80] = { + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, + {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, {{ &pin_type }}, +}; + +static int pin_parse(const char *str) { + int ret; + + if (str[0] < 'A' || str[0] > 'E') { + return -1; + } + + ret = (str[0] - 'A') << 4; + + if (str[1] == '1' && str[2] >= '0' && str[2] <= '5') { + if (str[3] != '\0') { + return -1; + } + ret |= str[2] - '0' + 10; + } else if (str[1] >= '0' && str[1] <= '9') { + if (str[2] != '\0') { + return -1; + } + ret |= str[1] - '0'; + } else { + return -1; + } + + return ret; +} + +static const pin_obj_t *pin_find(mp_obj_t user_obj) { + // If pin is SMALL_INT + if (mp_obj_is_small_int(user_obj)) { + uint value = MP_OBJ_SMALL_INT_VALUE(user_obj); + + if (value >= MP_ARRAY_SIZE(pin_base)) { + mp_raise_msg_varg(&mp_type_ValueError, + MP_ERROR_TEXT("Pin(%u) doesn't exist"), value); + } + return &pin_base[value]; + } + + // If a pin was provided, then use it + if (mp_obj_is_type(user_obj, &pin_type)) { + return MP_OBJ_TO_PTR(user_obj); + } + + const char *str = mp_obj_str_get_str(user_obj); + int pin = pin_parse(str); + + if (pin > 0) { + return &pin_base[pin]; + } + + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Pin('%s') doesn't exist"), str); +} + +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_value, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get pin + gpio_pin_t pin = pin_from_obj(self); + + // get mode + uint mode = args[0].u_int; + if (mode > 0xfU || mode == 0xcU) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("invalid pin mode: %u"), mode); + } + + // enable the peripheral clock for the port of this pin + gpio_pin_clock_enable(pin); + + // if given, set the pin value before initialising to prevent glitches + if (args[1].u_obj != MP_OBJ_NULL) { + if (mp_obj_is_true(args[1].u_obj)) { + gpio_pin_set(pin); + } else { + gpio_pin_clear(pin); + } + } + + // configure the GPIO as requested + gpio_pin_config(pin, mode); + + return mp_const_none; +} + +/// \classmethod \constructor(id, ...) +/// Create a new Pin object associated with the id. If additional arguments are given, +/// they are used to initialise the pin. See `init`. +mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // Run an argument through the mapper and return the result. + const pin_obj_t *pin = pin_find(args[0]); + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return MP_OBJ_FROM_PTR(pin); +} + +/// \method __str__() +/// Return a string describing the pin object. +STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + static const qstr pin_mode_name[16] = { + MP_QSTR_IN_ANALOG, + MP_QSTR_PP_10MHZ, + MP_QSTR_PP_2MHZ, + MP_QSTR_PP_50MHZ, + MP_QSTR_IN_FLOAT, + MP_QSTR_OD_10MHZ, + MP_QSTR_OD_2MHZ, + MP_QSTR_OD_50MHZ, + MP_QSTR_IN_PULL, + MP_QSTR_AF_PP_10MHZ, + MP_QSTR_AF_PP_2MHZ, + MP_QSTR_AF_PP_50MHZ, + 0, // reserved + MP_QSTR_AF_OD_10MHZ, + MP_QSTR_AF_OD_2MHZ, + MP_QSTR_AF_OD_50MHZ, + }; + const pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_pin_t pin = pin_from_obj(self); + + mp_printf(print, "Pin('%c%u', mode=Pin.%q, value=%u)", + 'A' + gpio_pin_port_nr(pin), gpio_pin_nr(pin), + pin_mode_name[gpio_pin_mode(pin)], + !!gpio_pin_get(pin)); +} + +// fast method for getting/setting pin value +STATIC mp_obj_t pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + const pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_pin_t pin = pin_from_obj(self); + + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(!!gpio_pin_high(pin)); + } else { + // set pin + if (mp_obj_is_true(args[0])) { + gpio_pin_set(pin); + } else { + gpio_pin_clear(pin); + } + return mp_const_none; + } +} + +STATIC mp_obj_t pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); + +/// \method value([value]) +/// Get or set the digital logic level of the pin: +/// +/// - With no argument, return 0 or 1 depending on the logic level of the pin. +/// - With `value` given, set the logic level of the pin. `value` can be +/// anything that converts to a boolean. If it converts to `True`, the pin +/// is set high, otherwise it is set low. +STATIC mp_obj_t pin_value(size_t n_args, const mp_obj_t *args) { + return pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); + +STATIC mp_obj_t pin_off(mp_obj_t self_in) { + const pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_pin_clear(pin_from_obj(self)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_off_obj, pin_off); + +STATIC mp_obj_t pin_on(mp_obj_t self_in) { + const pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_pin_set(pin_from_obj(self)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_on_obj, pin_on); + +STATIC const mp_rom_map_elem_t pin_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pin_on_obj) }, + + // Legacy names as used by pyb.Pin + { MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&pin_off_obj) }, + { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&pin_on_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_IN_ANALOG), MP_ROM_INT(GPIO_MODE_IN_ANALOG) }, + { MP_ROM_QSTR(MP_QSTR_PP_10MHZ), MP_ROM_INT(GPIO_MODE_PP_10MHZ) }, + { MP_ROM_QSTR(MP_QSTR_PP_2MHZ), MP_ROM_INT(GPIO_MODE_PP_2MHZ) }, + { MP_ROM_QSTR(MP_QSTR_PP_50MHZ), MP_ROM_INT(GPIO_MODE_PP_50MHZ) }, + { MP_ROM_QSTR(MP_QSTR_IN_FLOAT), MP_ROM_INT(GPIO_MODE_IN_FLOAT) }, + { MP_ROM_QSTR(MP_QSTR_OD_10MHZ), MP_ROM_INT(GPIO_MODE_OD_10MHZ) }, + { MP_ROM_QSTR(MP_QSTR_OD_2MHZ), MP_ROM_INT(GPIO_MODE_OD_2MHZ) }, + { MP_ROM_QSTR(MP_QSTR_OD_50MHZ), MP_ROM_INT(GPIO_MODE_OD_50MHZ) }, + { MP_ROM_QSTR(MP_QSTR_IN_PULL), MP_ROM_INT(GPIO_MODE_IN_PULL) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP_10MHZ), MP_ROM_INT(GPIO_MODE_AF_PP_10MHZ) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP_2MHZ), MP_ROM_INT(GPIO_MODE_AF_PP_2MHZ) }, + { MP_ROM_QSTR(MP_QSTR_AF_PP_50MHZ), MP_ROM_INT(GPIO_MODE_AF_PP_50MHZ) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD_10MHZ), MP_ROM_INT(GPIO_MODE_AF_OD_10MHZ) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD_2MHZ), MP_ROM_INT(GPIO_MODE_AF_OD_2MHZ) }, + { MP_ROM_QSTR(MP_QSTR_AF_OD_50MHZ), MP_ROM_INT(GPIO_MODE_AF_OD_50MHZ) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); + +STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + const pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + gpio_pin_t pin = pin_from_obj(self); + + switch (request) { + case MP_PIN_READ: + return !!gpio_pin_high(pin); + case MP_PIN_WRITE: + if (arg) { + gpio_pin_set(pin); + } else { + gpio_pin_clear(pin); + } + return 0; + } + return -1; +} + +STATIC const mp_pin_p_t pin_pin_p = { + .ioctl = pin_ioctl, +}; + +const mp_obj_type_t pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = pin_print, + .make_new = mp_pin_make_new, + .call = pin_call, + .protocol = &pin_pin_p, + .locals_dict = (mp_obj_dict_t *)&pin_locals_dict, +}; + +/* vim: set ts=4 sw=4 et: */ diff --git a/ports/gd32vf103/pin.h b/ports/gd32vf103/pin.h new file mode 100644 index 0000000000000..60547ee8fe7d5 --- /dev/null +++ b/ports/gd32vf103/pin.h @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Emil Renner Berthing + * + * 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_GD32VF103_PIN_H +#define MICROPY_GD32VF103_PIN_H + +#include "py/obj.h" + +#include "lib/gpio.h" + +extern const mp_obj_type_t pin_type; + +typedef struct { + mp_obj_base_t base; +} pin_obj_t; + +extern const pin_obj_t pin_base[80]; + +static inline gpio_pin_t pin_from_obj(const pin_obj_t *obj) { + ptrdiff_t v = obj - pin_base; + return GPIO_PIN(v >> 4, v & 0xf); +} + +#endif // MICROPY_GD32VF103_PIN_H diff --git a/ports/gd32vf103/qstrdefsport.h b/ports/gd32vf103/qstrdefsport.h new file mode 100644 index 0000000000000..3ba897069bf73 --- /dev/null +++ b/ports/gd32vf103/qstrdefsport.h @@ -0,0 +1 @@ +// qstrs specific to this port diff --git a/ports/gd32vf103/uart0.c b/ports/gd32vf103/uart0.c new file mode 100644 index 0000000000000..0cf88000f0f3f --- /dev/null +++ b/ports/gd32vf103/uart0.c @@ -0,0 +1,79 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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 + +#include "py/mpconfig.h" + +#include "gd32vf103/rcu.h" +#include "gd32vf103/usart.h" + +#include "lib/eclic.h" +#include "lib/gpio.h" + +#include "uart0.h" + +int mp_hal_stdin_rx_chr(void) { + while (!(USART0->STAT & USART_STAT_RBNE)) { + /* wait */ + } + + return USART0->DATA; +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + for (; len > 0; len--, str++) { + while (!(USART0->STAT & USART_STAT_TBE)) { + /* wait */ + } + USART0->DATA = *str; + } +} + +void uart0_init(uint32_t pclk, uint32_t target) { + /* enable GPIO clock */ + RCU->APB2EN |= RCU_APB2EN_PAEN; + /* enable USART clock */ + RCU->APB2EN |= RCU_APB2EN_USART0EN; + + gpio_pin_config(GPIO_PA9, GPIO_MODE_AF_PP_50MHZ); + gpio_pin_config(GPIO_PA10, GPIO_MODE_IN_FLOAT); + + /* reset usart0 */ + RCU->APB2RST |= RCU_APB2RST_USART0RST; + RCU->APB2RST &= ~RCU_APB2RST_USART0RST; + + /* set baudrate */ + USART0->BAUD = (2 * pclk + target) / (2 * target); + /* set 1 stop bit */ + USART0->CTL1 = USART_CTL1_STB_1; + /* enable rx and tx */ + USART0->CTL0 = USART_CTL0_TEN | USART_CTL0_REN; + /* enable usart0 */ + USART0->CTL0 |= USART_CTL0_UEN; +} diff --git a/ports/gd32vf103/uart0.h b/ports/gd32vf103/uart0.h new file mode 100644 index 0000000000000..9fbe58c2e52c4 --- /dev/null +++ b/ports/gd32vf103/uart0.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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 UART0_H +#define UART0_H + +#include + +void uart0_init(uint32_t pclk, uint32_t target); + +#endif diff --git a/ports/gd32vf103/usbacm.c b/ports/gd32vf103/usbacm.c new file mode 100644 index 0000000000000..11cede3d25b86 --- /dev/null +++ b/ports/gd32vf103/usbacm.c @@ -0,0 +1,1296 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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 +#include + +#include "gd32vf103/rcu.h" +#include "gd32vf103/mtimer.h" +#include "gd32vf103/usbfs.h" + +#include "lib/eclic.h" + +#include "py/mpconfig.h" + +#include "usbacm.h" + +#if 1 +#define debug(...) +#else +#include "uart0.h" +#define debug(...) uart0_printf(__VA_ARGS__) +#endif + +#define CDC_INTERFACE 0 +#define CDC_ENDPOINT 2 +/* up to 64 bytes for full-speed interrupt eps */ +#define CDC_PACKETSIZE 8 + +#define ACM_INTERFACE 1 +#define ACM_ENDPOINT 1 +/* 8, 16, 32 or 64 bytes for full-speed bulk eps */ +#define ACM_PACKETSIZE 64 + +#define USBFS_FIFO_RXSIZE 512 +#define USBFS_FIFO_TX0SIZE 256 +#define USBFS_FIFO_TX1SIZE 256 +#define USBFS_FIFO_TX2SIZE 64 +#define USBFS_FIFO_TX3SIZE 0 + +#define USB_WORD(x) ((x) & 0xFF),((x) >> 8) +#define USB_TRIPLE(x) ((x) & 0xFF),(((x) >> 8) & 0xFF),((x) >> 16) +#define USB_QUAD(x) ((x) & 0xFF),(((x) >> 8) & 0xFF),(((x) >> 16) & 0xFF),((x) >> 24) + +struct usb_setup_packet { + union { + struct { + uint8_t bmRequestType; + uint8_t bRequest; + }; + uint16_t request; + }; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +struct usb_descriptor_device { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +}; + +struct usb_descriptor_device_qualifier { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +}; + +struct usb_descriptor_configuration { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; + uint8_t rest[]; +}; + +struct usb_descriptor_string { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wCodepoint[]; +}; + +struct usb_setup_handler { + uint16_t req; + uint8_t idx; + uint8_t len; + int (*fn)(const struct usb_setup_packet *p, const void **data); +}; + + +struct acm_line_coding { + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +}; + +static const struct usb_descriptor_device usbfs_descriptor_device = { + .bLength = 18, + .bDescriptorType = 0x01, /* Device */ + .bcdUSB = 0x0200, + .bDeviceClass = 0x00, /* 0x00 = per interface */ + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 64, + .idVendor = 0x1d50, /* OpenMoko vendor id */ + .idProduct = 0x613f, /* GeckoBoot target product id */ + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +static const struct usb_descriptor_configuration usbfs_descriptor_configuration1 = { + .bLength = 9, + .bDescriptorType = 0x02, /* Configuration */ + .wTotalLength = 9 + 8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 250, + .rest = { + /* Interface Association */ + /* .bLength */ 8, + /* .bDescriptorType */ 0x0B, /* Interface Association */ + /* .bFirstInterface */ CDC_INTERFACE, + /* .bInterfaceCount */ 2, + /* .bFunctionClass */ 0x02, /* 0x02 = CDC */ + /* .bFunctionSubClass */ 0x02, /* 0x02 = ACM */ + /* .bFunctionProtocol */ 0, + /* .iFunction */ 0, + /* Interface */ + /* .bLength */ 9, + /* .bDescriptorType */ 0x04, /* Interface */ + /* .bInterfaceNumber */ CDC_INTERFACE, + /* .bAlternateSetting */ 0, + /* .bNumEndpoints */ 1, + /* .bInterfaceClass */ 0x02, /* 0x02 = CDC */ + /* .bInterfaceSubClass */ 0x02, /* 0x02 = ACM */ + /* .bInterfaceProtocol */ 0x01, /* 0x00 = no protocol required, 0x01 = AT commands V.250 etc */ + /* .iInterface */ 0, + /* CDC Header */ + /* .bLength */ 5, + /* .bDescriptorType */ 0x24, /* CS_INTERFACE */ + /* .bDescriptorSubtype */ 0x00, /* Header */ + /* .bcdCDC */ USB_WORD(0x0120), + /* CDC Call Management */ + /* .bLength */ 5, + /* .bDescriptorType */ 0x24, /* CS_INTERFACE */ + /* .bDescriptorSubtype */ 0x01, /* Call Management */ + /* .bmCapabilities */ 0x03, /* Handles call management over data line */ + /* .bDataInterface */ ACM_INTERFACE, + /* CDC ACM */ + /* .bLength */ 4, + /* .bDescriptorType */ 0x24, /* CS_INTERFACE */ + /* .bDescriptorSubtype */ 0x02, /* ACM */ + /* .bmCapabilities */ 0x02, /* 0x02 = supports line state and coding */ + /* CDC Union */ + /* .bLength */ 5, + /* .bDescriptorType */ 0x24, /* CS_INTERFACE */ + /* .bDescriptorSubtype */ 0x06, /* Union */ + /* .bControlInterface */ CDC_INTERFACE, + /* .bSubordinateInterface0 */ ACM_INTERFACE, + /* Endpoint */ + /* .bLength */ 7, + /* .bDescriptorType */ 0x05, /* Endpoint */ + /* .bEndpointAddress */ 0x80 | CDC_ENDPOINT, /* in */ + /* .bmAttributes */ 0x03, /* interrupt */ + /* .wMaxPacketSize */ USB_WORD(CDC_PACKETSIZE), + /* .bInterval */ 255, /* poll every 255ms */ + /* Interface */ + /* .bLength */ 9, + /* .bDescriptorType */ 0x04, /* Interface */ + /* .bInterfaceNumber */ ACM_INTERFACE, + /* .bAlternateSetting */ 0, + /* .bNumEndpoints */ 2, + /* .bInterfaceClass */ 0x0A, /* 0x0A = CDC Data */ + /* .bInterfaceSubClass */ 0x00, + /* .bInterfaceProtocol */ 0x00, + /* .iInterface */ 0, + /* Endpoint */ + /* .bLength */ 7, + /* .bDescriptorType */ 0x05, /* Endpoint */ + /* .bEndpointAddress */ 0x80 | ACM_ENDPOINT, /* in */ + /* .bmAttributes */ 0x02, /* bulk */ + /* .wMaxPacketSize */ USB_WORD(ACM_PACKETSIZE), + /* .bInterval */ 0, /* unused */ + /* Endpoint */ + /* .bLength */ 7, + /* .bDescriptorType */ 0x05, /* Endpoint */ + /* .bEndpointAddress */ ACM_ENDPOINT, /* out */ + /* .bmAttributes */ 0x02, /* bulk */ + /* .wMaxPacketSize */ USB_WORD(ACM_PACKETSIZE), + /* .bInterval */ 0, /* unused */ + } +}; + +static const struct usb_descriptor_string usbfs_descriptor_string0 = { + .bLength = 4, + .bDescriptorType = 0x03, /* String */ + .wCodepoint = { + 0x0409, /* English (US) */ + }, +}; + +static const struct usb_descriptor_string usbfs_descriptor_manufacturer = { + .bLength = 16, + .bDescriptorType = 0x03, /* String */ + .wCodepoint = { + 'L','a','b','i','t','a','t', + }, +}; + +static const struct usb_descriptor_string usbfs_descriptor_product = { + .bLength = 20, + .bDescriptorType = 0x03, /* String */ + .wCodepoint = { + 'G','D','3','2','V','F','1','0','3', + }, +}; + +/* must be at least 12 characters long and consist of only '0'-'9','A'-'B' + * at least according to the mass-storage bulk-only document */ +static const struct usb_descriptor_string usbfs_descriptor_serial = { + .bLength = 26, + .bDescriptorType = 0x03, /* String */ + .wCodepoint = { + '0','0','0','0','0','0','0','0','0','0','0','1', + }, +}; + +static const struct usb_descriptor_string *const usbfs_descriptor_string[] = { + &usbfs_descriptor_string0, + &usbfs_descriptor_manufacturer, + &usbfs_descriptor_product, + &usbfs_descriptor_serial, +}; + +static struct { + uint32_t *ep0out; + const unsigned char *ep0in; + uint32_t bytes; + uint32_t packetsize; +} usbfs_state; + +static struct { + union { + struct usb_setup_packet setup; + uint32_t v[2]; + }; + uint8_t data[64]; +} usbfs_outbuf; + +static uint16_t usbfs_status; + +static struct acm_line_coding acm_line_coding; + +static volatile bool acm_inidle; +static volatile uint16_t acm_inhead; +static volatile uint16_t acm_intail; +static uint8_t acm_inbuf[1024]; + +static volatile uint8_t acm_outbytes; +static union { + uint32_t word[64 / 4]; + uint8_t byte[64]; +} acm_outbuf; + +int mp_hal_stdin_rx_chr(void) { + static uint8_t head; + unsigned int bytes; + int ret; + + #if 0 + while (1) { + eclic_global_interrupt_disable(); + bytes = acm_outbytes; + if (bytes > 0) { + break; + } + wait_for_interrupt(); + eclic_global_interrupt_enable(); + } + eclic_global_interrupt_enable(); + #else + do { + bytes = acm_outbytes; + } while (bytes == 0); + #endif + + ret = acm_outbuf.byte[head]; + acm_outbytes = --bytes; + if (bytes == 0) { + head = 0; + USBFS->DOEP[ACM_ENDPOINT].LEN = USBFS_DOEPLEN_PCNT(1) | ACM_PACKETSIZE; + USBFS->DOEP[ACM_ENDPOINT].CTL |= USBFS_DOEPCTL_EPEN | USBFS_DOEPCTL_CNAK; + } else { + head++; + } + + return ret; +} + +static void +acm_send(void) { + unsigned int head = acm_inhead; + unsigned int tail = acm_intail; + unsigned int len; + uint32_t dieplen; + + if (head == tail) { + acm_inidle = true; + return; + } + + len = (tail - head) % ARRAY_SIZE(acm_inbuf); + debug("tfstat%x=%lu, len=%u\n", ACM_ENDPOINT, + USBFS->DIEP[ACM_ENDPOINT].TFSTAT, + len); + if (len >= 4 * ACM_PACKETSIZE) { + len = 4 * ACM_PACKETSIZE; + dieplen = USBFS_DIEPLEN_PCNT(4U); + } else if (len >= 3 * ACM_PACKETSIZE) { + len = 3 * ACM_PACKETSIZE; + dieplen = USBFS_DIEPLEN_PCNT(3U); + } else if (len >= 2 * ACM_PACKETSIZE) { + len = 2 * ACM_PACKETSIZE; + dieplen = USBFS_DIEPLEN_PCNT(2U); + } else { + if (len > ACM_PACKETSIZE) { + len = ACM_PACKETSIZE; + } + dieplen = USBFS_DIEPLEN_PCNT(1U); + } + dieplen |= len; + + tail = (head + len) % ARRAY_SIZE(acm_inbuf); + acm_inhead = tail; + + USBFS->DIEP[ACM_ENDPOINT].LEN = dieplen; + USBFS->DIEP[ACM_ENDPOINT].CTL |= USBFS_DIEPCTL_EPEN | USBFS_DIEPCTL_CNAK; + do { + uint32_t v = acm_inbuf[head++]; + + head %= ARRAY_SIZE(acm_inbuf); + if (head != tail) { + v |= ((uint32_t)acm_inbuf[head++]) << 8; + head %= ARRAY_SIZE(acm_inbuf); + } + if (head != tail) { + v |= ((uint32_t)acm_inbuf[head++]) << 16; + head %= ARRAY_SIZE(acm_inbuf); + } + if (head != tail) { + v |= ((uint32_t)acm_inbuf[head++]) << 24; + head %= ARRAY_SIZE(acm_inbuf); + } + USBFS->DFIFO[ACM_ENDPOINT][0] = v; + } while (head != tail); +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + unsigned int tail = acm_intail; + + for (; len > 0; len--, str++) { + acm_inbuf[tail++] = *str; + tail %= ARRAY_SIZE(acm_inbuf); + while (tail == acm_inhead) { + /* wait */ + } + } + + acm_intail = tail; + if (acm_inidle) { + acm_inidle = false; + acm_send(); + } +} + +static void +usbfs_udelay(unsigned int us) { + uint32_t zero = MTIMER->mtime_lo; + uint32_t end = us * (CORECLOCK / 4000000) + 1; + uint32_t now; + + do { + now = MTIMER->mtime_lo - zero; + } while (now < end); +} + +static void +usbfs_ep0in_transfer(void) { + uint32_t len = usbfs_state.bytes; + const unsigned char *p = usbfs_state.ep0in; + const unsigned char *end; + + if (len > usbfs_state.packetsize) { + len = usbfs_state.packetsize; + } + + end = p + len; + + debug("tfstat%x=%lu (0x%03x)\n", 0, + USBFS->DIEP[0].TFSTAT, + (uintptr_t)&USBFS->DIEP[0].TFSTAT - (uintptr_t)USBFS); + + USBFS->DIEP[0].LEN = USBFS_DIEPLEN_PCNT(1U) | len; + USBFS->DIEP[0].CTL |= USBFS_DIEPCTL_EPEN | USBFS_DIEPCTL_CNAK; + while (p < end) { + uint32_t v = *p++; + if (p < end) { + v |= (*p++) << 8; + } + if (p < end) { + v |= (*p++) << 16; + } + if (p < end) { + v |= (*p++) << 24; + } + USBFS->DFIFO[0][0] = v; + } +} + +#if 1 +static void +usbfs_ep0in_transfer_empty(void) { + USBFS->DIEP[0].LEN = USBFS_DIEPLEN_PCNT(1U); + USBFS->DIEP[0].CTL |= USBFS_DIEPCTL_EPEN | USBFS_DIEPCTL_CNAK; +} +#else +static inline void +usbfs_ep0in_transfer_empty(void) { + usbfs_ep0in_transfer(); +} +#endif + +static inline void +usbfs_ep0in_stall(void) { + USBFS->DIEP[0].CTL |= USBFS_DIEPCTL_STALL; +} + +static void +usbfs_ep0out_prepare_setup(void) { + USBFS->DOEP[0].LEN = + USBFS_DOEPLEN_STPCNT(3U) | + USBFS_DOEPLEN_PCNT(0U) | + USBFS_DOEPLEN_TLEN(0U); + USBFS->DOEP[0].CTL |= USBFS_DOEPCTL_EPEN | USBFS_DOEPCTL_STALL; +} + +static void +usbfs_ep0out_prepare_out(void) { + USBFS->DOEP[0].LEN = + USBFS_DOEPLEN_STPCNT(3U) | + USBFS_DOEPLEN_PCNT(1U) | + USBFS_DOEPLEN_TLEN(usbfs_state.packetsize); + USBFS->DOEP[0].CTL |= USBFS_DOEPCTL_EPEN | USBFS_DOEPCTL_CNAK; +} + +static void +usbfs_suspend(void) { + /* + usbfs_phy_stop(); + usbfs_flags_enable(USBFS_GINTMSK_WUIM + | USBFS_GINTMSK_USBRST); + */ +} + +static void +usbfs_wakeup(void) { + /* + usbfs_phy_start(); + usbfs_flags_enable(USB_OTG_GINTMSK_ENUMDNEM + | USB_OTG_GINTMSK_USBRST + | USB_OTG_GINTMSK_USBSUSPM + | USB_OTG_GINTMSK_OEPINT + | USB_OTG_GINTMSK_IEPINT); + */ +} + +static void +usbfs_txfifos_flush(void) { + /* flush all tx fifos */ + USBFS->GRSTCTL |= USBFS_GRSTCTL_TXFNUM(0x10U) | USBFS_GRSTCTL_TXFF; + while ((USBFS->GRSTCTL & USBFS_GRSTCTL_TXFF)) { + /* wait */ + } + /* wait 3 more phy clocks */ + usbfs_udelay(3); +} + +static void +usbfs_ep_reset(void) { + unsigned int i; + + USBFS->DIEP[0].CTL = + USBFS_DIEPCTL_STALL | + USBFS_DIEPCTL_EPTYPE_CONTROL | + USBFS_DIEP0CTL_MPL_64B; + USBFS->DIEP[0].INTF = + USBFS_DIEPINTF_IEPNE | + USBFS_DIEPINTF_EPTXFUD | + USBFS_DIEPINTF_CITO | + USBFS_DIEPINTF_EPDIS | + USBFS_DIEPINTF_TF; + for (i = 1; i < 4; i++) { + /* + if (USBFS->DIEP[i].CTL & USBFS_DIEPCTL_EPEN) + USBFS->DIEP[i].CTL = USBFS_DIEPCTL_EPD | USBFS_DIEPCTL_SNAK; + else + */ + USBFS->DIEP[i].CTL = USBFS_DIEPCTL_SNAK; + USBFS->DIEP[i].INTF = + USBFS_DIEPINTF_IEPNE | + USBFS_DIEPINTF_EPTXFUD | + USBFS_DIEPINTF_CITO | + USBFS_DIEPINTF_EPDIS | + USBFS_DIEPINTF_TF; + USBFS->DIEP[i].LEN = 0; + } + + USBFS->DOEP[0].CTL = + USBFS_DOEPCTL_STALL | + USBFS_DOEPCTL_EPTYPE_CONTROL | + USBFS_DOEP0CTL_MPL_64B; + USBFS->DOEP[0].INTF = + USBFS_DOEPINTF_BTBSTP | + USBFS_DOEPINTF_EPRXFOVR | + USBFS_DOEPINTF_STPF | + USBFS_DOEPINTF_EPDIS | + USBFS_DOEPINTF_TF; + for (i = 1; i < 4; i++) { + /* + if (USBFS->DOEP[i].CTL & USBFS_DOEPCTL_EPEN) + USBFS->DOEP[i].CTL = USBFS_DOEPCTL_EPD | USBFS_DOEPCTL_SNAK; + else + */ + USBFS->DOEP[i].CTL = USBFS_DOEPCTL_SNAK; + USBFS->DOEP[i].INTF = + USBFS_DOEPINTF_BTBSTP | + USBFS_DOEPINTF_EPRXFOVR | + USBFS_DOEPINTF_STPF | + USBFS_DOEPINTF_EPDIS | + USBFS_DOEPINTF_TF; + USBFS->DOEP[i].LEN = 0; + } +} + +static void +usbfs_reset(void) { + /* clear the remote wakeup signaling */ + USBFS->DCTL &= ~USBFS_DCTL_RWKUP; + + /* flush all tx fifos */ + usbfs_txfifos_flush(); + + /* reset endpoint registers */ + usbfs_ep_reset(); + + /* reset address */ + USBFS->DCFG &= ~USBFS_DCFG_DAR_Msk; + + /* enable interrupts for endpoint 0 only */ + USBFS->DAEPINTEN = + USBFS_DAEPINTEN_OEPIE(1U) | + USBFS_DAEPINTEN_IEPIE(1U); + USBFS->DOEPINTEN = + USBFS_DOEPINTEN_STPFEN | + /* USBFS_DOEPINTEN_EPDISEN | */ + USBFS_DOEPINTEN_TFEN; + USBFS->DIEPINTEN = + /* USBFS_DIEPINTEN_CITOEN | */ + /* USBFS_DIEPINTEN_EPDISEN | */ + USBFS_DIEPINTEN_TFEN; + + /* reset internal state */ + usbfs_state.bytes = 0; + usbfs_state.packetsize = 64; +} + +static void +usbfs_enumdone(void) { + USBFS->DCTL |= USBFS_DCTL_CGINAK; + + if ((USBFS->DSTAT & USBFS_DSTAT_ES_Msk) == USBFS_DSTAT_ES_FULL) { + /* we already set 64 byte packages at reset */ + debug("full speed.. "); + } else { + /* use 8 byte packages */ + USBFS->DIEP[0].CTL |= USBFS_DIEP0CTL_MPL_8B; + USBFS->DOEP[0].CTL |= USBFS_DOEP0CTL_MPL_8B; + usbfs_state.packetsize = 8; + debug("low speed.. "); + } + + /* prepare to receive setup package */ + usbfs_ep0out_prepare_setup(); +} + +static int +usbfs_handle_get_status_device(const struct usb_setup_packet *p, const void **data) { + debug("GET_STATUS: device\n"); + *data = &usbfs_status; + return 2; +} + +static int +usbfs_handle_set_address(const struct usb_setup_packet *p, const void **data) { + debug("SET_ADDRESS: wValue = %hu\n", p->wValue); + USBFS->DCFG = (USBFS->DCFG & ~USBFS_DCFG_DAR_Msk) | + USBFS_DCFG_DAR((uint32_t)p->wValue); + return 0; +} + +static int +usbfs_handle_get_descriptor_device(const void **data, uint8_t index) { + if (index != 0) { + debug("GET_DESCRIPTOR: type = 0x01, but index = 0x%02x\n", index); + return -1; + } + *data = &usbfs_descriptor_device; + return sizeof(usbfs_descriptor_device); +} + +static int +usbfs_handle_get_descriptor_configuration(const void **data, uint8_t index) { + if (index != 0) { + debug("GET_DESCRIPTOR: unknown configuration %hu\n", index); + return -1; + } + *data = &usbfs_descriptor_configuration1; + return usbfs_descriptor_configuration1.wTotalLength; +} + +static int +usbfs_handle_get_descriptor_string(const void **data, uint8_t index) { + const struct usb_descriptor_string *desc; + + if (index >= ARRAY_SIZE(usbfs_descriptor_string)) { + debug("GET_DESCRIPTOR: unknown string %hu\n", index); + return -1; + } + desc = usbfs_descriptor_string[index]; + *data = desc; + return desc->bLength; +} + +static int +usbfs_handle_get_descriptor(const struct usb_setup_packet *p, const void **data) { + uint8_t type = p->wValue >> 8; + uint8_t index = p->wValue & 0xFFU; + + switch (type) { + case 0x01: + debug("GET_DESCRIPTOR: device, %u bytes\n", p->wLength); + return usbfs_handle_get_descriptor_device(data, index); + case 0x02: + debug("GET_DESCRIPTOR: configuration %u, %u bytes\n", + index, p->wLength); + return usbfs_handle_get_descriptor_configuration(data, index); + case 0x03: + debug("GET_DESCRIPTOR: string %u, %u bytes\n", + index, p->wLength); + return usbfs_handle_get_descriptor_string(data, index); + #ifndef NDEBUG + case 0x06: /* DEVICE QUALIFIER (for high-speed) */ + debug("DEVICE_QUALIFIER\n"); + break; + default: + debug("GET_DESCRIPTOR: unknown type 0x%02x\n", type); + break; + #endif + } + return -1; +} + +static int +usbfs_handle_get_configuration(const struct usb_setup_packet *p, const void **data) { + debug("GET_CONFIGURATION\n"); + *data = &usbfs_descriptor_configuration1.bConfigurationValue; + return 1; +} + +static int +usbfs_handle_set_configuration(const struct usb_setup_packet *p, const void **data) { + debug("SET_CONFIGURATION: wValue = %hu\n", p->wValue); + + if (p->wValue != usbfs_descriptor_configuration1.bConfigurationValue) { + return -1; + } + + /* configure CDC endpoint */ + USBFS->DIEP[CDC_ENDPOINT].CTL = + USBFS_DIEPCTL_SNAK | + USBFS_DIEPCTL_EPTYPE_INTERRUPT | + USBFS_DIEPCTL_EPACT | + CDC_PACKETSIZE; + + /* configure ACM endpoints */ + USBFS->DIEP[ACM_ENDPOINT].CTL = + USBFS_DIEPCTL_SNAK | + USBFS_DIEPCTL_EPTYPE_BULK | + USBFS_DIEPCTL_EPACT | + ACM_PACKETSIZE; + + USBFS->DOEP[ACM_ENDPOINT].LEN = USBFS_DOEPLEN_PCNT(1) | ACM_PACKETSIZE; + USBFS->DOEP[ACM_ENDPOINT].CTL = + USBFS_DOEPCTL_EPEN | + USBFS_DOEPCTL_CNAK | + USBFS_DOEPCTL_EPTYPE_BULK | + USBFS_DOEPCTL_EPACT | + ACM_PACKETSIZE; + + USBFS->DAEPINTEN |= + /* (1U << (CDC_ENDPOINT + USBFS_DAEPINTEN_IEPIE_Pos)) | */ + (1U << (ACM_ENDPOINT + USBFS_DAEPINTEN_IEPIE_Pos)) | + (1U << (ACM_ENDPOINT + USBFS_DAEPINTEN_OEPIE_Pos)); + + acm_line_coding.dwDTERate = 9600; + acm_line_coding.bCharFormat = 0; + acm_line_coding.bParityType = 0; + acm_line_coding.bDataBits = 8; + acm_inidle = true; + acm_send(); + + return 0; +} + +static int +usbfs_handle_set_interface0(const struct usb_setup_packet *p, const void **data) { + debug("SET_INTERFACE: wIndex = %hu, wValue = %hu\n", p->wIndex, p->wValue); + + if (p->wValue != 0) { + return -1; + } + + return 0; +} + +static int +usbfs_handle_clear_feature_endpoint(const struct usb_setup_packet *p, const void **data) { + debug("CLEAR_FEATURE endpoint %hu\n", p->wIndex); + return -1; +} + +static int +acm_set_control_line_state(const struct usb_setup_packet *p, const void **data) { + debug("SET_CONTROL_LINE_STATE: wIndex = %hu wValue = 0x%04hx\r\n", + p->wIndex, p->wValue); + + debug(" RTS %u DTR %u\r\n", !!(p->wValue & 0x2), !!(p->wValue & 0x1)); + return 0; +} + +static int +acm_set_line_coding(const struct usb_setup_packet *p, const void **data) { + const struct acm_line_coding *lc = *data; + + debug("SET_LINE_CODING: {\r\n" + " dwDTERate = %lu\r\n" + " bCharFormat = 0x%02x\r\n" + " bParityType = 0x%02x\r\n" + " bDataBits = 0x%02x\r\n" + "}\r\n", + lc->dwDTERate, + lc->bCharFormat, + lc->bParityType, + lc->bDataBits); + + acm_line_coding.dwDTERate = lc->dwDTERate; + acm_line_coding.bCharFormat = lc->bCharFormat; + acm_line_coding.bParityType = lc->bParityType; + acm_line_coding.bDataBits = lc->bDataBits; + + debug("GRFLEN = 0x%08lx\n", USBFS->GRFLEN); + debug("DIEP0TFLEN = 0x%08lx\n", USBFS->DIEP0TFLEN); + debug("DIEP1TFLEN = 0x%08lx\n", USBFS->DIEP1TFLEN); + debug("DIEP2TFLEN = 0x%08lx\n", USBFS->DIEP2TFLEN); + debug("DIEP3TFLEN = 0x%08lx\n", USBFS->DIEP3TFLEN); + return 0; +} + +static int +acm_get_line_coding(const struct usb_setup_packet *p, const void **data) { + debug("GET_LINE_CODING: {\r\n" + " dwDTERate = %lu\r\n" + " bCharFormat = 0x%02x\r\n" + " bParityType = 0x%02x\r\n" + " bDataBits = 0x%02x\r\n" + "}\r\n", + acm_line_coding.dwDTERate, + acm_line_coding.bCharFormat, + acm_line_coding.bParityType, + acm_line_coding.bDataBits); + *data = &acm_line_coding; + return 7; +} + +static const struct usb_setup_handler usbfs_setup_handlers[] = { + { .req = 0x0080, .idx = 0, .len = -1, .fn = usbfs_handle_get_status_device }, + { .req = 0x0500, .idx = 0, .len = 0, .fn = usbfs_handle_set_address }, + { .req = 0x0680, .idx = -1, .len = -1, .fn = usbfs_handle_get_descriptor }, + { .req = 0x0880, .idx = 0, .len = -1, .fn = usbfs_handle_get_configuration }, + { .req = 0x0900, .idx = 0, .len = 0, .fn = usbfs_handle_set_configuration }, + { .req = 0x0102, .idx = 0, .len = 0, .fn = usbfs_handle_clear_feature_endpoint }, + { .req = 0x0b01, .idx = CDC_INTERFACE, .len = 0, .fn = usbfs_handle_set_interface0 }, + { .req = 0x2221, .idx = CDC_INTERFACE, .len = 0, .fn = acm_set_control_line_state }, + { .req = 0x2021, .idx = CDC_INTERFACE, .len = 7, .fn = acm_set_line_coding }, + { .req = 0x21a1, .idx = CDC_INTERFACE, .len = 7, .fn = acm_get_line_coding }, + { .req = 0x0102, .idx = CDC_ENDPOINT, .len = 0, .fn = usbfs_handle_clear_feature_endpoint }, + { .req = 0x0b01, .idx = ACM_INTERFACE, .len = 0, .fn = usbfs_handle_set_interface0 }, + { .req = 0x0102, .idx = ACM_ENDPOINT, .len = 0, .fn = usbfs_handle_clear_feature_endpoint }, +}; + +static int +usbfs_setup_handler_run(const struct usb_setup_packet *p, const void **data) { + uint8_t idx = p->wIndex; + const struct usb_setup_handler *h; + + for (h = usbfs_setup_handlers; h < ARRAY_END(usbfs_setup_handlers); h++) { + if (h->req == p->request && (h->idx == 0xFFU || h->idx == idx)) { + if (h->len != 0xFFU && h->len != p->wLength) { + break; + } + return h->fn(p, data); + } + } + + debug("unknown request:\n" + " bmRequestType 0x%02x\n" + " bRequest 0x%02x\n" + " wValue 0x%04x\n" + " wIndex 0x%04x\n" + " wLength 0x%04x\n", + p->bmRequestType, + p->bRequest, + p->wValue, + p->wIndex, + p->wLength); + return -1; +} + +static void +usbfs_handle_setup(void) { + const struct usb_setup_packet *p = &usbfs_outbuf.setup; + + usbfs_state.bytes = 0; + + if (p->bmRequestType & 0x80U) { + const void *data; + int ret = usbfs_setup_handler_run(p, &data); + + if (ret >= 0) { + /* send IN data */ + if (ret > p->wLength) { + ret = p->wLength; + } + usbfs_state.ep0in = data; + usbfs_state.bytes = ret; + usbfs_ep0in_transfer(); + /* prepare for IN ack */ + usbfs_ep0out_prepare_out(); + return; + } + } else if (p->wLength == 0) { + const void *data; + + if (!usbfs_setup_handler_run(p, &data)) { + /* send empty ack package */ + usbfs_ep0in_transfer_empty(); + /* prepare for next SETUP package */ + usbfs_ep0out_prepare_setup(); + return; + } + } else if (p->wLength <= ARRAY_SIZE(usbfs_outbuf.data)) { + /* receive OUT data */ + usbfs_ep0out_prepare_out(); + usbfs_state.bytes = p->wLength; + return; + } + + /* stall IN endpoint */ + usbfs_ep0in_stall(); + /* prepare for next SETUP package */ + usbfs_ep0out_prepare_setup(); +} + +static void +usbfs_handle_rx0(bool setup, unsigned int len) { + if (setup) { + for (; len > 8; len -= 4) { + (void)USBFS->DFIFO[0][0]; + } + usbfs_state.ep0out = usbfs_outbuf.v; + *usbfs_state.ep0out++ = USBFS->DFIFO[0][0]; + *usbfs_state.ep0out++ = USBFS->DFIFO[0][0]; + } else { + while (1) { + *usbfs_state.ep0out++ = USBFS->DFIFO[0][0]; + if (len <= 4) { + break; + } + len -= 4; + } + } +} + +static void +usbfs_handle_ep0(void) { + uint32_t oflags = USBFS->DOEP[0].INTF; + uint32_t iflags = USBFS->DIEP[0].INTF; + uint32_t bytes; + + USBFS->DOEP[0].INTF = oflags; + USBFS->DIEP[0].INTF = iflags; + + // debug("EP0 %04lx %04lx %lu\n", oflags, iflags, usbfs_state.bytes); + + if (oflags & USBFS_DOEPINTF_STPF) { + usbfs_handle_setup(); + return; + } + + bytes = usbfs_state.bytes; + if (bytes == 0) { + return; + } + + if (iflags & USBFS_DIEPINTF_TF) { + /* data IN */ + if (bytes > usbfs_state.packetsize) { + /* send next package */ + usbfs_state.ep0in += usbfs_state.packetsize; + usbfs_state.bytes = bytes - usbfs_state.packetsize; + usbfs_ep0in_transfer(); + } else { + usbfs_state.bytes = 0; + } + } else if (oflags & USBFS_DOEPINTF_TF) { + /* data OUT */ + bytes = usbfs_state.packetsize - (USBFS->DOEP[0].LEN & USBFS_DOEPLEN_TLEN_Msk); + if (usbfs_state.bytes > bytes) { + usbfs_state.bytes -= bytes; + /* prepare for more OUT data */ + usbfs_ep0out_prepare_out(); + } else { + const void *data = usbfs_outbuf.data; + + usbfs_state.bytes = 0; + if (!usbfs_setup_handler_run(&usbfs_outbuf.setup, &data)) { + /* send empty ack package */ + usbfs_ep0in_transfer_empty(); + } else { + usbfs_ep0in_stall(); + } + usbfs_ep0out_prepare_setup(); + } + } +} + +static void +acm_handle_rx(bool setup, unsigned int len) { + for (uint32_t *p = acm_outbuf.word;; p++) { + *p = USBFS->DFIFO[ACM_ENDPOINT][0]; + if (len <= 4) { + break; + } + len -= 4; + } +} + +static void +acm_handle_ep(void) { + uint32_t flags = USBFS->DOEP[ACM_ENDPOINT].INTF; + + USBFS->DOEP[ACM_ENDPOINT].INTF = flags; + + /* + debug("ACM OUT: 0x%02lx (0x%08lx)\n", flags, + USBFS->DOEP[ACM_ENDPOINT].CTL); + */ + + if (flags & USBFS_DOEPINTF_TF) { + unsigned int bytes = ACM_PACKETSIZE - + (USBFS->DOEP[ACM_ENDPOINT].LEN & USBFS_DOEPLEN_TLEN_Msk); + + acm_outbytes = bytes; + } + + flags = USBFS->DIEP[ACM_ENDPOINT].INTF; + + USBFS->DIEP[ACM_ENDPOINT].INTF = flags; + + /* + debug("ACM IN: 0x%02lx (0x%08lx)\n", flags, + USBFS->DIEP[ACM_ENDPOINT].CTL); + */ + + if (flags & USBFS_DIEPINTF_TF) { + acm_send(); + } +} + +struct { + void (*rx)(bool setup, unsigned int len); + void (*ep)(void); +} usbfs_endpoints[] = { + { + .rx = usbfs_handle_rx0, + .ep = usbfs_handle_ep0, + }, + { + .rx = acm_handle_rx, + .ep = acm_handle_ep, + }, +}; + +static void +usbfs_handle_rxdata(void) { + uint32_t grstat = USBFS->GRSTATP; + unsigned int len = (grstat & USBFS_GRSTAT_BCOUNT_Msk) >> USBFS_GRSTAT_BCOUNT_Pos; + unsigned int ep; + bool setup; + + if (len == 0) { + return; + } + + ep = grstat & USBFS_GRSTAT_EPNUM_Msk; + setup = (grstat & USBFS_GRSTAT_RPCKST_Msk) == USBFS_GRSTAT_RPCKST_STP; + usbfs_endpoints[ep].rx(setup, len); +} + +static void +usbfs_handle_endpoints(void) { + uint32_t flags = USBFS->DAEPINT; + uint32_t mask = 0x10001U; + + for (unsigned int i = 0; i < ARRAY_SIZE(usbfs_endpoints); i++, mask <<= 1) { + if (flags & mask) { + usbfs_endpoints[i].ep(); + } + } +} + +void +USBFS_IRQHandler(void) { + uint32_t flags = USBFS->GINTF; + + // debug("flags = %08lx\n", flags); + + /* read all incoming packets */ + while ((flags & USBFS_GINTF_RXFNEIF)) { + usbfs_handle_rxdata(); + flags = USBFS->GINTF; + } + + if (flags & (USBFS_GINTF_OEPIF | USBFS_GINTF_IEPIF)) { + usbfs_handle_endpoints(); + } + + /* + if (!(flags & ( + USBFS_GINTF_SP | + USBFS_GINTF_WKUPIF | + USBFS_GINTF_RST | + USBFS_GINTF_ENUMF))) + return; + */ + + if (flags & USBFS_GINTF_SP) { + debug("SUSPEND.. "); + usbfs_suspend(); + USBFS->GINTF = USBFS_GINTF_SP; + debug("done\n"); + return; + } + if (flags & USBFS_GINTF_WKUPIF) { + debug("WAKEUP.. "); + usbfs_wakeup(); + USBFS->GINTF = USBFS_GINTF_WKUPIF; + debug("done\n"); + } + if (flags & USBFS_GINTF_RST) { + debug("RESET.. "); + usbfs_reset(); + USBFS->GINTF = USBFS_GINTF_RST; + debug("done\n"); + } + if (flags & USBFS_GINTF_ENUMF) { + debug("ENUMDONE.. "); + usbfs_enumdone(); + USBFS->GINTF = USBFS_GINTF_ENUMF; + debug("done\n"); + } +} + +static void +usbfs_allocate_buffers(uint32_t rx, + uint32_t tx0, uint32_t tx1, uint32_t tx2, uint32_t tx3) { + /* round up to number of 32bit words */ + rx = (rx + 3) >> 2; + tx0 = (tx0 + 3) >> 2; + tx1 = (tx1 + 3) >> 2; + tx2 = (tx2 + 3) >> 2; + tx3 = (tx3 + 3) >> 2; + USBFS->GRFLEN = rx; + debug("GRFLEN (0x%03x) = %3lu = 0x%08lx\n", + (uintptr_t)&USBFS->GRFLEN - (uintptr_t)USBFS, + rx, + USBFS->GRFLEN); + USBFS->DIEP0TFLEN = (tx0 << 16) | rx; + debug("DIEP0TFLEN (0x%03x) = %3lu, %4lu = 0x%08lx\n", + (uintptr_t)&USBFS->DIEP0TFLEN - (uintptr_t)USBFS, + tx0, rx, + USBFS->DIEP0TFLEN); + USBFS->DIEP1TFLEN = (tx1 << 16) | (rx + tx0); + debug("DIEP1TFLEN (0x%03x) = %3lu, %4lu = 0x%08lx\n", + (uintptr_t)&USBFS->DIEP1TFLEN - (uintptr_t)USBFS, + tx1, (rx + tx0), + USBFS->DIEP1TFLEN); + USBFS->DIEP2TFLEN = (tx2 << 16) | (rx + tx0 + tx1); + debug("DIEP2TFLEN (0x%03x) = %3lu, %4lu = 0x%08lx\n", + (uintptr_t)&USBFS->DIEP2TFLEN - (uintptr_t)USBFS, + tx2, (rx + tx0 + tx1), + USBFS->DIEP2TFLEN); + USBFS->DIEP3TFLEN = (tx3 << 16) | (rx + tx0 + tx1 + tx2); + debug("DIEP3TFLEN (0x%03x) = %3lu, %4lu = 0x%08lx\n", + (uintptr_t)&USBFS->DIEP3TFLEN - (uintptr_t)USBFS, + tx3, (rx + tx0 + tx1 + tx2), + USBFS->DIEP3TFLEN); +} + +void +usbacm_init(void) { + /* turn on USBFS clock */ + RCU->AHBEN |= RCU_AHBEN_USBFSEN; + + /* turn on GPIOA and AFIO */ + RCU->APB2EN |= RCU_APB2EN_PAEN | RCU_APB2EN_AFEN; + + /* reset USBFS */ + RCU->AHBRST |= RCU_AHBRST_USBFSRST; + RCU->AHBRST &= ~RCU_AHBRST_USBFSRST; + + /* disable global interrupt flag */ + USBFS->GAHBCS = 0U; + + /* disable Vbus sensing */ + USBFS->GCCFG = USBFS_GCCFG_VBUSIG; + + debug("core reset"); + USBFS->GRSTCTL = USBFS_GRSTCTL_CSRST; + while ((USBFS->GRSTCTL & USBFS_GRSTCTL_CSRST)) { + debug("."); + } + debug(" done\n"); + usbfs_udelay(3); + + /* force device mode */ + debug("switching to device mode"); + USBFS->GUSBCS |= USBFS_GUSBCS_FDM; + while ((USBFS->GINTF & USBFS_GINTF_COPM)) { + debug("."); + } + debug(" done\n"); + + /* manual says: "the application must wait at + * least 25ms for [FDM to] take effect" */ + usbfs_udelay(25000); + + /* initialize device */ + USBFS->DCFG = + USBFS_DCFG_EOPFT_80PCT | + USBFS_DCFG_DS_FULL; + + /* disconnect */ + USBFS->DCTL = USBFS_DCTL_SD; + + /* now that we're disconnected, power on phy */ + USBFS->GCCFG = + USBFS_GCCFG_VBUSIG | + /* USBFS_GCCFG_VBUSACEN | */ + USBFS_GCCFG_VBUSBCEN | + USBFS_GCCFG_PWRON; + + /* setup fifo allocation */ + usbfs_allocate_buffers(USBFS_FIFO_RXSIZE, + USBFS_FIFO_TX0SIZE, + USBFS_FIFO_TX1SIZE, + USBFS_FIFO_TX2SIZE, + USBFS_FIFO_TX3SIZE); + + /* flush all tx fifos */ + usbfs_txfifos_flush(); + + /* flush rx fifo */ + USBFS->GRSTCTL |= USBFS_GRSTCTL_RXFF; + while ((USBFS->GRSTCTL & USBFS_GRSTCTL_RXFF)) { + /* wait */ + } + /* wait 3 more phy clocks */ + usbfs_udelay(3); + + USBFS->DIEPINTEN = 0U; + USBFS->DOEPINTEN = 0U; + USBFS->DAEPINTEN = 0U; + + /* reset endpoint registers */ + usbfs_ep_reset(); + + /* clear all sticky interrupts */ + USBFS->GINTF = + USBFS_GINTF_WKUPIF | + USBFS_GINTF_SESIF | + USBFS_GINTF_DISCIF | + USBFS_GINTF_IDPSC | + USBFS_GINTF_ISOONCIF | + USBFS_GINTF_ISOINCIF | + USBFS_GINTF_EOPFIF | + USBFS_GINTF_ISOOPDIF | + USBFS_GINTF_ENUMF | + USBFS_GINTF_RST | + USBFS_GINTF_SP | + USBFS_GINTF_ESP | + USBFS_GINTF_SOF | + USBFS_GINTF_MFIF; + + /* enable interrupts */ + USBFS->GINTEN = + USBFS_GINTEN_WKUPIE | + USBFS_GINTEN_OEPIE | + USBFS_GINTEN_IEPIE | + USBFS_GINTEN_ENUMFIE | + USBFS_GINTEN_RSTIE | + USBFS_GINTEN_RXFNEIE | + USBFS_GINTEN_SPIE; + + /* enable eclic interrupt */ + eclic_config(USBFS_IRQn, ECLIC_ATTR_TRIG_LEVEL, 4); + eclic_enable(USBFS_IRQn); + + /* set usb global interrupt flag */ + USBFS->GAHBCS |= USBFS_GAHBCS_GINTEN; + + /* connect */ + USBFS->DCTL &= ~USBFS_DCTL_SD; +} diff --git a/ports/gd32vf103/usbacm.h b/ports/gd32vf103/usbacm.h new file mode 100644 index 0000000000000..aa42ceb9cb37e --- /dev/null +++ b/ports/gd32vf103/usbacm.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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 USBACM_H +#define USBACM_H + +void usbacm_init(void); + +#endif diff --git a/ports/stm32/led.c b/ports/stm32/led.c index adcb240cc0cc6..9458b2173425e 100644 --- a/ports/stm32/led.c +++ b/ports/stm32/led.c @@ -25,6 +25,7 @@ */ #include +#include #include "py/runtime.h" #include "py/mphal.h" diff --git a/ports/unix/Makefile b/ports/unix/Makefile index ff5f355022bc5..7380e5e41259c 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -39,7 +39,7 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror -CWARN += -Wpointer-arith -Wuninitialized -Wdouble-promotion -Wsign-compare -Wfloat-conversion +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Debugging/Optimization diff --git a/ports/unix/main.c b/ports/unix/main.c index 0fe492a554cbd..6faeacb58672f 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "py/compile.h" #include "py/runtime.h" diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index 7a578becb9cc1..19ad276a93df0 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "py/objlist.h" #include "py/runtime.h" diff --git a/ports/unix/moduselect.c b/ports/unix/moduselect.c index 6a0ee79aa6f0d..195e424dc5776 100644 --- a/ports/unix/moduselect.c +++ b/ports/unix/moduselect.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "py/runtime.h" #include "py/stream.h" diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 17f4895573ed5..5e32064f8ed89 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -23,6 +23,7 @@ * 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 for this port, // overriding defaults in py/mpconfig.h. diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index de0f5923bafe9..15698a826547b 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "py/runtime.h" #include "py/mpthread.h" diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h index e87b5d8ec0ff3..7e10557ba5e87 100644 --- a/ports/unix/variants/minimal/mpconfigvariant.h +++ b/ports/unix/variants/minimal/mpconfigvariant.h @@ -23,6 +23,7 @@ * 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 diff --git a/ports/windows/windows_mphal.c b/ports/windows/windows_mphal.c index b442b59147e4e..4491d18862782 100644 --- a/ports/windows/windows_mphal.c +++ b/ports/windows/windows_mphal.c @@ -32,6 +32,7 @@ #include #include #include +#include HANDLE std_in = NULL; HANDLE con_out = NULL; diff --git a/py/argcheck.c b/py/argcheck.c index c333ead05b64a..ea3a5effd954e 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/bc.c b/py/bc.c index 34bc78fd3a588..ff7ef007c04ee 100644 --- a/py/bc.c +++ b/py/bc.c @@ -27,7 +27,6 @@ #include #include -#include #include "py/runtime.h" #include "py/bc0.h" diff --git a/py/binary.c b/py/binary.c index d0f72ec23c49c..524d9eda83fdd 100644 --- a/py/binary.c +++ b/py/binary.c @@ -26,10 +26,8 @@ */ #include -#include #include #include -#include #include "py/binary.h" #include "py/smallint.h" diff --git a/py/builtinimport.c b/py/builtinimport.c index bdc82e77c8f74..df5ac5f8a0994 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -27,6 +27,7 @@ #include #include +#include #include #include "py/compile.h" diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 2853da26c5465..cffaa4bb89950 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -108,7 +108,7 @@ STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint return 0; } const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); - if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { + if (!(strlen(p) == 2 && p[0] == 'r' && (mp_uint_t)p[1] == '0' + i)) { emit_inline_thumb_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence r0 to r3")); return 0; } diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index 6cc2e4d34b6a8..5dac2ae3907f1 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -92,7 +92,7 @@ STATIC mp_uint_t emit_inline_xtensa_count_params(emit_inline_asm_t *emit, mp_uin return 0; } const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); - if (!(strlen(p) == 2 && p[0] == 'a' && p[1] == '2' + i)) { + if (!(strlen(p) == 2 && p[0] == 'a' && (mp_uint_t)p[1] == '2' + i)) { emit_inline_xtensa_error_msg(emit, MP_ERROR_TEXT("parameters must be registers in sequence a2 to a5")); return 0; } diff --git a/py/gc.c b/py/gc.c index 9c6336852a0cd..767f1b81c4dfa 100644 --- a/py/gc.c +++ b/py/gc.c @@ -298,7 +298,8 @@ STATIC void gc_sweep(void) { #if MICROPY_PY_GC_COLLECT_RETVAL MP_STATE_MEM(gc_collected)++; #endif - // fall through to free the head + // fall through to free the head + MP_FALLTHROUGH case AT_TAIL: if (free_tail) { diff --git a/py/lexer.c b/py/lexer.c index 7d2a251d41d75..07ea2b96ab578 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -346,7 +346,8 @@ STATIC void parse_string_literal(mp_lexer_t *lex, bool is_raw) { vstr_add_char(&lex->vstr, '\\'); break; } - // Otherwise fall through. + // Otherwise fall through. + MP_FALLTHROUGH case 'x': { mp_uint_t num = 0; if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) { diff --git a/py/malloc.c b/py/malloc.c index c775d5b157312..205eb4ce3ee33 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -25,7 +25,7 @@ */ #include -#include +#include #include #include "py/mpconfig.h" @@ -62,6 +62,7 @@ #define realloc(ptr, n) gc_realloc(ptr, n, true) #define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) #else +#include // GC is disabled. Use system malloc/realloc/free. diff --git a/py/map.c b/py/map.c index 54f4b0204b87f..9b559a604b1b8 100644 --- a/py/map.c +++ b/py/map.c @@ -25,7 +25,7 @@ */ #include -#include +#include #include #include diff --git a/py/modmath.c b/py/modmath.c index b7948f39e7c91..3ab3ff334c41b 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -206,8 +206,8 @@ MATH_FUN_1(lgamma, lgamma) STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_a, ARG_b, ARG_rel_tol, ARG_abs_tol }; static const mp_arg_t allowed_args[] = { - {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, - {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}}, }; diff --git a/py/modstruct.c b/py/modstruct.c index 4cbcad6d496a8..0c0e3e722aa69 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -25,7 +25,6 @@ * THE SOFTWARE. */ -#include #include #include "py/runtime.h" diff --git a/py/moduerrno.c b/py/moduerrno.c index d9affd9b20c7a..2f5821f2b0ed2 100644 --- a/py/moduerrno.c +++ b/py/moduerrno.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include #include #include "py/obj.h" diff --git a/py/mpconfig.h b/py/mpconfig.h index cc83f3850d695..854188b66b585 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -1643,6 +1643,13 @@ typedef double mp_float_t; #endif #endif +// Explicitly annotate switch case fall throughs +#if defined(__GNUC__) && __GNUC__ >= 7 +#define MP_FALLTHROUGH __attribute__((fallthrough)); +#else +#define MP_FALLTHROUGH +#endif + #ifndef MP_HTOBE16 #if MP_ENDIANNESS_LITTLE #define MP_HTOBE16(x) ((uint16_t)((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))) diff --git a/py/mphal.h b/py/mphal.h index 0d4b1224e5cec..787b489836f1f 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_MPHAL_H #include +#include #include "py/mpconfig.h" #ifdef MICROPY_MPHALPORT_H diff --git a/py/nlr.h b/py/nlr.h index f9fbf56e54e60..00c994a56303b 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -29,9 +29,6 @@ // non-local return // exception handling, basically a stack of setjmp/longjmp buffers -#include -#include - #include "py/mpconfig.h" #define MICROPY_NLR_NUM_REGS_X86 (6) @@ -79,6 +76,9 @@ #define MICROPY_NLR_POWERPC (1) // this could be less but using 128 for safety #define MICROPY_NLR_NUM_REGS (128) +#elif defined(__riscv_xlen) && __riscv_xlen == 32 + #define MICROPY_NLR_RISCV32 (1) + #define MICROPY_NLR_NUM_REGS (14) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -150,6 +150,7 @@ NORETURN void nlr_jump_fail(void *val); #ifndef MICROPY_DEBUG_NLR #define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val)) #else +#include #include "mpstate.h" #define nlr_raise(val) \ do { \ diff --git a/py/nlrriscv32.c b/py/nlrriscv32.c new file mode 100644 index 0000000000000..af8d773d1a694 --- /dev/null +++ b/py/nlrriscv32.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Emil Renner Berthing + * + * 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_RISCV32 + +#undef nlr_push + +// For reference, riscv callee save regs are: +// s0-s11, ra and sp + +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + + __asm volatile ( + "sw s0, 0+%0 \n" // store s0 into nlr->regs + "sw s1, 4+%0 \n" // store s1 into nlr->regs + "sw s2, 8+%0 \n" // store s2 into nlr->regs + "sw s3, 12+%0 \n" // store s3 into nlr->regs + "sw s4, 16+%0 \n" // store s4 into nlr->regs + "sw s5, 20+%0 \n" // store s5 into nlr->regs + "sw s6, 24+%0 \n" // store s6 into nlr->regs + "sw s7, 28+%0 \n" // store s7 into nlr->regs + "sw s8, 32+%0 \n" // store s8 into nlr->regs + "sw s9, 36+%0 \n" // store s9 into nlr->regs + "sw s10, 40+%0 \n" // store s10 into nlr->regs + "sw s11, 44+%0 \n" // store s11 into nlr->regs + "sw ra, 48+%0 \n" // store ra into nlr->regs + "sw sp, 52+%0 \n" // store sp into nlr->regs + "tail nlr_push_tail \n" // do the rest in C + : "=o" (nlr->regs) + ); +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + + /* WARNING: if the above macro grows to call a function + * (that returns) after loading top, the compiler might + * decide to stash top in an s-register and the assembly + * below will break. + */ + __asm volatile ( + "lw s0, 0+%0 \n" // load s0 from top->regs + "lw s1, 4+%0 \n" // load s1 from top->regs + "lw s2, 8+%0 \n" // load s2 from top->regs + "lw s3, 12+%0 \n" // load s3 from top->regs + "lw s4, 16+%0 \n" // load s4 from top->regs + "lw s5, 20+%0 \n" // load s5 from top->regs + "lw s6, 24+%0 \n" // load s6 from top->regs + "lw s7, 28+%0 \n" // load s7 from top->regs + "lw s8, 32+%0 \n" // load s8 from top->regs + "lw s9, 36+%0 \n" // load s9 from top->regs + "lw s10, 40+%0 \n" // load s10 from top->regs + "lw s11, 44+%0 \n" // load s11 from top->regs + "lw ra, 48+%0 \n" // load ra from top->regs + "lw sp, 52+%0 \n" // load sp from top->regs + "li a0, 1 \n" // return 1, non-local return + "ret \n" // return + :: "o" (top->regs) + ); + + MP_UNREACHABLE +} + +#endif // MICROPY_NLR_RISCV32 diff --git a/py/objbool.c b/py/objbool.c index 23e023d8cbc15..cce62bf663c57 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include "py/runtime.h" diff --git a/py/objcomplex.c b/py/objcomplex.c index f4c4aeffcb91d..4d952ab4361d4 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include diff --git a/py/objenumerate.c b/py/objenumerate.c index d1de4add47ba8..0e34da46af4f0 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/objexcept.c b/py/objexcept.c index 517427ed71365..885032c3e3eed 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -208,7 +208,7 @@ mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type, size_t n_args, siz // reserved room (after the traceback data) for a tuple with 1 element. // Otherwise we are free to use the whole buffer after the traceback data. if (o_tuple == NULL && mp_emergency_exception_buf_size >= - EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args)) { + (mp_int_t)(EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(n_args))) { o_tuple = (mp_obj_tuple_t *) ((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TUPLE_OFFSET); } @@ -383,7 +383,7 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, mp_rom_error_te // that buffer to store the string object, reserving room at the start for the // traceback and 1-tuple. if (o_str == NULL - && mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t)) { + && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))) { o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_OFFSET); } @@ -465,7 +465,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_er // that buffer to store the string object and its data (at least 16 bytes for // the string data), reserving room at the start for the traceback and 1-tuple. if ((o_str == NULL || o_str_buf == NULL) - && mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16) { + && mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16)) { used_emg_buf = true; o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_OFFSET); o_str_buf = (byte *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_BUF_OFFSET); @@ -573,7 +573,7 @@ void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qs self->traceback_data = m_new_maybe(size_t, TRACEBACK_ENTRY_LEN); if (self->traceback_data == NULL) { #if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF - if (mp_emergency_exception_buf_size >= EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE) { + if (mp_emergency_exception_buf_size >= (mp_int_t)(EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)) { // There is room in the emergency buffer for traceback data size_t *tb = (size_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_TRACEBACK_OFFSET); diff --git a/py/objfloat.c b/py/objfloat.c index 451609492e5c1..80c2ac3f464ac 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include #include diff --git a/py/objgenerator.c b/py/objgenerator.c index 543685fac7860..a059af8e5c5f6 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -25,8 +25,7 @@ * THE SOFTWARE. */ -#include -#include +#include #include "py/runtime.h" #include "py/bc.h" diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index 54e27b8f11d0b..409fcefda5701 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include "py/runtime.h" diff --git a/py/objint.c b/py/objint.c index 4619fb5751fed..f2afb05365e17 100644 --- a/py/objint.c +++ b/py/objint.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include diff --git a/py/objint_longlong.c b/py/objint_longlong.c index f2e88c3ea5643..9d04ea45c18b4 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -25,8 +25,9 @@ * THE SOFTWARE. */ -#include +#include #include +#include #include "py/smallint.h" #include "py/objint.h" diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 6e52073a6e85b..7efe84e649946 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -26,6 +26,7 @@ #include #include +#include #include #include "py/parsenumbase.h" diff --git a/py/objmap.c b/py/objmap.c index 78c52c8925782..f4db0e7092c9b 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -24,8 +24,7 @@ * THE SOFTWARE. */ -#include -#include +#include #include "py/runtime.h" diff --git a/py/objmodule.c b/py/objmodule.c index a1f9d9d7f146a..2fce32e40ca79 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -25,9 +25,8 @@ * THE SOFTWARE. */ -#include +#include #include -#include #include "py/objmodule.h" #include "py/runtime.h" diff --git a/py/objnone.c b/py/objnone.c index 271a8543f9718..b27ba86a700e7 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -24,8 +24,6 @@ * THE SOFTWARE. */ -#include - #include "py/obj.h" #if !MICROPY_OBJ_IMMEDIATE_OBJS diff --git a/py/objobject.c b/py/objobject.c index 00082dfe08708..4c2787ba82d2f 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include "py/objtype.h" #include "py/runtime.h" diff --git a/py/objpolyiter.c b/py/objpolyiter.c index 01880bff9c1b9..27936a1256262 100644 --- a/py/objpolyiter.c +++ b/py/objpolyiter.c @@ -24,8 +24,6 @@ * THE SOFTWARE. */ -#include - #include "py/runtime.h" // This is universal iterator type which calls "iternext" method stored in diff --git a/py/objproperty.c b/py/objproperty.c index 8d2c292c52d76..cdd8779dd192b 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -24,8 +24,7 @@ * THE SOFTWARE. */ -#include -#include +#include #include "py/runtime.h" diff --git a/py/objrange.c b/py/objrange.c index 4eed4b9410550..1f9acbc56346e 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -24,7 +24,8 @@ * THE SOFTWARE. */ -#include +#include +#include #include "py/runtime.h" diff --git a/py/objreversed.c b/py/objreversed.c index 4254668e751c8..8a4a97f310c2d 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -24,8 +24,7 @@ * THE SOFTWARE. */ -#include -#include +#include #include "py/runtime.h" diff --git a/py/objset.c b/py/objset.c index f31a901a7008a..dac9b1138291e 100644 --- a/py/objset.c +++ b/py/objset.c @@ -445,6 +445,7 @@ STATIC mp_obj_t set_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } return MP_OBJ_NEW_SMALL_INT(hash); } + MP_FALLTHROUGH #endif default: return MP_OBJ_NULL; // op not supported diff --git a/py/objsingleton.c b/py/objsingleton.c index 2b896305cff5b..a7ce92b06f211 100644 --- a/py/objsingleton.c +++ b/py/objsingleton.c @@ -24,9 +24,6 @@ * THE SOFTWARE. */ -#include -#include - #include "py/obj.h" /******************************************************************************/ diff --git a/py/objslice.c b/py/objslice.c index c65c30601be69..e493b7e3cd520 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include #include #include "py/runtime.h" diff --git a/py/objzip.c b/py/objzip.c index 4abc917c3f525..ba0f38940d5cc 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -24,8 +24,7 @@ * THE SOFTWARE. */ -#include -#include +#include #include "py/objtuple.h" #include "py/runtime.h" diff --git a/py/parsenum.c b/py/parsenum.c index e665da7d8cdad..5ecbea11e2a17 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -25,7 +25,8 @@ */ #include -#include +#include +#include #include "py/runtime.h" #include "py/parsenumbase.h" diff --git a/py/profile.c b/py/profile.c index 863b0068a03e5..abf71618fc750 100644 --- a/py/profile.c +++ b/py/profile.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include + #include "py/profile.h" #include "py/bc0.h" #include "py/gc.h" diff --git a/py/py.mk b/py/py.mk index d864a7ed3d843..5973336085bc6 100644 --- a/py/py.mk +++ b/py/py.mk @@ -55,6 +55,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrthumb.o \ nlrpowerpc.o \ nlrxtensa.o \ + nlrriscv32.o \ nlrsetjmp.o \ malloc.o \ gc.o \ diff --git a/py/pystack.h b/py/pystack.h index ea8fddcf2f65b..99443c1e83340 100644 --- a/py/pystack.h +++ b/py/pystack.h @@ -33,6 +33,7 @@ #define MP_PYSTACK_DEBUG (0) #if MICROPY_ENABLE_PYSTACK +#include void mp_pystack_init(void *start, void *end); void *mp_pystack_alloc(size_t n_bytes); diff --git a/py/qstr.c b/py/qstr.c index c14ec5ae0073d..10266e1e6ae06 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include #include #include diff --git a/py/reader.c b/py/reader.c index d68406b1c68b3..b3f88dcc77b48 100644 --- a/py/reader.c +++ b/py/reader.c @@ -25,7 +25,6 @@ */ #include -#include #include "py/runtime.h" #include "py/mperrno.h" diff --git a/py/runtime.h b/py/runtime.h index 0bf988b905656..3b956939ea6c3 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -174,6 +174,7 @@ NORETURN void mp_raise_recursion_depth(void); #else // A port may define to raise TypeError for example #ifndef mp_check_self +#include #define mp_check_self(pred) assert(pred) #endif #endif diff --git a/py/scope.c b/py/scope.c index 073c2a38c2c21..98e02fb53fe31 100644 --- a/py/scope.c +++ b/py/scope.c @@ -72,7 +72,7 @@ void scope_free(scope_t *scope) { m_del(scope_t, scope, 1); } -id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, scope_kind_t kind) { +id_info_t *scope_find_or_add_id(scope_t *scope, qstr qst, id_info_kind_t kind) { id_info_t *id_info = scope_find(scope, qst); if (id_info != NULL) { return id_info; diff --git a/py/scope.h b/py/scope.h index b52d98ea1c72d..edf164c4adace 100644 --- a/py/scope.h +++ b/py/scope.h @@ -29,14 +29,14 @@ #include "py/parse.h" #include "py/emitglue.h" -enum { +typedef enum { ID_INFO_KIND_UNDECIDED, ID_INFO_KIND_GLOBAL_IMPLICIT, ID_INFO_KIND_GLOBAL_EXPLICIT, ID_INFO_KIND_LOCAL, // in a function f, written and only referenced by f ID_INFO_KIND_CELL, // in a function f, read/written by children of f ID_INFO_KIND_FREE, // in a function f, belongs to the parent of f -}; +} id_info_kind_t; enum { ID_FLAG_IS_PARAM = 0x01, @@ -92,7 +92,7 @@ typedef struct _scope_t { scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options); void scope_free(scope_t *scope); -id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, scope_kind_t kind); +id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, id_info_kind_t kind); id_info_t *scope_find(scope_t *scope, qstr qstr); id_info_t *scope_find_global(scope_t *scope, qstr qstr); void scope_check_to_close_over(scope_t *scope, id_info_t *id); diff --git a/py/stream.c b/py/stream.c index dce64a44dbeda..65f8c0792a082 100644 --- a/py/stream.c +++ b/py/stream.c @@ -431,13 +431,13 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) { struct mp_stream_seek_t seek_s; // TODO: Could be uint64 seek_s.offset = mp_obj_get_int(args[1]); - seek_s.whence = SEEK_SET; + seek_s.whence = MP_SEEK_SET; if (n_args == 3) { seek_s.whence = mp_obj_get_int(args[2]); } // In POSIX, it's error to seek before end of stream, we enforce it here. - if (seek_s.whence == SEEK_SET && seek_s.offset < 0) { + if (seek_s.whence == MP_SEEK_SET && seek_s.offset < 0) { mp_raise_OSError(MP_EINVAL); } @@ -455,7 +455,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj, 2, 3, stream_seek); STATIC mp_obj_t stream_tell(mp_obj_t self) { mp_obj_t offset = MP_OBJ_NEW_SMALL_INT(0); - mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(SEEK_CUR); + mp_obj_t whence = MP_OBJ_NEW_SMALL_INT(MP_SEEK_CUR); const mp_obj_t args[3] = {self, offset, whence}; return stream_seek(3, args); } diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 068214bf916cf..7912270872759 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -30,6 +30,10 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winitializer-overrides" #endif // __clang__ +#if __GNUC__ >= 5 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverride-init" +#endif // __GNUC__ >= 5 static const void *const entry_table[256] = { [0 ... 255] = &&entry_default, @@ -119,3 +123,6 @@ static const void *const entry_table[256] = { #if __clang__ #pragma clang diagnostic pop #endif // __clang__ +#if __GNUC__ >= 5 +#pragma GCC diagnostic pop +#endif // __GNUC__ >= 5 diff --git a/tests/run-tests b/tests/run-tests index eebc8c4252700..8d4efa4f61245 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -634,7 +634,7 @@ the last matching regex is used: sys.exit(0) LOCAL_TARGETS = ('unix', 'qemu-arm',) - EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf') + EXTERNAL_TARGETS = ('pyboard', 'wipy', 'esp8266', 'esp32', 'minimal', 'nrf', 'gd32vf103') if args.target in LOCAL_TARGETS or args.list_tests: pyb = None elif args.target in EXTERNAL_TARGETS: 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