diff options
-rw-r--r-- | py/builtin.h | 1 | ||||
-rw-r--r-- | py/builtintables.c | 3 | ||||
-rw-r--r-- | py/mkenv.mk | 2 | ||||
-rw-r--r-- | py/modcmath.c | 131 | ||||
-rw-r--r-- | py/modmath.c | 9 | ||||
-rw-r--r-- | py/mpconfig.h | 12 | ||||
-rw-r--r-- | py/nlr.h | 20 | ||||
-rw-r--r-- | py/nlrsetjmp.c | 16 | ||||
-rw-r--r-- | py/py.mk | 2 | ||||
-rw-r--r-- | py/qstrdefs.h | 9 | ||||
-rw-r--r-- | py/runtime.c | 5 | ||||
-rw-r--r-- | py/vm.c | 66 | ||||
-rw-r--r-- | stmhal/Makefile | 2 | ||||
-rw-r--r-- | stmhal/flash.c | 77 | ||||
-rw-r--r-- | stmhal/flash.h | 1 | ||||
-rw-r--r-- | stmhal/main.c | 36 | ||||
-rw-r--r-- | stmhal/malloc0.c | 37 | ||||
-rw-r--r-- | stmhal/math.c | 81 | ||||
-rw-r--r-- | stmhal/mathsincos.c | 601 | ||||
-rw-r--r-- | stmhal/pybstdio.c | 4 | ||||
-rw-r--r-- | stmhal/pyexec.c | 1 | ||||
-rw-r--r-- | stmhal/std.h | 2 | ||||
-rw-r--r-- | stmhal/stm32f4xx_it.c | 48 | ||||
-rw-r--r-- | stmhal/storage.c | 77 | ||||
-rw-r--r-- | stmhal/storage.h | 2 | ||||
-rw-r--r-- | stmhal/timer.c | 15 | ||||
-rw-r--r-- | stmhal/usbd_cdc_interface.c | 26 | ||||
-rw-r--r-- | stmhal/usbd_desc_cdc_msc.c | 18 | ||||
-rw-r--r-- | stmhal/usbd_msc_storage.c | 16 | ||||
-rw-r--r-- | stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h | 6 | ||||
-rw-r--r-- | stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c | 3 | ||||
-rw-r--r-- | stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c | 1 | ||||
-rw-r--r-- | tests/README | 4 | ||||
-rw-r--r-- | tests/basics/fun-callstar.py | 2 | ||||
-rw-r--r-- | tests/basics/fun-defargs.py | 2 | ||||
-rw-r--r-- | tests/basics/int-divzero.py | 5 | ||||
-rw-r--r-- | tests/basics/list1.py | 5 | ||||
-rw-r--r-- | tests/basics/modulo.py | 17 | ||||
-rw-r--r-- | tests/basics/string-format-modulo.py | 14 | ||||
-rw-r--r-- | tests/basics/string-format.py | 87 | ||||
-rw-r--r-- | tests/basics/true-value.py | 6 | ||||
-rw-r--r-- | tests/basics/types1.py | 6 | ||||
-rw-r--r-- | tests/basics/types2.py | 4 | ||||
-rw-r--r-- | tests/float/float1.py (renamed from tests/basics/float1.py) | 0 | ||||
-rw-r--r-- | tests/float/int-divzero.py | 4 | ||||
-rw-r--r-- | tests/float/list-index.py | 8 | ||||
-rw-r--r-- | tests/float/math-fun-bool.py (renamed from tests/basics/math-fun-bool.py) | 0 | ||||
-rw-r--r-- | tests/float/math-fun.py (renamed from tests/basics/math-fun.py) | 0 | ||||
-rw-r--r-- | tests/float/modulo.py | 14 | ||||
-rw-r--r-- | tests/float/string-format-modulo.py | 16 | ||||
-rw-r--r-- | tests/float/string-format.py | 123 | ||||
-rw-r--r-- | tests/float/true-value.py | 7 | ||||
-rw-r--r-- | tests/float/types.py | 17 | ||||
-rw-r--r-- | tests/import/import-pkg1.py (renamed from tests/basics/import-pkg1.py) | 0 | ||||
-rw-r--r-- | tests/import/import-pkg2.py (renamed from tests/basics/import-pkg2.py) | 0 | ||||
-rw-r--r-- | tests/import/import-pkg3.py (renamed from tests/basics/import-pkg3.py) | 0 | ||||
-rw-r--r-- | tests/import/import-pkg4.py (renamed from tests/basics/import-pkg4.py) | 0 | ||||
-rw-r--r-- | tests/import/import-pkg5.py (renamed from tests/basics/import-pkg5.py) | 0 | ||||
-rw-r--r-- | tests/import/import1a.py (renamed from tests/basics/import1a.py) | 0 | ||||
-rw-r--r-- | tests/import/import1b.py (renamed from tests/basics/import1b.py) | 0 | ||||
-rw-r--r-- | tests/import/import2a.py (renamed from tests/basics/import2a.py) | 0 | ||||
-rw-r--r-- | tests/import/import3a.py (renamed from tests/basics/import3a.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg/__init__.py (renamed from tests/basics/pkg/__init__.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg/mod.py (renamed from tests/basics/pkg/mod.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg2/__init__.py (renamed from tests/basics/pkg2/__init__.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg2/mod1.py (renamed from tests/basics/pkg2/mod1.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg2/mod2.py (renamed from tests/basics/pkg2/mod2.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg3/__init__.py (renamed from tests/basics/pkg3/__init__.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg3/mod1.py (renamed from tests/basics/pkg3/mod1.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg3/mod2.py (renamed from tests/basics/pkg3/mod2.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg3/subpkg1/__init__.py (renamed from tests/basics/pkg3/subpkg1/__init__.py) | 0 | ||||
-rw-r--r-- | tests/import/pkg3/subpkg1/mod1.py (renamed from tests/basics/pkg3/subpkg1/mod1.py) | 0 | ||||
-rw-r--r-- | tests/import/try-module.py (renamed from tests/basics/try-module.py) | 0 | ||||
-rwxr-xr-x | tests/run-tests | 19 | ||||
-rw-r--r-- | unix/Makefile | 5 | ||||
-rw-r--r-- | unix/modffi.c | 10 | ||||
-rw-r--r-- | unix/mpconfigport.h | 2 |
77 files changed, 1394 insertions, 313 deletions
diff --git a/py/builtin.h b/py/builtin.h index 36b9f38814..9b2b9c9424 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -48,6 +48,7 @@ extern const mp_obj_module_t mp_module_array; extern const mp_obj_module_t mp_module_collections; extern const mp_obj_module_t mp_module_io; extern const mp_obj_module_t mp_module_math; +extern const mp_obj_module_t mp_module_cmath; extern const mp_obj_module_t mp_module_micropython; extern const mp_obj_module_t mp_module_struct; extern const mp_obj_module_t mp_module_sys; diff --git a/py/builtintables.c b/py/builtintables.c index 6bdae24002..c4c96ed35a 100644 --- a/py/builtintables.c +++ b/py/builtintables.c @@ -139,6 +139,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = { #if MICROPY_ENABLE_FLOAT { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&mp_module_math }, +#if MICROPY_ENABLE_MOD_CMATH + { MP_OBJ_NEW_QSTR(MP_QSTR_cmath), (mp_obj_t)&mp_module_cmath }, +#endif #endif #if MICROPY_ENABLE_MOD_SYS { MP_OBJ_NEW_QSTR(MP_QSTR_sys), (mp_obj_t)&mp_module_sys }, diff --git a/py/mkenv.mk b/py/mkenv.mk index 8ae54f06bb..4bc71edd78 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -54,4 +54,6 @@ STRIP = $(CROSS_COMPILE)strip all: .PHONY: all +.DELETE_ON_ERROR: + MKENV_INCLUDED = 1 diff --git a/py/modcmath.c b/py/modcmath.c new file mode 100644 index 0000000000..3f561e7f30 --- /dev/null +++ b/py/modcmath.c @@ -0,0 +1,131 @@ +#include <math.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "builtin.h" + +#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH + +// These are defined in modmath.c +extern const mp_obj_float_t mp_math_e_obj; +extern const mp_obj_float_t mp_math_pi_obj; + +mp_obj_t mp_cmath_phase(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase); + +mp_obj_t mp_cmath_polar(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_obj_t tuple[2] = { + mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag)), + mp_obj_new_float(MICROPY_FLOAT_C_FUN(atan2)(imag, real)), + }; + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar); + +mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) { + mp_float_t r = mp_obj_get_float(r_obj); + mp_float_t phi = mp_obj_get_float(phi_obj); + return mp_obj_new_complex(r * MICROPY_FLOAT_C_FUN(cos)(phi), r * MICROPY_FLOAT_C_FUN(sin)(phi)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect); + +mp_obj_t mp_cmath_exp(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_float_t exp_real = MICROPY_FLOAT_C_FUN(exp)(real); + return mp_obj_new_complex(exp_real * MICROPY_FLOAT_C_FUN(cos)(imag), exp_real * MICROPY_FLOAT_C_FUN(sin)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp); + +// TODO can take second argument, being the base +mp_obj_t mp_cmath_log(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real*real + imag*imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log); + +mp_obj_t mp_cmath_log10(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real*real + imag*imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10); + +mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real*real + imag*imag, 0.25); + mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real); + return mp_obj_new_complex(sqrt_abs * cos(theta), sqrt_abs * sin(theta)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt); + +mp_obj_t mp_cmath_cos(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), -MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos); + +mp_obj_t mp_cmath_sin(mp_obj_t z_obj) { + mp_float_t real, imag; + mp_obj_get_complex(z_obj, &real, &imag); + return mp_obj_new_complex(MICROPY_FLOAT_C_FUN(sin)(real) * MICROPY_FLOAT_C_FUN(cosh)(imag), MICROPY_FLOAT_C_FUN(cos)(real) * MICROPY_FLOAT_C_FUN(sinh)(imag)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sin_obj, mp_cmath_sin); + +STATIC const mp_map_elem_t mp_module_cmath_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_cmath) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_e), (mp_obj_t)&mp_math_e_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_pi), (mp_obj_t)&mp_math_pi_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_phase), (mp_obj_t)&mp_cmath_phase_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_polar), (mp_obj_t)&mp_cmath_polar_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_rect), (mp_obj_t)&mp_cmath_rect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&mp_cmath_exp_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&mp_cmath_log_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&mp_cmath_log10_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&mp_cmath_sqrt_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&mp_cmath_acos_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&mp_cmath_asin_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&mp_cmath_atan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&mp_cmath_cos_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&mp_cmath_sin_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&mp_cmath_tan_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&mp_cmath_acosh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&mp_cmath_asinh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&mp_cmath_atanh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_cosh), (mp_obj_t)&mp_cmath_cosh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&mp_cmath_sinh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&mp_cmath_tanh_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&mp_cmath_isfinite_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&mp_cmath_isinf_obj }, + //{ MP_OBJ_NEW_QSTR(MP_QSTR_isnan), (mp_obj_t)&mp_cmath_isnan_obj }, +}; + +STATIC const mp_obj_dict_t mp_module_cmath_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = sizeof(mp_module_cmath_globals_table) / sizeof(mp_map_elem_t), + .alloc = sizeof(mp_module_cmath_globals_table) / sizeof(mp_map_elem_t), + .table = (mp_map_elem_t*)mp_module_cmath_globals_table, + }, +}; + +const mp_obj_module_t mp_module_cmath = { + .base = { &mp_type_module }, + .name = MP_QSTR_cmath, + .globals = (mp_obj_dict_t*)&mp_module_cmath_globals, +}; + +#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH diff --git a/py/modmath.c b/py/modmath.c index c26ba16189..09bb4ce3aa 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -6,7 +6,7 @@ #include "obj.h" #include "builtin.h" -#if MICROPY_ENABLE_FLOAT +#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH //TODO: Change macros to check for overflow and raise OverflowError or RangeError #define MATH_FUN_1(py_name, c_name) \ @@ -25,8 +25,9 @@ mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int((machine_int_t)MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name); -STATIC const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E}; -STATIC const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI}; +// These are also used by cmath.c +const mp_obj_float_t mp_math_e_obj = {{&mp_type_float}, M_E}; +const mp_obj_float_t mp_math_pi_obj = {{&mp_type_float}, M_PI}; MATH_FUN_1(sqrt, sqrt) MATH_FUN_2(pow, pow) @@ -156,4 +157,4 @@ const mp_obj_module_t mp_module_math = { .globals = (mp_obj_dict_t*)&mp_module_math_globals, }; -#endif // MICROPY_ENABLE_FLOAT +#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_MATH diff --git a/py/mpconfig.h b/py/mpconfig.h index 7fd7067953..43c931cd66 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -110,6 +110,16 @@ typedef double mp_float_t; #define MICROPY_ENABLE_FLOAT (0) #endif +// Whether to provide "math" module +#ifndef MICROPY_ENABLE_MOD_MATH +#define MICROPY_ENABLE_MOD_MATH (1) +#endif + +// Whether to provide "cmath" module +#ifndef MICROPY_ENABLE_MOD_CMATH +#define MICROPY_ENABLE_MOD_CMATH (0) +#endif + // Whether to provide "io" module #ifndef MICROPY_ENABLE_MOD_IO #define MICROPY_ENABLE_MOD_IO (1) @@ -137,7 +147,7 @@ typedef double mp_float_t; // Whether to support the property object #ifndef MICROPY_ENABLE_PROPERTY -#define MICROPY_ENABLE_PROPERTY (0) +#define MICROPY_ENABLE_PROPERTY (1) #endif // Enable features which improve CPython compatibility @@ -2,12 +2,14 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include <limits.h> +#include <setjmp.h> typedef struct _nlr_buf_t nlr_buf_t; struct _nlr_buf_t { // the entries here must all be machine word size nlr_buf_t *prev; void *ret_val; +#if !MICROPY_NLR_SETJMP #if defined(__i386__) void *regs[6]; #elif defined(__x86_64__) @@ -19,13 +21,29 @@ struct _nlr_buf_t { #elif defined(__thumb2__) void *regs[10]; #else -#error Unknown arch in nlr.h + #define MICROPY_NLR_SETJMP (1) + #warning "No native NLR support for this arch, using setjmp implementation" +#endif +#endif + +#if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; #endif }; +#if MICROPY_NLR_SETJMP +extern nlr_buf_t *nlr_setjmp_top; +void nlr_setjmp_jump(void *val) __attribute__((noreturn)); +// nlr_push() must be defined as a macro, because "The stack context will be +// invalidated if the function which called setjmp() returns." +#define nlr_push(buf) ((buf)->prev = nlr_setjmp_top, nlr_setjmp_top = (buf), setjmp((buf)->jmpbuf)) +#define nlr_pop() { nlr_setjmp_top = nlr_setjmp_top->prev; } +#define nlr_jump(val) nlr_setjmp_jump(val) +#else unsigned int nlr_push(nlr_buf_t *); void nlr_pop(void); void nlr_jump(void *val) __attribute__((noreturn)); +#endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c new file mode 100644 index 0000000000..a97c8634b2 --- /dev/null +++ b/py/nlrsetjmp.c @@ -0,0 +1,16 @@ +#include <setjmp.h> +#include <stdio.h> +#include "nlr.h" + +#if MICROPY_NLR_SETJMP + +nlr_buf_t *nlr_setjmp_top; + +void nlr_setjmp_jump(void *val) { + nlr_buf_t *buf = nlr_setjmp_top; + nlr_setjmp_top = buf->prev; + buf->ret_val = val; + longjmp(buf->jmpbuf, 1); +} + +#endif @@ -15,6 +15,7 @@ PY_O_BASENAME = \ nlrx86.o \ nlrx64.o \ nlrthumb.o \ + nlrsetjmp.o \ malloc.o \ gc.o \ qstr.o \ @@ -87,6 +88,7 @@ PY_O_BASENAME = \ modcollections.o \ modio.o \ modmath.o \ + modcmath.o \ modmicropython.o \ modstruct.o \ modsys.o \ diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 20c4db75f0..a4df86fda7 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -217,6 +217,7 @@ Q(iterator) Q(module) Q(slice) +#if MICROPY_ENABLE_MOD_MATH || MICROPY_ENABLE_MOD_CMATH Q(math) Q(e) Q(pi) @@ -258,6 +259,14 @@ Q(erf) Q(erfc) Q(gamma) Q(lgamma) +#endif + +#if MICROPY_ENABLE_MOD_CMATH +Q(cmath) +Q(phase) +Q(polar) +Q(rect) +#endif Q(mem_total) Q(mem_current) diff --git a/py/runtime.c b/py/runtime.c index a507f97f36..98b2d076ec 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -365,7 +365,8 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break; case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); break; - default: assert(0); + default: + goto unsupported_op; } // TODO: We just should make mp_obj_new_int() inline and use that if (MP_OBJ_FITS_SMALL_INT(lhs_val)) { @@ -437,9 +438,7 @@ generic_binary_op: // TODO implement dispatch for reverse binary ops // TODO specify in error message what the operator is -#if MICROPY_ENABLE_FLOAT unsupported_op: -#endif nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand types for binary operator: '%s', '%s'", mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs))); @@ -165,8 +165,6 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, 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_GOTOS #include "vmentrytable.h" #define DISPATCH() do { \ @@ -182,32 +180,43 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i #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; - qstr qst; - mp_obj_t obj1, obj2; - nlr_buf_t nlr; + // nlr_raise needs to be implemented as a goto, so that the C compiler's flow analyser + // sees that it's possible for us to jump from the dispatch loop to the exception + // handler. Without this, the code may have a different stack layout in the dispatch + // loop and the exception handler, leading to very obscure bugs. + #define RAISE(o) do { nlr_pop(); nlr.ret_val = o; goto exception_handler; } while(0) + // variables that are visible to the exception handler (declared volatile) volatile bool currently_in_except_block = MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(*exc_sp_in_out); // 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) + const byte *volatile save_ip = *ip_in_out; // 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) + mp_obj_t *volatile save_sp = *sp_in_out; // this is so we can access sp in the exception handler when needed // outer exception handling loop for (;;) { + nlr_buf_t nlr; outer_dispatch_loop: if (nlr_push(&nlr) == 0) { + // local variables that are not visible to the exception handler + byte op = 0; + const byte *ip = *ip_in_out; + mp_obj_t *sp = *sp_in_out; + machine_uint_t unum; + qstr qst; + mp_obj_t obj1, obj2; + // If we have exception to inject, now that we finish setting up // execution context, raise it. This works as if RAISE_VARARGS // bytecode was executed. // Injecting exc into yield from generator is a special case, // handled by MP_BC_YIELD_FROM itself if (inject_exc != MP_OBJ_NULL && *ip != MP_BC_YIELD_FROM) { - mp_obj_t t = inject_exc; + obj1 = inject_exc; inject_exc = MP_OBJ_NULL; - nlr_raise(mp_make_raise_obj(t)); + obj1 = mp_make_raise_obj(obj1); + RAISE(obj1); } + // loop to execute byte code for (;;) { dispatch_loop: @@ -297,7 +306,8 @@ dispatch_loop: 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")); + obj1 = mp_obj_new_exception_msg(&mp_type_NameError, "local variable referenced before assignment"); + RAISE(obj1); } PUSH(obj1); DISPATCH(); @@ -580,7 +590,7 @@ unwind_jump: // if TOS is an integer, does something else // else error if (mp_obj_is_exception_type(TOP())) { - nlr_raise(sp[-1]); + RAISE(sp[-1]); } if (TOP() == mp_const_none) { sp--; @@ -606,6 +616,7 @@ unwind_jump: ENTRY(MP_BC_FOR_ITER): DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward + save_sp = sp; obj1 = mp_iternext_allow_raise(TOP()); if (obj1 == MP_OBJ_NULL) { --sp; // pop the exhausted iterator @@ -829,12 +840,14 @@ unwind_return: } } if (obj1 == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise")); + obj1 = mp_obj_new_exception_msg(&mp_type_RuntimeError, "No active exception to reraise"); + RAISE(obj1); } } else { obj1 = POP(); } - nlr_raise(mp_make_raise_obj(obj1)); + obj1 = mp_make_raise_obj(obj1); + RAISE(obj1); ENTRY(MP_BC_YIELD_VALUE): yield: @@ -847,7 +860,7 @@ yield: 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); } +#define GENERATOR_EXIT_IF_NEEDED(t) if (t != MP_OBJ_NULL && EXC_MATCH(t, &mp_type_GeneratorExit)) { RAISE(t); } mp_vm_return_kind_t ret_kind; obj1 = POP(); mp_obj_t t_exc = MP_OBJ_NULL; @@ -890,7 +903,7 @@ yield: GENERATOR_EXIT_IF_NEEDED(t_exc); DISPATCH(); } else { - nlr_raise(obj2); + RAISE(obj2); } } } @@ -912,25 +925,27 @@ yield: 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_GOTOS } // switch #endif - } + } // for loop } else { +exception_handler: // exception occurred // check if it's a StopIteration within a for block if (*save_ip == MP_BC_FOR_ITER && mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) { - ip = save_ip + 1; + const byte *ip = save_ip + 1; + machine_uint_t unum; DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward - --sp; // pop the exhausted iterator - ip += unum; // jump to after for-block + *ip_in_out = ip + unum; // jump to after for-block + *sp_in_out = save_sp - 1; // pop the exhausted iterator goto outer_dispatch_loop; // continue with dispatch loop } @@ -969,14 +984,15 @@ yield: currently_in_except_block = 1; // catch exception and pass to byte code - sp = MP_TAGPTR_PTR(exc_sp->val_sp); - ip = exc_sp->handler; + *ip_in_out = exc_sp->handler; + mp_obj_t *sp = MP_TAGPTR_PTR(exc_sp->val_sp); // save this exception in the stack so it can be used in a reraise, if needed exc_sp->prev_exc = nlr.ret_val; // push(traceback, exc-val, exc-type) PUSH(mp_const_none); PUSH(nlr.ret_val); PUSH(mp_obj_get_type(nlr.ret_val)); + *sp_in_out = sp; } else { // propagate exception to higher level diff --git a/stmhal/Makefile b/stmhal/Makefile index aa4f4f3e8d..27caaca016 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -71,7 +71,7 @@ SRC_C = \ usb.c \ printf.c \ math.c \ - malloc0.c \ + mathsincos.c \ gccollect.c \ pybstdio.c \ readline.c \ diff --git a/stmhal/flash.c b/stmhal/flash.c index 6ed3b04324..ce16fe271b 100644 --- a/stmhal/flash.c +++ b/stmhal/flash.c @@ -49,7 +49,81 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *si return 0; } +void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + // check there is something to write + if (num_word32 == 0) { + return; + } + + // unlock + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); + EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; + uint32_t SectorError = 0; + if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { + // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash + return; + } +} + +/* +// erase the sector using an interrupt +void flash_erase_it(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + // check there is something to write + if (num_word32 == 0) { + return; + } + + // unlock + HAL_FLASH_Unlock(); + + // Clear pending flags (if any) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | + FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); + + // erase the sector(s) + FLASH_EraseInitTypeDef EraseInitStruct; + EraseInitStruct.TypeErase = TYPEERASE_SECTORS; + EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V + EraseInitStruct.Sector = flash_get_sector_info(flash_dest, NULL, NULL); + EraseInitStruct.NbSectors = flash_get_sector_info(flash_dest + 4 * num_word32 - 1, NULL, NULL) - EraseInitStruct.Sector + 1; + if (HAL_FLASHEx_Erase_IT(&EraseInitStruct) != HAL_OK) { + // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash + return; + } +} +*/ + void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { + // program the flash word by word + for (int i = 0; i < num_word32; i++) { + if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { + // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash + return; + } + flash_dest += 4; + src += 1; + } + + // lock the flash + HAL_FLASH_Lock(); +} + +/* + use erase, then write +void flash_erase_and_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) { // check there is something to write if (num_word32 == 0) { return; @@ -71,6 +145,7 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) uint32_t SectorError = 0; if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { // error occurred during sector erase + HAL_FLASH_Lock(); // lock the flash return; } @@ -78,6 +153,7 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) for (int i = 0; i < num_word32; i++) { if (HAL_FLASH_Program(TYPEPROGRAM_WORD, flash_dest, *src) != HAL_OK) { // error occurred during flash write + HAL_FLASH_Lock(); // lock the flash return; } flash_dest += 4; @@ -87,3 +163,4 @@ void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32) // lock the flash HAL_FLASH_Lock(); } +*/ diff --git a/stmhal/flash.h b/stmhal/flash.h index 33d31df7a6..7900d2c1ae 100644 --- a/stmhal/flash.h +++ b/stmhal/flash.h @@ -1,2 +1,3 @@ uint32_t flash_get_sector_info(uint32_t addr, uint32_t *start_addr, uint32_t *size); +void flash_erase(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); void flash_write(uint32_t flash_dest, const uint32_t *src, uint32_t num_word32); diff --git a/stmhal/main.c b/stmhal/main.c index c5633fb68b..2d7e76172f 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -1,9 +1,7 @@ #include <stdio.h> #include <string.h> -#include <stm32f4xx_hal.h> -#include <stm32f4xx_hal_gpio.h> -#include "std.h" +#include "stm32f4xx_hal.h" #include "misc.h" #include "systick.h" @@ -14,11 +12,10 @@ #include "lexer.h" #include "parse.h" #include "obj.h" -#include "parsehelper.h" -#include "compile.h" #include "runtime.h" #include "gc.h" #include "gccollect.h" +#include "pybstdio.h" #include "readline.h" #include "pyexec.h" #include "usart.h" @@ -64,12 +61,25 @@ void flash_error(int n) { } void __fatal_error(const char *msg) { -#if MICROPY_HW_HAS_LCD + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + led_state(1, 1); + led_state(2, 1); + led_state(3, 1); + led_state(4, 1); + stdout_tx_strn("\nFATAL ERROR:\n", 14); + stdout_tx_strn(msg, strlen(msg)); +#if 0 && MICROPY_HW_HAS_LCD lcd_print_strn("\nFATAL ERROR:\n", 14); lcd_print_strn(msg, strlen(msg)); #endif - for (;;) { - flash_error(1); + for (uint i = 0;;) { + led_toggle(((i++) & 3) + 1); + for (volatile uint delay = 0; delay < 10000000; delay++) { + } + if (i >= 8) { + __WFI(); + } } } @@ -109,16 +119,6 @@ STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) { MP_DEFINE_CONST_FUN_OBJ_1(pyb_usb_mode_obj, pyb_usb_mode); -void fatality(void) { - led_state(PYB_LED_R1, 1); - led_state(PYB_LED_G1, 1); - led_state(PYB_LED_R2, 1); - led_state(PYB_LED_G2, 1); - for (;;) { - flash_error(1); - } -} - static const char fresh_boot_py[] = "# boot.py -- run on boot-up\n" "# can run arbitrary Python, but best to keep it minimal\n" diff --git a/stmhal/malloc0.c b/stmhal/malloc0.c deleted file mode 100644 index 510fa0d740..0000000000 --- a/stmhal/malloc0.c +++ /dev/null @@ -1,37 +0,0 @@ -#include <stdio.h> -#include <stdint.h> -#include "misc.h" -#include "mpconfig.h" -#include "gc.h" - -#if 0 -static uint32_t mem = 0; - -void *malloc(size_t n) { - if (mem == 0) { - extern uint32_t _heap_start; - mem = (uint32_t)&_heap_start; // need to use big ram block so we can execute code from it (is it true that we can't execute from CCM?) - } - void *ptr = (void*)mem; - mem = (mem + n + 3) & (~3); - if (mem > 0x20000000 + 0x18000) { - void __fatal_error(const char*); - __fatal_error("out of memory"); - } - return ptr; -} - -void free(void *ptr) { -} - -void *realloc(void *ptr, size_t n) { - return malloc(n); -} - -#endif - -void __assert_func(void) { - printf("\nASSERT FAIL!"); - for (;;) { - } -} diff --git a/stmhal/math.c b/stmhal/math.c index 9b815f1180..75a5aeb2ee 100644 --- a/stmhal/math.c +++ b/stmhal/math.c @@ -70,16 +70,11 @@ float tanhf(float x) { return sinhf(x) / coshf(x); } float acoshf(float x) { return 0.0; } float asinhf(float x) { return 0.0; } float atanhf(float x) { return 0.0; } -float cosf(float x) { return 0.0; } -float sinf(float x) { return 0.0; } float tanf(float x) { return 0.0; } float acosf(float x) { return 0.0; } float asinf(float x) { return 0.0; } float atanf(float x) { return 0.0; } float atan2f(float x, float y) { return 0.0; } -float ceilf(float x) { return 0.0; } -float floorf(float x) { return 0.0; } -float truncf(float x) { return 0.0; } float fmodf(float x, float y) { return 0.0; } float tgammaf(float x) { return 0.0; } float lgammaf(float x) { return 0.0; } @@ -820,3 +815,79 @@ float sinhf(float x) t = 2*h*__expo2f(absx); return t; } + +/*****************************************************************************/ +/*****************************************************************************/ +// ceilf, floorf and truncf from musl-0.9.15 +/*****************************************************************************/ +/*****************************************************************************/ + +float ceilf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} + +float floorf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/stmhal/mathsincos.c b/stmhal/mathsincos.c new file mode 100644 index 0000000000..420c8bba10 --- /dev/null +++ b/stmhal/mathsincos.c @@ -0,0 +1,601 @@ +// These math functions are taken from newlib 2.1.0, the newlib/libm directory. + +#include <stdint.h> +#include <math.h> + + +/* @(#)fdlibm.h 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L) + +/* A union which permits us to convert between a float and a 32 bit + int. */ + +typedef union +{ + float value; + __uint32_t word; +} ieee_float_shape_type; + + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + + + +/* kf_rem_pio2.c -- float version of k_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* In the float version, the input parameter x contains 8 bit + integers, not 24 bit integers. 113 bit precision is not supported. */ + +#ifdef __STDC__ +static const int init_jk[] = {4,7,9}; /* initial value for jk */ +#else +static int init_jk[] = {4,7,9}; +#endif + +#ifdef __STDC__ +static const float PIo2[] = { +#else +static float PIo2[] = { +#endif + 1.5703125000e+00, /* 0x3fc90000 */ + 4.5776367188e-04, /* 0x39f00000 */ + 2.5987625122e-05, /* 0x37da0000 */ + 7.5437128544e-08, /* 0x33a20000 */ + 6.0026650317e-11, /* 0x2e840000 */ + 7.3896444519e-13, /* 0x2b500000 */ + 5.3845816694e-15, /* 0x27c20000 */ + 5.6378512969e-18, /* 0x22d00000 */ + 8.3009228831e-20, /* 0x1fc40000 */ + 3.2756352257e-22, /* 0x1bc60000 */ + 6.3331015649e-25, /* 0x17440000 */ +}; + +static const float +zero = 0.0000000000e+00, /* 0x00000000 */ +one = 1.0000000000e+00, /* 0x3f800000 */ +two8 = 2.5600000000e+02, /* 0x43800000 */ +twon8 = 3.9062500000e-03; /* 0x3b800000 */ + +int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2) +{ + __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + float z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/8; if(jv<0) jv=0; + q0 = e0-8*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (float)((__int32_t)(twon8* z)); + iq[i] = (__int32_t)(z-two8*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbnf(z,(int)q0); /* actual value of z */ + z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */ + n = (__int32_t) z; + z -= (float)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(8-q0)); n += i; + iq[jz-1] -= i<<(8-q0); + ih = iq[jz-1]>>(7-q0); + } + else if(q0==0) ih = iq[jz-1]>>8; + else if(z>=(float)0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i<jz ;i++) { /* compute 1-q */ + j = iq[i]; + if(carry==0) { + if(j!=0) { + carry = 1; iq[i] = 0x100- j; + } + } else iq[i] = 0xff - j; + } + if(q0>0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7f; break; + case 2: + iq[jz-1] &= 0x3f; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbnf(one,(int)q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (float) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==(float)0.0) { + jz -= 1; q0 -= 8; + while(iq[jz]==0) { jz--; q0-=8;} + } else { /* break z into 8-bit if necessary */ + z = scalbnf(z,-(int)q0); + if(z>=two8) { + fw = (float)((__int32_t)(twon8*z)); + iq[jz] = (__int32_t)(z-two8*fw); + jz += 1; q0 += 8; + iq[jz] = (__int32_t) fw; + } else iq[jz] = (__int32_t) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbnf(one,(int)q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(float)iq[i]; fw*=twon8; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} + + +/* ef_rem_pio2.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2f() + */ + + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +static const __int32_t two_over_pi[] = { +0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC, +0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62, +0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63, +0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A, +0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09, +0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29, +0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44, +0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41, +0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C, +0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8, +0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11, +0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF, +0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E, +0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5, +0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92, +0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08, +0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0, +0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3, +0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85, +0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80, +0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA, +0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B, +}; + +/* This array is like the one in e_rem_pio2.c, but the numbers are + single precision and the last 8 bits are forced to 0. */ +static const __int32_t npio2_hw[] = { +0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00, +0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00, +0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100, +0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00, +0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00, +0x4242c700, 0x42490f00 +}; + +/* + * invpio2: 24 bits of 2/pi + * pio2_1: first 17 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 17 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 17 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const float +half = 5.0000000000e-01, /* 0x3f000000 */ +invpio2 = 6.3661980629e-01, /* 0x3f22f984 */ +pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */ +pio2_1t = 1.0804334124e-05, /* 0x37354443 */ +pio2_2 = 1.0804273188e-05, /* 0x37354400 */ +pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */ +pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */ +pio2_3t = 6.1232342629e-17; /* 0x248d3132 */ + +__int32_t __ieee754_rem_pio2f(float x, float *y) +{ + float z,w,t,r,fn; + float tx[3]; + __int32_t i,j,n,ix,hx; + int e0,nx; + + GET_FLOAT_WORD(hx,x); + ix = hx&0x7fffffff; + if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 24+24+24 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */ + t = fabsf(x); + n = (__int32_t) (t*invpio2+half); + fn = (float)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 40 bit */ + if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + __uint32_t high; + j = ix>>23; + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>8) { /* 2nd iteration needed, good to 57 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + GET_FLOAT_WORD(high,y[0]); + i = j-((high>>23)&0xff); + if(i>25) { /* 3rd iteration need, 74 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else return n; + } + /* + * all other (large) arguments + */ + if(!FLT_UWORD_IS_FINITE(ix)) { + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-7) */ + e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */ + SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23)); + for(i=0;i<2;i++) { + tx[i] = (float)((__int32_t)(z)); + z = (z-tx[i])*two8; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} + + +/* kf_sin.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +static const float +S1 = -1.6666667163e-01, /* 0xbe2aaaab */ +S2 = 8.3333337680e-03, /* 0x3c088889 */ +S3 = -1.9841270114e-04, /* 0xb9500d01 */ +S4 = 2.7557314297e-06, /* 0x3638ef1b */ +S5 = -2.5050759689e-08, /* 0xb2d72f34 */ +S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */ + +float __kernel_sinf(float x, float y, int iy) /* iy=0 if y is zero */ +{ + float z,r,v; + __int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* high word of x */ + if(ix<0x32000000) /* |x| < 2**-27 */ + {if((int)x==0) return x;} /* generate inexact */ + z = x*x; + v = z*x; + r = S2+z*(S3+z*(S4+z*(S5+z*S6))); + if(iy==0) return x+v*(S1+z*r); + else return x-((z*(half*y-v*r)-y)-v*S1); +} + + + +/* kf_cos.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +static const float +C1 = 4.1666667908e-02, /* 0x3d2aaaab */ +C2 = -1.3888889225e-03, /* 0xbab60b61 */ +C3 = 2.4801587642e-05, /* 0x37d00d01 */ +C4 = -2.7557314297e-07, /* 0xb493f27c */ +C5 = 2.0875723372e-09, /* 0x310f74f6 */ +C6 = -1.1359647598e-11; /* 0xad47d74e */ + +float __kernel_cosf(float x, float y) +{ + float a,hz,z,r,qx; + __int32_t ix; + GET_FLOAT_WORD(ix,x); + ix &= 0x7fffffff; /* ix = |x|'s high word*/ + if(ix<0x32000000) { /* if x < 2**27 */ + if(((int)x)==0) return one; /* generate inexact */ + } + z = x*x; + r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); + if(ix < 0x3e99999a) /* if |x| < 0.3 */ + return one - ((float)0.5*z - (z*r - x*y)); + else { + if(ix > 0x3f480000) { /* x > 0.78125 */ + qx = (float)0.28125; + } else { + SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */ + } + hz = (float)0.5*z-qx; + a = one-qx; + return a - (hz - (z*r-x*y)); + } +} + + +/* sf_sin.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +float sinf(float x) +{ + float y[2],z=0.0; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0); + + /* sin(Inf or NaN) is NaN */ + else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + switch(n&3) { + case 0: return __kernel_sinf(y[0],y[1],1); + case 1: return __kernel_cosf(y[0],y[1]); + case 2: return -__kernel_sinf(y[0],y[1],1); + default: + return -__kernel_cosf(y[0],y[1]); + } + } +} + + +/* sf_cos.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +float cosf(float x) +{ + float y[2],z=0.0; + __int32_t n,ix; + + GET_FLOAT_WORD(ix,x); + + /* |x| ~< pi/4 */ + ix &= 0x7fffffff; + if(ix <= 0x3f490fd8) return __kernel_cosf(x,z); + + /* cos(Inf or NaN) is NaN */ + else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; + + /* argument reduction needed */ + else { + n = __ieee754_rem_pio2f(x,y); + switch(n&3) { + case 0: return __kernel_cosf(y[0],y[1]); + case 1: return -__kernel_sinf(y[0],y[1],1); + case 2: return -__kernel_cosf(y[0],y[1]); + default: + return __kernel_sinf(y[0],y[1],1); + } + } +} diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index d40cebf947..baabfd120c 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -9,7 +9,6 @@ #include "obj.h" #include "stream.h" #include "pybstdio.h" -#include "storage.h" #include "usb.h" #include "usart.h" @@ -50,9 +49,6 @@ int stdin_rx_chr(void) { return usart_rx_char(pyb_usart_global_debug); } __WFI(); - if (storage_needs_flush()) { - storage_flush(); - } } } diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 298e58a5fd..9821e6a929 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -21,7 +21,6 @@ #include "pybstdio.h" #include "readline.h" #include "pyexec.h" -#include "storage.h" #include "usb.h" #include "build/py/py-version.h" diff --git a/stmhal/std.h b/stmhal/std.h index 843ddd8270..6982b715d0 100644 --- a/stmhal/std.h +++ b/stmhal/std.h @@ -1,7 +1,5 @@ typedef unsigned int size_t; -void __assert_func(void); - void *memcpy(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n); void *memset(void *s, int c, size_t n); diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c index aee689d7e2..df69f52b8e 100644 --- a/stmhal/stm32f4xx_it.c +++ b/stmhal/stm32f4xx_it.c @@ -49,6 +49,7 @@ #include "obj.h"
#include "exti.h"
#include "timer.h"
+#include "storage.h"
/** @addtogroup STM32F4xx_HAL_Examples
* @{
@@ -63,7 +64,7 @@ /* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
-extern void fatality();
+extern void __fatal_error(const char*);
extern PCD_HandleTypeDef hpcd;
/* Private function prototypes -----------------------------------------------*/
@@ -87,12 +88,10 @@ void NMI_Handler(void) * @param None
* @retval None
*/
-void HardFault_Handler(void)
-{
+void HardFault_Handler(void) {
/* Go to infinite loop when Hard Fault exception occurs */
- while (1)
- {
- fatality();
+ while (1) {
+ __fatal_error("HardFault");
}
}
@@ -101,12 +100,10 @@ void HardFault_Handler(void) * @param None
* @retval None
*/
-void MemManage_Handler(void)
-{
+void MemManage_Handler(void) {
/* Go to infinite loop when Memory Manage exception occurs */
- while (1)
- {
- fatality();
+ while (1) {
+ __fatal_error("MemManage");
}
}
@@ -115,12 +112,10 @@ void MemManage_Handler(void) * @param None
* @retval None
*/
-void BusFault_Handler(void)
-{
+void BusFault_Handler(void) {
/* Go to infinite loop when Bus Fault exception occurs */
- while (1)
- {
- fatality();
+ while (1) {
+ __fatal_error("BusFault");
}
}
@@ -129,12 +124,10 @@ void BusFault_Handler(void) * @param None
* @retval None
*/
-void UsageFault_Handler(void)
-{
+void UsageFault_Handler(void) {
/* Go to infinite loop when Usage Fault exception occurs */
- while (1)
- {
- fatality();
+ while (1) {
+ __fatal_error("UsageFault");
}
}
@@ -263,6 +256,19 @@ void OTG_XX_WKUP_IRQHandler(void) {
}*/
+// Handle a flash (erase/program) interrupt.
+void FLASH_IRQHandler(void) {
+ // This calls the real flash IRQ handler, if needed
+ /*
+ uint32_t flash_cr = FLASH->CR;
+ if ((flash_cr & FLASH_IT_EOP) || (flash_cr & FLASH_IT_ERR)) {
+ HAL_FLASH_IRQHandler();
+ }
+ */
+ // This call the storage IRQ handler, to check if the flash cache needs flushing
+ storage_irq_handler();
+}
+
/**
* @brief These functions handle the EXTI interrupt requests.
* @param None
diff --git a/stmhal/storage.c b/stmhal/storage.c index 98d5ee7e70..0348986f26 100644 --- a/stmhal/storage.c +++ b/stmhal/storage.c @@ -16,20 +16,22 @@ #define FLASH_PART1_NUM_BLOCKS (224) // 16k+16k+16k+64k=112k #define FLASH_MEM_START_ADDR (0x08004000) // sector 1, 16k +#define FLASH_FLAG_DIRTY (1) +#define FLASH_FLAG_FORCE_WRITE (2) +#define FLASH_FLAG_ERASED (4) static bool flash_is_initialised = false; -static bool flash_cache_dirty; +static __IO uint8_t flash_flags = 0; static uint32_t flash_cache_sector_id; static uint32_t flash_cache_sector_start; static uint32_t flash_cache_sector_size; static uint32_t flash_tick_counter_last_write; static void flash_cache_flush(void) { - if (flash_cache_dirty) { - // sync the cache RAM buffer by writing it to the flash page - flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); - flash_cache_dirty = false; - // indicate a clean cache with LED off - led_state(PYB_LED_R1, 0); + if (flash_flags & FLASH_FLAG_DIRTY) { + flash_flags |= FLASH_FLAG_FORCE_WRITE; + while (flash_flags & FLASH_FLAG_DIRTY) { + NVIC->STIR = FLASH_IRQn; + } } } @@ -44,9 +46,9 @@ static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) { flash_cache_sector_start = flash_sector_start; flash_cache_sector_size = flash_sector_size; } - flash_cache_dirty = true; - // indicate a dirty cache with LED on - led_state(PYB_LED_R1, 1); + flash_flags |= FLASH_FLAG_DIRTY; + led_state(PYB_LED_R1, 1); // indicate a dirty cache with LED on + flash_tick_counter_last_write = HAL_GetTick(); return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start; } @@ -64,11 +66,17 @@ static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) { void storage_init(void) { if (!flash_is_initialised) { - flash_cache_dirty = false; + flash_flags = 0; flash_cache_sector_id = 0; - flash_is_initialised = true; flash_tick_counter_last_write = 0; + flash_is_initialised = true; } + + // Enable the flash IRQ, which is used to also call our storage IRQ handler + // It needs to go at a higher priority than all those components that rely on + // the flash storage (eg higher than USB MSC). + HAL_NVIC_SetPriority(FLASH_IRQn, 1, 1); + HAL_NVIC_EnableIRQ(FLASH_IRQn); } uint32_t storage_get_block_size(void) { @@ -79,9 +87,47 @@ uint32_t storage_get_block_count(void) { return FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS; } -bool storage_needs_flush(void) { - // wait 2 seconds after last write to flush - return flash_cache_dirty && sys_tick_has_passed(flash_tick_counter_last_write, 2000); +void storage_irq_handler(void) { + if (!(flash_flags & FLASH_FLAG_DIRTY)) { + return; + } + + // This code uses interrupts to erase the flash + /* + if (flash_erase_state == 0) { + flash_erase_it(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_erase_state = 1; + return; + } + + if (flash_erase_state == 1) { + // wait for erase + // TODO add timeout + #define flash_erase_done() (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) == RESET) + if (!flash_erase_done()) { + return; + } + flash_erase_state = 2; + } + */ + + // This code erases the flash directly, waiting for it to finish + if (!(flash_flags & FLASH_FLAG_ERASED)) { + flash_erase(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + flash_flags |= FLASH_FLAG_ERASED; + return; + } + + // If not a forced write, wait at least 5 seconds after last write to flush + // On file close and flash unmount we get a forced write, so we can afford to wait a while + if ((flash_flags & FLASH_FLAG_FORCE_WRITE) || sys_tick_has_passed(flash_tick_counter_last_write, 5000)) { + // sync the cache RAM buffer by writing it to the flash page + flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4); + // clear the flash flags now that we have a clean cache + flash_flags = 0; + // indicate a clean cache with LED off + led_state(PYB_LED_R1, 0); + } } void storage_flush(void) { @@ -167,7 +213,6 @@ bool storage_write_block(const uint8_t *src, uint32_t block) { uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE; uint8_t *dest = flash_cache_get_addr_for_write(flash_addr); memcpy(dest, src, FLASH_BLOCK_SIZE); - flash_tick_counter_last_write = HAL_GetTick(); return true; } else { diff --git a/stmhal/storage.h b/stmhal/storage.h index 4d153d2f69..ae6c832281 100644 --- a/stmhal/storage.h +++ b/stmhal/storage.h @@ -3,7 +3,7 @@ void storage_init(void); uint32_t storage_get_block_size(void); uint32_t storage_get_block_count(void); -bool storage_needs_flush(void); +void storage_irq_handler(void); void storage_flush(void); bool storage_read_block(uint8_t *dest, uint32_t block); bool storage_write_block(const uint8_t *src, uint32_t block); diff --git a/stmhal/timer.c b/stmhal/timer.c index 5ea605039d..26524fbdd9 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -19,6 +19,7 @@ // the interrupts to be dispatched, so they are all collected here. // // TIM3: +// - flash storage controller, to flush the cache // - USB CDC interface, interval, to check for new data // - LED 4, PWM to set the LED intensity // @@ -29,14 +30,17 @@ TIM_HandleTypeDef TIM3_Handle; TIM_HandleTypeDef TIM5_Handle; TIM_HandleTypeDef TIM6_Handle; +// Used to divide down TIM3 and periodically call the flash storage IRQ +static uint32_t tim3_counter = 0; + // TIM3 is set-up for the USB CDC interface void timer_tim3_init(void) { // set up the timer for USBD CDC __TIM3_CLK_ENABLE(); TIM3_Handle.Instance = TIM3; - TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; - TIM3_Handle.Init.Prescaler = 84-1; + TIM3_Handle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; // TIM3 fires every USBD_CDC_POLLING_INTERVAL ms + TIM3_Handle.Init.Prescaler = 84-1; // for System clock at 168MHz, TIM3 runs at 1MHz TIM3_Handle.Init.ClockDivision = 0; TIM3_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; HAL_TIM_Base_Init(&TIM3_Handle); @@ -105,6 +109,13 @@ void timer_tim6_init(uint freq) { void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim == &TIM3_Handle) { USBD_CDC_HAL_TIM_PeriodElapsedCallback(); + + // Periodically raise a flash IRQ for the flash storage controller + if (tim3_counter++ >= 500 / USBD_CDC_POLLING_INTERVAL) { + tim3_counter = 0; + NVIC->STIR = FLASH_IRQn; + } + } else if (htim == &TIM5_Handle) { servo_timer_irq_callback(); } diff --git a/stmhal/usbd_cdc_interface.c b/stmhal/usbd_cdc_interface.c index 552f7cc9ec..b2c85fa4f3 100644 --- a/stmhal/usbd_cdc_interface.c +++ b/stmhal/usbd_cdc_interface.c @@ -63,6 +63,7 @@ static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA static __IO uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained static uint16_t UserTxBufPtrOutShadow = 0; // shadow of above static uint8_t UserTxBufPtrWaitCount = 0; // used to implement a timeout waiting for low-level USB driver +static uint8_t UserTxNeedEmptyPacket = 0; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size static int user_interrupt_char = VCP_CHAR_NONE; static void *user_interrupt_data = NULL; @@ -257,7 +258,7 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { return; } - if (UserTxBufPtrOut == UserTxBufPtrIn) { + if (UserTxBufPtrOut == UserTxBufPtrIn && !UserTxNeedEmptyPacket) { // No outstanding data to send return; } @@ -265,10 +266,11 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { if (UserTxBufPtrOut != UserTxBufPtrOutShadow) { // We have sent data and are waiting for the low-level USB driver to // finish sending it over the USB in-endpoint. - if (UserTxBufPtrWaitCount < 10) { + // We have a 15 * 10ms = 150ms timeout + if (UserTxBufPtrWaitCount < 15) { PCD_HandleTypeDef *hpcd = hUSBDDevice.pData; USB_OTG_GlobalTypeDef *USBx = hpcd->Instance; - if (USBx_INEP(3)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { + if (USBx_INEP(CDC_IN_EP & 0x7f)->DIEPTSIZ & USB_OTG_DIEPTSIZ_XFRSIZ) { // USB in-endpoint is still reading the data UserTxBufPtrWaitCount++; return; @@ -277,7 +279,7 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { UserTxBufPtrOut = UserTxBufPtrOutShadow; } - if (UserTxBufPtrOutShadow != UserTxBufPtrIn) { + if (UserTxBufPtrOutShadow != UserTxBufPtrIn || UserTxNeedEmptyPacket) { uint32_t buffptr; uint32_t buffsize; @@ -289,14 +291,6 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { buffptr = UserTxBufPtrOutShadow; - // 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); if (USBD_CDC_TransmitPacket(&hUSBDDevice) == USBD_OK) { @@ -305,6 +299,14 @@ void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void) { UserTxBufPtrOutShadow = 0; } UserTxBufPtrWaitCount = 0; + + // According to the USB specification, a packet size of 64 bytes (CDC_DATA_FS_MAX_PACKET_SIZE) + // gets held at the USB host until the next packet is sent. This is because a + // packet of maximum size is considered to be part of a longer chunk of data, and + // the host waits for all data to arrive (ie, waits for a packet < max packet size). + // To flush a packet of exactly max packet size, we need to send a zero-size packet. + // See eg http://www.cypress.com/?id=4&rID=92719 + UserTxNeedEmptyPacket = (buffsize == CDC_DATA_FS_MAX_PACKET_SIZE && UserTxBufPtrOutShadow == UserTxBufPtrIn); } } } diff --git a/stmhal/usbd_desc_cdc_msc.c b/stmhal/usbd_desc_cdc_msc.c index 137e0bed99..1af99d0b90 100644 --- a/stmhal/usbd_desc_cdc_msc.c +++ b/stmhal/usbd_desc_cdc_msc.c @@ -32,6 +32,23 @@ /* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
+
+// So we don't clash with existing ST boards, we use the unofficial FOSS VID.
+// This needs a proper solution.
+#define USBD_VID 0xf055
+#define USBD_PID 0x9800
+#define USBD_LANGID_STRING 0x409
+#define USBD_MANUFACTURER_STRING "Micro Python"
+#define USBD_PRODUCT_HS_STRING "Pyboard Virtual Comm Port in HS Mode"
+#define USBD_SERIALNUMBER_HS_STRING "000000000010"
+#define USBD_PRODUCT_FS_STRING "Pyboard Virtual Comm Port in FS Mode"
+#define USBD_SERIALNUMBER_FS_STRING "000000000011"
+#define USBD_CONFIGURATION_HS_STRING "VCP Config"
+#define USBD_INTERFACE_HS_STRING "VCP Interface"
+#define USBD_CONFIGURATION_FS_STRING "VCP Config"
+#define USBD_INTERFACE_FS_STRING "VCP Interface"
+
+/*
#define USBD_VID 0x0483
#define USBD_PID 0x5740
#define USBD_LANGID_STRING 0x409
@@ -44,6 +61,7 @@ #define USBD_INTERFACE_HS_STRING "VCP Interface"
#define USBD_CONFIGURATION_FS_STRING "VCP Config"
#define USBD_INTERFACE_FS_STRING "VCP Interface"
+*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c index 0225a2a23c..6ec9abc3d1 100644 --- a/stmhal/usbd_msc_storage.c +++ b/stmhal/usbd_msc_storage.c @@ -38,7 +38,10 @@ // These are needed to support removal of the medium, so that the USB drive // can be unmounted, and won't be remounted automatically. static uint8_t flash_removed = 0; + +#if MICROPY_HW_HAS_SDCARD static uint8_t sdcard_removed = 0; +#endif /******************************************************************************/ // Callback functions for when the internal flash is the mass storage device @@ -109,6 +112,12 @@ int8_t FLASH_STORAGE_StopUnit(uint8_t lun) { return 0; } +int8_t FLASH_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { + // sync the flash so that the cache is cleared and the device can be unplugged/turned off + disk_ioctl(0, CTRL_SYNC, NULL); + return 0; +} + /** * @brief Read data from the medium * @param lun : logical unit number @@ -146,7 +155,6 @@ int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16 } } */ - storage_flush(); // XXX hack for now so that the cache is always flushed return 0; } @@ -165,6 +173,7 @@ const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = { FLASH_STORAGE_IsReady, FLASH_STORAGE_IsWriteProtected, FLASH_STORAGE_StopUnit, + FLASH_STORAGE_PreventAllowMediumRemoval, FLASH_STORAGE_Read, FLASH_STORAGE_Write, FLASH_STORAGE_GetMaxLun, @@ -295,6 +304,10 @@ int8_t SDCARD_STORAGE_StopUnit(uint8_t lun) { return 0; } +int8_t SDCARD_STORAGE_PreventAllowMediumRemoval(uint8_t lun, uint8_t param) { + return 0; +} + /** * @brief Read data from the medium * @param lun : logical unit number @@ -340,6 +353,7 @@ const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = { SDCARD_STORAGE_IsReady, SDCARD_STORAGE_IsWriteProtected, SDCARD_STORAGE_StopUnit, + SDCARD_STORAGE_PreventAllowMediumRemoval, SDCARD_STORAGE_Read, SDCARD_STORAGE_Write, SDCARD_STORAGE_GetMaxLun, diff --git a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h index 9343994931..798bdc99db 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h +++ b/stmhal/usbdev/class/cdc_msc_hid/inc/usbd_cdc_msc_hid.h @@ -13,6 +13,11 @@ #define MSC_IN_EP (0x81) #define MSC_OUT_EP (0x01) +// Need to define here for usbd_cdc_interface.c (it needs CDC_IN_EP) +#define CDC_IN_EP (0x83) +#define CDC_OUT_EP (0x03) +#define CDC_CMD_EP (0x82) + // only CDC_MSC and CDC_HID are available #define USBD_MODE_CDC (0x01) #define USBD_MODE_MSC (0x02) @@ -54,6 +59,7 @@ typedef struct _USBD_STORAGE { int8_t (* IsReady) (uint8_t lun); int8_t (* IsWriteProtected) (uint8_t lun); int8_t (* StopUnit)(uint8_t lun); + int8_t (* PreventAllowMediumRemoval)(uint8_t lun, uint8_t param0); int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len); int8_t (* GetMaxLun)(void); diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c index 6dc0af0e65..aa8c0c80cf 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c +++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_cdc_msc_hid.c @@ -4,9 +4,6 @@ #define USB_CDC_MSC_CONFIG_DESC_SIZ (98) #define USB_CDC_HID_CONFIG_DESC_SIZ (100) #define CDC_IFACE_NUM (1) -#define CDC_IN_EP (0x83) -#define CDC_OUT_EP (0x03) -#define CDC_CMD_EP (0x82) #define MSC_IFACE_NUM (0) #define HID_IFACE_NUM_WITH_CDC (0) #define HID_IFACE_NUM_WITH_MSC (1) diff --git a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c index b00d1ae2ce..60258d64d9 100644 --- a/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c +++ b/stmhal/usbdev/class/cdc_msc_hid/src/usbd_msc_scsi.c @@ -472,6 +472,7 @@ static int8_t SCSI_AllowMediumRemoval(USBD_HandleTypeDef *pdev, uint8_t lun, ui {
USBD_MSC_BOT_HandleTypeDef *hmsc = pdev->pClassData;
hmsc->bot_data_length = 0;
+ ((USBD_StorageTypeDef *)pdev->pUserData)->PreventAllowMediumRemoval(lun, params[0]);
return 0;
}
diff --git a/tests/README b/tests/README index ef00705712..0cb526c3b4 100644 --- a/tests/README +++ b/tests/README @@ -2,3 +2,7 @@ This directory contains tests for various functionality areas of MicroPython. To run all stable tests, run "run-tests" script in this directory. Note that bytecode tests are not yet stable and should be run separately in "bytecode" subdirectory. + +When creating new tests, anything that relies on float support should go in the +float/ subdirectory. Anything that relies on import x, where x is not a built-in +module, should go in the import/ subdirectory. diff --git a/tests/basics/fun-callstar.py b/tests/basics/fun-callstar.py index e19acb3491..255563b26b 100644 --- a/tests/basics/fun-callstar.py +++ b/tests/basics/fun-callstar.py @@ -31,5 +31,3 @@ a.foo(1, 2, *[100]) # Iterator a.foo(*range(3)) - -print('flush') # so that it works on pyboard... diff --git a/tests/basics/fun-defargs.py b/tests/basics/fun-defargs.py index 51516c7363..0666b8c494 100644 --- a/tests/basics/fun-defargs.py +++ b/tests/basics/fun-defargs.py @@ -18,5 +18,3 @@ try: fun2(1, 2, 3, 4) except TypeError: print("TypeError") - -print('flush') # so that it works on pyboard... diff --git a/tests/basics/int-divzero.py b/tests/basics/int-divzero.py index d1fc579321..28ec2a6995 100644 --- a/tests/basics/int-divzero.py +++ b/tests/basics/int-divzero.py @@ -1,9 +1,4 @@ try: - 1 / 0 -except ZeroDivisionError: - print("ZeroDivisionError") - -try: 1 // 0 except ZeroDivisionError: print("ZeroDivisionError") diff --git a/tests/basics/list1.py b/tests/basics/list1.py index a0c8afc4f8..c8317baa3d 100644 --- a/tests/basics/list1.py +++ b/tests/basics/list1.py @@ -22,8 +22,3 @@ print(x) print(x[1:]) print(x[:-1]) print(x[2:3]) - -try: - print(x[1.0]) -except TypeError: - print("TypeError") diff --git a/tests/basics/modulo.py b/tests/basics/modulo.py index 4d83db6ec8..c95305d13d 100644 --- a/tests/basics/modulo.py +++ b/tests/basics/modulo.py @@ -1,5 +1,6 @@ # check modulo matches python definition -# This test compiler version + +# this tests compiler constant folding print(123 % 7) print(-123 % 7) print(123 % -7) @@ -20,17 +21,3 @@ print(a % b) print(a % -b) print(-a % b) print(-a % -b) - -if False: - print(1.23456 % 0.7) - print(-1.23456 % 0.7) - print(1.23456 % -0.7) - print(-1.23456 % -0.7) - - a = 1.23456 - b = 0.7 - print(a % b) - print(a % -b) - print(-a % b) - print(-a % -b) - diff --git a/tests/basics/string-format-modulo.py b/tests/basics/string-format-modulo.py index 8e58be18c8..0e2c1d1096 100644 --- a/tests/basics/string-format-modulo.py +++ b/tests/basics/string-format-modulo.py @@ -23,11 +23,9 @@ except TypeError: print("%s" % True) print("%s" % 1) -print("%s" % 1.0) print("%r" % True) print("%r" % 1) -print("%r" % 1.0) print("%c" % 48) print("%c" % 'a') @@ -37,28 +35,16 @@ print("%d" % 10) print("%+d" % 10) print("% d" % 10) print("%d" % -10) -print("%d" % 1.0) print("%d" % True) print("%i" % -10) -print("%i" % 1.0) print("%i" % True) print("%u" % -10) -print("%u" % 1.0) print("%u" % True) print("%x" % 18) -print("%x" % 18.0) print("%o" % 18) -print("%o" % 18.0) print("%X" % 18) -print("%X" % 18.0) print("%#x" % 18) print("%#X" % 18) print("%#6o" % 18) print("%#6x" % 18) print("%#06x" % 18) -print("%e" % 1.23456) -print("%E" % 1.23456) -print("%f" % 1.23456) -print("%F" % 1.23456) -print("%g" % 1.23456) -print("%G" % 1.23456) diff --git a/tests/basics/string-format.py b/tests/basics/string-format.py index 2d6d0cc721..84ea054758 100644 --- a/tests/basics/string-format.py +++ b/tests/basics/string-format.py @@ -60,26 +60,6 @@ test("{:@<6d}", -123) test("{:@=6d}", -123) test("{:06d}", -123) -test("{:10.4e}", 123.456) -test("{:10.4e}", -123.456) -test("{:10.4f}", 123.456) -test("{:10.4f}", -123.456) -test("{:10.4g}", 123.456) -test("{:10.4g}", -123.456) -test("{:e}", 100) -test("{:f}", 200) -test("{:g}", 300) - -test("{:10.4E}", 123.456) -test("{:10.4E}", -123.456) -test("{:10.4F}", 123.456) -test("{:10.4F}", -123.456) -test("{:10.4G}", 123.456) -test("{:10.4G}", -123.456) - -# The following fails right now -#test("{:10.1}", 0.0) - def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): fmt = '{' if conv: @@ -137,71 +117,4 @@ if full_tests: for str in ('', 'a', 'bcd', 'This is a test with a longer string'): test_fmt(conv, fill, alignment, '', '', width, '', 's', str) -eg_nums = (0.0, -0.0, 0.1, 1.234, 12.3459, 1.23456789, 123456789.0, -0.0, - -0.1, -1.234, -12.3459, 1e4, 1e-4, 1e5, 1e-5, 1e6, 1e-6, 1e10, - 1e37, -1e37, 1e-37, -1e-37, - 1.23456e8, 1.23456e7, 1.23456e6, 1.23456e5, 1.23456e4, 1.23456e3, 1.23456e2, 1.23456e1, 1.23456e0, - 1.23456e-1, 1.23456e-2, 1.23456e-3, 1.23456e-4, 1.23456e-5, 1.23456e-6, 1.23456e-7, 1.23456e-8, - -1.23456e8, -1.23456e7, -1.23456e6, -1.23456e5, -1.23456e4, -1.23456e3, -1.23456e2, -1.23456e1, -1.23456e0, - -1.23456e-1, -1.23456e-2, -1.23456e-3, -1.23456e-4, -1.23456e-5, -1.23456e-6, -1.23456e-7, -1.23456e-8) - -if full_tests: - for type in ('e', 'E', 'g', 'G', 'n'): - for width in ('', '4', '6', '8', '10'): - for alignment in ('', '<', '>', '=', '^'): - for fill in ('', '@', '0', ' '): - for sign in ('', '+', '-', ' '): - for prec in ('', '1', '3', '6'): - for num in eg_nums: - test_fmt('', fill, alignment, sign, '', width, prec, type, num) - -# Note: We use 1.23459 rather than 1.2345 because '{:3f}'.format(1.2345) -# rounds differently than print("%.3f", 1.2345); - -f_nums = (0.0, -0.0, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, - 0.0012, 0.0123, 0.1234, 1.23459, 12.3456, - -0.0001, -0.001, -0.01, -0.1, -1.0, -10.0, - -0.0012, -0.0123, -0.1234, -1.23459, -12.3456) - -if full_tests: - for type in ('f', 'F'): - for width in ('', '4', '6', '8', '10'): - for alignment in ('', '<', '>', '=', '^'): - for fill in ('', ' ', '0', '@'): - for sign in ('', '+', '-', ' '): - # An empty precision defaults to 6, but when uPy is - # configured to use a float, we can only use a - # precision of 6 with numbers less than 10 and still - # get results that compare to CPython (which uses - # long doubles). - for prec in ('1', '2', '3'): - for num in f_nums: - test_fmt('', fill, alignment, sign, '', width, prec, type, num) - for num in int_nums2: - test_fmt('', fill, alignment, sign, '', width, '', type, num) - -pct_nums1 = (0.1, 0.58, 0.99, -0.1, -0.58, -0.99) -pct_nums2 = (True, False, 1, 0, -1) - -if full_tests: - type = '%' - for width in ('', '4', '6', '8', '10'): - for alignment in ('', '<', '>', '=', '^'): - for fill in ('', ' ', '0', '@'): - for sign in ('', '+', '-', ' '): - # An empty precision defaults to 6, but when uPy is - # configured to use a float, we can only use a - # precision of 6 with numbers less than 10 and still - # get results that compare to CPython (which uses - # long doubles). - for prec in ('1', '2', '3'): - for num in pct_nums1: - test_fmt('', fill, alignment, sign, '', width, prec, type, num) - for num in pct_nums2: - test_fmt('', fill, alignment, sign, '', width, '', type, num) - -# We don't currently test a type of '' with floats (see the detailed comment -# in objstr.c) - # TODO Add tests for erroneous format strings. - diff --git a/tests/basics/true-value.py b/tests/basics/true-value.py index 1dd547f326..9ec209fe82 100644 --- a/tests/basics/true-value.py +++ b/tests/basics/true-value.py @@ -9,12 +9,6 @@ if not None: if not 0: print("0") -if not 0.0: - print("float 0") - -if not 0+0j: - print("complex 0") - if not "": print("Empty string") if "foo": diff --git a/tests/basics/types1.py b/tests/basics/types1.py index 57b33b842b..38a20d6803 100644 --- a/tests/basics/types1.py +++ b/tests/basics/types1.py @@ -2,8 +2,6 @@ print(bool) print(int) -print(float) -print(complex) print(tuple) print(list) print(set) @@ -11,8 +9,6 @@ print(dict) print(type(bool()) == bool) print(type(int()) == int) -print(type(float()) == float) -print(type(complex()) == complex) print(type(tuple()) == tuple) print(type(list()) == list) print(type(set()) == set) @@ -20,8 +16,6 @@ print(type(dict()) == dict) print(type(False) == bool) print(type(0) == int) -print(type(0.0) == float) -print(type(1j) == complex) print(type(()) == tuple) print(type([]) == list) print(type({None}) == set) diff --git a/tests/basics/types2.py b/tests/basics/types2.py index 83a69c918f..ba7be6b154 100644 --- a/tests/basics/types2.py +++ b/tests/basics/types2.py @@ -9,4 +9,6 @@ print(int == int) print(int != list) d = {} -d[int] = float +d[int] = list +d[list] = int +print(len(d)) diff --git a/tests/basics/float1.py b/tests/float/float1.py index bf1305c3d5..bf1305c3d5 100644 --- a/tests/basics/float1.py +++ b/tests/float/float1.py diff --git a/tests/float/int-divzero.py b/tests/float/int-divzero.py new file mode 100644 index 0000000000..b037dd8c7b --- /dev/null +++ b/tests/float/int-divzero.py @@ -0,0 +1,4 @@ +try: + 1 / 0 +except ZeroDivisionError: + print("ZeroDivisionError") diff --git a/tests/float/list-index.py b/tests/float/list-index.py new file mode 100644 index 0000000000..13e4557af7 --- /dev/null +++ b/tests/float/list-index.py @@ -0,0 +1,8 @@ +x = [1, 2] + +print(x[1]) + +try: + print(x[1.0]) +except TypeError: + print("TypeError") diff --git a/tests/basics/math-fun-bool.py b/tests/float/math-fun-bool.py index cf718d4b80..cf718d4b80 100644 --- a/tests/basics/math-fun-bool.py +++ b/tests/float/math-fun-bool.py diff --git a/tests/basics/math-fun.py b/tests/float/math-fun.py index 7a37c58454..7a37c58454 100644 --- a/tests/basics/math-fun.py +++ b/tests/float/math-fun.py diff --git a/tests/float/modulo.py b/tests/float/modulo.py new file mode 100644 index 0000000000..911268513a --- /dev/null +++ b/tests/float/modulo.py @@ -0,0 +1,14 @@ +# check modulo matches python definition +# TODO we currenty fail with this +if False: + print(1.23456 % 0.7) + print(-1.23456 % 0.7) + print(1.23456 % -0.7) + print(-1.23456 % -0.7) + + a = 1.23456 + b = 0.7 + print(a % b) + print(a % -b) + print(-a % b) + print(-a % -b) diff --git a/tests/float/string-format-modulo.py b/tests/float/string-format-modulo.py new file mode 100644 index 0000000000..f2117f3565 --- /dev/null +++ b/tests/float/string-format-modulo.py @@ -0,0 +1,16 @@ +print("%s" % 1.0) +print("%r" % 1.0) + +print("%d" % 1.0) +print("%i" % 1.0) +print("%u" % 1.0) +print("%x" % 18.0) +print("%o" % 18.0) +print("%X" % 18.0) + +print("%e" % 1.23456) +print("%E" % 1.23456) +print("%f" % 1.23456) +print("%F" % 1.23456) +print("%g" % 1.23456) +print("%G" % 1.23456) diff --git a/tests/float/string-format.py b/tests/float/string-format.py new file mode 100644 index 0000000000..b5ff68b8ca --- /dev/null +++ b/tests/float/string-format.py @@ -0,0 +1,123 @@ +# Change the following to True to get a much more comprehensive set of tests +# to run, albeit, which take considerably longer. + +full_tests = False + +def test(fmt, *args): + print('{:8s}'.format(fmt) + '>' + fmt.format(*args) + '<') + +test("{:10.4e}", 123.456) +test("{:10.4e}", -123.456) +test("{:10.4f}", 123.456) +test("{:10.4f}", -123.456) +test("{:10.4g}", 123.456) +test("{:10.4g}", -123.456) +test("{:e}", 100) +test("{:f}", 200) +test("{:g}", 300) + +test("{:10.4E}", 123.456) +test("{:10.4E}", -123.456) +test("{:10.4F}", 123.456) +test("{:10.4F}", -123.456) +test("{:10.4G}", 123.456) +test("{:10.4G}", -123.456) + +# The following fails right now +#test("{:10.1}", 0.0) + +def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): + fmt = '{' + if conv: + fmt += '!' + fmt += conv + fmt += ':' + if alignment: + fmt += fill + fmt += alignment + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + if fill == '0' and alignment == '=': + fmt = '{:' + fmt += sign + fmt += prefix + fmt += width + if precision: + fmt += '.' + fmt += precision + fmt += type + fmt += '}' + test(fmt, arg) + +eg_nums = (0.0, -0.0, 0.1, 1.234, 12.3459, 1.23456789, 123456789.0, -0.0, + -0.1, -1.234, -12.3459, 1e4, 1e-4, 1e5, 1e-5, 1e6, 1e-6, 1e10, + 1e37, -1e37, 1e-37, -1e-37, + 1.23456e8, 1.23456e7, 1.23456e6, 1.23456e5, 1.23456e4, 1.23456e3, 1.23456e2, 1.23456e1, 1.23456e0, + 1.23456e-1, 1.23456e-2, 1.23456e-3, 1.23456e-4, 1.23456e-5, 1.23456e-6, 1.23456e-7, 1.23456e-8, + -1.23456e8, -1.23456e7, -1.23456e6, -1.23456e5, -1.23456e4, -1.23456e3, -1.23456e2, -1.23456e1, -1.23456e0, + -1.23456e-1, -1.23456e-2, -1.23456e-3, -1.23456e-4, -1.23456e-5, -1.23456e-6, -1.23456e-7, -1.23456e-8) + +if full_tests: + for type in ('e', 'E', 'g', 'G', 'n'): + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', '@', '0', ' '): + for sign in ('', '+', '-', ' '): + for prec in ('', '1', '3', '6'): + for num in eg_nums: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + +# Note: We use 1.23459 rather than 1.2345 because '{:3f}'.format(1.2345) +# rounds differently than print("%.3f", 1.2345); + +f_nums = (0.0, -0.0, 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, + 0.0012, 0.0123, 0.1234, 1.23459, 12.3456, + -0.0001, -0.001, -0.01, -0.1, -1.0, -10.0, + -0.0012, -0.0123, -0.1234, -1.23459, -12.3456) + +if full_tests: + for type in ('f', 'F'): + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', ' ', '0', '@'): + for sign in ('', '+', '-', ' '): + # An empty precision defaults to 6, but when uPy is + # configured to use a float, we can only use a + # precision of 6 with numbers less than 10 and still + # get results that compare to CPython (which uses + # long doubles). + for prec in ('1', '2', '3'): + for num in f_nums: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + for num in int_nums2: + test_fmt('', fill, alignment, sign, '', width, '', type, num) + +pct_nums1 = (0.1, 0.58, 0.99, -0.1, -0.58, -0.99) +pct_nums2 = (True, False, 1, 0, -1) + +if full_tests: + type = '%' + for width in ('', '4', '6', '8', '10'): + for alignment in ('', '<', '>', '=', '^'): + for fill in ('', ' ', '0', '@'): + for sign in ('', '+', '-', ' '): + # An empty precision defaults to 6, but when uPy is + # configured to use a float, we can only use a + # precision of 6 with numbers less than 10 and still + # get results that compare to CPython (which uses + # long doubles). + for prec in ('1', '2', '3'): + for num in pct_nums1: + test_fmt('', fill, alignment, sign, '', width, prec, type, num) + for num in pct_nums2: + test_fmt('', fill, alignment, sign, '', width, '', type, num) + +# We don't currently test a type of '' with floats (see the detailed comment +# in objstr.c) diff --git a/tests/float/true-value.py b/tests/float/true-value.py new file mode 100644 index 0000000000..df415f0031 --- /dev/null +++ b/tests/float/true-value.py @@ -0,0 +1,7 @@ +# Test true-ish value handling + +if not 0.0: + print("float 0") + +if not 0+0j: + print("complex 0") diff --git a/tests/float/types.py b/tests/float/types.py new file mode 100644 index 0000000000..75674c9246 --- /dev/null +++ b/tests/float/types.py @@ -0,0 +1,17 @@ +# float types + +print(float) +print(complex) + +print(type(float()) == float) +print(type(complex()) == complex) + +print(type(0.0) == float) +print(type(1j) == complex) + +# hashing float types + +d = dict() +d[float] = complex +d[complex] = float +print(len(d)) diff --git a/tests/basics/import-pkg1.py b/tests/import/import-pkg1.py index 8cd77af79d..8cd77af79d 100644 --- a/tests/basics/import-pkg1.py +++ b/tests/import/import-pkg1.py diff --git a/tests/basics/import-pkg2.py b/tests/import/import-pkg2.py index 2e9f34121b..2e9f34121b 100644 --- a/tests/basics/import-pkg2.py +++ b/tests/import/import-pkg2.py diff --git a/tests/basics/import-pkg3.py b/tests/import/import-pkg3.py index 0ee885b220..0ee885b220 100644 --- a/tests/basics/import-pkg3.py +++ b/tests/import/import-pkg3.py diff --git a/tests/basics/import-pkg4.py b/tests/import/import-pkg4.py index 90b6f2e0ee..90b6f2e0ee 100644 --- a/tests/basics/import-pkg4.py +++ b/tests/import/import-pkg4.py diff --git a/tests/basics/import-pkg5.py b/tests/import/import-pkg5.py index aa74bb45f0..aa74bb45f0 100644 --- a/tests/basics/import-pkg5.py +++ b/tests/import/import-pkg5.py diff --git a/tests/basics/import1a.py b/tests/import/import1a.py index 16b2d4d30f..16b2d4d30f 100644 --- a/tests/basics/import1a.py +++ b/tests/import/import1a.py diff --git a/tests/basics/import1b.py b/tests/import/import1b.py index be74eca094..be74eca094 100644 --- a/tests/basics/import1b.py +++ b/tests/import/import1b.py diff --git a/tests/basics/import2a.py b/tests/import/import2a.py index ce32b10b1b..ce32b10b1b 100644 --- a/tests/basics/import2a.py +++ b/tests/import/import2a.py diff --git a/tests/basics/import3a.py b/tests/import/import3a.py index 2e9d41f71d..2e9d41f71d 100644 --- a/tests/basics/import3a.py +++ b/tests/import/import3a.py diff --git a/tests/basics/pkg/__init__.py b/tests/import/pkg/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/tests/basics/pkg/__init__.py +++ b/tests/import/pkg/__init__.py diff --git a/tests/basics/pkg/mod.py b/tests/import/pkg/mod.py index 9e67bdd291..9e67bdd291 100644 --- a/tests/basics/pkg/mod.py +++ b/tests/import/pkg/mod.py diff --git a/tests/basics/pkg2/__init__.py b/tests/import/pkg2/__init__.py index 101ac7d400..101ac7d400 100644 --- a/tests/basics/pkg2/__init__.py +++ b/tests/import/pkg2/__init__.py diff --git a/tests/basics/pkg2/mod1.py b/tests/import/pkg2/mod1.py index 03754a45f6..03754a45f6 100644 --- a/tests/basics/pkg2/mod1.py +++ b/tests/import/pkg2/mod1.py diff --git a/tests/basics/pkg2/mod2.py b/tests/import/pkg2/mod2.py index 97dadcde46..97dadcde46 100644 --- a/tests/basics/pkg2/mod2.py +++ b/tests/import/pkg2/mod2.py diff --git a/tests/basics/pkg3/__init__.py b/tests/import/pkg3/__init__.py index 8b92fa9967..8b92fa9967 100644 --- a/tests/basics/pkg3/__init__.py +++ b/tests/import/pkg3/__init__.py diff --git a/tests/basics/pkg3/mod1.py b/tests/import/pkg3/mod1.py index 28a0f5bf10..28a0f5bf10 100644 --- a/tests/basics/pkg3/mod1.py +++ b/tests/import/pkg3/mod1.py diff --git a/tests/basics/pkg3/mod2.py b/tests/import/pkg3/mod2.py index 67f43bad52..67f43bad52 100644 --- a/tests/basics/pkg3/mod2.py +++ b/tests/import/pkg3/mod2.py diff --git a/tests/basics/pkg3/subpkg1/__init__.py b/tests/import/pkg3/subpkg1/__init__.py index 72b5423958..72b5423958 100644 --- a/tests/basics/pkg3/subpkg1/__init__.py +++ b/tests/import/pkg3/subpkg1/__init__.py diff --git a/tests/basics/pkg3/subpkg1/mod1.py b/tests/import/pkg3/subpkg1/mod1.py index 7a2ae44b54..7a2ae44b54 100644 --- a/tests/basics/pkg3/subpkg1/mod1.py +++ b/tests/import/pkg3/subpkg1/mod1.py diff --git a/tests/basics/try-module.py b/tests/import/try-module.py index 03a9db15b5..03a9db15b5 100644 --- a/tests/basics/try-module.py +++ b/tests/import/try-module.py diff --git a/tests/run-tests b/tests/run-tests index bd6e50bbd2..9e94026fa2 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -10,10 +10,10 @@ from glob import glob # to the correct executable. if os.name == 'nt': CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3.exe') - MP_PY = '../windows/micropython.exe' + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../windows/micropython.exe') else: CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') - MP_PY = '../unix/micropython' + MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../unix/micropython') # Set of tests that we shouldn't run under Travis CI skip_travis_tests = set(['basics/memoryerror.py']) @@ -29,7 +29,8 @@ failed_tests = [] tests = [] if not sys.argv[1:]: - tests = sorted(glob('basics/*.py') + glob('io/*.py') + glob('misc/*.py')) + test_dirs = ('basics', 'float', 'import', 'io', 'misc') + tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) else: tests = sys.argv[1:] @@ -39,7 +40,7 @@ if test_on_pyboard: pyb = pyboard.Pyboard('/dev/ttyACM0') pyb.enter_raw_repl() -running_under_travis = os.environ.get('TRAVIS', 'false') == 'true' +running_under_travis = os.getenv('TRAVIS') == 'true' for test_file in tests: if running_under_travis and test_file in skip_travis_tests: @@ -56,16 +57,12 @@ for test_file in tests: if test_on_pyboard: pyb.enter_raw_repl() try: - if test_file == 'basics/memoryerror.py': - # this test crashes the pyboard - output_mupy = b'CRASH' - else: - output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') + output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') except pyboard.PyboardError: - output_mupy = b'CRASH\n' + output_mupy + output_mupy = b'CRASH' else: try: - output_mupy = subprocess.check_output([MP_PY, '-X', 'emit=bytecode', test_file]) + output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file]) except subprocess.CalledProcessError: output_mupy = b'CRASH' diff --git a/unix/Makefile b/unix/Makefile index 64483d90df..1a29363c91 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -71,3 +71,8 @@ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) include ../py/mkrules.mk +.PHONY: test + +test: $(PROG) ../tests/run-tests + $(eval DIRNAME=$(notdir $(CURDIR))) + cd ../tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(PROG) ./run-tests diff --git a/unix/modffi.c b/unix/modffi.c index cb6a4424f3..f2bd6fcecf 100644 --- a/unix/modffi.c +++ b/unix/modffi.c @@ -61,6 +61,8 @@ STATIC ffi_type *char2ffi_type(char c) case 'I': return &ffi_type_uint; case 'l': return &ffi_type_slong; case 'L': return &ffi_type_ulong; + case 'f': return &ffi_type_float; + case 'd': return &ffi_type_double; case 'p': case 's': return &ffi_type_pointer; case 'v': return &ffi_type_void; @@ -92,6 +94,14 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) } case 'v': return mp_const_none; + case 'f': { + float *p = (float*)&val; + return mp_obj_new_float(*p); + } + case 'd': { + double *p = (double*)&val; + return mp_obj_new_float(*p); + } default: return mp_obj_new_int(val); } diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 9c91b757a8..cf6e6fae26 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -10,12 +10,12 @@ #define MICROPY_ENABLE_REPL_HELPERS (1) #define MICROPY_ENABLE_LEXER_UNIX (1) #define MICROPY_ENABLE_SOURCE_LINE (1) -#define MICROPY_ENABLE_PROPERTY (1) #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_GOTOS (1) #define MICROPY_MOD_SYS_STDFILES (1) +#define MICROPY_ENABLE_MOD_CMATH (1) // type definitions for the specific machine |