diff options
-rw-r--r-- | py/mkrules.mk | 2 | ||||
-rw-r--r-- | py/mpconfig.h | 6 | ||||
-rw-r--r-- | py/objstr.c | 2 | ||||
-rw-r--r-- | py/vm.c | 1418 | ||||
-rw-r--r-- | stmhal/modpyb.c | 8 | ||||
-rw-r--r-- | stmhal/qstrdefsport.h | 1 | ||||
-rw-r--r-- | stmhal/usart.c | 80 | ||||
-rw-r--r-- | stmhal/usart.h | 14 | ||||
-rw-r--r-- | stmhal/usbd_cdc_interface.c | 10 | ||||
-rw-r--r-- | tools/pyboard.py | 36 | ||||
-rw-r--r-- | unix/mpconfigport.h | 1 |
11 files changed, 882 insertions, 696 deletions
diff --git a/py/mkrules.mk b/py/mkrules.mk index ab4514d1c4..08ba8fc416 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -59,7 +59,7 @@ $(BUILD)/%.pp: %.c # object directories (but only for existance), and the object directories # will be created if they don't exist. OBJ_DIRS = $(sort $(dir $(OBJ))) -$(OBJ): | $(OBJ_DIRS) +$(OBJ): $(PY_BUILD)/qstrdefs.generated.h | $(OBJ_DIRS) $(OBJ_DIRS): $(MKDIR) -p $@ diff --git a/py/mpconfig.h b/py/mpconfig.h index f9c02a6f02..8f60c997bd 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -154,6 +154,12 @@ typedef double mp_float_t; #define MICROPY_PATH_MAX (512) #endif +// Whether to use computed gotos in the VM, or a switch +// Computed gotos are roughly 10% faster, and increase VM code size by a little +#ifndef MICROPY_USE_COMPUTED_GOTO +#define MICROPY_USE_COMPUTED_GOTO (0) +#endif + // Additional builtin function definitions - see builtintables.c:builtin_object_table for format. #ifndef MICROPY_EXTRA_BUILTINS #define MICROPY_EXTRA_BUILTINS diff --git a/py/objstr.c b/py/objstr.c index 08db2af669..fc1e1c5695 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -662,7 +662,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { if (arg_i > 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "cannot switch from automatic field numbering to manual field specification")); } - int index; + int index = 0; if (str_to_int(vstr_str(field_name), &index) != vstr_len(field_name) - 1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "attributes not supported yet")); } @@ -167,6 +167,110 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i volatile mp_obj_t inject_exc) { // careful: be sure to declare volatile any variables read in the exception handler (written is ok, I think) +#if MICROPY_USE_COMPUTED_GOTO + +# define DISPATCH() do { \ + save_ip = ip; \ + op = *ip++; \ + goto *entry_table[op]; \ + } while(0) +# define ENTRY(op) entry_##op +# define ENTRY_DEFAULT entry_default + + static void* entry_table[256] = { + [0 ... 255] = &&entry_default, + [MP_BC_LOAD_CONST_FALSE] = &&entry_MP_BC_LOAD_CONST_FALSE, + [MP_BC_LOAD_CONST_NONE] = &&entry_MP_BC_LOAD_CONST_NONE, + [MP_BC_LOAD_CONST_TRUE] = &&entry_MP_BC_LOAD_CONST_TRUE, + [MP_BC_LOAD_CONST_ELLIPSIS] = &&entry_MP_BC_LOAD_CONST_ELLIPSIS, + [MP_BC_LOAD_CONST_SMALL_INT] = &&entry_MP_BC_LOAD_CONST_SMALL_INT, + [MP_BC_LOAD_CONST_INT] = &&entry_MP_BC_LOAD_CONST_INT, + [MP_BC_LOAD_CONST_DEC] = &&entry_MP_BC_LOAD_CONST_DEC, + [MP_BC_LOAD_CONST_ID] = &&entry_MP_BC_LOAD_CONST_ID, + [MP_BC_LOAD_CONST_BYTES] = &&entry_MP_BC_LOAD_CONST_BYTES, + [MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING, + [MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL, + [MP_BC_LOAD_FAST_0] = &&entry_MP_BC_LOAD_FAST_0, + [MP_BC_LOAD_FAST_1] = &&entry_MP_BC_LOAD_FAST_1, + [MP_BC_LOAD_FAST_2] = &&entry_MP_BC_LOAD_FAST_2, + [MP_BC_LOAD_FAST_N] = &&entry_MP_BC_LOAD_FAST_N, + [MP_BC_LOAD_DEREF] = &&entry_MP_BC_LOAD_DEREF, + [MP_BC_LOAD_NAME] = &&entry_MP_BC_LOAD_NAME, + [MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL, + [MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR, + [MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD, + [MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS, + [MP_BC_STORE_FAST_0] = &&entry_MP_BC_STORE_FAST_0, + [MP_BC_STORE_FAST_1] = &&entry_MP_BC_STORE_FAST_1, + [MP_BC_STORE_FAST_2] = &&entry_MP_BC_STORE_FAST_2, + [MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N, + [MP_BC_STORE_DEREF] = &&entry_MP_BC_STORE_DEREF, + [MP_BC_STORE_NAME] = &&entry_MP_BC_STORE_NAME, + [MP_BC_STORE_GLOBAL] = &&entry_MP_BC_STORE_GLOBAL, + [MP_BC_STORE_ATTR] = &&entry_MP_BC_STORE_ATTR, + [MP_BC_STORE_SUBSCR] = &&entry_MP_BC_STORE_SUBSCR, + [MP_BC_DELETE_FAST] = &&entry_MP_BC_DELETE_FAST, + [MP_BC_DELETE_DEREF] = &&entry_MP_BC_DELETE_DEREF, + [MP_BC_DELETE_NAME] = &&entry_MP_BC_DELETE_NAME, + [MP_BC_DELETE_GLOBAL] = &&entry_MP_BC_DELETE_GLOBAL, + [MP_BC_DUP_TOP] = &&entry_MP_BC_DUP_TOP, + [MP_BC_DUP_TOP_TWO] = &&entry_MP_BC_DUP_TOP_TWO, + [MP_BC_POP_TOP] = &&entry_MP_BC_POP_TOP, + [MP_BC_ROT_TWO] = &&entry_MP_BC_ROT_TWO, + [MP_BC_ROT_THREE] = &&entry_MP_BC_ROT_THREE, + [MP_BC_JUMP] = &&entry_MP_BC_JUMP, + [MP_BC_POP_JUMP_IF_TRUE] = &&entry_MP_BC_POP_JUMP_IF_TRUE, + [MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE, + [MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP, + [MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP, +// [MP_BC_SETUP_LOOP] = &&entry_MP_BC_SETUP_LOOP, + [MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH, + [MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP, + [MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP, + [MP_BC_SETUP_EXCEPT] = &&entry_MP_BC_SETUP_EXCEPT, + [MP_BC_SETUP_FINALLY] = &&entry_MP_BC_SETUP_FINALLY, + [MP_BC_END_FINALLY] = &&entry_MP_BC_END_FINALLY, + [MP_BC_GET_ITER] = &&entry_MP_BC_GET_ITER, + [MP_BC_FOR_ITER] = &&entry_MP_BC_FOR_ITER, + [MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK, + [MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT, + [MP_BC_NOT] = &&entry_MP_BC_NOT, + [MP_BC_UNARY_OP] = &&entry_MP_BC_UNARY_OP, + [MP_BC_BINARY_OP] = &&entry_MP_BC_BINARY_OP, + [MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE, + [MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST, + [MP_BC_LIST_APPEND] = &&entry_MP_BC_LIST_APPEND, + [MP_BC_BUILD_MAP] = &&entry_MP_BC_BUILD_MAP, + [MP_BC_STORE_MAP] = &&entry_MP_BC_STORE_MAP, + [MP_BC_MAP_ADD] = &&entry_MP_BC_MAP_ADD, + [MP_BC_BUILD_SET] = &&entry_MP_BC_BUILD_SET, + [MP_BC_SET_ADD] = &&entry_MP_BC_SET_ADD, + [MP_BC_BUILD_SLICE] = &&entry_MP_BC_BUILD_SLICE, + [MP_BC_UNPACK_SEQUENCE] = &&entry_MP_BC_UNPACK_SEQUENCE, + [MP_BC_UNPACK_EX] = &&entry_MP_BC_UNPACK_EX, + [MP_BC_MAKE_FUNCTION] = &&entry_MP_BC_MAKE_FUNCTION, + [MP_BC_MAKE_FUNCTION_DEFARGS] = &&entry_MP_BC_MAKE_FUNCTION_DEFARGS, + [MP_BC_MAKE_CLOSURE] = &&entry_MP_BC_MAKE_CLOSURE, + [MP_BC_MAKE_CLOSURE_DEFARGS] = &&entry_MP_BC_MAKE_CLOSURE_DEFARGS, + [MP_BC_CALL_FUNCTION] = &&entry_MP_BC_CALL_FUNCTION, + [MP_BC_CALL_FUNCTION_VAR_KW] = &&entry_MP_BC_CALL_FUNCTION_VAR_KW, + [MP_BC_CALL_METHOD] = &&entry_MP_BC_CALL_METHOD, + [MP_BC_CALL_METHOD_VAR_KW] = &&entry_MP_BC_CALL_METHOD_VAR_KW, + [MP_BC_RETURN_VALUE] = &&entry_MP_BC_RETURN_VALUE, + [MP_BC_RAISE_VARARGS] = &&entry_MP_BC_RAISE_VARARGS, + [MP_BC_YIELD_VALUE] = &&entry_MP_BC_YIELD_VALUE, + [MP_BC_YIELD_FROM] = &&entry_MP_BC_YIELD_FROM, + [MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME, + [MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM, + [MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR, + }; +#else +# define DISPATCH() break +# define ENTRY(op) case op +# define ENTRY_DEFAULT default +#endif + + int op = 0; const byte *ip = *ip_in_out; mp_obj_t *sp = *sp_in_out; machine_uint_t unum; @@ -195,707 +299,715 @@ outer_dispatch_loop: // loop to execute byte code for (;;) { dispatch_loop: +#if MICROPY_USE_COMPUTED_GOTO + DISPATCH(); +#else save_ip = ip; - int op = *ip++; - //printf("ip=%p sp=%p op=%u\n", save_ip, sp, op); - switch (op) { - case MP_BC_LOAD_CONST_FALSE: - PUSH(mp_const_false); - break; - - case MP_BC_LOAD_CONST_NONE: - PUSH(mp_const_none); - break; - - case MP_BC_LOAD_CONST_TRUE: - PUSH(mp_const_true); - break; - - case MP_BC_LOAD_CONST_ELLIPSIS: - PUSH((mp_obj_t)&mp_const_ellipsis_obj); - break; - - case MP_BC_LOAD_CONST_SMALL_INT: { - machine_int_t num = 0; - if ((ip[0] & 0x40) != 0) { - // Number is negative - num--; - } - do { - num = (num << 7) | (*ip & 0x7f); - } while ((*ip++ & 0x80) != 0); - PUSH(MP_OBJ_NEW_SMALL_INT(num)); - break; - } + op = *ip++; - case MP_BC_LOAD_CONST_INT: - DECODE_QSTR; - PUSH(mp_obj_new_int_from_long_str(qstr_str(qst))); - break; - - case MP_BC_LOAD_CONST_DEC: - DECODE_QSTR; - PUSH(mp_load_const_dec(qst)); - break; - - case MP_BC_LOAD_CONST_ID: - DECODE_QSTR; - PUSH(mp_load_const_str(qst)); // TODO - break; - - case MP_BC_LOAD_CONST_BYTES: - DECODE_QSTR; - PUSH(mp_load_const_bytes(qst)); - break; - - case MP_BC_LOAD_CONST_STRING: - DECODE_QSTR; - PUSH(mp_load_const_str(qst)); - break; - - case MP_BC_LOAD_NULL: - PUSH(MP_OBJ_NULL); - break; - - case MP_BC_LOAD_FAST_0: - obj1 = fastn[0]; - goto load_check; - - case MP_BC_LOAD_FAST_1: - obj1 = fastn[-1]; - goto load_check; - - case MP_BC_LOAD_FAST_2: - obj1 = fastn[-2]; - goto load_check; - - case MP_BC_LOAD_FAST_N: - DECODE_UINT; - obj1 = fastn[-unum]; - load_check: - if (obj1 == MP_OBJ_NULL) { - local_name_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment")); - } - PUSH(obj1); - break; - - case MP_BC_LOAD_DEREF: - DECODE_UINT; - obj1 = mp_obj_cell_get(fastn[-unum]); - goto load_check; - - case MP_BC_LOAD_NAME: - DECODE_QSTR; - PUSH(mp_load_name(qst)); - break; - - case MP_BC_LOAD_GLOBAL: - DECODE_QSTR; - PUSH(mp_load_global(qst)); - break; - - case MP_BC_LOAD_ATTR: - DECODE_QSTR; - SET_TOP(mp_load_attr(TOP(), qst)); - break; - - case MP_BC_LOAD_METHOD: - DECODE_QSTR; - mp_load_method(*sp, qst, sp); - sp += 1; - break; - - case MP_BC_LOAD_BUILD_CLASS: - PUSH(mp_load_build_class()); - break; - - case MP_BC_STORE_FAST_0: - fastn[0] = POP(); - break; - - case MP_BC_STORE_FAST_1: - fastn[-1] = POP(); - break; - - case MP_BC_STORE_FAST_2: - fastn[-2] = POP(); - break; - - case MP_BC_STORE_FAST_N: - DECODE_UINT; - fastn[-unum] = POP(); - break; - - case MP_BC_STORE_DEREF: - DECODE_UINT; - mp_obj_cell_set(fastn[-unum], POP()); - break; - - case MP_BC_STORE_NAME: - DECODE_QSTR; - mp_store_name(qst, POP()); - break; - - case MP_BC_STORE_GLOBAL: - DECODE_QSTR; - mp_store_global(qst, POP()); - break; - - case MP_BC_STORE_ATTR: - DECODE_QSTR; - mp_store_attr(sp[0], qst, sp[-1]); - sp -= 2; - break; - - case MP_BC_STORE_SUBSCR: - mp_store_subscr(sp[-1], sp[0], sp[-2]); - sp -= 3; - break; - - case MP_BC_DELETE_FAST: - DECODE_UINT; - if (fastn[-unum] == MP_OBJ_NULL) { - goto local_name_error; - } - fastn[-unum] = MP_OBJ_NULL; - break; + switch (op) { +#endif + //printf("ip=%p sp=%p op=%u\n", save_ip, sp, op); - case MP_BC_DELETE_DEREF: - DECODE_UINT; - if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { - goto local_name_error; - } - mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL); - break; + ENTRY(MP_BC_LOAD_CONST_FALSE): + PUSH(mp_const_false); + DISPATCH(); - case MP_BC_DELETE_NAME: - DECODE_QSTR; - mp_delete_name(qst); - break; + ENTRY(MP_BC_LOAD_CONST_NONE): + PUSH(mp_const_none); + DISPATCH(); - case MP_BC_DELETE_GLOBAL: - DECODE_QSTR; - mp_delete_global(qst); - break; + ENTRY(MP_BC_LOAD_CONST_TRUE): + PUSH(mp_const_true); + DISPATCH(); - case MP_BC_DUP_TOP: - obj1 = TOP(); - PUSH(obj1); - break; - - case MP_BC_DUP_TOP_TWO: - sp += 2; - sp[0] = sp[-2]; - sp[-1] = sp[-3]; - break; - - case MP_BC_POP_TOP: - sp -= 1; - break; - - case MP_BC_ROT_TWO: - obj1 = sp[0]; - sp[0] = sp[-1]; - sp[-1] = obj1; - break; - - case MP_BC_ROT_THREE: - obj1 = sp[0]; - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = obj1; - break; - - case MP_BC_JUMP: - DECODE_SLABEL; - ip += unum; - break; + ENTRY(MP_BC_LOAD_CONST_ELLIPSIS): + PUSH((mp_obj_t)&mp_const_ellipsis_obj); + DISPATCH(); - case MP_BC_POP_JUMP_IF_TRUE: - DECODE_SLABEL; - if (mp_obj_is_true(POP())) { - ip += unum; - } - break; + ENTRY(MP_BC_LOAD_CONST_SMALL_INT): { + machine_int_t num = 0; + if ((ip[0] & 0x40) != 0) { + // Number is negative + num--; + } + do { + num = (num << 7) | (*ip & 0x7f); + } while ((*ip++ & 0x80) != 0); + PUSH(MP_OBJ_NEW_SMALL_INT(num)); + DISPATCH(); + } - case MP_BC_POP_JUMP_IF_FALSE: - DECODE_SLABEL; - if (!mp_obj_is_true(POP())) { - ip += unum; - } - break; + ENTRY(MP_BC_LOAD_CONST_INT): + DECODE_QSTR; + PUSH(mp_obj_new_int_from_long_str(qstr_str(qst))); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_DEC): + DECODE_QSTR; + PUSH(mp_load_const_dec(qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_ID): + DECODE_QSTR; + PUSH(mp_load_const_str(qst)); // TODO + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_BYTES): + DECODE_QSTR; + PUSH(mp_load_const_bytes(qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_CONST_STRING): + DECODE_QSTR; + PUSH(mp_load_const_str(qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_NULL): + PUSH(MP_OBJ_NULL); + DISPATCH(); + + ENTRY(MP_BC_LOAD_FAST_0): + obj1 = fastn[0]; + goto load_check; + + ENTRY(MP_BC_LOAD_FAST_1): + obj1 = fastn[-1]; + goto load_check; + + ENTRY(MP_BC_LOAD_FAST_2): + obj1 = fastn[-2]; + goto load_check; + + ENTRY(MP_BC_LOAD_FAST_N): + DECODE_UINT; + obj1 = fastn[-unum]; + load_check: + if (obj1 == MP_OBJ_NULL) { + local_name_error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment")); + } + PUSH(obj1); + DISPATCH(); + + ENTRY(MP_BC_LOAD_DEREF): + DECODE_UINT; + obj1 = mp_obj_cell_get(fastn[-unum]); + goto load_check; + + ENTRY(MP_BC_LOAD_NAME): + DECODE_QSTR; + PUSH(mp_load_name(qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_GLOBAL): + DECODE_QSTR; + PUSH(mp_load_global(qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_ATTR): + DECODE_QSTR; + SET_TOP(mp_load_attr(TOP(), qst)); + DISPATCH(); + + ENTRY(MP_BC_LOAD_METHOD): + DECODE_QSTR; + mp_load_method(*sp, qst, sp); + sp += 1; + DISPATCH(); + + ENTRY(MP_BC_LOAD_BUILD_CLASS): + PUSH(mp_load_build_class()); + DISPATCH(); + + ENTRY(MP_BC_STORE_FAST_0): + fastn[0] = POP(); + DISPATCH(); + + ENTRY(MP_BC_STORE_FAST_1): + fastn[-1] = POP(); + DISPATCH(); + + ENTRY(MP_BC_STORE_FAST_2): + fastn[-2] = POP(); + DISPATCH(); + + ENTRY(MP_BC_STORE_FAST_N): + DECODE_UINT; + fastn[-unum] = POP(); + DISPATCH(); + + ENTRY(MP_BC_STORE_DEREF): + DECODE_UINT; + mp_obj_cell_set(fastn[-unum], POP()); + DISPATCH(); + + ENTRY(MP_BC_STORE_NAME): + DECODE_QSTR; + mp_store_name(qst, POP()); + DISPATCH(); + + ENTRY(MP_BC_STORE_GLOBAL): + DECODE_QSTR; + mp_store_global(qst, POP()); + DISPATCH(); + + ENTRY(MP_BC_STORE_ATTR): + DECODE_QSTR; + mp_store_attr(sp[0], qst, sp[-1]); + sp -= 2; + DISPATCH(); + + ENTRY(MP_BC_STORE_SUBSCR): + mp_store_subscr(sp[-1], sp[0], sp[-2]); + sp -= 3; + DISPATCH(); + + ENTRY(MP_BC_DELETE_FAST): + DECODE_UINT; + if (fastn[-unum] == MP_OBJ_NULL) { + goto local_name_error; + } + fastn[-unum] = MP_OBJ_NULL; + DISPATCH(); - case MP_BC_JUMP_IF_TRUE_OR_POP: - DECODE_SLABEL; - if (mp_obj_is_true(TOP())) { - ip += unum; - } else { - sp--; - } - break; + ENTRY(MP_BC_DELETE_DEREF): + DECODE_UINT; + if (mp_obj_cell_get(fastn[-unum]) == MP_OBJ_NULL) { + goto local_name_error; + } + mp_obj_cell_set(fastn[-unum], MP_OBJ_NULL); + DISPATCH(); + + ENTRY(MP_BC_DELETE_NAME): + DECODE_QSTR; + mp_delete_name(qst); + DISPATCH(); + + ENTRY(MP_BC_DELETE_GLOBAL): + DECODE_QSTR; + mp_delete_global(qst); + DISPATCH(); + + ENTRY(MP_BC_DUP_TOP): + obj1 = TOP(); + PUSH(obj1); + DISPATCH(); + + ENTRY(MP_BC_DUP_TOP_TWO): + sp += 2; + sp[0] = sp[-2]; + sp[-1] = sp[-3]; + DISPATCH(); + + ENTRY(MP_BC_POP_TOP): + sp -= 1; + DISPATCH(); + + ENTRY(MP_BC_ROT_TWO): + obj1 = sp[0]; + sp[0] = sp[-1]; + sp[-1] = obj1; + DISPATCH(); + + ENTRY(MP_BC_ROT_THREE): + obj1 = sp[0]; + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = obj1; + DISPATCH(); + + ENTRY(MP_BC_JUMP): + DECODE_SLABEL; + ip += unum; + DISPATCH(); + + ENTRY(MP_BC_POP_JUMP_IF_TRUE): + DECODE_SLABEL; + if (mp_obj_is_true(POP())) { + ip += unum; + } + DISPATCH(); - case MP_BC_JUMP_IF_FALSE_OR_POP: - DECODE_SLABEL; - if (mp_obj_is_true(TOP())) { - sp--; - } else { - ip += unum; - } - break; + ENTRY(MP_BC_POP_JUMP_IF_FALSE): + DECODE_SLABEL; + if (!mp_obj_is_true(POP())) { + ip += unum; + } + DISPATCH(); - /* we are trying to get away without using this opcode - case MP_BC_SETUP_LOOP: - DECODE_UINT; - // push_block(MP_BC_SETUP_LOOP, ip + unum, sp) - break; - */ + ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP): + DECODE_SLABEL; + if (mp_obj_is_true(TOP())) { + ip += unum; + } else { + sp--; + } + DISPATCH(); - case MP_BC_SETUP_WITH: + ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP): + DECODE_SLABEL; + if (mp_obj_is_true(TOP())) { + sp--; + } else { + ip += unum; + } + DISPATCH(); + + /* we are trying to get away without using this opcode + ENTRY(MP_BC_SETUP_LOOP): + DECODE_UINT; + // push_block(MP_BC_SETUP_LOOP, ip + unum, sp) + DISPATCH(); + */ + + ENTRY(MP_BC_SETUP_WITH): + obj1 = TOP(); + SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__)); + mp_load_method(obj1, MP_QSTR___enter__, sp + 1); + obj2 = mp_call_method_n_kw(0, 0, sp + 1); + PUSH_EXC_BLOCK(); + PUSH(obj2); + DISPATCH(); + + ENTRY(MP_BC_WITH_CLEANUP): { + // Arriving here, there's "exception control block" on top of stack, + // and __exit__ bound method underneath it. Bytecode calls __exit__, + // and "deletes" it off stack, shifting "exception control block" + // to its place. + static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none}; + if (TOP() == mp_const_none) { + sp--; obj1 = TOP(); - SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__)); - mp_load_method(obj1, MP_QSTR___enter__, sp + 1); - obj2 = mp_call_method_n_kw(0, 0, sp + 1); - PUSH_EXC_BLOCK(); - PUSH(obj2); - break; - - case MP_BC_WITH_CLEANUP: { - // Arriving here, there's "exception control block" on top of stack, - // and __exit__ bound method underneath it. Bytecode calls __exit__, - // and "deletes" it off stack, shifting "exception control block" - // to its place. - static const mp_obj_t no_exc[] = {mp_const_none, mp_const_none, mp_const_none}; - if (TOP() == mp_const_none) { - sp--; - obj1 = TOP(); - SET_TOP(mp_const_none); - obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc); - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { - mp_obj_t cause = POP(); - switch (MP_OBJ_SMALL_INT_VALUE(cause)) { - case UNWIND_RETURN: { - mp_obj_t retval = POP(); - obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc); - SET_TOP(retval); - PUSH(cause); - break; - } - case UNWIND_JUMP: { - obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc); - // Pop __exit__ boundmethod at sp[-2] - sp[-2] = sp[-1]; - sp[-1] = sp[0]; - SET_TOP(cause); - break; - } - default: - assert(0); + SET_TOP(mp_const_none); + obj2 = mp_call_function_n_kw(obj1, 3, 0, no_exc); + } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + mp_obj_t cause = POP(); + switch (MP_OBJ_SMALL_INT_VALUE(cause)) { + case UNWIND_RETURN: { + mp_obj_t retval = POP(); + obj2 = mp_call_function_n_kw(TOP(), 3, 0, no_exc); + SET_TOP(retval); + PUSH(cause); + break; } - } else if (mp_obj_is_exception_type(TOP())) { - mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]}; - obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args); - // Pop __exit__ boundmethod at sp[-3] - // TODO: Once semantics is proven, optimize for case when obj2 == True - sp[-3] = sp[-2]; - sp[-2] = sp[-1]; - sp[-1] = sp[0]; - sp--; - if (mp_obj_is_true(obj2)) { - // This is what CPython does - //PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED)); - // But what we need to do is - pop exception from value stack... - sp -= 3; - // ... pop "with" exception handler, and signal END_FINALLY - // to just execute finally handler normally (by pushing None - // on value stack) - assert(exc_sp >= exc_stack); - assert(exc_sp->opcode == MP_BC_SETUP_WITH); - POP_EXC_BLOCK(); - PUSH(mp_const_none); + case UNWIND_JUMP: { + obj2 = mp_call_function_n_kw(sp[-2], 3, 0, no_exc); + // Pop __exit__ boundmethod at sp[-2] + sp[-2] = sp[-1]; + sp[-1] = sp[0]; + SET_TOP(cause); + break; } - } else { - assert(0); + default: + assert(0); } - break; - } - - case MP_BC_UNWIND_JUMP: - DECODE_SLABEL; - PUSH((void*)(ip + unum)); // push destination ip for jump - PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind -unwind_jump: - unum = (machine_uint_t)POP(); // get number of exception handlers to unwind - while (unum > 0) { - unum -= 1; + } else if (mp_obj_is_exception_type(TOP())) { + mp_obj_t args[3] = {sp[0], sp[-1], sp[-2]}; + obj2 = mp_call_function_n_kw(sp[-3], 3, 0, args); + // Pop __exit__ boundmethod at sp[-3] + // TODO: Once semantics is proven, optimize for case when obj2 == True + sp[-3] = sp[-2]; + sp[-2] = sp[-1]; + sp[-1] = sp[0]; + sp--; + if (mp_obj_is_true(obj2)) { + // This is what CPython does + //PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_SILENCED)); + // But what we need to do is - pop exception from value stack... + sp -= 3; + // ... pop "with" exception handler, and signal END_FINALLY + // to just execute finally handler normally (by pushing None + // on value stack) assert(exc_sp >= exc_stack); - if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) { - // We're going to run "finally" code as a coroutine - // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is - // done (when END_FINALLY reached). - PUSH((void*)unum); // push number of exception handlers left to unwind - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel - ip = exc_sp->handler; // get exception handler byte code address - exc_sp--; // pop exception handler - goto dispatch_loop; // run the exception handler - } - exc_sp--; - } - ip = (const byte*)POP(); // pop destination ip for jump - break; - - // matched against: POP_BLOCK or POP_EXCEPT (anything else?) - case MP_BC_SETUP_EXCEPT: - case MP_BC_SETUP_FINALLY: - PUSH_EXC_BLOCK(); - break; - - case MP_BC_END_FINALLY: - // not fully implemented - // if TOS is an exception, reraises the exception (3 values on TOS) - // if TOS is None, just pops it and continues - // if TOS is an integer, does something else - // else error - if (mp_obj_is_exception_type(TOP())) { - nlr_raise(sp[-1]); - } - if (TOP() == mp_const_none) { - sp--; - } else if (MP_OBJ_IS_SMALL_INT(TOP())) { - // We finished "finally" coroutine and now dispatch back - // to our caller, based on TOS value - mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); - switch (reason) { - case UNWIND_RETURN: - goto unwind_return; - case UNWIND_JUMP: - goto unwind_jump; - } - assert(0); - } else { - assert(0); + assert(exc_sp->opcode == MP_BC_SETUP_WITH); + POP_EXC_BLOCK(); + PUSH(mp_const_none); } - break; - - case MP_BC_GET_ITER: - SET_TOP(mp_getiter(TOP())); - break; - - case MP_BC_FOR_ITER: - DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward - obj1 = mp_iternext_allow_raise(TOP()); - if (obj1 == MP_OBJ_NULL) { - --sp; // pop the exhausted iterator - ip += unum; // jump to after for-block - } else { - PUSH(obj1); // push the next iteration value - } - break; - - // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH - case MP_BC_POP_BLOCK: - // we are exiting an exception handler, so pop the last one of the exception-stack - assert(exc_sp >= exc_stack); - POP_EXC_BLOCK(); - break; + } else { + assert(0); + } + DISPATCH(); + } - // matched against: SETUP_EXCEPT - case MP_BC_POP_EXCEPT: - // TODO need to work out how blocks work etc - // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate + ENTRY(MP_BC_UNWIND_JUMP): + DECODE_SLABEL; + PUSH((void*)(ip + unum)); // push destination ip for jump + PUSH((void*)(machine_uint_t)(*ip)); // push number of exception handlers to unwind +unwind_jump: + unum = (machine_uint_t)POP(); // get number of exception handlers to unwind + while (unum > 0) { + unum -= 1; assert(exc_sp >= exc_stack); - assert(currently_in_except_block); - //sp = (mp_obj_t*)(*exc_sp--); - //exc_sp--; // discard ip - POP_EXC_BLOCK(); - //sp -= 3; // pop 3 exception values - break; - - case MP_BC_NOT: - if (TOP() == mp_const_true) { - SET_TOP(mp_const_false); - } else { - SET_TOP(mp_const_true); + if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) { + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on a stack so it can return back to us when it is + // done (when END_FINALLY reached). + PUSH((void*)unum); // push number of exception handlers left to unwind + PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel + ip = exc_sp->handler; // get exception handler byte code address + exc_sp--; // pop exception handler + goto dispatch_loop; // run the exception handler } - break; - - case MP_BC_UNARY_OP: - unum = *ip++; - SET_TOP(mp_unary_op(unum, TOP())); - break; - - case MP_BC_BINARY_OP: - unum = *ip++; - obj2 = POP(); - obj1 = TOP(); - SET_TOP(mp_binary_op(unum, obj1, obj2)); - break; - - case MP_BC_BUILD_TUPLE: - DECODE_UINT; - sp -= unum - 1; - SET_TOP(mp_obj_new_tuple(unum, sp)); - break; - - case MP_BC_BUILD_LIST: - DECODE_UINT; - sp -= unum - 1; - SET_TOP(mp_obj_new_list(unum, sp)); - break; - - case MP_BC_LIST_APPEND: - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[unum] is a list - mp_obj_list_append(sp[-unum], sp[0]); - sp--; - break; - - case MP_BC_BUILD_MAP: - DECODE_UINT; - PUSH(mp_obj_new_dict(unum)); - break; - - case MP_BC_STORE_MAP: - sp -= 2; - mp_obj_dict_store(sp[0], sp[2], sp[1]); - break; - - case MP_BC_MAP_ADD: - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[-unum - 1] is a map - mp_obj_dict_store(sp[-unum - 1], sp[0], sp[-1]); - sp -= 2; - break; - - case MP_BC_BUILD_SET: - DECODE_UINT; - sp -= unum - 1; - SET_TOP(mp_obj_new_set(unum, sp)); - break; - - case MP_BC_SET_ADD: - DECODE_UINT; - // I think it's guaranteed by the compiler that sp[-unum] is a set - mp_obj_set_store(sp[-unum], sp[0]); + exc_sp--; + } + ip = (const byte*)POP(); // pop destination ip for jump + DISPATCH(); + + // matched against: POP_BLOCK or POP_EXCEPT (anything else?) + ENTRY(MP_BC_SETUP_EXCEPT): + ENTRY(MP_BC_SETUP_FINALLY): + PUSH_EXC_BLOCK(); + DISPATCH(); + + ENTRY(MP_BC_END_FINALLY): + // not fully implemented + // if TOS is an exception, reraises the exception (3 values on TOS) + // if TOS is None, just pops it and continues + // if TOS is an integer, does something else + // else error + if (mp_obj_is_exception_type(TOP())) { + nlr_raise(sp[-1]); + } + if (TOP() == mp_const_none) { sp--; - break; + } else if (MP_OBJ_IS_SMALL_INT(TOP())) { + // We finished "finally" coroutine and now dispatch back + // to our caller, based on TOS value + mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP()); + switch (reason) { + case UNWIND_RETURN: + goto unwind_return; + case UNWIND_JUMP: + goto unwind_jump; + } + assert(0); + } else { + assert(0); + } + DISPATCH(); + + ENTRY(MP_BC_GET_ITER): + SET_TOP(mp_getiter(TOP())); + DISPATCH(); + + ENTRY(MP_BC_FOR_ITER): + DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + obj1 = mp_iternext_allow_raise(TOP()); + if (obj1 == MP_OBJ_NULL) { + --sp; // pop the exhausted iterator + ip += unum; // jump to after for-block + } else { + PUSH(obj1); // push the next iteration value + } + DISPATCH(); + + // matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH + ENTRY(MP_BC_POP_BLOCK): + // we are exiting an exception handler, so pop the last one of the exception-stack + assert(exc_sp >= exc_stack); + POP_EXC_BLOCK(); + DISPATCH(); + + // matched against: SETUP_EXCEPT + ENTRY(MP_BC_POP_EXCEPT): + // TODO need to work out how blocks work etc + // pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate + assert(exc_sp >= exc_stack); + assert(currently_in_except_block); + //sp = (mp_obj_t*)(*exc_sp--); + //exc_sp--; // discard ip + POP_EXC_BLOCK(); + //sp -= 3; // pop 3 exception values + DISPATCH(); + + ENTRY(MP_BC_NOT): + if (TOP() == mp_const_true) { + SET_TOP(mp_const_false); + } else { + SET_TOP(mp_const_true); + } + DISPATCH(); + + ENTRY(MP_BC_UNARY_OP): + unum = *ip++; + SET_TOP(mp_unary_op(unum, TOP())); + DISPATCH(); + + ENTRY(MP_BC_BINARY_OP): + unum = *ip++; + obj2 = POP(); + obj1 = TOP(); + SET_TOP(mp_binary_op(unum, obj1, obj2)); + DISPATCH(); + + ENTRY(MP_BC_BUILD_TUPLE): + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_tuple(unum, sp)); + DISPATCH(); + + ENTRY(MP_BC_BUILD_LIST): + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_list(unum, sp)); + DISPATCH(); + + ENTRY(MP_BC_LIST_APPEND): + DECODE_UINT; + // I think it's guaranteed by the compiler that sp[unum] is a list + mp_obj_list_append(sp[-unum], sp[0]); + sp--; + DISPATCH(); + + ENTRY(MP_BC_BUILD_MAP): + DECODE_UINT; + PUSH(mp_obj_new_dict(unum)); + DISPATCH(); + + ENTRY(MP_BC_STORE_MAP): + sp -= 2; + mp_obj_dict_store(sp[0], sp[2], sp[1]); + DISPATCH(); + + ENTRY(MP_BC_MAP_ADD): + DECODE_UINT; + // I think it's guaranteed by the compiler that sp[-unum - 1] is a map + mp_obj_dict_store(sp[-unum - 1], sp[0], sp[-1]); + sp -= 2; + DISPATCH(); + + ENTRY(MP_BC_BUILD_SET): + DECODE_UINT; + sp -= unum - 1; + SET_TOP(mp_obj_new_set(unum, sp)); + DISPATCH(); + + ENTRY(MP_BC_SET_ADD): + DECODE_UINT; + // I think it's guaranteed by the compiler that sp[-unum] is a set + mp_obj_set_store(sp[-unum], sp[0]); + sp--; + DISPATCH(); #if MICROPY_ENABLE_SLICE - case MP_BC_BUILD_SLICE: - DECODE_UINT; - if (unum == 2) { - obj2 = POP(); - obj1 = TOP(); - SET_TOP(mp_obj_new_slice(obj1, obj2, NULL)); - } else { - obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported"); - nlr_pop(); - fastn[0] = obj1; - return MP_VM_RETURN_EXCEPTION; - } - break; + ENTRY(MP_BC_BUILD_SLICE): + DECODE_UINT; + if (unum == 2) { + obj2 = POP(); + obj1 = TOP(); + SET_TOP(mp_obj_new_slice(obj1, obj2, NULL)); + } else { + obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported"); + nlr_pop(); + fastn[0] = obj1; + return MP_VM_RETURN_EXCEPTION; + } + DISPATCH(); #endif - case MP_BC_UNPACK_SEQUENCE: - DECODE_UINT; - mp_unpack_sequence(sp[0], unum, sp); - sp += unum - 1; - break; - - case MP_BC_UNPACK_EX: - DECODE_UINT; - mp_unpack_ex(sp[0], unum, sp); - sp += (unum & 0xff) + ((unum >> 8) & 0xff); - break; - - case MP_BC_MAKE_FUNCTION: - DECODE_PTR; - PUSH(mp_make_function_from_raw_code((mp_raw_code_t*)unum, MP_OBJ_NULL, MP_OBJ_NULL)); - break; - - case MP_BC_MAKE_FUNCTION_DEFARGS: - DECODE_PTR; - // Stack layout: def_tuple def_dict <- TOS - obj1 = POP(); - SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1)); - break; - - case MP_BC_MAKE_CLOSURE: - DECODE_PTR; - // Stack layout: closure_tuple <- TOS - SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, TOP(), MP_OBJ_NULL, MP_OBJ_NULL)); - break; - - case MP_BC_MAKE_CLOSURE_DEFARGS: - DECODE_PTR; - // Stack layout: def_tuple def_dict closure_tuple <- TOS - obj1 = POP(); - obj2 = POP(); - SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, obj1, TOP(), obj2)); - break; - - case MP_BC_CALL_FUNCTION: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); - SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); - break; - - case MP_BC_CALL_FUNCTION_VAR_KW: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2; - SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); - break; - - case MP_BC_CALL_METHOD: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; - SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); - break; - - case MP_BC_CALL_METHOD_VAR_KW: - DECODE_UINT; - // unum & 0xff == n_positional - // (unum >> 8) & 0xff == n_keyword - // We have folowing stack layout here: - // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS - sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3; - SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); - break; - - case MP_BC_RETURN_VALUE: + ENTRY(MP_BC_UNPACK_SEQUENCE): + DECODE_UINT; + mp_unpack_sequence(sp[0], unum, sp); + sp += unum - 1; + DISPATCH(); + + ENTRY(MP_BC_UNPACK_EX): + DECODE_UINT; + mp_unpack_ex(sp[0], unum, sp); + sp += (unum & 0xff) + ((unum >> 8) & 0xff); + DISPATCH(); + + ENTRY(MP_BC_MAKE_FUNCTION): + DECODE_PTR; + PUSH(mp_make_function_from_raw_code((mp_raw_code_t*)unum, MP_OBJ_NULL, MP_OBJ_NULL)); + DISPATCH(); + + ENTRY(MP_BC_MAKE_FUNCTION_DEFARGS): + DECODE_PTR; + // Stack layout: def_tuple def_dict <- TOS + obj1 = POP(); + SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1)); + DISPATCH(); + + ENTRY(MP_BC_MAKE_CLOSURE): + DECODE_PTR; + // Stack layout: closure_tuple <- TOS + SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, TOP(), MP_OBJ_NULL, MP_OBJ_NULL)); + DISPATCH(); + + ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): + DECODE_PTR; + // Stack layout: def_tuple def_dict closure_tuple <- TOS + obj1 = POP(); + obj2 = POP(); + SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, obj1, TOP(), obj2)); + DISPATCH(); + + ENTRY(MP_BC_CALL_FUNCTION): + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe); + SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); + DISPATCH(); + + ENTRY(MP_BC_CALL_FUNCTION_VAR_KW): + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 2; + SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); + DISPATCH(); + + ENTRY(MP_BC_CALL_METHOD): + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 1; + SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); + DISPATCH(); + + ENTRY(MP_BC_CALL_METHOD_VAR_KW): + DECODE_UINT; + // unum & 0xff == n_positional + // (unum >> 8) & 0xff == n_keyword + // We have folowing stack layout here: + // fun self arg0 arg1 ... kw0 val0 kw1 val1 ... seq dict <- TOS + sp -= (unum & 0xff) + ((unum >> 7) & 0x1fe) + 3; + SET_TOP(mp_call_method_n_kw_var(true, unum, sp)); + DISPATCH(); + + ENTRY(MP_BC_RETURN_VALUE): unwind_return: - while (exc_sp >= exc_stack) { - if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) { - // We're going to run "finally" code as a coroutine - // (not calling it recursively). Set up a sentinel - // on a stack so it can return back to us when it is - // done (when END_FINALLY reached). - PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); - ip = exc_sp->handler; - // We don't need to do anything with sp, finally is just - // syntactic sugar for sequential execution?? - // sp = - exc_sp--; - goto dispatch_loop; - } + while (exc_sp >= exc_stack) { + if (exc_sp->opcode == MP_BC_SETUP_FINALLY || exc_sp->opcode == MP_BC_SETUP_WITH) { + // We're going to run "finally" code as a coroutine + // (not calling it recursively). Set up a sentinel + // on a stack so it can return back to us when it is + // done (when END_FINALLY reached). + PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN)); + ip = exc_sp->handler; + // We don't need to do anything with sp, finally is just + // syntactic sugar for sequential execution?? + // sp = exc_sp--; + goto dispatch_loop; } - nlr_pop(); - *sp_in_out = sp; - assert(exc_sp == exc_stack - 1); - return MP_VM_RETURN_NORMAL; - - case MP_BC_RAISE_VARARGS: - unum = *ip++; - assert(unum <= 1); - if (unum == 0) { - // search for the inner-most previous exception, to reraise it - obj1 = MP_OBJ_NULL; - for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { - if (e->prev_exc != MP_OBJ_NULL) { - obj1 = e->prev_exc; - break; - } - } - if (obj1 == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise")); + exc_sp--; + } + nlr_pop(); + *sp_in_out = sp; + assert(exc_sp == exc_stack - 1); + return MP_VM_RETURN_NORMAL; + + ENTRY(MP_BC_RAISE_VARARGS): + unum = *ip++; + assert(unum <= 1); + if (unum == 0) { + // search for the inner-most previous exception, to reraise it + obj1 = MP_OBJ_NULL; + for (mp_exc_stack_t *e = exc_sp; e >= exc_stack; e--) { + if (e->prev_exc != MP_OBJ_NULL) { + obj1 = e->prev_exc; + break; } - } else { - obj1 = POP(); } - nlr_raise(mp_make_raise_obj(obj1)); + if (obj1 == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise")); + } + } else { + obj1 = POP(); + } + nlr_raise(mp_make_raise_obj(obj1)); - case MP_BC_YIELD_VALUE: + ENTRY(MP_BC_YIELD_VALUE): yield: - nlr_pop(); - *ip_in_out = ip; - *sp_in_out = sp; - *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); - return MP_VM_RETURN_YIELD; + nlr_pop(); + *ip_in_out = ip; + *sp_in_out = sp; + *exc_sp_in_out = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); + return MP_VM_RETURN_YIELD; - case MP_BC_YIELD_FROM: { + ENTRY(MP_BC_YIELD_FROM): { //#define EXC_MATCH(exc, type) MP_OBJ_IS_TYPE(exc, type) #define EXC_MATCH(exc, type) mp_obj_exception_match(exc, type) #define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { nlr_raise(t); } - mp_vm_return_kind_t ret_kind; - obj1 = POP(); - mp_obj_t t_exc = MP_OBJ_NULL; - if (inject_exc != MP_OBJ_NULL) { - t_exc = inject_exc; - inject_exc = MP_OBJ_NULL; - ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &obj2); - } else { - ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2); - } + mp_vm_return_kind_t ret_kind; + obj1 = POP(); + mp_obj_t t_exc = MP_OBJ_NULL; + if (inject_exc != MP_OBJ_NULL) { + t_exc = inject_exc; + inject_exc = MP_OBJ_NULL; + ret_kind = mp_resume(TOP(), MP_OBJ_NULL, t_exc, &obj2); + } else { + ret_kind = mp_resume(TOP(), obj1, MP_OBJ_NULL, &obj2); + } - if (ret_kind == MP_VM_RETURN_YIELD) { - ip--; + if (ret_kind == MP_VM_RETURN_YIELD) { + ip--; + PUSH(obj2); + goto yield; + } + if (ret_kind == MP_VM_RETURN_NORMAL) { + // Pop exhausted gen + sp--; + if (obj2 == MP_OBJ_NULL) { + // Optimize StopIteration + // TODO: get StopIteration's value + PUSH(mp_const_none); + } else { PUSH(obj2); - goto yield; } - if (ret_kind == MP_VM_RETURN_NORMAL) { - // Pop exhausted gen - sp--; - if (obj2 == MP_OBJ_NULL) { - // Optimize StopIteration - // TODO: get StopIteration's value - PUSH(mp_const_none); - } else { - PUSH(obj2); - } + // If we injected GeneratorExit downstream, then even + // if it was swallowed, we re-raise GeneratorExit + GENERATOR_EXIT_IF_NEEDED(t_exc); + DISPATCH(); + } + if (ret_kind == MP_VM_RETURN_EXCEPTION) { + // Pop exhausted gen + sp--; + if (EXC_MATCH(obj2, &mp_type_StopIteration)) { + PUSH(mp_obj_exception_get_value(obj2)); // If we injected GeneratorExit downstream, then even // if it was swallowed, we re-raise GeneratorExit GENERATOR_EXIT_IF_NEEDED(t_exc); - break; - } - if (ret_kind == MP_VM_RETURN_EXCEPTION) { - // Pop exhausted gen - sp--; - if (EXC_MATCH(obj2, &mp_type_StopIteration)) { - PUSH(mp_obj_exception_get_value(obj2)); - // If we injected GeneratorExit downstream, then even - // if it was swallowed, we re-raise GeneratorExit - GENERATOR_EXIT_IF_NEEDED(t_exc); - break; - } else { - nlr_raise(obj2); - } + DISPATCH(); + } else { + nlr_raise(obj2); } } + } - case MP_BC_IMPORT_NAME: - DECODE_QSTR; - obj1 = POP(); - SET_TOP(mp_import_name(qst, obj1, TOP())); - break; - - case MP_BC_IMPORT_FROM: - DECODE_QSTR; - obj1 = mp_import_from(TOP(), qst); - PUSH(obj1); - break; - - case MP_BC_IMPORT_STAR: - mp_import_all(POP()); - break; - - default: - printf("code %p, byte code 0x%02x not implemented\n", ip, op); - obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); - nlr_pop(); - fastn[0] = obj1; - return MP_VM_RETURN_EXCEPTION; + ENTRY(MP_BC_IMPORT_NAME): + DECODE_QSTR; + obj1 = POP(); + SET_TOP(mp_import_name(qst, obj1, TOP())); + DISPATCH(); + + ENTRY(MP_BC_IMPORT_FROM): + DECODE_QSTR; + obj1 = mp_import_from(TOP(), qst); + PUSH(obj1); + DISPATCH(); + + ENTRY(MP_BC_IMPORT_STAR): + mp_import_all(POP()); + DISPATCH(); + + ENTRY_DEFAULT: + printf("code %p, byte code 0x%02x not implemented\n", ip, op); + obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); + nlr_pop(); + fastn[0] = obj1; + return MP_VM_RETURN_EXCEPTION; +#if !MICROPY_USE_COMPUTED_GOTO } +#endif } } else { diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index c564a0f195..288008108f 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -132,6 +132,13 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay); +STATIC mp_obj_t pyb_wfi(void) { + __WFI(); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi); + #if 0 STATIC void SYSCLKConfig_STOP(void) { /* After wake-up from STOP reconfigure the system clock */ @@ -221,6 +228,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&pyb_gc_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_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 }, diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 546b5b1430..0dd8c2b61b 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -6,6 +6,7 @@ Q(info) Q(sd_test) Q(present) Q(power) +Q(wfi) Q(stop) Q(standby) Q(source_dir) diff --git a/stmhal/usart.c b/stmhal/usart.c index 3cf8da6deb..247ab629d6 100644 --- a/stmhal/usart.c +++ b/stmhal/usart.c @@ -19,7 +19,7 @@ struct _pyb_usart_obj_t { pyb_usart_obj_t *pyb_usart_global_debug = NULL; -void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { +bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { USART_TypeDef *USARTx=NULL; uint32_t GPIO_Pin=0; @@ -27,50 +27,74 @@ void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { GPIO_TypeDef* GPIO_Port=NULL; switch (usart_obj->usart_id) { - case PYB_USART_NONE: - return; - + // USART1 is on PA9/PA10, PB6/PB7 case PYB_USART_1: USARTx = USART1; + GPIO_AF_USARTx = GPIO_AF7_USART1; +#if defined(PYBV10) + GPIO_Port = GPIOB; + GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; +#else GPIO_Port = GPIOA; - GPIO_AF_USARTx = GPIO_AF7_USART1; GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10; +#endif __USART1_CLK_ENABLE(); break; + +#if !defined(PYBV10) + // USART2 is on PA2/PA3, PD5/PD6 case PYB_USART_2: USARTx = USART2; + GPIO_AF_USARTx = GPIO_AF7_USART2; GPIO_Port = GPIOD; - GPIO_AF_USARTx = GPIO_AF7_USART2; GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_6; __USART2_CLK_ENABLE(); break; +#endif + + // USART3 is on PB10/PB11, PC10/PC11, PD8/PD9 case PYB_USART_3: USARTx = USART3; + GPIO_AF_USARTx = GPIO_AF7_USART3; -#if defined(PYBV3) || defined(PYBV4) +#if defined(PYBV3) || defined(PYBV4) | defined(PYBV10) GPIO_Port = GPIOB; - GPIO_AF_USARTx = GPIO_AF7_USART3; GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11; #else GPIO_Port = GPIOD; - GPIO_AF_USARTx = GPIO_AF7_USART3; GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9; #endif __USART3_CLK_ENABLE(); break; + + // USART4 is on PA0/PA1, PC10/PC11 + case PYB_USART_4: + USARTx = UART4; + GPIO_AF_USARTx = GPIO_AF8_UART4; + + GPIO_Port = GPIOA; + GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1; + + __UART4_CLK_ENABLE(); + break; + + // USART6 is on PC6/PC7 case PYB_USART_6: USARTx = USART6; + GPIO_AF_USARTx = GPIO_AF8_USART6; GPIO_Port = GPIOC; - GPIO_AF_USARTx = GPIO_AF8_USART6; GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7; __USART6_CLK_ENABLE(); break; + + default: + return false; } // Initialize USARTx @@ -94,6 +118,8 @@ void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { uh->Init.HwFlowCtl = UART_HWCONTROL_NONE; uh->Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(uh); + + return true; } bool usart_rx_any(pyb_usart_obj_t *usart_obj) { @@ -148,17 +174,35 @@ STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Usart accepts 2 arguments")); } - if (mp_obj_get_int(args[0]) > PYB_USART_MAX) { - return mp_const_none; - } - + // create object pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t); o->base.type = &pyb_usart_type; - o->usart_id = mp_obj_get_int(args[0]); - o->is_enabled = true; - /* init USART */ - usart_init(o, mp_obj_get_int(args[1])); + // work out port + o->usart_id = 0; + if (MP_OBJ_IS_STR(args[0])) { + const char *port = mp_obj_str_get_str(args[0]); + if (strcmp(port, "XA") == 0) { + o->usart_id = PYB_USART_XA; + } else if (strcmp(port, "XB") == 0) { + o->usart_id = PYB_USART_XB; + } else if (strcmp(port, "YA") == 0) { + o->usart_id = PYB_USART_YA; + } else if (strcmp(port, "YB") == 0) { + o->usart_id = PYB_USART_YB; + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Usart port %s does not exist", port)); + } + } else if (MP_OBJ_IS_INT(args[0])) { + o->usart_id = mp_obj_get_int(args[0]); + } + + // init USART (if it fails, it's because the port doesn't exist) + if (!usart_init(o, mp_obj_get_int(args[1]))) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Usart port %d does not exist", o->usart_id)); + } + + o->is_enabled = true; return o; } diff --git a/stmhal/usart.h b/stmhal/usart.h index 02464080b8..e7db1db3da 100644 --- a/stmhal/usart.h +++ b/stmhal/usart.h @@ -3,13 +3,17 @@ typedef enum { PYB_USART_1 = 1, PYB_USART_2 = 2, PYB_USART_3 = 3, - PYB_USART_6 = 4, - PYB_USART_MAX = 4, + PYB_USART_4 = 4, + PYB_USART_5 = 5, + PYB_USART_6 = 6, - //PYB_USART_XA = // USART4 on X1, X2 = PA0, PA1 +#if defined(PYBV10) + PYB_USART_XA = 4, // USART4 on X1, X2 = PA0, PA1 PYB_USART_XB = 1, // USART1 on X9, X10 = PB6, PB7 - PYB_USART_YA = 4, // USART6 on Y1, Y2 = PC6, PC7 + PYB_USART_YA = 6, // USART6 on Y1, Y2 = PC6, PC7 PYB_USART_YB = 3, // USART3 on Y9, Y10 = PB10, PB11 +#endif + } pyb_usart_t; typedef struct _pyb_usart_obj_t pyb_usart_obj_t; @@ -17,7 +21,7 @@ typedef struct _pyb_usart_obj_t pyb_usart_obj_t; extern pyb_usart_obj_t *pyb_usart_global_debug; extern const mp_obj_type_t pyb_usart_type; -void usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate); +bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate); bool usart_rx_any(pyb_usart_obj_t *usart_obj); int usart_rx_char(pyb_usart_obj_t *usart_obj); void usart_tx_str(pyb_usart_obj_t *usart_obj, const char *str); diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c index 81f541df43..c6b6cf23f6 100644 --- a/stmhal/usbd_cdc_interface.c +++ b/stmhal/usbd_cdc_interface.c @@ -60,7 +60,7 @@ static uint16_t UserRxBufLen = 0; // counts number of valid characters in UserRx static uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available -static uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained +static __IO uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained static int user_interrupt_char = VCP_CHAR_NONE; static void *user_interrupt_data = NULL; @@ -265,6 +265,14 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { } buffptr = UserTxBufPtrOut; + + // dpgeorge: For some reason that I don't understand, a packet size of 64 bytes + // (CDC_DATA_FS_MAX_PACKET_SIZE) does not get through to the USB host until the + // next packet is sent. To work around this, we just make sure that we never + // send a packet 64 bytes in length. + if (buffsize == CDC_DATA_FS_MAX_PACKET_SIZE) { + buffsize -= 1; + } USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t*)&UserTxBuffer[buffptr], buffsize); diff --git a/tools/pyboard.py b/tools/pyboard.py index 902a93c15a..d5b3237cab 100644 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -32,13 +32,27 @@ class Pyboard: def close(self): self.serial.close() + def read_until(self, min_num_bytes, ending, timeout=10): + data = self.serial.read(min_num_bytes) + timeout_count = 0 + while True: + if self.serial.inWaiting() > 0: + data = data + self.serial.read(self.serial.inWaiting()) + time.sleep(0.01) + timeout_count = 0 + elif data.endswith(ending): + break + else: + timeout_count += 1 + if timeout_count >= 10 * timeout: + break + time.sleep(0.1) + return data + def enter_raw_repl(self): self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL self.serial.write(b'\x04') # ctrl-D: soft reset - data = self.serial.read(1) - while self.serial.inWaiting() > 0: - data = data + self.serial.read(self.serial.inWaiting()) - time.sleep(0.1) + data = self.read_until(1, b'to exit\r\n>') if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'): print(data) raise PyboardError('could not enter raw repl') @@ -60,19 +74,7 @@ class Pyboard: data = self.serial.read(2) if data != b'OK': raise PyboardError('could not exec command') - data = self.serial.read(2) - timeout = 0 - while True: - if self.serial.inWaiting() > 0: - data = data + self.serial.read(self.serial.inWaiting()) - timeout = 0 - elif data.endswith(b'\x04>'): - break - else: - timeout += 1 - if timeout > 100: - break - time.sleep(0.1) + data = self.read_until(2, b'\x04>') if not data.endswith(b'\x04>'): print(data) raise PyboardError('timeout waiting for EOF reception') diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index fe35e5b094..75f119e918 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -14,6 +14,7 @@ #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_PATH_MAX (PATH_MAX) +#define MICROPY_USE_COMPUTED_GOTO (1) #define MICROPY_MOD_SYS_STDFILES (1) // type definitions for the specific machine |