diff options
173 files changed, 4012 insertions, 922 deletions
diff --git a/.travis.yml b/.travis.yml index e6c12b9677..489cceaa27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,4 +20,4 @@ script: - (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests) after_failure: - - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff $testbase.exp $testbase.out; done) + - (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done) diff --git a/bare-arm/Makefile b/bare-arm/Makefile index ed8c00482b..eeaaf423d0 100644 --- a/bare-arm/Makefile +++ b/bare-arm/Makefile @@ -22,7 +22,7 @@ else CFLAGS += -Os -DNDEBUG endif -LDFLAGS = -nostdlib -T stm32f405.ld +LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref LIBS = SRC_C = \ diff --git a/bare-arm/mpconfigport.h b/bare-arm/mpconfigport.h index 1587dca57a..8598735480 100644 --- a/bare-arm/mpconfigport.h +++ b/bare-arm/mpconfigport.h @@ -12,10 +12,12 @@ #define MICROPY_HELPER_REPL (0) #define MICROPY_HELPER_LEXER_UNIX (0) #define MICROPY_ENABLE_SOURCE_LINE (0) +#define MICROPY_PY_BUILTINS_BYTEARRAY (0) #define MICROPY_PY_BUILTINS_FROZENSET (0) #define MICROPY_PY_BUILTINS_SET (0) #define MICROPY_PY_BUILTINS_SLICE (0) #define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_ARRAY (0) #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_MATH (0) #define MICROPY_PY_CMATH (0) @@ -26,6 +28,8 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) + // type definitions for the specific machine #define BYTES_PER_WORD (4) diff --git a/py/asmthumb.c b/py/asmthumb.c index 891947567b..03752ed938 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -28,8 +28,8 @@ #include <assert.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "asmthumb.h" // wrapper around everything in this file diff --git a/py/asmx64.c b/py/asmx64.c index 6c22ea25de..4695bdc731 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -29,8 +29,8 @@ #include <assert.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" // wrapper around everything in this file #if MICROPY_EMIT_X64 diff --git a/py/binary.c b/py/binary.c index 833d9c85ad..d755bc86e0 100644 --- a/py/binary.c +++ b/py/binary.c @@ -29,8 +29,8 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "binary.h" @@ -125,24 +125,9 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) { return MP_OBJ_NEW_SMALL_INT(val); } -#define is_signed(typecode) (typecode > 'Z') -mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { - byte *p = *ptr; - uint align; - - int size = mp_binary_get_size(struct_type, val_type, &align); - if (struct_type == '@') { - // Make pointer aligned - p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1)); - #if MP_ENDIANNESS_LITTLE - struct_type = '<'; - #else - struct_type = '>'; - #endif - } - +machine_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) { int delta; - if (struct_type == '<') { + if (!big_endian) { delta = -1; p += size - 1; } else { @@ -150,7 +135,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { } machine_int_t val = 0; - if (is_signed(val_type) && *p & 0x80) { + if (is_signed && *p & 0x80) { val = -1; } for (uint i = 0; i < size; i++) { @@ -159,7 +144,28 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { p += delta; } - *ptr += size; + return val; +} + +#define is_signed(typecode) (typecode > 'Z') +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { + byte *p = *ptr; + uint align; + + int size = mp_binary_get_size(struct_type, val_type, &align); + if (struct_type == '@') { + // Make pointer aligned + p = (byte*)(((machine_uint_t)p + align - 1) & ~((machine_uint_t)align - 1)); + #if MP_ENDIANNESS_LITTLE + struct_type = '<'; + #else + struct_type = '>'; + #endif + } + *ptr = p + size; + + machine_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); + if (val_type == 'O') { return (mp_obj_t)val; } else if (val_type == 'S') { @@ -178,13 +184,14 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** int size = mp_binary_get_size(struct_type, val_type, &align); if (struct_type == '@') { // Make pointer aligned - p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1)); + p = (byte*)(((machine_uint_t)p + align - 1) & ~((machine_uint_t)align - 1)); #if MP_ENDIANNESS_LITTLE struct_type = '<'; #else struct_type = '>'; #endif } + *ptr = p + size; #if MP_ENDIANNESS_BIG #error Not implemented @@ -215,7 +222,6 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** in += in_delta; } - *ptr += size; } void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) { diff --git a/py/binary.h b/py/binary.h index f15a2fd7fb..63ea5d741e 100644 --- a/py/binary.h +++ b/py/binary.h @@ -34,3 +34,4 @@ void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val); mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr); +machine_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p); diff --git a/py/builtin.c b/py/builtin.c index 834108f1b5..f4bbe0e237 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -113,11 +113,13 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) { } else { return o_in; } +#if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) { mp_float_t real, imag; mp_obj_complex_get(o_in, &real, &imag); return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)); #endif +#endif } else { assert(0); return mp_const_none; @@ -154,7 +156,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any); STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) { mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in }; - return mp_obj_str_format(ARRAY_SIZE(args), args); + return mp_obj_str_format(MP_ARRAY_SIZE(args), args); } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin); @@ -170,13 +172,40 @@ STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable); STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { - int ord = mp_obj_get_int(o_in); + #if MICROPY_PY_BUILTINS_STR_UNICODE + machine_int_t c = mp_obj_get_int(o_in); + char str[4]; + int len = 0; + if (c < 0x80) { + *str = c; len = 1; + } else if (c < 0x800) { + str[0] = (c >> 6) | 0xC0; + str[1] = (c & 0x3F) | 0x80; + len = 2; + } else if (c < 0x10000) { + str[0] = (c >> 12) | 0xE0; + str[1] = ((c >> 6) & 0x3F) | 0x80; + str[2] = (c & 0x3F) | 0x80; + len = 3; + } else if (c < 0x110000) { + str[0] = (c >> 18) | 0xF0; + str[1] = ((c >> 12) & 0x3F) | 0x80; + str[2] = ((c >> 6) & 0x3F) | 0x80; + str[3] = (c & 0x3F) | 0x80; + len = 4; + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); + } + return mp_obj_new_str(str, len, true); + #else + machine_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0x10ffff) { char str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); } + #endif } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr); @@ -342,13 +371,32 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { uint len; const char *str = mp_obj_str_get_data(o_in, &len); + #if MICROPY_PY_BUILTINS_STR_UNICODE + machine_uint_t charlen = unichar_charlen(str, len); + if (charlen == 1) { + if (MP_OBJ_IS_STR(o_in) && UTF8_IS_NONASCII(*str)) { + machine_int_t ord = *str++ & 0x7F; + for (machine_int_t mask = 0x40; ord & mask; mask >>= 1) { + ord &= ~mask; + } + while (UTF8_IS_CONT(*str)) { + ord = (ord << 6) | (*str++ & 0x3F); + } + return mp_obj_new_int(ord); + } else { + return mp_obj_new_int(((const byte*)str)[0]); + } + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", charlen)); + } + #else if (len == 1) { // don't sign extend when converting to ord - // TODO unicode return mp_obj_new_int(((const byte*)str)[0]); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len)); } + #endif } MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord); diff --git a/py/builtintables.c b/py/builtintables.c index 857a581de4..c42cdf89bb 100644 --- a/py/builtintables.c +++ b/py/builtintables.c @@ -26,8 +26,8 @@ #include <stdlib.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -43,8 +43,10 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = { // built-in types { MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool }, { MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes }, +#if MICROPY_PY_BUILTINS_BYTEARRAY { MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray }, -#if MICROPY_PY_BUILTINS_FLOAT +#endif +#if MICROPY_PY_BUILTINS_COMPLEX { MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex }, #endif { MP_OBJ_NEW_QSTR(MP_QSTR_dict), (mp_obj_t)&mp_type_dict }, @@ -150,8 +152,8 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_builtin_object_table), - .alloc = ARRAY_SIZE(mp_builtin_object_table), + .used = MP_ARRAY_SIZE(mp_builtin_object_table), + .alloc = MP_ARRAY_SIZE(mp_builtin_object_table), .table = (mp_map_elem_t*)mp_builtin_object_table, }, }; @@ -160,7 +162,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ }, { MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython }, +#if MICROPY_PY_ARRAY { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array }, +#endif #if MICROPY_PY_IO { MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io }, #endif @@ -195,8 +199,8 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_builtin_module_table), - .alloc = ARRAY_SIZE(mp_builtin_module_table), + .used = MP_ARRAY_SIZE(mp_builtin_module_table), + .alloc = MP_ARRAY_SIZE(mp_builtin_module_table), .table = (mp_map_elem_t*)mp_builtin_module_table, }, }; diff --git a/py/compile.c b/py/compile.c index 946c8924b2..f2a108074f 100644 --- a/py/compile.c +++ b/py/compile.c @@ -31,8 +31,8 @@ #include <assert.h> #include <math.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -111,8 +111,8 @@ STATIC const mp_map_elem_t mp_constants_table[] = { STATIC const mp_map_t mp_constants_map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_constants_table), - .alloc = ARRAY_SIZE(mp_constants_table), + .used = MP_ARRAY_SIZE(mp_constants_table), + .alloc = MP_ARRAY_SIZE(mp_constants_table), .table = (mp_map_elem_t*)mp_constants_table, }; @@ -1894,7 +1894,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, EMIT_ARG(jump, success_label); // jump over exception handler EMIT_ARG(label_assign, l1); // start of exception handler - EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state + EMIT(start_except_handler); uint l2 = comp_next_label(comp); @@ -1966,7 +1966,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, compile_decrease_except_level(comp); EMIT(end_finally); - EMIT_ARG(adjust_stack_size, -5); // stack adjust + EMIT(end_except_handler); EMIT_ARG(label_assign, success_label); compile_node(comp, pn_else); // else block, can be null @@ -134,6 +134,11 @@ typedef struct _emit_method_table_t { void (*yield_value)(emit_t *emit); void (*yield_from)(emit_t *emit); + // these methods are used to control entry to/exit from an exception handler + // they may or may not emit code + void (*start_except_handler)(emit_t *emit); + void (*end_except_handler)(emit_t *emit); + #if MICROPY_EMIT_CPYTHON // these methods are only needed for emitcpy void (*load_const_verbatim_str)(emit_t *emit, const char *str); diff --git a/py/emitbc.c b/py/emitbc.c index 841dd4aabb..f9fbed4aaf 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -30,8 +30,8 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -849,6 +849,14 @@ STATIC void emit_bc_yield_from(emit_t *emit) { emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM); } +STATIC void emit_bc_start_except_handler(emit_t *emit) { + emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state +} + +STATIC void emit_bc_end_except_handler(emit_t *emit) { + emit_bc_adjust_stack_size(emit, -5); // stack adjust +} + const emit_method_table_t emit_bc_method_table = { emit_bc_set_native_types, emit_bc_start_pass, @@ -934,6 +942,9 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_raise_varargs, emit_bc_yield_value, emit_bc_yield_from, + + emit_bc_start_except_handler, + emit_bc_end_except_handler, }; #endif // !MICROPY_EMIT_CPYTHON diff --git a/py/emitcommon.c b/py/emitcommon.c index ea65183623..4649793134 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -28,8 +28,8 @@ #include <stdint.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" diff --git a/py/emitcpy.c b/py/emitcpy.c index a8a6265b8c..4ff99866a0 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -30,8 +30,8 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) { } } +STATIC void emit_cpy_start_except_handler(emit_t *emit) { + emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items +} + +STATIC void emit_cpy_end_except_handler(emit_t *emit) { + emit_cpy_adjust_stack_size(emit, -5); // stack adjust +} + STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) { emit_pre(emit, 1, 3); if (emit->pass == MP_PASS_EMIT) { @@ -899,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_yield_value, emit_cpy_yield_from, + emit_cpy_start_except_handler, + emit_cpy_end_except_handler, + // emitcpy specific functions emit_cpy_load_const_verbatim_str, emit_cpy_load_closure, diff --git a/py/emitglue.c b/py/emitglue.c index f9b9460837..17dc8f867c 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -30,8 +30,8 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 79ed1c4a02..435e1b64d9 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -30,8 +30,8 @@ #include <stdarg.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -167,7 +167,7 @@ STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t if (MP_PARSE_NODE_IS_ID(pn)) { qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn); const char *reg_str = qstr_str(reg_qstr); - for (uint i = 0; i < ARRAY_SIZE(reg_name_table); i++) { + for (uint i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) { const reg_name_t *r = ®_name_table[i]; if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) { if (r->reg > max_reg) { @@ -286,7 +286,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m asm_thumb_b_n(emit->as, label_num); } else if (op_str[0] == 'b' && op_len == 3) { uint cc = -1; - for (uint i = 0; i < ARRAY_SIZE(cc_name_table); i++) { + for (uint i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) { if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { cc = cc_name_table[i].cc; } diff --git a/py/emitnative.c b/py/emitnative.c index 4dac5ffb09..4cab3f4697 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -48,8 +48,9 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "nlr.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -723,7 +724,11 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qstr, bool bytes) { assert(0); emit_post_push_imm(emit, VTYPE_PTR, (machine_uint_t)qstr_str(qstr)); } else { - emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1); + if (bytes) { + emit_call_with_imm_arg(emit, 0, mp_load_const_bytes, qstr, REG_ARG_1); // TODO need to add function to runtime table + } else { + emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_STR, mp_load_const_str, qstr, REG_ARG_1); + } emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } } @@ -917,8 +922,11 @@ STATIC void emit_native_delete_global(emit_t *emit, qstr qstr) { } STATIC void emit_native_delete_attr(emit_t *emit, qstr qstr) { - // not supported - assert(0); + vtype_kind_t vtype_base; + emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base + assert(vtype_base == VTYPE_PYOBJ); + emit_call_with_2_imm_args(emit, MP_F_STORE_ATTR, mp_store_attr, qstr, REG_ARG_2, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg2 = attribute name, arg3 = value (null for delete) + emit_post(emit); } STATIC void emit_native_delete_subscr(emit_t *emit) { @@ -1054,17 +1062,33 @@ STATIC void emit_native_setup_with(emit_t *emit, uint label) { // not supported, or could be with runtime call assert(0); } + STATIC void emit_native_with_cleanup(emit_t *emit) { assert(0); } + STATIC void emit_native_setup_except(emit_t *emit, uint label) { - assert(0); + emit_native_pre(emit); + // need to commit stack because we may jump elsewhere + need_stack_settled(emit); + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(machine_uint_t)); // arg1 = pointer to nlr buf + emit_call(emit, 0, nlr_push); // TODO need to add function to runtime table +#if N_X64 + asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET); + asm_x64_jcc_label(emit->as, JCC_JNZ, label); +#elif N_THUMB + asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0); + asm_thumb_bcc_label(emit->as, THUMB_CC_NE, label); +#endif + emit_post(emit); } + STATIC void emit_native_setup_finally(emit_t *emit, uint label) { assert(0); } + STATIC void emit_native_end_finally(emit_t *emit) { - assert(0); + //assert(0); } STATIC void emit_native_get_iter(emit_t *emit) { @@ -1104,19 +1128,31 @@ STATIC void emit_native_for_iter_end(emit_t *emit) { STATIC void emit_native_pop_block(emit_t *emit) { emit_native_pre(emit); + emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table + adjust_stack(emit, -(machine_int_t)(sizeof(nlr_buf_t) / sizeof(machine_uint_t))); emit_post(emit); } STATIC void emit_native_pop_except(emit_t *emit) { - assert(0); + /* + emit_native_pre(emit); + emit_call(emit, 0, nlr_pop); // TODO need to add function to runtime table + adjust_stack(emit, -(machine_int_t)(sizeof(nlr_buf_t) / sizeof(machine_uint_t))); + emit_post(emit); + */ } STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) { - vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_ARG_2); - assert(vtype == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + if (op == MP_UNARY_OP_NOT) { + // we need to synthesise this operation + assert(0); + } else { + vtype_kind_t vtype; + emit_pre_pop_reg(emit, &vtype, REG_ARG_2); + assert(vtype == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_UNARY_OP, mp_unary_op, op, REG_ARG_1); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } } STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { @@ -1230,17 +1266,26 @@ STATIC void emit_native_set_add(emit_t *emit, int set_index) { STATIC void emit_native_build_slice(emit_t *emit, int n_args) { DEBUG_printf("build_slice %d\n", n_args); - assert(n_args == 2); - vtype_kind_t vtype_start, vtype_stop; - emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop - assert(vtype_start == VTYPE_PYOBJ); - assert(vtype_stop == VTYPE_PYOBJ); - emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg3 = step - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + if (n_args == 2) { + vtype_kind_t vtype_start, vtype_stop; + emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop + assert(vtype_start == VTYPE_PYOBJ); + assert(vtype_stop == VTYPE_PYOBJ); + emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)mp_const_none, REG_ARG_3); // arg3 = step + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } else { + assert(n_args == 3); + vtype_kind_t vtype_start, vtype_stop, vtype_step; + emit_pre_pop_reg_reg_reg(emit, &vtype_step, REG_ARG_3, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop, arg3 = step + assert(vtype_start == VTYPE_PYOBJ); + assert(vtype_stop == VTYPE_PYOBJ); + assert(vtype_step == VTYPE_PYOBJ); + emit_call(emit, MP_F_NEW_SLICE, mp_obj_new_slice); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + } } STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) { - // TODO this is untested DEBUG_printf("unpack_sequence %d\n", n_args); vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq @@ -1250,13 +1295,12 @@ STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) { } STATIC void emit_native_unpack_ex(emit_t *emit, int n_left, int n_right) { - // TODO this is untested DEBUG_printf("unpack_ex %d %d\n", n_left, n_right); vtype_kind_t vtype_base; emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq assert(vtype_base == VTYPE_PYOBJ); - emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right); // arg3 = dest ptr - emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left + n_right, REG_ARG_2); // arg2 = n_left + n_right + emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right + 1); // arg3 = dest ptr + emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left | (n_right << 8), REG_ARG_2); // arg2 = n_left + n_right } STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { @@ -1365,9 +1409,16 @@ STATIC void emit_native_return_value(emit_t *emit) { } STATIC void emit_native_raise_varargs(emit_t *emit, int n_args) { - // call runtime - assert(0); + assert(n_args == 1); + vtype_kind_t vtype_err; + emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1); // arg1 = object to raise + assert(vtype_err == VTYPE_PYOBJ); + emit_call(emit, 0, mp_make_raise_obj); // TODO need to add function to runtime table + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + emit_pre_pop_reg(emit, &vtype_err, REG_ARG_1); + emit_call(emit, 0, nlr_jump); // TODO need to add function to runtime table } + STATIC void emit_native_yield_value(emit_t *emit) { // not supported (for now) assert(0); @@ -1377,6 +1428,21 @@ STATIC void emit_native_yield_from(emit_t *emit) { assert(0); } +STATIC void emit_native_start_except_handler(emit_t *emit) { + // This instruction follows an nlr_pop, so the stack counter is back to zero, when really + // it should be up by a whole nlr_buf_t. We then want to pop the nlr_buf_t here, but save + // the first 2 elements, so we can get the thrown value. + adjust_stack(emit, 2); + vtype_kind_t vtype_nlr; + emit_pre_pop_reg(emit, &vtype_nlr, REG_ARG_1); // get the thrown value + emit_pre_pop_discard(emit, &vtype_nlr); // discard the linked-list pointer in the nlr_buf + emit_post_push_reg_reg_reg(emit, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1, VTYPE_PYOBJ, REG_ARG_1); // push the 3 exception items +} + +STATIC void emit_native_end_except_handler(emit_t *emit) { + adjust_stack(emit, -3); // stack adjust (not sure why it's this much...) +} + const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_set_viper_types, emit_native_start_pass, @@ -1462,6 +1528,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_raise_varargs, emit_native_yield_value, emit_native_yield_from, + + emit_native_start_except_handler, + emit_native_end_except_handler, }; #endif // (MICROPY_EMIT_X64 && N_X64) || (MICROPY_EMIT_THUMB && N_THUMB) diff --git a/py/emitpass1.c b/py/emitpass1.c index 2e76420a21..b39597318a 100644 --- a/py/emitpass1.c +++ b/py/emitpass1.c @@ -28,8 +28,8 @@ #include <stdint.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" @@ -214,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = { (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, + + (void*)emit_pass1_dummy, + (void*)emit_pass1_dummy, + #if MICROPY_EMIT_CPYTHON (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, @@ -33,7 +33,6 @@ #include "misc.h" #include "gc.h" -#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -113,7 +112,7 @@ STATIC machine_uint_t gc_lock_depth; void gc_init(void *start, void *end) { // align end pointer on block boundary end = (void*)((machine_uint_t)end & (~(BYTES_PER_BLOCK - 1))); - DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, end - start); + DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start); // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes): // T = A + F + P @@ -173,6 +172,10 @@ void gc_unlock(void) { gc_lock_depth--; } +bool gc_is_locked(void) { + return gc_lock_depth != 0; +} + #define VERIFY_PTR(ptr) ( \ (ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \ && ptr >= (machine_uint_t)gc_pool_start /* must be above start of pool */ \ @@ -268,6 +271,7 @@ STATIC void gc_sweep(void) { case AT_TAIL: if (free_tail) { + DEBUG_printf("gc_sweep(%p)\n",PTR_FROM_BLOCK(block)); ATB_ANY_TO_FREE(block); } break; @@ -401,6 +405,7 @@ found: // get pointer to first block void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK); + DEBUG_printf("gc_alloc(%p)\n", ret_ptr); // zero out the additional bytes of the newly allocated blocks // This is needed because the blocks may have previously held pointers @@ -439,6 +444,7 @@ void gc_free(void *ptr_in) { } machine_uint_t ptr = (machine_uint_t)ptr_in; + DEBUG_printf("gc_free(%p)\n", ptr); if (VERIFY_PTR(ptr)) { machine_uint_t block = BLOCK_FROM_PTR(ptr); @@ -590,7 +596,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) { return NULL; } - DEBUG_printf("gc_realloc: allocating new block\n"); + DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out); memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK); gc_free(ptr_in); return ptr_out; @@ -30,6 +30,7 @@ void gc_init(void *start, void *end); // They can be used to prevent the GC from allocating/freeing. void gc_lock(void); void gc_unlock(void); +bool gc_is_locked(void); // A given port must implement gc_collect by using the other collect functions. void gc_collect(void); diff --git a/py/lexer.c b/py/lexer.c index a65df54ba6..8732d64362 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -32,8 +32,8 @@ #include <stdio.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" @@ -502,19 +502,32 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs case 'v': c = 0x0b; break; case 'f': c = 0x0c; break; case 'r': c = 0x0d; break; + case 'u': + case 'U': + if (is_bytes) { + // b'\u1234' == b'\\u1234' + vstr_add_char(&lex->vstr, '\\'); + break; + } + // Otherwise fall through. case 'x': { uint num = 0; - if (!get_hex(lex, 2, &num)) { + if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) { // TODO error message assert(0); } c = num; break; } - case 'N': break; // TODO \N{name} only in strings - case 'u': break; // TODO \uxxxx only in strings - case 'U': break; // TODO \Uxxxxxxxx only in strings + case 'N': + // Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the + // entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly + // 3MB of text; even gzip-compressed and with minimal structure, it'll take + // roughly half a meg of storage. This form of Unicode escape may be added + // later on, but it's definitely not a priority right now. -- CJA 20140607 + assert(!"Unicode name escapes not supported"); + break; default: if (c >= '0' && c <= '7') { // Octal sequence, 1-3 chars @@ -533,7 +546,13 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs } } if (c != MP_LEXER_CHAR_EOF) { - vstr_add_char(&lex->vstr, c); + if (c < 0x110000 && !is_bytes) { + vstr_add_char(&lex->vstr, c); + } else if (c < 0x100 && is_bytes) { + vstr_add_byte(&lex->vstr, c); + } else { + assert(!"TODO: Throw an error, invalid escape code probably"); + } } } else { vstr_add_char(&lex->vstr, CUR_CHAR(lex)); @@ -694,10 +713,10 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs // need to check for this special token in many places in the compiler. // TODO improve speed of these string comparisons //for (int i = 0; tok_kw[i] != NULL; i++) { - for (int i = 0; i < ARRAY_SIZE(tok_kw); i++) { + for (int i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) { if (str_strn_equal(tok_kw[i], tok->str, tok->len)) { - if (i == ARRAY_SIZE(tok_kw) - 1) { - // tok_kw[ARRAY_SIZE(tok_kw) - 1] == "__debug__" + if (i == MP_ARRAY_SIZE(tok_kw) - 1) { + // tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__" tok->kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE); } else { tok->kind = MP_TOKEN_KW_FALSE + i; diff --git a/py/lexerstr.c b/py/lexerstr.c index 76e90671be..666dbfa37c 100644 --- a/py/lexerstr.c +++ b/py/lexerstr.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" diff --git a/py/lexerunix.c b/py/lexerunix.c index 89dc80b004..51bc915b22 100644 --- a/py/lexerunix.c +++ b/py/lexerunix.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #if MICROPY_HELPER_LEXER_UNIX diff --git a/py/malloc.c b/py/malloc.c index b180ddf6b5..8e90849e93 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -28,8 +28,8 @@ #include <stdlib.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #if 0 // print debugging info #define DEBUG_printf DEBUG_printf @@ -27,8 +27,8 @@ #include <stdlib.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" @@ -82,7 +82,7 @@ int m_get_peak_bytes_allocated(void); /** array helpers ***********************************************/ // get the number of elements in a fixed-size array -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /** unichar / UTF-8 *********************************************/ @@ -100,7 +100,9 @@ bool unichar_isupper(unichar c); bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); -#define unichar_charlen(s, bytelen) (bytelen) +machine_uint_t unichar_charlen(const char *str, machine_uint_t len); +#define UTF8_IS_NONASCII(ch) ((ch) & 0x80) +#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) /** variable string *********************************************/ @@ -164,4 +166,18 @@ int DEBUG_printf(const char *fmt, ...); extern uint mp_verbose_flag; +// This is useful for unicode handling. Some CPU archs has +// special instructions for efficient implentation of this +// function (e.g. CLZ on ARM). +// NOTE: this function is unused at the moment +#ifndef count_lead_ones +static inline uint count_lead_ones(byte val) { + uint c = 0; + for (byte mask = 0x80; val & mask; mask >>= 1) { + c++; + } + return c; +} +#endif + #endif // _INCLUDED_MINILIB_H diff --git a/py/mkrules.mk b/py/mkrules.mk index 9592d6c590..6127ece8fe 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -73,9 +73,9 @@ all: $(PROG) $(PROG): $(OBJ) $(ECHO) "LINK $@" - $(Q)$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS) + $(Q)$(CC) $(COPT) -o $@ $(OBJ) $(LIB) $(LDFLAGS) ifndef DEBUG - $(Q)$(STRIP) $(PROG) + $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG) endif $(Q)$(SIZE) $(PROG) @@ -97,4 +97,10 @@ print-cfg: $(ECHO) "OBJ = $(OBJ)" .PHONY: print-cfg +print-def: + @$(ECHO) "The following defines are built into the $(CC) compiler" + touch __empty__.c + @$(CC) -E -Wp,-dM __empty__.c + @$(RM) -f __empty__.c + -include $(OBJ:.o=.P) diff --git a/py/modarray.c b/py/modarray.c index a741a0ecb4..c0fe331643 100644 --- a/py/modarray.c +++ b/py/modarray.c @@ -24,12 +24,14 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" +#if MICROPY_PY_ARRAY + STATIC const mp_map_elem_t mp_module_array_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) }, { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array }, @@ -40,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_array_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_array_globals_table), - .alloc = ARRAY_SIZE(mp_module_array_globals_table), + .used = MP_ARRAY_SIZE(mp_module_array_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_array_globals_table), .table = (mp_map_elem_t*)mp_module_array_globals_table, }, }; @@ -51,3 +53,5 @@ const mp_obj_module_t mp_module_array = { .name = MP_QSTR_array, .globals = (mp_obj_dict_t*)&mp_module_array_globals, }; + +#endif diff --git a/py/modcmath.c b/py/modcmath.c index 3bc3055dc8..ddd8abf71e 100644 --- a/py/modcmath.c +++ b/py/modcmath.c @@ -26,8 +26,8 @@ #include <math.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -142,8 +142,8 @@ STATIC const mp_obj_dict_t mp_module_cmath_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_cmath_globals_table), - .alloc = ARRAY_SIZE(mp_module_cmath_globals_table), + .used = MP_ARRAY_SIZE(mp_module_cmath_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_cmath_globals_table), .table = (mp_map_elem_t*)mp_module_cmath_globals_table, }, }; diff --git a/py/modcollections.c b/py/modcollections.c index 9e3da7e666..5cd0b317a1 100644 --- a/py/modcollections.c +++ b/py/modcollections.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -42,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_collections_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_collections_globals_table), - .alloc = ARRAY_SIZE(mp_module_collections_globals_table), + .used = MP_ARRAY_SIZE(mp_module_collections_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_collections_globals_table), .table = (mp_map_elem_t*)mp_module_collections_globals_table, }, }; diff --git a/py/modgc.c b/py/modgc.c index c53eed235f..4ffdc2be68 100644 --- a/py/modgc.c +++ b/py/modgc.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -61,11 +61,27 @@ STATIC mp_obj_t gc_enable(void) { } MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable); +STATIC mp_obj_t gc_mem_free(void) { + gc_info_t info; + gc_info(&info); + return MP_OBJ_NEW_SMALL_INT((machine_uint_t)info.free); +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free); + +STATIC mp_obj_t gc_mem_alloc(void) { + gc_info_t info; + gc_info(&info); + return MP_OBJ_NEW_SMALL_INT((machine_uint_t)info.used); +} +MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc); + STATIC const mp_map_elem_t mp_module_gc_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gc) }, { MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj }, }; STATIC const mp_obj_dict_t mp_module_gc_globals = { @@ -73,8 +89,8 @@ STATIC const mp_obj_dict_t mp_module_gc_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_gc_globals_table), - .alloc = ARRAY_SIZE(mp_module_gc_globals_table), + .used = MP_ARRAY_SIZE(mp_module_gc_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_gc_globals_table), .table = (mp_map_elem_t*)mp_module_gc_globals_table, }, }; diff --git a/py/modio.c b/py/modio.c index 08c6c59dd9..ef3b29b53f 100644 --- a/py/modio.c +++ b/py/modio.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -57,8 +57,8 @@ STATIC const mp_obj_dict_t mp_module_io_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_io_globals_table), - .alloc = ARRAY_SIZE(mp_module_io_globals_table), + .used = MP_ARRAY_SIZE(mp_module_io_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_io_globals_table), .table = (mp_map_elem_t*)mp_module_io_globals_table, }, }; diff --git a/py/modmath.c b/py/modmath.c index 0fd583c2ff..0d0d13b4e2 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -26,8 +26,8 @@ #include <math.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -172,8 +172,8 @@ STATIC const mp_obj_dict_t mp_module_math_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_math_globals_table), - .alloc = ARRAY_SIZE(mp_module_math_globals_table), + .used = MP_ARRAY_SIZE(mp_module_math_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_math_globals_table), .table = (mp_map_elem_t*)mp_module_math_globals_table, }, }; diff --git a/py/modmicropython.c b/py/modmicropython.c index 40d749da2d..bbb315189b 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -65,8 +65,8 @@ STATIC const mp_obj_dict_t mp_module_micropython_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_micropython_globals_table), - .alloc = ARRAY_SIZE(mp_module_micropython_globals_table), + .used = MP_ARRAY_SIZE(mp_module_micropython_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_micropython_globals_table), .table = (mp_map_elem_t*)mp_module_micropython_globals_table, }, }; diff --git a/py/modstruct.c b/py/modstruct.c index a45181852c..2e40264e8d 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -27,8 +27,8 @@ #include <assert.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -210,8 +210,8 @@ STATIC const mp_obj_dict_t mp_module_struct_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_struct_globals_table), - .alloc = ARRAY_SIZE(mp_module_struct_globals_table), + .used = MP_ARRAY_SIZE(mp_module_struct_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_struct_globals_table), .table = (mp_map_elem_t*)mp_module_struct_globals_table, }, }; diff --git a/py/modsys.c b/py/modsys.c index a99db1b7f8..1e7f7eff7f 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "builtin.h" @@ -87,8 +87,8 @@ STATIC const mp_obj_dict_t mp_module_sys_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_sys_globals_table), - .alloc = ARRAY_SIZE(mp_module_sys_globals_table), + .used = MP_ARRAY_SIZE(mp_module_sys_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_sys_globals_table), .table = (mp_map_elem_t*)mp_module_sys_globals_table, }, }; diff --git a/py/mpconfig.h b/py/mpconfig.h index 93e98c25b6..3a9d342ea3 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -157,6 +157,12 @@ #define MICROPY_ENABLE_GC_FINALISER (0) #endif +// Whether to check C stack usage. C stack used for calling Python functions, +// etc. Not checking means segfault on overflow. +#ifndef MICROPY_STACK_CHECK +#define MICROPY_STACK_CHECK (1) +#endif + // Whether to include REPL helper function #ifndef MICROPY_HELPER_REPL #define MICROPY_HELPER_REPL (0) @@ -223,6 +229,10 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_FLOAT (0) #endif +#ifndef MICROPY_PY_BUILTINS_COMPLEX +#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT) +#endif + // Enable features which improve CPython compatibility // but may lead to more code size/memory usage. // TODO: Originally intended as generic category to not @@ -239,6 +249,16 @@ typedef double mp_float_t; /*****************************************************************************/ /* Fine control over Python builtins, classes, modules, etc */ +// Whether str object is proper unicode +#ifndef MICROPY_PY_BUILTINS_STR_UNICODE +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#endif + +// Whether to support bytearray object +#ifndef MICROPY_PY_BUILTINS_BYTEARRAY +#define MICROPY_PY_BUILTINS_BYTEARRAY (1) +#endif + // Whether to support set object #ifndef MICROPY_PY_BUILTINS_SET #define MICROPY_PY_BUILTINS_SET (1) @@ -259,6 +279,13 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_PROPERTY (1) #endif +// Whether to provide "array" module. Note that large chunk of the +// underlying code is shared with "bytearray" builtin type, so to +// get real savings, it should be disabled too. +#ifndef MICROPY_PY_ARRAY +#define MICROPY_PY_ARRAY (1) +#endif + // Whether to provide "collections" module #ifndef MICROPY_PY_COLLECTIONS #define MICROPY_PY_COLLECTIONS (1) @@ -377,3 +404,8 @@ typedef double mp_float_t; #ifndef NORETURN #define NORETURN __attribute__((noreturn)) #endif + +// Modifier for weak functions +#ifndef MP_WEAK +#define MP_WEAK __attribute__((weak)) +#endif @@ -30,8 +30,8 @@ #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "mpz.h" #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ @@ -29,6 +29,7 @@ #include <limits.h> #include <setjmp.h> +#include <assert.h> typedef struct _nlr_buf_t nlr_buf_t; struct _nlr_buf_t { @@ -44,7 +45,7 @@ struct _nlr_buf_t { #else void *regs[8]; #endif -#elif defined(__thumb2__) +#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) void *regs[10]; #else #define MICROPY_NLR_SETJMP (1) diff --git a/py/nlrthumb.S b/py/nlrthumb.S index b306c01753..dabf57cf85 100644 --- a/py/nlrthumb.S +++ b/py/nlrthumb.S @@ -24,19 +24,21 @@ * THE SOFTWARE. */ -#if defined(__thumb2__) && !MICROPY_NLR_SETJMP -/* thumb callee save: bx, bp, sp, r12, r14, r14, r15 */ +#if !MICROPY_NLR_SETJMP && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +/* arm callee save: bx, bp, sp, r12, r14, r14, r15 */ .syntax unified /*.cpu cortex-m4*/ - .thumb + /*.thumb*/ .text .align 2 /* uint nlr_push(r0=nlr_buf_t *nlr) */ .global nlr_push +#if defined(__thumb2__) .thumb .thumb_func +#endif .type nlr_push, %function nlr_push: str lr, [r0, #8] @ store lr into nlr_buf @@ -64,8 +66,10 @@ nlr_push: @ void nlr_pop() .global nlr_pop +#if defined(__thumb2__) .thumb .thumb_func +#endif .type nlr_pop, %function nlr_pop: ldr r3, .L5 @ load addr of nlr_top @@ -80,8 +84,10 @@ nlr_pop: /* void nlr_jump(r0=uint val) */ .global nlr_jump +#if defined(__thumb2__) .thumb .thumb_func +#endif .type nlr_jump, %function nlr_jump: ldr r3, .L2 @ load addr of nlr_top @@ -35,6 +35,7 @@ #include "obj.h" #include "runtime0.h" #include "runtime.h" +#include "stackctrl.h" mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) { if (MP_OBJ_IS_SMALL_INT(o_in)) { @@ -59,6 +60,8 @@ void printf_wrapper(void *env, const char *fmt, ...) { } void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { + // There can be data structures nested too deep, or just recursive + MP_STACK_CHECK(); #if !NDEBUG if (o_in == NULL) { print(env, "(nil)"); @@ -274,6 +277,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { } } +#if MICROPY_PY_BUILTINS_COMPLEX void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { if (arg == mp_const_false) { *real = 0; @@ -297,6 +301,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { } } #endif +#endif void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) { if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) { @@ -352,7 +357,12 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index, // may return MP_OBJ_NULL mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) { - if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { + if ( +#if !MICROPY_PY_BUILTINS_STR_UNICODE + // It's simple - unicode is slow, non-unicode is fast + MP_OBJ_IS_STR(o_in) || +#endif + MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) { return MP_OBJ_NEW_SMALL_INT((machine_int_t)mp_obj_str_get_len(o_in)); } else { mp_obj_type_t *type = mp_obj_get_type(o_in); diff --git a/py/objarray.c b/py/objarray.c index 05821e8de4..b13df2bdba 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -37,6 +37,8 @@ #include "runtime.h" #include "binary.h" +#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY + typedef struct _mp_obj_array_t { mp_obj_base_t base; machine_uint_t typecode : 8; @@ -310,3 +312,5 @@ STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) { o->cur = 0; return o; } + +#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY diff --git a/py/objcomplex.c b/py/objcomplex.c index d58b53463c..20e7c97d37 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -36,7 +36,7 @@ #include "runtime0.h" #include "runtime.h" -#if MICROPY_PY_BUILTINS_FLOAT +#if MICROPY_PY_BUILTINS_COMPLEX #include <math.h> diff --git a/py/objenumerate.c b/py/objenumerate.c index 7d9ea9915a..37414464de 100644 --- a/py/objenumerate.c +++ b/py/objenumerate.c @@ -27,8 +27,8 @@ #include <stdlib.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -45,7 +45,7 @@ STATIC const mp_arg_t enumerate_make_new_args[] = { { MP_QSTR_iterable, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_start, MP_ARG_INT, {.u_int = 0} }, }; -#define ENUMERATE_MAKE_NEW_NUM_ARGS ARRAY_SIZE(enumerate_make_new_args) +#define ENUMERATE_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(enumerate_make_new_args) STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { #if MICROPY_CPYTHON_COMPAT diff --git a/py/objexcept.c b/py/objexcept.c index 9f421373bb..ad66bb50fe 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -37,6 +37,7 @@ #include "objtype.h" #include "runtime.h" #include "runtime0.h" +#include "gc.h" typedef struct _mp_obj_exception_t { mp_obj_base_t base; @@ -335,6 +336,13 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in) { } void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) { + #if MICROPY_ENABLE_GC + if (gc_is_locked()) { + // We can't allocate memory, so don't bother to try + return; + } + #endif + GET_NATIVE_EXCEPTION(self, self_in); // for traceback, we are just using the list object for convenience, it's not really a list of Python objects diff --git a/py/objfloat.c b/py/objfloat.c index b608b1a3d7..e3fefad8db 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -102,9 +102,12 @@ STATIC mp_obj_t float_unary_op(int op, mp_obj_t o_in) { STATIC mp_obj_t float_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_float_t *lhs = lhs_in; +#if MICROPY_PY_BUILTINS_COMPLEX if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, lhs->value, 0, rhs_in); - } else { + } else +#endif + { return mp_obj_float_binary_op(op, lhs->value, rhs_in); } } diff --git a/py/objfun.c b/py/objfun.c index 29363129b2..74e959f9d3 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -39,6 +39,7 @@ #include "runtime0.h" #include "runtime.h" #include "bc.h" +#include "stackctrl.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -204,6 +205,8 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui // code_state should have ->ip filled in (pointing past code info block), // as well as ->n_state. void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // This function is pretty complicated. It's main aim is to be efficient in speed and RAM + // usage for the common case of positional only args. mp_obj_fun_bc_t *self = self_in; machine_uint_t n_state = code_state->n_state; const byte *ip = code_state->ip; @@ -353,8 +356,7 @@ continue2:; STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { - // This function is pretty complicated. It's main aim is to be efficient in speed and RAM - // usage for the common case of positional only args. + MP_STACK_CHECK(); DEBUG_printf("Input n_args: %d, n_kw: %d\n", n_args, n_kw); DEBUG_printf("Input pos args: "); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 516fb52746..cf7896f9e1 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -121,9 +121,11 @@ mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { #if MICROPY_PY_BUILTINS_FLOAT } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_float)) { return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in); +#if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_complex)) { return mp_obj_complex_binary_op(op, mpz_as_float(zlhs), 0, rhs_in); #endif +#endif } else { // delegate to generic function to check for extra cases return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); diff --git a/py/objstr.c b/py/objstr.c index c84d7c900d..b13517b63d 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -32,6 +32,7 @@ #include "mpconfig.h" #include "nlr.h" #include "misc.h" +#include "unicode.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" @@ -43,16 +44,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t *args, mp_obj_t dict); const mp_obj_t mp_const_empty_bytes; -// use this macro to extract the string hash -#define GET_STR_HASH(str_obj_in, str_hash) uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; } - -// use this macro to extract the string length -#define GET_STR_LEN(str_obj_in, str_len) uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; } - -// use this macro to extract the string data and length -#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; } - -STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str); +mp_obj_t mp_obj_new_str_iterator(mp_obj_t str); STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str); STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); STATIC NORETURN void arg_type_mixup(); @@ -259,7 +251,7 @@ STATIC const byte *find_subbytes(const byte *haystack, machine_uint_t hlen, cons return NULL; } -STATIC mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { +mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { GET_STR_DATA_LEN(lhs_in, lhs_data, lhs_len); mp_obj_type_t *lhs_type = mp_obj_get_type(lhs_in); mp_obj_type_t *rhs_type = mp_obj_get_type(rhs_in); @@ -352,11 +344,14 @@ uncomparable: return MP_OBJ_NULL; // op not supported } +#if !MICROPY_PY_BUILTINS_STR_UNICODE +// objstrunicode defines own version const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len, mp_obj_t index, bool is_slice) { machine_uint_t index_val = mp_get_index(type, self_len, index, is_slice); return self_data + index_val; } +#endif STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_type_t *type = mp_obj_get_type(self_in); @@ -571,7 +566,6 @@ STATIC mp_obj_t str_rsplit(uint n_args, const mp_obj_t *args) { return res; } - STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t direction, bool is_index) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); assert(2 <= n_args && n_args <= 4); @@ -600,6 +594,11 @@ STATIC mp_obj_t str_finder(uint n_args, const mp_obj_t *args, machine_int_t dire } } else { // found + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (self_type == &mp_type_str) { + return MP_OBJ_NEW_SMALL_INT(utf8_ptr_to_index(haystack, p)); + } + #endif return MP_OBJ_NEW_SMALL_INT(p - haystack); } } @@ -1610,7 +1609,7 @@ STATIC mp_obj_t str_encode(uint n_args, const mp_obj_t *args) { } #endif -STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) { +machine_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags) { if (flags == MP_BUFFER_READ) { GET_STR_DATA_LEN(self_in, str_data, str_len); bufinfo->buf = (void*)str_data; @@ -1627,38 +1626,45 @@ STATIC machine_int_t str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, } #if MICROPY_CPYTHON_COMPAT -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_decode_obj, 1, 3, bytes_decode); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj, 1, 3, str_encode); #endif -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj, 2, 4, str_find); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj, 2, 4, str_rfind); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj, 2, 4, str_index); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex); +MP_DEFINE_CONST_FUN_OBJ_2(str_join_obj, str_join); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj, 1, 3, str_split); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj, 1, 3, str_rsplit); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj, 1, 2, str_lstrip); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj, 1, 2, str_rstrip); +MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, mp_obj_str_format); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count); +MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); +MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); +MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); +MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); +MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); +MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha); +MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit); +MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper); +MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); STATIC const mp_map_elem_t str_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT { MP_OBJ_NEW_QSTR(MP_QSTR_decode), (mp_obj_t)&bytes_decode_obj }, + #if !MICROPY_PY_BUILTINS_STR_UNICODE + // If we have separate unicode type, then here we have methods only + // for bytes type, and it should not have encode() methods. Otherwise, + // we have non-compliant-but-practical bytestring type, which shares + // method table with bytes, so they both have encode() and decode() + // methods (which should do type checking at runtime). { MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj }, + #endif #endif { MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj }, @@ -1688,17 +1694,19 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table); +#if !MICROPY_PY_BUILTINS_STR_UNICODE const mp_obj_type_t mp_type_str = { { &mp_type_type }, .name = MP_QSTR_str, .print = str_print, .make_new = str_make_new, - .binary_op = str_binary_op, + .binary_op = mp_obj_str_binary_op, .subscr = str_subscr, .getiter = mp_obj_new_str_iterator, - .buffer_p = { .get_buffer = str_get_buffer }, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, .locals_dict = (mp_obj_t)&str_locals_dict, }; +#endif // Reuses most of methods from str const mp_obj_type_t mp_type_bytes = { @@ -1706,10 +1714,10 @@ const mp_obj_type_t mp_type_bytes = { .name = MP_QSTR_bytes, .print = str_print, .make_new = bytes_make_new, - .binary_op = str_binary_op, + .binary_op = mp_obj_str_binary_op, .subscr = str_subscr, .getiter = mp_obj_new_bytes_iterator, - .buffer_p = { .get_buffer = str_get_buffer }, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, .locals_dict = (mp_obj_t)&str_locals_dict, }; @@ -1866,6 +1874,7 @@ typedef struct _mp_obj_str_it_t { machine_uint_t cur; } mp_obj_str_it_t; +#if !MICROPY_PY_BUILTINS_STR_UNICODE STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str_it_t *self = self_in; GET_STR_DATA_LEN(self->str, str, len); @@ -1885,6 +1894,15 @@ STATIC const mp_obj_type_t mp_type_str_it = { .iternext = str_it_iternext, }; +mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) { + mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t); + o->base.type = &mp_type_str_it; + o->str = str; + o->cur = 0; + return o; +} +#endif + STATIC mp_obj_t bytes_it_iternext(mp_obj_t self_in) { mp_obj_str_it_t *self = self_in; GET_STR_DATA_LEN(self->str, str, len); @@ -1904,14 +1922,6 @@ STATIC const mp_obj_type_t mp_type_bytes_it = { .iternext = bytes_it_iternext, }; -mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) { - mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t); - o->base.type = &mp_type_str_it; - o->str = str; - o->cur = 0; - return o; -} - mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str) { mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t); o->base.type = &mp_type_bytes_it; diff --git a/py/objstr.h b/py/objstr.h index 5be137d36d..515890c6e1 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -35,5 +35,53 @@ typedef struct _mp_obj_str_t { #define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str}; +// use this macro to extract the string hash +#define GET_STR_HASH(str_obj_in, str_hash) \ + uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; } + +// use this macro to extract the string length +#define GET_STR_LEN(str_obj_in, str_len) \ + uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_len = qstr_len(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_len = ((mp_obj_str_t*)str_obj_in)->len; } + +// use this macro to extract the string data and length +#define GET_STR_DATA_LEN(str_obj_in, str_data, str_len) \ + const byte *str_data; uint str_len; if (MP_OBJ_IS_QSTR(str_obj_in)) \ + { str_data = qstr_data(MP_OBJ_QSTR_VALUE(str_obj_in), &str_len); } \ + else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; } + mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, uint len); + +mp_obj_t mp_obj_str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); +machine_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, int flags); + +const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len, + mp_obj_t index, bool is_slice); + +MP_DECLARE_CONST_FUN_OBJ(str_encode_obj); +MP_DECLARE_CONST_FUN_OBJ(str_find_obj); +MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj); +MP_DECLARE_CONST_FUN_OBJ(str_index_obj); +MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj); +MP_DECLARE_CONST_FUN_OBJ(str_join_obj); +MP_DECLARE_CONST_FUN_OBJ(str_split_obj); +MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj); +MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj); +MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj); +MP_DECLARE_CONST_FUN_OBJ(str_strip_obj); +MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj); +MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj); +MP_DECLARE_CONST_FUN_OBJ(str_format_obj); +MP_DECLARE_CONST_FUN_OBJ(str_replace_obj); +MP_DECLARE_CONST_FUN_OBJ(str_count_obj); +MP_DECLARE_CONST_FUN_OBJ(str_partition_obj); +MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ(str_lower_obj); +MP_DECLARE_CONST_FUN_OBJ(str_upper_obj); +MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj); +MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj); +MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj); +MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj); +MP_DECLARE_CONST_FUN_OBJ(str_islower_obj); diff --git a/py/objstrunicode.c b/py/objstrunicode.c new file mode 100644 index 0000000000..d96ce0a552 --- /dev/null +++ b/py/objstrunicode.c @@ -0,0 +1,359 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * 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 <stdbool.h> +#include <string.h> +#include <assert.h> + +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "runtime0.h" +#include "runtime.h" +#include "pfenv.h" +#include "objstr.h" +#include "objlist.h" + +#if MICROPY_PY_BUILTINS_STR_UNICODE + +STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str); + +/******************************************************************************/ +/* str */ + +STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) { + // this escapes characters, but it will be very slow to print (calling print many times) + bool has_single_quote = false; + bool has_double_quote = false; + for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { + if (*s == '\'') { + has_single_quote = true; + } else if (*s == '"') { + has_double_quote = true; + } + } + int quote_char = '\''; + if (has_single_quote && !has_double_quote) { + quote_char = '"'; + } + print(env, "%c", quote_char); + const byte *s = str_data, *top = str_data + str_len; + while (s < top) { + unichar ch; + ch = utf8_get_char(s); + s = utf8_next_char(s); + if (ch == quote_char) { + print(env, "\\%c", quote_char); + } else if (ch == '\\') { + print(env, "\\\\"); + } else if (32 <= ch && ch <= 126) { + print(env, "%c", ch); + } else if (ch == '\n') { + print(env, "\\n"); + } else if (ch == '\r') { + print(env, "\\r"); + } else if (ch == '\t') { + print(env, "\\t"); + } else if (ch < 0x100) { + print(env, "\\x%02x", ch); + } else if (ch < 0x10000) { + print(env, "\\u%04x", ch); + } else { + print(env, "\\U%08x", ch); + } + } + print(env, "%c", quote_char); +} + +STATIC void uni_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + if (kind == PRINT_STR) { + print(env, "%.*s", str_len, str_data); + } else { + uni_print_quoted(print, env, str_data, str_len); + } +} + +STATIC mp_obj_t uni_unary_op(int op, mp_obj_t self_in) { + GET_STR_DATA_LEN(self_in, str_data, str_len); + switch (op) { + case MP_UNARY_OP_BOOL: + return MP_BOOL(str_len != 0); + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len)); + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +#if MICROPY_CPYTHON_COMPAT + if (n_kw != 0) { + mp_arg_error_unimpl_kw(); + } +#endif + + switch (n_args) { + case 0: + return MP_OBJ_NEW_QSTR(MP_QSTR_); + + case 1: + { + vstr_t *vstr = vstr_new(); + mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR); + mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false); + vstr_free(vstr); + return s; + } + + case 2: + case 3: + { + // TODO: validate 2nd/3rd args + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected")); + } + GET_STR_DATA_LEN(args[0], str_data, str_len); + GET_STR_HASH(args[0], str_hash); + mp_obj_str_t *o = mp_obj_new_str_of_type(&mp_type_str, NULL, str_len); + o->data = str_data; + o->hash = str_hash; + return o; + } + + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments")); + } +} + +// Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or +// be capped to the first/last character of the string, depending on is_slice. +const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, uint self_len, + mp_obj_t index, bool is_slice) { + machine_int_t i; + // Copied from mp_get_index; I don't want bounds checking, just give me + // the integer as-is. (I can't bounds-check without scanning the whole + // string; an out-of-bounds index will be caught in the loops below.) + if (MP_OBJ_IS_SMALL_INT(index)) { + i = MP_OBJ_SMALL_INT_VALUE(index); + } else if (!mp_obj_get_int_maybe(index, &i)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); + } + const byte *s, *top = self_data + self_len; + if (i < 0) + { + // Negative indexing is performed by counting from the end of the string. + for (s = top - 1; i; --s) { + if (s < self_data) { + if (is_slice) { + return self_data; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range")); + } + if (!UTF8_IS_CONT(*s)) { + ++i; + } + } + ++s; + } else if (!i) { + return self_data; // Shortcut - str[0] is its base pointer + } else { + // Positive indexing, correspondingly, counts from the start of the string. + // It's assumed that negative indexing will generally be used with small + // absolute values (eg str[-1], not str[-1000000]), which means it'll be + // more efficient this way. + for (s = self_data; true; ++s) { + if (s >= top) { + if (is_slice) { + return top; + } + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "string index out of range")); + } + while (UTF8_IS_CONT(*s)) { + ++s; + } + if (!i--) { + return s; + } + } + } + return s; +} + +STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_type_t *type = mp_obj_get_type(self_in); + GET_STR_DATA_LEN(self_in, self_data, self_len); + if (value == MP_OBJ_SENTINEL) { + // load +#if MICROPY_PY_BUILTINS_SLICE + if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + mp_obj_t ostart, ostop, ostep; + mp_obj_slice_get(index, &ostart, &ostop, &ostep); + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, + "only slices with step=1 (aka None) are supported")); + } + + if (type == &mp_type_bytes) { + machine_int_t start = 0, stop = self_len; + if (ostart != mp_const_none) { + start = MP_OBJ_SMALL_INT_VALUE(ostart); + if (start < 0) { + start = self_len + start; + } + } + if (ostop != mp_const_none) { + stop = MP_OBJ_SMALL_INT_VALUE(ostop); + if (stop < 0) { + stop = self_len + stop; + } + } + return mp_obj_new_str_of_type(type, self_data + start, stop - start); + } + const byte *pstart, *pstop; + if (ostart != mp_const_none) { + pstart = str_index_to_ptr(type, self_data, self_len, ostart, true); + } else { + pstart = self_data; + } + if (ostop != mp_const_none) { + // pstop will point just after the stop character. This depends on + // the \0 at the end of the string. + pstop = str_index_to_ptr(type, self_data, self_len, ostop, true); + } else { + pstop = self_data + self_len; + } + if (pstop < pstart) { + return MP_OBJ_NEW_QSTR(MP_QSTR_); + } + return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart); + } +#endif + if (type == &mp_type_bytes) { + uint index_val = mp_get_index(type, self_len, index, false); + return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self_data[index_val]); + } + const byte *s = str_index_to_ptr(type, self_data, self_len, index, false); + int len = 1; + if (UTF8_IS_NONASCII(*s)) { + // Count the number of 1 bits (after the first) + for (char mask = 0x40; *s & mask; mask >>= 1) { + ++len; + } + } + return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string + } else { + return MP_OBJ_NULL; // op not supported + } +} + +STATIC const mp_map_elem_t str_locals_dict_table[] = { +#if MICROPY_CPYTHON_COMPAT + { MP_OBJ_NEW_QSTR(MP_QSTR_encode), (mp_obj_t)&str_encode_obj }, +#endif + { MP_OBJ_NEW_QSTR(MP_QSTR_find), (mp_obj_t)&str_find_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rfind), (mp_obj_t)&str_rfind_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&str_index_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rindex), (mp_obj_t)&str_rindex_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_join), (mp_obj_t)&str_join_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t)&str_split_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rsplit), (mp_obj_t)&str_rsplit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_startswith), (mp_obj_t)&str_startswith_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_endswith), (mp_obj_t)&str_endswith_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_strip), (mp_obj_t)&str_strip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_lstrip), (mp_obj_t)&str_lstrip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rstrip), (mp_obj_t)&str_rstrip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&str_format_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_replace), (mp_obj_t)&str_replace_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_count), (mp_obj_t)&str_count_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_partition), (mp_obj_t)&str_partition_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table); + +const mp_obj_type_t mp_type_str = { + { &mp_type_type }, + .name = MP_QSTR_str, + .print = uni_print, + .make_new = str_make_new, + .unary_op = uni_unary_op, + .binary_op = mp_obj_str_binary_op, + .subscr = str_subscr, + .getiter = mp_obj_new_str_iterator, + .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, + .locals_dict = (mp_obj_t)&str_locals_dict, +}; + +/******************************************************************************/ +/* str iterator */ + +typedef struct _mp_obj_str_it_t { + mp_obj_base_t base; + mp_obj_t str; + machine_uint_t cur; +} mp_obj_str_it_t; + +STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { + mp_obj_str_it_t *self = self_in; + GET_STR_DATA_LEN(self->str, str, len); + if (self->cur < len) { + const byte *cur = str + self->cur; + const byte *end = utf8_next_char(str + self->cur); + mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true); + self->cur += end - cur; + return o_out; + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +STATIC const mp_obj_type_t mp_type_str_it = { + { &mp_type_type }, + .name = MP_QSTR_iterator, + .getiter = mp_identity, + .iternext = str_it_iternext, +}; + +mp_obj_t mp_obj_new_str_iterator(mp_obj_t str) { + mp_obj_str_it_t *o = m_new_obj(mp_obj_str_it_t); + o->base.type = &mp_type_str_it; + o->str = str; + o->cur = 0; + return o; +} + +#endif // MICROPY_PY_BUILTINS_STR_UNICODE diff --git a/py/parse.c b/py/parse.c index af09c335f2..492c1678b5 100644 --- a/py/parse.c +++ b/py/parse.c @@ -30,8 +30,8 @@ #include <assert.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parsenumbase.h" diff --git a/py/parsehelper.c b/py/parsehelper.c index 3ead5a3031..105afe711e 100644 --- a/py/parsehelper.c +++ b/py/parsehelper.c @@ -29,8 +29,8 @@ #include <stdint.h> #include <stdio.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "parse.h" diff --git a/py/parsenum.c b/py/parsenum.c index 1c1868ae0a..b9801ab6a1 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -27,14 +27,15 @@ #include <stdbool.h> #include <stdlib.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "nlr.h" #include "obj.h" #include "parsenumbase.h" #include "parsenum.h" #include "smallint.h" +#include "runtime.h" #if MICROPY_PY_BUILTINS_FLOAT #include <math.h> @@ -252,10 +253,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool f } // return the object +#if MICROPY_PY_BUILTINS_COMPLEX if (imag) { return mp_obj_new_complex(0, dec_val); } else if (force_complex) { return mp_obj_new_complex(dec_val, 0); +#else + if (imag || force_complex) { + mp_not_implemented("complex values not supported"); +#endif } else { return mp_obj_new_float(dec_val); } diff --git a/py/parsenumbase.c b/py/parsenumbase.c index ce140655bd..4fddac9c3d 100644 --- a/py/parsenumbase.c +++ b/py/parsenumbase.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "parsenumbase.h" // find real radix base, and strip preceding '0x', '0o' and '0b' diff --git a/py/pfenv.c b/py/pfenv.c index e631f8654a..ca1e3e919b 100644 --- a/py/pfenv.c +++ b/py/pfenv.c @@ -27,8 +27,8 @@ #include <stdint.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "mpz.h" @@ -43,6 +43,7 @@ PY_O_BASENAME = \ parsenum.o \ emitglue.o \ runtime.o \ + stackctrl.o \ argcheck.o \ map.o \ obj.o \ @@ -74,6 +75,7 @@ PY_O_BASENAME = \ objset.o \ objslice.o \ objstr.o \ + objstrunicode.o \ objstringio.o \ objtuple.o \ objtype.o \ @@ -27,8 +27,8 @@ #include <assert.h> #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" // NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 856853fa55..4ff9ca87c8 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -377,6 +377,8 @@ Q(gc) Q(collect) Q(disable) Q(enable) +Q(mem_free) +Q(mem_alloc) #endif #if MICROPY_PY_BUILTINS_PROPERTY @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "repl.h" #if MICROPY_HELPER_REPL diff --git a/py/runtime.c b/py/runtime.c index d57bb686d1..5490bcbac5 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -45,6 +45,7 @@ #include "smallint.h" #include "objgenerator.h" #include "lexer.h" +#include "stackctrl.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -69,6 +70,8 @@ const mp_obj_module_t mp_module___main__ = { }; void mp_init(void) { + mp_stack_ctrl_init(); + // call port specific initialization if any #ifdef MICROPY_PORT_INIT_FUNC MICROPY_PORT_INIT_FUNC; @@ -426,6 +429,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } else { return res; } +#if MICROPY_PY_BUILTINS_COMPLEX } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) { mp_obj_t res = mp_obj_complex_binary_op(op, lhs_val, 0, rhs); if (res == MP_OBJ_NULL) { @@ -434,6 +438,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return res; } #endif +#endif } } diff --git a/py/scope.c b/py/scope.c index 839e8216c1..83c2b6e07c 100644 --- a/py/scope.c +++ b/py/scope.c @@ -29,8 +29,8 @@ #include <stdio.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "parse.h" diff --git a/py/smallint.c b/py/smallint.c index 5543f126c3..c57f364e36 100644 --- a/py/smallint.c +++ b/py/smallint.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "smallint.h" diff --git a/py/stackctrl.c b/py/stackctrl.c new file mode 100644 index 0000000000..724d54a1be --- /dev/null +++ b/py/stackctrl.c @@ -0,0 +1,63 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * 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 "mpconfig.h" +#include "misc.h" +#include "nlr.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include "stackctrl.h" + +// Stack top at the start of program +char *stack_top; + +void mp_stack_ctrl_init() { + volatile int stack_dummy; + stack_top = (char*)&stack_dummy; +} + +uint mp_stack_usage() { + // Assumes descending stack + volatile int stack_dummy; + return stack_top - (char*)&stack_dummy; +} + +#if MICROPY_STACK_CHECK + +static uint stack_limit = 10240; + +void mp_stack_set_limit(uint limit) { + stack_limit = limit; +} + +void mp_stack_check() { + if (mp_stack_usage() >= stack_limit) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "maximum recursion depth exceeded")); + } +} + +#endif // MICROPY_STACK_CHECK diff --git a/py/stackctrl.h b/py/stackctrl.h new file mode 100644 index 0000000000..92de882bfa --- /dev/null +++ b/py/stackctrl.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +void mp_stack_ctrl_init(); +uint mp_stack_usage(); + +#if MICROPY_STACK_CHECK + +void mp_stack_set_limit(uint limit); +void mp_stack_check(); +#define MP_STACK_CHECK() mp_stack_check() + +#else + +#define mp_stack_set_limit(limit) +#define MP_STACK_CHECK() + +#endif diff --git a/py/stream.c b/py/stream.c index 07a79248ab..cfdea15cca 100644 --- a/py/stream.c +++ b/py/stream.c @@ -33,9 +33,13 @@ #include "qstr.h" #include "obj.h" #include "objstr.h" +#include "runtime.h" #include "stream.h" #if MICROPY_STREAMS_NON_BLOCK #include <errno.h> +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#define EWOULDBLOCK 140 +#endif #endif // This file defines generic Python stream read/write methods which @@ -67,6 +71,13 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) { if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) { return stream_readall(args[0]); } + + #if MICROPY_PY_BUILTINS_STR_UNICODE + if (!o->type->stream_p->is_bytes) { + mp_not_implemented("Reading from unicode text streams by character count"); + } + #endif + byte *buf = m_new(byte, sz); int error; machine_int_t out_sz = o->type->stream_p->read(o, buf, sz, &error); diff --git a/py/unicode.c b/py/unicode.c index c8faa57009..d69e81c8e0 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -26,8 +26,8 @@ #include <stdint.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" // attribute flags #define FL_PRINT (0x01) @@ -65,14 +65,65 @@ STATIC const uint8_t attr[] = { AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0 }; +// TODO: Rename to str_get_char unichar utf8_get_char(const byte *s) { +#if MICROPY_PY_BUILTINS_STR_UNICODE + unichar ord = *s++; + if (!UTF8_IS_NONASCII(ord)) return ord; + ord &= 0x7F; + for (unichar mask = 0x40; ord & mask; mask >>= 1) { + ord &= ~mask; + } + while (UTF8_IS_CONT(*s)) { + ord = (ord << 6) | (*s++ & 0x3F); + } + return ord; +#else return *s; +#endif } +// TODO: Rename to str_next_char const byte *utf8_next_char(const byte *s) { +#if MICROPY_PY_BUILTINS_STR_UNICODE + ++s; + while (UTF8_IS_CONT(*s)) { + ++s; + } + return s; +#else return s + 1; +#endif +} + +machine_uint_t utf8_ptr_to_index(const char *s, const char *ptr) { + machine_uint_t i = 0; + while (ptr > s) { + if (!UTF8_IS_CONT(*--ptr)) { + i++; + } + } + + return i; +} + +// TODO: Rename to str_charlen +machine_uint_t unichar_charlen(const char *str, machine_uint_t len) +{ +#if MICROPY_PY_BUILTINS_STR_UNICODE + machine_uint_t charlen = 0; + for (const char *top = str + len; str < top; ++str) { + if (!UTF8_IS_CONT(*str)) { + ++charlen; + } + } + return charlen; +#else + return len; +#endif } +// Be aware: These unichar_is* functions are actually ASCII-only! bool unichar_isspace(unichar c) { return c < 128 && (attr[c] & FL_SPACE) != 0; } diff --git a/py/unicode.h b/py/unicode.h new file mode 100644 index 0000000000..2468b2fecf --- /dev/null +++ b/py/unicode.h @@ -0,0 +1 @@ +machine_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr); @@ -29,8 +29,8 @@ #include <stdarg.h> #include <string.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" // returned value is always at least 1 greater than argument #define ROUND_ALLOC(a) (((a) & ((~0) - 7)) + 8) @@ -199,12 +199,48 @@ void vstr_add_byte(vstr_t *vstr, byte b) { } void vstr_add_char(vstr_t *vstr, unichar c) { - // TODO UNICODE +#if MICROPY_PY_BUILTINS_STR_UNICODE + // TODO: Can this be simplified and deduplicated? + // Is it worth just calling vstr_add_len(vstr, 4)? + if (c < 0x80) { + byte *buf = (byte*)vstr_add_len(vstr, 1); + if (buf == NULL) { + return; + } + *buf = (byte)c; + } else if (c < 0x800) { + byte *buf = (byte*)vstr_add_len(vstr, 2); + if (buf == NULL) { + return; + } + buf[0] = (c >> 6) | 0xC0; + buf[1] = (c & 0x3F) | 0x80; + } else if (c < 0x10000) { + byte *buf = (byte*)vstr_add_len(vstr, 3); + if (buf == NULL) { + return; + } + buf[0] = (c >> 12) | 0xE0; + buf[1] = ((c >> 6) & 0x3F) | 0x80; + buf[2] = (c & 0x3F) | 0x80; + } else { + assert(c < 0x110000); + byte *buf = (byte*)vstr_add_len(vstr, 4); + if (buf == NULL) { + return; + } + buf[0] = (c >> 18) | 0xF0; + buf[1] = ((c >> 12) & 0x3F) | 0x80; + buf[2] = ((c >> 6) & 0x3F) | 0x80; + buf[3] = (c & 0x3F) | 0x80; + } +#else byte *buf = (byte*)vstr_add_len(vstr, 1); if (buf == NULL) { return; } buf[0] = c; +#endif } void vstr_add_str(vstr_t *vstr, const char *str) { diff --git a/stmhal/adc.c b/stmhal/adc.c index c2419d543f..817b32ea89 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -202,7 +202,9 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); /// \method read_timed(buf, freq) -/// Read analog values into the given buffer at the given frequency. +/// Read analog values into the given buffer at the given frequency. Buffer +/// can be bytearray or array.array for example. If a buffer with 8-bit elements +/// is used, sample resolution will be reduced to 8 bits. /// /// Example: /// diff --git a/stmhal/boards/HYDRABUS/mpconfigboard.h b/stmhal/boards/HYDRABUS/mpconfigboard.h index f87a14142e..db49434b5b 100644 --- a/stmhal/boards/HYDRABUS/mpconfigboard.h +++ b/stmhal/boards/HYDRABUS/mpconfigboard.h @@ -1,6 +1,7 @@ #define HYDRABUSV10 #define MICROPY_HW_BOARD_NAME "HydraBus1.0" +#define MICROPY_HW_MCU_NAME "STM32F4" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index 0e40545253..2679aee576 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -1,6 +1,7 @@ #define NETDUINO_PLUS_2 #define MICROPY_HW_BOARD_NAME "NetduinoPlus2" +#define MICROPY_HW_MCU_NAME "STM32F405RG" #define MICROPY_HW_HAS_SWITCH (1) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index 3def531232..4ae6954a7d 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -1,6 +1,7 @@ #define PYBV10 #define MICROPY_HW_BOARD_NAME "PYBv1.0" +#define MICROPY_HW_MCU_NAME "STM32F405RG" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index ac0d84ca29..43d860a0cc 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -1,6 +1,7 @@ #define PYBV3 #define MICROPY_HW_BOARD_NAME "PYBv3" +#define MICROPY_HW_MCU_NAME "STM32F405RG" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index 9fedb70136..a278dea9fb 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -1,6 +1,7 @@ #define PYBV4 #define MICROPY_HW_BOARD_NAME "PYBv4" +#define MICROPY_HW_MCU_NAME "STM32F405RG" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_SDCARD (1) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index e6780eacbd..10bbe45188 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -1,6 +1,7 @@ #define STM32F4DISC #define MICROPY_HW_BOARD_NAME "F4DISC" +#define MICROPY_HW_MCU_NAME "STM32F407" #define MICROPY_HW_HAS_SWITCH (1) #define MICROPY_HW_HAS_SDCARD (0) diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c index 4d2313075a..3bbb6bda0e 100644 --- a/stmhal/boards/stm32f4xx-prefix.c +++ b/stmhal/boards/stm32f4xx-prefix.c @@ -5,8 +5,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "pin.h" diff --git a/stmhal/bufhelper.c b/stmhal/bufhelper.c index dd72655520..1f823ea963 100644 --- a/stmhal/bufhelper.c +++ b/stmhal/bufhelper.c @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "bufhelper.h" diff --git a/stmhal/dac.c b/stmhal/dac.c index 81ce993a8c..725e14e906 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -237,7 +237,7 @@ STATIC const mp_arg_t pyb_dac_write_timed_args[] = { { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_NORMAL} }, }; -#define PYB_DAC_WRITE_TIMED_NUM_ARGS ARRAY_SIZE(pyb_dac_write_timed_args) +#define PYB_DAC_WRITE_TIMED_NUM_ARGS MP_ARRAY_SIZE(pyb_dac_write_timed_args) mp_obj_t pyb_dac_write_timed(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_dac_obj_t *self = args[0]; diff --git a/stmhal/diskio.c b/stmhal/diskio.c index cde5874946..35b9eab99f 100644 --- a/stmhal/diskio.c +++ b/stmhal/diskio.c @@ -32,8 +32,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "systick.h" diff --git a/stmhal/extint.c b/stmhal/extint.c index 24d51ffb8d..591246cdd1 100644 --- a/stmhal/extint.c +++ b/stmhal/extint.c @@ -296,7 +296,7 @@ STATIC const mp_arg_t pyb_extint_make_new_args[] = { { MP_QSTR_pull, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; -#define PYB_EXTINT_MAKE_NEW_NUM_ARGS ARRAY_SIZE(pyb_extint_make_new_args) +#define PYB_EXTINT_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(pyb_extint_make_new_args) STATIC mp_obj_t extint_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // type_in == extint_obj_type diff --git a/stmhal/gccollect.c b/stmhal/gccollect.c index 79082e2f2e..c71ed13a5e 100644 --- a/stmhal/gccollect.c +++ b/stmhal/gccollect.c @@ -25,15 +25,15 @@ */ #include <stdio.h> +#include <stdint.h> -#include <stm32f4xx_hal.h> - -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "gc.h" #include "gccollect.h" +#include MICROPY_HAL_H machine_uint_t gc_helper_get_regs_and_sp(machine_uint_t *regs); diff --git a/stmhal/i2c.c b/stmhal/i2c.c index 00501a57da..b6ab531293 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -220,7 +220,7 @@ STATIC const mp_arg_t pyb_i2c_init_args[] = { { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, { MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; -#define PYB_I2C_INIT_NUM_ARGS ARRAY_SIZE(pyb_i2c_init_args) +#define PYB_I2C_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_init_args) STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // parse args @@ -271,7 +271,7 @@ STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const machine_int_t i2c_id = mp_obj_get_int(args[0]) - 1; // check i2c number - if (!(0 <= i2c_id && i2c_id < ARRAY_SIZE(pyb_i2c_obj) && pyb_i2c_obj[i2c_id].i2c != NULL)) { + if (!(0 <= i2c_id && i2c_id < MP_ARRAY_SIZE(pyb_i2c_obj) && pyb_i2c_obj[i2c_id].i2c != NULL)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1)); } @@ -363,7 +363,7 @@ STATIC const mp_arg_t pyb_i2c_send_args[] = { { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_I2C_SEND_NUM_ARGS ARRAY_SIZE(pyb_i2c_send_args) +#define PYB_I2C_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_send_args) STATIC mp_obj_t pyb_i2c_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_i2c_obj_t *self = args[0]; @@ -414,7 +414,7 @@ STATIC const mp_arg_t pyb_i2c_recv_args[] = { { MP_QSTR_addr, MP_ARG_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_I2C_RECV_NUM_ARGS ARRAY_SIZE(pyb_i2c_recv_args) +#define PYB_I2C_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_recv_args) STATIC mp_obj_t pyb_i2c_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_i2c_obj_t *self = args[0]; @@ -470,7 +470,7 @@ STATIC const mp_arg_t pyb_i2c_mem_read_args[] = { { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_I2C_MEM_READ_NUM_ARGS ARRAY_SIZE(pyb_i2c_mem_read_args) +#define PYB_I2C_MEM_READ_NUM_ARGS MP_ARRAY_SIZE(pyb_i2c_mem_read_args) STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_i2c_obj_t *self = args[0]; diff --git a/stmhal/import.c b/stmhal/import.c index abc618bef0..88ddaefacf 100644 --- a/stmhal/import.c +++ b/stmhal/import.c @@ -27,8 +27,8 @@ #include <stdio.h> #include <stdint.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "ff.h" diff --git a/stmhal/led.c b/stmhal/led.c index e23b30ab75..c1b298b179 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -61,7 +61,7 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = { #endif #endif }; -#define NUM_LEDS ARRAY_SIZE(pyb_led_obj) +#define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) void led_init(void) { /* GPIO structure */ diff --git a/stmhal/lexerfatfs.c b/stmhal/lexerfatfs.c index 6a0e83fb13..c578b13af6 100644 --- a/stmhal/lexerfatfs.c +++ b/stmhal/lexerfatfs.c @@ -27,8 +27,8 @@ #include <stdint.h> #include <stdio.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "lexer.h" #include "lexerfatfs.h" diff --git a/stmhal/main.c b/stmhal/main.c index 9751dcac2e..0e260e18cd 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -29,10 +29,10 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "misc.h" #include "systick.h" #include "pendsv.h" -#include "mpconfig.h" #include "qstr.h" #include "misc.h" #include "nlr.h" @@ -40,6 +40,7 @@ #include "parse.h" #include "obj.h" #include "runtime.h" +#include "stackctrl.h" #include "gc.h" #include "gccollect.h" #include "pybstdio.h" @@ -85,7 +86,7 @@ void flash_error(int n) { led_state(PYB_LED_R2, 0); } -void __fatal_error(const char *msg) { +void NORETURN __fatal_error(const char *msg) { for (volatile uint delay = 0; delay < 10000000; delay++) { } led_state(1, 1); @@ -111,8 +112,7 @@ void nlr_jump_fail(void *val) { } #ifndef NDEBUG -void __attribute__((weak)) - __assert_func(const char *file, int line, const char *func, const char *expr) { +void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) { (void)func; printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line); __fatal_error(""); @@ -186,6 +186,10 @@ static const char fresh_readme_txt[] = int main(void) { // TODO disable JTAG + // Stack limit should be less than real stack size, so we + // had chance to recover from limit hit. + mp_stack_set_limit(&_ram_end - &_heap_end - 512); + /* STM32F4xx HAL library initialization: - Configure the Flash prefetch, instruction and Data caches - Configure the Systick to generate an interrupt each 1 msec @@ -308,7 +312,7 @@ soft_reset: MP_OBJ_NEW_SMALL_INT(115200), }; pyb_uart_global_debug = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, - ARRAY_SIZE(args), + MP_ARRAY_SIZE(args), 0, args); } #else diff --git a/stmhal/math.c b/stmhal/math.c index 637f447cf1..91ffb2503f 100644 --- a/stmhal/math.c +++ b/stmhal/math.c @@ -72,6 +72,7 @@ float __attribute__((pcs("aapcs"))) __aeabi_d2f(double x) { fx.m = (dx.m>>(52-23)); // right justify return fx.f; } + double __aeabi_dmul(double x , double y) { return 0.0; @@ -85,6 +86,18 @@ float sqrtf(float x) { return x; } +#ifndef NDEBUG +float copysignf(float x, float y) { + float_s_t fx={.f = x}; + float_s_t fy={.f = y}; + + // copy sign bit; + fx.s = fy.s; + + return fx.f; +} +#endif + // some compilers define log2f in terms of logf #ifdef log2f #undef log2f diff --git a/stmhal/modos.c b/stmhal/modos.c index 4a6949a844..e0df05ca6b 100644 --- a/stmhal/modos.c +++ b/stmhal/modos.c @@ -194,8 +194,8 @@ STATIC const mp_obj_dict_t os_module_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(os_module_globals_table), - .alloc = ARRAY_SIZE(os_module_globals_table), + .used = MP_ARRAY_SIZE(os_module_globals_table), + .alloc = MP_ARRAY_SIZE(os_module_globals_table), .table = (mp_map_elem_t*)os_module_globals_table, }, }; diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 6879a2c1b7..9dcd0e76ca 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -426,8 +426,8 @@ STATIC const mp_obj_dict_t pyb_module_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(pyb_module_globals_table), - .alloc = ARRAY_SIZE(pyb_module_globals_table), + .used = MP_ARRAY_SIZE(pyb_module_globals_table), + .alloc = MP_ARRAY_SIZE(pyb_module_globals_table), .table = (mp_map_elem_t*)pyb_module_globals_table, }, }; diff --git a/stmhal/modstm.c b/stmhal/modstm.c index 520c8e51bd..1196ff82ff 100644 --- a/stmhal/modstm.c +++ b/stmhal/modstm.c @@ -131,8 +131,8 @@ STATIC const mp_obj_dict_t stm_module_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(stm_module_globals_table), - .alloc = ARRAY_SIZE(stm_module_globals_table), + .used = MP_ARRAY_SIZE(stm_module_globals_table), + .alloc = MP_ARRAY_SIZE(stm_module_globals_table), .table = (mp_map_elem_t*)stm_module_globals_table, }, }; diff --git a/stmhal/modtime.c b/stmhal/modtime.c index 4fbee31293..ea4e3210a6 100644 --- a/stmhal/modtime.c +++ b/stmhal/modtime.c @@ -122,8 +122,8 @@ STATIC const mp_obj_dict_t time_module_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(time_module_globals_table), - .alloc = ARRAY_SIZE(time_module_globals_table), + .used = MP_ARRAY_SIZE(time_module_globals_table), + .alloc = MP_ARRAY_SIZE(time_module_globals_table), .table = (mp_map_elem_t*)time_module_globals_table, }, }; diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 28cd90bb01..28e654c8a6 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -44,6 +44,7 @@ */ #define MICROPY_ENABLE_LFN (1) #define MICROPY_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) @@ -104,3 +105,6 @@ typedef const void *machine_const_ptr_t; // must be of pointer size // We need to provide a declaration/definition of alloca() #include <alloca.h> + +#define MICROPY_HAL_H "mphal.h" +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stmhal.h" diff --git a/stmhal/mphal.h b/stmhal/mphal.h new file mode 100644 index 0000000000..4e9a8b2bb8 --- /dev/null +++ b/stmhal/mphal.h @@ -0,0 +1,7 @@ +// We use the ST Cube HAL library for most hardware peripherals +#include <stm32f4xx_hal.h> + +// Basic GPIO functions +#define GPIO_read_pin(gpio, pin) (((gpio)->IDR >> (pin)) & 1) +#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRRL) = (pin_mask)) +#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRRH) = (pin_mask)) diff --git a/stmhal/pendsv.c b/stmhal/pendsv.c index f8e3b30072..a0eff7e5de 100644 --- a/stmhal/pendsv.c +++ b/stmhal/pendsv.c @@ -27,8 +27,8 @@ #include <stdlib.h> #include <stm32f4xx_hal.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "pendsv.h" diff --git a/stmhal/pin.c b/stmhal/pin.c index 9806a8c49a..a9ebfa9766 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -28,14 +28,13 @@ #include <stdint.h> #include <string.h> -#include "stm32f4xx_hal.h" - #include "mpconfig.h" #include "nlr.h" #include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" +#include MICROPY_HAL_H #include "pin.h" /// \moduleref pyb @@ -100,8 +99,8 @@ STATIC mp_obj_t pin_class_map_dict; STATIC bool pin_class_debug; void pin_init(void) { - pin_class_mapper = MP_OBJ_NULL; - pin_class_map_dict = MP_OBJ_NULL; + pin_class_mapper = mp_const_none; + pin_class_map_dict = mp_const_none; pin_class_debug = false; } @@ -120,7 +119,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { return pin_obj; } - if (pin_class_mapper != MP_OBJ_NULL) { + if (pin_class_mapper != mp_const_none) { pin_obj = mp_call_function_1(pin_class_mapper, user_obj); if (pin_obj != mp_const_none) { if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) { @@ -139,7 +138,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { // other lookup methods. } - if (pin_class_map_dict != MP_OBJ_NULL) { + if (pin_class_map_dict != mp_const_none) { mp_map_t *pin_map_map = mp_obj_dict_get_map(pin_class_map_dict); mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP); if (elem != NULL && elem->value != NULL) { @@ -310,13 +309,13 @@ STATIC mp_obj_t pin_value(uint n_args, mp_obj_t *args) { pin_obj_t *self = args[0]; if (n_args == 1) { // get pin - return MP_OBJ_NEW_SMALL_INT((self->gpio->IDR >> self->pin) & 1); + return MP_OBJ_NEW_SMALL_INT(GPIO_read_pin(self->gpio, self->pin)); } else { // set pin if (mp_obj_is_true(args[1])) { - self->gpio->BSRRL = self->pin_mask; + GPIO_set_pin(self->gpio, self->pin_mask); } else { - self->gpio->BSRRH = self->pin_mask; + GPIO_clear_pin(self->gpio, self->pin_mask); } return mp_const_none; } @@ -327,7 +326,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); /// Set the pin to a low logic level. STATIC mp_obj_t pin_low(mp_obj_t self_in) { pin_obj_t *self = self_in; - self->gpio->BSRRH = self->pin_mask; + GPIO_clear_pin(self->gpio, self->pin_mask);; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); @@ -336,7 +335,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); /// Set the pin to a high logic level. STATIC mp_obj_t pin_high(mp_obj_t self_in) { pin_obj_t *self = self_in; - self->gpio->BSRRL = self->pin_mask; + GPIO_set_pin(self->gpio, self->pin_mask);; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); diff --git a/stmhal/pin.h b/stmhal/pin.h index d60bd22fd7..8513db109b 100644 --- a/stmhal/pin.h +++ b/stmhal/pin.h @@ -24,63 +24,10 @@ * THE SOFTWARE. */ -enum { - PORT_A, - PORT_B, - PORT_C, - PORT_D, - PORT_E, - PORT_F, - PORT_G, - PORT_H, - PORT_I, - PORT_J, -}; +// This file requires pin_defs_xxx.h (which has port specific enums and +// defines, so we include it here. It should never be included directly -enum { - AF_FN_TIM, - AF_FN_I2C, - AF_FN_USART, - AF_FN_UART = AF_FN_USART, - AF_FN_SPI -}; - -enum { - AF_PIN_TYPE_TIM_CH1 = 0, - AF_PIN_TYPE_TIM_CH2, - AF_PIN_TYPE_TIM_CH3, - AF_PIN_TYPE_TIM_CH4, - AF_PIN_TYPE_TIM_CH1N, - AF_PIN_TYPE_TIM_CH2N, - AF_PIN_TYPE_TIM_CH3N, - AF_PIN_TYPE_TIM_CH1_ETR, - AF_PIN_TYPE_TIM_ETR, - AF_PIN_TYPE_TIM_BKIN, - - AF_PIN_TYPE_I2C_SDA = 0, - AF_PIN_TYPE_I2C_SCL, - - AF_PIN_TYPE_USART_TX = 0, - AF_PIN_TYPE_USART_RX, - AF_PIN_TYPE_USART_CTS, - AF_PIN_TYPE_USART_RTS, - AF_PIN_TYPE_USART_CK, - AF_PIN_TYPE_UART_TX = AF_PIN_TYPE_USART_TX, - AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX, - AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS, - AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS, - - AF_PIN_TYPE_SPI_MOSI = 0, - AF_PIN_TYPE_SPI_MISO, - AF_PIN_TYPE_SPI_SCK, - AF_PIN_TYPE_SPI_NSS, -}; - -enum { - PIN_ADC1 = (1 << 0), - PIN_ADC2 = (1 << 1), - PIN_ADC3 = (1 << 2), -}; +#include MICROPY_PIN_DEFS_PORT_H typedef struct { mp_obj_base_t base; @@ -91,24 +38,21 @@ typedef struct { union { void *reg; - TIM_TypeDef *TIM; - I2C_TypeDef *I2C; - USART_TypeDef *USART; - USART_TypeDef *UART; - SPI_TypeDef *SPI; + + PIN_DEFS_PORT_AF_UNION }; } pin_af_obj_t; typedef struct { mp_obj_base_t base; const char *name; - uint16_t port : 4; - uint16_t pin : 4; - uint16_t num_af : 4; - uint16_t adc_channel : 4; - uint16_t adc_num : 3; // 1 bit per ADC - uint16_t pin_mask; - GPIO_TypeDef *gpio; + uint32_t port : 4; + uint32_t pin : 5; // Some ARM processors use 32 bits/PORT + uint32_t num_af : 4; + uint32_t adc_channel : 5; // Some ARM processors use 32 bits/PORT + uint32_t adc_num : 3; // 1 bit per ADC + uint32_t pin_mask; + pin_gpio_t *gpio; const pin_af_obj_t *af; } pin_obj_t; diff --git a/stmhal/pin_defs_stmhal.h b/stmhal/pin_defs_stmhal.h new file mode 100644 index 0000000000..2b6d9da0e7 --- /dev/null +++ b/stmhal/pin_defs_stmhal.h @@ -0,0 +1,96 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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. + */ + +// This file contains pin definitions that are specific to the stmhal port. +// This file should only ever be #included by pin.h and not directly. + +enum { + PORT_A, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + PORT_F, + PORT_G, + PORT_H, + PORT_I, + PORT_J, +}; + +enum { + AF_FN_TIM, + AF_FN_I2C, + AF_FN_USART, + AF_FN_UART = AF_FN_USART, + AF_FN_SPI +}; + +enum { + AF_PIN_TYPE_TIM_CH1 = 0, + AF_PIN_TYPE_TIM_CH2, + AF_PIN_TYPE_TIM_CH3, + AF_PIN_TYPE_TIM_CH4, + AF_PIN_TYPE_TIM_CH1N, + AF_PIN_TYPE_TIM_CH2N, + AF_PIN_TYPE_TIM_CH3N, + AF_PIN_TYPE_TIM_CH1_ETR, + AF_PIN_TYPE_TIM_ETR, + AF_PIN_TYPE_TIM_BKIN, + + AF_PIN_TYPE_I2C_SDA = 0, + AF_PIN_TYPE_I2C_SCL, + + AF_PIN_TYPE_USART_TX = 0, + AF_PIN_TYPE_USART_RX, + AF_PIN_TYPE_USART_CTS, + AF_PIN_TYPE_USART_RTS, + AF_PIN_TYPE_USART_CK, + AF_PIN_TYPE_UART_TX = AF_PIN_TYPE_USART_TX, + AF_PIN_TYPE_UART_RX = AF_PIN_TYPE_USART_RX, + AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS, + AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS, + + AF_PIN_TYPE_SPI_MOSI = 0, + AF_PIN_TYPE_SPI_MISO, + AF_PIN_TYPE_SPI_SCK, + AF_PIN_TYPE_SPI_NSS, +}; + +enum { + PIN_ADC1 = (1 << 0), + PIN_ADC2 = (1 << 1), + PIN_ADC3 = (1 << 2), +}; + +#define PIN_DEFS_PORT_AF_UNION \ + TIM_TypeDef *TIM; \ + I2C_TypeDef *I2C; \ + USART_TypeDef *USART; \ + USART_TypeDef *UART; \ + SPI_TypeDef *SPI; + +typedef GPIO_TypeDef pin_gpio_t; + diff --git a/stmhal/pin_named_pins.c b/stmhal/pin_named_pins.c index 3a1794e1d9..dbf03d1a0f 100644 --- a/stmhal/pin_named_pins.c +++ b/stmhal/pin_named_pins.c @@ -28,13 +28,12 @@ #include <stdint.h> #include <string.h> -#include "stm32f4xx_hal.h" - -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" +#include MICROPY_HAL_H #include "pin.h" STATIC void pin_named_pins_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { diff --git a/stmhal/printf.c b/stmhal/printf.c index 26c552039f..c4731aa88d 100644 --- a/stmhal/printf.c +++ b/stmhal/printf.c @@ -28,10 +28,10 @@ #include <string.h> #include <stdarg.h> +#include "mpconfig.h" #include "std.h" #include "misc.h" #include "systick.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "pfenv.h" diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index 05ea06eb44..5447a62202 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -25,15 +25,15 @@ */ #include <stdio.h> +#include <stdint.h> -#include <stm32f4xx_hal.h> - -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "misc.h" #include "obj.h" #include "stream.h" +#include MICROPY_HAL_H #include "pybstdio.h" #include "usb.h" #include "uart.h" diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 45928427e1..93f4d62a96 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -26,8 +26,7 @@ #include <stdlib.h> #include <stdio.h> - -#include <stm32f4xx_hal.h> +#include <stdint.h> #include "mpconfig.h" #include "nlr.h" @@ -43,6 +42,7 @@ #include "repl.h" #include "gc.h" #include "gccollect.h" +#include MICROPY_HAL_H #include "systick.h" #include "pybstdio.h" #include "readline.h" @@ -185,7 +185,7 @@ int pyexec_friendly_repl(void) { #endif friendly_repl_reset: - stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); + stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); stdout_tx_str("Type \"help()\" for more information.\r\n"); // to test ctrl-C diff --git a/stmhal/readline.c b/stmhal/readline.c index d40bd4219b..0703dcf4ea 100644 --- a/stmhal/readline.c +++ b/stmhal/readline.c @@ -25,15 +25,15 @@ */ #include <stdio.h> +#include <stdint.h> #include <string.h> -#include <stm32f4xx_hal.h> - -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "misc.h" #include "obj.h" +#include MICROPY_HAL_H #include "pybstdio.h" #include "readline.h" #include "usb.h" diff --git a/stmhal/rng.c b/stmhal/rng.c index 69fcb9d6ff..ea636770c0 100644 --- a/stmhal/rng.c +++ b/stmhal/rng.c @@ -28,8 +28,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "rng.h" diff --git a/stmhal/rtc.c b/stmhal/rtc.c index 412816c396..8f0d007327 100644 --- a/stmhal/rtc.c +++ b/stmhal/rtc.c @@ -28,8 +28,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index bd45af3a14..204dbe3b46 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -28,8 +28,8 @@ #include <stm32f4xx_hal.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/stmhal/spi.c b/stmhal/spi.c index 10ecf7ec8e..448b8696ea 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -188,7 +188,7 @@ STATIC const pyb_spi_obj_t pyb_spi_obj[] = { {{&pyb_spi_type}, NULL}, #endif }; -#define PYB_NUM_SPI ARRAY_SIZE(pyb_spi_obj) +#define PYB_NUM_SPI MP_ARRAY_SIZE(pyb_spi_obj) STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; @@ -242,7 +242,7 @@ STATIC const mp_arg_t pyb_spi_init_args[] = { { MP_QSTR_ti, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_crc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; -#define PYB_SPI_INIT_NUM_ARGS ARRAY_SIZE(pyb_spi_init_args) +#define PYB_SPI_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_spi_init_args) STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // parse args @@ -359,7 +359,7 @@ STATIC const mp_arg_t pyb_spi_send_args[] = { { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_SPI_SEND_NUM_ARGS ARRAY_SIZE(pyb_spi_send_args) +#define PYB_SPI_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_spi_send_args) STATIC mp_obj_t pyb_spi_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide @@ -401,7 +401,7 @@ STATIC const mp_arg_t pyb_spi_recv_args[] = { { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_SPI_RECV_NUM_ARGS ARRAY_SIZE(pyb_spi_recv_args) +#define PYB_SPI_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_spi_recv_args) STATIC mp_obj_t pyb_spi_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide @@ -449,7 +449,7 @@ STATIC const mp_arg_t pyb_spi_send_recv_args[] = { { MP_QSTR_recv, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_SPI_SEND_RECV_NUM_ARGS ARRAY_SIZE(pyb_spi_send_recv_args) +#define PYB_SPI_SEND_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_spi_send_recv_args) STATIC mp_obj_t pyb_spi_send_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide diff --git a/stmhal/stm32f4xx_hal_msp.c b/stmhal/stm32f4xx_hal_msp.c index 5816249e25..90baa41f82 100644 --- a/stmhal/stm32f4xx_hal_msp.c +++ b/stmhal/stm32f4xx_hal_msp.c @@ -66,8 +66,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "servo.h" diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c index 17cdaf5fa2..5fa7f8289d 100644 --- a/stmhal/stm32f4xx_it.c +++ b/stmhal/stm32f4xx_it.c @@ -70,8 +70,8 @@ #include "stm32f4xx_it.h" #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "extint.h" diff --git a/stmhal/storage.c b/stmhal/storage.c index ba7e303e21..001d87afe0 100644 --- a/stmhal/storage.c +++ b/stmhal/storage.c @@ -28,9 +28,9 @@ #include <string.h> #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "misc.h" #include "systick.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "led.h" diff --git a/stmhal/systick.c b/stmhal/systick.c index 8a8d6403dc..196f1fbcae 100644 --- a/stmhal/systick.c +++ b/stmhal/systick.c @@ -25,6 +25,7 @@ */ #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "misc.h" #include "systick.h" diff --git a/stmhal/timer.c b/stmhal/timer.c index 0ba24754b2..ec0c4dec4c 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -105,7 +105,7 @@ static uint32_t tim3_counter = 0; // Used to do callbacks to Python code on interrupt STATIC pyb_timer_obj_t *pyb_timer_obj_all[14]; -#define PYB_TIMER_OBJ_ALL_NUM ARRAY_SIZE(pyb_timer_obj_all) +#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all) void timer_init0(void) { tim3_counter = 0; @@ -234,7 +234,7 @@ STATIC const mp_arg_t pyb_timer_init_args[] = { { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_COUNTERMODE_UP} }, { MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_CLOCKDIVISION_DIV1} }, }; -#define PYB_TIMER_INIT_NUM_ARGS ARRAY_SIZE(pyb_timer_init_args) +#define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args) STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // parse args diff --git a/stmhal/uart.c b/stmhal/uart.c index 5bbd9f299e..a85f7f9e3a 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -270,7 +270,7 @@ STATIC const mp_arg_t pyb_uart_init_args[] = { { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; -#define PYB_UART_INIT_NUM_ARGS ARRAY_SIZE(pyb_uart_init_args) +#define PYB_UART_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_init_args) STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // parse args @@ -396,7 +396,7 @@ STATIC const mp_arg_t pyb_uart_send_args[] = { { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_UART_SEND_NUM_ARGS ARRAY_SIZE(pyb_uart_send_args) +#define PYB_UART_SEND_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_send_args) STATIC mp_obj_t pyb_uart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide @@ -438,7 +438,7 @@ STATIC const mp_arg_t pyb_uart_recv_args[] = { { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, }; -#define PYB_UART_RECV_NUM_ARGS ARRAY_SIZE(pyb_uart_recv_args) +#define PYB_UART_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_recv_args) STATIC mp_obj_t pyb_uart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide diff --git a/stmhal/usrsw.c b/stmhal/usrsw.c index 4ed9e3abe4..8a082eac95 100644 --- a/stmhal/usrsw.c +++ b/stmhal/usrsw.c @@ -28,8 +28,8 @@ #include "stm32f4xx_hal.h" -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/teensy/Makefile b/teensy/Makefile index 8244d52d31..18ffb32af9 100644 --- a/teensy/Makefile +++ b/teensy/Makefile @@ -20,12 +20,15 @@ CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -fsingle-precision-c INC = -I. INC += -I$(PY_SRC) +INC += -I../stmhal INC += -I$(BUILD) INC += -I$(CORE_PATH) CFLAGS = $(INC) -Wall -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) LDFLAGS = -nostdlib -T mk20dx256.ld -LIBS = -L $(COMPILER_PATH)/../lib/gcc/arm-none-eabi/4.7.2/thumb2 -lgcc +LIBS = -L $(COMPILER_PATH)/../arm-none-eabi/lib/thumb2 -lm +LIBS += -L $(COMPILER_PATH)/../arm-none-eabi/lib/thumb2 -lc +LIBS += -L $(COMPILER_PATH)/../lib/gcc/arm-none-eabi/4.7.2/thumb2 -lgcc #Debugging/Optimization ifdef DEBUG @@ -35,23 +38,32 @@ CFLAGS += -Os #-DNDEBUG endif SRC_C = \ + hal_gpio.c \ + help.c \ + import.c \ main.c \ lcd.c \ led.c \ - lexerfatfs.c \ lexermemzip.c \ memzip.c \ - servo.c \ - usart.c \ + modpyb.c \ + teensy_hal.c \ + uart.c \ usb.c \ -STM_SRC_C = $(addprefix stm/,\ - malloc0.c \ +STM_SRC_C = $(addprefix stmhal/,\ + gccollect.c \ + input.c \ + pin.c \ + pin_named_pins.c \ printf.c \ + pyexec.c \ + pybstdio.c \ + readline.c \ string0.c \ ) -STM_SRC_S = $(addprefix stm/,\ +STM_SRC_S = $(addprefix stmhal/,\ gchelper.s \ ) @@ -66,9 +78,7 @@ SRC_TEENSY = \ yield.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(STM_SRC_C:.c=.o) $(STM_SRC_S:.s=.o) $(SRC_TEENSY:.c=.o)) -#LIB = -lreadline -# the following is needed for BSD -#LIB += -ltermcap +OBJ += $(BUILD)/pins_gen.o all: hex hex: $(BUILD)/micropython-mz.hex @@ -84,7 +94,7 @@ reboot: upload: post_compile reboot $(BUILD)/micropython.elf: $(OBJ) - $(ECHO) "LINK $<" + $(ECHO) "LINK $@" $(Q)$(CC) $(LDFLAGS) -o "$@" -Wl,-Map,$(@:.elf=.map) $(OBJ) $(LIBS) $(Q)$(SIZE) $@ @@ -103,4 +113,31 @@ $(BUILD)/%.hex: $(BUILD)/%.elf $(BUILD)/%.o: $(CORE_PATH)/%.c $(call compile_c) +MAKE_PINS = make-pins.py +BOARD_PINS = teensy-pins.csv +AF_FILE = mk20dx256-af.csv +PREFIX_FILE = mk20dx256-prefix.c +GEN_PINS_SRC = $(BUILD)/pins_gen.c +GEN_PINS_HDR = $(HEADER_BUILD)/pins.h + +# Making OBJ use an order-only depenedency on the generated pins.h file +# has the side effect of making the pins.h file before we actually compile +# any of the objects. The normal dependency generation will deal with the +# case when pins.h is modified. But when it doesn't exist, we don't know +# which source files might need it. +$(OBJ): | $(HEADER_BUILD)/pins.h + +# Use a pattern rule here so that make will only call make-pins.py once to make +# both pins_$(BOARD).c and pins.h +$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: teensy-%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) + $(ECHO) "Create $@" + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC) + +$(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c + $(call compile_c) + +$(BUILD)/%.pp: $(BUILD)/%.c + $(ECHO) "PreProcess $<" + $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $< + include ../py/mkrules.mk diff --git a/teensy/hal_gpio.c b/teensy/hal_gpio.c new file mode 100644 index 0000000000..0811f76fda --- /dev/null +++ b/teensy/hal_gpio.c @@ -0,0 +1,115 @@ +#include <stdint.h> +#include <mk20dx128.h> +#include "teensy_hal.h" + +#define GPIO_NUMBER 32 + +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) +{ + /* Check the parameters */ + assert_param(IS_GPIO_PIN(GPIO_Init->Pin)); + assert_param(IS_GPIO_MODE(GPIO_Init->Mode)); + assert_param(IS_GPIO_PULL(GPIO_Init->Pull)); + + /* Configure the port pins */ + for (uint32_t position = 0; position < GPIO_NUMBER; position++) { + uint32_t bitmask = 1 << position; + if ((GPIO_Init->Pin & bitmask) == 0) { + continue; + } + + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(GPIOx, position); + + /*--------------------- GPIO Mode Configuration ------------------------*/ + /* In case of Alternate function mode selection */ + if ((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) { + /* Check the Alternate function parameter */ + assert_param(IS_GPIO_AF(GPIO_Init->Alternate)); + /* Configure Alternate function mapped with the current IO */ + + *port_pcr &= ~PORT_PCR_MUX_MASK; + *port_pcr |= PORT_PCR_MUX(GPIO_Init->Alternate); + } + + /* Configure IO Direction mode (Input, Output, Alternate or Analog) */ + if (GPIO_Init->Mode == GPIO_MODE_INPUT || GPIO_Init->Mode == GPIO_MODE_ANALOG) { + GPIOx->PDDR &= ~bitmask; + } else { + GPIOx->PDDR |= bitmask; + } + + /* In case of Output or Alternate function mode selection */ + if ((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) || + (GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) { + /* Check the Speed parameter */ + assert_param(IS_GPIO_SPEED(GPIO_Init->Speed)); + + /* Configure the IO Speed */ + if (GPIO_Init->Speed > GPIO_SPEED_MEDIUM) { + *port_pcr &= ~PORT_PCR_SRE; + } else { + *port_pcr |= PORT_PCR_SRE; + } + + /* Configure the IO Output Type */ + if (GPIO_Init->Mode & GPIO_OUTPUT_TYPE) { + *port_pcr |= PORT_PCR_ODE; + } else { + *port_pcr &= ~PORT_PCR_ODE; + } + } + + /* Activate the Pull-up or Pull down resistor for the current IO */ + if (GPIO_Init->Pull == GPIO_NOPULL) { + *port_pcr &= ~PORT_PCR_PE; + } else { + *port_pcr |= PORT_PCR_PE; + if (GPIO_Init->Pull == GPIO_PULLDOWN) { + *port_pcr &= ~PORT_PCR_PS; + } else { + *port_pcr |= PORT_PCR_PS; + } + } + +#if 0 + /*--------------------- EXTI Mode Configuration ------------------------*/ + /* Configure the External Interrupt or event for the current IO */ + if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE) + { + /* Enable SYSCFG Clock */ + __SYSCFG_CLK_ENABLE(); + + temp = ((uint32_t)0x0F) << (4 * (position & 0x03)); + SYSCFG->EXTICR[position >> 2] &= ~temp; + SYSCFG->EXTICR[position >> 2] |= ((uint32_t)(__HAL_GET_GPIO_SOURCE(GPIOx)) << (4 * (position & 0x03))); + + /* Clear EXTI line configuration */ + EXTI->IMR &= ~((uint32_t)iocurrent); + EXTI->EMR &= ~((uint32_t)iocurrent); + + if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT) + { + EXTI->IMR |= iocurrent; + } + if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT) + { + EXTI->EMR |= iocurrent; + } + + /* Clear Rising Falling edge configuration */ + EXTI->RTSR &= ~((uint32_t)iocurrent); + EXTI->FTSR &= ~((uint32_t)iocurrent); + + if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE) + { + EXTI->RTSR |= iocurrent; + } + if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE) + { + EXTI->FTSR |= iocurrent; + } + } +#endif + } +} + diff --git a/teensy/help.c b/teensy/help.c new file mode 100644 index 0000000000..598b6f4e30 --- /dev/null +++ b/teensy/help.c @@ -0,0 +1,123 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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 <stdio.h> + +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" + +STATIC const char *help_text = +"Welcome to Micro Python!\n" +"\n" +"For online help please visit http://micropython.org/help/.\n" +"\n" +"Quick overview of commands for the board:\n" +" pyb.info() -- print some general information\n" +" pyb.gc() -- run the garbage collector\n" +" pyb.delay(n) -- wait for n milliseconds\n" +" pyb.Switch() -- create a switch object\n" +" Switch methods: (), callback(f)\n" +" pyb.LED(n) -- create an LED object for LED n (n=1,2,3,4)\n" +" LED methods: on(), off(), toggle(), intensity(<n>)\n" +" pyb.Pin(pin) -- get a pin, eg pyb.Pin('X1')\n" +" pyb.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n" +" Pin methods: init(..), value([v]), high(), low()\n" +" pyb.ExtInt(pin, m, p, callback) -- create an external interrupt object\n" +" pyb.ADC(pin) -- make an analog object from a pin\n" +" ADC methods: read(), read_timed(buf, freq)\n" +" pyb.DAC(port) -- make a DAC object\n" +" DAC methods: triangle(freq), write(n), write_timed(buf, freq)\n" +" pyb.RTC() -- make an RTC object; methods: datetime([val])\n" +" pyb.rng() -- get a 30-bit hardware random number\n" +" pyb.Servo(n) -- create Servo object for servo n (n=1,2,3,4)\n" +" Servo methods: calibration(..), angle([x, [t]]), speed([x, [t]])\n" +" pyb.Accel() -- create an Accelerometer object\n" +" Accelerometer methods: x(), y(), z(), tilt(), filtered_xyz()\n" +"\n" +"Pins are numbered X1-X12, X17-X22, Y1-Y12, or by their MCU name\n" +"Pin IO modes are: pyb.Pin.IN, pyb.Pin.OUT_PP, pyb.Pin.OUT_OD\n" +"Pin pull modes are: pyb.Pin.PULL_NONE, pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN\n" +"Additional serial bus objects: pyb.I2C(n), pyb.SPI(n), pyb.UART(n)\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; + +STATIC void pyb_help_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { + printf(" "); + mp_obj_print(name_o, PRINT_STR); + printf(" -- "); + mp_obj_print(value, PRINT_STR); + printf("\n"); +} + +STATIC mp_obj_t pyb_help(uint n_args, const mp_obj_t *args) { + if (n_args == 0) { + // print a general help message + printf("%s", help_text); + + } else { + // try to print something sensible about the given object + + printf("object "); + mp_obj_print(args[0], PRINT_STR); + printf(" is of type %s\n", mp_obj_get_type_str(args[0])); + + mp_map_t *map = NULL; + if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) { + map = mp_obj_dict_get_map(mp_obj_module_get_globals(args[0])); + } else { + mp_obj_type_t *type; + if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) { + type = args[0]; + } else { + type = mp_obj_get_type(args[0]); + } + if (type->locals_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)) { + map = mp_obj_dict_get_map(type->locals_dict); + } + } + if (map != NULL) { + for (uint i = 0; i < map->alloc; i++) { + if (map->table[i].key != MP_OBJ_NULL) { + pyb_help_print_info_about_object(map->table[i].key, map->table[i].value); + } + } + } + } + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, pyb_help); diff --git a/teensy/import.c b/teensy/import.c new file mode 100644 index 0000000000..967de102ac --- /dev/null +++ b/teensy/import.c @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdint.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "lexer.h" + +#include "memzip.h" + +mp_import_stat_t mp_import_stat(const char *path) { + MEMZIP_FILE_INFO info; + + if (memzip_stat(path, &info) != MZ_OK) { + return MP_IMPORT_STAT_NO_EXIST; + } + + if (info.is_dir) { + return MP_IMPORT_STAT_DIR; + } + return MP_IMPORT_STAT_FILE; +} diff --git a/teensy/lcd.c b/teensy/lcd.c index cc3f52bad5..5b991aac77 100644 --- a/teensy/lcd.c +++ b/teensy/lcd.c @@ -1,5 +1,10 @@ +#include "mpconfig.h" +#include "nlr.h" #include "misc.h" -#include "../stm/lcd.h" +#include "qstr.h" +#include "parse.h" +#include "obj.h" +#include "../stmhal/lcd.h" void lcd_init(void) { } diff --git a/teensy/led.c b/teensy/led.c index e2a0574168..5a9d8701d2 100644 --- a/teensy/led.c +++ b/teensy/led.c @@ -1,53 +1,114 @@ #include <stdio.h> -#include "misc.h" +#include "Arduino.h" + #include "mpconfig.h" +#include "nlr.h" +#include "misc.h" #include "qstr.h" #include "obj.h" +#include "runtime.h" #include "led.h" +#include MICROPY_HAL_H +#include "pin.h" +#include "genhdr/pins.h" -#include "Arduino.h" +typedef struct _pyb_led_obj_t { + mp_obj_base_t base; + machine_uint_t led_id; + const pin_obj_t *led_pin; +} pyb_led_obj_t; + +STATIC const pyb_led_obj_t pyb_led_obj[] = { + {{&pyb_led_type}, 1, &MICROPY_HW_LED1}, +#if defined(MICROPY_HW_LED2) + {{&pyb_led_type}, 2, &MICROPY_HW_LED2}, +#if defined(MICROPY_HW_LED3) + {{&pyb_led_type}, 3, &MICROPY_HW_LED3}, +#if defined(MICROPY_HW_LED4) + {{&pyb_led_type}, 4, &MICROPY_HW_LED4}, +#endif +#endif +#endif +}; +#define NUM_LEDS ARRAY_SIZE(pyb_led_obj) void led_init(void) { + /* GPIO structure */ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Configure I/O speed, mode, output type and pull */ + GPIO_InitStructure.Speed = GPIO_SPEED_LOW; + GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; + GPIO_InitStructure.Pull = GPIO_NOPULL; + + /* Turn off LEDs and initialize */ + for (int led = 0; led < NUM_LEDS; led++) { + const pin_obj_t *led_pin = pyb_led_obj[led].led_pin; + MICROPY_HW_LED_OFF(led_pin); + GPIO_InitStructure.Pin = led_pin->pin_mask; + HAL_GPIO_Init(led_pin->gpio, &GPIO_InitStructure); + } } void led_state(pyb_led_t led, int state) { - uint8_t pin; - - if (led == 0) { - pin = LED_BUILTIN; - } else { + if (led < 1 || led > NUM_LEDS) { return; } - digitalWrite(pin, state); + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + //printf("led_state(%d,%d)\n", led, state); + if (state == 0) { + // turn LED off + MICROPY_HW_LED_OFF(led_pin); + } else { + // turn LED on + MICROPY_HW_LED_ON(led_pin); + } } void led_toggle(pyb_led_t led) { - uint8_t pin; - - if (led == 0) { - pin = LED_BUILTIN; - } else { + if (led < 1 || led > NUM_LEDS) { return; } - - digitalWrite(pin, !digitalRead(pin)); + const pin_obj_t *led_pin = pyb_led_obj[led - 1].led_pin; + GPIO_TypeDef *gpio = led_pin->gpio; + + // We don't know if we're turning the LED on or off, but we don't really + // care. Just invert the state. + if (gpio->PDOR & led_pin->pin_mask) { + // pin is high, make it low + gpio->PCOR = led_pin->pin_mask; + } else { + // pin is low, make it high + gpio->PSOR = led_pin->pin_mask; + } } /******************************************************************************/ /* Micro Python bindings */ -typedef struct _pyb_led_obj_t { - mp_obj_base_t base; - uint led_id; -} pyb_led_obj_t; - void led_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_led_obj_t *self = self_in; (void)kind; print(env, "<LED %lu>", self->led_id); } +STATIC mp_obj_t led_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // get led number + machine_int_t led_id = mp_obj_get_int(args[0]); + + // check led number + if (!(1 <= led_id && led_id <= NUM_LEDS)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "LED %d does not exist", led_id)); + } + + // return static led object + return (mp_obj_t)&pyb_led_obj[led_id - 1]; +} + mp_obj_t led_obj_on(mp_obj_t self_in) { pyb_led_obj_t *self = self_in; led_state(self->led_id, 1); @@ -60,25 +121,28 @@ mp_obj_t led_obj_off(mp_obj_t self_in) { return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); -static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +mp_obj_t led_obj_toggle(mp_obj_t self_in) { + pyb_led_obj_t *self = self_in; + led_toggle(self->led_id); + return mp_const_none; +} -static const mp_method_t led_methods[] = { - { "on", &led_obj_on_obj }, - { "off", &led_obj_off_obj }, - { NULL, NULL }, +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle); + +STATIC const mp_map_elem_t led_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_on), (mp_obj_t)&led_obj_on_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&led_obj_off_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_toggle), (mp_obj_t)&led_obj_toggle_obj }, }; -static const mp_obj_type_t led_obj_type = { +STATIC MP_DEFINE_CONST_DICT(led_locals_dict, led_locals_dict_table); + +const mp_obj_type_t pyb_led_type = { { &mp_type_type }, - .name = MP_QSTR_Led, + .name = MP_QSTR_LED, .print = led_obj_print, - .methods = led_methods, + .make_new = led_obj_make_new, + .locals_dict = (mp_obj_t)&led_locals_dict, }; - -mp_obj_t pyb_Led(mp_obj_t led_id) { - pyb_led_obj_t *o = m_new_obj(pyb_led_obj_t); - o->base.type = &led_obj_type; - o->led_id = mp_obj_get_int(led_id); - return o; -} diff --git a/teensy/led.h b/teensy/led.h index c5a4812549..7f4ba18f26 100644 --- a/teensy/led.h +++ b/teensy/led.h @@ -1,9 +1,9 @@ typedef enum { - PYB_LED_BUILTIN = 0, + PYB_LED_BUILTIN = 1, } pyb_led_t; void led_init(void); void led_state(pyb_led_t led, int state); void led_toggle(pyb_led_t led); -mp_obj_t pyb_Led(mp_obj_t led_id); +extern const mp_obj_type_t pyb_led_type; diff --git a/teensy/lexerfatfs.c b/teensy/lexerfatfs.c index 95084b6501..84245f8878 100644 --- a/teensy/lexerfatfs.c +++ b/teensy/lexerfatfs.c @@ -6,19 +6,10 @@ #include "qstr.h" #include "lexer.h" typedef int FIL; -#include "../stm/lexerfatfs.h" +#include "../stmhal/lexerfatfs.h" mp_lexer_t *mp_lexer_new_from_file(const char *filename) { printf("import not implemented\n"); return NULL; } -mp_lexer_t *mp_import_open_file(qstr mod_name) { - printf("import not implemented\n"); - return NULL; -} - -mp_import_stat_t mp_import_stat(const char *path) { - // TODO implement me! - return MP_IMPORT_STAT_NO_EXIST; -} diff --git a/teensy/lexermemzip.c b/teensy/lexermemzip.c index 3e15717acf..f50a3c0808 100644 --- a/teensy/lexermemzip.c +++ b/teensy/lexermemzip.c @@ -7,7 +7,7 @@ #include "lexer.h" #include "memzip.h" -mp_lexer_t *mp_lexer_new_from_memzip_file(const char *filename) +mp_lexer_t *mp_lexer_new_from_file(const char *filename) { void *data; size_t len; diff --git a/teensy/main.c b/teensy/main.c index eb153c245d..97c1db6528 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -3,29 +3,32 @@ #include <string.h> #include <stdlib.h> -#include "nlr.h" #include "misc.h" #include "mpconfig.h" #include "qstr.h" +#include "nlr.h" #include "lexer.h" #include "lexermemzip.h" #include "parse.h" #include "obj.h" -#include "compile.h" -#include "runtime0.h" #include "runtime.h" -#include "repl.h" +#include "gc.h" +#include "gccollect.h" +#include "pyexec.h" +#include "pybstdio.h" +#include "readline.h" + +#include "Arduino.h" +#include MICROPY_HAL_H + #include "servo.h" #include "usb.h" -#include "gc.h" #include "led.h" -#include "build/py/py-version.h" -#include "Arduino.h" +//#include "pin.h" -extern uint32_t _heap_start; -bool do_file(const char *filename); +extern uint32_t _heap_start; void flash_error(int n) { for (int i = 0; i < n; i++) { @@ -36,25 +39,36 @@ void flash_error(int n) { } } -static const char *help_text = -"Welcome to Micro Python!\n\n" -"This is a *very* early version of Micro Python and has minimal functionality.\n\n" -"Specific commands for the board:\n" -" pyb.info() -- print some general information\n" -" pyb.gc() -- run the garbage collector\n" -" pyb.delay(<n>) -- wait for n milliseconds\n" -" pyb.Led(<n>) -- create Led object for LED n (n=0)\n" -" Led methods: on(), off()\n" -" pyb.gpio(<pin>) -- read gpio pin\n" -" pyb.gpio(<pin>, <val>) -- set gpio pin\n" -#if 0 -" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n" -" Servo methods: angle(<x>)\n" -" pyb.switch() -- return True/False if switch pressed or not\n" -" pyb.accel() -- get accelerometer values\n" -" pyb.rand() -- get a 16-bit random number\n" -#endif -; +void __fatal_error(const char *msg) { + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + led_state(1, 1); + led_state(2, 1); + led_state(3, 1); + led_state(4, 1); + stdout_tx_strn("\nFATAL ERROR:\n", 14); + stdout_tx_strn(msg, strlen(msg)); + for (uint i = 0;;) { + led_toggle(((i++) & 3) + 1); + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + if (i >= 16) { + // to conserve power + __WFI(); + } + } +} + +void nlr_jump_fail(void *val) { + printf("FATAL: uncaught exception %p\n", val); + __fatal_error(""); +} + +void __assert_func(const char *file, int line, const char *func, const char *expr) { + + printf("Assertion failed: %s, file %s, line %d\n", expr, file, line); + __fatal_error(""); +} mp_obj_t pyb_analog_read(mp_obj_t pin_obj) { uint pin = mp_obj_get_int(pin_obj); @@ -82,12 +96,7 @@ mp_obj_t pyb_analog_write_frequency(mp_obj_t pin_obj, mp_obj_t freq_obj) { return mp_const_none; } -// get some help about available functions -static mp_obj_t pyb_help(void) { - printf("%s", help_text); - return mp_const_none; -} - +#if 0 // get lots of info about the board static mp_obj_t pyb_info(void) { // get and print unique id; 96 bits @@ -101,12 +110,6 @@ static mp_obj_t pyb_info(void) { // to print info about memory { - extern void *_sdata; - extern void *_edata; - extern void *_sbss; - extern void *_ebss; - extern void *_estack; - extern void *_etext; printf("_sdata=%p\n", &_sdata); printf("_edata=%p\n", &_edata); printf("_sbss=%p\n", &_sbss); @@ -121,9 +124,9 @@ static mp_obj_t pyb_info(void) { gc_info_t info; gc_info(&info); printf("GC:\n"); - printf(" %lu total\n", info.total); - printf(" %lu used %lu free\n", info.used, info.free); - printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block); + printf(" %u total\n", info.total); + printf(" %u used %u free\n", info.used, info.free); + printf(" 1=%u 2=%u m=%u\n", info.num_1block, info.num_2block, info.max_block); } #if 0 @@ -139,32 +142,15 @@ static mp_obj_t pyb_info(void) { return mp_const_none; } +#endif + #define RAM_START (0x1FFF8000) // fixed for chip #define HEAP_END (0x20006000) // tunable #define RAM_END (0x20008000) // fixed for chip -void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end); +#if 0 -void gc_collect(void) { - uint32_t start = micros(); - gc_collect_start(); - gc_collect_root((void**)RAM_START, (((uint32_t)&_heap_start) - RAM_START) / 4); - machine_uint_t regs[10]; - gc_helper_get_regs_and_clean_stack(regs, HEAP_END); - gc_collect_root((void**)HEAP_END, (RAM_END - HEAP_END) / 4); // will trace regs since they now live in this function on the stack - gc_collect_end(); - uint32_t ticks = micros() - start; // TODO implement a function that does this properly - - if (0) { - // print GC info - gc_info_t info; - gc_info(&info); - printf("GC@%lu %luus\n", start, ticks); - printf(" %lu total\n", info.total); - printf(" %lu used %lu free\n", info.used, info.free); - printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block); - } -} +void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end); mp_obj_t pyb_gc(void) { gc_collect(); @@ -191,7 +177,7 @@ mp_obj_t pyb_gpio(int n_args, mp_obj_t *args) { return mp_const_none; pin_error: - nlr_raise(mp_obj_new_exception_msg_varg(MP_QSTR_ValueError, "pin %d does not exist", pin)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %d does not exist", pin)); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio); @@ -209,29 +195,41 @@ mp_obj_t pyb_hid_send_report(mp_obj_t arg) { } #endif -static mp_obj_t pyb_config_source_dir = MP_OBJ_NULL; -static mp_obj_t pyb_config_main = MP_OBJ_NULL; +#endif // 0 + +STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL; +STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL; +STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL; mp_obj_t pyb_source_dir(mp_obj_t source_dir) { if (MP_OBJ_IS_STR(source_dir)) { pyb_config_source_dir = source_dir; - printf("source_dir = '"); - mp_obj_print(source_dir, PRINT_STR); - printf("'\n"); } return mp_const_none; } +MP_DEFINE_CONST_FUN_OBJ_1(pyb_source_dir_obj, pyb_source_dir); + mp_obj_t pyb_main(mp_obj_t main) { if (MP_OBJ_IS_STR(main)) { pyb_config_main = main; - printf("main = '"); - mp_obj_print(main, PRINT_STR); - printf("'\n"); } return mp_const_none; } +MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main); + +STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) { + if (MP_OBJ_IS_STR(usb_mode)) { + pyb_config_usb_mode = usb_mode; + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_mode_obj, pyb_usb_mode); + +#if 0 + mp_obj_t pyb_delay(mp_obj_t count) { delay(mp_obj_get_int(count)); return mp_const_none; @@ -242,12 +240,9 @@ mp_obj_t pyb_led(mp_obj_t state) { return state; } -mp_obj_t pyb_run(mp_obj_t filename_obj) { - const char *filename = qstr_str(mp_obj_str_get_qstr(filename_obj)); - do_file(filename); - return mp_const_none; -} +#endif // 0 +#if 0 char *strdup(const char *str) { uint32_t len = strlen(str); char *s2 = m_new(char, len + 1); @@ -255,219 +250,31 @@ char *strdup(const char *str) { s2[len] = 0; return s2; } - -#define READLINE_HIST_SIZE (8) - -static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - -void stdout_tx_str(const char *str) { -// usart_tx_str(str); - usb_vcp_send_str(str); -} - -int readline(vstr_t *line, const char *prompt) { - stdout_tx_str(prompt); - int len = vstr_len(line); - int escape = 0; - int hist_num = 0; - for (;;) { - char c; - for (;;) { - if (usb_vcp_rx_any() != 0) { - c = usb_vcp_rx_get(); - break; -#if 0 - } else if (usart_rx_any()) { - c = usart_rx_char(); - break; #endif - } - //delay(1); - //if (storage_needs_flush()) { - // storage_flush(); - //} - } - if (escape == 0) { - if (c == 4 && vstr_len(line) == len) { - return 0; - } else if (c == '\r') { - stdout_tx_str("\r\n"); - for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) { - readline_hist[i] = readline_hist[i - 1]; - } - readline_hist[0] = strdup(vstr_str(line)); - return 1; - } else if (c == 27) { - escape = true; - } else if (c == 127) { - if (vstr_len(line) > len) { - vstr_cut_tail(line, 1); - stdout_tx_str("\b \b"); - } - } else if (32 <= c && c <= 126) { - vstr_add_char(line, c); - stdout_tx_str(line->buf + line->len - 1); - } - } else if (escape == 1) { - if (c == '[') { - escape = 2; - } else { - escape = 0; - } - } else if (escape == 2) { - escape = 0; - if (c == 'A') { - // up arrow - if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) { - // erase line - for (int i = line->len - len; i > 0; i--) { - stdout_tx_str("\b \b"); - } - // set line to history - line->len = len; - vstr_add_str(line, readline_hist[hist_num]); - // draw line - stdout_tx_str(readline_hist[hist_num]); - // increase hist num - hist_num += 1; - } - } - } else { - escape = 0; - } - delay(10); - } -} - -bool do_file(const char *filename) { - mp_lexer_t *lex = mp_lexer_new_from_memzip_file(filename); - - if (lex == NULL) { - printf("could not open file '%s' for reading\n", filename); - return false; - } - - mp_parse_error_kind_t parse_error_kind; - mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind); - qstr source_name = mp_lexer_source_name(lex); - - if (pn == MP_PARSE_NODE_NULL) { - // parse error - mp_parse_show_exception(lex, parse_error_kind); - mp_lexer_free(lex); - return false; - } - - mp_lexer_free(lex); - - mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false); - mp_parse_node_free(pn); - - if (module_fun == mp_const_none) { - return false; - } - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_call_function_0(module_fun); - nlr_pop(); - return true; - } else { - // uncaught exception - mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR); - printf("\n"); - return false; - } -} - -void do_repl(void) { - stdout_tx_str("Micro Python build " MICROPY_GIT_HASH " on " MICROPY_BUILD_DATE "; Teensy 3.1 version\n"); - stdout_tx_str("Type \"help()\" for more information.\r\n"); - - vstr_t line; - vstr_init(&line, 32); - - for (;;) { - vstr_reset(&line); - int ret = readline(&line, ">>> "); - if (ret == 0) { - // EOF - break; - } - - if (vstr_len(&line) == 0) { - continue; - } - - while (mp_repl_continue_with_input(vstr_str(&line))) { - vstr_add_char(&line, '\n'); - int ret = readline(&line, "... "); - if (ret == 0) { - // stop entering compound statement - break; - } - } - - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0); - mp_parse_error_kind_t parse_error_kind; - mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind); - qstr source_name = mp_lexer_source_name(lex); - - if (pn == MP_PARSE_NODE_NULL) { - // parse error - mp_parse_show_exception(lex, parse_error_kind); - mp_lexer_free(lex); - } else { - // parse okay - mp_lexer_free(lex); - mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true); - if (module_fun != mp_const_none) { - nlr_buf_t nlr; - uint32_t start = micros(); - if (nlr_push(&nlr) == 0) { - mp_call_function_0(module_fun); - nlr_pop(); - // optional timing - if (0) { - uint32_t ticks = micros() - start; // TODO implement a function that does this properly - printf("(took %lu ms)\n", ticks); - } - } else { - // uncaught exception - mp_obj_print((mp_obj_t)nlr.ret_val, PRINT_REPR); - printf("\n"); - } - } - } - } - - stdout_tx_str("\r\n"); -} int main(void) { pinMode(LED_BUILTIN, OUTPUT); -#if 0 - // Wait for host side to get connected - while (!usb_vcp_is_connected()) { - ; - } -#else delay(1000); -#endif led_init(); - led_state(PYB_LED_BUILTIN, 1); // int first_soft_reset = true; soft_reset: + led_state(PYB_LED_BUILTIN, 1); + // GC init gc_init(&_heap_start, (void*)HEAP_END); qstr_init(); mp_init(); + readline_init(); + + //pin_init(); + +#if 0 // add some functions to the python namespace { mp_store_name(MP_QSTR_help, mp_make_function_n(0, pyb_help)); @@ -478,7 +285,7 @@ soft_reset: mp_store_attr(m, MP_QSTR_gc, mp_make_function_n(0, pyb_gc)); mp_store_attr(m, MP_QSTR_delay, mp_make_function_n(1, pyb_delay)); mp_store_attr(m, MP_QSTR_led, mp_make_function_n(1, pyb_led)); - mp_store_attr(m, MP_QSTR_Led, mp_make_function_n(1, pyb_Led)); + mp_store_attr(m, MP_QSTR_LED, (mp_obj_t)&pyb_led_type); mp_store_attr(m, MP_QSTR_analogRead, mp_make_function_n(1, pyb_analog_read)); mp_store_attr(m, MP_QSTR_analogWrite, mp_make_function_n(2, pyb_analog_write)); mp_store_attr(m, MP_QSTR_analogWriteResolution, mp_make_function_n(1, pyb_analog_write_resolution)); @@ -487,15 +294,12 @@ soft_reset: mp_store_attr(m, MP_QSTR_gpio, (mp_obj_t)&pyb_gpio_obj); mp_store_attr(m, MP_QSTR_Servo, mp_make_function_n(0, pyb_Servo)); mp_store_name(MP_QSTR_pyb, m); - mp_store_name(MP_QSTR_run, mp_make_function_n(1, pyb_run)); } +#endif - printf("About execute /boot.py\n"); - if (!do_file("/boot.py")) { - printf("Unable to open '/boot.py'\n"); + if (!pyexec_file("/boot.py")) { flash_error(4); } - printf("Done executing /boot.py\n"); // Turn bootup LED off led_state(PYB_LED_BUILTIN, 0); @@ -504,27 +308,30 @@ soft_reset: { vstr_t *vstr = vstr_new(); vstr_add_str(vstr, "/"); - if (pyb_config_source_dir == MP_OBJ_NULL) { - vstr_add_str(vstr, "src"); - } else { - vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir)); - } - vstr_add_char(vstr, '/'); if (pyb_config_main == MP_OBJ_NULL) { vstr_add_str(vstr, "main.py"); } else { vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main)); } - printf("About execute '%s'\n", vstr_str(vstr)); - if (!do_file(vstr_str(vstr))) { - printf("Unable to open '%s'\n", vstr_str(vstr)); + if (!pyexec_file(vstr_str(vstr))) { flash_error(3); } - printf("Done executing '%s'\n", vstr_str(vstr)); vstr_free(vstr); } - do_repl(); + // enter REPL + // REPL mode can change, or it can request a soft reset + for (;;) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } + } + } printf("PYB: soft reboot\n"); @@ -532,22 +339,15 @@ soft_reset: goto soft_reset; } -double sqrt(double x) { - // TODO - return 0.0; -} - -machine_float_t machine_sqrt(machine_float_t x) { - // TODO - return x; -} - // stub out __libc_init_array. It's called by mk20dx128.c and is used to call // global C++ constructors. Since this is a C-only projects, we don't need to // call constructors. void __libc_init_array(void) { } +// ultoa is used by usb_init_serialnumber. Normally ultoa would be provided +// by nonstd.c from the teensy core, but it conflicts with some of the +// MicroPython functions in string0.c, so we provide ultoa here. char * ultoa(unsigned long val, char *buf, int radix) { unsigned digit; @@ -569,3 +369,12 @@ char * ultoa(unsigned long val, char *buf, int radix) } return buf; } + +STATIC NORETURN mp_obj_t mp_sys_exit(uint n_args, const mp_obj_t *args) { + int rc = 0; + if (n_args > 0) { + rc = mp_obj_get_int(args[0]); + } + nlr_raise(mp_obj_new_exception_arg1(&mp_type_SystemExit, mp_obj_new_int(rc))); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit); diff --git a/teensy/make-pins.py b/teensy/make-pins.py new file mode 100755 index 0000000000..1fd05ec207 --- /dev/null +++ b/teensy/make-pins.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python +"""Creates the pin file for the Teensy.""" + +from __future__ import print_function + +import argparse +import sys +import csv + +SUPPORTED_FN = { + 'FTM' : ['CH0', 'CH1', 'CH2', 'CH3', + 'QD_PHA', 'QD_PHB'], + 'I2C' : ['SDA', 'SCL'], + 'UART' : ['RX', 'TX', 'CTS', 'RTS'], + 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI'] +} + +def parse_port_pin(name_str): + """Parses a string and returns a (port-num, pin-num) tuple.""" + if len(name_str) < 4: + raise ValueError("Expecting pin name to be at least 4 charcters.") + if name_str[0:2] != 'PT': + raise ValueError("Expecting pin name to start with PT") + if name_str[2] not in ('A', 'B', 'C', 'D', 'E', 'Z'): + raise ValueError("Expecting pin port to be between A and E or Z") + port = ord(name_str[2]) - ord('A') + pin_str = name_str[3:].split('/')[0] + if not pin_str.isdigit(): + raise ValueError("Expecting numeric pin number.") + return (port, int(pin_str)) + +def split_name_num(name_num): + num = None + for num_idx in range(len(name_num) - 1, -1, -1): + if not name_num[num_idx].isdigit(): + name = name_num[0:num_idx + 1] + num_str = name_num[num_idx + 1:] + if len(num_str) > 0: + num = int(num_str) + break + return name, num + + +class AlternateFunction(object): + """Holds the information associated with a pins alternate function.""" + + def __init__(self, idx, af_str): + self.idx = idx + self.af_str = af_str + + self.func = '' + self.fn_num = None + self.pin_type = '' + self.supported = False + + af_words = af_str.split('_', 1) + self.func, self.fn_num = split_name_num(af_words[0]) + if len(af_words) > 1: + self.pin_type = af_words[1] + if self.func in SUPPORTED_FN: + pin_types = SUPPORTED_FN[self.func] + if self.pin_type in pin_types: + self.supported = True + + def is_supported(self): + return self.supported + + def ptr(self): + """Returns the numbered function (i.e. USART6) for this AF.""" + if self.fn_num is None: + return self.func + return '{:s}{:d}'.format(self.func, self.fn_num) + + def print(self): + """Prints the C representation of this AF.""" + if self.supported: + print(' AF', end='') + else: + print(' //', end='') + fn_num = self.fn_num + if fn_num is None: + fn_num = 0 + print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, + self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + + +class Pin(object): + """Holds the information associated with a pin.""" + + def __init__(self, port, pin): + self.port = port + self.pin = pin + self.alt_fn = [] + self.alt_fn_count = 0 + self.adc_num = 0 + self.adc_channel = 0 + self.board_pin = False + + def port_letter(self): + return chr(self.port + ord('A')) + + def cpu_pin_name(self): + return '{:s}{:d}'.format(self.port_letter(), self.pin) + + def is_board_pin(self): + return self.board_pin + + def set_is_board_pin(self): + self.board_pin = True + + def parse_adc(self, adc_str): + if (adc_str[:3] != 'ADC'): + return + (adc,channel) = adc_str.split('_') + for idx in range(3, len(adc)): + adc_num = int(adc[idx]) # 1, 2, or 3 + self.adc_num |= (1 << (adc_num - 1)) + self.adc_channel = int(channel[2:]) + + def parse_af(self, af_idx, af_strs_in): + if len(af_strs_in) == 0: + return + # If there is a slash, then the slash separates 2 aliases for the + # same alternate function. + af_strs = af_strs_in.split('/') + for af_str in af_strs: + alt_fn = AlternateFunction(af_idx, af_str) + self.alt_fn.append(alt_fn) + if alt_fn.is_supported(): + self.alt_fn_count += 1 + + def alt_fn_name(self, null_if_0=False): + if null_if_0 and self.alt_fn_count == 0: + return 'NULL' + return 'pin_{:s}_af'.format(self.cpu_pin_name()) + + def adc_num_str(self): + str = '' + for adc_num in range(1,4): + if self.adc_num & (1 << (adc_num - 1)): + if len(str) > 0: + str += ' | ' + str += 'PIN_ADC' + str += chr(ord('0') + adc_num) + if len(str) == 0: + str = '0' + return str + + def print(self): + if self.alt_fn_count == 0: + print("// ", end='') + print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name())) + for alt_fn in self.alt_fn: + alt_fn.print() + if self.alt_fn_count == 0: + print("// ", end='') + print('};') + print('') + print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s}, {:s}, {:d});'.format( + self.cpu_pin_name(), self.port_letter(), self.pin, + self.alt_fn_count, self.alt_fn_name(null_if_0=True), + self.adc_num_str(), self.adc_channel)) + print('') + + def print_header(self, hdr_file): + hdr_file.write('extern const pin_obj_t pin_{:s};\n'. + format(self.cpu_pin_name())) + if self.alt_fn_count > 0: + hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. + format(self.cpu_pin_name())) + +class NamedPin(object): + + def __init__(self, name, pin): + self._name = name + self._pin = pin + + def pin(self): + return self._pin + + def name(self): + return self._name + + +class Pins(object): + + def __init__(self): + self.cpu_pins = [] # list of NamedPin objects + self.board_pins = [] # list of NamedPin objects + + def find_pin(self, port_num, pin_num): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.port == port_num and pin.pin == pin_num: + return pin + + def parse_af_file(self, filename, pinname_col, af_col): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[pinname_col]) + except: + continue + pin = Pin(port_num, pin_num) + for af_idx in range(af_col, len(row)): + if af_idx >= af_col: + pin.parse_af(af_idx - af_col, row[af_idx]) + self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) + + def parse_board_file(self, filename): + with open(filename, 'r') as csvfile: + rows = csv.reader(csvfile) + for row in rows: + try: + (port_num, pin_num) = parse_port_pin(row[1]) + except: + continue + pin = self.find_pin(port_num, pin_num) + if pin: + pin.set_is_board_pin() + self.board_pins.append(NamedPin(row[0], pin)) + + def print_named(self, label, named_pins): + print('const pin_named_pin_t pin_{:s}_pins[] = {{'.format(label)) + for named_pin in named_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + print(' {{ "{:s}", &pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) + print(' { NULL, NULL }') + print('};') + + def print(self): + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print() + self.print_named('cpu', self.cpu_pins) + print('') + self.print_named('board', self.board_pins) + + def print_adc(self, adc_num): + print(''); + print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) + for channel in range(16): + adc_found = False + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if (pin.is_board_pin() and + (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)): + print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel)) + adc_found = True + break + if not adc_found: + print(' NULL, // {:d}'.format(channel)) + print('};') + + + def print_header(self, hdr_filename): + with open(hdr_filename, 'wt') as hdr_file: + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + pin.print_header(hdr_file) + hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') + hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + + +def main(): + parser = argparse.ArgumentParser( + prog="make-pins.py", + usage="%(prog)s [options] [command]", + description="Generate board specific pin file" + ) + parser.add_argument( + "-a", "--af", + dest="af_filename", + help="Specifies the alternate function file for the chip", + default="stm32f4xx-af.csv" + ) + parser.add_argument( + "-b", "--board", + dest="board_filename", + help="Specifies the board file", + ) + parser.add_argument( + "-p", "--prefix", + dest="prefix_filename", + help="Specifies beginning portion of generated pins file", + default="stm32f4xx-prefix.c" + ) + parser.add_argument( + "-r", "--hdr", + dest="hdr_filename", + help="Specifies name of generated pin header file", + default="build/pins.h" + ) + args = parser.parse_args(sys.argv[1:]) + + pins = Pins() + + print('// This file was automatically generated by make-pins.py') + print('//') + if args.af_filename: + print('// --af {:s}'.format(args.af_filename)) + pins.parse_af_file(args.af_filename, 4, 3) + + if args.board_filename: + print('// --board {:s}'.format(args.board_filename)) + pins.parse_board_file(args.board_filename) + + if args.prefix_filename: + print('// --prefix {:s}'.format(args.prefix_filename)) + print('') + with open(args.prefix_filename, 'r') as prefix_file: + print(prefix_file.read()) + pins.print() + pins.print_adc(1) + pins.print_adc(2) + pins.print_adc(3) + pins.print_header(args.hdr_filename) + + +if __name__ == "__main__": + main() diff --git a/teensy/memzip.c b/teensy/memzip.c index ec6c26980c..b269c472a1 100644 --- a/teensy/memzip.c +++ b/teensy/memzip.c @@ -1,12 +1,13 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> +#include "misc.h" #include "memzip.h" extern uint8_t _staticfs[]; -MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) -{ +const MEMZIP_FILE_HDR *memzip_find_file_header(const char *filename) { + const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)_staticfs; uint8_t *mem_data; @@ -22,16 +23,83 @@ MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) mem_data += file_hdr->extra_len; if (!strncmp(file_hdr_filename, filename, file_hdr->filename_len)) { /* We found a match */ - if (file_hdr->compression_method != 0) { - return MZ_FILE_COMPRESSED; - } + return file_hdr; + } + mem_data += file_hdr->uncompressed_size; + file_hdr = (const MEMZIP_FILE_HDR *)mem_data; + } + return NULL; +} - *data = mem_data; - *len = file_hdr->uncompressed_size; - return MZ_OK; +bool memzip_is_dir(const char *filename) { + const MEMZIP_FILE_HDR *file_hdr = (const MEMZIP_FILE_HDR *)_staticfs; + uint8_t *mem_data; + + if (strcmp(filename, "/") == 0) { + // The root directory is a directory. + return true; + } + + // Zip filenames don't have a leading /, so we strip it off + if (*filename == '/') { + filename++; + } + size_t filename_len = strlen(filename); + + while (file_hdr->signature == MEMZIP_FILE_HEADER_SIGNATURE) { + const char *file_hdr_filename = (const char *)&file_hdr[1]; + if (filename_len < file_hdr->filename_len && + strncmp(file_hdr_filename, filename, filename_len) == 0 && + file_hdr_filename[filename_len] == '/') { + return true; } + + mem_data = (uint8_t *)file_hdr_filename; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; mem_data += file_hdr->uncompressed_size; file_hdr = (const MEMZIP_FILE_HDR *)mem_data; } - return MZ_NO_FILE; + return NULL; + +} + +MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len) +{ + const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(filename); + if (file_hdr == NULL) { + return MZ_NO_FILE; + } + if (file_hdr->compression_method != 0) { + return MZ_FILE_COMPRESSED; + } + + uint8_t *mem_data; + mem_data = (uint8_t *)&file_hdr[1]; + mem_data += file_hdr->filename_len; + mem_data += file_hdr->extra_len; + + *data = mem_data; + *len = file_hdr->uncompressed_size; + return MZ_OK; +} + +MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info) { + const MEMZIP_FILE_HDR *file_hdr = memzip_find_file_header(path); + if (file_hdr == NULL) { + if (memzip_is_dir(path)) { + info->file_size = 0; + info->last_mod_date = 0; + info->last_mod_time = 0; + info->is_dir = 1; + return MZ_OK; + } + return MZ_NO_FILE; + } + info->file_size = file_hdr->uncompressed_size; + info->last_mod_date = file_hdr->last_mod_date; + info->last_mod_time = file_hdr->last_mod_time; + info->is_dir = 0; + + return MZ_OK; } diff --git a/teensy/memzip.h b/teensy/memzip.h index ecbd98763c..667e2df7e1 100644 --- a/teensy/memzip.h +++ b/teensy/memzip.h @@ -70,4 +70,14 @@ typedef enum { } MEMZIP_RESULT; +typedef struct { + uint32_t file_size; + uint16_t last_mod_date; + uint16_t last_mod_time; + uint8_t is_dir; + +} MEMZIP_FILE_INFO; + MEMZIP_RESULT memzip_locate(const char *filename, void **data, size_t *len); + +MEMZIP_RESULT memzip_stat(const char *path, MEMZIP_FILE_INFO *info); diff --git a/teensy/memzip_files/boot.py b/teensy/memzip_files/boot.py index 3fe9f05e53..4702d7b5d3 100644 --- a/teensy/memzip_files/boot.py +++ b/teensy/memzip_files/boot.py @@ -1 +1,2 @@ +import pyb print("Executing boot.py") diff --git a/teensy/memzip_files/src/main.py b/teensy/memzip_files/main.py index 8fc08db15e..4f30f2fc5f 100644 --- a/teensy/memzip_files/src/main.py +++ b/teensy/memzip_files/main.py @@ -1,11 +1,13 @@ print("Executing main.py") -x=pyb.led(1) +led = pyb.LED(1) + +led.on() pyb.delay(100) -x=pyb.led(0) +led.off() pyb.delay(100) -x=pyb.led(1) +led.on() pyb.delay(100) -x=pyb.led(0) +led.off() diff --git a/teensy/memzip_files/src/test.py b/teensy/memzip_files/src/test.py deleted file mode 100644 index 7957b27caf..0000000000 --- a/teensy/memzip_files/src/test.py +++ /dev/null @@ -1 +0,0 @@ -print("Executing /src/test.py") diff --git a/teensy/memzip_files/test.py b/teensy/memzip_files/test.py deleted file mode 100644 index 088cb4383a..0000000000 --- a/teensy/memzip_files/test.py +++ /dev/null @@ -1 +0,0 @@ -print("Executing /test.py") diff --git a/teensy/mk20dx256-af.csv b/teensy/mk20dx256-af.csv new file mode 100644 index 0000000000..3015c6c7a1 --- /dev/null +++ b/teensy/mk20dx256-af.csv @@ -0,0 +1,65 @@ +Pin,Name,Default,ALT0,ALT1,ALT2,ALT3,ALT4,ALT5,ALT6,ALT7,EzPort +1,PTE0,ADC1_SE4a,ADC1_SE4a,PTE0,SPI1_PCS1,UART1_TX,,,I2C1_SDA,RTC_CLKOUT, +2,PTE1/LLWU_P0,ADC1_SE5a,ADC1_SE5a,PTE1/LLWU_P0,SPI1_SOUT,UART1_RX,,,I2C1_SCL,SPI1_SIN, +3,VDD,VDD,VDD,,,,,,,, +4,VSS,VSS,VSS,,,,,,,, +5,USB0_DP,USB0_DP,USB0_DP,,,,,,,, +6,USB0_DM,USB0_DM,USB0_DM,,,,,,,, +7,VOUT33,VOUT33,VOUT33,,,,,,,, +8,VREGIN,VREGIN,VREGIN,,,,,,,, +9,PGA0_DP/ADC0_DP0/ADC1_DP3,PGA0_DP/ADC0_DP0/ADC1_DP3,PGA0_DP/ADC0_DP0/ADC1_DP3,PTZ0,,,,,,, +10,PGA0_DM/ADC0_DM0/ADC1_DM3,PGA0_DM/ADC0_DM0/ADC1_DM3,PGA0_DM/ADC0_DM0/ADC1_DM3,PTZ1,,,,,,, +11,PGA1_DP/ADC1_DP0/ADC0_DP3,PGA1_DP/ADC1_DP0/ADC0_DP3,PGA1_DP/ADC1_DP0/ADC0_DP3,PTZ2,,,,,,, +12,PGA1_DM/ADC1_DM0/ADC0_DM3,PGA1_DM/ADC1_DM0/ADC0_DM3,PGA1_DM/ADC1_DM0/ADC0_DM3,PTZ3,,,,,,, +13,VDDA,VDDA,VDDA,,,,,,,, +14,VREFH,VREFH,VREFH,,,,,,,, +15,VREFL,VREFL,VREFL,,,,,,,, +16,VSSA,VSSA,VSSA,,,,,,,, +17,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,VREF_OUT/CMP1_IN5/CMP0_IN5/ADC1_SE18,PTZ4,,,,,,, +18,DAC0_OUT/CMP1_IN3/ADC0_SE23,DAC0_OUT/CMP1_IN3/ADC0_SE23,DAC0_OUT/CMP1_IN3/ADC0_SE23,PTZ5,,,,,,, +19,XTAL32,XTAL32,XTAL32,,,,,,,, +20,EXTAL32,EXTAL32,EXTAL32,,,,,,,, +21,VBAT,VBAT,VBAT,,,,,,,, +22,PTA0,JTAG_TCLK/SWD_CLK/EZP_CLK,TSI0_CH1,PTA0,UART0_CTS_b/UART0_COL_b,FTM0_CH5,,,,JTAG_TCLK/SWD_CLK,EZP_CLK +23,PTA1,JTAG_TDI/EZP_DI,TSI0_CH2,PTA1,UART0_RX,FTM0_CH6,,,,JTAG_TDI,EZP_DI +24,PTA2,JTAG_TDO/TRACE_SWO/EZP_DO,TSI0_CH3,PTA2,UART0_TX,FTM0_CH7,,,,JTAG_TDO/TRACE_SWO,EZP_DO +25,PTA3,JTAG_TMS/SWD_DIO,TSI0_CH4,PTA3,UART0_RTS_b,FTM0_CH0,,,,JTAG_TMS/SWD_DIO, +26,PTA4/LLWU_P3,NMI_b/EZP_CS_b,TSI0_CH5,PTA4/LLWU_P3,,FTM0_CH1,,,NMI_b,EZP_CS_b, +27,PTA5,DISABLED,,PTA5,USB_CLKIN,FTM0_CH2,,CMP2_OUT,I2S0_TX_BCLK,JTAG_TRST_b, +28,PTA12,CMP2_IN0,CMP2_IN0,PTA12,CAN0_TX,FTM1_CH0,,,I2S0_TXD0,FTM1_QD_PHA, +29,PTA13/LLWU_P4,CMP2_IN1,CMP2_IN1,PTA13/LLWU_P4,CAN0_RX,FTM1_CH1,,,I2S0_TX_FS,FTM1_QD_PHB, +30,VDD,VDD,VDD,,,,,,,, +31,VSS,VSS,VSS,,,,,,,, +32,PTA18,EXTAL0,EXTAL0,PTA18,,FTM0_FLT2,FTM_CLKIN0,,,, +33,PTA19,XTAL0,XTAL0,PTA19,,FTM1_FLT0,FTM_CLKIN1,,LPTMR0_ALT1,, +34,RESET_b,RESET_b,RESET_b,,,,,,,, +35,PTB0/LLWU_P5,ADC0_SE8/ADC1_SE8/TSI0_CH0,ADC0_SE8/ADC1_SE8/TSI0_CH0,PTB0/LLWU_P5,I2C0_SCL,FTM1_CH0,,,FTM1_QD_PHA,, +36,PTB1,ADC0_SE9/ADC1_SE9/TSI0_CH6,ADC0_SE9/ADC1_SE9/TSI0_CH6,PTB1,I2C0_SDA,FTM1_CH1,,,FTM1_QD_PHB,, +37,PTB2,ADC0_SE12/TSI0_CH7,ADC0_SE12/TSI0_CH7,PTB2,I2C0_SCL,UART0_RTS_b,,,FTM0_FLT3,, +38,PTB3,ADC0_SE13/TSI0_CH8,ADC0_SE13/TSI0_CH8,PTB3,I2C0_SDA,UART0_CTS_b/UART0_COL_b,,,FTM0_FLT0,, +39,PTB16,TSI0_CH9,TSI0_CH9,PTB16,SPI1_SOUT,UART0_RX,,FB_AD17,EWM_IN,, +40,PTB17,TSI0_CH10,TSI0_CH10,PTB17,SPI1_SIN,UART0_TX,,FB_AD16,EWM_OUT_b,, +41,PTB18,TSI0_CH11,TSI0_CH11,PTB18,CAN0_TX,FTM2_CH0,I2S0_TX_BCLK,FB_AD15,FTM2_QD_PHA,, +42,PTB19,TSI0_CH12,TSI0_CH12,PTB19,CAN0_RX,FTM2_CH1,I2S0_TX_FS,FB_OE_b,FTM2_QD_PHB,, +43,PTC0,ADC0_SE14/TSI0_CH13,ADC0_SE14/TSI0_CH13,PTC0,SPI0_PCS4,PDB0_EXTRG,,FB_AD14,I2S0_TXD1,, +44,PTC1/LLWU_P6,ADC0_SE15/TSI0_CH14,ADC0_SE15/TSI0_CH14,PTC1/LLWU_P6,SPI0_PCS3,UART1_RTS_b,FTM0_CH0,FB_AD13,I2S0_TXD0,, +45,PTC2,ADC0_SE4b/CMP1_IN0/TSI0_CH15,ADC0_SE4b/CMP1_IN0/TSI0_CH15,PTC2,SPI0_PCS2,UART1_CTS_b,FTM0_CH1,FB_AD12,I2S0_TX_FS,, +46,PTC3/LLWU_P7,CMP1_IN1,CMP1_IN1,PTC3/LLWU_P7,SPI0_PCS1,UART1_RX,FTM0_CH2,CLKOUT,I2S0_TX_BCLK,, +47,VSS,VSS,VSS,,,,,,,, +48,VDD,VDD,VDD,,,,,,,, +49,PTC4/LLWU_P8,DISABLED,,PTC4/LLWU_P8,SPI0_PCS0,UART1_TX,FTM0_CH3,FB_AD11,CMP1_OUT,, +50,PTC5/LLWU_P9,DISABLED,,PTC5/LLWU_P9,SPI0_SCK,LPTMR0_ALT2,I2S0_RXD0,FB_AD10,CMP0_OUT,, +51,PTC6/LLWU_P10,CMP0_IN0,CMP0_IN0,PTC6/LLWU_P10,SPI0_SOUT,PDB0_EXTRG,I2S0_RX_BCLK,FB_AD9,I2S0_MCLK,, +52,PTC7,CMP0_IN1,CMP0_IN1,PTC7,SPI0_SIN,USB_SOF_OUT,I2S0_RX_FS,FB_AD8,,, +53,PTC8,ADC1_SE4b/CMP0_IN2,ADC1_SE4b/CMP0_IN2,PTC8,,,I2S0_MCLK,FB_AD7,,, +54,PTC9,ADC1_SE5b/CMP0_IN3,ADC1_SE5b/CMP0_IN3,PTC9,,,I2S0_RX_BCLK,FB_AD6,FTM2_FLT0,, +55,PTC10,ADC1_SE6b,ADC1_SE6b,PTC10,I2C1_SCL,,I2S0_RX_FS,FB_AD5,,, +56,PTC11/LLWU_P11,ADC1_SE7b,ADC1_SE7b,PTC11/LLWU_P11,I2C1_SDA,,I2S0_RXD1,FB_RW_b,,, +57,PTD0/LLWU_P12,DISABLED,,PTD0/LLWU_P12,SPI0_PCS0,UART2_RTS_b,,FB_ALE/FB_CS1_b/FB_TS_b,,, +58,PTD1,ADC0_SE5b,ADC0_SE5b,PTD1,SPI0_SCK,UART2_CTS_b,,FB_CS0_b,,, +59,PTD2/LLWU_P13,DISABLED,,PTD2/LLWU_P13,SPI0_SOUT,UART2_RX,,FB_AD4,,, +60,PTD3,DISABLED,,PTD3,SPI0_SIN,UART2_TX,,FB_AD3,,, +61,PTD4/LLWU_P14,DISABLED,,PTD4/LLWU_P14,SPI0_PCS1,UART0_RTS_b,FTM0_CH4,FB_AD2,EWM_IN,, +62,PTD5,ADC0_SE6b,ADC0_SE6b,PTD5,SPI0_PCS2,UART0_CTS_b/UART0_COL_b,FTM0_CH5,FB_AD1,EWM_OUT_b,, +63,PTD6/LLWU_P15,ADC0_SE7b,ADC0_SE7b,PTD6/LLWU_P15,SPI0_PCS3,UART0_RX,FTM0_CH6,FB_AD0,FTM0_FLT0,, +64,PTD7,DISABLED,,PTD7,CMT_IRO,UART0_TX,FTM0_CH7,,FTM0_FLT1,, diff --git a/teensy/mk20dx256-prefix.c b/teensy/mk20dx256-prefix.c new file mode 100644 index 0000000000..ea9eec74a2 --- /dev/null +++ b/teensy/mk20dx256-prefix.c @@ -0,0 +1,37 @@ +// stm32fxx-prefix.c becomes the initial portion of the generated pins file. + +#include <stdio.h> +#include <stdint.h> +#include <mk20dx128.h> + +#include "teensy_hal.h" + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "pin.h" + +#define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ +{ \ + { &pin_af_type }, \ + .idx = (af_idx), \ + .fn = AF_FN_ ## af_fn, \ + .unit = (af_unit), \ + .type = AF_PIN_TYPE_ ## af_fn ## _ ## af_type, \ + .af_fn = (af_ptr) \ +} + +#define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ +{ \ + { &pin_type }, \ + .name = #p_port #p_pin, \ + .port = PORT_ ## p_port, \ + .pin = (p_pin), \ + .num_af = (p_num_af), \ + .pin_mask = (1 << (p_pin)), \ + .gpio = GPIO ## p_port, \ + .af = p_af, \ + .adc_num = p_adc_num, \ + .adc_channel = p_adc_channel, \ +} diff --git a/teensy/mk20dx256.ld b/teensy/mk20dx256.ld index e46efd3e26..bff0a8c4aa 100644 --- a/teensy/mk20dx256.ld +++ b/teensy/mk20dx256.ld @@ -10,10 +10,10 @@ * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -30,8 +30,8 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K - RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K + RAM (rwx) : ORIGIN = 0x1FFF8000, LENGTH = 64K } /* produce a link error if there is not this amount of RAM for these sections */ @@ -52,10 +52,10 @@ _minimum_heap_size = 16K; * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * 1. The above copyright notice and this permission notice shall be + * 1. The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * 2. If the Software is incorporated into a build system that allows + * 2. If the Software is incorporated into a build system that allows * selection among a list of target devices, then similar target * devices manufactured by PJRC.COM must be included in the list of * target devices and selectable in the same manner. @@ -74,95 +74,101 @@ _minimum_heap_size = 16K; SECTIONS { - .text : { - . = 0; - KEEP(*(.vectors)) - *(.startup*) - /* TODO: does linker detect startup overflow onto flashconfig? */ - . = 0x400; - KEEP(*(.flashconfig*)) - *(.text*) - *(.rodata*) - . = ALIGN(4); - KEEP(*(.init)) - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - } > FLASH = 0xFF - - .ARM.exidx : { - __exidx_start = .; - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - __exidx_end = .; - } > FLASH - _etext = .; - - .usbdescriptortable (NOLOAD) : { - /* . = ORIGIN(RAM); */ - . = ALIGN(512); - *(.usbdescriptortable*) - } > RAM - - .dmabuffers (NOLOAD) : { - . = ALIGN(4); - *(.dmabuffers*) - } > RAM - - .usbbuffers (NOLOAD) : { - . = ALIGN(4); - *(.usbbuffers*) - } > RAM - - .data : AT (_etext) { - . = ALIGN(4); - _sdata = .; - *(.data*) - . = ALIGN(4); - _edata = .; - } > RAM - - /* - * _staticfs is the place in flash where the static filesystem which - * is concatenated to the .hex file will wind up. - */ - _staticfs = LOADADDR(.data) + SIZEOF(.data); - - .noinit (NOLOAD) : { - *(.noinit*) - } > RAM - - .bss : { - . = ALIGN(4); - _sbss = .; - *(.bss*) - *(COMMON) - . = ALIGN(4); - _ebss = .; - __bss_end = .; - } > RAM - - /* this is to define the start of the heap, and make sure we have a minimum size */ - .heap : - { - . = ALIGN(4); - _heap_start = .; /* define a global symbol at heap start */ - . = . + _minimum_heap_size; - } >RAM - - /* this just checks there is enough RAM for the stack */ - .stack : - { - . = ALIGN(4); - . = . + _minimum_stack_size; - . = ALIGN(4); - } >RAM - - _estack = ORIGIN(RAM) + LENGTH(RAM); + .text : { + . = 0; + KEEP(*(.vectors)) + *(.startup*) + /* TODO: does linker detect startup overflow onto flashconfig? */ + . = 0x400; + KEEP(*(.flashconfig*)) + *(.text*) + *(.rodata*) + . = ALIGN(4); + KEEP(*(.init)) + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + } > FLASH = 0xFF + + .ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + _etext = .; + + .usbdescriptortable (NOLOAD) : { + /* . = ORIGIN(RAM); */ + . = ALIGN(512); + *(.usbdescriptortable*) + } > RAM + + .dmabuffers (NOLOAD) : { + . = ALIGN(4); + *(.dmabuffers*) + } > RAM + + .usbbuffers (NOLOAD) : { + . = ALIGN(4); + *(.usbbuffers*) + } > RAM + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + .data : AT (_etext) { + . = ALIGN(4); + _sdata = .; + _ram_start = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } > RAM + + /* + * _staticfs is the place in flash where the static filesystem which + * is concatenated to the .hex file will wind up. + */ + _staticfs = LOADADDR(.data) + SIZEOF(.data); + + .noinit (NOLOAD) : { + *(.noinit*) + } > RAM + + .bss : { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + __bss_end = .; + } > RAM + + /* this is to define the start of the heap, and make sure we have a minimum size */ + .heap : + { + . = ALIGN(4); + _heap_start = .; /* define a global symbol at heap start */ + . = . + _minimum_heap_size; + } >RAM + + /* this just checks there is enough RAM for the stack */ + .stack : + { + . = ALIGN(4); + . = . + _minimum_stack_size; + . = ALIGN(4); + } >RAM + + _estack = ORIGIN(RAM) + LENGTH(RAM); + _ram_end = ORIGIN(RAM) + LENGTH(RAM); + _heap_end = ORIGIN(RAM) + 0xe000; } diff --git a/teensy/modpyb.c b/teensy/modpyb.c new file mode 100644 index 0000000000..0240395dc7 --- /dev/null +++ b/teensy/modpyb.c @@ -0,0 +1,341 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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 <stdint.h> +#include <stdio.h> +#include <mk20dx128.h> +#include "Arduino.h" + +#include "misc.h" +#include "mpconfig.h" + +#include "teensy_hal.h" + +#include "qstr.h" +#include "obj.h" +#include "gc.h" +#include "gccollect.h" +#include "systick.h" +#include "pybstdio.h" +#include "pyexec.h" +#include "led.h" +#include "pin.h" +//#include "timer.h" +#include "extint.h" +#include "usrsw.h" +#include "rng.h" +//#include "rtc.h" +//#include "i2c.h" +//#include "spi.h" +#include "uart.h" +#include "adc.h" +#include "storage.h" +#include "sdcard.h" +#include "accel.h" +#include "servo.h" +#include "dac.h" +#include "usb.h" +#include "portmodules.h" + +/// \module pyb - functions related to the pyboard +/// +/// The `pyb` module contains specific functions related to the pyboard. + +/// \function bootloader() +/// Activate the bootloader without BOOT* pins. +STATIC mp_obj_t pyb_bootloader(void) { + printf("bootloader command not current supported\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_bootloader_obj, pyb_bootloader); + +/// \function info([dump_alloc_table]) +/// Print out lots of information about the board. +STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) { + // get and print unique id; 96 bits + { + byte *id = (byte*)0x40048058; + printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]); + } + + // get and print clock speeds + printf("CPU=%u\nBUS=%u\nMEM=%u\n", F_CPU, F_BUS, F_MEM); + + // to print info about memory + { + printf("_etext=%p\n", &_etext); + printf("_sidata=%p\n", &_sidata); + printf("_sdata=%p\n", &_sdata); + printf("_edata=%p\n", &_edata); + printf("_sbss=%p\n", &_sbss); + printf("_ebss=%p\n", &_ebss); + printf("_estack=%p\n", &_estack); + printf("_ram_start=%p\n", &_ram_start); + printf("_heap_start=%p\n", &_heap_start); + printf("_heap_end=%p\n", &_heap_end); + printf("_ram_end=%p\n", &_ram_end); + } + + // qstr info + { + uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); + printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + } + + // GC info + { + gc_info_t info; + gc_info(&info); + printf("GC:\n"); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); + } + + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info); + +/// \function unique_id() +/// Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU. +STATIC mp_obj_t pyb_unique_id(void) { + byte *id = (byte*)0x40048058; + return mp_obj_new_bytes(id, 12); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id); + +/// \function freq() +/// Return a tuple of clock frequencies: (SYSCLK, HCLK, PCLK1, PCLK2). +// TODO should also be able to set frequency via this function +STATIC mp_obj_t pyb_freq(void) { + mp_obj_t tuple[3] = { + mp_obj_new_int(F_CPU), + mp_obj_new_int(F_BUS), + mp_obj_new_int(F_MEM), + }; + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq); + +/// \function sync() +/// Sync all file systems. +STATIC mp_obj_t pyb_sync(void) { + printf("sync not currently implemented\n"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync); + +/// \function millis() +/// Returns the number of milliseconds since the board was last reset. +STATIC mp_obj_t pyb_millis(void) { + return mp_obj_new_int(HAL_GetTick()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis); + +/// \function delay(ms) +/// Delay for the given number of milliseconds. +STATIC mp_obj_t pyb_delay(mp_obj_t ms_in) { + machine_int_t ms = mp_obj_get_int(ms_in); + if (ms >= 0) { + HAL_Delay(ms); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay); + +/// \function udelay(us) +/// Delay for the given number of microseconds. +STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) { + machine_int_t usec = mp_obj_get_int(usec_in); + delayMicroseconds(usec); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay); + +/// \function wfi() +/// Wait for an interrupt. +/// This executies a `wfi` instruction which reduces power consumption +/// of the MCU until an interrupt occurs, at which point execution continues. +STATIC mp_obj_t pyb_wfi(void) { + __WFI(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi); + +/// \function disable_irq() +/// Disable interrupt requests. +STATIC mp_obj_t pyb_disable_irq(void) { + __disable_irq(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq); + +/// \function enable_irq() +/// Enable interrupt requests. +STATIC mp_obj_t pyb_enable_irq(void) { + __enable_irq(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_enable_irq_obj, pyb_enable_irq); + +STATIC mp_obj_t pyb_stop(void) { + printf("stop not currently implemented\n"); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_0(pyb_stop_obj, pyb_stop); + +STATIC mp_obj_t pyb_standby(void) { + printf("standby not currently implemented\n"); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby); + +/// \function have_cdc() +/// Return True if USB is connected as a serial device, False otherwise. +STATIC mp_obj_t pyb_have_cdc(void ) { + return MP_BOOL(usb_vcp_is_connected()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc); + +/// \function hid((buttons, x, y, z)) +/// Takes a 4-tuple (or list) and sends it to the USB host (the PC) to +/// signal a HID mouse-motion event. +STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { +#if 1 + printf("hid_send_report not currently implemented\n"); +#else + mp_obj_t *items; + mp_obj_get_array_fixed_n(arg, 4, &items); + uint8_t data[4]; + data[0] = mp_obj_get_int(items[0]); + data[1] = mp_obj_get_int(items[1]); + data[2] = mp_obj_get_int(items[2]); + data[3] = mp_obj_get_int(items[3]); + usb_hid_send_report(data); +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); + +MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); // defined in main.c + +STATIC const mp_map_elem_t pyb_module_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&pyb_bootloader_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_wfi), (mp_obj_t)&pyb_wfi_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&pyb_stop_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_source_dir), (mp_obj_t)&pyb_source_dir_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_usb_mode), (mp_obj_t)&pyb_usb_mode_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_have_cdc), (mp_obj_t)&pyb_have_cdc_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj }, + +// { MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type }, + +//#if MICROPY_HW_ENABLE_RNG +// { MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&pyb_rng_get_obj }, +//#endif + +//#if MICROPY_HW_ENABLE_RTC +// { MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type }, +//#endif + + { MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type }, +// { MP_OBJ_NEW_QSTR(MP_QSTR_ExtInt), (mp_obj_t)&extint_type }, + +#if MICROPY_HW_ENABLE_SERVO + { MP_OBJ_NEW_QSTR(MP_QSTR_pwm), (mp_obj_t)&pyb_pwm_set_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_servo), (mp_obj_t)&pyb_servo_set_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_Servo), (mp_obj_t)&pyb_servo_type }, +#endif + +#if MICROPY_HW_HAS_SWITCH + { MP_OBJ_NEW_QSTR(MP_QSTR_Switch), (mp_obj_t)&pyb_switch_type }, +#endif + +//#if MICROPY_HW_HAS_SDCARD +// { MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sdcard_obj }, +//#endif + + { MP_OBJ_NEW_QSTR(MP_QSTR_LED), (mp_obj_t)&pyb_led_type }, +// { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type }, +// { MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type }, + +// { MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type }, +// { MP_OBJ_NEW_QSTR(MP_QSTR_ADCAll), (mp_obj_t)&pyb_adc_all_type }, + +//#if MICROPY_HW_ENABLE_DAC +// { MP_OBJ_NEW_QSTR(MP_QSTR_DAC), (mp_obj_t)&pyb_dac_type }, +//#endif + +//#if MICROPY_HW_HAS_MMA7660 +// { MP_OBJ_NEW_QSTR(MP_QSTR_Accel), (mp_obj_t)&pyb_accel_type }, +//#endif +}; + +STATIC const mp_obj_dict_t pyb_module_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = ARRAY_SIZE(pyb_module_globals_table), + .alloc = ARRAY_SIZE(pyb_module_globals_table), + .table = (mp_map_elem_t*)pyb_module_globals_table, + }, +}; + +const mp_obj_module_t pyb_module = { + .base = { &mp_type_module }, + .name = MP_QSTR_pyb, + .globals = (mp_obj_dict_t*)&pyb_module_globals, +}; diff --git a/teensy/mpconfigport.h b/teensy/mpconfigport.h index f7c66d8874..ff0a31f272 100644 --- a/teensy/mpconfigport.h +++ b/teensy/mpconfigport.h @@ -2,20 +2,98 @@ // options to control how Micro Python is built +#define MICROPY_ALLOC_PATH_MAX (128) #define MICROPY_EMIT_THUMB (1) #define MICROPY_EMIT_INLINE_THUMB (1) #define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_OPT_COMPUTED_GOTO (1) + +#define MICROPY_PY_IO (0) +#define MICROPY_PY_FROZENSET (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_CMATH (1) + +// extra built in names to add to the global namespace +extern const struct _mp_obj_fun_native_t mp_builtin_help_obj; +extern const struct _mp_obj_fun_native_t mp_builtin_input_obj; +extern const struct _mp_obj_fun_native_t mp_builtin_open_obj; +#define MICROPY_PORT_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \ + +// extra built in modules to add to the list of known ones +extern const struct _mp_obj_module_t os_module; +extern const struct _mp_obj_module_t pyb_module; +extern const struct _mp_obj_module_t time_module; +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ + +// extra constants +#define MICROPY_PORT_CONSTANTS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ // type definitions for the specific machine #define BYTES_PER_WORD (4) +#define UINT_FMT "%u" +#define INT_FMT "%d" + typedef int32_t machine_int_t; // must be pointer size -typedef uint32_t machine_uint_t; // must be pointer size +typedef unsigned int machine_uint_t; // must be pointer size typedef void *machine_ptr_t; // must be of pointer size typedef const void *machine_const_ptr_t; // must be of pointer size -typedef float machine_float_t; -machine_float_t machine_sqrt(machine_float_t x); +// There is no classical C heap in bare-metal ports, only Python +// garbage-collected heap. For completeness, emulate C heap via +// GC heap. Note that MicroPython core never uses malloc() and friends, +// so these defines are mostly to help extension module writers. +#define malloc gc_alloc +#define free gc_free +#define realloc gc_realloc + +// We need to provide a declaration/definition of alloca() +#include <alloca.h> + +// The following would be from a board specific file, if one existed + +#define MICROPY_HW_BOARD_NAME "Teensy-3.1" + +#define MICROPY_HW_HAS_SWITCH (0) +#define MICROPY_HW_HAS_SDCARD (0) +#define MICROPY_HW_HAS_MMA7660 (0) +#define MICROPY_HW_HAS_LIS3DSH (0) +#define MICROPY_HW_HAS_LCD (0) +#define MICROPY_HW_ENABLE_RNG (0) +#define MICROPY_HW_ENABLE_RTC (0) +#define MICROPY_HW_ENABLE_TIMER (0) +#define MICROPY_HW_ENABLE_SERVO (0) +#define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_I2C1 (0) +#define MICROPY_HW_ENABLE_SPI1 (0) +#define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) + +#define MICROPY_HW_LED1 (pin_C5) +#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) +#define MICROPY_HW_LED_ON(pin) (pin->gpio->PSOR = pin->pin_mask) +#define MICROPY_HW_LED_OFF(pin) (pin->gpio->PCOR = pin->pin_mask) + +#if 0 +// SD card detect switch +#define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) +#define MICROPY_HW_SDCARD_DETECT_PULL (GPIO_PULLUP) +#define MICROPY_HW_SDCARD_DETECT_PRESENT (GPIO_PIN_RESET) +#endif + +#define MICROPY_MATH_SQRT_ASM (1) + +#define MICROPY_HAL_H "teensy_hal.h" +#define MICROPY_PIN_DEFS_PORT_H "pin_defs_teensy.h" diff --git a/teensy/pin_defs_teensy.h b/teensy/pin_defs_teensy.h new file mode 100644 index 0000000000..66942c2ea8 --- /dev/null +++ b/teensy/pin_defs_teensy.h @@ -0,0 +1,46 @@ +enum { + PORT_A, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + PORT_Z, +}; + +enum { + AF_FN_FTM, + AF_FN_I2C, + AF_FN_UART, + AF_FN_SPI +}; + +enum { + AF_PIN_TYPE_FTM_CH0 = 0, + AF_PIN_TYPE_FTM_CH1, + AF_PIN_TYPE_FTM_CH2, + AF_PIN_TYPE_FTM_CH3, + AF_PIN_TYPE_FTM_QD_PHA, + AF_PIN_TYPE_FTM_QD_PHB, + + AF_PIN_TYPE_I2C_SDA = 0, + AF_PIN_TYPE_I2C_SCL, + + AF_PIN_TYPE_SPI_MOSI = 0, + AF_PIN_TYPE_SPI_MISO, + AF_PIN_TYPE_SPI_SCK, + AF_PIN_TYPE_SPI_NSS, + + AF_PIN_TYPE_UART_TX = 0, + AF_PIN_TYPE_UART_RX, + AF_PIN_TYPE_UART_CTS, + AF_PIN_TYPE_UART_RTS, +}; + +#define PIN_DEFS_PORT_AF_UNION \ + FTM_TypeDef *FTM; \ + I2C_TypeDef *I2C; \ + UART_TypeDef *UART; \ + SPI_TypeDef *SPI; + +typedef GPIO_TypeDef pin_gpio_t; + diff --git a/teensy/qstrdefsport.h b/teensy/qstrdefsport.h index 8b23a86bf0..2fb70af7b4 100644 --- a/teensy/qstrdefsport.h +++ b/teensy/qstrdefsport.h @@ -20,7 +20,7 @@ Q(mma_mode) Q(hid) Q(time) Q(rand) -Q(Led) +Q(LED) Q(led) Q(Servo) Q(I2C) @@ -32,5 +32,63 @@ Q(analogRead) Q(analogWrite) Q(analogWriteResolution) Q(analogWriteFrequency) -Q(run) +Q(on) +Q(off) +Q(toggle) +Q(readall) +Q(readline) +Q(FileIO) +Q(input) +Q(os) +Q(bootloader) +Q(unique_id) +Q(freq) +Q(repl_info) +Q(wfi) +Q(disable_irq) +Q(enable_irq) +Q(usb_mode) +Q(have_cdc) +Q(millis) +Q(udelay) +Q(UART) + +// for Pin class +Q(Pin) +Q(PinAF) +Q(PinNamed) +Q(init) +Q(value) +Q(low) +Q(high) +Q(name) +Q(port) +Q(pin) +Q(mapper) +Q(dict) +Q(debug) +Q(board) +Q(cpu) +Q(IN) +Q(OUT_PP) +Q(OUT_OD) +Q(AF_PP) +Q(AF_OD) +Q(ANALOG) +Q(PULL_NONE) +Q(PULL_UP) +Q(PULL_DOWN) + +// for UART class +Q(UART) +Q(baudrate) +Q(bits) +Q(stop) +Q(parity) +Q(init) +Q(deinit) +Q(all) +Q(send) +Q(recv) +Q(timeout) diff --git a/teensy/servo.h b/teensy/servo.h index c4a5bd49b1..5dad041138 100644 --- a/teensy/servo.h +++ b/teensy/servo.h @@ -1,2 +1,7 @@ -mp_obj_t pyb_Servo(void); +void servo_init(void); + +extern const mp_obj_type_t pyb_servo_type; + +MP_DECLARE_CONST_FUN_OBJ(pyb_servo_set_obj); +MP_DECLARE_CONST_FUN_OBJ(pyb_pwm_set_obj); diff --git a/teensy/teensy-pins.csv b/teensy/teensy-pins.csv new file mode 100644 index 0000000000..acaef63aad --- /dev/null +++ b/teensy/teensy-pins.csv @@ -0,0 +1,55 @@ +D0,PTB16 +D1,PTB17 +D2,PTD0 +D3,PTA12 +D4,PTA13 +D5,PTD7 +D6,PTD4 +D7,PTD2 +D8,PTD3 +D9,PTC3 +D10,PTC4 +D11,PTC6 +D12,PTC7 +D13,PTC5 +D14,PTD1 +D15,PTC0 +D16,PTB0 +D17,PTB1 +D18,PTB3 +D19,PTB2 +D20,PTD5 +D21,PTD6 +D22,PTC1 +D23,PTC2 +D24,PTA5 +D25,PTB19 +D26,PTE1 +D27,PTC9 +D28,PTC8 +D29,PTC10 +D30,PTC11 +D31,PTE0 +D32,PTB18 +D33,PTA4 +A0,PTD1 +A1,PTC0 +A2,PTB0 +A3,PTB1 +A4,PTB3 +A5,PTB2 +A6,PTD5 +A7,PTD6 +A8,PTC1 +A9,PTC2 +A10,PTZ0 +A11,PTZ1 +A12,PTZ2 +A13,PTZ3 +A14,PTZ5 +A15,PTE1 +A16,PTC9 +A17,PTC8 +A18,PTC10 +A19,PTC11 +A20,PTE0 diff --git a/teensy/teensy_hal.c b/teensy/teensy_hal.c new file mode 100644 index 0000000000..b7ac842af8 --- /dev/null +++ b/teensy/teensy_hal.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#include <stdint.h> + +#include "mpconfig.h" + +#include "Arduino.h" + +#include MICROPY_HAL_H + +uint32_t HAL_GetTick(void) { + return micros(); +} + +void HAL_Delay(uint32_t Delay) { + delay(Delay); +} diff --git a/teensy/teensy_hal.h b/teensy/teensy_hal.h new file mode 100644 index 0000000000..ff16c98c5c --- /dev/null +++ b/teensy/teensy_hal.h @@ -0,0 +1,111 @@ + +#ifdef USE_FULL_ASSERT + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#define FTM0 ((FTM_TypeDef *)&FTM0_SC) +#define FTM1 ((FTM_TypeDef *)&FTM1_SC) +#define FTM2 ((FTM_TypeDef *)&FTM2_SC) + +#define GPIOA ((GPIO_TypeDef *)&GPIOA_PDOR) +#define GPIOB ((GPIO_TypeDef *)&GPIOB_PDOR) +#define GPIOC ((GPIO_TypeDef *)&GPIOC_PDOR) +#define GPIOD ((GPIO_TypeDef *)&GPIOD_PDOR) +#define GPIOE ((GPIO_TypeDef *)&GPIOE_PDOR) +#define GPIOZ ((GPIO_TypeDef *)NULL) + +#define I2C0 ((I2C_TypeDef *)0x40066000) +#define I2C1 ((I2C_TypeDef *)0x40067000) + +#undef SPI0 +#define SPI0 ((SPI_TypeDef *)0x4002C000) +#define SPI1 ((SPI_TypeDef *)0x4002D000) + +#define UART0 ((UART_TypeDef *)&UART0_BDH) +#define UART1 ((UART_TypeDef *)&UART1_BDH) +#define UART2 ((UART_TypeDef *)&UART2_BDH) + +typedef struct { + uint32_t dummy; +} FTM_TypeDef; + +typedef struct { + uint32_t dummy; +} I2C_TypeDef; + +typedef struct { + uint32_t dummy; +} UART_TypeDef; + +typedef struct { + uint32_t dummy; +} SPI_TypeDef; + +typedef struct { + volatile uint32_t PDOR; // Output register + volatile uint32_t PSOR; // Set output register + volatile uint32_t PCOR; // Clear output register + volatile uint32_t PTOR; // Toggle output register + volatile uint32_t PDIR; // Data Input register + volatile uint32_t PDDR; // Data Direction register +} GPIO_TypeDef; + +#define GPIO_OUTPUT_TYPE ((uint32_t)0x00000010) // Indicates OD + +#define GPIO_MODE_INPUT ((uint32_t)0x00000000) +#define GPIO_MODE_OUTPUT_PP ((uint32_t)0x00000001) +#define GPIO_MODE_OUTPUT_OD ((uint32_t)0x00000011) +#define GPIO_MODE_AF_PP ((uint32_t)0x00000002) +#define GPIO_MODE_AF_OD ((uint32_t)0x00000012) +#define GPIO_MODE_ANALOG ((uint32_t)0x00000003) + +#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_MODE_INPUT) ||\ + ((MODE) == GPIO_MODE_OUTPUT_PP) ||\ + ((MODE) == GPIO_MODE_OUTPUT_OD) ||\ + ((MODE) == GPIO_MODE_AF_PP) ||\ + ((MODE) == GPIO_MODE_AF_OD) ||\ + ((MODE) == GPIO_MODE_ANALOG)) + +#define GPIO_NOPULL ((uint32_t)0) +#define GPIO_PULLUP ((uint32_t)1) +#define GPIO_PULLDOWN ((uint32_t)2) + +#define IS_GPIO_PULL(PULL) (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ + ((PULL) == GPIO_PULLDOWN)) + +#define GPIO_SPEED_LOW ((uint32_t)0) +#define GPIO_SPEED_MEDIUM ((uint32_t)1) +#define GPIO_SPEED_FAST ((uint32_t)2) +#define GPIO_SPEED_HIGH ((uint32_t)3) + + +typedef struct { + uint32_t Pin; + uint32_t Mode; + uint32_t Pull; + uint32_t Speed; + uint32_t Alternate; +} GPIO_InitTypeDef; + +#define GPIO_PORT_TO_PORT_NUM(GPIOx) \ + ((GPIOx->PDOR - GPIOA_PDOR) / (GPIOB_PDOR - GPIOA_PDOR)) + +#define GPIO_PIN_TO_PORT_PCR(GPIOx, pin) \ + (&PORTA_PCR0 + GPIO_PORT_TO_PORT_NUM(GPIOx) * 32 + (pin)) + +__attribute__(( always_inline )) static inline void __WFI(void) +{ + __asm volatile ("wfi"); +} + +uint32_t HAL_GetTick(void); +void HAL_Delay(uint32_t Delay); + +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *init); + +#define GPIO_read_pin(gpio, pin) (((gpio)->PDIR >> (pin)) & 1) +#define GPIO_set_pin(gpio, pin_mask) (((gpio)->PSOR) = (pin_mask)) +#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->PCOR) = (pin_mask)) diff --git a/teensy/uart.c b/teensy/uart.c new file mode 100644 index 0000000000..97a1a058c9 --- /dev/null +++ b/teensy/uart.c @@ -0,0 +1,522 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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 <stdio.h> +#include <string.h> + +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include MICROPY_HAL_H +#include "bufhelper.h" +#include "uart.h" + +/// \moduleref pyb +/// \class UART - duplex serial communication bus +/// +/// UART implements the standard UART/USART duplex serial communications protocol. At +/// the physical level it consists of 2 lines: RX and TX. +/// +/// See usage model of I2C. UART is very similar. Main difference is +/// parameters to init the UART bus: +/// +/// from pyb import UART +/// +/// uart = UART(1, 9600) # init with given baudrate +/// uart.init(9600, bits=8, stop=1, parity=None) # init with given parameters +/// +/// Bits can be 8 or 9, stop can be 1 or 2, parity can be None, 0 (even), 1 (odd). +/// +/// Extra method: +/// +/// uart.any() # returns True if any characters waiting + +struct _pyb_uart_obj_t { + mp_obj_base_t base; + pyb_uart_t uart_id; + bool is_enabled; +// UART_HandleTypeDef uart; +}; + +pyb_uart_obj_t *pyb_uart_global_debug = NULL; + +// assumes Init parameters have been set up correctly +bool uart_init2(pyb_uart_obj_t *uart_obj) { +#if 0 + USART_TypeDef *UARTx = NULL; + + uint32_t GPIO_Pin = 0; + uint8_t GPIO_AF_UARTx = 0; + GPIO_TypeDef* GPIO_Port = NULL; + + switch (uart_obj->uart_id) { + // USART1 is on PA9/PA10 (CK on PA8), PB6/PB7 + case PYB_UART_1: + UARTx = USART1; + GPIO_AF_UARTx = GPIO_AF7_USART1; + +#if defined (PYBV4) || defined(PYBV10) + GPIO_Port = GPIOB; + GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; +#else + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10; +#endif + + __USART1_CLK_ENABLE(); + break; + + // USART2 is on PA2/PA3 (CK on PA4), PD5/PD6 (CK on PD7) + case PYB_UART_2: + UARTx = USART2; + GPIO_AF_UARTx = GPIO_AF7_USART2; + + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_2 | GPIO_PIN_3; + + __USART2_CLK_ENABLE(); + break; + + // USART3 is on PB10/PB11 (CK on PB12), PC10/PC11 (CK on PC12), PD8/PD9 (CK on PD10) + case PYB_UART_3: + UARTx = USART3; + GPIO_AF_UARTx = GPIO_AF7_USART3; + +#if defined(PYBV3) || defined(PYBV4) | defined(PYBV10) + GPIO_Port = GPIOB; + GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11; +#else + GPIO_Port = GPIOD; + GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; +#endif + __USART3_CLK_ENABLE(); + break; + + // UART4 is on PA0/PA1, PC10/PC11 + case PYB_UART_4: + UARTx = UART4; + GPIO_AF_UARTx = GPIO_AF8_UART4; + + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1; + + __UART4_CLK_ENABLE(); + break; + + // USART6 is on PC6/PC7 (CK on PC8) + case PYB_UART_6: + UARTx = USART6; + GPIO_AF_UARTx = GPIO_AF8_USART6; + + GPIO_Port = GPIOC; + GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; + + __USART6_CLK_ENABLE(); + break; + + default: + return false; + } + + // init GPIO + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Pin = GPIO_Pin; + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Alternate = GPIO_AF_UARTx; + HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure); + + // init UARTx + uart_obj->uart.Instance = UARTx; + HAL_UART_Init(&uart_obj->uart); + + uart_obj->is_enabled = true; +#endif + return true; +} + +bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate) { +#if 0 + UART_HandleTypeDef *uh = &uart_obj->uart; + memset(uh, 0, sizeof(*uh)); + uh->Init.BaudRate = baudrate; + uh->Init.WordLength = UART_WORDLENGTH_8B; + uh->Init.StopBits = UART_STOPBITS_1; + uh->Init.Parity = UART_PARITY_NONE; + uh->Init.Mode = UART_MODE_TX_RX; + uh->Init.HwFlowCtl = UART_HWCONTROL_NONE; + uh->Init.OverSampling = UART_OVERSAMPLING_16; +#endif + return uart_init2(uart_obj); +} + +void uart_deinit(pyb_uart_obj_t *uart_obj) { +#if 0 + uart_obj->is_enabled = false; + UART_HandleTypeDef *uart = &uart_obj->uart; + HAL_UART_DeInit(uart); + if (uart->Instance == USART1) { + __USART1_FORCE_RESET(); + __USART1_RELEASE_RESET(); + __USART1_CLK_DISABLE(); + } else if (uart->Instance == USART2) { + __USART2_FORCE_RESET(); + __USART2_RELEASE_RESET(); + __USART2_CLK_DISABLE(); + } else if (uart->Instance == USART3) { + __USART3_FORCE_RESET(); + __USART3_RELEASE_RESET(); + __USART3_CLK_DISABLE(); + } else if (uart->Instance == UART4) { + __UART4_FORCE_RESET(); + __UART4_RELEASE_RESET(); + __UART4_CLK_DISABLE(); + } else if (uart->Instance == USART6) { + __USART6_FORCE_RESET(); + __USART6_RELEASE_RESET(); + __USART6_CLK_DISABLE(); + } +#endif +} + +bool uart_rx_any(pyb_uart_obj_t *uart_obj) { +#if 0 + return __HAL_UART_GET_FLAG(&uart_obj->uart, UART_FLAG_RXNE); +#else + return false; +#endif +} + +int uart_rx_char(pyb_uart_obj_t *uart_obj) { + uint8_t ch; +#if 0 + if (HAL_UART_Receive(&uart_obj->uart, &ch, 1, 0) != HAL_OK) { + ch = 0; + } +#else + ch = 'A'; +#endif + return ch; +} + +void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) { +#if 0 + uint8_t ch = c; + HAL_UART_Transmit(&uart_obj->uart, &ch, 1, 100000); +#endif +} + +void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str) { +#if 0 + HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, strlen(str), 100000); +#endif +} + +void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) { +#if 0 + HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, 100000); +#endif +} + +void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) { + for (const char *top = str + len; str < top; str++) { + if (*str == '\n') { + uart_tx_char(uart_obj, '\r'); + } + uart_tx_char(uart_obj, *str); + } +} + +/******************************************************************************/ +/* Micro Python bindings */ + +STATIC void pyb_uart_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_uart_obj_t *self = self_in; + if (!self->is_enabled) { + print(env, "UART(%lu)", self->uart_id); + } else { +#if 0 + print(env, "UART(%lu, baudrate=%u, bits=%u, stop=%u", + self->uart_id, self->uart.Init.BaudRate, + self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9, + self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2); + if (self->uart.Init.Parity == UART_PARITY_NONE) { + print(env, ", parity=None)"); + } else { + print(env, ", parity=%u)", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1); + } +#endif + } +} + +/// \method init(baudrate, *, bits=8, stop=1, parity=None) +/// +/// Initialise the SPI bus with the given parameters: +/// +/// - `baudrate` is the clock rate. +/// - `bits` is the number of bits per byte, 8 or 9. +/// - `stop` is the number of stop bits, 1 or 2. +/// - `parity` is the parity, `None`, 0 (even) or 1 (odd). +STATIC const mp_arg_t pyb_uart_init_args[] = { + { MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, +}; +#define PYB_UART_INIT_NUM_ARGS ARRAY_SIZE(pyb_uart_init_args) + +STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t vals[PYB_UART_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PYB_UART_INIT_NUM_ARGS, pyb_uart_init_args, vals); +#if 0 + // set the UART configuration values + memset(&self->uart, 0, sizeof(self->uart)); + UART_InitTypeDef *init = &self->uart.Init; + init->BaudRate = vals[0].u_int; + init->WordLength = vals[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B; + switch (vals[2].u_int) { + case 1: init->StopBits = UART_STOPBITS_1; break; + default: init->StopBits = UART_STOPBITS_2; break; + } + if (vals[3].u_obj == mp_const_none) { + init->Parity = UART_PARITY_NONE; + } else { + machine_int_t parity = mp_obj_get_int(vals[3].u_obj); + init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; + } + init->Mode = UART_MODE_TX_RX; + init->HwFlowCtl = UART_HWCONTROL_NONE; + init->OverSampling = UART_OVERSAMPLING_16; + + // init UART (if it fails, it's because the port doesn't exist) + if (!uart_init2(self)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART port %d does not exist", self->uart_id)); + } +#endif + + return mp_const_none; +} + +/// \classmethod \constructor(bus, ...) +/// +/// Construct a UART object on the given bus. `bus` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'. +/// With no additional parameters, the UART object is created but not +/// initialised (it has the settings from the last initialisation of +/// the bus, if any). If extra arguments are given, the bus is initialised. +/// See `init` for parameters of initialisation. +/// +/// The physical pins of the UART busses are: +/// +/// - `UART(4)` is on `XA`: `(TX, RX) = (X1, X2) = (PA0, PA1)` +/// - `UART(1)` is on `XB`: `(TX, RX) = (X9, X10) = (PB6, PB7)` +/// - `UART(6)` is on `YA`: `(TX, RX) = (Y1, Y2) = (PC6, PC7)` +/// - `UART(3)` is on `YB`: `(TX, RX) = (Y9, Y10) = (PB10, PB11)` +/// - `UART(2)` is on: `(TX, RX) = (X3, X4) = (PA2, PA3)` +STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // create object + pyb_uart_obj_t *o = m_new_obj(pyb_uart_obj_t); + o->base.type = &pyb_uart_type; + + // work out port + o->uart_id = 0; +#if 0 + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (0) { +#if defined(PYBV10) + } else if (strcmp(port, "XA") == 0) { + o->uart_id = PYB_UART_XA; + } else if (strcmp(port, "XB") == 0) { + o->uart_id = PYB_UART_XB; + } else if (strcmp(port, "YA") == 0) { + o->uart_id = PYB_UART_YA; + } else if (strcmp(port, "YB") == 0) { + o->uart_id = PYB_UART_YB; +#endif + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART port %s does not exist", port)); + } + } else { + o->uart_id = mp_obj_get_int(args[0]); + } +#endif + + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_uart_init_helper(o, n_args - 1, args + 1, &kw_args); + } + + return o; +} + +STATIC mp_obj_t pyb_uart_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init); + +/// \method deinit() +/// Turn off the UART bus. +STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + uart_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_deinit_obj, pyb_uart_deinit); + +/// \method any() +/// Return `True` if any characters waiting, else `False`. +STATIC mp_obj_t pyb_uart_any(mp_obj_t self_in) { + pyb_uart_obj_t *self = self_in; + if (uart_rx_any(self)) { + return mp_const_true; + } else { + return mp_const_false; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any); + +/// \method send(send, *, timeout=5000) +/// Send data on the bus: +/// +/// - `send` is the data to send (an integer to send, or a buffer object). +/// - `timeout` is the timeout in milliseconds to wait for the send. +/// +/// Return value: `None`. +STATIC const mp_arg_t pyb_uart_send_args[] = { + { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, +}; +#define PYB_UART_SEND_NUM_ARGS ARRAY_SIZE(pyb_uart_send_args) + +STATIC mp_obj_t pyb_uart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + pyb_uart_obj_t *self = args[0]; + + // parse args + mp_arg_val_t vals[PYB_UART_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_UART_SEND_NUM_ARGS, pyb_uart_send_args, vals); + +#if 0 + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // send the data + HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Transmit failed with code %d", status)); + } +#else + (void)self; +#endif + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_send_obj, 1, pyb_uart_send); + +/// \method recv(recv, *, timeout=5000) +/// +/// Receive data on the bus: +/// +/// - `recv` can be an integer, which is the number of bytes to receive, +/// or a mutable buffer, which will be filled with received bytes. +/// - `timeout` is the timeout in milliseconds to wait for the receive. +/// +/// Return value: if `recv` is an integer then a new buffer of the bytes received, +/// otherwise the same buffer that was passed in to `recv`. +STATIC const mp_arg_t pyb_uart_recv_args[] = { + { MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, +}; +#define PYB_UART_RECV_NUM_ARGS ARRAY_SIZE(pyb_uart_recv_args) + +STATIC mp_obj_t pyb_uart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide + + pyb_uart_obj_t *self = args[0]; + +#if 0 + // parse args + mp_arg_val_t vals[PYB_UART_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_UART_RECV_NUM_ARGS, pyb_uart_recv_args, vals); + + // get the buffer to receive into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); + + // receive the data + HAL_StatusTypeDef status = HAL_UART_Receive(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Receive failed with code %d", status)); + } + + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } +#else + (void)self; + return mp_const_none; +#endif +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_recv_obj, 1, pyb_uart_recv); + +STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_uart_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_uart_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_uart_recv_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table); + +const mp_obj_type_t pyb_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .print = pyb_uart_print, + .make_new = pyb_uart_make_new, + .locals_dict = (mp_obj_t)&pyb_uart_locals_dict, +}; diff --git a/teensy/usart.c b/teensy/usart.c deleted file mode 100644 index a700e8e379..0000000000 --- a/teensy/usart.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "misc.h" -#include "mpconfig.h" -#include "qstr.h" -#include "obj.h" -#include "../stm/usart.h" - -pyb_usart_t pyb_usart_global_debug = PYB_USART_NONE; - -void usart_init(pyb_usart_t usart_id, uint32_t baudrate) -{ - (void)usart_id; - (void)baudrate; -} - -bool usart_rx_any(pyb_usart_t usart_id) -{ - (void)usart_id; - return false; -} - -int usart_rx_char(pyb_usart_t usart_id) -{ - (void)usart_id; - return 0; -} - -void usart_tx_str(pyb_usart_t usart_id, const char *str) -{ - (void)usart_id; - (void)str; -} - -void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len) -{ - (void)usart_id; - (void)str; - (void)len; -} diff --git a/teensy/usb.c b/teensy/usb.c index a045a2ed69..ab4731f27b 100644 --- a/teensy/usb.c +++ b/teensy/usb.c @@ -13,8 +13,13 @@ int usb_vcp_is_enabled(void) return 1; } -int usb_vcp_rx_any(void) -{ +void usb_vcp_set_interrupt_char(int c) { + // The teensy 3.1 usb stack doesn't currently have the notion of generating + // an exception when a certain character is received. That just means that + // you can't press Control-C and get your python script to stop. +} + +int usb_vcp_rx_num(void) { return usb_serial_available(); } diff --git a/tests/basics/struct1.py b/tests/basics/struct1.py index b114a789b5..c3049c55d6 100644 --- a/tests/basics/struct1.py +++ b/tests/basics/struct1.py @@ -21,3 +21,7 @@ print(struct.calcsize("100sI")) print(struct.calcsize("97sI")) print(struct.unpack("<6sH", b"foo\0\0\0\x12\x34")) print(struct.pack("<6sH", b"foo", 10000)) + +s = struct.pack("BHBI", 10, 100, 200, 300) +v = struct.unpack("BHBI", s) +print(v == (10, 100, 200, 300)) diff --git a/tests/float/math-fun-bool.py b/tests/float/math-fun-bool.py index cf718d4b80..57232857ab 100644 --- a/tests/float/math-fun-bool.py +++ b/tests/float/math-fun-bool.py @@ -1,6 +1,11 @@ # Test the bool functions from math -from math import isfinite, isnan, isinf +try: + from math import isfinite, isnan, isinf +except ImportError: + print("SKIP") + import sys + sys.exit() test_values = [1, 0, -1, 1.0, 0.0, -1.0, float('NaN'), float('Inf'), -float('NaN'), -float('Inf')] diff --git a/tests/float/math-fun.py b/tests/float/math-fun.py index 7a37c58454..fa111e33e3 100644 --- a/tests/float/math-fun.py +++ b/tests/float/math-fun.py @@ -1,6 +1,11 @@ # Tests the functions imported from math -from math import * +try: + from math import * +except ImportError: + print("SKIP") + import sys + sys.exit() test_values = [-100., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 100.] p_test_values = [0.1, 0.5, 1.23456] diff --git a/tests/misc/recursion.py b/tests/misc/recursion.py new file mode 100644 index 0000000000..227f48396a --- /dev/null +++ b/tests/misc/recursion.py @@ -0,0 +1,7 @@ +def foo(): + foo() + +try: + foo() +except RuntimeError: + print("RuntimeError") diff --git a/tests/misc/recursive_data.py_ b/tests/misc/recursive_data.py_ new file mode 100644 index 0000000000..6a52a3c0e8 --- /dev/null +++ b/tests/misc/recursive_data.py_ @@ -0,0 +1,9 @@ +# This tests that printing recursive data structure doesn't lead to segfault. +# Unfortunately, print() so far doesn't support "file "kwarg, so variable-len +# output of this test cannot be redirected, and this test cannot be validated. +l = [1, 2, 3, None] +l[-1] = l +try: + print(l) +except RuntimeError: + print("RuntimeError") diff --git a/tests/run-tests b/tests/run-tests index 8f5f7d470d..c6bc4020d4 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -88,10 +88,10 @@ def run_tests(pyb, tests): rm_f(filename_expected) rm_f(filename_mupy) else: - with open(filename_expected, "w") as f: - f.write(str(output_expected, "ascii")) - with open(filename_mupy, "w") as f: - f.write(str(output_mupy, "ascii")) + with open(filename_expected, "wb") as f: + f.write(output_expected) + with open(filename_mupy, "wb") as f: + f.write(output_mupy) print("FAIL ", test_file) failed_tests.append(test_name) diff --git a/tests/unicode/data/utf-8_1.txt b/tests/unicode/data/utf-8_1.txt new file mode 100644 index 0000000000..d84c480d1d --- /dev/null +++ b/tests/unicode/data/utf-8_1.txt @@ -0,0 +1 @@ +Привет diff --git a/tests/unicode/file1.py b/tests/unicode/file1.py new file mode 100644 index 0000000000..554e886743 --- /dev/null +++ b/tests/unicode/file1.py @@ -0,0 +1,4 @@ +f = open("unicode/data/utf-8_1.txt") +l = f.readline() +print(l) +print(len(l)) diff --git a/tests/unicode/unicode.py b/tests/unicode/unicode.py new file mode 100644 index 0000000000..c7e523f06a --- /dev/null +++ b/tests/unicode/unicode.py @@ -0,0 +1,18 @@ +# Test a UTF-8 encoded literal +s = "asdf©qwer" +for i in range(len(s)): + print("s[%d]: %s %X"%(i, s[i], ord(s[i]))) + +# Test all three forms of Unicode escape, and +# all blocks of UTF-8 byte patterns +s = "a\xA9\xFF\u0123\u0800\uFFEE\U0001F44C" +for i in range(-len(s), len(s)): + print("s[%d]: %s %X"%(i, s[i], ord(s[i]))) + print("s[:%d]: %d chars, '%s'"%(i, len(s[:i]), s[:i])) + for j in range(i, len(s)): + print("s[%d:%d]: %d chars, '%s'"%(i, j, len(s[i:j]), s[i:j])) + print("s[%d:]: %d chars, '%s'"%(i, len(s[i:]), s[i:])) + +# Test UTF-8 encode and decode +enc = s.encode() +print(enc, enc.decode() == s) diff --git a/tests/unicode/unicode_index.py b/tests/unicode/unicode_index.py new file mode 100644 index 0000000000..3c31468a41 --- /dev/null +++ b/tests/unicode/unicode_index.py @@ -0,0 +1,6 @@ +print("Привет".find("т")) +print("Привет".find("П")) +print("Привет".rfind("т")) +print("Привет".rfind("П")) +print("Привет".index("т")) +print("Привет".index("П")) diff --git a/tests/unicode/unicode_iter.py b/tests/unicode/unicode_iter.py new file mode 100644 index 0000000000..f08a4aceed --- /dev/null +++ b/tests/unicode/unicode_iter.py @@ -0,0 +1,4 @@ +for c in "Hello": + print(c) +for c in "Привет": + print(c) diff --git a/tests/unicode/unicode_pos.py b/tests/unicode/unicode_pos.py new file mode 100644 index 0000000000..6a5982920a --- /dev/null +++ b/tests/unicode/unicode_pos.py @@ -0,0 +1,5 @@ +# str methods with explicit start/end pos +print("Привет".startswith("П")) +print("Привет".startswith("р", 1)) +print("абвба".find("а", 1)) +print("абвба".find("а", 1, -1)) diff --git a/tools/gendoc.py b/tools/gendoc.py index 5a33a8195d..727bc60d76 100644 --- a/tools/gendoc.py +++ b/tools/gendoc.py @@ -228,16 +228,18 @@ class DocModule(DocItem): s.append('# module {}'.format(self.name)) s.append('') s.append(super().dump()) - s.append('') - s.append('## Functions') - for f in sorted(self.functions.values(), key=lambda x:x.name): + if self.functions: s.append('') - s.append(f.dump(self.name)) - s.append('') - s.append('## Classes') - for c in sorted(self.classes.values(), key=lambda x:x.name): + s.append('## Functions') + for f in sorted(self.functions.values(), key=lambda x:x.name): + s.append('') + s.append(f.dump(self.name)) + if self.classes: s.append('') - s.append('[`{}.{}`]({}) - {}'.format(self.name, c.name, c.name, c.descr)) + s.append('## Classes') + for c in sorted(self.classes.values(), key=lambda x:x.name): + s.append('') + s.append('[`{}.{}`]({}) - {}'.format(self.name, c.name, c.name, c.descr)) return '\n'.join(s) def write(self, dir): diff --git a/unix/Makefile b/unix/Makefile index 485009135f..afe268ae45 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -7,6 +7,9 @@ PROG = micropython # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h +# OS name, for simple autoconfig +UNAME_S := $(shell uname -s) + # include py core make definitions include ../py/py.mk @@ -15,14 +18,18 @@ INC += -I$(PY_SRC) INC += -I$(BUILD) # compiler settings -CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) +CWARN = -Wall -Werror -Wno-error=cpp +CFLAGS = $(INC) $(CWARN) -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) -UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - LDFLAGS = $(LDFLAGS_MOD) -lm -Wl,-map,$@.map,-order_file,$(BUILD)/order.def - else - LDFLAGS = $(LDFLAGS_MOD) -lm -Wl,-Map=$@.map,--cref - endif +# Debugging/Optimization +ifdef DEBUG +CFLAGS += -g +COPT = -O0 +else +COPT = -Os #-DNDEBUG +endif + +LDFLAGS = $(LDFLAGS_MOD) -lm -Wl,-Map=$@.map,--cref $(LDFLAGS_EXTRA) ifeq ($(MICROPY_FORCE_32BIT),1) CFLAGS += -m32 @@ -56,14 +63,6 @@ SRC_MOD += modffi.c endif -# Debugging/Optimization -ifdef DEBUG -CFLAGS += -g -COPT = -O0 -else -COPT = -Os #-DNDEBUG -endif - # source files SRC_C = \ main.c \ @@ -75,6 +74,9 @@ SRC_C = \ $(SRC_MOD) ifeq ($(UNAME_S),Darwin) + +LDFLAGS+ = -Wl,-order_file,$(BUILD)/order.def + # Must be the last file in list of sources SRC_C += seg_helpers.c diff --git a/unix/gccollect.c b/unix/gccollect.c index 4f3b786e72..d04e5d87fb 100644 --- a/unix/gccollect.c +++ b/unix/gccollect.c @@ -26,13 +26,13 @@ #include <stdio.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "gc.h" #if MICROPY_ENABLE_GC -extern void *stack_top; +extern char *stack_top; #if MICROPY_GCREGS_SETJMP #include <setjmp.h> @@ -97,7 +97,7 @@ void gc_helper_get_regs(regs_t arr) { } #endif -#ifdef __thumb2__ +#if defined(__thumb2__) || defined(__thumb__) || defined(__arm__) typedef machine_uint_t regs_t[10]; void gc_helper_get_regs(regs_t arr) { @@ -130,8 +130,11 @@ void gc_collect(void) { gc_collect_start(); // this traces the .bss section -#ifdef __CYGWIN__ +#if defined( __CYGWIN__ ) #define BSS_START __bss_start__ +#elif defined( _MSC_VER ) || defined( __MINGW32__ ) +#define BSS_START *bss_start +#define _end *bss_end #else #define BSS_START __bss_start #endif @@ -141,7 +144,8 @@ void gc_collect(void) { regs_t regs; gc_helper_get_regs(regs); // GC stack (and regs because we captured them) - gc_collect_root((void**)®s, ((machine_uint_t)stack_top - (machine_uint_t)®s) / sizeof(machine_uint_t)); + void **regs_ptr = (void**)(void*)®s; + gc_collect_root(regs_ptr, ((machine_uint_t)stack_top - (machine_uint_t)®s) / sizeof(machine_uint_t)); gc_collect_end(); //printf("-----\n"); diff --git a/unix/input.c b/unix/input.c index 4d856f2ff8..19ca649c9f 100644 --- a/unix/input.c +++ b/unix/input.c @@ -41,8 +41,6 @@ #include <readline/history.h> #endif -#define CTRL_D '\x04' - char *prompt(char *p) { #if MICROPY_USE_READLINE char *line = readline(p); diff --git a/unix/main.c b/unix/main.c index 26736e4318..176cbc6ec3 100644 --- a/unix/main.c +++ b/unix/main.c @@ -51,6 +51,7 @@ #include "gc.h" #include "genhdr/py-version.h" #include "input.h" +#include "stackctrl.h" // Command line options, with their defaults bool compile_only = false; @@ -63,9 +64,6 @@ uint mp_verbose_flag; long heap_size = 128*1024 * (sizeof(machine_uint_t) / 4); #endif -// Stack top at the start of program -char *stack_top; - void microsocket_init(); void time_init(); void ffi_init(); @@ -149,7 +147,7 @@ STATIC char *strjoin(const char *s1, int sep_char, const char *s2) { } STATIC void do_repl(void) { - printf("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; UNIX version\n"); + printf("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_PY_SYS_PLATFORM " version\n"); for (;;) { char *line = prompt(">>> "); @@ -201,8 +199,8 @@ int usage(char **argv) { impl_opts_cnt++; #if MICROPY_ENABLE_GC printf( -" heapsize=<n> -- set the heap size for the GC\n" -); +" heapsize=<n> -- set the heap size for the GC (default %ld)\n" +, heap_size); impl_opts_cnt++; #endif @@ -214,10 +212,9 @@ int usage(char **argv) { } mp_obj_t mem_info(void) { - volatile int stack_dummy; printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated()); - printf("stack: " INT_FMT "\n", stack_top - (char*)&stack_dummy); + printf("stack: %u\n", mp_stack_usage()); #if MICROPY_ENABLE_GC gc_dump_info(); #endif @@ -268,8 +265,7 @@ void pre_process_options(int argc, char **argv) { #endif int main(int argc, char **argv) { - volatile int stack_dummy; - stack_top = (char*)&stack_dummy; + mp_stack_set_limit(32768); pre_process_options(argc, argv); @@ -365,7 +361,8 @@ int main(int argc, char **argv) { return usage(argv); } } else { - char *basedir = realpath(argv[a], NULL); + char *pathbuf = malloc(PATH_MAX); + char *basedir = realpath(argv[a], pathbuf); if (basedir == NULL) { fprintf(stderr, "%s: can't open file '%s': [Errno %d] ", argv[0], argv[a], errno); perror(""); @@ -377,7 +374,7 @@ int main(int argc, char **argv) { // Set base dir of the script as first entry in sys.path char *p = strrchr(basedir, '/'); path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); - free(basedir); + free(pathbuf); for (int i = a; i < argc; i++) { mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i]))); diff --git a/unix/modffi.c b/unix/modffi.c index bfc840ceff..eca3f9131b 100644 --- a/unix/modffi.c +++ b/unix/modffi.c @@ -51,6 +51,10 @@ * s - as argument, the same as "p", as return value, causes string * to be allocated and returned, instead of pointer value. * + * TODO: + * O - mp_obj_t, passed as is (mostly useful as callback param) + * C - callback function + * * Note: all constraint specified by typecode can be not enforced at this time, * but may be later. */ @@ -100,12 +104,15 @@ STATIC ffi_type *char2ffi_type(char c) switch (c) { case 'b': return &ffi_type_schar; case 'B': return &ffi_type_uchar; + case 'h': return &ffi_type_sshort; + case 'H': return &ffi_type_ushort; case 'i': return &ffi_type_sint; case 'I': return &ffi_type_uint; case 'l': return &ffi_type_slong; case 'L': return &ffi_type_ulong; case 'f': return &ffi_type_float; case 'd': return &ffi_type_double; + case 'C': // (*)() case 'P': // const void* case 'p': // void* case 's': return &ffi_type_pointer; @@ -421,8 +428,8 @@ STATIC const mp_obj_dict_t mp_module_ffi_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_ffi_globals_table), - .alloc = ARRAY_SIZE(mp_module_ffi_globals_table), + .used = MP_ARRAY_SIZE(mp_module_ffi_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_ffi_globals_table), .table = (mp_map_elem_t*)mp_module_ffi_globals_table, }, }; diff --git a/unix/modos.c b/unix/modos.c index 657958d04c..9b034cdbc2 100644 --- a/unix/modos.c +++ b/unix/modos.c @@ -30,8 +30,8 @@ #include <unistd.h> #include <errno.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "nlr.h" #include "qstr.h" #include "obj.h" @@ -75,8 +75,8 @@ STATIC const mp_obj_dict_t mp_module_os_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_os_globals_table), - .alloc = ARRAY_SIZE(mp_module_os_globals_table), + .used = MP_ARRAY_SIZE(mp_module_os_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_os_globals_table), .table = (mp_map_elem_t*)mp_module_os_globals_table, }, }; diff --git a/unix/modsocket.c b/unix/modsocket.c index b1a34a39b8..5b3fb01877 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -356,6 +356,8 @@ STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { const char *host = mp_obj_str_get_str(args[0]); const char *serv = NULL; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); // getaddrinfo accepts port in string notation, so however // it may seem stupid, we need to convert int to str if (MP_OBJ_IS_SMALL_INT(args[1])) { @@ -363,23 +365,35 @@ STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { char buf[6]; sprintf(buf, "%d", port); serv = buf; + hints.ai_flags = AI_NUMERICSERV; +#ifdef __UCLIBC_MAJOR__ +#if __UCLIBC_MAJOR__ == 0 && (__UCLIBC_MINOR__ < 9 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ <= 32)) +#warning Working around uClibc bug with numeric service name + // Older versions og uClibc have bugs when numeric ports in service + // arg require also hints.ai_socktype (or hints.ai_protocol) != 0 + // This actually was fixed in 0.9.32.1, but uClibc doesn't allow to + // test for that. + // http://git.uclibc.org/uClibc/commit/libc/inet/getaddrinfo.c?id=bc3be18145e4d5 + // Note that this is crude workaround, precluding UDP socket addresses + // to be returned. TODO: set only if not set by Python args. + hints.ai_socktype = SOCK_STREAM; +#endif +#endif } else { serv = mp_obj_str_get_str(args[1]); } - struct addrinfo hints; - struct addrinfo *addr; - memset(&hints, 0, sizeof(hints)); - int res = getaddrinfo(host, serv, NULL/*&hints*/, &addr); + struct addrinfo *addr_list; + int res = getaddrinfo(host, serv, &hints, &addr_list); if (res != 0) { // CPython: socket.gaierror nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[addrinfo error %d]", res)); } - assert(addr); + assert(addr_list); mp_obj_t list = mp_obj_new_list(0, NULL); - for (; addr; addr = addr->ai_next) { + for (struct addrinfo *addr = addr_list; addr; addr = addr->ai_next) { mp_obj_tuple_t *t = mp_obj_new_tuple(5, NULL); t->items[0] = MP_OBJ_NEW_SMALL_INT((machine_int_t)addr->ai_family); t->items[1] = MP_OBJ_NEW_SMALL_INT((machine_int_t)addr->ai_socktype); @@ -394,6 +408,7 @@ STATIC mp_obj_t mod_socket_getaddrinfo(uint n_args, const mp_obj_t *args) { t->items[4] = mp_obj_new_bytearray(addr->ai_addrlen, addr->ai_addr); mp_obj_list_append(list, t); } + freeaddrinfo(addr_list); return list; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod_socket_getaddrinfo); @@ -436,8 +451,8 @@ STATIC const mp_obj_dict_t mp_module_socket_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_socket_globals_table), - .alloc = ARRAY_SIZE(mp_module_socket_globals_table), + .used = MP_ARRAY_SIZE(mp_module_socket_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_socket_globals_table), .table = (mp_map_elem_t*)mp_module_socket_globals_table, }, }; diff --git a/unix/modtime.c b/unix/modtime.c index 3cc09e3cd8..286d8ea97e 100644 --- a/unix/modtime.c +++ b/unix/modtime.c @@ -30,8 +30,8 @@ #include <sys/time.h> #include <math.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -113,8 +113,8 @@ STATIC const mp_obj_dict_t mp_module_time_globals = { .map = { .all_keys_are_qstrs = 1, .table_is_fixed_array = 1, - .used = ARRAY_SIZE(mp_module_time_globals_table), - .alloc = ARRAY_SIZE(mp_module_time_globals_table), + .used = MP_ARRAY_SIZE(mp_module_time_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_time_globals_table), .table = (mp_map_elem_t*)mp_module_time_globals_table, }, }; diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 3426ae44fe..763b34ba3e 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -41,6 +41,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_OPT_COMPUTED_GOTO (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_PLATFORM "linux" @@ -53,7 +54,9 @@ #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) // Define to 1 to use untested inefficient GC helper implementation // (if more efficient arch-specific one is not available). +#ifndef MICROPY_GCREGS_SETJMP #define MICROPY_GCREGS_SETJMP (0) +#endif extern const struct _mp_obj_module_t mp_module_os; extern const struct _mp_obj_module_t mp_module_time; diff --git a/windows/Makefile b/windows/Makefile index a188979bd5..e3085ff23b 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -35,9 +35,11 @@ SRC_C = \ unix/file.c \ unix/input.c \ unix/modtime.c \ + unix/gccollect.c \ realpath.c \ init.c \ sleep.c \ + bss.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/windows/bss.c b/windows/bss.c new file mode 100644 index 0000000000..b860c4ee85 --- /dev/null +++ b/windows/bss.c @@ -0,0 +1,74 @@ +/* +* This file is part of the Micro Python project, http://micropython.org/ +* +* The MIT License (MIT) +* +* Copyright (c) 2013, 2014 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 "mpconfig.h" +#include "misc.h" +#include "nlr.h" +#include "qstr.h" +#include "obj.h" +#include <windows.h> + +IMAGE_NT_HEADERS *header_from_memory(const char *module) { + BYTE *base_addr = (BYTE*)GetModuleHandleA(module); + IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER*)base_addr; + return (IMAGE_NT_HEADERS*)(base_addr + dos_header->e_lfanew); +} + +IMAGE_SECTION_HEADER *find_section(IMAGE_NT_HEADERS *nt_header, const char *name) { + int i; + IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nt_header); + for (i = 0; i < nt_header->FileHeader.NumberOfSections; ++i) { + if (strcmp((const char *)section->Name, name) == 0) { + return section; + } + ++section; + } + return NULL; +} + +void section_boundaries(IMAGE_NT_HEADERS *nt_header, IMAGE_SECTION_HEADER *section, char **start, char **end) { + if (section == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Could not lookup section boundaries")); + } + *start = (char*)(nt_header->OptionalHeader.ImageBase + section->VirtualAddress); + *end = *start + section->Misc.VirtualSize; +} + +void section_boundaries_from_module(const char *module, const char *section, char **start, char **end) { + IMAGE_NT_HEADERS *nt_header = header_from_memory(module); + IMAGE_SECTION_HEADER *dsection = find_section(nt_header, section); + section_boundaries(nt_header, dsection, start, end); +} + +char *bss_start = 0; +char *bss_end = 0; + +//MSVC has no __bss_start and _end but we can get accurate section info from the PE header. +//The standard .bss section is appended to the standard .data section however so it cannot +//be looked up by name. To deal with that we put all uPy static variables in a named section. +void getbss() { + section_boundaries_from_module(NULL, MICROPY_PORT_BSSSECTION, &bss_start, &bss_end); +} diff --git a/windows/init.c b/windows/init.c index a370c464e8..57f349ef89 100644 --- a/windows/init.c +++ b/windows/init.c @@ -28,9 +28,12 @@ #include <stdio.h> #include <windows.h> +extern void getbss(); + HANDLE hSleepEvent = NULL; void init() { + getbss(); hSleepEvent = CreateEvent(NULL, TRUE, FALSE, FALSE); #ifdef __MINGW32__ putenv("PRINTF_EXPONENT_DIGITS=2"); diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index b9a50b0841..963fcfe768 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -35,16 +35,30 @@ #define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_ENABLE_FINALISER (1) #define MICROPY_MEM_STATS (1) #define MICROPY_DEBUG_PRINTERS (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_HELPER_LEXER_UNIX (1) -#define MICROPY_PY_BUILTINS_FROZENSET (1) -#define MICROPY_PY_CMATH (1) -#define MICROPY_PY_SYS_STDFILES (1) -#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_STREAMS_NON_BLOCK (1) +#define MICROPY_OPT_COMPUTED_GOTO (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_FROZENSET (1) +#define MICROPY_PY_SYS_EXIT (1) +#define MICROPY_PY_SYS_PLATFORM "win32" +#define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_CMATH (1) +#define MICROPY_PY_IO_FILEIO (1) +#define MICROPY_PY_GC_COLLECT_RETVAL (1) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#ifdef _MSC_VER +#define MICROPY_GCREGS_SETJMP (1) +#endif + #define MICROPY_PORT_INIT_FUNC init() #define MICROPY_PORT_DEINIT_FUNC deinit() @@ -113,6 +127,14 @@ void msec_sleep(double msec); #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +// Put static/global variables in sections with a known name we can lookup for the GC +// For this to work this header must be included by all sources, which is the case normally +#define MICROPY_PORT_DATASECTION "upydata" +#define MICROPY_PORT_BSSSECTION "upybss" +#pragma data_seg(MICROPY_PORT_DATASECTION) +#pragma bss_seg(MICROPY_PORT_BSSSECTION) + + // System headers (needed e.g. for nlr.h) #include <stddef.h> //for NULL @@ -122,3 +144,8 @@ void msec_sleep(double msec); int snprintf(char *dest, size_t count, const char *format, ...); #endif + +// MingW specifics +#ifdef __MINGW32__ +#define MICROPY_PORT_BSSSECTION ".bss" +#endif diff --git a/windows/msvc/common.props b/windows/msvc/common.props index 300de46a53..b6f22c6151 100644 --- a/windows/msvc/common.props +++ b/windows/msvc/common.props @@ -16,7 +16,8 @@ </ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
+ <GenerateMapFile>true</GenerateMapFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
-</Project>
\ No newline at end of file +</Project>
diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props index 8af03e7563..6fd3306b92 100644 --- a/windows/msvc/sources.props +++ b/windows/msvc/sources.props @@ -5,7 +5,7 @@ </PropertyGroup> <ItemGroup> <ClCompile Include="$(PyBaseDir)py\*.c" /> - <ClCompile Include="$(PyBaseDir)unix\*.c" Exclude="$(PyBaseDir)unix\modffi.c;$(PyBaseDir)unix\modsocket.c" /> + <ClCompile Include="$(PyBaseDir)unix\*.c" Exclude="$(PyBaseDir)unix\modffi.c;$(PyBaseDir)unix\modsocket.c;$(PyBaseDir)unix\seg_helpers.c" /> <ClCompile Include="$(PyBaseDir)windows\*.c" /> <ClCompile Include="$(PyBaseDir)windows\msvc\*.c" /> </ItemGroup> |