diff options
42 files changed, 731 insertions, 198 deletions
diff --git a/examples/unix/ffi_example.py b/examples/unix/ffi_example.py new file mode 100644 index 0000000000..0ac12203e6 --- /dev/null +++ b/examples/unix/ffi_example.py @@ -0,0 +1,38 @@ +import ffi + +libc = ffi.open("libc.so.6") +print("libc:", libc) +print() + +# Declare few functions +perror = libc.func("v", "perror", ["s"]) +time = libc.func("i", "time", "p") +open = libc.func("i", "open", ["s", "i"]) +qsort = libc.func("v", "qsort", "piip") +# And one variable +errno = libc.var("i", "errno") + +print("time:", time) +print("UNIX time is:", time(None)) +print() + +perror("ffi before error") +open("somethingnonexistent__", 0) +print(errno) +perror("ffi after error") +print() + +def cmp(pa, pb): + a = ffi.as_bytearray(pa, 1) + b = ffi.as_bytearray(pb, 1) + print("cmp:", a, b) + return a[0] - b[0] + +cmp_c = ffi.callback("i", cmp, "pp") +print("callback:", cmp_c) + +# TODO: violates Py semantics, pass bytearray +s = "foobar" +print("org string:", s) +qsort(s, len(s), 1, cmp_c) +print("qsort'ed:", s) diff --git a/py/compile.c b/py/compile.c index e1b62a11bf..c1a7955dcd 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1912,7 +1912,21 @@ void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); +#if MICROPY_EMIT_CPYTHON EMIT_ARG(unary_op, RT_UNARY_OP_NOT); +#else + // eliminate use of NOT byte code + int l_load_false = comp_next_label(comp); + int l_done = comp_next_label(comp); + int stack_size = EMIT(get_stack_size); + EMIT_ARG(pop_jump_if_true, l_load_false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_TRUE); + EMIT_ARG(jump, l_done); + EMIT_ARG(label_assign, l_load_false); + EMIT_ARG(load_const_tok, MP_TOKEN_KW_FALSE); + EMIT_ARG(label_assign, l_done); + EMIT_ARG(set_stack_size, stack_size); // force stack size since it counts 1 pop and 2 pushes statically, but really it's 1 pop and 1 push dynamically +#endif } void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2487,7 +2501,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) { if (MP_PARSE_NODE_IS_NULL(pn)) { // pass } else if (MP_PARSE_NODE_IS_LEAF(pn)) { - int arg = MP_PARSE_NODE_LEAF_ARG(pn); + machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break; case MP_PARSE_NODE_SMALL_INT: EMIT_ARG(load_const_small_int, arg); break; @@ -3016,7 +3030,8 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) { scope->flags |= SCOPE_FLAG_OPTIMISED; // TODO possibly other ways it can be nested - if (scope->parent->kind == SCOPE_FUNCTION || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) { + // Note that we don't actually use this information at the moment (for CPython compat only) + if ((SCOPE_FUNCTION <= scope->parent->kind && scope->parent->kind <= SCOPE_SET_COMP) || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) { scope->flags |= SCOPE_FLAG_NESTED; } } @@ -34,7 +34,7 @@ typedef struct _emit_method_table_t { void (*import_from)(emit_t *emit, qstr qstr); void (*import_star)(emit_t *emit); void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok); - void (*load_const_small_int)(emit_t *emit, int arg); + void (*load_const_small_int)(emit_t *emit, machine_int_t arg); void (*load_const_int)(emit_t *emit, qstr qstr); void (*load_const_dec)(emit_t *emit, qstr qstr); void (*load_const_id)(emit_t *emit, qstr qstr); diff --git a/py/emitbc.c b/py/emitbc.c index 9fa2880ecb..d74b065253 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -108,7 +108,7 @@ static void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) { } // integers (for small ints) are stored as 24 bits, in excess -static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, int num) { +static void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) { num += 0x800000; assert(0 <= num && num <= 0xffffff); byte* c = emit_get_cur_to_write_byte_code(emit, 4); @@ -249,6 +249,7 @@ static void emit_bc_set_stack_size(emit_t *emit, int size) { static void emit_bc_set_source_line(emit_t *emit, int source_line) { //printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->byte_code_offset); +#if MICROPY_ENABLE_SOURCE_LINE if (source_line > emit->last_source_line) { uint bytes_to_skip = emit->byte_code_offset - emit->last_source_line_offset; uint lines_to_skip = source_line - emit->last_source_line; @@ -257,6 +258,7 @@ static void emit_bc_set_source_line(emit_t *emit, int source_line) { emit->last_source_line_offset = emit->byte_code_offset; emit->last_source_line = source_line; } +#endif } static void emit_bc_load_id(emit_t *emit, qstr qstr) { @@ -319,7 +321,7 @@ static void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) { } } -static void emit_bc_load_const_small_int(emit_t *emit, int arg) { +static void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit, 1); emit_write_byte_code_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg); } @@ -390,7 +392,7 @@ static void emit_bc_load_attr(emit_t *emit, qstr qstr) { } static void emit_bc_load_method(emit_t *emit, qstr qstr) { - emit_pre(emit, 0); + emit_pre(emit, 1); emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr); } @@ -707,7 +709,7 @@ static void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, b if (have_dbl_star_arg) { s += 1; } - emit_pre(emit, -n_positional - 2 * n_keyword - s); + emit_pre(emit, -1 - n_positional - 2 * n_keyword - s); int op; if (have_star_arg) { if (have_dbl_star_arg) { diff --git a/py/emitcpy.c b/py/emitcpy.c index 71861c918d..2e5c34cb2b 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -149,10 +149,10 @@ static void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) { } } -static void emit_cpy_load_const_small_int(emit_t *emit, int arg) { +static void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { - printf("LOAD_CONST %d\n", arg); + printf("LOAD_CONST " INT_FMT "\n", arg); } } diff --git a/py/emitnative.c b/py/emitnative.c index 258aa9fce5..1e5ea1fa9b 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -599,7 +599,7 @@ static void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) { emit_post_push_imm(emit, vtype, val); } -static void emit_native_load_const_small_int(emit_t *emit, int arg) { +static void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) { emit_pre(emit); if (emit->do_viper_types) { emit_post_push_imm(emit, VTYPE_INT, arg); diff --git a/py/malloc.c b/py/malloc.c index 4f01dc63f5..a2c55eb06b 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -4,6 +4,12 @@ #include "misc.h" #include "mpconfig.h" +#if 0 // print debugging info +#define DEBUG_printf(args...) printf(args) +#else // don't print debugging info +#define DEBUG_printf(args...) (void)0 +#endif + #if MICROPY_MEM_STATS static int total_bytes_allocated = 0; static int current_bytes_allocated = 0; @@ -26,6 +32,7 @@ void *m_malloc(int num_bytes) { current_bytes_allocated += num_bytes; UPDATE_PEAK(); #endif + DEBUG_printf("malloc %d : %p\n", num_bytes, ptr); return ptr; } @@ -43,6 +50,7 @@ void *m_malloc0(int num_bytes) { current_bytes_allocated += num_bytes; UPDATE_PEAK(); #endif + DEBUG_printf("malloc0 %d : %p\n", num_bytes, ptr); return ptr; } @@ -67,6 +75,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) { current_bytes_allocated += diff; UPDATE_PEAK(); #endif + DEBUG_printf("realloc %d, %d : %p\n", old_num_bytes, new_num_bytes, ptr); return ptr; } @@ -77,6 +86,7 @@ void m_free(void *ptr, int num_bytes) { #if MICROPY_MEM_STATS current_bytes_allocated -= num_bytes; #endif + DEBUG_printf("free %p, %d\n", ptr, num_bytes); } int m_get_total_bytes_allocated(void) { diff --git a/py/mpconfig.h b/py/mpconfig.h index 97e4b13875..38b74b733a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -76,6 +76,12 @@ typedef long long mp_longint_impl_t; #endif +// Whether to include information in the byte code to determine source +// line number (increases RAM usage, but doesn't slow byte code execution) +#ifndef MICROPY_ENABLE_SOURCE_LINE +#define MICROPY_ENABLE_SOURCE_LINE (0) +#endif + // Whether to support float and complex types #ifndef MICROPY_ENABLE_FLOAT #define MICROPY_ENABLE_FLOAT (0) @@ -57,7 +57,11 @@ void mp_obj_print_exception(mp_obj_t exc) { if (n > 0) { printf("Traceback (most recent call last):\n"); for (int i = n - 3; i >= 0; i -= 3) { +#if MICROPY_ENABLE_SOURCE_LINE printf(" File \"%s\", line %d, in %s\n", qstr_str(values[i]), (int)values[i + 1], qstr_str(values[i + 2])); +#else + printf(" File \"%s\", in %s\n", qstr_str(values[i]), qstr_str(values[i + 2])); +#endif } } } @@ -223,7 +223,7 @@ mp_obj_t mp_obj_new_range(int start, int stop, int step); mp_obj_t mp_obj_new_range_iterator(int cur, int stop, int step); mp_obj_t mp_obj_new_fun_bc(int n_args, uint n_state, const byte *code); mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun); -mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun); +mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_gen_instance(const byte *bytecode, uint n_state, int n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple); mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items); @@ -291,6 +291,7 @@ uint mp_obj_str_get_len(mp_obj_t self_in); qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated const byte *mp_obj_str_get_data(mp_obj_t self_in, uint *len); +void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len); // bytes extern const mp_obj_type_t bytes_type; @@ -348,6 +349,7 @@ extern const mp_obj_type_t zip_type; // array extern const mp_obj_type_t array_type; uint mp_obj_array_len(mp_obj_t self_in); +mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items); // functions typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM) diff --git a/py/objarray.c b/py/objarray.c index 4f36561153..42dbfcda05 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -124,17 +124,22 @@ static void array_set_el(mp_obj_array_t *o, int index, mp_obj_t val_in) { static void array_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_array_t *o = o_in; if (o->typecode == BYTEARRAY_TYPECODE) { - print(env, "bytearray([", o->typecode); + print(env, "bytearray(b", o->typecode); + mp_str_print_quoted(print, env, o->items, o->len); } else { - print(env, "array('%c', [", o->typecode); - } - for (int i = 0; i < o->len; i++) { - if (i > 0) { - print(env, ", "); + print(env, "array('%c'", o->typecode); + if (o->len > 0) { + print(env, ", [", o->typecode); + for (int i = 0; i < o->len; i++) { + if (i > 0) { + print(env, ", "); + } + print(env, "%d", array_get_el(o, i)); + } + print(env, "]"); } - print(env, "%d", array_get_el(o, i)); } - print(env, "])"); + print(env, ")"); } static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { @@ -164,20 +169,17 @@ static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { } static mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { - switch (n_args) { - case 2: - { - // TODO check args - uint l; - const byte *s = mp_obj_str_get_data(args[0], &l); - mp_obj_t initializer = args[1]; - return array_construct(*s, initializer); - } - - default: - nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args)); + if (n_args < 1 || n_args > 2) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_TypeError, "unexpected # of arguments, %d given", n_args)); + } + // TODO check args + uint l; + const byte *typecode = mp_obj_str_get_data(args[0], &l); + if (n_args == 1) { + return array_new(*typecode, 0); } - return NULL; + + return array_construct(*typecode, args[1]); } // This is top-level factory function, not virtual method @@ -269,6 +271,17 @@ mp_obj_t mp_obj_new_bytearray(uint n, void *items) { return o; } +// Create bytearray which references specified memory area +mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) { + mp_obj_array_t *o = m_new_obj(mp_obj_array_t); + o->base.type = &array_type; + o->typecode = BYTEARRAY_TYPECODE; + o->free = 0; + o->len = n; + o->items = items; + return o; +} + /******************************************************************************/ /* array iterator */ diff --git a/py/objcomplex.c b/py/objcomplex.c index af148a2786..24762e8b11 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -24,9 +24,9 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag); void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_complex_t *o = o_in; if (o->real == 0) { - print(env, "%.8gj", o->imag); + print(env, "%.8gj", (double) o->imag); } else { - print(env, "(%.8g+%.8gj)", o->real, o->imag); + print(env, "(%.8g+%.8gj)", (double) o->real, (double) o->imag); } } diff --git a/py/objdict.c b/py/objdict.c index 55a612913d..93ff1af90a 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -43,6 +43,14 @@ static mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp return rt_build_map(0); } +static mp_obj_t dict_unary_op(int op, mp_obj_t self_in) { + mp_obj_dict_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->map.used == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { mp_obj_dict_t *o = lhs_in; switch (op) { @@ -436,6 +444,7 @@ const mp_obj_type_t dict_type = { "dict", .print = dict_print, .make_new = dict_make_new, + .unary_op = dict_unary_op, .binary_op = dict_binary_op, .getiter = dict_getiter, .methods = dict_type_methods, diff --git a/py/objexcept.c b/py/objexcept.c index c91b71dd9e..8eb4e966e9 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -13,20 +13,19 @@ // This is unified class for C-level and Python-level exceptions // Python-level exception have empty ->msg and all arguments are in -// args tuple. C-level excepttion likely have ->msg, and may as well -// have args tuple (or otherwise have it as NULL). +// args tuple. C-level excepttion likely have ->msg and args is empty. typedef struct mp_obj_exception_t { mp_obj_base_t base; mp_obj_t traceback; // a list object, holding (file,line,block) as numbers (not Python objects); a hack for now qstr id; - qstr msg; + vstr_t *msg; mp_obj_tuple_t args; } mp_obj_exception_t; void exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = o_in; - if (o->msg != 0) { - print(env, "%s: %s", qstr_str(o->id), qstr_str(o->msg)); + if (o->msg != NULL) { + print(env, "%s: %s", qstr_str(o->id), vstr_str(o->msg)); } else { // Yes, that's how CPython has it if (kind == PRINT_REPR) { @@ -55,7 +54,7 @@ static mp_obj_t exception_call(mp_obj_t self_in, uint n_args, uint n_kw, const m mp_obj_exception_t *o = m_new_obj_var(mp_obj_exception_t, mp_obj_t, n_args); o->base.type = &exception_type; o->id = base->id; - o->msg = 0; + o->msg = NULL; o->args.len = n_args; memcpy(o->args.items, args, n_args * sizeof(mp_obj_t)); return o; @@ -92,15 +91,14 @@ mp_obj_t mp_obj_new_exception_msg_varg(qstr id, const char *fmt, ...) { o->id = id; o->args.len = 0; if (fmt == NULL) { - o->msg = 0; + o->msg = NULL; } else { // render exception message - vstr_t *vstr = vstr_new(); + o->msg = vstr_new(); va_list ap; va_start(ap, fmt); - vstr_vprintf(vstr, fmt, ap); + vstr_vprintf(o->msg, fmt, ap); va_end(ap); - o->msg = qstr_from_strn_take(vstr->buf, vstr->alloc, vstr->len); } return o; diff --git a/py/objfloat.c b/py/objfloat.c index 9f1f478cab..69fd65e199 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -21,7 +21,7 @@ mp_obj_t mp_obj_new_float(mp_float_t value); static void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_float_t *o = o_in; - print(env, "%.8g", o->value); + print(env, "%.8g", (double) o->value); } static mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 91bbbceb2f..67f8eed59c 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -16,7 +16,6 @@ typedef struct _mp_obj_gen_wrap_t { mp_obj_base_t base; - uint n_state; mp_obj_t *fun; } mp_obj_gen_wrap_t; @@ -35,7 +34,7 @@ mp_obj_t gen_wrap_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t nlr_jump(mp_obj_new_exception_msg(MP_QSTR_TypeError, "function does not take keyword arguments")); } - return mp_obj_new_gen_instance(bc_code, self->n_state, n_args, args); + return mp_obj_new_gen_instance(bc_code, bc_n_state, n_args, args); } const mp_obj_type_t gen_wrap_type = { @@ -44,11 +43,9 @@ const mp_obj_type_t gen_wrap_type = { .call = gen_wrap_call, }; -mp_obj_t mp_obj_new_gen_wrap(uint n_locals, uint n_stack, mp_obj_t fun) { +mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun) { mp_obj_gen_wrap_t *o = m_new_obj(mp_obj_gen_wrap_t); o->base.type = &gen_wrap_type; - // we have at least 3 locals so the bc can write back fast[0,1,2] safely; should improve how this is done - o->n_state = (n_locals < 3 ? 3 : n_locals) + n_stack; o->fun = fun; return o; } diff --git a/py/objlist.c b/py/objlist.c index d21e16000d..fb68e2c566 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -122,6 +122,14 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { return true; } +static mp_obj_t list_unary_op(int op, mp_obj_t self_in) { + mp_obj_list_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_list_t *o = lhs; switch (op) { @@ -399,6 +407,7 @@ const mp_obj_type_t list_type = { "list", .print = list_print, .make_new = list_make_new, + .unary_op = list_unary_op, .binary_op = list_binary_op, .getiter = list_getiter, .methods = list_type_methods, diff --git a/py/objnone.c b/py/objnone.c index ecc7c4b4e7..4151403b21 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -6,19 +6,28 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "runtime0.h" typedef struct _mp_obj_none_t { mp_obj_base_t base; } mp_obj_none_t; -void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +static void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { print(env, "None"); } +static mp_obj_t none_unary_op(int op, mp_obj_t o_in) { + switch (op) { + case RT_UNARY_OP_NOT: return mp_const_true; + default: return MP_OBJ_NULL; // op not supported for None + } +} + const mp_obj_type_t none_type = { { &mp_const_type }, "NoneType", .print = none_print, + .unary_op = none_unary_op, }; static const mp_obj_none_t none_obj = {{&none_type}}; diff --git a/py/objstr.c b/py/objstr.c index 84ac74bab9..c30da00d71 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -34,45 +34,49 @@ static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str); /******************************************************************************/ /* str */ -void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +void mp_str_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_single_quote || !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); + for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { + if (*s == quote_char) { + print(env, "\\%c", quote_char); + } else if (*s == '\\') { + print(env, "\\\\"); + } else if (32 <= *s && *s <= 126) { + print(env, "%c", *s); + } else if (*s == '\n') { + print(env, "\\n"); + // TODO add more escape codes here if we want to match CPython + } else { + print(env, "\\x%02x", *s); + } + } + print(env, "%c", quote_char); +} + +static void str_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); bool is_bytes = MP_OBJ_IS_TYPE(self_in, &bytes_type); if (kind == PRINT_STR && !is_bytes) { print(env, "%.*s", str_len, str_data); } else { - // 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_single_quote || !has_double_quote) && s < top; s++) { - if (*s == '\'') { - has_single_quote = true; - } else if (*s == '"') { - has_double_quote = true; - } - } if (is_bytes) { print(env, "b"); } - int quote_char = '\''; - if (has_single_quote && !has_double_quote) { - quote_char = '"'; - } - print(env, "%c", quote_char); - for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) { - if (*s == quote_char) { - print(env, "\\%c", quote_char); - } else if (*s == '\\') { - print(env, "\\\\"); - } else if (32 <= *s && *s <= 126) { - print(env, "%c", *s); - } else if (*s == '\n') { - print(env, "\\n"); - // TODO add more escape codes here if we want to match CPython - } else { - print(env, "\\x%02x", *s); - } - } - print(env, "%c", quote_char); + mp_str_print_quoted(print, env, str_data, str_len); } } diff --git a/py/objtuple.c b/py/objtuple.c index ec35ef8550..754fe4b662 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -73,6 +73,14 @@ static mp_obj_t tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m } } +static mp_obj_t tuple_unary_op(int op, mp_obj_t self_in) { + mp_obj_tuple_t *self = self_in; + switch (op) { + case RT_UNARY_OP_NOT: if (self->len == 0) { return mp_const_true; } else { return mp_const_false; } + default: return MP_OBJ_NULL; // op not supported for None + } +} + static mp_obj_t tuple_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_tuple_t *o = lhs; switch (op) { @@ -97,6 +105,7 @@ const mp_obj_type_t tuple_type = { "tuple", .print = tuple_print, .make_new = tuple_make_new, + .unary_op = tuple_unary_op, .binary_op = tuple_binary_op, .getiter = tuple_getiter, }; diff --git a/py/parse.c b/py/parse.c index d9969d6785..d0776cefba 100644 --- a/py/parse.c +++ b/py/parse.c @@ -172,15 +172,15 @@ void mp_parse_node_print(mp_parse_node_t pn, int indent) { if (MP_PARSE_NODE_IS_NULL(pn)) { printf("NULL\n"); } else if (MP_PARSE_NODE_IS_LEAF(pn)) { - int arg = MP_PARSE_NODE_LEAF_ARG(pn); + machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pn); switch (MP_PARSE_NODE_LEAF_KIND(pn)) { case MP_PARSE_NODE_ID: printf("id(%s)\n", qstr_str(arg)); break; - case MP_PARSE_NODE_SMALL_INT: printf("int(%d)\n", arg); break; + case MP_PARSE_NODE_SMALL_INT: printf("int(" INT_FMT ")\n", arg); break; case MP_PARSE_NODE_INTEGER: printf("int(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_DECIMAL: printf("dec(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_STRING: printf("str(%s)\n", qstr_str(arg)); break; case MP_PARSE_NODE_BYTES: printf("bytes(%s)\n", qstr_str(arg)); break; - case MP_PARSE_NODE_TOKEN: printf("tok(%d)\n", arg); break; + case MP_PARSE_NODE_TOKEN: printf("tok(" INT_FMT ")\n", arg); break; default: assert(0); } } else { @@ -185,3 +185,19 @@ const byte *qstr_data(qstr q, uint *len) { *len = Q_GET_LENGTH(qd); return Q_GET_DATA(qd); } + +void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes) { + *n_pool = 0; + *n_qstr = 0; + *n_str_data_bytes = 0; + *n_total_bytes = 0; + for (qstr_pool_t *pool = last_pool; pool != NULL && pool != &const_pool; pool = pool->prev) { + *n_pool += 1; + *n_qstr += pool->len; + for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + *n_str_data_bytes += Q_GET_ALLOC(*q); + } + *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc; + } + *n_total_bytes += *n_str_data_bytes; +} @@ -36,3 +36,5 @@ machine_uint_t qstr_hash(qstr q); const char* qstr_str(qstr q); uint qstr_len(qstr q); const byte* qstr_data(qstr q, uint *len); + +void qstr_pool_info(uint *n_pool, uint *n_qstr, uint *n_str_data_bytes, uint *n_total_bytes); diff --git a/py/runtime.c b/py/runtime.c index 8ad98d5f12..6dd6921599 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -44,11 +44,14 @@ typedef enum { } mp_code_kind_t; typedef struct _mp_code_t { - mp_code_kind_t kind; - int n_args; - int n_locals; - int n_stack; - bool is_generator; + struct { + mp_code_kind_t kind : 8; + bool is_generator : 1; + }; + struct { + uint n_args : 16; + uint n_state : 16; + }; union { struct { byte *code; @@ -63,7 +66,7 @@ typedef struct _mp_code_t { }; } mp_code_t; -static int next_unique_code_id; +static uint next_unique_code_id; static machine_uint_t unique_codes_alloc = 0; static mp_code_t *unique_codes = NULL; @@ -130,7 +133,6 @@ void rt_init(void) { mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array); rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type); - rt_store_name(MP_QSTR_array, m_array); // built-in user functions mp_map_add_qstr(&map_builtins, MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj); @@ -188,37 +190,37 @@ void rt_deinit(void) { #endif } -int rt_get_unique_code_id(void) { +uint rt_get_unique_code_id(void) { return next_unique_code_id++; } static void alloc_unique_codes(void) { if (next_unique_code_id > unique_codes_alloc) { + DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id); // increase size of unique_codes table unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id); - for (int i = unique_codes_alloc; i < next_unique_code_id; i++) { + for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) { unique_codes[i].kind = MP_CODE_NONE; } unique_codes_alloc = next_unique_code_id; } } -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) { +void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_BYTE; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = n_locals; - unique_codes[unique_code_id].n_stack = n_stack; unique_codes[unique_code_id].is_generator = is_generator; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = n_locals + n_stack; unique_codes[unique_code_id].u_byte.code = code; unique_codes[unique_code_id].u_byte.len = len; //printf("byte code: %d bytes\n", len); #ifdef DEBUG_PRINT - DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d\n", unique_code_id, code, len, n_args); + DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d n_locals=%d n_stack=%d\n", unique_code_id, code, len, n_args, n_locals, n_stack); for (int i = 0; i < 128 && i < len; i++) { if (i > 0 && i % 16 == 0) { DEBUG_printf("\n"); @@ -239,15 +241,14 @@ void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, i #endif } -void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) { +void rt_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_NATIVE; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = 0; - unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = 0; unique_codes[unique_code_id].u_native.fun = fun; //printf("native code: %d bytes\n", len); @@ -272,15 +273,14 @@ void rt_assign_native_code(int unique_code_id, void *fun, uint len, int n_args) #endif } -void rt_assign_inline_asm_code(int unique_code_id, void *fun, uint len, int n_args) { +void rt_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) { alloc_unique_codes(); assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE); unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM; - unique_codes[unique_code_id].n_args = n_args; - unique_codes[unique_code_id].n_locals = 0; - unique_codes[unique_code_id].n_stack = 0; unique_codes[unique_code_id].is_generator = false; + unique_codes[unique_code_id].n_args = n_args; + unique_codes[unique_code_id].n_state = 0; unique_codes[unique_code_id].u_inline_asm.fun = fun; #ifdef DEBUG_PRINT @@ -316,23 +316,18 @@ int rt_is_true(mp_obj_t arg) { return 0; } else if (arg == mp_const_true) { return 1; - } else if (MP_OBJ_IS_STR(arg)) { - return mp_obj_str_get_len(arg) != 0; - } else if (MP_OBJ_IS_TYPE(arg, &list_type)) { - uint len; - mp_obj_t *dummy; - mp_obj_list_get(arg, &len, &dummy); - return len != 0; - } else if (MP_OBJ_IS_TYPE(arg, &tuple_type)) { - uint len; - mp_obj_t *dummy; - mp_obj_tuple_get(arg, &len, &dummy); - return len != 0; - } else if (MP_OBJ_IS_TYPE(arg, &dict_type)) { - return mp_obj_dict_len(arg) != 0; } else { - assert(0); - return 0; + mp_obj_t len = mp_obj_len_maybe(arg); + if (len != MP_OBJ_NULL) { + // obj has a length, truth determined if len != 0 + return len != MP_OBJ_NEW_SMALL_INT(0); + } else { + // TODO check for __bool__ method + // TODO check floats and complex numbers + + // any other obj is true (TODO is that correct?) + return 1; + } } } @@ -481,7 +476,7 @@ mp_obj_t rt_unary_op(int op, mp_obj_t arg) { if (MP_OBJ_IS_SMALL_INT(arg)) { mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { - case RT_UNARY_OP_NOT: if (val != 0) { return mp_const_true;} else { return mp_const_false; } + case RT_UNARY_OP_NOT: if (val == 0) { return mp_const_true;} else { return mp_const_false; } case RT_UNARY_OP_POSITIVE: break; case RT_UNARY_OP_NEGATIVE: val = -val; break; case RT_UNARY_OP_INVERT: val = ~val; break; @@ -684,7 +679,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { mp_obj_t fun; switch (c->kind) { case MP_CODE_BYTE: - fun = mp_obj_new_fun_bc(c->n_args, c->n_locals + c->n_stack, c->u_byte.code); + fun = mp_obj_new_fun_bc(c->n_args, c->n_state, c->u_byte.code); break; case MP_CODE_NATIVE: fun = rt_make_function_n(c->n_args, c->u_native.fun); @@ -699,7 +694,7 @@ mp_obj_t rt_make_function_from_id(int unique_code_id) { // check for generator functions and if so wrap in generator object if (c->is_generator) { - fun = mp_obj_new_gen_wrap(c->n_locals, c->n_stack, fun); + fun = mp_obj_new_gen_wrap(fun); } return fun; diff --git a/py/runtime0.h b/py/runtime0.h index 4fdcdc3cc9..cd82b1412b 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -1,5 +1,5 @@ typedef enum { - RT_UNARY_OP_NOT, + RT_UNARY_OP_NOT, // TODO remove this op since it's no longer needed RT_UNARY_OP_POSITIVE, RT_UNARY_OP_NEGATIVE, RT_UNARY_OP_INVERT, @@ -78,7 +78,7 @@ extern void *const rt_fun_table[RT_F_NUMBER_OF]; void rt_init(void); void rt_deinit(void); -int rt_get_unique_code_id(void); -void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); -void rt_assign_native_code(int unique_code_id, void *f, uint len, int n_args); -void rt_assign_inline_asm_code(int unique_code_id, void *f, uint len, int n_args); +uint rt_get_unique_code_id(void); +void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, bool is_generator); +void rt_assign_native_code(uint unique_code_id, void *f, uint len, int n_args); +void rt_assign_inline_asm_code(uint unique_code_id, void *f, uint len, int n_args); diff --git a/py/showbc.c b/py/showbc.c index f914223933..d7ae17c2e3 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -68,12 +68,10 @@ void mp_byte_code_print(const byte *ip, int len) { printf("LOAD_CONST_INT %s", qstr_str(qstr)); break; - /* case MP_BC_LOAD_CONST_DEC: DECODE_QSTR; - PUSH(rt_load_const_dec(qstr)); + printf("LOAD_CONST_DEC %s", qstr_str(qstr)); break; - */ case MP_BC_LOAD_CONST_ID: DECODE_QSTR; @@ -351,12 +349,12 @@ void mp_byte_code_print(const byte *ip, int len) { case MP_BC_IMPORT_NAME: DECODE_QSTR; - printf("IMPORT NAME %s", qstr_str(qstr)); + printf("IMPORT_NAME %s", qstr_str(qstr)); break; case MP_BC_IMPORT_FROM: DECODE_QSTR; - printf("IMPORT NAME %s", qstr_str(qstr)); + printf("IMPORT_FROM %s", qstr_str(qstr)); break; default: @@ -26,8 +26,6 @@ #define SET_TOP(val) *sp = (val) mp_obj_t mp_execute_byte_code(const byte *code, const mp_obj_t *args, uint n_args, uint n_state) { - n_state += 1; // XXX there is a bug somewhere which doesn't count enough state... (conwaylife and mandel have the bug) - // allocate state for locals and stack mp_obj_t temp_state[10]; mp_obj_t *state = &temp_state[0]; @@ -82,7 +80,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob machine_uint_t unum; qstr qst; mp_obj_t obj1, obj2; - mp_obj_t fast0 = fastn[0], fast1 = fastn[-1], fast2 = fastn[-2]; nlr_buf_t nlr; volatile machine_uint_t currently_in_except_block = 0; // 0 or 1, to detect nested exceptions @@ -90,8 +87,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob machine_uint_t *volatile exc_sp = &exc_stack[0] - 1; // stack grows up, exc_sp points to top of stack const byte *volatile save_ip = ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop) - // TODO if an exception occurs, do fast[0,1,2] become invalid?? - // outer exception handling loop for (;;) { if (nlr_push(&nlr) == 0) { @@ -148,15 +143,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob break; case MP_BC_LOAD_FAST_0: - PUSH(fast0); + PUSH(fastn[0]); break; case MP_BC_LOAD_FAST_1: - PUSH(fast1); + PUSH(fastn[-1]); break; case MP_BC_LOAD_FAST_2: - PUSH(fast2); + PUSH(fastn[-2]); break; case MP_BC_LOAD_FAST_N: @@ -166,16 +161,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_LOAD_DEREF: DECODE_UINT; - if (unum == 0) { - obj1 = fast0; - } else if (unum == 1) { - obj1 = fast1; - } else if (unum == 2) { - obj1 = fast2; - } else { - obj1 = fastn[-unum]; - } - PUSH(rt_get_cell(obj1)); + PUSH(rt_get_cell(fastn[-unum])); break; case MP_BC_LOAD_NAME: @@ -204,15 +190,15 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob break; case MP_BC_STORE_FAST_0: - fast0 = POP(); + fastn[0] = POP(); break; case MP_BC_STORE_FAST_1: - fast1 = POP(); + fastn[-1] = POP(); break; case MP_BC_STORE_FAST_2: - fast2 = POP(); + fastn[-2] = POP(); break; case MP_BC_STORE_FAST_N: @@ -222,16 +208,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_STORE_DEREF: DECODE_UINT; - if (unum == 0) { - obj1 = fast0; - } else if (unum == 1) { - obj1 = fast1; - } else if (unum == 2) { - obj1 = fast2; - } else { - obj1 = fastn[-unum]; - } - rt_set_cell(obj1, POP()); + rt_set_cell(fastn[-unum], POP()); break; case MP_BC_STORE_NAME: @@ -479,8 +456,7 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_MAKE_CLOSURE: DECODE_UINT; - obj1 = POP(); - PUSH(rt_make_closure_from_id(unum, obj1)); + SET_TOP(rt_make_closure_from_id(unum, TOP())); break; case MP_BC_CALL_FUNCTION: @@ -514,9 +490,6 @@ bool mp_execute_byte_code_2(const byte *code_info, const byte **ip_in_out, mp_ob case MP_BC_YIELD_VALUE: nlr_pop(); *ip_in_out = ip; - fastn[0] = fast0; - fastn[-1] = fast1; - fastn[-2] = fast2; *sp_in_out = sp; return true; diff --git a/stm/file.c b/stm/file.c index 35bfca16a5..84f7251fec 100644 --- a/stm/file.c +++ b/stm/file.c @@ -3,7 +3,6 @@ #include "misc.h" #include "mpconfig.h" -#include "mpconfigport.h" #include "qstr.h" #include "obj.h" #include "file.h" diff --git a/stm/gccollect.c b/stm/gccollect.c index c0f67ac0d5..ada5493a23 100644 --- a/stm/gccollect.c +++ b/stm/gccollect.c @@ -13,10 +13,10 @@ void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t hea void gc_collect(void) { uint32_t start = sys_tick_counter; gc_collect_start(); - gc_collect_root((void**)&_ram_start, ((uint32_t)&_heap_start - (uint32_t)&_ram_start) / 4); + gc_collect_root((void**)&_ram_start, ((uint32_t)&_heap_start - (uint32_t)&_ram_start) / sizeof(uint32_t)); 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_helper_get_regs_and_clean_stack(regs, (machine_uint_t)&_heap_end); + gc_collect_root((void**)&_heap_end, ((uint32_t)&_ram_end - (uint32_t)&_heap_end) / sizeof(uint32_t)); // will trace regs since they now live in this function on the stack gc_collect_end(); uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly diff --git a/stm/gccollect.h b/stm/gccollect.h index 6467ec7d21..9187f0e9df 100644 --- a/stm/gccollect.h +++ b/stm/gccollect.h @@ -1,8 +1,7 @@ -#define HEAP_END (0x2001c000) // tunable -#define RAM_END (0x20020000) // fixed for chip - extern uint32_t _ram_start; extern uint32_t _heap_start; +extern uint32_t _ram_end; +extern uint32_t _heap_end; void gc_collect(void); @@ -41,6 +41,16 @@ #define PYB_LCD_BL_PORT (GPIOB) #define PYB_LCD_BL_PIN (GPIO_Pin_1) // Y12 = PB1 */ +#elif defined(STM32F4DISC) +/* Configure if needed */ +#define PYB_LCD_PORT (GPIOA) +#define PYB_LCD_CS1_PIN (GPIO_Pin_2) // X3 +#define PYB_LCD_RST_PIN (GPIO_Pin_3) // X4 +#define PYB_LCD_A0_PIN (GPIO_Pin_4) // X5 +#define PYB_LCD_SCL_PIN (GPIO_Pin_5) // X6 +#define PYB_LCD_SI_PIN (GPIO_Pin_7) // X8 +#define PYB_LCD_BL_PORT (GPIOC) +#define PYB_LCD_BL_PIN (GPIO_Pin_5) // X12 #endif #define LCD_INSTR (0) diff --git a/stm/main.c b/stm/main.c index 90fdab3d22..313a868c41 100644 --- a/stm/main.c +++ b/stm/main.c @@ -129,6 +129,7 @@ static const char *help_text = "Specific commands for the board:\n" " pyb.info() -- print some general information\n" " pyb.gc() -- run the garbage collector\n" +" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n" " pyb.delay(<n>) -- wait for n milliseconds\n" " pyb.Led(<n>) -- create Led object for LED n (n=1,2)\n" " Led methods: on(), off()\n" @@ -174,15 +175,24 @@ static mp_obj_t pyb_info(void) { extern void *_ebss; extern void *_estack; extern void *_etext; + 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("_etext=%p\n", &_etext); 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 @@ -206,12 +216,21 @@ static mp_obj_t pyb_info(void) { return mp_const_none; } +static bool repl_display_debugging_info = 0; + +static mp_obj_t pyb_set_repl_info(mp_obj_t o_value) { + repl_display_debugging_info = mp_obj_get_int(o_value); + return mp_const_none; +} + +#if MICROPY_HW_HAS_SDCARD // SD card test static mp_obj_t pyb_sd_test(void) { extern void sdio_init(void); sdio_init(); return mp_const_none; } +#endif static void SYSCLKConfig_STOP(void) { /* After wake-up from STOP reconfigure the system clock */ @@ -418,15 +437,18 @@ void do_repl(void) { if (nlr_push(&nlr) == 0) { rt_call_function_0(module_fun); nlr_pop(); - // optional timing - if (0) { - uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly - printf("(took %lu ms)\n", ticks); - } } else { // uncaught exception mp_obj_print_exception((mp_obj_t)nlr.ret_val); } + + // display debugging info if wanted + if (repl_display_debugging_info) { + uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly + printf("took %lu ms\n", ticks); + gc_collect(); + pyb_info(); + } } } } @@ -594,7 +616,7 @@ int main(void) { soft_reset: // GC init - gc_init(&_heap_start, (void*)HEAP_END); + gc_init(&_heap_start, &_heap_end); // Micro Python init qstr_init(); @@ -632,6 +654,8 @@ soft_reset: mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb); rt_store_attr(m, MP_QSTR_info, rt_make_function_n(0, pyb_info)); + rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj); + rt_store_attr(m, qstr_from_str("repl_info"), rt_make_function_n(1, pyb_set_repl_info)); #if MICROPY_HW_HAS_SDCARD rt_store_attr(m, MP_QSTR_sd_test, rt_make_function_n(0, pyb_sd_test)); #endif @@ -640,7 +664,6 @@ soft_reset: rt_store_attr(m, MP_QSTR_source_dir, rt_make_function_n(1, pyb_source_dir)); rt_store_attr(m, MP_QSTR_main, rt_make_function_n(1, pyb_main)); rt_store_attr(m, MP_QSTR_sync, rt_make_function_n(0, pyb_sync)); - rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj); rt_store_attr(m, MP_QSTR_delay, rt_make_function_n(1, pyb_delay)); #if MICROPY_HW_HAS_SWITCH rt_store_attr(m, MP_QSTR_switch, (mp_obj_t)&pyb_switch_obj); @@ -655,7 +678,7 @@ soft_reset: rt_store_attr(m, MP_QSTR_mma_mode, (mp_obj_t)&pyb_mma_write_mode_obj); #endif rt_store_attr(m, MP_QSTR_hid, rt_make_function_n(1, pyb_hid_send_report)); -#if MICROPY_HW_HAS_RTC +#if MICROPY_HW_ENABLE_RTC rt_store_attr(m, MP_QSTR_time, rt_make_function_n(0, pyb_rtc_read)); #endif #if MICROPY_HW_ENABLE_RNG diff --git a/stm/printf.c b/stm/printf.c index 82b168d1c4..a0620018cc 100644 --- a/stm/printf.c +++ b/stm/printf.c @@ -247,7 +247,9 @@ void stdout_print_strn(void *data, const char *str, unsigned int len) { any = true; } if (!any) { +#if MICROPY_HW_HAS_LCD lcd_print_strn(str, len); +#endif } } @@ -8,8 +8,20 @@ #include "rtc.h" void rtc_init(void) { - uint32_t rtc_clksrc; - uint32_t timeout = 1000000; + /* Enable the PWR clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); + + /* Allow access to RTC */ + PWR_BackupAccessCmd(ENABLE); + + if (RTC_ReadBackupRegister(RTC_BKP_DR0) == 0x32F2) { + // RTC still alive, so don't re-init it + // wait for RTC APB register synchronisation + RTC_WaitForSynchro(); + return; + } + + uint32_t timeout = 10000000; /* Enable the PWR clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); @@ -26,7 +38,10 @@ void rtc_init(void) { /* If LSE timed out, use LSI instead */ if (timeout == 0) { - /* Enable the LSI OSC */ + // Disable the LSE OSC + RCC_LSEConfig(RCC_LSE_OFF); + + // Enable the LSI OSC RCC_LSICmd(ENABLE); /* Wait till LSI is ready */ @@ -34,15 +49,12 @@ void rtc_init(void) { } /* Use LSI as the RTC Clock Source */ - rtc_clksrc = RCC_RTCCLKSource_LSI; + RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); } else { /* Use LSE as the RTC Clock Source */ - rtc_clksrc = RCC_RTCCLKSource_LSE; + RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); } - /* Select the RTC Clock Source */ - RCC_RTCCLKConfig(rtc_clksrc); - /* Note: LSI is around (32KHz), these dividers should work either way */ /* ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/ uint32_t uwSynchPrediv = 0xFF; @@ -78,7 +90,7 @@ void rtc_init(void) { RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure); // Indicator for the RTC configuration - //RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2); + RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2); } /******************************************************************************/ diff --git a/stm/stm32f405.ld b/stm/stm32f405.ld index fbfc584f9d..6c29a681ce 100644 --- a/stm/stm32f405.ld +++ b/stm/stm32f405.ld @@ -19,6 +19,10 @@ _minimum_heap_size = 16K; /* top end of the stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); +/* RAM extents for the garbage collector */ +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_end = 0x2001c000; /* tunable */ + /* define output sections */ SECTIONS { diff --git a/tests/basics/array1.py b/tests/basics/array1.py new file mode 100644 index 0000000000..6f70fdb911 --- /dev/null +++ b/tests/basics/array1.py @@ -0,0 +1,13 @@ +import array + +a = array.array('B', [1, 2, 3]) +print(a, len(a)) +i = array.array('I', [1, 2, 3]) +print(i, len(i)) +print(a[0]) +print(i[-1]) + +# Empty arrays +print(len(array.array('h'))) +print(array.array('i')) + diff --git a/tests/basics/bytearray1.py b/tests/basics/bytearray1.py index 3658713fa8..3111832f6c 100644 --- a/tests/basics/bytearray1.py +++ b/tests/basics/bytearray1.py @@ -1,6 +1,7 @@ a = bytearray([1, 2, 200]) print(a[0], a[2]) print(a[-1]) +print(a) a[2] = 255 print(a[-1]) a.append(10) diff --git a/tests/basics/unary_op.py b/tests/basics/unary_op.py new file mode 100644 index 0000000000..9846285d55 --- /dev/null +++ b/tests/basics/unary_op.py @@ -0,0 +1,12 @@ +print(not None) +print(not False) +print(not True) +print(not 0) +print(not 1) +print(not -1) +print(not ()) +print(not (1,)) +print(not []) +print(not [1,]) +print(not {}) +print(not {1:1}) diff --git a/unix/Makefile b/unix/Makefile index 75825b7c4c..db01ccf9af 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -11,7 +11,8 @@ include ../py/py.mk # compiler settings CFLAGS = -I. -I$(PY_SRC) -Wall -Werror -ansi -std=gnu99 -DUNIX -LDFLAGS = -lm +CFLAGS += -I/usr/lib/libffi-3.0.13/include +LDFLAGS = -lm -ldl -lffi # Debugging/Optimization ifdef DEBUG @@ -25,6 +26,7 @@ SRC_C = \ main.c \ file.c \ socket.c \ + ffi.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) LIB = -lreadline diff --git a/unix/ffi.c b/unix/ffi.c new file mode 100644 index 0000000000..b40e9a4ee6 --- /dev/null +++ b/unix/ffi.c @@ -0,0 +1,330 @@ +#include <assert.h> +#include <string.h> +#include <errno.h> +#include <dlfcn.h> +#include <ffi.h> + +#include "nlr.h" +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" + +typedef struct _mp_obj_opaque_t { + mp_obj_base_t base; + void *val; +} mp_obj_opaque_t; + +typedef struct _mp_obj_ffimod_t { + mp_obj_base_t base; + void *handle; +} mp_obj_ffimod_t; + +typedef struct _mp_obj_ffivar_t { + mp_obj_base_t base; + void *var; + char type; +// ffi_type *type; +} mp_obj_ffivar_t; + +typedef struct _mp_obj_ffifunc_t { + mp_obj_base_t base; + void *func; + char rettype; + ffi_cif cif; + ffi_type *params[]; +} mp_obj_ffifunc_t; + +typedef struct _mp_obj_fficallback_t { + mp_obj_base_t base; + void *func; + ffi_closure *clo; + char rettype; + ffi_cif cif; + ffi_type *params[]; +} mp_obj_fficallback_t; + +static const mp_obj_type_t opaque_type; +static const mp_obj_type_t ffimod_type; +static const mp_obj_type_t ffifunc_type; +static const mp_obj_type_t fficallback_type; +static const mp_obj_type_t ffivar_type; + +static ffi_type *char2ffi_type(char c) +{ + switch (c) { + case 'b': return &ffi_type_schar; + case 'B': return &ffi_type_uchar; + 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 'p': + case 's': return &ffi_type_pointer; + case 'v': return &ffi_type_void; + default: return NULL; + } +} + +static ffi_type *get_ffi_type(mp_obj_t o_in) +{ + if (MP_OBJ_IS_STR(o_in)) { + uint len; + const byte *s = mp_obj_str_get_data(o_in, &len); + ffi_type *t = char2ffi_type(*s); + if (t != NULL) { + return t; + } + } + // TODO: Support actual libffi type objects + + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Unknown type")); +} + +static mp_obj_t return_ffi_value(ffi_arg val, char type) +{ + switch (type) { + case 's': { + const char *s = (const char *)val; + return mp_obj_new_str((const byte *)s, strlen(s), false); + } + case 'v': + return mp_const_none; + default: + return mp_obj_new_int(val); + } +} + +// FFI module + +static void ffimod_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_ffimod_t *self = self_in; + print(env, "<ffimod %p>", self->handle); +} + +static mp_obj_t ffimod_close(mp_obj_t self_in) { + mp_obj_ffimod_t *self = self_in; + dlclose(self->handle); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(ffimod_close_obj, ffimod_close); + +static mp_obj_t ffimod_func(uint n_args, const mp_obj_t *args) { + mp_obj_ffimod_t *self = args[0]; + const char *rettype = mp_obj_str_get_str(args[1]); + const char *symname = mp_obj_str_get_str(args[2]); + + void *sym = dlsym(self->handle, symname); + if (sym == NULL) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno)); + } + int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(args[3])); + mp_obj_ffifunc_t *o = m_new_obj_var(mp_obj_ffifunc_t, ffi_type*, nparams); + o->base.type = &ffifunc_type; + + o->func = sym; + o->rettype = *rettype; + + mp_obj_t iterable = rt_getiter(args[3]); + mp_obj_t item; + int i = 0; + while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) { + o->params[i++] = get_ffi_type(item); + } + + int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); + if (res != FFI_OK) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Error in ffi_prep_cif")); + } + + return o; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ffimod_func_obj, 4, 4, ffimod_func); + +static void call_py_func(ffi_cif *cif, void *ret, void** args, mp_obj_t func) { + mp_obj_t pyargs[cif->nargs]; + for (int i = 0; i < cif->nargs; i++) { + pyargs[i] = mp_obj_new_int(*(int*)args[i]); + } + mp_obj_t res = rt_call_function_n_kw(func, cif->nargs, 0, pyargs); + + *(ffi_arg*)ret = mp_obj_int_get(res); +} + +static mp_obj_t mod_ffi_callback(mp_obj_t rettype_in, mp_obj_t func_in, mp_obj_t paramtypes_in) { + const char *rettype = mp_obj_str_get_str(rettype_in); + + int nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in)); + mp_obj_fficallback_t *o = m_new_obj_var(mp_obj_fficallback_t, ffi_type*, nparams); + o->base.type = &fficallback_type; + + o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func); + + o->rettype = *rettype; + + mp_obj_t iterable = rt_getiter(paramtypes_in); + mp_obj_t item; + int i = 0; + while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) { + o->params[i++] = get_ffi_type(item); + } + + int res = ffi_prep_cif(&o->cif, FFI_DEFAULT_ABI, nparams, char2ffi_type(*rettype), o->params); + if (res != FFI_OK) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "Error in ffi_prep_cif")); + } + + res = ffi_prep_closure_loc(o->clo, &o->cif, call_py_func, func_in, o->func); + if (res != FFI_OK) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "ffi_prep_closure_loc")); + } + + return o; +} +MP_DEFINE_CONST_FUN_OBJ_3(mod_ffi_callback_obj, mod_ffi_callback); + +static mp_obj_t ffimod_var(mp_obj_t self_in, mp_obj_t vartype_in, mp_obj_t symname_in) { + mp_obj_ffimod_t *self = self_in; + const char *rettype = mp_obj_str_get_str(vartype_in); + const char *symname = mp_obj_str_get_str(symname_in); + + void *sym = dlsym(self->handle, symname); + if (sym == NULL) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno)); + } + mp_obj_ffivar_t *o = m_new_obj(mp_obj_ffivar_t); + o->base.type = &ffivar_type; + + o->var = sym; + o->type = *rettype; + return o; +} +MP_DEFINE_CONST_FUN_OBJ_3(ffimod_var_obj, ffimod_var); + +static mp_obj_t ffimod_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { + const char *fname = mp_obj_str_get_str(args[0]); + void *mod = dlopen(fname, RTLD_NOW | RTLD_LOCAL); + + if (mod == NULL) { + nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_OSError, "[Errno %d]", errno)); + } + mp_obj_ffimod_t *o = m_new_obj(mp_obj_ffimod_t); + o->base.type = type_in; + o->handle = mod; + return o; +} + +static const mp_method_t ffimod_type_methods[] = { + { "func", &ffimod_func_obj }, + { "var", &ffimod_var_obj }, + { "close", &ffimod_close_obj }, + { NULL, NULL }, +}; + +static const mp_obj_type_t ffimod_type = { + { &mp_const_type }, + "ffimod", + .print = ffimod_print, + .make_new = ffimod_make_new, + .methods = ffimod_type_methods, +}; + +// FFI function + +static void ffifunc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_ffifunc_t *self = self_in; + print(env, "<ffifunc %p>", self->func); +} + +mp_obj_t ffifunc_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { + mp_obj_ffifunc_t *self = self_in; + assert(n_kw == 0); + assert(n_args == self->cif.nargs); + + ffi_arg values[n_args]; + void *valueptrs[n_args]; + int i; + for (i = 0; i < n_args; i++) { + mp_obj_t a = args[i]; + if (a == mp_const_none) { + values[i] = 0; + } else if (MP_OBJ_IS_INT(a)) { + values[i] = mp_obj_int_get(a); + } else if (MP_OBJ_IS_STR(a) || MP_OBJ_IS_TYPE(a, &bytes_type)) { + const char *s = mp_obj_str_get_str(a); + values[i] = (ffi_arg)s; + } else if (MP_OBJ_IS_TYPE(a, &fficallback_type)) { + mp_obj_fficallback_t *p = a; + values[i] = (ffi_arg)p->func; + } else { + assert(0); + } + valueptrs[i] = &values[i]; + } + + ffi_arg retval; + ffi_call(&self->cif, self->func, &retval, valueptrs); + return return_ffi_value(retval, self->rettype); +} + +static const mp_obj_type_t ffifunc_type = { + { &mp_const_type }, + "ffifunc", + .print = ffifunc_print, + .call = ffifunc_call, +}; + +// FFI callback for Python function + +static void fficallback_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_fficallback_t *self = self_in; + print(env, "<fficallback %p>", self->func); +} + +static const mp_obj_type_t fficallback_type = { + { &mp_const_type }, + "fficallback", + .print = fficallback_print, +}; + +// FFI variable + +static void ffivar_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_ffivar_t *self = self_in; + print(env, "<ffivar @%p: 0x%x>", self->var, *(int*)self->var); +} + +static const mp_obj_type_t ffivar_type = { + { &mp_const_type }, + "ffivar", + .print = ffivar_print, +}; + +// Generic opaque storage object + +static const mp_obj_type_t opaque_type = { + { &mp_const_type }, + "opaqueval", +// .print = opaque_print, +}; + + +mp_obj_t mod_ffi_open(uint n_args, const mp_obj_t *args) { + return ffimod_make_new((mp_obj_t)&ffimod_type, n_args, 0, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_ffi_open_obj, 1, 2, mod_ffi_open); + +mp_obj_t mod_ffi_as_bytearray(mp_obj_t ptr, mp_obj_t size) { + return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr)); +} +MP_DEFINE_CONST_FUN_OBJ_2(mod_ffi_as_bytearray_obj, mod_ffi_as_bytearray); + + +void ffi_init() { + mp_obj_t m = mp_obj_new_module(QSTR_FROM_STR_STATIC("ffi")); + rt_store_attr(m, MP_QSTR_open, (mp_obj_t)&mod_ffi_open_obj); + rt_store_attr(m, QSTR_FROM_STR_STATIC("callback"), (mp_obj_t)&mod_ffi_callback_obj); + // there would be as_bytes, but bytes currently is value, not reference type! + rt_store_attr(m, QSTR_FROM_STR_STATIC("as_bytearray"), (mp_obj_t)&mod_ffi_as_bytearray_obj); +} diff --git a/unix/main.c b/unix/main.c index 212bbe877e..cd45e3be86 100644 --- a/unix/main.c +++ b/unix/main.c @@ -24,6 +24,7 @@ extern const mp_obj_fun_native_t mp_builtin_open_obj; void file_init(); void rawsocket_init(); +void ffi_init(); static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { if (lex == NULL) { @@ -215,6 +216,18 @@ int usage(void) { return 1; } +mp_obj_t mem_info(void) { + printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated()); + return mp_const_none; +} + +mp_obj_t qstr_info(void) { + 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 pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + return mp_const_none; +} + int main(int argc, char **argv) { qstr_init(); rt_init(); @@ -224,9 +237,12 @@ int main(int argc, char **argv) { rt_store_attr(m_sys, MP_QSTR_argv, py_argv); rt_store_name(qstr_from_str("test"), test_obj_new(42)); + rt_store_name(qstr_from_str("mem_info"), rt_make_function_n(0, mem_info)); + rt_store_name(qstr_from_str("qstr_info"), rt_make_function_n(0, qstr_info)); file_init(); rawsocket_init(); + ffi_init(); // Here is some example code to create a class and instance of that class. // First is the Python, then the C code. diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 10abb8ce75..5eba0df613 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -12,6 +12,7 @@ #define MICROPY_DEBUG_PRINTERS (1) #define MICROPY_ENABLE_REPL_HELPERS (1) #define MICROPY_ENABLE_LEXER_UNIX (1) +#define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_ENABLE_FLOAT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) |