From 6324c3e05499a31c5a80ad58f030e693f459f294 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 10:42:57 +0200 Subject: [PATCH 01/17] py/scope: Name and use id_kind_type_t. The function scope_find_or_add_id used to take a scope_kind_t enum and save it in an uint8_t. Saving an enum in a uint8_t is fine, but everywhere this function is called it is not actually given a scope_kind_t but an anonymous enum instead. Let's give this enum a name and use that as the argument type. This doesn't change the generated code, but is a C type mismatch that unfortunately doesn't show up unless you enable -Wenum-conversion. --- py/scope.c | 2 +- py/scope.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) 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); From 6d3aa16443c3eeef3945bf3d31429a655f690e0c Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Fri, 13 Dec 2019 08:24:18 +0100 Subject: [PATCH 02/17] py/objexcept: Compare mp_emergency_exception_buf_size signed. mp_emergency_exception_buf_size is signed, so let's make sure we compare it as such. --- py/objexcept.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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); From fdd6fa389ed68a5d0761f7cb71c94db5e927d741 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 10:51:59 +0200 Subject: [PATCH 03/17] py: Use unsigned comparison of chars. On x86 chars are signed, but we're comparing a char to '0' + unsigned int, which is promoted to an unsigned int. Let's promote the char to unsigned before doing the comparison to avoid weird corner cases. --- py/emitinlinethumb.c | 2 +- py/emitinlinextensa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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; } From 9aa58cf8bac353297ff5e7b4f3331e5618046095 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 11:23:12 +0200 Subject: [PATCH 04/17] py, extmod: Add explicit initializers for default values. When compiling with -Wextra which includes -Wmissing-field-initializers GCC will warn that the defval field of mp_arg_val_t is not initialized. This is just a warning as it is defined to be zero initialized, but since it is a union it makes sense to be explicit about which member we're going to use, so add the explicit initializers and get rid of the warning. --- extmod/machine_i2c.c | 4 ++-- extmod/vfs_lfs.c | 2 +- py/modmath.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) 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/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/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)}}, }; From f1f6ef7b17dc97f784a4cdb33154800129dc6d26 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Thu, 28 Nov 2019 12:50:08 +0100 Subject: [PATCH 05/17] py/vmentrytable: Ignore GCC -Woverride-init. Like Clang, GCC warns about this file, but only with -Woverride-init which is enabled by -Wextra. Disable the warnings for this file just like we do for Clang to make -Wextra happy. --- py/vmentrytable.h | 7 +++++++ 1 file changed, 7 insertions(+) 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 From dde3db21fcd8d810bb59e0c56dfa5fd9208e1544 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 12:19:48 +0200 Subject: [PATCH 06/17] extmod: Disable -Wmissing-field-initializers for lfs2. --- extmod/extmod.mk | 2 ++ 1 file changed, 2 insertions(+) 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 ################################################################################ From ccd92335a11f03597f94da2ac937811ff3fa50cf Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Thu, 28 Nov 2019 12:47:21 +0100 Subject: [PATCH 07/17] py, extmod: Introduce and use MP_FALLTHROUGH macro. Newer GCC versions are able to warn about switch cases that fall through. This is usually a sign of a forgotten break statement, but in the few cases where a fall through is intended we annotate it with this macro to avoid the warning. --- extmod/moductypes.c | 3 ++- extmod/re1.5/compilecode.c | 1 + extmod/re1.5/recursiveloop.c | 1 + py/gc.c | 3 ++- py/lexer.c | 3 ++- py/mpconfig.h | 7 +++++++ py/objset.c | 1 + 7 files changed, 16 insertions(+), 3 deletions(-) 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/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/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/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/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 From bef412789ea93c521bd9c2dddc22b9b3484da574 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 11:29:16 +0200 Subject: [PATCH 08/17] mpy-cross: Enable more warnings. --- mpy-cross/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 05f95682e7ddfb08c317e83826df9a1d636676f3 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 3 Oct 2020 11:31:13 +0200 Subject: [PATCH 09/17] unix: Enable more warnings. --- ports/unix/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From a012df18950c7132c88a258f818beba54e6fe299 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 30 Nov 2019 09:54:16 +0100 Subject: [PATCH 10/17] py: Use stddef.h for size_t. MicroPython already includes its own implementation of memcpy, memmove, strlen, printf and other functions required to build without a C library. So use stddef.h for size_t since it is provided by the compiler, and leave out stdlib.h where it isn't needed and thus make it easier to compile MicroPython without a C library. --- lib/utils/pyexec.c | 2 +- py/argcheck.c | 2 +- py/binary.c | 1 - py/malloc.c | 3 ++- py/map.c | 2 +- py/mphal.h | 1 + py/objbool.c | 2 +- py/objcomplex.c | 2 +- py/objenumerate.c | 2 +- py/objfloat.c | 2 +- py/objgenerator.c | 2 +- py/objgetitemiter.c | 2 -- py/objint.c | 2 +- py/objint_longlong.c | 2 +- py/objmap.c | 2 +- py/objmodule.c | 2 +- py/objnone.c | 2 -- py/objobject.c | 2 +- py/objpolyiter.c | 2 -- py/objproperty.c | 2 +- py/objrange.c | 2 +- py/objreversed.c | 2 +- py/objsingleton.c | 1 - py/objslice.c | 1 - py/objzip.c | 2 +- py/parsenum.c | 2 +- 26 files changed, 21 insertions(+), 28 deletions(-) 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/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/binary.c b/py/binary.c index d0f72ec23c49c..be66015c5ef77 100644 --- a/py/binary.c +++ b/py/binary.c @@ -26,7 +26,6 @@ */ #include -#include #include #include #include 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/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/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/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..e0fc8084bdaf8 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index 54e27b8f11d0b..ef24266f1df86 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -24,8 +24,6 @@ * THE SOFTWARE. */ -#include - #include "py/runtime.h" // this is a wrapper object that turns something that has a __getitem__ method into an iterator 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..51ede7f5e8ec0 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/smallint.h" diff --git a/py/objmap.c b/py/objmap.c index 78c52c8925782..df3af41b76776 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/objmodule.c b/py/objmodule.c index a1f9d9d7f146a..05fe8fc6ad32d 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include +#include #include #include 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..a2a258c41659f 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/objrange.c b/py/objrange.c index 4eed4b9410550..b7d70a0c8eed9 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include "py/runtime.h" diff --git a/py/objreversed.c b/py/objreversed.c index 4254668e751c8..006d9c24d6f56 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/runtime.h" diff --git a/py/objsingleton.c b/py/objsingleton.c index 2b896305cff5b..5b629420c5046 100644 --- a/py/objsingleton.c +++ b/py/objsingleton.c @@ -24,7 +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..7fe0a52039f8f 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include +#include #include #include "py/objtuple.h" diff --git a/py/parsenum.c b/py/parsenum.c index e665da7d8cdad..f15bea6618924 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -25,7 +25,7 @@ */ #include -#include +#include #include "py/runtime.h" #include "py/parsenumbase.h" From 0ee0b1b5c881f6191f97ad15aca32b4aba852bab Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Mon, 2 Dec 2019 10:01:28 +0100 Subject: [PATCH 11/17] py: Clean up assert.h usage. That is include assert.h in files where assert() is used, and don't include assert.h in files where it is not used. --- extmod/modbluetooth.c | 1 + extmod/modlwip.c | 1 + extmod/moduselect.c | 1 + extmod/moduwebsocket.c | 1 + extmod/modwebrepl.c | 1 + extmod/vfs.c | 1 + extmod/vfs_fat.c | 1 + extmod/vfs_fat_file.c | 1 + ports/stm32/led.c | 1 + ports/unix/modtermios.c | 1 + ports/unix/moduselect.c | 1 + ports/unix/mpthreadport.c | 2 ++ ports/windows/windows_mphal.c | 1 + py/bc.c | 1 - py/binary.c | 1 - py/modstruct.c | 1 - py/moduerrno.c | 1 - py/nlr.h | 2 +- py/objgenerator.c | 1 - py/objgetitemiter.c | 2 ++ py/objint_longlong.c | 1 + py/objmap.c | 1 - py/objmodule.c | 1 - py/objproperty.c | 1 - py/objrange.c | 1 + py/objreversed.c | 1 - py/objsingleton.c | 2 -- py/objzip.c | 1 - py/profile.c | 2 ++ py/pystack.h | 1 + py/qstr.c | 1 - py/reader.c | 1 - py/runtime.h | 1 + 33 files changed, 23 insertions(+), 15 deletions(-) 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/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/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/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/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/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/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/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 be66015c5ef77..524d9eda83fdd 100644 --- a/py/binary.c +++ b/py/binary.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "py/binary.h" #include "py/smallint.h" 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/nlr.h b/py/nlr.h index f9fbf56e54e60..b9a0455baa94a 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -30,7 +30,6 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include -#include #include "py/mpconfig.h" @@ -150,6 +149,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/objgenerator.c b/py/objgenerator.c index e0fc8084bdaf8..a059af8e5c5f6 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -26,7 +26,6 @@ */ #include -#include #include "py/runtime.h" #include "py/bc.h" diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index ef24266f1df86..409fcefda5701 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include + #include "py/runtime.h" // this is a wrapper object that turns something that has a __getitem__ method into an iterator diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 51ede7f5e8ec0..9d04ea45c18b4 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -27,6 +27,7 @@ #include #include +#include #include "py/smallint.h" #include "py/objint.h" diff --git a/py/objmap.c b/py/objmap.c index df3af41b76776..f4db0e7092c9b 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -25,7 +25,6 @@ */ #include -#include #include "py/runtime.h" diff --git a/py/objmodule.c b/py/objmodule.c index 05fe8fc6ad32d..2fce32e40ca79 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -27,7 +27,6 @@ #include #include -#include #include "py/objmodule.h" #include "py/runtime.h" diff --git a/py/objproperty.c b/py/objproperty.c index a2a258c41659f..cdd8779dd192b 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -25,7 +25,6 @@ */ #include -#include #include "py/runtime.h" diff --git a/py/objrange.c b/py/objrange.c index b7d70a0c8eed9..1f9acbc56346e 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -25,6 +25,7 @@ */ #include +#include #include "py/runtime.h" diff --git a/py/objreversed.c b/py/objreversed.c index 006d9c24d6f56..8a4a97f310c2d 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -25,7 +25,6 @@ */ #include -#include #include "py/runtime.h" diff --git a/py/objsingleton.c b/py/objsingleton.c index 5b629420c5046..a7ce92b06f211 100644 --- a/py/objsingleton.c +++ b/py/objsingleton.c @@ -24,8 +24,6 @@ * THE SOFTWARE. */ -#include - #include "py/obj.h" /******************************************************************************/ diff --git a/py/objzip.c b/py/objzip.c index 7fe0a52039f8f..ba0f38940d5cc 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -25,7 +25,6 @@ */ #include -#include #include "py/objtuple.h" #include "py/runtime.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/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 From f033a2c07cae6c1f07470fcc7cc38109829b0825 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Mon, 2 Dec 2019 11:04:19 +0100 Subject: [PATCH 12/17] py: Clean up limits.h usage. We need to include limits.h for PATH_MAX among other things. --- ports/unix/main.c | 1 + ports/unix/mpconfigport.h | 1 + ports/unix/variants/minimal/mpconfigvariant.h | 1 + py/builtinimport.c | 1 + py/nlr.h | 2 -- py/objint_mpz.c | 1 + py/parsenum.c | 1 + 7 files changed, 6 insertions(+), 2 deletions(-) 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/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/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/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/nlr.h b/py/nlr.h index b9a0455baa94a..c2a538d6c3d9e 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -29,8 +29,6 @@ // non-local return // exception handling, basically a stack of setjmp/longjmp buffers -#include - #include "py/mpconfig.h" #define MICROPY_NLR_NUM_REGS_X86 (6) 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/parsenum.c b/py/parsenum.c index f15bea6618924..5ecbea11e2a17 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -26,6 +26,7 @@ #include #include +#include #include "py/runtime.h" #include "py/parsenumbase.h" From 083f331829f3cb2bc094dca3d46de792fb14cc07 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Mon, 2 Dec 2019 10:11:47 +0100 Subject: [PATCH 13/17] py/stream: Use our own MP_SEEK_CUR and MP_SEEK_SET. Use the defines from our stream.h rather than SEEK_CUR and SEEK_SET from the C library. This makes it possible to compile even when a C library is not available. We already rely on our own versions being equal to the C library versions in other places, so this shouldn't break any users. --- py/stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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); } From 5b5f7a50b367a0502d75b9235509346b4d7e06cf Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Tue, 26 Nov 2019 14:54:24 +0100 Subject: [PATCH 14/17] py/nlrriscv32: Add 32-bit RISC-V support. --- py/nlr.h | 3 ++ py/nlrriscv32.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ py/py.mk | 1 + 3 files changed, 93 insertions(+) create mode 100644 py/nlrriscv32.c diff --git a/py/nlr.h b/py/nlr.h index c2a538d6c3d9e..00c994a56303b 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -76,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" 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/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 \ From 4f30dd39940f43b8724279cac74fdd08fedfeefc Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Tue, 26 Nov 2019 14:57:18 +0100 Subject: [PATCH 15/17] ports/gd32vf103: Add GigaDevice GD32VF103 port. --- .gitmodules | 3 + ports/gd32vf103/Makefile | 104 +++ ports/gd32vf103/README.md | 47 ++ ports/gd32vf103/gd32vf103inator | 1 + ports/gd32vf103/main.c | 170 ++++ ports/gd32vf103/modmachine.c | 108 +++ ports/gd32vf103/modutime.c | 47 ++ ports/gd32vf103/mpconfigport.h | 90 +++ ports/gd32vf103/mphalport.c | 71 ++ ports/gd32vf103/mphalport.h | 2 + ports/gd32vf103/pin.c | 312 ++++++++ ports/gd32vf103/pin.h | 46 ++ ports/gd32vf103/qstrdefsport.h | 1 + ports/gd32vf103/uart0.c | 79 ++ ports/gd32vf103/uart0.h | 34 + ports/gd32vf103/usbacm.c | 1296 +++++++++++++++++++++++++++++++ ports/gd32vf103/usbacm.h | 32 + tests/run-tests | 2 +- 18 files changed, 2444 insertions(+), 1 deletion(-) create mode 100644 ports/gd32vf103/Makefile create mode 100644 ports/gd32vf103/README.md create mode 160000 ports/gd32vf103/gd32vf103inator create mode 100644 ports/gd32vf103/main.c create mode 100644 ports/gd32vf103/modmachine.c create mode 100644 ports/gd32vf103/modutime.c create mode 100644 ports/gd32vf103/mpconfigport.h create mode 100644 ports/gd32vf103/mphalport.c create mode 100644 ports/gd32vf103/mphalport.h create mode 100644 ports/gd32vf103/pin.c create mode 100644 ports/gd32vf103/pin.h create mode 100644 ports/gd32vf103/qstrdefsport.h create mode 100644 ports/gd32vf103/uart0.c create mode 100644 ports/gd32vf103/uart0.h create mode 100644 ports/gd32vf103/usbacm.c create mode 100644 ports/gd32vf103/usbacm.h 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/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/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: From 8aa61289163d869d2ffb737d420016dd63893e9f Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Mon, 9 Dec 2019 20:50:40 +0100 Subject: [PATCH 16/17] travis: Optionally disable coveralls. This is useful to enable travis on your own github fork without having to create a coveralls.io account. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9fcc21336efd..a918e80e71b43 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 From 877f1f32e488e1e73e2fe8d7d7286484068baa3f Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Sat, 21 Dec 2019 11:51:08 +0100 Subject: [PATCH 17/17] travis: Compile test GD32VF103 port. --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index a918e80e71b43..8d1320ba5e2c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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- 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