Compare commits

..

45 Commits

Author SHA1 Message Date
Damien George
ccedf000ed docs: Increase size of pyboard pinout. 2014-10-26 22:58:18 +00:00
Paul Sokolovsky
429e3f077e unix: Make -v dump memory info at exit.
Also, move bytecode dumps to -v -v, because they're too verbose for just -v.
2014-10-26 22:36:56 +00:00
Damien George
8768f8ad4b docs: Add quick reference page, with pinout and short example code. 2014-10-26 22:11:34 +00:00
Damien George
e4e52f5370 stmhal: Allow DAC object to be initialised from a pin.
Eg: dac = DAC(Pin.board.X5)
2014-10-26 21:46:06 +00:00
Paul Sokolovsky
e503512f83 unix: Implement -m option (execute module from stdlib).
Support for packages as argument not implemented, but otherwise error and
exit handling should be correct. This for example will allow to do:

pip-micropython install micropython-test.pystone
micropython -m test.pystone
2014-10-26 15:54:19 +00:00
Damien George
bc1488a05f stmhal: Improve REPL control codes; improve pyboard.py script.
Improvements are:

2 ctrl-C's are now needed to truly kill running script on pyboard, so
make CDC interface allow multiple ctrl-C's through at once (ie sending
b'\x03\x03' to pyboard now counts as 2 ctrl-C's).

ctrl-C in friendly-repl can now stop multi-line input.

In raw-repl mode, use ctrl-D to indicate end of running script, and also
end of any error message.  Thus, output of raw-repl is always at least 2
ctrl-D's and it's much easier to parse.

pyboard.py is now a bit faster, handles exceptions from pyboard better
(prints them and exits with exit code 1), prints out the pyboard output
while the script is running (instead of waiting till the end), and
allows to follow the output of a previous script when run with no
arguments.
2014-10-26 15:39:22 +00:00
Damien George
b2f19b8d34 tests: Get builtin_compile to skin properly on pyboard. 2014-10-26 15:38:28 +00:00
Damien George
480a7ce58f stmhal: Change SPI phase spec to 0,1 to match standard conventions.
Was 1 or 2, now 0 or 1 (respectively).  0 means sample MISO on first
edge, 1 means sample on second edge.

Addresses issue #936.
2014-10-26 13:54:31 +00:00
Damien George
de3c806965 py: Fix memoryview referencing so it retains ptr to original buffer.
This way, if original parent object is GC'd, the memoryview still points
to the underlying buffer data so that buffer is not GC'd.
2014-10-26 13:20:50 +00:00
Damien George
c76af32575 unix/windows: Disable sigaction on windows port. 2014-10-26 00:42:41 +01:00
Damien George
b0b0012fd8 py: Fix VM dispatch following a pending exception check. 2014-10-26 00:33:23 +01:00
Sebastian Plamauer
91bd4e8a23 changed file paths to new names 2014-10-25 23:59:33 +01:00
Damien George
124df6f8d0 py: Add mp_pending_exception global variable, for VM soft interrupt.
This allows to implement KeyboardInterrupt on unix, and a much safer
ctrl-C in stmhal port.  First ctrl-C is a soft one, with hope that VM
will notice it; second ctrl-C is a hard one that kills anything (for
both unix and stmhal).

One needs to check for a pending exception in the VM only for jump
opcodes.  Others can't produce an infinite loop (infinite recursion is
caught by stack check).
2014-10-25 23:37:57 +01:00
Damien George
d7353fe6fe stmhal: Change USB PID when in CDC+HID mode.
This gets CDC+HID working on Windows, since it needs a different PID for
a different USB configuration.

Thanks to tmbinc and dhylands.
2014-10-25 22:55:07 +01:00
Damien George
627852019b tests: Add test for compile builtin. 2014-10-25 22:07:25 +01:00
Damien George
c9fc620723 py: Implement compile builtin, enabled only on unix port.
This should be pretty compliant with CPython, except perhaps for some
corner cases to do with globals/locals context.

Addresses issue #879.
2014-10-25 22:07:25 +01:00
Paul Sokolovsky
e5a3759ff5 py: Factor out mp_obj_is_package() function. 2014-10-25 22:31:33 +03:00
Paul Sokolovsky
8becca7c82 py: mp_builtin___import__(): Add const to arg type. 2014-10-25 22:31:26 +03:00
Damien George
8456cc017b py: Compress load-int, load-fast, store-fast, unop, binop bytecodes.
There is a lot potential in compress bytecodes and make more use of the
coding space.  This patch introduces "multi" bytecodes which have their
argument included in the bytecode (by addition).

UNARY_OP and BINARY_OP now no longer take a 1 byte argument for the
opcode.  Rather, the opcode is included in the first byte itself.

LOAD_FAST_[0,1,2] and STORE_FAST_[0,1,2] are removed in favour of their
multi versions, which can take an argument between 0 and 15 inclusive.
The majority of LOAD_FAST/STORE_FAST codes fit in this range and so this
saves a byte for each of these.

LOAD_CONST_SMALL_INT_MULTI is used to load small ints between -16 and 47
inclusive.  Such ints are quite common and now only need 1 byte to
store, and now have much faster decoding.

In all this patch saves about 2% RAM for typically bytecode (1.8% on
64-bit test, 2.5% on pyboard test).  It also reduces the binary size
(because bytecodes are simplified) and doesn't harm performance.
2014-10-25 20:23:13 +01:00
Damien George
1084b0f9c2 py: Store bytecode arg names in bytecode (were in own array).
This saves a lot of RAM for 2 reasons:

1. For functions that don't have default values, var args or var kw
args (which is a large number of functions in the general case), the
mp_obj_fun_bc_t type now fits in 1 GC block (previously needed 2 because
of the extra pointer to point to the arg_names array).  So this saves 16
bytes per function (32 bytes on 64-bit machines).

2. Combining separate memory regions generally saves RAM because the
unused bytes at the end of the GC block are saved for 1 of the blocks
(since that block doesn't exist on its own anymore).  So generally this
saves 8 bytes per function.

Tested by importing lots of modules:

- 64-bit Linux gave about an 8% RAM saving for 86k of used RAM.
- pyboard gave about a 6% RAM saving for 31k of used RAM.
2014-10-25 20:23:13 +01:00
Paul Sokolovsky
fcff4663dd unix: Allow -X heapsize= option take numbers with K & M suffixes.
For kilobytes and megabytes respectively.
2014-10-25 17:00:55 +01:00
Damien George
8204db6831 stmhal: Change fresh boot.py and main.py to use \r\n newlines.
This is so it's compatible with Windows.
2014-10-25 01:14:39 +01:00
Damien George
21dfd207ca stmhal: Fill in USB class/subclass/proto for CDC+HID device.
Also change HID device from keyboard to mouse (should have been mouse
all along).
2014-10-25 01:14:39 +01:00
Felix Domke
a64d5d67b5 USB CDC ACM: populate bFunction{Class,SubClass,Protocol} in the interface association descriptor 2014-10-25 01:14:39 +01:00
Damien George
0b13f3e026 py: Improve memory usage debugging; better GC AT dumping.
In unix port, mem_info(1) now prints pretty GC alloc table.
2014-10-24 23:12:25 +01:00
Damien George
564963a170 py: Fix debug-printing of bytecode line numbers.
Also move the raw bytecode printing code from emitglue to mp_bytecode_print.
2014-10-24 14:42:50 +00:00
Damien George
d00d8ac95c py: Use mp_uint_t where appropriate in stream functions. 2014-10-24 11:26:12 +00:00
Damien George
e294bee45b stmhal: Use stream's readinto. 2014-10-24 11:19:01 +00:00
Damien George
e5b1b7348a stmhal: Fix pin af definition: TIM2_CH1_ETR -> TIM2_CH1/TIM2_ETR. 2014-10-23 22:07:24 +01:00
Paul Sokolovsky
e2f8d98525 stream: Add optional 2nd "length" arg to .readinto() - extension to CPython.
While extension to file.readinto() definition of CPython, the additional arg
is similar to what in CPython available in socket.recv_into().
2014-10-23 21:43:59 +03:00
Damien George
185cb0d943 stmhal: Use OSError with POSIX error code for HAL errors.
Addresses issue #921.
2014-10-23 14:25:32 +01:00
Damien George
e7bb0443cd py: Properly free string parse-node; add assertion to gc_free. 2014-10-23 14:13:05 +01:00
Damien George
dd4f4530ab py: Add builtin memoryview object (mostly using array code). 2014-10-23 13:34:35 +01:00
Damien George
3aa09f5784 py: Use MP_OBJ_NULL instead of NULL in a few places. 2014-10-23 12:06:53 +01:00
Damien George
37378f8a9d py: Clean up edge cases of malloc/realloc/free. 2014-10-23 12:02:00 +01:00
Damien George
f5d69794a8 extmod: Add uheapq module. 2014-10-22 23:20:15 +01:00
Damien George
e72be1b999 py: Fix smallint modulo with negative arguments.
Addresses issue #927.
2014-10-22 23:05:50 +01:00
Damien George
5fc42a6c97 tools, pydfu: Some fixes to support Python 3. 2014-10-22 20:27:43 +01:00
Dave Hylands
842210f53a Add pydfu.py to the micropython tree. Use dfu_util bgy default
You can do:

make USE_PYDFU=1 deploy

to use pydfu.py
2014-10-22 20:18:38 +01:00
Damien George
e7a478204a py: Remove unused and unneeded SystemError exception.
It's purpose is for internal errors that are not catastrophic (ie not as
bad as RuntimeError).  Since we don't use it, we don't need it.
2014-10-22 19:42:55 +01:00
Damien George
efa04eafd3 stmhal: Add MMA_INT/PB2 to available pins on PYBV10.
This allows you to register ExtInt on the MMA interrupt pin.
2014-10-22 19:31:27 +01:00
Dave Hylands
d46a822262 Fixed TIM2_CH1 definition.
TIM2_CH1_ETR is really bundling 2 functions to the same pin:
TIM2_CH1 (where its used as a channel)
TIM2_ETR (where iss used as an external trigger).

I fixed most of these a while back, but it looks like I missed this one.
2014-10-22 19:16:51 +01:00
Damien George
3be6984b8f stmhal: Don't return SystemExit value from parse_compile_execute.
There is no need, since we don't (currently) use the value.
2014-10-22 19:14:20 +01:00
Dave Hylands
8d62bbd46a Add pyb.hard_reset, and make sys.exit() or raise SystemExit do a soft reset. 2014-10-22 19:14:20 +01:00
Damien George
3e42570538 stmhal: Change cc3k.recv to only make 1 call to underlying recv().
Also make cc3k.send and cc3k.recv independent functions (not wrapped by
stream write/read).  Also make wiznet5k.recv more memory efficient.

This might address issue #920.
2014-10-22 01:10:53 +01:00
81 changed files with 2188 additions and 772 deletions

View File

@@ -13,6 +13,7 @@
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)

View File

@@ -5,6 +5,11 @@ Micro Python documentation and references
Here you can find documentation for Micro Python and the pyboard.
.. toctree::
:maxdepth: 1
quickref.rst
Software
--------

127
docs/quickref.rst Normal file
View File

@@ -0,0 +1,127 @@
Quick reference for the pyboard
=====================================
.. image:: http://micropython.org/static/resources/pybv10-pinout.jpg
:alt: AMP skin
:width: 700px
General board control
---------------------
::
import pyb
pyb.delay(50) # wait 50 milliseconds
pyb.millis() # number of milliseconds since bootup
pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1)
pyb.wfi() # pause CPU, waiting for interrupt
pyb.freq() # get CPU and bus frequencies
pyb.freq(60000000) # set CPU freq to 60MHz
pyb.stop() # stop CPU, waiting for external interrupt
LEDs
----
::
from pyb import LED
led = LED(1) # red led
led.toggle()
led.on()
led.off()
Pins and GPIO
-------------
::
from pyb import Pin
p_out = Pin('X1', Pin.OUT_PP)
p_out.high()
p_out.low()
p_in = Pin('X2', Pin.IN, Pin.PULL_UP)
p_in.value() # get value, 0 or 1
External interrupts
-------------------
::
from pyb import Pin, ExtInt
callback = lambda e: print("intr")
ext = ExtInt(Pin('Y1'), ExtInt.IRQ_RISING, Pin.PULL_NONE, callback)
Timers
------
::
from pyb import Timer
tim = Timer(1, freq=1000)
tim.counter() # get counter value
tim.freq(0.5) # 0.5 Hz
tim.callback(lambda t: pyb.LED(1).toggle())
PWM (pulse width modulation)
----------------------------
::
from pyb import Pin, Timer
p = Pin('X1') # X1 has TIM2, CH1
tim = Timer(2, freq=1000)
ch = tim.channel(1, Timer.PWM, pin=p)
ch.pulse_width_percent(50)
ADC (analog to digital conversion)
----------------------------------
::
from pyb import Pin, ADC
adc = ADC(Pin('X19'))
adc.read() # read value, 0-4095
DAC (digital to analog conversion)
----------------------------------
::
from pyb import Pin, DAC
dac = DAC(Pin('X5'))
dac.write(120) # output between 0 and 255
UART (serial bus)
-----------------
::
from pyb import UART
uart = UART(1, 9600)
uart.write('hello')
uart.read(5) # read up to 5 bytes
SPI bus
-------
::
from pyb import SPI
spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0)
spi.send('hello')
spi.recv(5) # receive 5 bytes on the bus
spi.send_recv('hello') # send a receive 5 bytes
I2C bus
-------
::
from pyb import I2C
i2c = I2C(1, I2C.MASTER, baudrate=100000)
i2c.scan() # returns list of slave addresses
i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42
i2c.recv(5, 0x42) # receive 5 bytes from slave
i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10
i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10

View File

@@ -19,7 +19,7 @@ while True:
if switch():
pyb.delay(200) # delay avoids detection of multiple presses
blue.on() # blue LED indicates file open
log = open('1:/log.csv', 'w') # open file on SD (SD: '1:/', flash: '0/)
log = open('/sd/log.csv', 'w') # open file on SD (SD: '/sd/', flash: '/flash/)
# until switch is pressed again
while not switch():

138
extmod/moduheapq.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <unistd.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "objlist.h"
#include "runtime0.h"
#include "runtime.h"
#if MICROPY_PY_UHEAPQ
// the algorithm here is modelled on CPython's heapq.py
STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "heap must be a list"));
}
return heap_in;
}
STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
mp_obj_t item = heap->items[pos];
while (pos > start_pos) {
mp_uint_t parent_pos = (pos - 1) >> 1;
mp_obj_t parent = heap->items[parent_pos];
if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
heap->items[pos] = parent;
pos = parent_pos;
} else {
break;
}
}
heap->items[pos] = item;
}
STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
mp_uint_t start_pos = pos;
mp_uint_t end_pos = heap->len;
mp_obj_t item = heap->items[pos];
for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
// choose right child if it's <= left child
if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
child_pos += 1;
}
// bubble up the smaller child
heap->items[pos] = heap->items[child_pos];
pos = child_pos;
}
heap->items[pos] = item;
heap_siftdown(heap, start_pos, pos);
}
STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
mp_obj_list_t *heap = get_heap(heap_in);
mp_obj_list_append(heap, item);
heap_siftdown(heap, 0, heap->len - 1);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
mp_obj_list_t *heap = get_heap(heap_in);
if (heap->len == 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
}
mp_obj_t item = heap->items[0];
heap->len -= 1;
heap->items[0] = heap->items[heap->len];
heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
if (heap->len) {
heap_siftup(heap, 0);
}
return item;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
mp_obj_list_t *heap = get_heap(heap_in);
for (mp_uint_t i = heap->len / 2; i > 0;) {
heap_siftup(heap, --i);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
STATIC const mp_map_elem_t mp_module_uheapq_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uheapq) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappush), (mp_obj_t)&mod_uheapq_heappush_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappop), (mp_obj_t)&mod_uheapq_heappop_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapify), (mp_obj_t)&mod_uheapq_heapify_obj },
};
STATIC const mp_obj_dict_t mp_module_uheapq_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
.table = (mp_map_elem_t*)mp_module_uheapq_globals_table,
},
};
const mp_obj_module_t mp_module_uheapq = {
.base = { &mp_type_module },
.name = MP_QSTR_uheapq,
.globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
};
#endif //MICROPY_PY_UHEAPQ

20
py/bc.c
View File

@@ -93,7 +93,6 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
// usage for the common case of positional only args.
mp_obj_fun_bc_t *self = self_in;
mp_uint_t n_state = code_state->n_state;
const byte *ip = code_state->ip;
code_state->code_info = self->bytecode;
code_state->sp = &code_state->state[0] - 1;
@@ -153,13 +152,21 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
*var_pos_kw_args = dict;
}
// get pointer to arg_names array at start of bytecode prelude
const mp_obj_t *arg_names;
{
const byte *code_info = code_state->code_info;
mp_uint_t code_info_size = mp_decode_uint(&code_info);
arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
}
for (mp_uint_t i = 0; i < n_kw; i++) {
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
mp_obj_t wanted_arg_name = kwargs[2 * i];
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
if (arg_name == self->args[j]) {
if (wanted_arg_name == arg_names[j]) {
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function got multiple values for argument '%s'", qstr_str(arg_name)));
"function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
}
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
goto continue2;
@@ -202,13 +209,13 @@ continue2:;
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
mp_map_elem_t *elem = NULL;
if (self->has_def_kw_args) {
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, arg_names[self->n_pos_args + i], MP_MAP_LOOKUP);
}
if (elem != NULL) {
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
"function missing required keyword argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(arg_names[self->n_pos_args + i]))));
}
}
}
@@ -225,6 +232,7 @@ continue2:;
}
// bytecode prelude: initialise closed over variables
const byte *ip = code_state->ip;
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
mp_uint_t local_num = *ip++;
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);

View File

@@ -53,7 +53,7 @@ mp_uint_t mp_decode_uint(const byte **ptr);
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len);
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
void mp_bytecode_print2(const byte *code, mp_uint_t len);
// Helper macros to access pointer with least significant bit holding a flag

152
py/bc0.h
View File

@@ -31,92 +31,90 @@
#define MP_BC_LOAD_CONST_NONE (0x11)
#define MP_BC_LOAD_CONST_TRUE (0x12)
#define MP_BC_LOAD_CONST_ELLIPSIS (0x13)
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // 24-bit, in excess
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int
#define MP_BC_LOAD_CONST_INT (0x15) // qstr
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
#define MP_BC_LOAD_CONST_BYTES (0x18) // qstr
#define MP_BC_LOAD_CONST_STRING (0x19) // qstr
#define MP_BC_LOAD_NULL (0x1a)
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
#define MP_BC_LOAD_NULL (0x19)
#define MP_BC_LOAD_FAST_0 (0x20)
#define MP_BC_LOAD_FAST_1 (0x21)
#define MP_BC_LOAD_FAST_2 (0x22)
#define MP_BC_LOAD_FAST_N (0x23) // uint
#define MP_BC_LOAD_DEREF (0x25) // uint
#define MP_BC_LOAD_NAME (0x26) // qstr
#define MP_BC_LOAD_GLOBAL (0x27) // qstr
#define MP_BC_LOAD_ATTR (0x28) // qstr
#define MP_BC_LOAD_METHOD (0x29) // qstr
#define MP_BC_LOAD_BUILD_CLASS (0x2a)
#define MP_BC_LOAD_SUBSCR (0x2b)
#define MP_BC_LOAD_FAST_N (0x1a) // uint
#define MP_BC_LOAD_DEREF (0x1b) // uint
#define MP_BC_LOAD_NAME (0x1c) // qstr
#define MP_BC_LOAD_GLOBAL (0x1d) // qstr
#define MP_BC_LOAD_ATTR (0x1e) // qstr
#define MP_BC_LOAD_METHOD (0x1f) // qstr
#define MP_BC_LOAD_BUILD_CLASS (0x20)
#define MP_BC_LOAD_SUBSCR (0x21)
#define MP_BC_STORE_FAST_0 (0x30)
#define MP_BC_STORE_FAST_1 (0x31)
#define MP_BC_STORE_FAST_2 (0x32)
#define MP_BC_STORE_FAST_N (0x33) // uint
#define MP_BC_STORE_DEREF (0x34) // uint
#define MP_BC_STORE_NAME (0x35) // qstr
#define MP_BC_STORE_GLOBAL (0x36) // qstr
#define MP_BC_STORE_ATTR (0x37) // qstr
#define MP_BC_STORE_SUBSCR (0x38)
#define MP_BC_STORE_FAST_N (0x22) // uint
#define MP_BC_STORE_DEREF (0x23) // uint
#define MP_BC_STORE_NAME (0x24) // qstr
#define MP_BC_STORE_GLOBAL (0x25) // qstr
#define MP_BC_STORE_ATTR (0x26) // qstr
#define MP_BC_STORE_SUBSCR (0x27)
#define MP_BC_DELETE_FAST (0x39) // uint
#define MP_BC_DELETE_DEREF (0x3a) // uint
#define MP_BC_DELETE_NAME (0x3b) // qstr
#define MP_BC_DELETE_GLOBAL (0x3c) // qstr
#define MP_BC_DELETE_FAST (0x28) // uint
#define MP_BC_DELETE_DEREF (0x29) // uint
#define MP_BC_DELETE_NAME (0x2a) // qstr
#define MP_BC_DELETE_GLOBAL (0x2b) // qstr
#define MP_BC_DUP_TOP (0x40)
#define MP_BC_DUP_TOP_TWO (0x41)
#define MP_BC_POP_TOP (0x42)
#define MP_BC_ROT_TWO (0x43)
#define MP_BC_ROT_THREE (0x44)
#define MP_BC_DUP_TOP (0x30)
#define MP_BC_DUP_TOP_TWO (0x31)
#define MP_BC_POP_TOP (0x32)
#define MP_BC_ROT_TWO (0x33)
#define MP_BC_ROT_THREE (0x34)
#define MP_BC_JUMP (0x45) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_POP_JUMP_IF_TRUE (0x46) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned
#define MP_BC_WITH_CLEANUP (0x4e)
#define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned
#define MP_BC_SETUP_FINALLY (0x50) // rel byte code offset, 16-bit unsigned
#define MP_BC_END_FINALLY (0x51)
#define MP_BC_GET_ITER (0x52)
#define MP_BC_FOR_ITER (0x53) // rel byte code offset, 16-bit unsigned
#define MP_BC_POP_BLOCK (0x54)
#define MP_BC_POP_EXCEPT (0x55)
#define MP_BC_UNWIND_JUMP (0x56) // rel byte code offset, 16-bit signed, in excess; then a byte
#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess
#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned
#define MP_BC_WITH_CLEANUP (0x3e)
#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned
#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned
#define MP_BC_END_FINALLY (0x41)
#define MP_BC_GET_ITER (0x42)
#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned
#define MP_BC_POP_BLOCK (0x44)
#define MP_BC_POP_EXCEPT (0x45)
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
#define MP_BC_NOT (0x60)
#define MP_BC_UNARY_OP (0x61) // byte
#define MP_BC_BINARY_OP (0x62) // byte
#define MP_BC_NOT (0x47)
#define MP_BC_BUILD_TUPLE (0x70) // uint
#define MP_BC_BUILD_LIST (0x71) // uint
#define MP_BC_LIST_APPEND (0x72) // uint
#define MP_BC_BUILD_MAP (0x73) // uint
#define MP_BC_STORE_MAP (0x74)
#define MP_BC_MAP_ADD (0x75) // uint
#define MP_BC_BUILD_SET (0x76) // uint
#define MP_BC_SET_ADD (0x77) // uint
#define MP_BC_BUILD_SLICE (0x78) // uint
#define MP_BC_UNPACK_SEQUENCE (0x79) // uint
#define MP_BC_UNPACK_EX (0x7a) // uint
#define MP_BC_BUILD_TUPLE (0x50) // uint
#define MP_BC_BUILD_LIST (0x51) // uint
#define MP_BC_LIST_APPEND (0x52) // uint
#define MP_BC_BUILD_MAP (0x53) // uint
#define MP_BC_STORE_MAP (0x54)
#define MP_BC_MAP_ADD (0x55) // uint
#define MP_BC_BUILD_SET (0x56) // uint
#define MP_BC_SET_ADD (0x57) // uint
#define MP_BC_BUILD_SLICE (0x58) // uint
#define MP_BC_UNPACK_SEQUENCE (0x59) // uint
#define MP_BC_UNPACK_EX (0x5a) // uint
#define MP_BC_RETURN_VALUE (0x80)
#define MP_BC_RAISE_VARARGS (0x81) // byte
#define MP_BC_YIELD_VALUE (0x82)
#define MP_BC_YIELD_FROM (0x83)
#define MP_BC_RETURN_VALUE (0x5b)
#define MP_BC_RAISE_VARARGS (0x5c) // byte
#define MP_BC_YIELD_VALUE (0x5d)
#define MP_BC_YIELD_FROM (0x5e)
#define MP_BC_MAKE_FUNCTION (0x90) // uint
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x91) // uint
#define MP_BC_MAKE_CLOSURE (0x92) // uint
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x93) // uint
#define MP_BC_CALL_FUNCTION (0x94) // uint
#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint
#define MP_BC_CALL_METHOD (0x96) // uint
#define MP_BC_CALL_METHOD_VAR_KW (0x97) // uint
#define MP_BC_MAKE_FUNCTION (0x60) // uint
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint
#define MP_BC_MAKE_CLOSURE (0x62) // uint
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint
#define MP_BC_CALL_FUNCTION (0x64) // uint
#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint
#define MP_BC_CALL_METHOD (0x66) // uint
#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint
#define MP_BC_IMPORT_NAME (0xe0) // qstr
#define MP_BC_IMPORT_FROM (0xe1) // qstr
#define MP_BC_IMPORT_STAR (0xe2)
#define MP_BC_IMPORT_NAME (0x68) // qstr
#define MP_BC_IMPORT_FROM (0x69) // qstr
#define MP_BC_IMPORT_STAR (0x6a)
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)

View File

@@ -33,6 +33,7 @@
#include "qstr.h"
#include "obj.h"
#include "objstr.h"
#include "smallint.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
@@ -253,8 +254,8 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
}
mp_obj_t args[2];
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
args[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(i1, i2));
args[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(i1, i2));
return mp_obj_new_tuple(2, args);
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {

View File

@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args);
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
@@ -35,6 +35,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
@@ -91,3 +92,4 @@ extern const mp_obj_module_t mp_module_uctypes;
extern const mp_obj_module_t mp_module_uzlib;
extern const mp_obj_module_t mp_module_ujson;
extern const mp_obj_module_t mp_module_ure;
extern const mp_obj_module_t mp_module_uheapq;

View File

@@ -34,19 +34,87 @@
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
#include "objfun.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) {
#if MICROPY_PY_BUILTINS_COMPILE
typedef struct _mp_obj_code_t {
mp_obj_base_t base;
mp_obj_t module_fun;
} mp_obj_code_t;
STATIC const mp_obj_type_t mp_type_code = {
{ &mp_type_type },
.name = MP_QSTR_code,
};
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t locals) {
// save context and set new context
mp_obj_dict_t *old_globals = mp_globals_get();
mp_obj_dict_t *old_locals = mp_locals_get();
mp_globals_set(globals);
mp_locals_set(locals);
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
// the correct one
if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) {
mp_obj_fun_bc_t *fun_bc = self->module_fun;
fun_bc->globals = globals;
}
// execute code
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t ret = mp_call_function_0(self->module_fun);
nlr_pop();
mp_globals_set(old_globals);
mp_locals_set(old_locals);
return ret;
} else {
// exception; restore context and re-raise same exception
mp_globals_set(old_globals);
mp_locals_set(old_locals);
nlr_raise(nlr.ret_val);
}
}
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
// get the source
mp_uint_t str_len;
const char *str = mp_obj_str_get_data(args[0], &str_len);
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
// get the filename
qstr filename = mp_obj_str_get_qstr(args[1]);
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0);
// get the compile mode
qstr mode = mp_obj_str_get_qstr(args[2]);
mp_parse_input_kind_t parse_input_kind;
switch (mode) {
case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break;
case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break;
case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break;
default:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode"));
}
mp_obj_code_t *code = m_new_obj(mp_obj_code_t);
code->base.type = &mp_type_code;
code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL);
return code;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile);
#endif // MICROPY_PY_BUILTINS_COMPILE
STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) {
// work out the context
mp_obj_dict_t *globals = mp_globals_get();
mp_obj_dict_t *locals = mp_locals_get();
@@ -59,6 +127,18 @@ STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_pars
}
}
#if MICROPY_PY_BUILTINS_COMPILE
if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) {
return code_execute(args[0], globals, locals);
}
#endif
mp_uint_t str_len;
const char *str = mp_obj_str_get_data(args[0], &str_len);
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);
}

View File

@@ -55,6 +55,12 @@
#define PATH_SEP_CHAR '/'
bool mp_obj_is_package(mp_obj_t module) {
mp_obj_t dest[2];
mp_load_method_maybe(module, MP_QSTR___path__, dest);
return dest[0] != MP_OBJ_NULL;
}
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
//printf("stat %s\n", vstr_str(path));
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
@@ -122,7 +128,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
}
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
#if DEBUG_PRINT
DEBUG_printf("__import__:\n");
for (mp_uint_t i = 0; i < n_args; i++) {
@@ -280,6 +286,14 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
module_obj = mp_obj_new_module(mod_name);
// if args[3] (fromtuple) has magic value False, set up
// this module for command-line "-m" option (set module's
// name to __main__ instead of real name).
if (i == mod_len && fromtuple == mp_const_false) {
mp_obj_module_t *o = module_obj;
mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
}
if (stat == MP_IMPORT_STAT_DIR) {
DEBUG_printf("%s is dir\n", vstr_str(&path));
// https://docs.python.org/3/reference/import.html

View File

@@ -61,6 +61,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
#if MICROPY_PY_BUILTINS_MEMORYVIEW
{ MP_OBJ_NEW_QSTR(MP_QSTR_memoryview), (mp_obj_t)&mp_type_memoryview },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
#if MICROPY_PY_BUILTINS_PROPERTY
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
@@ -88,6 +91,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
#if MICROPY_PY_BUILTINS_COMPILE
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mp_builtin_compile_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_divmod), (mp_obj_t)&mp_builtin_divmod_obj },
@@ -136,7 +142,6 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_RuntimeError), (mp_obj_t)&mp_type_RuntimeError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
@@ -212,6 +217,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_URE
{ MP_OBJ_NEW_QSTR(MP_QSTR_ure), (mp_obj_t)&mp_module_ure },
#endif
#if MICROPY_PY_UHEAPQ
{ MP_OBJ_NEW_QSTR(MP_QSTR_uheapq), (mp_obj_t)&mp_module_uheapq },
#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES

View File

@@ -218,6 +218,13 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, mp_uint_t val) {
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
}
STATIC void emit_write_bytecode_prealigned_ptr(emit_t* emit, void *ptr) {
mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
// Verify thar c is already uint-aligned
assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
*c = (mp_uint_t)ptr;
}
// aligns the pointer so it is friendly to GC
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
emit_write_bytecode_byte(emit, b);
@@ -294,7 +301,16 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
emit_write_code_info_qstr(emit, scope->simple_name);
emit_write_code_info_qstr(emit, scope->source_file);
// bytecode prelude: local state size and exception stack size; 16 bit uints for now
// bytecode prelude: argument names (needed to resolve positional args passed as keywords)
// we store them as full word-sized objects for efficient access in mp_setup_code_state
// this is the start of the prelude and is guaranteed to be aligned on a word boundary
{
for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(scope->id_info[i].qst));
}
}
// bytecode prelude: local state size and exception stack size
{
mp_uint_t n_state = scope->num_locals + scope->stack_size;
if (n_state == 0) {
@@ -358,13 +374,9 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
} else if (emit->pass == MP_PASS_EMIT) {
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
arg_names[i] = emit->scope->id_info[i].qst;
}
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
emit->code_info_size + emit->bytecode_size,
emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
emit->scope->num_pos_args, emit->scope->num_kwonly_args,
emit->scope->scope_flags);
}
}
@@ -457,7 +469,11 @@ 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, mp_int_t arg) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
if (-16 <= arg && arg <= 47) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg);
} else {
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
}
}
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qst) {
@@ -487,11 +503,10 @@ STATIC void emit_bc_load_null(emit_t *emit) {
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, 1);
switch (local_num) {
case 0: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_0); break;
case 1: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_1); break;
case 2: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_2); break;
default: emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
if (local_num <= 15) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num);
} else {
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num);
}
}
@@ -533,11 +548,10 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, -1);
switch (local_num) {
case 0: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_0); break;
case 1: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_1); break;
case 2: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_2); break;
default: emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); break;
if (local_num <= 15) {
emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
} else {
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num);
}
}
@@ -712,12 +726,12 @@ STATIC void emit_bc_pop_except(emit_t *emit) {
STATIC void emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
if (op == MP_UNARY_OP_NOT) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, MP_UNARY_OP_BOOL);
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_BOOL);
emit_bc_pre(emit, 0);
emit_write_bytecode_byte(emit, MP_BC_NOT);
} else {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, op);
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op);
}
}
@@ -731,7 +745,7 @@ STATIC void emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
op = MP_BINARY_OP_IS;
}
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_byte(emit, MP_BC_BINARY_OP, op);
emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op);
if (invert) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte(emit, MP_BC_NOT);

View File

@@ -55,33 +55,20 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
return rc;
}
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) {
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags) {
rc->kind = MP_CODE_BYTECODE;
rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args;
rc->n_kwonly_args = n_kwonly_args;
rc->arg_names = arg_names;
rc->u_byte.code = code;
rc->u_byte.len = len;
#ifdef DEBUG_PRINT
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
DEBUG_printf(" arg names:");
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
DEBUG_printf(" %s", qstr_str(arg_names[i]));
}
DEBUG_printf("\n");
#endif
#if MICROPY_DEBUG_PRINTERS
if (mp_verbose_flag > 0) {
for (mp_uint_t i = 0; i < len; i++) {
if (i > 0 && i % 16 == 0) {
printf("\n");
}
printf(" %02x", code[i]);
}
printf("\n");
mp_bytecode_print(rc, code, len);
if (mp_verbose_flag >= 2) {
mp_bytecode_print(rc, n_pos_args + n_kwonly_args, code, len);
}
#endif
}
@@ -128,7 +115,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
mp_obj_t fun;
switch (rc->kind) {
case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
break;
#if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:

View File

@@ -35,12 +35,11 @@ typedef enum {
MP_CODE_NATIVE_ASM,
} mp_raw_code_kind_t;
typedef struct _mp_code_t {
typedef struct _mp_raw_code_t {
mp_raw_code_kind_t kind : 3;
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
mp_uint_t n_kwonly_args : 11;
qstr *arg_names;
union {
struct {
byte *code;
@@ -55,7 +54,7 @@ typedef struct _mp_code_t {
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);

45
py/gc.c
View File

@@ -484,11 +484,15 @@ void gc_free(void *ptr_in) {
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
} else {
assert(!"bad free");
}
} else if (ptr_in != NULL) {
assert(!"bad free");
}
}
mp_uint_t gc_nbytes(void *ptr_in) {
mp_uint_t gc_nbytes(const void *ptr_in) {
mp_uint_t ptr = (mp_uint_t)ptr_in;
if (VERIFY_PTR(ptr)) {
@@ -546,6 +550,12 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
return gc_alloc(n_bytes, false);
}
// check for pure free
if (n_bytes == 0) {
gc_free(ptr_in);
return NULL;
}
mp_uint_t ptr = (mp_uint_t)ptr_in;
// sanity check the ptr
@@ -671,31 +681,32 @@ void gc_dump_alloc_table(void) {
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
if (bl % DUMP_BYTES_PER_LINE == 0) {
// a new line of blocks
#if EXTENSIVE_HEAP_PROFILING
{
// check if this line contains only free blocks
bool only_free_blocks = true;
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
if (ATB_GET_KIND(bl2) != AT_FREE) {
only_free_blocks = false;
mp_uint_t bl2 = bl;
while (bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
bl2++;
}
if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {
// there are at least 2 lines containing only free blocks, so abbreviate their printing
printf("\n (" UINT_FMT " lines all free)", (bl2 - bl) / DUMP_BYTES_PER_LINE);
bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));
if (bl >= gc_alloc_table_byte_len * BLOCKS_PER_ATB) {
// got to end of heap
break;
}
}
if (only_free_blocks) {
// line contains only free blocks, so skip printing it
bl += DUMP_BYTES_PER_LINE - 1;
continue;
}
}
#endif
// print header for new line of blocks
printf("\n%04x: ", (uint)bl);
#if EXTENSIVE_HEAP_PROFILING
printf("\n%05x: ", (uint)(bl * BYTES_PER_BLOCK) & 0xfffff);
#else
printf("\n%05x: ", (uint)PTR_FROM_BLOCK(bl) & 0xfffff);
#endif
}
int c = ' ';
switch (ATB_GET_KIND(bl)) {
case AT_FREE: c = '.'; break;
case AT_HEAD: c = 'h'; break;
/* this prints out if the object is reachable from BSS or STACK (for unix only)
case AT_HEAD: {
extern char __bss_start, _end;
@@ -724,7 +735,7 @@ void gc_dump_alloc_table(void) {
break;
}
*/
/* this prints the uPy object type of the head block
/* this prints the uPy object type of the head block */
case AT_HEAD: {
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
@@ -732,10 +743,10 @@ void gc_dump_alloc_table(void) {
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; }
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
else if (*ptr == (mp_uint_t)&mp_type_module) { c = 'M'; }
else { c = 'h'; }
break;
}
*/
case AT_TAIL: c = 't'; break;
case AT_MARK: c = 'm'; break;
}

View File

@@ -40,7 +40,7 @@ void gc_collect_end(void);
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
void gc_free(void *ptr);
mp_uint_t gc_nbytes(void *ptr);
mp_uint_t gc_nbytes(const void *ptr);
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
typedef struct _gc_info_t {

View File

@@ -63,11 +63,8 @@ STATIC size_t peak_bytes_allocated = 0;
#endif // MICROPY_ENABLE_GC
void *m_malloc(size_t num_bytes) {
if (num_bytes == 0) {
return NULL;
}
void *ptr = malloc(num_bytes);
if (ptr == NULL) {
if (ptr == NULL && num_bytes != 0) {
return m_malloc_fail(num_bytes);
}
#if MICROPY_MEM_STATS
@@ -81,9 +78,6 @@ void *m_malloc(size_t num_bytes) {
void *m_malloc_maybe(size_t num_bytes) {
void *ptr = malloc(num_bytes);
if (ptr == NULL) {
return NULL;
}
#if MICROPY_MEM_STATS
total_bytes_allocated += num_bytes;
current_bytes_allocated += num_bytes;
@@ -95,11 +89,8 @@ void *m_malloc_maybe(size_t num_bytes) {
#if MICROPY_ENABLE_FINALISER
void *m_malloc_with_finaliser(size_t num_bytes) {
if (num_bytes == 0) {
return NULL;
}
void *ptr = malloc_with_finaliser(num_bytes);
if (ptr == NULL) {
if (ptr == NULL && num_bytes != 0) {
return m_malloc_fail(num_bytes);
}
#if MICROPY_MEM_STATS
@@ -114,19 +105,16 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
void *m_malloc0(size_t num_bytes) {
void *ptr = m_malloc(num_bytes);
if (ptr != NULL) {
memset(ptr, 0, num_bytes);
if (ptr == NULL && num_bytes != 0) {
return m_malloc_fail(num_bytes);
}
memset(ptr, 0, num_bytes);
return ptr;
}
void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
if (new_num_bytes == 0) {
free(ptr);
return NULL;
}
void *new_ptr = realloc(ptr, new_num_bytes);
if (new_ptr == NULL) {
if (new_ptr == NULL && new_num_bytes != 0) {
return m_malloc_fail(new_num_bytes);
}
#if MICROPY_MEM_STATS
@@ -146,28 +134,26 @@ void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
void *new_ptr = realloc(ptr, new_num_bytes);
if (new_ptr == NULL) {
return NULL;
}
#if MICROPY_MEM_STATS
// At first thought, "Total bytes allocated" should only grow,
// after all, it's *total*. But consider for example 2K block
// shrunk to 1K and then grown to 2K again. It's still 2K
// allocated total. If we process only positive increments,
// we'll count 3K.
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
UPDATE_PEAK();
// Also, don't count failed reallocs.
if (!(new_ptr == NULL && new_num_bytes != 0)) {
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
UPDATE_PEAK();
}
#endif
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
return new_ptr;
}
void m_free(void *ptr, size_t num_bytes) {
if (ptr != NULL) {
free(ptr);
}
free(ptr);
#if MICROPY_MEM_STATS
current_bytes_allocated -= num_bytes;
#endif

View File

@@ -287,6 +287,11 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#endif
// Whether to support memoryview object
#ifndef MICROPY_PY_BUILTINS_MEMORYVIEW
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#endif
// Whether to support set object
#ifndef MICROPY_PY_BUILTINS_SET
#define MICROPY_PY_BUILTINS_SET (1)
@@ -307,6 +312,11 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_PROPERTY (1)
#endif
// Whether to support compile function
#ifndef MICROPY_PY_BUILTINS_COMPILE
#define MICROPY_PY_BUILTINS_COMPILE (0)
#endif
// Whether to set __file__ for imported modules
#ifndef MICROPY_PY___FILE__
#define MICROPY_PY___FILE__ (1)
@@ -403,6 +413,10 @@ typedef double mp_float_t;
#define MICROPY_PY_URE (0)
#endif
#ifndef MICROPY_PY_UHEAPQ
#define MICROPY_PY_UHEAPQ (0)
#endif
/*****************************************************************************/
/* Hooks for a port to add builtins */

View File

@@ -292,6 +292,7 @@ extern const mp_obj_type_t mp_type_int;
extern const mp_obj_type_t mp_type_str;
extern const mp_obj_type_t mp_type_bytes;
extern const mp_obj_type_t mp_type_bytearray;
extern const mp_obj_type_t mp_type_memoryview;
extern const mp_obj_type_t mp_type_float;
extern const mp_obj_type_t mp_type_complex;
extern const mp_obj_type_t mp_type_tuple;
@@ -329,6 +330,7 @@ extern const mp_obj_type_t mp_type_GeneratorExit;
extern const mp_obj_type_t mp_type_ImportError;
extern const mp_obj_type_t mp_type_IndentationError;
extern const mp_obj_type_t mp_type_IndexError;
extern const mp_obj_type_t mp_type_KeyboardInterrupt;
extern const mp_obj_type_t mp_type_KeyError;
extern const mp_obj_type_t mp_type_LookupError;
extern const mp_obj_type_t mp_type_MemoryError;
@@ -339,7 +341,6 @@ extern const mp_obj_type_t mp_type_OverflowError;
extern const mp_obj_type_t mp_type_RuntimeError;
extern const mp_obj_type_t mp_type_StopIteration;
extern const mp_obj_type_t mp_type_SyntaxError;
extern const mp_obj_type_t mp_type_SystemError;
extern const mp_obj_type_t mp_type_SystemExit;
extern const mp_obj_type_t mp_type_TypeError;
extern const mp_obj_type_t mp_type_ValueError;
@@ -383,7 +384,7 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
@@ -529,7 +530,6 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
// array
mp_uint_t mp_obj_array_len(mp_obj_t self_in);
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items);
// functions
@@ -556,6 +556,8 @@ typedef struct _mp_obj_module_t {
mp_obj_dict_t *globals;
} mp_obj_module_t;
mp_obj_dict_t *mp_obj_module_get_globals(mp_obj_t self_in);
// check if given module object is a package
bool mp_obj_is_package(mp_obj_t module);
// staticmethod and classmethod types; defined here so we can make const versions
// this structure is used for instances of both staticmethod and classmethod

View File

@@ -37,7 +37,28 @@
#include "runtime.h"
#include "binary.h"
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
#if MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW
// About memoryview object: We want to reuse as much code as possible from
// array, and keep the memoryview object 4 words in size so it fits in 1 GC
// block. Also, memoryview must keep a pointer to the base of the buffer so
// that the buffer is not GC'd if the original parent object is no longer
// around (we are assuming that all memoryview'able objects return a pointer
// which points to the start of a GC chunk). Given the above constraints we
// do the following:
// - typecode high bit is set if the buffer is read-write (else read-only)
// - free is the offset in elements to the first item in the memoryview
// - len is the length in elements
// - items points to the start of the original buffer
// Note that we don't handle the case where the original buffer might change
// size due to a resize of the original parent object.
// make (& TYPECODE_MASK) a null operation if memorview not enabled
#if MICROPY_PY_BUILTINS_MEMORYVIEW
#define TYPECODE_MASK (0x7f)
#else
#define TYPECODE_MASK (~(mp_uint_t)1)
#endif
typedef struct _mp_obj_array_t {
mp_obj_base_t base;
@@ -50,13 +71,13 @@ typedef struct _mp_obj_array_t {
} mp_obj_array_t;
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n);
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
/******************************************************************************/
/* array */
// array
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
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) {
@@ -77,7 +98,31 @@ STATIC void array_print(void (*print)(void *env, const char *fmt, ...), void *en
}
print(env, ")");
}
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
int typecode_size = mp_binary_get_size('@', typecode, NULL);
if (typecode_size <= 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
}
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
#if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY
o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
#elif MICROPY_PY_BUILTINS_BYTEARRAY
o->base.type = &mp_type_bytearray;
#else
o->base.type = &mp_type_array;
#endif
o->typecode = typecode;
o->free = 0;
o->len = n;
o->items = m_malloc(typecode_size * o->len);
return o;
}
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
uint len;
// Try to create array of exact len if initializer len is known
@@ -103,7 +148,9 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
return array;
}
#endif
#if MICROPY_PY_ARRAY
STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
@@ -119,7 +166,9 @@ STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
return array_construct(*typecode, args[1]);
}
}
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
@@ -137,6 +186,33 @@ STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
return array_construct(BYTEARRAY_TYPECODE, args[0]);
}
}
#endif
#if MICROPY_PY_BUILTINS_MEMORYVIEW
STATIC mp_obj_t memoryview_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// TODO possibly allow memoryview constructor to take start/stop so that one
// can do memoryview(b, 4, 8) instead of memoryview(b)[4:8] (uses less RAM)
mp_arg_check_num(n_args, n_kw, 1, 1, false);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
self->base.type = type_in;
self->typecode = bufinfo.typecode;
self->free = 0;
self->len = bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL); // element len
self->items = bufinfo.buf;
// test if the object can be written to
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
self->typecode |= 0x80; // used to indicate writable buffer
}
return self;
}
#endif
STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
mp_obj_array_t *o = o_in;
@@ -154,7 +230,7 @@ STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in)
mp_buffer_info_t rhs_bufinfo;
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
return mp_const_false;
return mp_const_false;
}
return MP_BOOL(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
}
@@ -202,21 +278,41 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
"only slices with step=1 (aka None) are supported"));
}
mp_obj_array_t *res = array_new(o->typecode, slice.stop - slice.start);
int sz = mp_binary_get_size('@', o->typecode, NULL);
mp_obj_array_t *res;
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
assert(sz > 0);
byte *p = o->items;
memcpy(res->items, p + slice.start * sz, (slice.stop - slice.start) * sz);
if (0) {
// dummy
#if MICROPY_PY_BUILTINS_MEMORYVIEW
} else if (o->base.type == &mp_type_memoryview) {
res = m_new_obj(mp_obj_array_t);
*res = *o;
res->free += slice.start;
res->len = slice.stop - slice.start;
#endif
} else {
res = array_new(o->typecode, slice.stop - slice.start);
memcpy(res->items, o->items + slice.start * sz, (slice.stop - slice.start) * sz);
}
return res;
#endif
} else {
mp_uint_t index = mp_get_index(o->base.type, o->len, index_in, false);
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (o->base.type == &mp_type_memoryview) {
index += o->free;
if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) {
// store to read-only memoryview
return MP_OBJ_NULL;
}
}
#endif
if (value == MP_OBJ_SENTINEL) {
// load
return mp_binary_get_val_array(o->typecode, o->items, index);
return mp_binary_get_val_array(o->typecode & TYPECODE_MASK, o->items, index);
} else {
// store
mp_binary_set_val_array(o->typecode, o->items, index, value);
mp_binary_set_val_array(o->typecode & TYPECODE_MASK, o->items, index, value);
return mp_const_none;
}
}
@@ -225,18 +321,31 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
mp_obj_array_t *o = o_in;
int sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
bufinfo->buf = o->items;
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
bufinfo->typecode = o->typecode;
bufinfo->len = o->len * sz;
bufinfo->typecode = o->typecode & TYPECODE_MASK;
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (o->base.type == &mp_type_memoryview) {
if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) {
// read-only memoryview
return 1;
}
bufinfo->buf += (mp_uint_t)o->free * sz;
}
#endif
return 0;
}
#if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY
STATIC const mp_map_elem_t array_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_append), (mp_obj_t)&array_append_obj },
};
STATIC MP_DEFINE_CONST_DICT(array_locals_dict, array_locals_dict_table);
#endif
#if MICROPY_PY_ARRAY
const mp_obj_type_t mp_type_array = {
{ &mp_type_type },
.name = MP_QSTR_array,
@@ -249,7 +358,9 @@ const mp_obj_type_t mp_type_array = {
.buffer_p = { .get_buffer = array_get_buffer },
.locals_dict = (mp_obj_t)&array_locals_dict,
};
#endif
#if MICROPY_PY_BUILTINS_BYTEARRAY
const mp_obj_type_t mp_type_bytearray = {
{ &mp_type_type },
.name = MP_QSTR_bytearray,
@@ -262,25 +373,28 @@ const mp_obj_type_t mp_type_bytearray = {
.buffer_p = { .get_buffer = array_get_buffer },
.locals_dict = (mp_obj_t)&array_locals_dict,
};
#endif
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
int typecode_size = mp_binary_get_size('@', typecode, NULL);
if (typecode_size <= 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
}
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;
o->typecode = typecode;
o->free = 0;
o->len = n;
o->items = m_malloc(typecode_size * o->len);
return o;
}
#if MICROPY_PY_BUILTINS_MEMORYVIEW
const mp_obj_type_t mp_type_memoryview = {
{ &mp_type_type },
.name = MP_QSTR_memoryview,
.make_new = memoryview_make_new,
.getiter = array_iterator_new,
.unary_op = array_unary_op,
.binary_op = array_binary_op,
.subscr = array_subscr,
.buffer_p = { .get_buffer = array_get_buffer },
};
#endif
/* unused
mp_uint_t mp_obj_array_len(mp_obj_t self_in) {
return ((mp_obj_array_t *)self_in)->len;
}
*/
#if MICROPY_PY_BUILTINS_BYTEARRAY
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
memcpy(o->items, items, n);
@@ -290,27 +404,29 @@ mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
// Create bytearray which references specified memory area
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items) {
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
o->base.type = &mp_type_array;
o->base.type = &mp_type_bytearray;
o->typecode = BYTEARRAY_TYPECODE;
o->free = 0;
o->len = n;
o->items = items;
return o;
}
#endif
/******************************************************************************/
/* array iterator */
// array iterator
typedef struct _mp_obj_array_it_t {
mp_obj_base_t base;
mp_obj_array_t *array;
mp_uint_t offset;
mp_uint_t cur;
} mp_obj_array_it_t;
STATIC mp_obj_t array_it_iternext(mp_obj_t self_in) {
mp_obj_array_it_t *self = self_in;
if (self->cur < self->array->len) {
return mp_binary_get_val_array(self->array->typecode, self->array->items, self->cur++);
return mp_binary_get_val_array(self->array->typecode & TYPECODE_MASK, self->array->items, self->offset + self->cur++);
} else {
return MP_OBJ_STOP_ITERATION;
}
@@ -325,11 +441,15 @@ STATIC const mp_obj_type_t array_it_type = {
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in) {
mp_obj_array_t *array = array_in;
mp_obj_array_it_t *o = m_new_obj(mp_obj_array_it_t);
mp_obj_array_it_t *o = m_new0(mp_obj_array_it_t, 1);
o->base.type = &array_it_type;
o->array = array;
o->cur = 0;
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (array->base.type == &mp_type_memoryview) {
o->offset = array->free;
}
#endif
return o;
}
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY
#endif // MICROPY_PY_ARRAY || MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_BUILTINS_MEMORYVIEW

View File

@@ -211,7 +211,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
// http://docs.python.org/3/library/exceptions.html
MP_DEFINE_EXCEPTION_BASE(BaseException)
MP_DEFINE_EXCEPTION(SystemExit, BaseException)
//MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(KeyboardInterrupt, BaseException)
MP_DEFINE_EXCEPTION(GeneratorExit, BaseException)
MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION_BASE(Exception)
@@ -268,7 +268,7 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
MP_DEFINE_EXCEPTION_BASE(IndentationError)
MP_DEFINE_EXCEPTION(TabError, IndentationError)
*/
MP_DEFINE_EXCEPTION(SystemError, Exception)
//MP_DEFINE_EXCEPTION(SystemError, Exception)
MP_DEFINE_EXCEPTION(TypeError, Exception)
MP_DEFINE_EXCEPTION(ValueError, Exception)
//TODO: Implement UnicodeErrors which take arguments

View File

@@ -173,7 +173,10 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
mp_uint_t code_info_size = mp_decode_uint(&code_info);
const byte *ip = self->bytecode + code_info_size;
// bytecode prelude: state size and exception stack size; 16 bit uints
// bytecode prelude: skip arg names
ip += (self->n_pos_args + self->n_kwonly_args) * sizeof(mp_obj_t);
// bytecode prelude: state size and exception stack size
mp_uint_t n_state = mp_decode_uint(&ip);
mp_uint_t n_exc_stack = mp_decode_uint(&ip);
@@ -268,7 +271,7 @@ const mp_obj_type_t mp_type_fun_bc = {
.binary_op = mp_obj_fun_binary_op,
};
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const byte *code) {
mp_uint_t n_def_args = 0;
mp_uint_t n_extra_args = 0;
mp_obj_tuple_t *def_args = def_args_in;
@@ -283,7 +286,6 @@ mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_ar
mp_obj_fun_bc_t *o = m_new_obj_var(mp_obj_fun_bc_t, mp_obj_t, n_extra_args);
o->base.type = &mp_type_fun_bc;
o->globals = mp_globals_get();
o->args = args;
o->n_pos_args = n_pos_args;
o->n_kwonly_args = n_kwonly_args;
o->n_def_args = n_def_args;

View File

@@ -27,14 +27,13 @@
typedef struct _mp_obj_fun_bc_t {
mp_obj_base_t base;
mp_obj_dict_t *globals; // the context within which this function was defined
mp_uint_t n_pos_args : 16; // number of arguments this function takes
mp_uint_t n_kwonly_args : 16; // number of arguments this function takes
mp_uint_t n_def_args : 16; // number of default arguments
mp_uint_t n_pos_args : 8; // number of arguments this function takes
mp_uint_t n_kwonly_args : 8; // number of keyword-only arguments this function takes
mp_uint_t n_def_args : 8; // number of default arguments
mp_uint_t has_def_kw_args : 1; // set if this function has default keyword args
mp_uint_t takes_var_args : 1; // set if this function takes variable args
mp_uint_t takes_kw_args : 1; // set if this function takes keyword args
const byte *bytecode; // bytecode for the function
qstr *args; // argument names (needed to resolve positional args passed as keywords)
// the following extra_args array is allocated space to take (in order):
// - values of positional default args (if any)
// - a single slot for default kw args dict (if it has them)

View File

@@ -62,6 +62,9 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw
mp_uint_t code_info_size = mp_decode_uint(&code_info);
const byte *ip = self_fun->bytecode + code_info_size;
// bytecode prelude: skip arg names
ip += (self_fun->n_pos_args + self_fun->n_kwonly_args) * sizeof(mp_obj_t);
// bytecode prelude: get state size and exception stack size
mp_uint_t n_state = mp_decode_uint(&ip);
mp_uint_t n_exc_stack = mp_decode_uint(&ip);

View File

@@ -215,7 +215,7 @@ STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k
mp_int_t len;
byte *data;
vstr_t *vstr = NULL;
mp_obj_t o = NULL;
mp_obj_t o = MP_OBJ_NULL;
// Try to create array of exact len if initializer len is known
mp_obj_t len_in = mp_obj_len_maybe(args[0]);
if (len_in == MP_OBJ_NULL) {

View File

@@ -292,7 +292,7 @@ mp_obj_t instance_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, c
o = new_ret;
// now call Python class __init__ function with all args
init_fn[0] = init_fn[1] = NULL;
init_fn[0] = init_fn[1] = MP_OBJ_NULL;
lookup.obj = o;
lookup.attr = MP_QSTR___init__;
lookup.meth_offset = 0;

View File

@@ -180,17 +180,17 @@ void mp_parse_node_free(mp_parse_node_t pn) {
mp_uint_t rule_id = MP_PARSE_NODE_STRUCT_KIND(pns);
if (rule_id == RULE_string) {
m_del(char, (char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]);
return;
}
bool adjust = ADD_BLANK_NODE(rule_id);
if (adjust) {
n--;
}
for (mp_uint_t i = 0; i < n; i++) {
mp_parse_node_free(pns->nodes[i]);
}
if (adjust) {
n++;
} else {
bool adjust = ADD_BLANK_NODE(rule_id);
if (adjust) {
n--;
}
for (mp_uint_t i = 0; i < n; i++) {
mp_parse_node_free(pns->nodes[i]);
}
if (adjust) {
n++;
}
}
m_del_var(mp_parse_node_struct_t, mp_parse_node_t, n, pns);
}

View File

@@ -114,6 +114,7 @@ PY_O_BASENAME = \
../extmod/modujson.o \
../extmod/modure.o \
../extmod/moduzlib.o \
../extmod/moduheapq.o \
# prepend the build destination prefix to the py object files
PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))

View File

@@ -30,6 +30,7 @@
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "gc.h"
// NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings)
// ultimately we will replace this with a static hash table of some kind
@@ -220,9 +221,17 @@ void qstr_pool_info(mp_uint_t *n_pool, mp_uint_t *n_qstr, mp_uint_t *n_str_data_
*n_pool += 1;
*n_qstr += pool->len;
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
#if MICROPY_ENABLE_GC
*n_str_data_bytes += gc_nbytes(*q); // this counts actual bytes used in heap
#else
*n_str_data_bytes += Q_GET_ALLOC(*q);
#endif
}
#if MICROPY_ENABLE_GC
*n_total_bytes += gc_nbytes(pool); // this counts actual bytes used in heap
#else
*n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc;
#endif
}
*n_total_bytes += *n_str_data_bytes;
}

View File

@@ -108,6 +108,7 @@ Q(GeneratorExit)
Q(ImportError)
Q(IndentationError)
Q(IndexError)
Q(KeyboardInterrupt)
Q(KeyError)
Q(LookupError)
Q(MemoryError)
@@ -117,7 +118,6 @@ Q(OSError)
Q(OverflowError)
Q(RuntimeError)
Q(SyntaxError)
Q(SystemError)
Q(SystemExit)
Q(TypeError)
Q(UnboundLocalError)
@@ -135,11 +135,18 @@ Q(abs)
Q(all)
Q(any)
Q(args)
#if MICROPY_PY_ARRAY
Q(array)
#endif
Q(bin)
Q({:#b})
Q(bool)
#if MICROPY_PY_BUILTINS_BYTEARRAY
Q(bytearray)
#endif
#if MICROPY_PY_BUILTINS_MEMORYVIEW
Q(memoryview)
#endif
Q(bytes)
Q(callable)
#if MICROPY_PY_STRUCT
@@ -207,6 +214,12 @@ Q(value)
Q(write)
Q(zip)
#if MICROPY_PY_BUILTINS_COMPILE
Q(compile)
Q(code)
Q(single)
#endif
Q(sep)
Q(end)
@@ -486,3 +499,10 @@ Q(search)
Q(group)
Q(DEBUG)
#endif
#if MICROPY_PY_UHEAPQ
Q(uheapq)
Q(heappush)
Q(heappop)
Q(heapify)
#endif

View File

@@ -62,6 +62,9 @@
#define DEBUG_OP_printf(...) (void)0
#endif
// pending exception object (MP_OBJ_NULL if not pending)
mp_obj_t mp_pending_exception;
// locals and globals need to be pointers because they can be the same in outer module scope
STATIC mp_obj_dict_t *dict_locals;
STATIC mp_obj_dict_t *dict_globals;
@@ -79,6 +82,9 @@ void mp_init(void) {
qstr_init();
mp_stack_ctrl_init();
// no pending exceptions to start with
mp_pending_exception = MP_OBJ_NULL;
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
mp_init_emergency_exception_buf();
#endif
@@ -475,8 +481,8 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
}
if (type->getiter != NULL) {
/* second attempt, walk the iterator */
mp_obj_t next = NULL;
mp_obj_t iter = mp_getiter(rhs);
mp_obj_t next;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
if (mp_obj_equal(next, lhs)) {
return mp_const_true;
@@ -1098,8 +1104,7 @@ import_error:
}
// See if it's a package, then can try FS import
mp_load_method_maybe(module, MP_QSTR___path__, dest);
if (dest[0] == MP_OBJ_NULL) {
if (!mp_obj_is_package(module)) {
goto import_error;
}
@@ -1190,6 +1195,13 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i
nlr_raise(module_fun);
}
// for compile only
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
mp_globals_set(old_globals);
mp_locals_set(old_locals);
return module_fun;
}
// complied successfully, execute it
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {

View File

@@ -116,6 +116,7 @@ mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type);
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, const mp_obj_t *args);
NORETURN void mp_native_raise(mp_obj_t o);
extern mp_obj_t mp_pending_exception;
extern struct _mp_obj_list_t mp_sys_path_obj;
extern struct _mp_obj_list_t mp_sys_argv_obj;
#define mp_sys_path ((mp_obj_t)&mp_sys_path_obj)

View File

@@ -57,7 +57,7 @@
ip += sizeof(mp_uint_t); \
} while (0)
void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len) {
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *ip, mp_uint_t len) {
const byte *ip_start = ip;
// get code info size
@@ -70,6 +70,24 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len) {
printf("File %s, code block '%s' (descriptor: %p, bytecode @%p " UINT_FMT " bytes)\n",
qstr_str(source_file), qstr_str(block_name), descr, code_info, len);
// raw bytecode dump
printf("Raw bytecode (code_info_size=" UINT_FMT ", bytecode_size=" UINT_FMT "):\n", code_info_size, len - code_info_size);
for (mp_uint_t i = 0; i < len; i++) {
if (i > 0 && i % 16 == 0) {
printf("\n");
}
printf(" %02x", ip_start[i]);
}
printf("\n");
// bytecode prelude: arg names (as qstr objects)
printf("arg names:");
for (int i = 0; i < n_total_args; i++) {
printf(" %s", qstr_str(MP_OBJ_QSTR_VALUE(*(mp_obj_t*)ip)));
ip += sizeof(mp_obj_t);
}
printf("\n");
// bytecode prelude: state size and exception stack size; 16 bit uints
{
uint n_state = mp_decode_uint(&ip);
@@ -87,15 +105,14 @@ void mp_bytecode_print(const void *descr, const byte *ip, mp_uint_t len) {
printf("(INIT_CELL %u)\n", local_num);
}
len -= ip - ip_start;
ip_start = ip;
}
// print out line number info
{
mp_int_t bc = (code_info + code_info_size) - ip;
mp_int_t bc = (ip_start + code_info_size) - ip; // start counting from the prelude
mp_uint_t source_line = 1;
printf(" bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line);
for (const byte* ci = code_info + 12; *ci;) {
for (const byte* ci = code_info; *ci;) {
if ((ci[0] & 0x80) == 0) {
// 0b0LLBBBBB encoding
bc += ci[0] & 0x1f;
@@ -173,18 +190,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
printf("LOAD_NULL");
break;
case MP_BC_LOAD_FAST_0:
printf("LOAD_FAST_0");
break;
case MP_BC_LOAD_FAST_1:
printf("LOAD_FAST_1");
break;
case MP_BC_LOAD_FAST_2:
printf("LOAD_FAST_2");
break;
case MP_BC_LOAD_FAST_N:
DECODE_UINT;
printf("LOAD_FAST_N " UINT_FMT, unum);
@@ -223,18 +228,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
printf("LOAD_SUBSCR");
break;
case MP_BC_STORE_FAST_0:
printf("STORE_FAST_0");
break;
case MP_BC_STORE_FAST_1:
printf("STORE_FAST_1");
break;
case MP_BC_STORE_FAST_2:
printf("STORE_FAST_2");
break;
case MP_BC_STORE_FAST_N:
DECODE_UINT;
printf("STORE_FAST_N " UINT_FMT, unum);
@@ -380,16 +373,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
printf("NOT");
break;
case MP_BC_UNARY_OP:
unum = *ip++;
printf("UNARY_OP " UINT_FMT, unum);
break;
case MP_BC_BINARY_OP:
unum = *ip++;
printf("BINARY_OP " UINT_FMT, unum);
break;
case MP_BC_BUILD_TUPLE:
DECODE_UINT;
printf("BUILD_TUPLE " UINT_FMT, unum);
@@ -517,9 +500,22 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
break;
default:
printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]);
assert(0);
return;
if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {
printf("LOAD_CONST_SMALL_INT " INT_FMT, (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16);
} else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {
printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 5) {
printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
printf("BINARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_BINARY_OP_MULTI);
} else {
printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]);
assert(0);
return;
}
break;
}
printf("\n");
}

View File

@@ -57,23 +57,23 @@ bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) {
}
mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) {
mp_int_t lsign = (dividend >= 0) ? 1 :-1;
mp_int_t rsign = (divisor >= 0) ? 1 :-1;
// Python specs require that mod has same sign as second operand
dividend %= divisor;
if (lsign != rsign) {
if ((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)) {
dividend += divisor;
}
return dividend;
}
mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom) {
mp_int_t lsign = num > 0 ? 1 : -1;
mp_int_t rsign = denom > 0 ? 1 : -1;
if (lsign == -1) {num *= -1;}
if (rsign == -1) {denom *= -1;}
if (lsign != rsign){
return - ( num + denom - 1) / denom;
if (num >= 0) {
if (denom < 0) {
num += -denom - 1;
}
} else {
return num / denom;
if (denom >= 0) {
num += -denom + 1;
}
}
return num / denom;
}

View File

@@ -60,7 +60,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
#define STREAM_CONTENT_TYPE(stream) (((stream)->is_text) ? &mp_type_str : &mp_type_bytes)
STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t stream_read(mp_uint_t n_args, const mp_obj_t *args) {
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
// CPython: io.UnsupportedOperation, OSError subclass
@@ -215,17 +215,28 @@ STATIC mp_obj_t stream_write_method(mp_obj_t self_in, mp_obj_t arg) {
return mp_stream_write(self_in, bufinfo.buf, bufinfo.len);
}
STATIC mp_obj_t stream_readinto(mp_obj_t self_in, mp_obj_t arg) {
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)self_in;
STATIC mp_obj_t stream_readinto(mp_uint_t n_args, const mp_obj_t *args) {
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
// CPython: io.UnsupportedOperation, OSError subclass
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_WRITE);
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
// CPython extension: if 2nd arg is provided, that's max len to read,
// instead of full buffer. Similar to
// https://docs.python.org/3/library/socket.html#socket.socket.recv_into
mp_uint_t len = bufinfo.len;
if (n_args > 2) {
len = mp_obj_int_get(args[2]);
if (len > bufinfo.len) {
len = bufinfo.len;
}
}
int error;
mp_uint_t out_sz = o->type->stream_p->read(o, bufinfo.buf, bufinfo.len, &error);
mp_uint_t out_sz = o->type->stream_p->read(o, bufinfo.buf, len, &error);
if (out_sz == MP_STREAM_ERROR) {
if (is_nonblocking_error(error)) {
return mp_const_none;
@@ -243,12 +254,12 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));
}
int total_size = 0;
mp_uint_t total_size = 0;
vstr_t *vstr = vstr_new_size(DEFAULT_BUFFER_SIZE);
char *p = vstr_str(vstr);
int error;
int current_read = DEFAULT_BUFFER_SIZE;
mp_uint_t current_read = DEFAULT_BUFFER_SIZE;
while (true) {
int error;
mp_uint_t out_sz = o->type->stream_p->read(self_in, p, current_read, &error);
if (out_sz == MP_STREAM_ERROR) {
if (is_nonblocking_error(error)) {
@@ -285,7 +296,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
}
// Unbuffered, inefficient implementation of readline() for raw I/O files.
STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t stream_unbuffered_readline(mp_uint_t n_args, const mp_obj_t *args) {
struct _mp_obj_base_t *o = (struct _mp_obj_base_t *)args[0];
if (o->type->stream_p == NULL || o->type->stream_p->read == NULL) {
// CPython: io.UnsupportedOperation, OSError subclass
@@ -304,13 +315,13 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) {
vstr = vstr_new();
}
int error;
while (max_size == -1 || max_size-- != 0) {
char *p = vstr_add_len(vstr, 1);
if (p == NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory"));
}
int error;
mp_uint_t out_sz = o->type->stream_p->read(o, p, 1, &error);
if (out_sz == MP_STREAM_ERROR) {
if (is_nonblocking_error(error)) {
@@ -370,7 +381,7 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj, 1, 2, stream_read);
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_readinto_obj, stream_readinto);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto);
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_readall_obj, stream_readall);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj, 1, 2, stream_unbuffered_readline);
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write_obj, stream_write_method);

107
py/vm.c
View File

@@ -110,10 +110,12 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_o
code_state->ip = ip; \
goto *entry_table[*ip++]; \
} while(0)
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
#define ENTRY(op) entry_##op
#define ENTRY_DEFAULT entry_default
#else
#define DISPATCH() break
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
#define ENTRY(op) case op
#define ENTRY_DEFAULT default
#endif
@@ -223,18 +225,6 @@ dispatch_loop:
PUSH(MP_OBJ_NULL);
DISPATCH();
ENTRY(MP_BC_LOAD_FAST_0):
obj_shared = fastn[0];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_1):
obj_shared = fastn[-1];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_2):
obj_shared = fastn[-2];
goto load_check;
ENTRY(MP_BC_LOAD_FAST_N):
DECODE_UINT;
obj_shared = fastn[-unum];
@@ -288,18 +278,6 @@ dispatch_loop:
DISPATCH();
}
ENTRY(MP_BC_STORE_FAST_0):
fastn[0] = POP();
DISPATCH();
ENTRY(MP_BC_STORE_FAST_1):
fastn[-1] = POP();
DISPATCH();
ENTRY(MP_BC_STORE_FAST_2):
fastn[-2] = POP();
DISPATCH();
ENTRY(MP_BC_STORE_FAST_N):
DECODE_UINT;
fastn[-unum] = POP();
@@ -396,21 +374,21 @@ dispatch_loop:
ENTRY(MP_BC_JUMP):
DECODE_SLABEL;
ip += unum;
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
ENTRY(MP_BC_POP_JUMP_IF_TRUE):
DECODE_SLABEL;
if (mp_obj_is_true(POP())) {
ip += unum;
}
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
ENTRY(MP_BC_POP_JUMP_IF_FALSE):
DECODE_SLABEL;
if (!mp_obj_is_true(POP())) {
ip += unum;
}
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
ENTRY(MP_BC_JUMP_IF_TRUE_OR_POP):
DECODE_SLABEL;
@@ -419,7 +397,7 @@ dispatch_loop:
} else {
sp--;
}
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
ENTRY(MP_BC_JUMP_IF_FALSE_OR_POP):
DECODE_SLABEL;
@@ -428,7 +406,7 @@ dispatch_loop:
} else {
ip += unum;
}
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
ENTRY(MP_BC_SETUP_WITH): {
mp_obj_t obj = TOP();
@@ -526,7 +504,7 @@ unwind_jump:
if (unum != 0) {
sp--;
}
DISPATCH();
DISPATCH_WITH_PEND_EXC_CHECK();
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
ENTRY(MP_BC_SETUP_EXCEPT):
@@ -606,19 +584,6 @@ unwind_jump:
}
DISPATCH();
ENTRY(MP_BC_UNARY_OP):
unum = *ip++;
SET_TOP(mp_unary_op(unum, TOP()));
DISPATCH();
ENTRY(MP_BC_BINARY_OP): {
unum = *ip++;
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(unum, lhs, rhs));
DISPATCH();
}
ENTRY(MP_BC_BUILD_TUPLE):
DECODE_UINT;
sp -= unum - 1;
@@ -890,7 +855,53 @@ yield:
mp_import_all(POP());
DISPATCH();
ENTRY_DEFAULT: {
#if MICROPY_OPT_COMPUTED_GOTO
ENTRY(MP_BC_LOAD_CONST_SMALL_INT_MULTI):
PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16));
DISPATCH();
ENTRY(MP_BC_LOAD_FAST_MULTI):
obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];
goto load_check;
ENTRY(MP_BC_STORE_FAST_MULTI):
fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();
DISPATCH();
ENTRY(MP_BC_UNARY_OP_MULTI):
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
DISPATCH();
ENTRY(MP_BC_BINARY_OP_MULTI): {
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
DISPATCH();
}
ENTRY_DEFAULT:
#else
ENTRY_DEFAULT:
if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {
PUSH(MP_OBJ_NEW_SMALL_INT((mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16));
DISPATCH();
} else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {
obj_shared = fastn[MP_BC_LOAD_FAST_MULTI - (mp_int_t)ip[-1]];
goto load_check;
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();
DISPATCH();
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 5) {
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
DISPATCH();
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
DISPATCH();
} else
#endif
{
mp_obj_t obj = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented");
nlr_pop();
fastn[0] = obj;
@@ -900,6 +911,14 @@ yield:
#if !MICROPY_OPT_COMPUTED_GOTO
} // switch
#endif
pending_exception_check:
if (mp_pending_exception != MP_OBJ_NULL) {
mp_obj_t obj = mp_pending_exception;
mp_pending_exception = MP_OBJ_NULL;
RAISE(obj);
}
} // for loop
} else {

View File

@@ -41,9 +41,6 @@ static void* entry_table[256] = {
[MP_BC_LOAD_CONST_BYTES] = &&entry_MP_BC_LOAD_CONST_BYTES,
[MP_BC_LOAD_CONST_STRING] = &&entry_MP_BC_LOAD_CONST_STRING,
[MP_BC_LOAD_NULL] = &&entry_MP_BC_LOAD_NULL,
[MP_BC_LOAD_FAST_0] = &&entry_MP_BC_LOAD_FAST_0,
[MP_BC_LOAD_FAST_1] = &&entry_MP_BC_LOAD_FAST_1,
[MP_BC_LOAD_FAST_2] = &&entry_MP_BC_LOAD_FAST_2,
[MP_BC_LOAD_FAST_N] = &&entry_MP_BC_LOAD_FAST_N,
[MP_BC_LOAD_DEREF] = &&entry_MP_BC_LOAD_DEREF,
[MP_BC_LOAD_NAME] = &&entry_MP_BC_LOAD_NAME,
@@ -52,9 +49,6 @@ static void* entry_table[256] = {
[MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD,
[MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS,
[MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR,
[MP_BC_STORE_FAST_0] = &&entry_MP_BC_STORE_FAST_0,
[MP_BC_STORE_FAST_1] = &&entry_MP_BC_STORE_FAST_1,
[MP_BC_STORE_FAST_2] = &&entry_MP_BC_STORE_FAST_2,
[MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N,
[MP_BC_STORE_DEREF] = &&entry_MP_BC_STORE_DEREF,
[MP_BC_STORE_NAME] = &&entry_MP_BC_STORE_NAME,
@@ -86,8 +80,6 @@ static void* entry_table[256] = {
[MP_BC_POP_BLOCK] = &&entry_MP_BC_POP_BLOCK,
[MP_BC_POP_EXCEPT] = &&entry_MP_BC_POP_EXCEPT,
[MP_BC_NOT] = &&entry_MP_BC_NOT,
[MP_BC_UNARY_OP] = &&entry_MP_BC_UNARY_OP,
[MP_BC_BINARY_OP] = &&entry_MP_BC_BINARY_OP,
[MP_BC_BUILD_TUPLE] = &&entry_MP_BC_BUILD_TUPLE,
[MP_BC_BUILD_LIST] = &&entry_MP_BC_BUILD_LIST,
[MP_BC_LIST_APPEND] = &&entry_MP_BC_LIST_APPEND,
@@ -114,6 +106,11 @@ static void* entry_table[256] = {
[MP_BC_IMPORT_NAME] = &&entry_MP_BC_IMPORT_NAME,
[MP_BC_IMPORT_FROM] = &&entry_MP_BC_IMPORT_FROM,
[MP_BC_IMPORT_STAR] = &&entry_MP_BC_IMPORT_STAR,
[MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI,
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
[MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + 4] = &&entry_MP_BC_UNARY_OP_MULTI,
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 34] = &&entry_MP_BC_BINARY_OP_MULTI,
};
#if __clang__

View File

@@ -24,6 +24,8 @@ USBDEV_DIR=usbdev
FATFS_DIR=fatfs
DFU=../tools/dfu.py
# may need to prefix dfu-util with sudo
USE_PYDFU ?= 0
PYDFU = ../tools/pydfu.py
DFU_UTIL ?= dfu-util
DEVICE=0483:df11
@@ -78,6 +80,7 @@ SRC_C = \
usbd_desc_cdc_msc.c \
usbd_cdc_interface.c \
usbd_msc_storage.c \
mphal.c \
irq.c \
pendsv.c \
systick.c \
@@ -249,7 +252,11 @@ all: $(BUILD)/firmware.dfu $(BUILD)/firmware.hex
deploy: $(BUILD)/firmware.dfu
$(ECHO) "Writing $< to the board"
ifeq ($(USE_PYDFU),1)
$(Q)$(PYTHON) $(PYDFU) -u $<
else
$(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $<
endif
$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf
$(ECHO) "Create $@"

View File

@@ -44,3 +44,4 @@ LED_GREEN,PA14
LED_YELLOW,PA15
SW,PB3
SD,PA8
MMA_INT,PB2
1 X1 PA0
44 LED_YELLOW PA15
45 SW PB3
46 SD PA8
47 MMA_INT PB2

View File

@@ -1,11 +1,11 @@
Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,
,,SYS,TIM1/2,TIM3/4/5,TIM8/9/10/11,I2C1/2/3,SPI1/SPI2/I2S2/I2S2ext,SPI3/I2Sext/I2S3,USART1/2/3/I2S3ext,UART4/5/USART6,CAN1/CAN2/TIM12/13/14,OTG_FS/OTG_HS,ETH,FSMC/SDIO/OTG_FS,DCMI,,,ADC
PortA,PA0,,TIM2_CH1_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
PortA,PA0,,TIM2_CH1/TIM2_ETR,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,ETH_MII_CRS,,,,EVENTOUT,ADC123_IN0
PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,UART4_RX,,,ETH_MII_RX_CLK/ETH_RMII__REF_CLK,,,,EVENTOUT,ADC123_IN1
PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,ETH_MDIO,,,,EVENTOUT,ADC123_IN2
PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,OTG_HS_ULPI_D0,ETH_MII_COL,,,,EVENTOUT,ADC123_IN3
PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,OTG_HS_SOF,DCMI_HSYNC,,EVENTOUT,ADC12_IN4
PortA,PA5,,TIM2_CH1_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
PortA,PA5,,TIM2_CH1/TIM2_ETR,,TIM8_CH1N,,SPI1_SCK,,,,,OTG_HS_ULPI_CK,,,,,EVENTOUT,ADC12_IN5
PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,,,TIM13_CH1,,,,DCMI_PIXCK,,EVENTOUT,ADC12_IN6
PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,TIM14_CH1,,ETH_MII_RX_DV/ETH_RMII_CRS_DV,,,,EVENTOUT,ADC12_IN7
PortA,PA8,MCO1,TIM1_CH1,,,I2C3_SCL,,,USART1_CK,,,OTG_FS_SOF,,,,,EVENTOUT,
1 Port AF0 AF1 AF2 AF3 AF4 AF5 AF6 AF7 AF8 AF9 AF10 AF11 AF12 AF13 AF14 AF15
2 SYS TIM1/2 TIM3/4/5 TIM8/9/10/11 I2C1/2/3 SPI1/SPI2/I2S2/I2S2ext SPI3/I2Sext/I2S3 USART1/2/3/I2S3ext UART4/5/USART6 CAN1/CAN2/TIM12/13/14 OTG_FS/OTG_HS ETH FSMC/SDIO/OTG_FS DCMI ADC
3 PortA PA0 TIM2_CH1_ETR TIM2_CH1/TIM2_ETR TIM5_CH1 TIM8_ETR USART2_CTS UART4_TX ETH_MII_CRS EVENTOUT ADC123_IN0
4 PortA PA1 TIM2_CH2 TIM5_CH2 USART2_RTS UART4_RX ETH_MII_RX_CLK/ETH_RMII__REF_CLK EVENTOUT ADC123_IN1
5 PortA PA2 TIM2_CH3 TIM5_CH3 TIM9_CH1 USART2_TX ETH_MDIO EVENTOUT ADC123_IN2
6 PortA PA3 TIM2_CH4 TIM5_CH4 TIM9_CH2 USART2_RX OTG_HS_ULPI_D0 ETH_MII_COL EVENTOUT ADC123_IN3
7 PortA PA4 SPI1_NSS SPI3_NSS/I2S3_WS USART2_CK OTG_HS_SOF DCMI_HSYNC EVENTOUT ADC12_IN4
8 PortA PA5 TIM2_CH1_ETR TIM2_CH1/TIM2_ETR TIM8_CH1N SPI1_SCK OTG_HS_ULPI_CK EVENTOUT ADC12_IN5
9 PortA PA6 TIM1_BKIN TIM3_CH1 TIM8_BKIN SPI1_MISO TIM13_CH1 DCMI_PIXCK EVENTOUT ADC12_IN6
10 PortA PA7 TIM1_CH1N TIM3_CH2 TIM8_CH1N SPI1_MOSI TIM14_CH1 ETH_MII_RX_DV/ETH_RMII_CRS_DV EVENTOUT ADC12_IN7
11 PortA PA8 MCO1 TIM1_CH1 I2C3_SCL USART1_CK OTG_FS_SOF EVENTOUT

View File

@@ -29,8 +29,6 @@
#include <stdarg.h>
#include <errno.h>
#include "stm32f4xx_hal.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
@@ -41,6 +39,7 @@
#include "bufhelper.h"
#include "can.h"
#include "pybioctl.h"
#include MICROPY_HAL_H
#if MICROPY_HW_ENABLE_CAN
@@ -334,8 +333,7 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
HAL_StatusTypeDef status = HAL_CAN_Transmit(&self->can, args[2].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_CAN_Transmit failed with code %d", status));
mp_hal_raise(status);
}
return mp_const_none;
@@ -367,8 +365,7 @@ STATIC mp_obj_t pyb_can_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
HAL_StatusTypeDef status = HAL_CAN_Receive(&self->can, args[0].u_int, args[1].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_CAN_Receive failed with code %d", status));
mp_hal_raise(status);
}
// return the received data

View File

@@ -39,6 +39,8 @@
#include "runtime.h"
#include "timer.h"
#include "dac.h"
#include "pin.h"
#include "genhdr/pins.h"
/// \moduleref pyb
/// \class DAC - digital to analog conversion
@@ -107,18 +109,33 @@ typedef struct _pyb_dac_obj_t {
// create the dac object
// currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2)
/// \classmethod \constructor(id)
/// \classmethod \constructor(port)
/// Construct a new DAC object.
///
/// `id` can be 1 or 2: DAC 1 is on pin X5 and DAC 2 is on pin X6.
/// `port` can be a pin object, or an integer (1 or 2).
/// DAC(1) is on pin X5 and DAC(2) is on pin X6.
STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, 1, false);
// get pin/channel to output on
mp_int_t dac_id;
if (MP_OBJ_IS_INT(args[0])) {
dac_id = mp_obj_get_int(args[0]);
} else {
const pin_obj_t *pin = pin_find(args[0]);
if (pin == &pin_A4) {
dac_id = 1;
} else if (pin == &pin_A5) {
dac_id = 2;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have DAC capabilities", qstr_str(pin->name)));
}
}
pyb_dac_obj_t *dac = m_new_obj(pyb_dac_obj_t);
dac->base.type = &pyb_dac_type;
mp_int_t dac_id = mp_obj_get_int(args[0]);
uint32_t pin;
if (dac_id == 1) {
pin = GPIO_PIN_4;

View File

@@ -27,8 +27,6 @@
#include <stdio.h>
#include <string.h>
#include "stm32f4xx_hal.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
@@ -39,6 +37,7 @@
#include "genhdr/pins.h"
#include "bufhelper.h"
#include "i2c.h"
#include MICROPY_HAL_H
/// \moduleref pyb
/// \class I2C - a two-wire serial protocol
@@ -148,7 +147,7 @@ void i2c_init(I2C_HandleTypeDef *i2c) {
// init error
// TODO should raise an exception, but this function is not necessarily going to be
// called via Python, so may not be properly wrapped in an NLR handler
printf("HardwareError: HAL_I2C_Init failed\n");
printf("OSError: HAL_I2C_Init failed\n");
return;
}
}
@@ -390,8 +389,7 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
}
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Transmit failed with code %d", status));
mp_hal_raise(status);
}
return mp_const_none;
@@ -440,8 +438,7 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
}
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Receive failed with code %d", status));
mp_hal_raise(status);
}
// return the received data
@@ -501,8 +498,7 @@ STATIC mp_obj_t pyb_i2c_mem_read(mp_uint_t n_args, const mp_obj_t *args, mp_map_
HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, vals[3].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Read failed with code %d", status));
mp_hal_raise(status);
}
// return the read data
@@ -554,8 +550,7 @@ STATIC mp_obj_t pyb_i2c_mem_write(mp_uint_t n_args, const mp_obj_t *args, mp_map
HAL_StatusTypeDef status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, vals[3].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Write failed with code %d", status));
mp_hal_raise(status);
}
return mp_const_none;

View File

@@ -137,17 +137,17 @@ 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);
static const char fresh_boot_py[] =
"# boot.py -- run on boot-up\n"
"# can run arbitrary Python, but best to keep it minimal\n"
"\n"
"import pyb\n"
"#pyb.main('main.py') # main script to run after this one\n"
"#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device\n"
"#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse\n"
"# boot.py -- run on boot-up\r\n"
"# can run arbitrary Python, but best to keep it minimal\r\n"
"\r\n"
"import pyb\r\n"
"#pyb.main('main.py') # main script to run after this one\r\n"
"#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device\r\n"
"#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse\r\n"
;
static const char fresh_main_py[] =
"# main.py -- put your code here!\n"
"# main.py -- put your code here!\r\n"
;
static const char fresh_pybcdc_inf[] =
@@ -458,7 +458,11 @@ soft_reset:
const char *boot_py = "boot.py";
FRESULT res = f_stat(boot_py, NULL);
if (res == FR_OK) {
if (!pyexec_file(boot_py)) {
int ret = pyexec_file(boot_py);
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
if (!ret) {
flash_error(4);
}
}
@@ -517,7 +521,11 @@ soft_reset:
}
FRESULT res = f_stat(main_py, NULL);
if (res == FR_OK) {
if (!pyexec_file(main_py)) {
int ret = pyexec_file(main_py);
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
if (!ret) {
flash_error(3);
}
}
@@ -537,6 +545,8 @@ soft_reset:
}
}
soft_reset_exit:
// soft reset
printf("PYB: sync filesystems\n");

View File

@@ -365,57 +365,57 @@ STATIC void cc3k_socket_print(void (*print)(void *env, const char *fmt, ...), vo
printf("<CC3k.socket fd=%d>", self->fd);
}
STATIC mp_uint_t cc3k_socket_send(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
STATIC mp_obj_t cc3k_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
cc3k_socket_obj_t *self = self_in;
if (cc3k_get_fd_closed_state(self->fd)) {
CC3000_EXPORT(closesocket)(self->fd);
*errcode = EPIPE;
return 0;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
// CC3K does not handle fragmentation, and will overflow,
// split the packet into smaller ones and send them out.
int bytes = 0;
while (bytes < size) {
int n = MIN((size-bytes), MAX_TX_PACKET);
n = CC3000_EXPORT(send)(self->fd, buf+bytes, n, 0);
mp_int_t bytes = 0;
while (bytes < bufinfo.len) {
int n = MIN((bufinfo.len - bytes), MAX_TX_PACKET);
n = CC3000_EXPORT(send)(self->fd, bufinfo.buf + bytes, n, 0);
if (n <= 0) {
bytes = n;
*errcode = CC3000_EXPORT(errno);
break;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(CC3000_EXPORT(errno))));
}
bytes += n;
}
return bytes;
return MP_OBJ_NEW_SMALL_INT(bytes);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_send_obj, cc3k_socket_send);
STATIC mp_uint_t cc3k_socket_recv(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
STATIC mp_obj_t cc3k_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
cc3k_socket_obj_t *self = self_in;
if (cc3k_get_fd_closed_state(self->fd)) {
CC3000_EXPORT(closesocket)(self->fd);
return 0;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
}
// recv MAX_RX_PACKET
int bytes = 0;
while (bytes < size) {
int n = MIN((size-bytes), MAX_RX_PACKET);
n = CC3000_EXPORT(recv)(self->fd, buf+bytes, n, 0);
if (n == 0) {
break;
} else if (n < 0) {
bytes = n;
*errcode = CC3000_EXPORT(errno);
break;
}
bytes += n;
}
// recv upto MAX_RX_PACKET
mp_int_t len = mp_obj_get_int(len_in);
len = MIN(len, MAX_RX_PACKET);
return bytes;
byte *buf;
mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
len = CC3000_EXPORT(recv)(self->fd, buf, len, 0);
if (len == 0) {
return mp_const_empty_bytes;
} else if (len < 0) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(CC3000_EXPORT(errno))));
} else {
return mp_obj_str_builder_end_with_len(ret_obj, len);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_recv_obj, cc3k_socket_recv);
STATIC mp_obj_t cc3k_socket_bind(mp_obj_t self_in, mp_obj_t addr_obj) {
cc3k_socket_obj_t *self = self_in;
@@ -565,9 +565,8 @@ STATIC mp_obj_t cc3k_socket_close(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_socket_close_obj, cc3k_socket_close);
STATIC const mp_map_elem_t cc3k_socket_locals_dict_table[] = {
// TODO read/write/send/recv distinctions
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&mp_stream_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&mp_stream_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&cc3k_socket_send_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&cc3k_socket_recv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&cc3k_socket_bind_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&cc3k_socket_listen_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&cc3k_socket_accept_obj },
@@ -644,8 +643,6 @@ mp_uint_t cc3k_ioctl(mp_obj_t self_in, mp_uint_t request, int *errcode, ...) {
}
STATIC const mp_stream_p_t cc3k_socket_stream_p = {
.read = cc3k_socket_recv,
.write = cc3k_socket_send,
.ioctl = cc3k_ioctl,
.is_text = false,
};

View File

@@ -88,6 +88,15 @@ STATIC NORETURN mp_obj_t pyb_bootloader(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_bootloader_obj, pyb_bootloader);
/// \function hard_reset()
/// Resets the pyboard in a manner similar to pushing the external RESET
/// button.
STATIC mp_obj_t pyb_hard_reset(void) {
NVIC_SystemReset();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_hard_reset_obj, pyb_hard_reset);
/// \function info([dump_alloc_table])
/// Print out lots of information about the board.
STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) {
@@ -443,6 +452,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&pyb_bootloader_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },

View File

@@ -415,12 +415,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_send_obj, wiznet5k_socket_send)
STATIC mp_obj_t wiznet5k_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
wiznet5k_socket_obj_t *self = self_in;
mp_int_t len = mp_obj_get_int(len_in);
uint8_t *buf = m_new(uint8_t, len);
byte *buf;
mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
mp_int_t ret = WIZCHIP_EXPORT(recv)(self->sn, buf, len);
check_sock_return_value(ret);
mp_obj_t ret_buf = mp_obj_new_bytes(buf, ret);
m_del(uint8_t, buf, len);
return ret_buf;
return mp_obj_str_builder_end_with_len(ret_obj, len);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_recv_obj, wiznet5k_socket_recv);

View File

@@ -50,6 +50,7 @@
#define MICROPY_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_STDFILES (1)
@@ -60,6 +61,7 @@
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URE (1)
#define MICROPY_PY_UHEAPQ (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)

20
stmhal/mphal.c Normal file
View File

@@ -0,0 +1,20 @@
#include <errno.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "mphal.h"
// this table converts from HAL_StatusTypeDef to POSIX errno
const byte mp_hal_status_to_errno_table[4] = {
[HAL_OK] = 0,
[HAL_ERROR] = EIO,
[HAL_BUSY] = EBUSY,
[HAL_TIMEOUT] = ETIMEDOUT,
};
NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, (mp_obj_t)(mp_uint_t)mp_hal_status_to_errno_table[status]));
}

View File

@@ -6,3 +6,7 @@
#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRRL) = (pin_mask))
#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRRH) = (pin_mask))
#define GPIO_read_output_pin(gpio, pin) (((gpio)->ODR >> (pin)) & 1)
extern const byte mp_hal_status_to_errno_table[4];
NORETURN void mp_hal_raise(HAL_StatusTypeDef status);

View File

@@ -31,6 +31,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "pendsv.h"
static void *pendsv_object = NULL;
@@ -40,12 +41,22 @@ void pendsv_init(void) {
HAL_NVIC_SetPriority(PendSV_IRQn, 0xf, 0xf);
}
// call this function to raise a pending exception during an interrupt
// it will wait until all interrupts are finished then raise the given
// exception object using nlr_jump in the context of the top-level thread
// Call this function to raise a pending exception during an interrupt.
// It will first try to raise the exception "softly" by setting the
// mp_pending_exception variable and hoping that the VM will notice it.
// If this function is called a second time (ie with the mp_pending_exception
// variable already set) then it will force the exception by using the hardware
// PENDSV feature. This will wait until all interrupts are finished then raise
// the given exception object using nlr_jump in the context of the top-level
// thread.
void pendsv_nlr_jump(void *o) {
pendsv_object = o;
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
if (mp_pending_exception == MP_OBJ_NULL) {
mp_pending_exception = o;
} else {
mp_pending_exception = MP_OBJ_NULL;
pendsv_object = o;
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
}
// since we play tricks with the stack, the compiler must not generate a

View File

@@ -54,48 +54,77 @@
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
STATIC bool repl_display_debugging_info = 0;
#define EXEC_FLAG_PRINT_EOF (1)
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
#define EXEC_FLAG_IS_REPL (4)
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, int exec_flags) {
int ret = 0;
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
qstr source_name = mp_lexer_source_name(lex);
// check for parse error
if (pn == MP_PARSE_NODE_NULL) {
// parse error
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
stdout_tx_strn("\x04", 1);
}
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
return false;
goto finish;
}
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, is_repl);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);
// check for compile error
if (mp_obj_is_exception_instance(module_fun)) {
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
stdout_tx_strn("\x04", 1);
}
mp_obj_print_exception(module_fun);
return false;
goto finish;
}
// execute code
nlr_buf_t nlr;
bool ret;
uint32_t start = HAL_GetTick();
if (nlr_push(&nlr) == 0) {
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
mp_call_function_0(module_fun);
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
nlr_pop();
ret = true;
ret = 1;
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
stdout_tx_strn("\x04", 1);
}
} else {
// uncaught exception
// FIXME it could be that an interrupt happens just before we disable it here
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
ret = false;
// print EOF after normal output
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
stdout_tx_strn("\x04", 1);
}
// check for SystemExit
if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
// at the moment, the value of SystemExit is unused
ret = PYEXEC_FORCED_EXIT;
} else {
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
ret = 0;
}
}
// display debugging info if wanted
if (is_repl && repl_display_debugging_info) {
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
printf("took %lu ms\n", ticks);
gc_collect();
@@ -117,6 +146,11 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo
}
}
finish:
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
stdout_tx_strn("\x04", 1);
}
return ret;
}
@@ -160,18 +194,18 @@ raw_repl_reset:
// exit for a soft reset
stdout_tx_str("\r\n");
vstr_clear(&line);
return 1;
return PYEXEC_FORCED_EXIT;
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0);
if (lex == NULL) {
printf("MemoryError\n");
printf("\x04MemoryError\n\x04");
} else {
parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF);
if (ret & PYEXEC_FORCED_EXIT) {
return ret;
}
}
// indicate end of output with EOF character
stdout_tx_str("\004");
}
}
@@ -208,6 +242,7 @@ friendly_repl_reset:
*/
for (;;) {
input_restart:
vstr_reset(&line);
int ret = readline(&line, ">>> ");
@@ -229,7 +264,7 @@ friendly_repl_reset:
// exit for a soft reset
stdout_tx_str("\r\n");
vstr_clear(&line);
return 1;
return PYEXEC_FORCED_EXIT;
} else if (vstr_len(&line) == 0) {
continue;
}
@@ -237,7 +272,11 @@ friendly_repl_reset:
while (mp_repl_continue_with_input(vstr_str(&line))) {
vstr_add_char(&line, '\n');
int ret = readline(&line, "... ");
if (ret == VCP_CHAR_CTRL_D) {
if (ret == VCP_CHAR_CTRL_C) {
// cancel everything
stdout_tx_str("\r\n");
goto input_restart;
} else if (ret == VCP_CHAR_CTRL_D) {
// stop entering compound statement
break;
}
@@ -247,12 +286,15 @@ friendly_repl_reset:
if (lex == NULL) {
printf("MemoryError\n");
} else {
parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true);
int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL);
if (ret & PYEXEC_FORCED_EXIT) {
return ret;
}
}
}
}
bool pyexec_file(const char *filename) {
int pyexec_file(const char *filename) {
mp_lexer_t *lex = mp_lexer_new_from_file(filename);
if (lex == NULL) {
@@ -260,7 +302,7 @@ bool pyexec_file(const char *filename) {
return false;
}
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0);
}
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {

View File

@@ -31,8 +31,10 @@ typedef enum {
extern pyexec_mode_kind_t pyexec_mode_kind;
#define PYEXEC_FORCED_EXIT (0x100)
int pyexec_raw_repl(void);
int pyexec_friendly_repl(void);
bool pyexec_file(const char *filename);
int pyexec_file(const char *filename);
MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj);

View File

@@ -30,6 +30,7 @@ Q(help)
Q(pyb)
Q(unique_id)
Q(bootloader)
Q(hard_reset)
Q(info)
Q(sd_test)
Q(present)

View File

@@ -86,6 +86,9 @@ int readline(vstr_t *line, const char *prompt) {
} else if (c == VCP_CHAR_CTRL_A) {
// CTRL-A with non-empty line is go-to-start-of-line
goto home_key;
} else if (c == VCP_CHAR_CTRL_C) {
// CTRL-C with non-empty line is cancel
return c;
} else if (c == VCP_CHAR_CTRL_E) {
// CTRL-E is go-to-end-of-line
goto end_key;

View File

@@ -27,8 +27,6 @@
#include <stdio.h>
#include <string.h>
#include "stm32f4xx_hal.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
@@ -39,6 +37,7 @@
#include "genhdr/pins.h"
#include "bufhelper.h"
#include "spi.h"
#include MICROPY_HAL_H
/// \moduleref pyb
/// \class SPI - a master-driven serial protocol
@@ -50,11 +49,12 @@
/// parameters to init the SPI bus:
///
/// from pyb import SPI
/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=1, crc=0x7)
/// spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
///
/// Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
/// 0 or 1, and is the level the idle clock line sits at. Phase can be 1 or 2
/// for number of edges. Crc can be None for no CRC, or a polynomial specifier.
/// 0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
/// to sample data on the first or second clock edge respectively. Crc can be
/// None for no CRC, or a polynomial specifier.
///
/// Additional method for SPI:
///
@@ -140,7 +140,7 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) {
// init error
// TODO should raise an exception, but this function is not necessarily going to be
// called via Python, so may not be properly wrapped in an NLR handler
printf("HardwareError: HAL_SPI_Init failed\n");
printf("OSError: HAL_SPI_Init failed\n");
return;
}
}
@@ -224,7 +224,7 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *
} else {
print(env, "SPI(%u, SPI.SLAVE", spi_num);
}
print(env, ", polarity=%u, phase=%u, bits=%u", self->spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, self->spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 1 : 2, self->spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
print(env, ", polarity=%u, phase=%u, bits=%u", self->spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, self->spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 0 : 1, self->spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16);
if (self->spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) {
print(env, ", crc=0x%x", self->spi->Init.CRCPolynomial);
}
@@ -232,7 +232,7 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *
}
}
/// \method init(mode, baudrate=328125, *, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
/// \method init(mode, baudrate=328125, *, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
///
/// Initialise the SPI bus with the given parameters:
///
@@ -242,7 +242,7 @@ STATIC const mp_arg_t pyb_spi_init_args[] = {
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 328125} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_dir, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_DIRECTION_2LINES} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_nss, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SPI_NSS_SOFT} },
@@ -282,7 +282,7 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, mp_uint_t n_args,
else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; }
init->CLKPolarity = vals[2].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
init->CLKPhase = vals[3].u_int == 1 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
init->CLKPhase = vals[3].u_int == 0 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
init->Direction = vals[4].u_int;
init->DataSize = (vals[5].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
init->NSS = vals[6].u_int;
@@ -387,8 +387,7 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
HAL_StatusTypeDef status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_Transmit failed with code %d", status));
mp_hal_raise(status);
}
return mp_const_none;
@@ -428,8 +427,7 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *k
HAL_StatusTypeDef status = HAL_SPI_Receive(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_Receive failed with code %d", status));
mp_hal_raise(status);
}
// return the received data
@@ -503,8 +501,7 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, vals[2].u_int);
if (status != HAL_OK) {
// TODO really need a HardwareError object, or something
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_TransmitReceive failed with code %d", status));
mp_hal_raise(status);
}
// return the received data

View File

@@ -29,8 +29,6 @@
#include <stdarg.h>
#include <errno.h>
#include "stm32f4xx_hal.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
@@ -40,6 +38,7 @@
#include "stream.h"
#include "uart.h"
#include "pybioctl.h"
#include MICROPY_HAL_H
/// \moduleref pyb
/// \class UART - duplex serial communication bus
@@ -94,14 +93,6 @@ struct _pyb_uart_obj_t {
byte *read_buf; // byte or uint16_t, depending on char size
};
// this table converts from HAL_StatusTypeDef to POSIX errno
STATIC const byte hal_status_to_errno_table[4] = {
[HAL_OK] = 0,
[HAL_ERROR] = EIO,
[HAL_BUSY] = EBUSY,
[HAL_TIMEOUT] = ETIMEDOUT,
};
// pointers to all UART objects (if they have been created)
STATIC pyb_uart_obj_t *pyb_uart_obj_all[6];
@@ -563,7 +554,7 @@ STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, (uint8_t*)&data, 1, self->timeout);
if (status != HAL_OK) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, (mp_obj_t)(mp_uint_t)hal_status_to_errno_table[status]));
mp_hal_raise(status);
}
return mp_const_none;
@@ -584,53 +575,6 @@ STATIC mp_obj_t pyb_uart_readchar(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
/// \method readinto(buf, len=-1)
///
/// Read data on the bus:
///
/// - `buf` is a mutable buffer which will be filled with read characters.
/// - `len` is the maximum number of characters to read; if negative, uses len(buf).
///
/// Return value: number of characters stored in buf.
STATIC mp_obj_t pyb_uart_readinto(mp_uint_t n_args, const mp_obj_t *pos_args) {
pyb_uart_obj_t *self = pos_args[0];
// get the buffer to read into
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(pos_args[1], &bufinfo, MP_BUFFER_WRITE);
bufinfo.len >>= self->char_width;
// adjust the length, if given
if (n_args == 3) {
mp_int_t len = mp_obj_get_int(pos_args[2]);
if (len >= 0 && len < bufinfo.len) {
bufinfo.len = len;
}
}
// make sure we want at least 1 char, and wait for it to become available
if (bufinfo.len == 0 || !uart_rx_wait(self, self->timeout)) {
return MP_OBJ_NEW_SMALL_INT(0);
}
// read the chars
byte *buf = bufinfo.buf;
for (;;) {
int data = uart_rx_char(self);
if (self->char_width == CHAR_WIDTH_9BIT) {
*(uint16_t*)buf = data;
buf += 2;
} else {
*buf++ = data;
}
if (--bufinfo.len == 0 || !uart_rx_wait(self, self->timeout_char)) {
// return the number of chars read
return mp_obj_new_int((buf - (byte*)bufinfo.buf) >> self->char_width);
}
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(pyb_uart_readinto_obj, 2, pyb_uart_readinto);
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
// instance methods
@@ -644,12 +588,13 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
/// \method readline()
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
/// \method readinto(buf[, nbytes])
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj },
/// \method write(buf)
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_writechar), (mp_obj_t)&pyb_uart_writechar_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_readchar), (mp_obj_t)&pyb_uart_readchar_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&pyb_uart_readinto_obj },
};
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
@@ -713,7 +658,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
// return number of bytes written
return size;
} else {
*errcode = hal_status_to_errno_table[status];
*errcode = mp_hal_status_to_errno_table[status];
return MP_STREAM_ERROR;
}
}

View File

@@ -50,7 +50,7 @@ STATIC mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
void pyb_usb_init0(void) {
// create an exception object for interrupting by VCP
mp_const_vcp_interrupt = mp_obj_new_exception_msg(&mp_type_OSError, "VCPInterrupt");
mp_const_vcp_interrupt = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
USBD_CDC_SetInterrupt(VCP_CHAR_NONE, mp_const_vcp_interrupt);
}
@@ -58,10 +58,14 @@ void pyb_usb_dev_init(usb_device_mode_t mode, usb_storage_medium_t medium) {
#ifdef USE_DEVICE_MODE
if (!dev_is_enabled) {
// only init USB once in the device's power-lifetime
// Windows needs a different PID to distinguish different device
// configurations, so we set it here depending on mode.
if (mode == USB_DEVICE_MODE_CDC_MSC) {
USBD_SelectMode(USBD_MODE_CDC_MSC);
USBD_SetPID(0x9800);
} else {
USBD_SelectMode(USBD_MODE_CDC_HID);
USBD_SetPID(0x9801);
}
USBD_Init(&hUSBDDevice, (USBD_DescriptorsTypeDef*)&VCP_Desc, 0);
USBD_RegisterClass(&hUSBDDevice, &USBD_CDC_MSC_HID);

View File

@@ -364,6 +364,8 @@ static int8_t CDC_Itf_Receive(uint8_t* Buf, uint32_t *Len) {
for (; src < buf_top; src++) {
if (*src == user_interrupt_char) {
char_found = true;
// raise exception when interrupts are finished
pendsv_nlr_jump(user_interrupt_data);
} else {
if (char_found) {
*dest = *src;
@@ -372,12 +374,6 @@ static int8_t CDC_Itf_Receive(uint8_t* Buf, uint32_t *Len) {
}
}
if (char_found) {
// raise exception when interrupts are finished
user_interrupt_char = VCP_CHAR_NONE;
pendsv_nlr_jump(user_interrupt_data);
}
// length of remaining characters
delta_len = dest - Buf;
}

View File

@@ -25,3 +25,5 @@
*/
extern const USBD_DescriptorsTypeDef VCP_Desc;
void USBD_SetPID(uint16_t pid);

View File

@@ -20,8 +20,8 @@
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
@@ -29,14 +29,10 @@
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
/* 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
@@ -52,199 +48,144 @@
#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
#define USBD_MANUFACTURER_STRING "STMicroelectronics"
#define USBD_PRODUCT_HS_STRING "STM32 Virtual ComPort in HS Mode"
#define USBD_SERIALNUMBER_HS_STRING "00000000001A"
#define USBD_PRODUCT_FS_STRING "STM32 Virtual ComPort in FS Mode"
#define USBD_SERIALNUMBER_FS_STRING "00000000001B"
#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"
*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
uint8_t *USBD_VCP_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
uint8_t *USBD_VCP_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t *USBD_VCP_USRStringDesc (USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);
#endif /* USB_SUPPORT_USER_STRING_DESC */
/* Private variables ---------------------------------------------------------*/
const USBD_DescriptorsTypeDef VCP_Desc = {
USBD_VCP_DeviceDescriptor,
USBD_VCP_LangIDStrDescriptor,
USBD_VCP_ManufacturerStrDescriptor,
USBD_VCP_ProductStrDescriptor,
USBD_VCP_SerialStrDescriptor,
USBD_VCP_ConfigStrDescriptor,
USBD_VCP_InterfaceStrDescriptor,
};
/* USB Standard Device Descriptor */
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
// USB Standard Device Descriptor
__ALIGN_BEGIN static uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
0x12, /* bLength */
USB_DESC_TYPE_DEVICE, /* bDescriptorType */
0x00, /* bcdUSB */
0x02,
0x00, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
USB_MAX_EP0_SIZE, /* bMaxPacketSize */
LOBYTE(USBD_VID), /* idVendor */
HIBYTE(USBD_VID), /* idVendor */
LOBYTE(USBD_PID), /* idVendor */
HIBYTE(USBD_PID), /* idVendor */
0x00, /* bcdDevice rel. 2.00 */
0x02,
USBD_IDX_MFC_STR, /* Index of manufacturer string */
USBD_IDX_PRODUCT_STR, /* Index of product string */
USBD_IDX_SERIAL_STR, /* Index of serial number string */
USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */
}; /* USB_DeviceDescriptor */
/* USB Standard Device Descriptor */
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING),
0x12, // bLength
USB_DESC_TYPE_DEVICE, // bDescriptorType
0x00, // bcdUSB
0x02,
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
USB_MAX_EP0_SIZE, // bMaxPacketSize
LOBYTE(USBD_VID), // idVendor
HIBYTE(USBD_VID), // idVendor
LOBYTE(USBD_PID), // idVendor
HIBYTE(USBD_PID), // idVendor
0x00, // bcdDevice rel. 2.00
0x02,
USBD_IDX_MFC_STR, // Index of manufacturer string
USBD_IDX_PRODUCT_STR, // Index of product string
USBD_IDX_SERIAL_STR, // Index of serial number string
USBD_MAX_NUM_CONFIGURATION // bNumConfigurations
};
__ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
USB_LEN_LANGID_STR_DESC,
USB_DESC_TYPE_STRING,
LOBYTE(USBD_LANGID_STRING),
HIBYTE(USBD_LANGID_STRING),
};
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma data_alignment=4
#endif
__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
/* Private functions ---------------------------------------------------------*/
// set the PID
void USBD_SetPID(uint16_t pid) {
hUSBDDeviceDesc[10] = LOBYTE(pid);
hUSBDDeviceDesc[11] = HIBYTE(pid);
}
/**
* @brief Returns the device descriptor.
* @brief Returns the device descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
*length = sizeof(hUSBDDeviceDesc);
return hUSBDDeviceDesc;
STATIC uint8_t *USBD_VCP_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
*length = sizeof(hUSBDDeviceDesc);
return hUSBDDeviceDesc;
}
/**
* @brief Returns the LangID string descriptor.
* @brief Returns the LangID string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
*length = sizeof(USBD_LangIDDesc);
return USBD_LangIDDesc;
STATIC uint8_t *USBD_VCP_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
*length = sizeof(USBD_LangIDDesc);
return USBD_LangIDDesc;
}
/**
* @brief Returns the product string descriptor.
* @brief Returns the product string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == 0)
{
USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
STATIC uint8_t *USBD_VCP_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
if(speed == 0) {
USBD_GetString((uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length);
} else {
USBD_GetString((uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Returns the manufacturer string descriptor.
* @brief Returns the manufacturer string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
STATIC uint8_t *USBD_VCP_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
/**
* @brief Returns the serial number string descriptor.
* @brief Returns the serial number string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == USBD_SPEED_HIGH)
{
USBD_GetString((uint8_t *)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
STATIC uint8_t *USBD_VCP_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
if(speed == USBD_SPEED_HIGH) {
USBD_GetString((uint8_t *)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length);
} else {
USBD_GetString((uint8_t *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Returns the configuration string descriptor.
* @brief Returns the configuration string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == USBD_SPEED_HIGH)
{
USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
STATIC uint8_t *USBD_VCP_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
if(speed == USBD_SPEED_HIGH) {
USBD_GetString((uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length);
} else {
USBD_GetString((uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
/**
* @brief Returns the interface string descriptor.
* @brief Returns the interface string descriptor.
* @param speed: Current device speed
* @param length: Pointer to data length variable
* @retval Pointer to descriptor buffer
*/
uint8_t *USBD_VCP_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
if(speed == 0)
{
USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length);
}
else
{
USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
STATIC uint8_t *USBD_VCP_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) {
if(speed == 0) {
USBD_GetString((uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length);
} else {
USBD_GetString((uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
}
return USBD_StrDesc;
}
const USBD_DescriptorsTypeDef VCP_Desc = {
USBD_VCP_DeviceDescriptor,
USBD_VCP_LangIDStrDescriptor,
USBD_VCP_ManufacturerStrDescriptor,
USBD_VCP_ProductStrDescriptor,
USBD_VCP_SerialStrDescriptor,
USBD_VCP_ConfigStrDescriptor,
USBD_VCP_InterfaceStrDescriptor,
};
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -92,9 +92,9 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_MSC_CfgDesc[USB_CDC_MSC_CONFIG_DESC_SIZ] _
USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD
CDC_IFACE_NUM, // bFirstInterface: first interface for this association
0x02, // bInterfaceCount: nummber of interfaces for this association
0x00, // bFunctionClass: ?
0x00, // bFunctionSubClass: ?
0x00, // bFunctionProtocol: ?
0x02, // bFunctionClass: Communication Interface Class
0x02, // bFunctionSubClass: Abstract Control Model
0x01, // bFunctionProtocol: Common AT commands
0x00, // iFunction: index of string for this function
//--------------------------------------------------------------------------
@@ -229,9 +229,9 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] _
USB_DESC_TYPE_ASSOCIATION, // bDescriptorType: IAD
CDC_IFACE_NUM, // bFirstInterface: first interface for this association
0x02, // bInterfaceCount: nummber of interfaces for this association
0x00, // bFunctionClass: ?
0x00, // bFunctionSubClass: ?
0x00, // bFunctionProtocol: ?
0x02, // bFunctionClass: Communication Interface Class
0x02, // bFunctionSubClass: Abstract Control Model
0x01, // bFunctionProtocol: Common AT commands
0x00, // iFunction: index of string for this function
//--------------------------------------------------------------------------
@@ -324,7 +324,7 @@ __ALIGN_BEGIN static uint8_t USBD_CDC_HID_CfgDesc[USB_CDC_HID_CONFIG_DESC_SIZ] _
0x01, // bNumEndpoints
0x03, // bInterfaceClass: HID Class
0x01, // bInterfaceSubClass: 1=BOOT, 0=no boot
0x01, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse
0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse
0x00, // iInterface:
// HID descriptor

View File

@@ -0,0 +1,29 @@
# test compile builtin
def have_compile():
try:
compile
return True
except NameError:
return False
# global variable for compiled code to access
x = 1
def test():
c = compile("print(x)", "file", "exec")
try:
exec(c)
except NameError:
print("NameError")
exec(c)
exec(c, {"x":2})
exec(c, {}, {"x":3})
if have_compile():
test()
else:
print("SKIP")

View File

@@ -298,15 +298,15 @@ except SyntaxError:
#except SyntaxWarning:
# print("Caught SyntaxWarning")
try:
raise SystemError
except Exception:
print("Caught SystemError via Exception")
#try:
# raise SystemError
#except Exception:
# print("Caught SystemError via Exception")
try:
raise SystemError
except SystemError:
print("Caught SystemError")
#try:
# raise SystemError
#except SystemError:
# print("Caught SystemError")
#try:
# raise TabError

View File

@@ -0,0 +1,21 @@
# test integer floor division and modulo
# test all combination of +/-/0 cases
for i in range(-2, 3):
for j in range(-4, 5):
if j != 0:
print(i, j, i // j, i % j, divmod(i, j))
# this tests compiler constant folding
print(123 // 7, 123 % 7)
print(-123 // 7, -123 % 7)
print(123 // -7, 123 % -7)
print(-123 // -7, -123 % -7)
# this tests bignum modulo
a = 987654321987987987987987987987
b = 19
print(a % b)
print(a % -b)
print(-a % b)
print(-a % -b)

View File

@@ -0,0 +1,34 @@
# test memoryview
# test reading from bytes
b = b'1234'
m = memoryview(b)
print(len(m))
print(m[0], m[1], m[-1])
print(list(m))
# test writing to bytes
try:
m[0] = 1
except TypeError:
print("TypeError")
# test writing to bytearray
b = bytearray(b)
m = memoryview(b)
m[0] = 1
print(b)
print(list(m))
# test slice
m = memoryview(b'1234')
print(list(m[1:]))
print(list(m[1:-1]))
import array
a = array.array('i', [1, 2, 3, 4])
m = memoryview(a)
print(list(m))
print(list(m[1:-1]))
m[2] = 6
print(a)

View File

@@ -0,0 +1,18 @@
# test memoryview retains pointer to original object/buffer
b = bytearray(10)
m = memoryview(b)[1:]
for i in range(len(m)):
m[i] = i
# reclaim b, but hopefully not the buffer
b = None
import gc
gc.collect()
# allocate lots of memory
for i in range(100000):
[42, 42, 42, 42]
# check that the memoryview is still what we want
print(list(m))

View File

@@ -1,23 +0,0 @@
# check modulo matches python definition
# this tests compiler constant folding
print(123 % 7)
print(-123 % 7)
print(123 % -7)
print(-123 % -7)
a = 321
b = 19
print(a % b)
print(a % -b)
print(-a % b)
print(-a % -b)
a = 987654321987987987987987987987
b = 19
print(a % b)
print(a % -b)
print(-a % b)
print(-a % -b)

36
tests/extmod/uheapq1.py Normal file
View File

@@ -0,0 +1,36 @@
try:
import uheapq as heapq
except:
import heapq
try:
heapq.heappop([])
except IndexError:
print("IndexError")
try:
heapq.heappush((), 1)
except TypeError:
print("TypeError")
def pop_and_print(h):
l = []
while h:
l.append(str(heapq.heappop(h)))
print(' '.join(l))
h = []
heapq.heappush(h, 3)
heapq.heappush(h, 1)
heapq.heappush(h, 2)
print(h)
pop_and_print(h)
h = [4, 3, 8, 9, 10, 2, 7, 11, 5]
heapq.heapify(h)
print(h)
heapq.heappush(h, 1)
heapq.heappush(h, 6)
heapq.heappush(h, 12)
print(h)
pop_and_print(h)

View File

@@ -0,0 +1,10 @@
b = bytearray(30)
f = open("io/data/file1", "rb")
# 2nd arg (length to read) is extension to CPython
print(f.readinto(b, 8))
print(b)
b = bytearray(4)
f = open("io/data/file1", "rb")
print(f.readinto(b, 8))
print(b)

View File

@@ -0,0 +1,4 @@
8
bytearray(b'longer l\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
4
bytearray(b'long')

View File

@@ -69,10 +69,10 @@ print(sorted(list(viper_set(1, 2))))
# raising an exception
@micropython.viper
def viper_raise(x:int):
raise SystemError(x)
raise OSError(x)
try:
viper_raise(1)
except SystemError as e:
except OSError as e:
print(repr(e))
# this doesn't work at the moment

View File

@@ -8,6 +8,6 @@
(1, 3)
[1, 3]
[1, 3]
SystemError(1,)
OSError(1,)
1
1

View File

@@ -5,10 +5,10 @@ print(spi)
spi = SPI(1, SPI.MASTER)
spi = SPI(1, SPI.MASTER, baudrate=500000)
spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
print(spi)
spi.init(SPI.SLAVE)
spi.init(SPI.SLAVE, phase=1)
print(spi)
spi.init(SPI.MASTER)

View File

@@ -1,5 +1,5 @@
SPI(1)
SPI(1, SPI.MASTER, baudrate=328125, polarity=1, phase=1, bits=8)
SPI(1, SPI.MASTER, baudrate=328125, polarity=1, phase=0, bits=8)
SPI(1, SPI.SLAVE, polarity=1, phase=1, bits=8)
b'\xff'
b'\xff'

123
tools/pyboard.py Normal file → Executable file
View File

@@ -1,3 +1,5 @@
#!/usr/bin/env python
"""
pyboard interface
@@ -19,10 +21,15 @@ To run a script from the local machine on the board and print out the results:
This script can also be run directly. To execute a local script, use:
./pyboard.py test.py
Or:
python pyboard.py test.py
"""
import sys
import time
import serial
@@ -31,21 +38,26 @@ class PyboardError(BaseException):
class Pyboard:
def __init__(self, serial_device):
self.serial = serial.Serial(serial_device)
self.serial = serial.Serial(serial_device, baudrate=115200, interCharTimeout=1)
def close(self):
self.serial.close()
def read_until(self, min_num_bytes, ending, timeout=10):
def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
data = self.serial.read(min_num_bytes)
if data_consumer:
data_consumer(data)
timeout_count = 0
while True:
if self.serial.inWaiting() > 0:
data = data + self.serial.read(self.serial.inWaiting())
time.sleep(0.01)
timeout_count = 0
elif data.endswith(ending):
if data.endswith(ending):
break
elif self.serial.inWaiting() > 0:
new_data = self.serial.read(1)
data = data + new_data
if data_consumer:
data_consumer(new_data)
#time.sleep(0.01)
timeout_count = 0
else:
timeout_count += 1
if timeout_count >= 10 * timeout:
@@ -54,8 +66,12 @@ class Pyboard:
return data
def enter_raw_repl(self):
self.serial.write(b'\r\x03') # ctrl-C: interrupt any running program
self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL
data = self.read_until(1, b'to exit\r\n>')
if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'):
print(data)
raise PyboardError('could not enter raw repl')
self.serial.write(b'\x04') # ctrl-D: soft reset
data = self.read_until(1, b'to exit\r\n>')
if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'):
@@ -65,31 +81,51 @@ class Pyboard:
def exit_raw_repl(self):
self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL
def follow(self, data_consumer=False):
# wait for normal output
data = self.read_until(1, b'\x04', data_consumer=data_consumer)
if not data.endswith(b'\x04'):
raise PyboardError('timeout waiting for first EOF reception')
data = data[:-1]
# wait for error output
data_err = self.read_until(2, b'\x04>')
if not data_err.endswith(b'\x04>'):
raise PyboardError('timeout waiting for second EOF reception')
data_err = data_err[:-2]
# return normal and error output
return data, data_err
def exec_raw(self, command, data_consumer=False):
if isinstance(command, bytes):
command_bytes = command
else:
command_bytes = bytes(command, encoding='ascii')
# write command
for i in range(0, len(command_bytes), 32):
self.serial.write(command_bytes[i:min(i+32, len(command_bytes))])
time.sleep(0.01)
self.serial.write(b'\x04')
# check if we could exec command
data = self.serial.read(2)
if data != b'OK':
raise PyboardError('could not exec command')
return self.follow(data_consumer)
def eval(self, expression):
ret = self.exec('print({})'.format(expression))
ret = ret.strip()
return ret
def exec(self, command):
if isinstance(command, bytes):
command_bytes = command
else:
command_bytes = bytes(command, encoding='ascii')
for i in range(0, len(command_bytes), 32):
self.serial.write(command_bytes[i:min(i+32, len(command_bytes))])
time.sleep(0.01)
self.serial.write(b'\x04')
data = self.serial.read(2)
if data != b'OK':
raise PyboardError('could not exec command')
data = self.read_until(2, b'\x04>')
if not data.endswith(b'\x04>'):
print(data)
raise PyboardError('timeout waiting for EOF reception')
if data.startswith(b'Traceback') or data.startswith(b' File '):
print(data)
raise PyboardError('command failed')
return data[:-2]
ret, ret_err = self.exec_raw(command)
if ret_err:
raise PyboardError('exception', ret, ret_err)
return ret
def execfile(self, filename):
with open(filename) as f:
@@ -175,8 +211,37 @@ def main():
if args.test:
run_test(device=args.device)
for file in args.files:
execfile(file, device=args.device)
if len(args.files) == 0:
try:
pyb = Pyboard(args.device)
ret, ret_err = pyb.follow(data_consumer=lambda d:print(str(d, encoding='ascii'), end=''))
pyb.close()
except PyboardError as er:
print(er)
sys.exit(1)
except KeyboardInterrupt:
sys.exit(1)
if ret_err:
print(str(ret_err, encoding='ascii'), end='')
sys.exit(1)
for filename in args.files:
try:
pyb = Pyboard(args.device)
pyb.enter_raw_repl()
with open(filename) as f:
pyfile = f.read()
ret, ret_err = pyb.exec_raw(pyfile, data_consumer=lambda d:print(str(d, encoding='ascii'), end=''))
pyb.exit_raw_repl()
pyb.close()
except PyboardError as er:
print(er)
sys.exit(1)
except KeyboardInterrupt:
sys.exit(1)
if ret_err:
print(str(ret_err, encoding='ascii'), end='')
sys.exit(1)
if __name__ == "__main__":
main()

531
tools/pydfu.py Executable file
View File

@@ -0,0 +1,531 @@
#!/usr/bin/env python
# This file is part of the OpenMV project.
# Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
# This work is licensed under the MIT license, see the file LICENSE for
# details.
"""This module implements enough functionality to program the STM32F4xx over
DFU, without requiringdfu-util.
See app note AN3156 for a description of the DFU protocol.
See document UM0391 for a dscription of the DFuse file.
"""
from __future__ import print_function
import argparse
import re
import struct
import sys
import usb.core
import usb.util
import zlib
# VID/PID
__VID = 0x0483
__PID = 0xdf11
# USB request __TIMEOUT
__TIMEOUT = 4000
# DFU commands
__DFU_DETACH = 0
__DFU_DNLOAD = 1
__DFU_UPLOAD = 2
__DFU_GETSTATUS = 3
__DFU_CLRSTATUS = 4
__DFU_GETSTATE = 5
__DFU_ABORT = 6
# DFU status
__DFU_STATE_APP_IDLE = 0x00
__DFU_STATE_APP_DETACH = 0x01
__DFU_STATE_DFU_IDLE = 0x02
__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03
__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04
__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05
__DFU_STATE_DFU_MANIFEST_SYNC = 0x06
__DFU_STATE_DFU_MANIFEST = 0x07
__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08
__DFU_STATE_DFU_UPLOAD_IDLE = 0x09
__DFU_STATE_DFU_ERROR = 0x0a
_DFU_DESCRIPTOR_TYPE = 0x21
# USB device handle
__dev = None
__verbose = None
# USB DFU interface
__DFU_INTERFACE = 0
def init():
"""Initializes the found DFU device so that we can program it."""
global __dev
devices = get_dfu_devices(idVendor=__VID, idProduct=__PID)
if not devices:
raise ValueError('No DFU device found')
if len(devices) > 1:
raise ValueError("Multiple DFU devices found")
__dev = devices[0]
# Claim DFU interface
usb.util.claim_interface(__dev, __DFU_INTERFACE)
# Clear status
clr_status()
def clr_status():
"""Clears any error status (perhaps left over from a previous session)."""
__dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE,
None, __TIMEOUT)
def get_status():
"""Get the status of the last operation."""
stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE,
6, 20000)
# print (__DFU_STAT[stat[4]], stat)
return stat[4]
def mass_erase():
"""Performs a MASS erase (i.e. erases the entire device."""
# Send DNLOAD with first byte=0x41
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE,
"\x41", __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
raise Exception("DFU: erase failed")
# Check command state
if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE:
raise Exception("DFU: erase failed")
def page_erase(addr):
"""Erases a single page."""
if __verbose:
print("Erasing page: 0x%x..." % (addr))
# Send DNLOAD with first byte=0x41 and page address
buf = struct.pack("<BI", 0x41, addr)
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, buf, __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
raise Exception("DFU: erase failed")
# Check command state
if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE:
raise Exception("DFU: erase failed")
def set_address(addr):
"""Sets the address for the next operation."""
# Send DNLOAD with first byte=0x21 and page address
buf = struct.pack("<BI", 0x21, addr)
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, buf, __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
raise Exception("DFU: set address failed")
# Check command state
if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE:
raise Exception("DFU: set address failed")
def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0):
"""Writes a buffer into memory. This routine assumes that memory has
already been erased.
"""
xfer_count = 0
xfer_bytes = 0
xfer_total = len(buf)
xfer_base = addr
while xfer_bytes < xfer_total:
if __verbose and xfer_count % 512 == 0:
print ("Addr 0x%x %dKBs/%dKBs..." % (xfer_base + xfer_bytes,
xfer_bytes // 1024,
xfer_total // 1024))
if progress and xfer_count % 256 == 0:
progress(progress_addr, xfer_base + xfer_bytes - progress_addr,
progress_size)
# Set mem write address
set_address(xfer_base+xfer_bytes)
# Send DNLOAD with fw data
chunk = min(64, xfer_total-xfer_bytes)
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE,
buf[xfer_bytes:xfer_bytes + chunk], __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
raise Exception("DFU: write memory failed")
# Check command state
if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE:
raise Exception("DFU: write memory failed")
xfer_count += 1
xfer_bytes += chunk
def write_page(buf, xfer_offset):
"""Writes a single page. This routine assumes that memory has already
been erased.
"""
xfer_base = 0x08000000
# Set mem write address
set_address(xfer_base+xfer_offset)
# Send DNLOAD with fw data
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE, buf, __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
raise Exception("DFU: write memory failed")
# Check command state
if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE:
raise Exception("DFU: write memory failed")
if __verbose:
print ("Write: 0x%x " % (xfer_base + xfer_offset))
def exit_dfu():
"""Exit DFU mode, and start running the program."""
# set jump address
set_address(0x08000000)
# Send DNLOAD with 0 length to exit DFU
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE,
None, __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_MANIFEST:
print("Failed to reset device")
# Release device
usb.util.dispose_resources(__dev)
def named(values, names):
"""Creates a dict with `names` as fields, and `values` as values."""
return dict(zip(names.split(), values))
def consume(fmt, data, names):
"""Parses the struct defined by `fmt` from `data`, stores the parsed fields
into a named tuple using `names`. Returns the named tuple, and the data
with the struct stripped off."""
size = struct.calcsize(fmt)
return named(struct.unpack(fmt, data[:size]), names), data[size:]
def cstring(string):
"""Extracts a null-terminated string from a byte array."""
return string.split(b'\0', 1)[0]
def compute_crc(data):
"""Computes the CRC32 value for the data passed in."""
return 0xFFFFFFFF & -zlib.crc32(data) - 1
def read_dfu_file(filename):
"""Reads a DFU file, and parses the individual elements from the file.
Returns an array of elements. Each element is a dictionary with the
following keys:
num - The element index
address - The address that the element data should be written to.
size - The size of the element ddata.
data - The element data.
If an error occurs while parsing the file, then None is returned.
"""
print("File: {}".format(filename))
with open(filename, 'rb') as fin:
data = fin.read()
crc = compute_crc(data[:-4])
elements = []
# Decode the DFU Prefix
#
# <5sBIB
# < little endian
# 5s char[5] signature "DfuSe"
# B uint8_t version 1
# I uint32_t size Size of the DFU file (not including suffix)
# B uint8_t targets Number of targets
dfu_prefix, data = consume('<5sBIB', data,
'signature version size targets')
print (" %(signature)s v%(version)d, image size: %(size)d, "
"targets: %(targets)d" % dfu_prefix)
for target_idx in range(dfu_prefix['targets']):
# Decode the Image Prefix
#
# <6sBI255s2I
# < little endian
# 6s char[6] signature "Target"
# B uint8_t altsetting
# I uint32_t named bool indicating if a name was used
# 255s char[255] name name of the target
# I uint32_t size size of image (not incl prefix)
# I uint32_t elements Number of elements in the image
img_prefix, data = consume('<6sBI255s2I', data,
'signature altsetting named name '
'size elements')
img_prefix['num'] = target_idx
if img_prefix['named']:
img_prefix['name'] = cstring(img_prefix['name'])
else:
img_prefix['name'] = ''
print(' %(signature)s %(num)d, alt setting: %(altsetting)s, '
'name: "%(name)s", size: %(size)d, elements: %(elements)d'
% img_prefix)
target_size = img_prefix['size']
target_data, data = data[:target_size], data[target_size:]
for elem_idx in range(img_prefix['elements']):
# Decode target prefix
# < little endian
# I uint32_t element address
# I uint32_t element size
elem_prefix, target_data = consume('<2I', target_data, 'addr size')
elem_prefix['num'] = elem_idx
print(' %(num)d, address: 0x%(addr)08x, size: %(size)d'
% elem_prefix)
elem_size = elem_prefix['size']
elem_data = target_data[:elem_size]
target_data = target_data[elem_size:]
elem_prefix['data'] = elem_data
elements.append(elem_prefix)
if len(target_data):
print("target %d PARSE ERROR" % target_idx)
# Decode DFU Suffix
# < little endian
# H uint16_t device Firmware version
# H uint16_t product
# H uint16_t vendor
# H uint16_t dfu 0x11a (DFU file format version)
# 3s char[3] ufd 'UFD'
# B uint8_t len 16
# I uint32_t crc32
dfu_suffix = named(struct.unpack('<4H3sBI', data[:16]),
'device product vendor dfu ufd len crc')
print (' usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, '
'dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % dfu_suffix)
if crc != dfu_suffix['crc']:
print("CRC ERROR: computed crc32 is 0x%08x" % crc)
return
data = data[16:]
if data:
print("PARSE ERROR")
return
return elements
class FilterDFU(object):
"""Class for filtering USB devices to identify devices which are in DFU
mode.
"""
def __call__(self, device):
for cfg in device:
for intf in cfg:
return (intf.bInterfaceClass == 0xFE and
intf.bInterfaceSubClass == 1)
def get_dfu_devices(*args, **kwargs):
"""Returns a list of USB device which are currently in DFU mode.
Additional filters (like idProduct and idVendor) can be passed in to
refine the search.
"""
return list(usb.core.find(*args, find_all=True,
custom_match=FilterDFU(), **kwargs))
def get_memory_layout(device):
"""Returns an array which identifies the memory layout. Each entry
of the array will contain a dictionary with the following keys:
addr - Address of this memory segment
last_addr - Last address contained within the memory segment.
size - size of the segment, in bytes
num_pages - number of pages in the segment
page_size - size of each page, in bytes
"""
cfg = device[0]
intf = cfg[(0, 0)]
mem_layout_str = usb.util.get_string(device, 255, intf.iInterface)
mem_layout = mem_layout_str.split('/')
addr = int(mem_layout[1], 0)
segments = mem_layout[2].split(',')
seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)')
result = []
for segment in segments:
seg_match = seg_re.match(segment)
num_pages = int(seg_match.groups()[0], 10)
page_size = int(seg_match.groups()[1], 10)
multiplier = seg_match.groups()[2]
if multiplier == 'K':
page_size *= 1024
if multiplier == 'M':
page_size *= 1024 * 1024
size = num_pages * page_size
last_addr = addr + size - 1
result.append(named((addr, last_addr, size, num_pages, page_size),
"addr last_addr size num_pages page_size"))
addr += size
return result
def list_dfu_devices(*args, **kwargs):
"""Prints a lits of devices detected in DFU mode."""
devices = get_dfu_devices(*args, **kwargs)
if not devices:
print("No DFU capable devices found")
return
for device in devices:
print("Bus {} Device {:03d}: ID {:04x}:{:04x}"
.format(device.bus, device.address,
device.idVendor, device.idProduct))
layout = get_memory_layout(device)
print("Memory Layout")
for entry in layout:
print(" 0x{:x} {:2d} pages of {:3d}K bytes"
.format(entry['addr'], entry['num_pages'],
entry['page_size'] // 1024))
def write_elements(elements, mass_erase_used, progress=None):
"""Writes the indicated elements into the target memory,
erasing as needed.
"""
mem_layout = get_memory_layout(__dev)
for elem in elements:
addr = elem['addr']
size = elem['size']
data = elem['data']
elem_size = size
elem_addr = addr
if progress:
progress(elem_addr, 0, elem_size)
while size > 0:
write_size = size
if not mass_erase_used:
for segment in mem_layout:
if addr >= segment['addr'] and \
addr <= segment['last_addr']:
# We found the page containing the address we want to
# write, erase it
page_size = segment['page_size']
page_addr = addr & ~(page_size - 1)
if addr + write_size > page_addr + page_size:
write_size = page_addr + page_size - addr
page_erase(page_addr)
break
write_memory(addr, data[:write_size], progress,
elem_addr, elem_size)
data = data[write_size:]
addr += write_size
size -= write_size
if progress:
progress(elem_addr, addr - elem_addr, elem_size)
def cli_progress(addr, offset, size):
"""Prints a progress report suitable for use on the command line."""
width = 25
done = offset * width // size
print("\r0x{:08x} {:7d} [{}{}] {:3d}% "
.format(addr, size, '=' * done, ' ' * (width - done),
offset * 100 // size), end="")
sys.stdout.flush()
if offset == size:
print("")
def main():
"""Test program for verifying this files functionality."""
global __verbose
# Parse CMD args
parser = argparse.ArgumentParser(description='DFU Python Util')
#parser.add_argument("path", help="file path")
parser.add_argument(
"-l", "--list",
help="list available DFU devices",
action="store_true",
default=False
)
parser.add_argument(
"-m", "--mass-erase",
help="mass erase device",
action="store_true",
default=False
)
parser.add_argument(
"-u", "--upload",
help="read file from DFU device",
dest="path",
default=False
)
parser.add_argument(
"-v", "--verbose",
help="increase output verbosity",
action="store_true",
default=False
)
args = parser.parse_args()
__verbose = args.verbose
if args.list:
list_dfu_devices(idVendor=__VID, idProduct=__PID)
return
try:
init()
except ValueError as er:
print(str(er))
sys.exit(1)
if args.mass_erase:
print ("Mass erase...")
mass_erase()
if args.path:
elements = read_dfu_file(args.path)
if not elements:
return
print("Writing memory...")
write_elements(elements, args.mass_erase, progress=cli_progress)
print("Exiting DFU...")
exit_dfu()
return
print("No command specified")
if __name__ == '__main__':
main()

View File

@@ -47,6 +47,7 @@
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "repl.h"
#include "gc.h"
#include "genhdr/py-version.h"
@@ -64,9 +65,47 @@ mp_uint_t mp_verbose_flag = 0;
long heap_size = 128*1024 * (sizeof(mp_uint_t) / 4);
#endif
#ifndef _WIN32
#include <signal.h>
STATIC mp_obj_t keyboard_interrupt_obj;
STATIC void sighandler(int signum) {
if (signum == SIGINT) {
mp_obj_exception_clear_traceback(keyboard_interrupt_obj);
mp_pending_exception = keyboard_interrupt_obj;
// disable our handler so next we really die
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
}
}
#endif
#define FORCED_EXIT (0x100)
// returns standard error codes: 0 for success, 1 for all other errors
// if FORCED_EXIT bit is set then script raised SystemExit and the
// If exc is SystemExit, return value where FORCED_EXIT bit set,
// and lower 8 bits are SystemExit value. For all other exceptions,
// return 1.
STATIC int handle_uncaught_exception(mp_obj_t exc) {
// check for SystemExit
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
// None is an exit value of 0; an int is its value; anything else is 1
mp_obj_t exit_val = mp_obj_exception_get_value(exc);
mp_int_t val = 0;
if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) {
val = 1;
}
return FORCED_EXIT | (val & 255);
}
// Report all other exceptions
mp_obj_print_exception(exc);
return 1;
}
// Returns standard error codes: 0 for success, 1 for all other errors,
// except if FORCED_EXIT bit is set then script raised SystemExit and the
// value of the exit is in the lower 8 bits of the return value
STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
if (lex == NULL) {
@@ -119,27 +158,30 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind,
return 0;
}
#ifndef _WIN32
// enable signal handler
struct sigaction sa;
sa.sa_handler = sighandler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_DFL;
#endif
// execute it
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_0(module_fun);
#ifndef _WIN32
sigaction(SIGINT, &sa, NULL);
#endif
nlr_pop();
return 0;
} else {
// uncaught exception
// check for SystemExit
mp_obj_t exc = (mp_obj_t)nlr.ret_val;
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
// None is an exit value of 0; an int is its value; anything else is 1
mp_obj_t exit_val = mp_obj_exception_get_value(exc);
mp_int_t val = 0;
if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) {
val = 1;
}
return FORCED_EXIT | (val & 255);
}
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
return 1;
#ifndef _WIN32
sigaction(SIGINT, &sa, NULL);
#endif
return handle_uncaught_exception((mp_obj_t)nlr.ret_val);
}
}
@@ -226,16 +268,20 @@ int usage(char **argv) {
}
#if MICROPY_MEM_STATS
STATIC mp_obj_t mem_info(void) {
STATIC mp_obj_t mem_info(mp_uint_t n_args, const mp_obj_t *args) {
printf("mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n",
m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
printf("stack: " UINT_FMT "\n", mp_stack_usage());
#if MICROPY_ENABLE_GC
gc_dump_info();
if (n_args == 1) {
// arg given means dump gc allocation table
gc_dump_alloc_table();
}
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mem_info_obj, mem_info);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mem_info_obj, 0, 1, mem_info);
#endif
STATIC mp_obj_t qstr_info(void) {
@@ -265,7 +311,14 @@ void pre_process_options(int argc, char **argv) {
emit_opt = MP_EMIT_OPT_VIPER;
#if MICROPY_ENABLE_GC
} else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) {
heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, NULL, 0);
char *end;
heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0);
// Don't bring unneeded libc dependencies like tolower()
if ((*end | 0x20) == 'k') {
heap_size *= 1024;
} else if ((*end | 0x20) == 'm') {
heap_size *= 1024 * 1024;
}
#endif
} else {
exit(usage(argv));
@@ -276,6 +329,12 @@ void pre_process_options(int argc, char **argv) {
}
}
void set_sys_argv(char *argv[], int argc, int start_arg) {
for (int i = start_arg; i < argc; i++) {
mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
}
}
#ifdef _WIN32
#define PATHLIST_SEP_CHAR ';'
#else
@@ -294,6 +353,11 @@ int main(int argc, char **argv) {
mp_init();
#ifndef _WIN32
// create keyboard interrupt object
keyboard_interrupt_obj = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
#endif
char *home = getenv("HOME");
char *path = getenv("MICROPYPATH");
if (path == NULL) {
@@ -368,6 +432,40 @@ int main(int argc, char **argv) {
break;
}
a += 1;
} else if (strcmp(argv[a], "-m") == 0) {
if (a + 1 >= argc) {
return usage(argv);
}
mp_obj_t import_args[4];
import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]), false);
import_args[1] = import_args[2] = mp_const_none;
// Ask __import__ to handle imported module specially - set its __name__
// to __main__, and also return this leaf module, not top-level package
// containing it.
import_args[3] = mp_const_false;
// TODO: https://docs.python.org/3/using/cmdline.html#cmdoption-m :
// "the first element of sys.argv will be the full path to
// the module file (while the module file is being located,
// the first element will be set to "-m")."
set_sys_argv(argv, argc, a + 1);
mp_obj_t mod;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args);
nlr_pop();
} else {
// uncaught exception
return handle_uncaught_exception((mp_obj_t)nlr.ret_val);
}
if (mp_obj_is_package(mod)) {
// TODO
fprintf(stderr, "%s: -m for packages not yet implemented\n", argv[0]);
exit(1);
}
ret = 0;
break;
} else if (strcmp(argv[a], "-X") == 0) {
a += 1;
} else if (strcmp(argv[a], "-v") == 0) {
@@ -398,9 +496,7 @@ int main(int argc, char **argv) {
path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir));
free(pathbuf);
for (int i = a; i < argc; i++) {
mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
}
set_sys_argv(argv, argc, a);
ret = do_file(argv[a]);
break;
}
@@ -410,6 +506,10 @@ int main(int argc, char **argv) {
ret = do_repl();
}
if (mp_verbose_flag) {
mem_info(0, NULL);
}
mp_deinit();
#if MICROPY_ENABLE_GC && !defined(NDEBUG)

View File

@@ -45,7 +45,9 @@
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_OPT_COMPUTED_GOTO (1)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
#define MICROPY_PY_BUILTINS_FROZENSET (1)
#define MICROPY_PY_BUILTINS_COMPILE (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_PLATFORM "linux"
#define MICROPY_PY_SYS_MAXSIZE (1)
@@ -58,6 +60,7 @@
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URE (1)
#define MICROPY_PY_UHEAPQ (1)
// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc.
// names in exception messages (may require more RAM).