Merge branch 'master' into nrf5_no_sdk
This commit is contained in:
commit
9d91e990f7
@ -59,8 +59,6 @@ typedef struct _pyb_i2c_obj_t {
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define PYBI2C_MASTER (0)
|
||||
|
||||
#define PYBI2C_MIN_BAUD_RATE_HZ (50000)
|
||||
#define PYBI2C_MAX_BAUD_RATE_HZ (400000)
|
||||
|
||||
@ -79,7 +77,6 @@ typedef struct _pyb_i2c_obj_t {
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0};
|
||||
STATIC const mp_obj_t pyb_i2c_def_pin[2] = {&pin_GP13, &pin_GP23};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
@ -289,33 +286,34 @@ STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) {
|
||||
STATIC void pyb_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_i2c_obj_t *self = self_in;
|
||||
if (self->baudrate > 0) {
|
||||
mp_printf(print, "I2C(0, I2C.MASTER, baudrate=%u)", self->baudrate);
|
||||
mp_printf(print, "I2C(0, baudrate=%u)", self->baudrate);
|
||||
} else {
|
||||
mp_print_str(print, "I2C(0)");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *args) {
|
||||
// verify that mode is master
|
||||
if (args[0].u_int != PYBI2C_MASTER) {
|
||||
goto invalid_args;
|
||||
}
|
||||
STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_scl, ARG_sda, ARG_freq };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// make sure the baudrate is between the valid range
|
||||
self->baudrate = MIN(MAX(args[1].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
self->baudrate = MIN(MAX(args[ARG_freq].u_int, PYBI2C_MIN_BAUD_RATE_HZ), PYBI2C_MAX_BAUD_RATE_HZ);
|
||||
|
||||
// assign the pins
|
||||
mp_obj_t pins_o = args[2].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_i2c_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array_fixed_n(pins_o, 2, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
mp_obj_t pins[2] = {&pin_GP13, &pin_GP23}; // default (SDA, SCL) pins
|
||||
if (args[ARG_scl].u_obj != MP_OBJ_NULL) {
|
||||
pins[1] = args[ARG_scl].u_obj;
|
||||
}
|
||||
if (args[ARG_sda].u_obj != MP_OBJ_NULL) {
|
||||
pins[0] = args[ARG_sda].u_obj;
|
||||
}
|
||||
pin_assign_pins_af(pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
|
||||
// init the I2C bus
|
||||
i2c_init(self);
|
||||
@ -324,44 +322,34 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
invalid_args:
|
||||
mp_raise_ValueError(mpexception_value_invalid_arguments);
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t pyb_i2c_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = PYBI2C_MASTER} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// check the id argument, if given
|
||||
if (n_args > 0) {
|
||||
if (all_args[0] != MP_OBJ_NEW_SMALL_INT(0)) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
--n_args;
|
||||
++all_args;
|
||||
}
|
||||
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_i2c_init_args, args);
|
||||
|
||||
// check the peripheral id
|
||||
if (args[0].u_int != 0) {
|
||||
mp_raise_OSError(MP_ENODEV);
|
||||
}
|
||||
|
||||
// setup the object
|
||||
pyb_i2c_obj_t *self = &pyb_i2c_obj;
|
||||
self->base.type = &pyb_i2c_type;
|
||||
|
||||
// start the peripheral
|
||||
pyb_i2c_init_helper(self, &args[1]);
|
||||
pyb_i2c_init_helper(self, n_args, all_args, &kw_args);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(pyb_i2c_init_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_i2c_init_args[1], args);
|
||||
return pyb_i2c_init_helper(pos_args[0], args);
|
||||
STATIC mp_obj_t pyb_i2c_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
return pyb_i2c_init_helper(pos_args[0], n_args - 1, pos_args + 1, kw_args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init);
|
||||
|
||||
@ -489,7 +477,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem_into(mp_uint_t n_args, const mp_obj_t *pos_
|
||||
// get the buffer to read into
|
||||
vstr_t vstr;
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_int(vstr.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
|
||||
|
||||
@ -513,8 +501,7 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
|
||||
// write the register address to write to.
|
||||
if (pyb_i2c_mem_write (i2c_addr, (byte *)&mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len)) {
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_raise_OSError(MP_EIO);
|
||||
@ -532,9 +519,6 @@ STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem), (mp_obj_t)&pyb_i2c_readfrom_mem_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_readfrom_mem_into), (mp_obj_t)&pyb_i2c_readfrom_mem_into_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_writeto_mem), (mp_obj_t)&pyb_i2c_writeto_mem_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYBI2C_MASTER) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
|
||||
|
@ -88,7 +88,7 @@ Use the :mod:`time <utime>` module::
|
||||
Timers
|
||||
------
|
||||
|
||||
Virtual (RTOS-based) timers are supported. Use the ``machine.Timer`` class
|
||||
Virtual (RTOS-based) timers are supported. Use the :ref:`machine.Timer <machine.Timer>` class
|
||||
with timer ID of -1::
|
||||
|
||||
from machine import Timer
|
||||
@ -102,7 +102,7 @@ The period is in milliseconds.
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
Use the ``machine.Pin`` class::
|
||||
Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
@ -155,7 +155,7 @@ ADC (analog to digital conversion)
|
||||
ADC is available on a dedicated pin.
|
||||
Note that input voltages on the ADC pin must be between 0v and 1.0v.
|
||||
|
||||
Use the ``machine.ADC`` class::
|
||||
Use the :ref:`machine.ADC <machine.ADC>` class::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
@ -166,7 +166,8 @@ Software SPI bus
|
||||
----------------
|
||||
|
||||
There are two SPI drivers. One is implemented in software (bit-banging)
|
||||
and works on all pins::
|
||||
and works on all pins, and is accessed via the :ref:`machine.SPI <machine.SPI>`
|
||||
class::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
@ -208,7 +209,8 @@ constructor and init (as those are fixed)::
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
The I2C driver is implemented in software and works on all pins::
|
||||
The I2C driver is implemented in software and works on all pins,
|
||||
and is accessed via the :ref:`machine.I2C <machine.I2C>` class::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
|
@ -20,9 +20,12 @@ characteristic of a board is how much flash it has, how the GPIO pins are
|
||||
connected to the outside world, and whether it includes a built-in USB-serial
|
||||
convertor to make the UART available to your PC.
|
||||
|
||||
The minimum requirement for flash size is 512k. A board with this amount of
|
||||
flash will not have room for a filesystem, but otherwise is fully functional.
|
||||
If your board has 1Mbyte or more of flash then it will support a filesystem.
|
||||
The minimum requirement for flash size is 1Mbyte. There is also a special
|
||||
build for boards with 512KB, but it is highly limited comparing to the
|
||||
normal build: there is no support for filesystem, and thus features which
|
||||
depend on it won't work (WebREPL, upip, etc.). As such, 512KB build will
|
||||
be more interesting for users who build from source and fine-tune parameters
|
||||
for their particular application.
|
||||
|
||||
Names of pins will be given in this tutorial using the chip names (eg GPIO0)
|
||||
and it should be straightforward to find which pin this corresponds to on your
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.ADC:
|
||||
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.I2C:
|
||||
|
||||
class I2C -- a two-wire serial protocol
|
||||
=======================================
|
||||
@ -9,86 +10,55 @@ level it consists of 2 wires: SCL and SDA, the clock and data lines respectively
|
||||
I2C objects are created attached to a specific bus. They can be initialised
|
||||
when created, or initialised later on.
|
||||
|
||||
.. only:: port_wipy
|
||||
Printing the I2C object gives you information about its configuration.
|
||||
|
||||
Example::
|
||||
Example usage::
|
||||
|
||||
from machine import I2C
|
||||
from machine import I2C
|
||||
|
||||
i2c = I2C(0) # create on bus 0
|
||||
i2c = I2C(0, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.deinit() # turn off the peripheral
|
||||
i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz
|
||||
# depending on the port, extra parameters may be required
|
||||
# to select the peripheral and/or pins to use
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
i2c.scan() # scan for slaves, returning a list of 7-bit addresses
|
||||
|
||||
.. only:: port_wipy
|
||||
i2c.writeto(42, b'123') # write 3 bytes to slave with 7-bit address 42
|
||||
i2c.readfrom(42, 4) # read 4 bytes from slave with 7-bit address 42
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
|
||||
i2c.writeto(addr=0x42, b'456') # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of slave 42,
|
||||
# starting at memory-address 8 in the slave
|
||||
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of slave 42
|
||||
# starting at address 2 in the slave
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. class:: I2C(id=-1, \*, scl, sda, freq=400000)
|
||||
|
||||
.. class:: I2C(bus, ...)
|
||||
Construct and return a new I2C object using the following parameters:
|
||||
|
||||
Construct an I2C object on the given bus. `bus` can only be 0.
|
||||
If the bus is not given, the default one will be selected (0).
|
||||
|
||||
.. only:: not port_wipy
|
||||
|
||||
.. class:: I2C(id=-1, \*, scl, sda, freq=400000)
|
||||
|
||||
Construct and return a new I2C object using the following parameters:
|
||||
|
||||
- `id` identifies the particular I2C peripheral. The default
|
||||
value of -1 selects a software implementation of I2C which can
|
||||
work (in most cases) with arbitrary pins for SCL and SDA.
|
||||
If `id` is -1 then `scl` and `sda` must be specified. Other
|
||||
allowed values for `id` depend on the particular port/board,
|
||||
and specifying `scl` and `sda` may or may not be required or
|
||||
allowed in this case.
|
||||
- `scl` should be a pin object specifying the pin to use for SCL.
|
||||
- `sda` should be a pin object specifying the pin to use for SDA.
|
||||
- `freq` should be an integer which sets the maximum frequency
|
||||
for SCL.
|
||||
- `id` identifies the particular I2C peripheral. The default
|
||||
value of -1 selects a software implementation of I2C which can
|
||||
work (in most cases) with arbitrary pins for SCL and SDA.
|
||||
If `id` is -1 then `scl` and `sda` must be specified. Other
|
||||
allowed values for `id` depend on the particular port/board,
|
||||
and specifying `scl` and `sda` may or may not be required or
|
||||
allowed in this case.
|
||||
- `scl` should be a pin object specifying the pin to use for SCL.
|
||||
- `sda` should be a pin object specifying the pin to use for SDA.
|
||||
- `freq` should be an integer which sets the maximum frequency
|
||||
for SCL.
|
||||
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. method:: I2C.init(scl, sda, \*, freq=400000)
|
||||
|
||||
.. method:: I2C.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
|
||||
Initialise the I2C bus with the given arguments:
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``I2C.MASTER``
|
||||
- ``baudrate`` is the SCL clock rate
|
||||
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
|
||||
|
||||
.. only:: port_esp8266
|
||||
|
||||
.. method:: I2C.init(scl, sda, \*, freq=400000)
|
||||
|
||||
Initialise the I2C bus with the given arguments:
|
||||
|
||||
- `scl` is a pin object for the SCL line
|
||||
- `sda` is a pin object for the SDA line
|
||||
- `freq` is the SCL clock rate
|
||||
- `scl` is a pin object for the SCL line
|
||||
- `sda` is a pin object for the SDA line
|
||||
- `freq` is the SCL clock rate
|
||||
|
||||
.. method:: I2C.deinit()
|
||||
|
||||
@ -102,8 +72,6 @@ General Methods
|
||||
those that respond. A device responds if it pulls the SDA line low after
|
||||
its address (including a write bit) is sent on the bus.
|
||||
|
||||
Note: on WiPy the I2C object must be in master mode for this method to be valid.
|
||||
|
||||
Primitive I2C operations
|
||||
------------------------
|
||||
|
||||
@ -192,8 +160,7 @@ methods are convenience functions to communicate with such devices.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
|
||||
On WiPy the return value is the number of bytes read. Otherwise the
|
||||
return value is `None`.
|
||||
The method returns `None`.
|
||||
|
||||
.. method:: I2C.writeto_mem(addr, memaddr, buf, \*, addrsize=8)
|
||||
|
||||
@ -202,14 +169,4 @@ methods are convenience functions to communicate with such devices.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
|
||||
On WiPy the return value is the number of bytes written. Otherwise the
|
||||
return value is `None`.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: I2C.MASTER
|
||||
|
||||
for initialising the bus to master mode
|
||||
|
||||
Availability: WiPy.
|
||||
The method returns `None`.
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Pin:
|
||||
|
||||
class Pin -- control I/O pins
|
||||
=============================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.RTC:
|
||||
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SD:
|
||||
|
||||
class SD -- secure digital memory card
|
||||
======================================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SPI:
|
||||
|
||||
class SPI -- a Serial Peripheral Interface bus protocol (master side)
|
||||
=====================================================================
|
||||
@ -44,7 +45,7 @@ Methods
|
||||
a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver
|
||||
(``id`` = -1).
|
||||
- ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to
|
||||
specify them as a tuple of ``pins`` parameter.
|
||||
specify them as a tuple of ``pins`` parameter.
|
||||
|
||||
.. method:: SPI.deinit()
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Timer:
|
||||
|
||||
class Timer -- control hardware timers
|
||||
======================================
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.UART:
|
||||
|
||||
class UART -- duplex serial communication bus
|
||||
=============================================
|
||||
@ -32,17 +33,6 @@ using the standard stream methods::
|
||||
uart.readinto(buf) # read and store into the given buffer
|
||||
uart.write('abc') # write the 3 characters
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
Individual characters can be read/written using::
|
||||
|
||||
uart.readchar() # read 1 character and returns it as an integer
|
||||
uart.writechar(42) # write 1 character
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns True if any characters waiting
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@ -69,15 +59,14 @@ Methods
|
||||
When no pins are given, then the default set of TX and RX pins is taken, and hardware
|
||||
flow control will be disabled. If pins=None, no pin assignment will be made.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
.. method:: UART.deinit()
|
||||
|
||||
.. method:: UART.deinit()
|
||||
Turn off the UART bus.
|
||||
|
||||
Turn off the UART bus.
|
||||
.. method:: UART.any()
|
||||
|
||||
.. method:: UART.any()
|
||||
|
||||
Return the number of characters available for reading.
|
||||
Return true value if there're characters available for reading. On some
|
||||
boards, the number of available characters is returned.
|
||||
|
||||
.. method:: UART.read([nbytes])
|
||||
|
||||
@ -107,13 +96,10 @@ Methods
|
||||
|
||||
Return value: number of bytes written or ``None`` on timeout.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
.. method:: UART.sendbreak()
|
||||
|
||||
.. method:: UART.sendbreak()
|
||||
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
of 13 bits.
|
||||
Return value: ``None``.
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
longer than required for a normal transmission of a character.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
@ -140,8 +126,6 @@ Methods
|
||||
|
||||
Returns an irq object.
|
||||
|
||||
.. only:: not port_esp8266
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.WDT:
|
||||
|
||||
class WDT -- watchdog timer
|
||||
===========================
|
||||
|
@ -17,7 +17,7 @@ A note of callbacks used by functions and class methods of ``machine`` module:
|
||||
all these callbacks should be considered as executing in an interrupt context.
|
||||
This is true for both physical devices with IDs >= 0 and "virtual" devices
|
||||
with negative IDs like -1 (these "virtual" devices are still thin shims on
|
||||
top of real hardware and real hardware intrerrupts). See :ref:`isr_rules`.
|
||||
top of real hardware and real hardware interrupts). See :ref:`isr_rules`.
|
||||
|
||||
Reset related functions
|
||||
-----------------------
|
||||
@ -85,13 +85,6 @@ Miscellaneous functions
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: main(filename)
|
||||
|
||||
Set the filename of the main script to run after boot.py is finished. If
|
||||
this function is not called then the default file main.py will be executed.
|
||||
|
||||
It only makes sense to call this function from within boot.py.
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
|
@ -7,26 +7,6 @@
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. only:: port_pyboard or port_unix
|
||||
|
||||
.. function:: mem_info([verbose])
|
||||
|
||||
Print information about currently used memory. If the ``verbose`` argument
|
||||
is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the amount of stack and heap used. In verbose mode it prints out
|
||||
the entire heap indicating which blocks are used and which are free.
|
||||
|
||||
.. function:: qstr_info([verbose])
|
||||
|
||||
Print information about currently interned strings. If the ``verbose``
|
||||
argument is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the number of interned strings and the amount of RAM they use. In
|
||||
verbose mode it prints out the names of all RAM-interned strings.
|
||||
|
||||
.. function:: alloc_emergency_exception_buf(size)
|
||||
|
||||
Allocate ``size`` bytes of RAM for the emergency exception buffer (a good
|
||||
@ -37,3 +17,21 @@ Functions
|
||||
A good way to use this function is to put it at the start of your main script
|
||||
(eg boot.py or main.py) and then the emergency exception buffer will be active
|
||||
for all the code following it.
|
||||
|
||||
.. function:: mem_info([verbose])
|
||||
|
||||
Print information about currently used memory. If the ``verbose`` argument
|
||||
is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the amount of stack and heap used. In verbose mode it prints out
|
||||
the entire heap indicating which blocks are used and which are free.
|
||||
|
||||
.. function:: qstr_info([verbose])
|
||||
|
||||
Print information about currently interned strings. If the ``verbose``
|
||||
argument is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the number of interned strings and the amount of RAM they use. In
|
||||
verbose mode it prints out the names of all RAM-interned strings.
|
||||
|
@ -88,8 +88,8 @@ Functions
|
||||
|
||||
.. function:: urandom(n)
|
||||
|
||||
Return a bytes object with n random bytes, generated by the hardware
|
||||
random number generator.
|
||||
Return a bytes object with n random bytes. Whenever possible, it is
|
||||
generated by the hardware random number generator.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
|
@ -1,86 +1,46 @@
|
||||
:mod:`ussl` -- ssl module
|
||||
===============================
|
||||
:mod:`ussl` -- SSL/TLS module
|
||||
=============================
|
||||
|
||||
.. module:: ussl
|
||||
:synopsis: TLS/SSL wrapper for socket objects
|
||||
|
||||
This module provides access to Transport Layer Security (often known as
|
||||
“Secure Sockets Layer”) encryption and peer authentication facilities for
|
||||
network sockets, both client-side and server-side.
|
||||
This module provides access to Transport Layer Security (previously and
|
||||
widely known as “Secure Sockets Layer”) encryption and peer authentication
|
||||
facilities for network sockets, both client-side and server-side.
|
||||
|
||||
.. only:: not port_wipy
|
||||
Functions
|
||||
---------
|
||||
|
||||
Functions
|
||||
---------
|
||||
.. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)
|
||||
|
||||
.. function:: ssl.wrap_socket(sock, server_side=False)
|
||||
Takes a stream `sock` (usually usocket.socket instance of ``SOCK_STREAM`` type),
|
||||
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
|
||||
an SSL context. Returned object has the usual stream interface methods like
|
||||
`read()`, `write()`, etc. In MicroPython, the returned object does not expose
|
||||
socket interface and methods like `recv()`, `send()`. In particular, a
|
||||
server-side SSL socket should be created from a normal socket returned from
|
||||
`accept()` on a non-SSL listening server socket.
|
||||
|
||||
Takes a stream `sock` (usually usocket.socket instance of ``SOCK_STREAM`` type),
|
||||
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
|
||||
an SSL context. Returned object has the usual stream interface methods like
|
||||
`read()`, `write()`, etc. In MicroPython, the returned object does not expose
|
||||
socket interface and methods like `recv()`, `send()`. In particular, a
|
||||
server-side SSL socket should be created from a normal socket returned from
|
||||
`accept()` on a non-SSL listening server socket.
|
||||
Depending on the underlying module implementation for a particular board,
|
||||
some or all keyword arguments above may be not supported.
|
||||
|
||||
.. warning::
|
||||
.. warning::
|
||||
|
||||
Currently, this function does NOT validate server certificates, which makes
|
||||
an SSL connection established prone to man-in-the-middle attacks.
|
||||
Some implementations of ``ssl`` module do NOT validate server certificates,
|
||||
which makes an SSL connection established prone to man-in-the-middle attacks.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. data:: ssl.SSLError
|
||||
|
||||
Functions
|
||||
---------
|
||||
This exception does NOT exist. Instead its base class, OSError, is used.
|
||||
|
||||
.. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None)
|
||||
Constants
|
||||
---------
|
||||
|
||||
Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of
|
||||
``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM``
|
||||
socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example::
|
||||
.. data:: ssl.CERT_NONE
|
||||
ssl.CERT_OPTIONAL
|
||||
ssl.CERT_REQUIRED
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
|
||||
|
||||
Certificates must be used in order to validate the other side of the connection, and also to
|
||||
authenticate ourselves with the other end. Such certificates must be stored as files using the
|
||||
FTP server, and they must be placed in specific paths with specific names.
|
||||
|
||||
- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'**
|
||||
- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'**
|
||||
- The key for our own certificate goes in: **'/flash/cert/private.key'**
|
||||
|
||||
.. note::
|
||||
|
||||
When these files are stored, they are placed inside the internal **hidden** file system
|
||||
(just like firmware updates), and therefore they are never visible.
|
||||
|
||||
For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located
|
||||
in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_
|
||||
and put it in '/flash/cert/'. Then do::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
|
||||
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
|
||||
|
||||
SSL sockets inherit all methods and from the standard sockets, see the :mod:`usocket` module.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. data:: ssl.SSLError
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: ssl.CERT_NONE
|
||||
.. data:: ssl.CERT_OPTIONAL
|
||||
.. data:: ssl.CERT_REQUIRED
|
||||
|
||||
supported values in ``cert_reqs``
|
||||
Supported values for `cert_reqs` parameter.
|
||||
|
@ -240,6 +240,23 @@ Additional Pin methods:
|
||||
Returns a list of the alternate functions supported by the pin. List items are
|
||||
a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)``
|
||||
|
||||
Additional details for machine.I2C
|
||||
----------------------------------
|
||||
|
||||
On the WiPy there is a single hardware I2C peripheral, identified by "0". By
|
||||
default this is the peripheral that is used when constructing an I2C instance.
|
||||
The default pins are GP23 for SCL and GP13 for SDA, and one can create the
|
||||
default I2C peripheral simply by doing::
|
||||
|
||||
i2c = machine.I2C()
|
||||
|
||||
The pins and frequency can be specified as::
|
||||
|
||||
i2c = machine.I2C(freq=400000, scl='GP23', sda='GP13')
|
||||
|
||||
Only certain pins can be used as SCL/SDA. Please refer to the pinout for further
|
||||
information.
|
||||
|
||||
Known issues
|
||||
------------
|
||||
|
||||
@ -254,6 +271,29 @@ SSL sockets need to be created the following way before wrapping them with.
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
|
||||
Certificates must be used in order to validate the other side of the connection, and also to
|
||||
authenticate ourselves with the other end. Such certificates must be stored as files using the
|
||||
FTP server, and they must be placed in specific paths with specific names.
|
||||
|
||||
- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'**
|
||||
- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'**
|
||||
- The key for our own certificate goes in: **'/flash/cert/private.key'**
|
||||
|
||||
.. note::
|
||||
|
||||
When these files are stored, they are placed inside the internal **hidden** file system
|
||||
(just like firmware updates), and therefore they are never visible.
|
||||
|
||||
For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located
|
||||
in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_.
|
||||
and put it in '/flash/cert/'. Then do::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
|
||||
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
|
||||
|
||||
Incompatibilities in uhashlib module
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -273,3 +313,13 @@ Example::
|
||||
...
|
||||
hash.update('12345') # last chunk may be of any length
|
||||
hash.digest()
|
||||
|
||||
Unrelated function in machine module
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. function:: main(filename)
|
||||
|
||||
Set the filename of the main script to run after boot.py is finished. If
|
||||
this function is not called then the default file main.py will be executed.
|
||||
|
||||
It only makes sense to call this function from within boot.py.
|
||||
|
@ -112,7 +112,7 @@ See :ref:`machine.I2C <machine.I2C>`. ::
|
||||
|
||||
from machine import I2C
|
||||
# configure the I2C bus
|
||||
i2c = I2C(0, I2C.MASTER, baudrate=100000)
|
||||
i2c = I2C(baudrate=100000)
|
||||
i2c.scan() # returns list of slave addresses
|
||||
i2c.writeto(0x42, 'hello') # send 5 bytes to slave with address 0x42
|
||||
i2c.readfrom(0x42, 5) # receive 5 bytes from slave
|
||||
|
@ -79,6 +79,16 @@ $ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy
|
||||
|
||||
The image produced is `build/firmware-combined.bin`, to be flashed at 0x00000.
|
||||
|
||||
__512KB FlashROM version__
|
||||
|
||||
The normal build described above requires modules with at least 1MB of FlashROM
|
||||
onboard. There's a special configuration for 512KB modules, which can be
|
||||
built with `make 512k`. This configuration is highly limited, lacks filesystem
|
||||
support, WebREPL, and has many other features disabled. It's mostly suitable
|
||||
for advanced users who are interested to fine-tune options to achieve a required
|
||||
setup. If you are an end user, please consider using a module with at least 1MB
|
||||
of FlashROM.
|
||||
|
||||
First start
|
||||
-----------
|
||||
|
||||
@ -110,7 +120,7 @@ http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
While the port is still in alpha, it's known to be generally stable. If you
|
||||
While the port is in beta, it's known to be generally stable. If you
|
||||
experience strange bootloops, crashes, lockups, here's a list to check against:
|
||||
|
||||
- You didn't erase flash before programming MicroPython firmware.
|
||||
|
@ -287,7 +287,7 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c
|
||||
}
|
||||
|
||||
// constructor(id, ...)
|
||||
STATIC mp_obj_t pyb_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// get the wanted pin object
|
||||
@ -436,7 +436,7 @@ const mp_obj_type_t pyb_pin_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Pin,
|
||||
.print = pyb_pin_print,
|
||||
.make_new = pyb_pin_make_new,
|
||||
.make_new = mp_pin_make_new,
|
||||
.call = pyb_pin_call,
|
||||
.protocol = &pin_pin_p,
|
||||
.locals_dict = (mp_obj_t)&pyb_pin_locals_dict,
|
||||
|
@ -73,6 +73,7 @@
|
||||
#define MICROPY_PY_UZLIB (1)
|
||||
#define MICROPY_PY_LWIP (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
|
||||
#define MICROPY_PY_MACHINE_PULSE (1)
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_SPI (1)
|
||||
|
@ -2,4 +2,4 @@ from machine import Pin, Signal
|
||||
|
||||
# ESP12 module as used by many boards
|
||||
# Blue LED on pin 2, active low (inverted)
|
||||
LED = Signal(Pin(2, Pin.OUT), inverted=True)
|
||||
LED = Signal(Pin(2, Pin.OUT), invert=True)
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "py/mpconfig.h"
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/virtpin.h"
|
||||
@ -37,24 +39,77 @@
|
||||
typedef struct _machine_signal_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t pin;
|
||||
bool inverted;
|
||||
bool invert;
|
||||
} machine_signal_t;
|
||||
|
||||
STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
enum { ARG_pin, ARG_inverted };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_OBJ | MP_ARG_REQUIRED },
|
||||
{ MP_QSTR_inverted, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
mp_obj_t pin = args[0];
|
||||
bool invert = false;
|
||||
|
||||
mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)];
|
||||
#if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
|
||||
mp_pin_p_t *pin_p = NULL;
|
||||
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args);
|
||||
if (MP_OBJ_IS_OBJ(pin)) {
|
||||
mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
|
||||
pin_p = (mp_pin_p_t*)pin_base->type->protocol;
|
||||
}
|
||||
|
||||
if (pin_p == NULL) {
|
||||
// If first argument isn't a Pin-like object, we filter out "invert"
|
||||
// from keyword arguments and pass them all to the exported Pin
|
||||
// constructor to create one.
|
||||
mp_obj_t pin_args[n_args + n_kw * 2];
|
||||
memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
|
||||
const mp_obj_t *src = args + n_args;
|
||||
mp_obj_t *dst = pin_args + n_args;
|
||||
mp_obj_t *sig_value = NULL;
|
||||
for (size_t cnt = n_kw; cnt; cnt--) {
|
||||
if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
|
||||
invert = mp_obj_is_true(src[1]);
|
||||
n_kw--;
|
||||
} else {
|
||||
*dst++ = *src;
|
||||
*dst++ = src[1];
|
||||
}
|
||||
if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {
|
||||
// Value is pertained to Signal, so we should invert
|
||||
// it for Pin if needed, and we should do it only when
|
||||
// inversion status is guaranteedly known.
|
||||
sig_value = dst - 1;
|
||||
}
|
||||
src += 2;
|
||||
}
|
||||
|
||||
if (invert && sig_value != NULL) {
|
||||
*sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);
|
||||
}
|
||||
|
||||
// Here we pass NULL as a type, hoping that mp_pin_make_new()
|
||||
// will just ignore it as set a concrete type. If not, we'd need
|
||||
// to expose port's "default" pin type too.
|
||||
pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// Otherwise there should be 1 or 2 args
|
||||
{
|
||||
if (n_args == 1) {
|
||||
if (n_kw == 0) {
|
||||
} else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
|
||||
invert = mp_obj_is_true(args[1]);
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
error:
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
machine_signal_t *o = m_new_obj(machine_signal_t);
|
||||
o->base.type = type;
|
||||
o->pin = parsed_args[ARG_pin].u_obj;
|
||||
o->inverted = parsed_args[ARG_inverted].u_bool;
|
||||
o->pin = pin;
|
||||
o->invert = invert;
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
@ -64,10 +119,10 @@ STATIC mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg
|
||||
|
||||
switch (request) {
|
||||
case MP_PIN_READ: {
|
||||
return mp_virtual_pin_read(self->pin) ^ self->inverted;
|
||||
return mp_virtual_pin_read(self->pin) ^ self->invert;
|
||||
}
|
||||
case MP_PIN_WRITE: {
|
||||
mp_virtual_pin_write(self->pin, arg ^ self->inverted);
|
||||
mp_virtual_pin_write(self->pin, arg ^ self->invert);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
mp_int_t v = mp_obj_get_int(val);
|
||||
mp_int_t v = mp_obj_get_int_truncated(val);
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
((uint8_t*)p)[index] = (uint8_t)v; return;
|
||||
|
@ -38,3 +38,6 @@ typedef struct _mp_pin_p_t {
|
||||
|
||||
int mp_virtual_pin_read(mp_obj_t pin);
|
||||
void mp_virtual_pin_write(mp_obj_t pin, int value);
|
||||
|
||||
// If a port exposes a Pin object, it's constructor should be like this
|
||||
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
|
Binary file not shown.
@ -125,7 +125,7 @@ void Default_Handler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
|
||||
const uint32_t isr_vector[] __attribute__((section(".isr_vector"))) = {
|
||||
(uint32_t)&_estack,
|
||||
(uint32_t)&Reset_Handler,
|
||||
(uint32_t)&Default_Handler, // NMI_Handler
|
||||
|
@ -44,6 +44,7 @@
|
||||
#define MICROPY_COMP_CONST (1)
|
||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
|
||||
|
2
py/bc.c
2
py/bc.c
@ -304,7 +304,7 @@ STATIC const byte opcode_format_table[64] = {
|
||||
OC4(U, U, U, U), // 0x0c-0x0f
|
||||
OC4(B, B, B, U), // 0x10-0x13
|
||||
OC4(V, U, Q, V), // 0x14-0x17
|
||||
OC4(B, U, V, V), // 0x18-0x1b
|
||||
OC4(B, V, V, Q), // 0x18-0x1b
|
||||
OC4(Q, Q, Q, Q), // 0x1c-0x1f
|
||||
OC4(B, B, V, V), // 0x20-0x23
|
||||
OC4(Q, Q, Q, B), // 0x24-0x27
|
||||
|
13
py/bc0.h
13
py/bc0.h
@ -37,12 +37,13 @@
|
||||
#define MP_BC_LOAD_CONST_OBJ (0x17) // ptr
|
||||
#define MP_BC_LOAD_NULL (0x18)
|
||||
|
||||
#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_FAST_N (0x19) // uint
|
||||
#define MP_BC_LOAD_DEREF (0x1a) // uint
|
||||
#define MP_BC_LOAD_NAME (0x1b) // qstr
|
||||
#define MP_BC_LOAD_GLOBAL (0x1c) // qstr
|
||||
#define MP_BC_LOAD_ATTR (0x1d) // qstr
|
||||
#define MP_BC_LOAD_METHOD (0x1e) // qstr
|
||||
#define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr
|
||||
#define MP_BC_LOAD_BUILD_CLASS (0x20)
|
||||
#define MP_BC_LOAD_SUBSCR (0x21)
|
||||
|
||||
|
152
py/compile.c
152
py/compile.c
@ -115,7 +115,6 @@ typedef struct _compiler_t {
|
||||
|
||||
uint8_t is_repl;
|
||||
uint8_t pass; // holds enum type pass_kind_t
|
||||
uint8_t func_arg_is_super; // used to compile special case of super() function call
|
||||
uint8_t have_star;
|
||||
|
||||
// try to keep compiler clean from nlr
|
||||
@ -586,8 +585,16 @@ STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int
|
||||
}
|
||||
|
||||
STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_varargslist_star)) {
|
||||
// For efficiency of the code below we extract the parse-node kind here
|
||||
int pn_kind;
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
pn_kind = -1;
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pn));
|
||||
pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn);
|
||||
}
|
||||
|
||||
if (pn_kind == PN_typedargslist_star || pn_kind == PN_varargslist_star) {
|
||||
comp->have_star = true;
|
||||
/* don't need to distinguish bare from named star
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
@ -598,8 +605,7 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn)
|
||||
}
|
||||
*/
|
||||
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_dbl_star)
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_varargslist_dbl_star)) {
|
||||
} else if (pn_kind == PN_typedargslist_dbl_star || pn_kind == PN_varargslist_dbl_star) {
|
||||
// named double star
|
||||
// TODO do we need to do anything with this?
|
||||
|
||||
@ -607,14 +613,14 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn)
|
||||
mp_parse_node_t pn_id;
|
||||
mp_parse_node_t pn_colon;
|
||||
mp_parse_node_t pn_equal;
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
if (pn_kind == -1) {
|
||||
// this parameter is just an id
|
||||
|
||||
pn_id = pn;
|
||||
pn_colon = MP_PARSE_NODE_NULL;
|
||||
pn_equal = MP_PARSE_NODE_NULL;
|
||||
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_name)) {
|
||||
} else if (pn_kind == PN_typedargslist_name) {
|
||||
// this parameter has a colon and/or equal specifier
|
||||
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
@ -623,7 +629,7 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn)
|
||||
pn_equal = pns->nodes[2];
|
||||
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_varargslist_name)); // should be
|
||||
assert(pn_kind == PN_varargslist_name); // should be
|
||||
// this parameter has an equal specifier
|
||||
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
@ -755,7 +761,6 @@ STATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pn
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) {
|
||||
parents = MP_PARSE_NODE_NULL;
|
||||
}
|
||||
comp->func_arg_is_super = false;
|
||||
compile_trailer_paren_helper(comp, parents, false, 2);
|
||||
|
||||
// return its name (the 'C' in class C(...):")
|
||||
@ -829,7 +834,6 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// nodes[1] contains arguments to the decorator function, if any
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
|
||||
// call the decorator function with the arguments in nodes[1]
|
||||
comp->func_arg_is_super = false;
|
||||
compile_node(comp, pns_decorator->nodes[1]);
|
||||
}
|
||||
}
|
||||
@ -973,7 +977,8 @@ STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
|
||||
// no argument to 'return', so return None
|
||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {
|
||||
} else if (MICROPY_COMP_RETURN_IF_EXPR
|
||||
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {
|
||||
// special case when returning an if-expression; to match CPython optimisation
|
||||
mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0];
|
||||
mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1];
|
||||
@ -1422,7 +1427,7 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
mp_parse_node_struct_t *pns_it = (mp_parse_node_struct_t*)pns->nodes[1];
|
||||
if (MP_PARSE_NODE_IS_ID(pns_it->nodes[0])
|
||||
&& MP_PARSE_NODE_LEAF_ARG(pns_it->nodes[0]) == MP_QSTR_range
|
||||
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns_it->nodes[1], PN_trailer_paren)) {
|
||||
&& MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pns_it->nodes[1]) == PN_trailer_paren) {
|
||||
mp_parse_node_t pn_range_args = ((mp_parse_node_struct_t*)pns_it->nodes[1])->nodes[0];
|
||||
mp_parse_node_t *args;
|
||||
int n_args = mp_parse_node_extract_list(&pn_range_args, PN_arglist, &args);
|
||||
@ -1689,7 +1694,7 @@ STATIC void compile_yield_from(compiler_t *comp) {
|
||||
|
||||
#if MICROPY_PY_ASYNC_AWAIT
|
||||
STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
|
||||
EMIT_ARG(load_method, method);
|
||||
EMIT_ARG(load_method, method, false);
|
||||
EMIT_ARG(call_method, 0, 0, 0);
|
||||
compile_yield_from(comp);
|
||||
}
|
||||
@ -1780,7 +1785,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
|
||||
}
|
||||
|
||||
compile_load_id(comp, context);
|
||||
EMIT_ARG(load_method, MP_QSTR___aexit__);
|
||||
EMIT_ARG(load_method, MP_QSTR___aexit__, false);
|
||||
|
||||
EMIT_ARG(setup_except, try_exception_label);
|
||||
compile_increase_except_level(comp);
|
||||
@ -2167,10 +2172,85 @@ STATIC void compile_factor_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
|
||||
STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// this is to handle special super() call
|
||||
comp->func_arg_is_super = MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super;
|
||||
// compile the subject of the expression
|
||||
compile_node(comp, pns->nodes[0]);
|
||||
|
||||
compile_generic_all_nodes(comp, pns);
|
||||
// compile_atom_expr_await may call us with a NULL node
|
||||
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the array of trailers (known to be an array of PARSE_NODE_STRUCT)
|
||||
size_t num_trail = 1;
|
||||
mp_parse_node_struct_t **pns_trail = (mp_parse_node_struct_t**)&pns->nodes[1];
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_atom_expr_trailers) {
|
||||
num_trail = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_trail[0]);
|
||||
pns_trail = (mp_parse_node_struct_t**)&pns_trail[0]->nodes[0];
|
||||
}
|
||||
|
||||
// the current index into the array of trailers
|
||||
size_t i = 0;
|
||||
|
||||
// handle special super() call
|
||||
if (comp->scope_cur->kind == SCOPE_FUNCTION
|
||||
&& MP_PARSE_NODE_IS_ID(pns->nodes[0])
|
||||
&& MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_super
|
||||
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren
|
||||
&& MP_PARSE_NODE_IS_NULL(pns_trail[0]->nodes[0])) {
|
||||
// at this point we have matched "super()" within a function
|
||||
|
||||
// load the class for super to search for a parent
|
||||
compile_load_id(comp, MP_QSTR___class__);
|
||||
|
||||
// look for first argument to function (assumes it's "self")
|
||||
bool found = false;
|
||||
id_info_t *id = &comp->scope_cur->id_info[0];
|
||||
for (size_t n = comp->scope_cur->id_info_len; n > 0; --n, ++id) {
|
||||
if (id->flags & ID_FLAG_IS_PARAM) {
|
||||
// first argument found; load it
|
||||
compile_load_id(comp, id->qst);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns_trail[0],
|
||||
"super() can't find self"); // really a TypeError
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_trail >= 3
|
||||
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[1]) == PN_trailer_period
|
||||
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[2]) == PN_trailer_paren) {
|
||||
// optimisation for method calls super().f(...), to eliminate heap allocation
|
||||
mp_parse_node_struct_t *pns_period = pns_trail[1];
|
||||
mp_parse_node_struct_t *pns_paren = pns_trail[2];
|
||||
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), true);
|
||||
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
|
||||
i = 3;
|
||||
} else {
|
||||
// a super() call
|
||||
EMIT_ARG(call_function, 2, 0, 0);
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// compile the remaining trailers
|
||||
for (; i < num_trail; i++) {
|
||||
if (i + 1 < num_trail
|
||||
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[i]) == PN_trailer_period
|
||||
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[i + 1]) == PN_trailer_paren) {
|
||||
// optimisation for method calls a.f(...), following PyPy
|
||||
mp_parse_node_struct_t *pns_period = pns_trail[i];
|
||||
mp_parse_node_struct_t *pns_paren = pns_trail[i + 1];
|
||||
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), false);
|
||||
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
|
||||
i += 1;
|
||||
} else {
|
||||
// node is one of: trailer_paren, trailer_bracket, trailer_period
|
||||
compile_node(comp, (mp_parse_node_t)pns_trail[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
@ -2181,23 +2261,6 @@ STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
|
||||
// function to call is on top of stack
|
||||
|
||||
// this is to handle special super() call
|
||||
if (MP_PARSE_NODE_IS_NULL(pn_arglist) && comp->func_arg_is_super && comp->scope_cur->kind == SCOPE_FUNCTION) {
|
||||
compile_load_id(comp, MP_QSTR___class__);
|
||||
// look for first argument to function (assumes it's "self")
|
||||
for (int i = 0; i < comp->scope_cur->id_info_len; i++) {
|
||||
id_info_t *id = &comp->scope_cur->id_info[i];
|
||||
if (id->flags & ID_FLAG_IS_PARAM) {
|
||||
// first argument found; load it and call super
|
||||
compile_load_id(comp, id->qst);
|
||||
EMIT_ARG(call_function, 2, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "super() call cannot find self"); // really a TypeError
|
||||
return;
|
||||
}
|
||||
|
||||
// get the list of arguments
|
||||
mp_parse_node_t *args;
|
||||
int n_args = mp_parse_node_extract_list(&pn_arglist, PN_arglist, &args);
|
||||
@ -2277,23 +2340,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void compile_atom_expr_trailers(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
if (i + 1 < num_nodes && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i], PN_trailer_period) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[i + 1], PN_trailer_paren)) {
|
||||
// optimisation for method calls a.f(...), following PyPy
|
||||
mp_parse_node_struct_t *pns_period = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
mp_parse_node_struct_t *pns_paren = (mp_parse_node_struct_t*)pns->nodes[i + 1];
|
||||
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0])); // get the method
|
||||
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
|
||||
i += 1;
|
||||
} else {
|
||||
compile_node(comp, pns->nodes[i]);
|
||||
}
|
||||
comp->func_arg_is_super = false;
|
||||
}
|
||||
}
|
||||
|
||||
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
|
||||
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
|
||||
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);
|
||||
@ -2825,14 +2871,14 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn
|
||||
} else {
|
||||
EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5);
|
||||
}
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_iter, PN_comp_if)) {
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_if) {
|
||||
// if condition
|
||||
mp_parse_node_struct_t *pns_comp_if = (mp_parse_node_struct_t*)pn_iter;
|
||||
c_if_cond(comp, pns_comp_if->nodes[0], false, l_top);
|
||||
pn_iter = pns_comp_if->nodes[1];
|
||||
goto tail_recursion;
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_iter, PN_comp_for)); // should be
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn_iter) == PN_comp_for); // should be
|
||||
// for loop
|
||||
mp_parse_node_struct_t *pns_comp_for2 = (mp_parse_node_struct_t*)pn_iter;
|
||||
compile_node(comp, pns_comp_for2->nodes[1]);
|
||||
|
@ -88,7 +88,7 @@ typedef struct _emit_method_table_t {
|
||||
void (*load_const_obj)(emit_t *emit, mp_obj_t obj);
|
||||
void (*load_null)(emit_t *emit);
|
||||
void (*load_attr)(emit_t *emit, qstr qst);
|
||||
void (*load_method)(emit_t *emit, qstr qst);
|
||||
void (*load_method)(emit_t *emit, qstr qst, bool is_super);
|
||||
void (*load_build_class)(emit_t *emit);
|
||||
void (*load_subscr)(emit_t *emit);
|
||||
void (*store_attr)(emit_t *emit, qstr qst);
|
||||
@ -205,7 +205,7 @@ void mp_emit_bc_load_const_str(emit_t *emit, qstr qst);
|
||||
void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj);
|
||||
void mp_emit_bc_load_null(emit_t *emit);
|
||||
void mp_emit_bc_load_attr(emit_t *emit, qstr qst);
|
||||
void mp_emit_bc_load_method(emit_t *emit, qstr qst);
|
||||
void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super);
|
||||
void mp_emit_bc_load_build_class(emit_t *emit);
|
||||
void mp_emit_bc_load_subscr(emit_t *emit);
|
||||
void mp_emit_bc_store_attr(emit_t *emit, qstr qst);
|
||||
|
@ -594,9 +594,9 @@ void mp_emit_bc_load_attr(emit_t *emit, qstr qst) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_emit_bc_load_method(emit_t *emit, qstr qst) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qst);
|
||||
void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
|
||||
emit_bc_pre(emit, 1 - 2 * is_super);
|
||||
emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst);
|
||||
}
|
||||
|
||||
void mp_emit_bc_load_build_class(emit_t *emit) {
|
||||
|
@ -85,6 +85,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
[MP_F_LOAD_BUILD_CLASS] = 0,
|
||||
[MP_F_LOAD_ATTR] = 2,
|
||||
[MP_F_LOAD_METHOD] = 3,
|
||||
[MP_F_LOAD_SUPER_METHOD] = 2,
|
||||
[MP_F_STORE_NAME] = 2,
|
||||
[MP_F_STORE_GLOBAL] = 2,
|
||||
[MP_F_STORE_ATTR] = 3,
|
||||
@ -1065,12 +1066,18 @@ STATIC void emit_native_load_attr(emit_t *emit, qstr qst) {
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_method(emit_t *emit, qstr qst) {
|
||||
vtype_kind_t vtype_base;
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
|
||||
assert(vtype_base == VTYPE_PYOBJ);
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name
|
||||
STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) {
|
||||
if (is_super) {
|
||||
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name
|
||||
} else {
|
||||
vtype_kind_t vtype_base;
|
||||
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
|
||||
assert(vtype_base == VTYPE_PYOBJ);
|
||||
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
|
||||
emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_build_class(emit_t *emit) {
|
||||
|
14
py/gc.c
14
py/gc.c
@ -258,18 +258,20 @@ STATIC void gc_sweep(void) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
if (FTB_GET(block)) {
|
||||
#if MICROPY_PY_THREAD
|
||||
// TODO need to think about reentrancy with finaliser code
|
||||
assert(!"finaliser with threading not implemented");
|
||||
#endif
|
||||
mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block);
|
||||
if (obj->type != NULL) {
|
||||
// if the object has a type then see if it has a __del__ method
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
// load_method returned a method
|
||||
mp_call_method_n_kw(0, 0, dest);
|
||||
// load_method returned a method, execute it in a protected environment
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
mp_sched_lock();
|
||||
#endif
|
||||
mp_call_function_1_protected(dest[0], dest[1]);
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
mp_sched_unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// clear finaliser flag
|
||||
|
@ -261,7 +261,7 @@ DEF_RULE(atom_expr_await, c(atom_expr_await), and(3), tok(KW_AWAIT), rule(atom),
|
||||
DEF_RULE_NC(atom_expr, or(1), rule(atom_expr_normal))
|
||||
#endif
|
||||
DEF_RULE(atom_expr_normal, c(atom_expr_normal), and_ident(2), rule(atom), opt_rule(atom_expr_trailers))
|
||||
DEF_RULE(atom_expr_trailers, c(atom_expr_trailers), one_or_more, rule(trailer))
|
||||
DEF_RULE_NC(atom_expr_trailers, one_or_more, rule(trailer))
|
||||
DEF_RULE_NC(power_dbl_star, and_ident(2), tok(OP_DBL_STAR), rule(factor))
|
||||
|
||||
// atom: '(' [yield_expr|testlist_comp] ')' | '[' [testlist_comp] ']' | '{' [dictorsetmaker] '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
// Various builtins specific to MicroPython runtime,
|
||||
// living in micropython module
|
||||
@ -129,6 +130,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
|
||||
#endif
|
||||
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
STATIC mp_obj_t mp_micropython_kbd_intr(mp_obj_t int_chr_in) {
|
||||
mp_hal_set_interrupt_char(mp_obj_get_int(int_chr_in));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_micropython_kbd_intr_obj, mp_micropython_kbd_intr);
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
STATIC mp_obj_t mp_micropython_schedule(mp_obj_t function, mp_obj_t arg) {
|
||||
if (!mp_sched_schedule(function, arg)) {
|
||||
@ -162,6 +171,9 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) },
|
||||
#endif
|
||||
#if MICROPY_KBD_EXCEPTION
|
||||
{ MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
{ MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) },
|
||||
#endif
|
||||
|
@ -353,6 +353,12 @@
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable optimisation of: return a if b else c
|
||||
// Costs about 80 bytes (Thumb2) and saves 2 bytes of bytecode for each use
|
||||
#ifndef MICROPY_COMP_RETURN_IF_EXPR
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Internal debugging stuff */
|
||||
|
||||
@ -445,7 +451,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Whether to provide the mp_kbd_exception object
|
||||
// Whether to provide the mp_kbd_exception object, and micropython.kbd_intr function
|
||||
#ifndef MICROPY_KBD_EXCEPTION
|
||||
#define MICROPY_KBD_EXCEPTION (0)
|
||||
#endif
|
||||
@ -548,6 +554,12 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT)
|
||||
#endif
|
||||
|
||||
// Whether to provide a high-quality hash for float and complex numbers.
|
||||
// Otherwise the default is a very simple but correct hashing function.
|
||||
#ifndef MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (0)
|
||||
#endif
|
||||
|
||||
// Enable features which improve CPython compatibility
|
||||
// but may lead to more code size/memory usage.
|
||||
// TODO: Originally intended as generic category to not
|
||||
|
@ -120,8 +120,8 @@ typedef struct _mp_state_vm_t {
|
||||
// memory for exception arguments if we can't allocate RAM
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||
#if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
|
||||
// statically allocated buf
|
||||
byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
|
||||
// statically allocated buf (needs to be aligned to mp_obj_t)
|
||||
mp_obj_t mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE / sizeof(mp_obj_t)];
|
||||
#else
|
||||
// dynamically allocated buf
|
||||
byte *mp_emergency_exception_buf;
|
||||
|
@ -133,6 +133,7 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
|
||||
mp_load_build_class,
|
||||
mp_load_attr,
|
||||
mp_load_method,
|
||||
mp_load_super_method,
|
||||
mp_store_name,
|
||||
mp_store_global,
|
||||
mp_store_attr,
|
||||
|
@ -29,10 +29,14 @@
|
||||
#if MICROPY_NLR_SETJMP
|
||||
|
||||
void nlr_setjmp_jump(void *val) {
|
||||
nlr_buf_t *buf = MP_STATE_THREAD(nlr_top);
|
||||
MP_STATE_THREAD(nlr_top) = buf->prev;
|
||||
buf->ret_val = val;
|
||||
longjmp(buf->jmpbuf, 1);
|
||||
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
|
||||
nlr_buf_t *top = *top_ptr;
|
||||
if (top == NULL) {
|
||||
nlr_jump_fail(val);
|
||||
}
|
||||
top->ret_val = val;
|
||||
*top_ptr = top->prev;
|
||||
longjmp(top->jmpbuf, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
65
py/obj.h
65
py/obj.h
@ -470,16 +470,27 @@ typedef struct _mp_stream_p_t {
|
||||
} mp_stream_p_t;
|
||||
|
||||
struct _mp_obj_type_t {
|
||||
// A type is an object so must start with this entry, which points to mp_type_type.
|
||||
mp_obj_base_t base;
|
||||
|
||||
// The name of this type.
|
||||
qstr name;
|
||||
|
||||
// Corresponds to __repr__ and __str__ special methods.
|
||||
mp_print_fun_t print;
|
||||
mp_make_new_fun_t make_new; // to make an instance of the type
|
||||
|
||||
// Corresponds to __new__ and __init__ special methods, to make an instance of the type.
|
||||
mp_make_new_fun_t make_new;
|
||||
|
||||
// Corresponds to __call__ special method, ie T(...).
|
||||
mp_call_fun_t call;
|
||||
mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported
|
||||
mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported
|
||||
|
||||
// implements load, store and delete attribute
|
||||
// Implements unary and binary operations.
|
||||
// Can return MP_OBJ_NULL if the operation is not supported.
|
||||
mp_unary_op_fun_t unary_op;
|
||||
mp_binary_op_fun_t binary_op;
|
||||
|
||||
// Implements load, store and delete attribute.
|
||||
//
|
||||
// dest[0] = MP_OBJ_NULL means load
|
||||
// return: for fail, do nothing
|
||||
@ -492,35 +503,36 @@ struct _mp_obj_type_t {
|
||||
// for success set dest[0] = MP_OBJ_NULL
|
||||
mp_attr_fun_t attr;
|
||||
|
||||
mp_subscr_fun_t subscr; // implements load, store, delete subscripting
|
||||
// value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store
|
||||
// can return MP_OBJ_NULL if op not supported
|
||||
// Implements load, store and delete subscripting:
|
||||
// - value = MP_OBJ_SENTINEL means load
|
||||
// - value = MP_OBJ_NULL means delete
|
||||
// - all other values mean store the value
|
||||
// Can return MP_OBJ_NULL if operation not supported.
|
||||
mp_subscr_fun_t subscr;
|
||||
|
||||
// corresponds to __iter__ special method
|
||||
// can use given mp_obj_iter_buf_t to store iterator
|
||||
// otherwise can return a pointer to an object on the heap
|
||||
// Corresponds to __iter__ special method.
|
||||
// Can use the given mp_obj_iter_buf_t to store iterator object,
|
||||
// otherwise can return a pointer to an object on the heap.
|
||||
mp_getiter_fun_t getiter;
|
||||
|
||||
mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args)
|
||||
// Corresponds to __next__ special method. May return MP_OBJ_STOP_ITERATION
|
||||
// as an optimisation instead of raising StopIteration() with no args.
|
||||
mp_fun_1_t iternext;
|
||||
|
||||
// Implements the buffer protocol if supported by this type.
|
||||
mp_buffer_p_t buffer_p;
|
||||
|
||||
// One of disjoint protocols (interfaces), like mp_stream_p_t, etc.
|
||||
const void *protocol;
|
||||
|
||||
// these are for dynamically created types (classes)
|
||||
struct _mp_obj_tuple_t *bases_tuple;
|
||||
// A pointer to the parents of this type:
|
||||
// - 0 parents: pointer is NULL (object is implicitly the single parent)
|
||||
// - 1 parent: a pointer to the type of that parent
|
||||
// - 2 or more parents: pointer to a tuple object containing the parent types
|
||||
const void *parent;
|
||||
|
||||
// A dict mapping qstrs to objects local methods/constants/etc.
|
||||
struct _mp_obj_dict_t *locals_dict;
|
||||
|
||||
/*
|
||||
What we might need to add here:
|
||||
|
||||
len str tuple list map
|
||||
abs float complex
|
||||
hash bool int none str
|
||||
equal int str
|
||||
|
||||
unpack seq list tuple
|
||||
*/
|
||||
};
|
||||
|
||||
// Constant types, globally accessible
|
||||
@ -649,7 +661,6 @@ mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items);
|
||||
mp_obj_t mp_obj_new_dict(size_t n_args);
|
||||
mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items);
|
||||
mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
|
||||
mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj);
|
||||
mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self);
|
||||
mp_obj_t mp_obj_new_getitem_iter(mp_obj_t *args, mp_obj_iter_buf_t *iter_buf);
|
||||
mp_obj_t mp_obj_new_module(qstr module_name);
|
||||
@ -718,7 +729,11 @@ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t s
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// float
|
||||
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
mp_int_t mp_float_hash(mp_float_t val);
|
||||
#else
|
||||
static inline mp_int_t mp_float_hash(mp_float_t val) { return (mp_int_t)val; }
|
||||
#endif
|
||||
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
|
||||
|
||||
// complex
|
||||
|
@ -50,7 +50,11 @@ STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_
|
||||
mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
char buf[16];
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
const int precision = 6;
|
||||
#else
|
||||
const int precision = 7;
|
||||
#endif
|
||||
#else
|
||||
char buf[32];
|
||||
const int precision = 16;
|
||||
|
@ -577,8 +577,6 @@ const mp_obj_type_t mp_type_dict = {
|
||||
};
|
||||
|
||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
||||
STATIC const mp_rom_obj_tuple_t ordereddict_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_dict)}};
|
||||
|
||||
const mp_obj_type_t mp_type_ordereddict = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_OrderedDict,
|
||||
@ -588,7 +586,7 @@ const mp_obj_type_t mp_type_ordereddict = {
|
||||
.binary_op = dict_binary_op,
|
||||
.subscr = dict_subscr,
|
||||
.getiter = dict_getiter,
|
||||
.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&ordereddict_base_tuple,
|
||||
.parent = &mp_type_dict,
|
||||
.locals_dict = (mp_obj_dict_t*)&dict_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
@ -197,9 +197,6 @@ const mp_obj_type_t mp_type_BaseException = {
|
||||
.locals_dict = (mp_obj_dict_t*)&exc_locals_dict,
|
||||
};
|
||||
|
||||
#define MP_DEFINE_EXCEPTION_BASE(base_name) \
|
||||
STATIC const mp_rom_obj_tuple_t mp_type_ ## base_name ## _base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_ ## base_name)}};\
|
||||
|
||||
#define MP_DEFINE_EXCEPTION(exc_name, base_name) \
|
||||
const mp_obj_type_t mp_type_ ## exc_name = { \
|
||||
{ &mp_type_type }, \
|
||||
@ -207,23 +204,20 @@ const mp_obj_type_t mp_type_ ## exc_name = { \
|
||||
.print = mp_obj_exception_print, \
|
||||
.make_new = mp_obj_exception_make_new, \
|
||||
.attr = exception_attr, \
|
||||
.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&mp_type_ ## base_name ## _base_tuple, \
|
||||
.parent = &mp_type_ ## base_name, \
|
||||
};
|
||||
|
||||
// List of all exceptions, arranged as in the table at:
|
||||
// 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(GeneratorExit, BaseException)
|
||||
MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION_BASE(Exception)
|
||||
#if MICROPY_PY_ASYNC_AWAIT
|
||||
MP_DEFINE_EXCEPTION(StopAsyncIteration, Exception)
|
||||
#endif
|
||||
MP_DEFINE_EXCEPTION(StopIteration, Exception)
|
||||
MP_DEFINE_EXCEPTION(ArithmeticError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(ArithmeticError)
|
||||
//MP_DEFINE_EXCEPTION(FloatingPointError, ArithmeticError)
|
||||
MP_DEFINE_EXCEPTION(OverflowError, ArithmeticError)
|
||||
MP_DEFINE_EXCEPTION(ZeroDivisionError, ArithmeticError)
|
||||
@ -235,18 +229,15 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION(ImportError, Exception)
|
||||
//MP_DEFINE_EXCEPTION(IOError, Exception) use OSError instead
|
||||
MP_DEFINE_EXCEPTION(LookupError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(LookupError)
|
||||
MP_DEFINE_EXCEPTION(IndexError, LookupError)
|
||||
MP_DEFINE_EXCEPTION(KeyError, LookupError)
|
||||
MP_DEFINE_EXCEPTION(MemoryError, Exception)
|
||||
MP_DEFINE_EXCEPTION(NameError, Exception)
|
||||
/*
|
||||
MP_DEFINE_EXCEPTION_BASE(NameError)
|
||||
MP_DEFINE_EXCEPTION(UnboundLocalError, NameError)
|
||||
*/
|
||||
MP_DEFINE_EXCEPTION(OSError, Exception)
|
||||
#if MICROPY_PY_BUILTINS_TIMEOUTERROR
|
||||
MP_DEFINE_EXCEPTION_BASE(OSError)
|
||||
MP_DEFINE_EXCEPTION(TimeoutError, OSError)
|
||||
#endif
|
||||
/*
|
||||
@ -267,30 +258,24 @@ MP_DEFINE_EXCEPTION(Exception, BaseException)
|
||||
MP_DEFINE_EXCEPTION(ReferenceError, Exception)
|
||||
*/
|
||||
MP_DEFINE_EXCEPTION(RuntimeError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(RuntimeError)
|
||||
MP_DEFINE_EXCEPTION(NotImplementedError, RuntimeError)
|
||||
MP_DEFINE_EXCEPTION(SyntaxError, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(SyntaxError)
|
||||
MP_DEFINE_EXCEPTION(IndentationError, SyntaxError)
|
||||
/*
|
||||
MP_DEFINE_EXCEPTION_BASE(IndentationError)
|
||||
MP_DEFINE_EXCEPTION(TabError, IndentationError)
|
||||
*/
|
||||
//MP_DEFINE_EXCEPTION(SystemError, Exception)
|
||||
MP_DEFINE_EXCEPTION(TypeError, Exception)
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
MP_DEFINE_EXCEPTION_BASE(TypeError)
|
||||
MP_DEFINE_EXCEPTION(ViperTypeError, TypeError)
|
||||
#endif
|
||||
MP_DEFINE_EXCEPTION(ValueError, Exception)
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
MP_DEFINE_EXCEPTION_BASE(ValueError)
|
||||
MP_DEFINE_EXCEPTION(UnicodeError, ValueError)
|
||||
//TODO: Implement more UnicodeError subclasses which take arguments
|
||||
#endif
|
||||
/*
|
||||
MP_DEFINE_EXCEPTION(Warning, Exception)
|
||||
MP_DEFINE_EXCEPTION_BASE(Warning)
|
||||
MP_DEFINE_EXCEPTION(DeprecationWarning, Warning)
|
||||
MP_DEFINE_EXCEPTION(PendingDeprecationWarning, Warning)
|
||||
MP_DEFINE_EXCEPTION(RuntimeWarning, Warning)
|
||||
@ -348,7 +333,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
tuple->items[0] = MP_OBJ_FROM_PTR(str);
|
||||
|
||||
byte *str_data = (byte *)&str[1];
|
||||
uint max_len = MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size
|
||||
size_t max_len = (byte*)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size
|
||||
- str_data;
|
||||
|
||||
vstr_t vstr;
|
||||
@ -366,14 +351,14 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
|
||||
|
||||
o->args = tuple;
|
||||
|
||||
uint offset = &str_data[str->len] - MP_STATE_VM(mp_emergency_exception_buf);
|
||||
size_t offset = &str_data[str->len] - (byte*)MP_STATE_VM(mp_emergency_exception_buf);
|
||||
offset += sizeof(void *) - 1;
|
||||
offset &= ~(sizeof(void *) - 1);
|
||||
|
||||
if ((mp_emergency_exception_buf_size - offset) > (sizeof(o->traceback_data[0]) * 3)) {
|
||||
// We have room to store some traceback.
|
||||
o->traceback_data = (size_t*)((byte *)MP_STATE_VM(mp_emergency_exception_buf) + offset);
|
||||
o->traceback_alloc = (MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]);
|
||||
o->traceback_alloc = ((byte*)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - (byte *)o->traceback_data) / sizeof(o->traceback_data[0]);
|
||||
o->traceback_len = 0;
|
||||
}
|
||||
}
|
||||
|
@ -59,12 +59,65 @@ const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI};
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
// must return actual integer value if it fits in mp_int_t
|
||||
mp_int_t mp_float_hash(mp_float_t src) {
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
typedef uint64_t mp_float_uint_t;
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
typedef uint32_t mp_float_uint_t;
|
||||
#endif
|
||||
union {
|
||||
mp_float_t f;
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct { mp_float_uint_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
|
||||
#else
|
||||
struct { mp_float_uint_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
|
||||
#endif
|
||||
mp_float_uint_t i;
|
||||
} u = {.f = src};
|
||||
|
||||
mp_int_t val;
|
||||
const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
|
||||
if (adj_exp < 0) {
|
||||
// value < 1; must be sure to handle 0.0 correctly (ie return 0)
|
||||
val = u.i;
|
||||
} else {
|
||||
// if adj_exp is max then: u.p.frc==0 indicates inf, else NaN
|
||||
// else: 1 <= value
|
||||
mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);
|
||||
|
||||
if (adj_exp <= MP_FLOAT_FRAC_BITS) {
|
||||
// number may have a fraction; xor the integer part with the fractional part
|
||||
val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp))
|
||||
^ (frc & ((1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));
|
||||
} else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) {
|
||||
// the number is a (big) whole integer and will fit in val's signed-width
|
||||
val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS);
|
||||
} else {
|
||||
// integer part will overflow val's width so just use what bits we can
|
||||
val = frc;
|
||||
}
|
||||
}
|
||||
|
||||
if (u.p.sgn) {
|
||||
val = -val;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_float_t o_val = mp_obj_float_get(o_in);
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
char buf[16];
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
const int precision = 6;
|
||||
#else
|
||||
const int precision = 7;
|
||||
#endif
|
||||
#else
|
||||
char buf[32];
|
||||
const int precision = 16;
|
||||
|
@ -170,8 +170,10 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||
typedef mp_longint_impl_t fmt_int_t;
|
||||
typedef unsigned long long fmt_uint_t;
|
||||
#else
|
||||
typedef mp_int_t fmt_int_t;
|
||||
typedef mp_uint_t fmt_uint_t;
|
||||
#endif
|
||||
|
||||
void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
@ -224,7 +226,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
|
||||
fmt_int_t num;
|
||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||
// A small int; get the integer value to format.
|
||||
num = mp_obj_get_int(self_in);
|
||||
num = MP_OBJ_SMALL_INT_VALUE(self_in);
|
||||
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
|
||||
// Not a small int.
|
||||
@ -265,8 +267,9 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
|
||||
*(--b) = '0';
|
||||
} else {
|
||||
do {
|
||||
int c = num % base;
|
||||
num /= base;
|
||||
// The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic
|
||||
int c = (fmt_uint_t)num % base;
|
||||
num = (fmt_uint_t)num / base;
|
||||
if (c >= 10) {
|
||||
c += base_char - 10;
|
||||
} else {
|
||||
|
@ -116,6 +116,7 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf
|
||||
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) {
|
||||
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
|
||||
mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
memset(buf, 0, len);
|
||||
mpz_as_bytes(&self->mpz, big_endian, len, buf);
|
||||
}
|
||||
|
||||
|
@ -134,8 +134,6 @@ STATIC mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args,
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
|
||||
STATIC const mp_rom_obj_tuple_t namedtuple_base_tuple = {{&mp_type_tuple}, 1, {MP_ROM_PTR(&mp_type_tuple)}};
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) {
|
||||
mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields);
|
||||
memset(&o->base, 0, sizeof(o->base));
|
||||
@ -148,7 +146,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t
|
||||
o->base.attr = namedtuple_attr;
|
||||
o->base.subscr = mp_obj_tuple_subscr;
|
||||
o->base.getiter = mp_obj_tuple_getiter;
|
||||
o->base.bases_tuple = (mp_obj_tuple_t*)(mp_rom_obj_tuple_t*)&namedtuple_base_tuple;
|
||||
o->base.parent = &mp_type_tuple;
|
||||
o->n_fields = n_fields;
|
||||
for (size_t i = 0; i < n_fields; i++) {
|
||||
o->fields[i] = mp_obj_str_get_qstr(fields[i]);
|
||||
|
175
py/objtype.c
175
py/objtype.c
@ -57,26 +57,34 @@ STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs)
|
||||
}
|
||||
|
||||
STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
|
||||
size_t len = type->bases_tuple->len;
|
||||
mp_obj_t *items = type->bases_tuple->items;
|
||||
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
|
||||
const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(items[i]);
|
||||
if (bt == &mp_type_object) {
|
||||
// Not a "real" type
|
||||
continue;
|
||||
}
|
||||
if (mp_obj_is_native_type(bt)) {
|
||||
*last_native_base = bt;
|
||||
count++;
|
||||
for (;;) {
|
||||
if (type == &mp_type_object) {
|
||||
// Not a "real" type, end search here.
|
||||
return count;
|
||||
} else if (mp_obj_is_native_type(type)) {
|
||||
// Native types don't have parents (at least not from our perspective) so end.
|
||||
*last_native_base = type;
|
||||
return count + 1;
|
||||
} else if (type->parent == NULL) {
|
||||
// No parents so end search here.
|
||||
return count;
|
||||
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
|
||||
// Multiple parents, search through them all recursively.
|
||||
const mp_obj_tuple_t *parent_tuple = type->parent;
|
||||
const mp_obj_t *item = parent_tuple->items;
|
||||
const mp_obj_t *top = item + parent_tuple->len;
|
||||
for (; item < top; ++item) {
|
||||
assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
|
||||
const mp_obj_type_t *bt = (const mp_obj_type_t *)MP_OBJ_TO_PTR(*item);
|
||||
count += instance_count_native_bases(bt, last_native_base);
|
||||
}
|
||||
return count;
|
||||
} else {
|
||||
count += instance_count_native_bases(bt, last_native_base);
|
||||
// A single parent, use iteration to continue the search.
|
||||
type = type->parent;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// TODO
|
||||
@ -160,32 +168,31 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
|
||||
|
||||
// attribute not found, keep searching base classes
|
||||
|
||||
// for a const struct, this entry might be NULL
|
||||
if (type->bases_tuple == NULL) {
|
||||
if (type->parent == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = type->bases_tuple->len;
|
||||
mp_obj_t *items = type->bases_tuple->items;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < len - 1; i++) {
|
||||
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
|
||||
mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]);
|
||||
if (bt == &mp_type_object) {
|
||||
// Not a "real" type
|
||||
continue;
|
||||
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
|
||||
const mp_obj_tuple_t *parent_tuple = type->parent;
|
||||
const mp_obj_t *item = parent_tuple->items;
|
||||
const mp_obj_t *top = item + parent_tuple->len - 1;
|
||||
for (; item < top; ++item) {
|
||||
assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
|
||||
mp_obj_type_t *bt = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
|
||||
if (bt == &mp_type_object) {
|
||||
// Not a "real" type
|
||||
continue;
|
||||
}
|
||||
mp_obj_class_lookup(lookup, bt);
|
||||
if (lookup->dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mp_obj_class_lookup(lookup, bt);
|
||||
if (lookup->dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// search last base (simple tail recursion elimination)
|
||||
assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_type_type));
|
||||
type = (mp_obj_type_t*)MP_OBJ_TO_PTR(items[len - 1]);
|
||||
// search last base (simple tail recursion elimination)
|
||||
assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
|
||||
type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
|
||||
} else {
|
||||
type = type->parent;
|
||||
}
|
||||
if (type == &mp_type_object) {
|
||||
// Not a "real" type
|
||||
return;
|
||||
@ -946,14 +953,21 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
||||
o->getiter = instance_getiter;
|
||||
//o->iternext = ; not implemented
|
||||
o->buffer_p.get_buffer = instance_get_buffer;
|
||||
// Inherit protocol from a base class. This allows to define an
|
||||
// abstract base class which would translate C-level protocol to
|
||||
// Python method calls, and any subclass inheriting from it will
|
||||
// support this feature.
|
||||
|
||||
if (len > 0) {
|
||||
// Inherit protocol from a base class. This allows to define an
|
||||
// abstract base class which would translate C-level protocol to
|
||||
// Python method calls, and any subclass inheriting from it will
|
||||
// support this feature.
|
||||
o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol;
|
||||
|
||||
if (len >= 2) {
|
||||
o->parent = MP_OBJ_TO_PTR(bases_tuple);
|
||||
} else {
|
||||
o->parent = MP_OBJ_TO_PTR(items[0]);
|
||||
}
|
||||
}
|
||||
o->bases_tuple = MP_OBJ_TO_PTR(bases_tuple);
|
||||
|
||||
o->locals_dict = MP_OBJ_TO_PTR(locals_dict);
|
||||
|
||||
const mp_obj_type_t *native_base;
|
||||
@ -999,7 +1013,9 @@ STATIC mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size
|
||||
// 0 arguments are turned into 2 in the compiler
|
||||
// 1 argument is not yet implemented
|
||||
mp_arg_check_num(n_args, n_kw, 2, 2, false);
|
||||
return mp_obj_new_super(args[0], args[1]);
|
||||
mp_obj_super_t *o = m_new_obj(mp_obj_super_t);
|
||||
*o = (mp_obj_super_t){{type_in}, args[0], args[1]};
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
@ -1015,13 +1031,6 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
|
||||
mp_obj_type_t *type = MP_OBJ_TO_PTR(self->type);
|
||||
|
||||
// for a const struct, this entry might be NULL
|
||||
if (type->bases_tuple == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = type->bases_tuple->len;
|
||||
mp_obj_t *items = type->bases_tuple->items;
|
||||
struct class_lookup_data lookup = {
|
||||
.obj = MP_OBJ_TO_PTR(self->obj),
|
||||
.attr = attr,
|
||||
@ -1029,13 +1038,27 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
.dest = dest,
|
||||
.is_type = false,
|
||||
};
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
|
||||
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]));
|
||||
|
||||
if (type->parent == NULL) {
|
||||
// no parents, do nothing
|
||||
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
|
||||
const mp_obj_tuple_t *parent_tuple = type->parent;
|
||||
size_t len = parent_tuple->len;
|
||||
const mp_obj_t *items = parent_tuple->items;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
|
||||
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]));
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mp_obj_class_lookup(&lookup, type->parent);
|
||||
if (dest[0] != MP_OBJ_NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_class_lookup(&lookup, &mp_type_object);
|
||||
}
|
||||
|
||||
@ -1047,10 +1070,9 @@ const mp_obj_type_t mp_type_super = {
|
||||
.attr = super_attr,
|
||||
};
|
||||
|
||||
mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) {
|
||||
mp_obj_super_t *o = m_new_obj(mp_obj_super_t);
|
||||
*o = (mp_obj_super_t){{&mp_type_super}, type, obj};
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
void mp_load_super_method(qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]};
|
||||
mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -1073,27 +1095,28 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
|
||||
|
||||
const mp_obj_type_t *self = MP_OBJ_TO_PTR(object);
|
||||
|
||||
// for a const struct, this entry might be NULL
|
||||
if (self->bases_tuple == NULL) {
|
||||
if (self->parent == NULL) {
|
||||
// type has no parents
|
||||
return false;
|
||||
}
|
||||
} else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) {
|
||||
// get the base objects (they should be type objects)
|
||||
const mp_obj_tuple_t *parent_tuple = self->parent;
|
||||
const mp_obj_t *item = parent_tuple->items;
|
||||
const mp_obj_t *top = item + parent_tuple->len - 1;
|
||||
|
||||
// get the base objects (they should be type objects)
|
||||
size_t len = self->bases_tuple->len;
|
||||
mp_obj_t *items = self->bases_tuple->items;
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate through the base objects
|
||||
for (size_t i = 0; i < len - 1; i++) {
|
||||
if (mp_obj_is_subclass_fast(items[i], classinfo)) {
|
||||
return true;
|
||||
// iterate through the base objects
|
||||
for (; item < top; ++item) {
|
||||
if (mp_obj_is_subclass_fast(*item, classinfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search last base (simple tail recursion elimination)
|
||||
object = items[len - 1];
|
||||
// search last base (simple tail recursion elimination)
|
||||
object = *item;
|
||||
} else {
|
||||
// type has 1 parent
|
||||
object = MP_OBJ_FROM_PTR(self->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
#include "py/smallint.h"
|
||||
|
||||
// The current version of .mpy files
|
||||
#define MPY_VERSION (1)
|
||||
#define MPY_VERSION (2)
|
||||
|
||||
// The feature flags byte encodes the compile-time config options that
|
||||
// affect the generate bytecode.
|
||||
|
@ -78,7 +78,7 @@ void mp_init(void) {
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_alloc = 0;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_len = 0;
|
||||
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
|
||||
MP_STATE_VM(mp_kbd_exception).args = mp_const_empty_tuple;
|
||||
MP_STATE_VM(mp_kbd_exception).args = (mp_obj_tuple_t*)&mp_const_empty_tuple_obj;
|
||||
#endif
|
||||
|
||||
// call port specific initialization if any
|
||||
|
@ -131,6 +131,7 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr);
|
||||
void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
|
||||
void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest);
|
||||
void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest);
|
||||
void mp_load_super_method(qstr attr, mp_obj_t *dest);
|
||||
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);
|
||||
|
||||
mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf);
|
||||
|
@ -107,6 +107,7 @@ typedef enum {
|
||||
MP_F_LOAD_BUILD_CLASS,
|
||||
MP_F_LOAD_ATTR,
|
||||
MP_F_LOAD_METHOD,
|
||||
MP_F_LOAD_SUPER_METHOD,
|
||||
MP_F_STORE_NAME,
|
||||
MP_F_STORE_GLOBAL,
|
||||
MP_F_STORE_ATTR,
|
||||
|
@ -245,6 +245,11 @@ const byte *mp_bytecode_print_str(const byte *ip) {
|
||||
printf("LOAD_METHOD %s", qstr_str(qst));
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_SUPER_METHOD:
|
||||
DECODE_QSTR;
|
||||
printf("LOAD_SUPER_METHOD %s", qstr_str(qst));
|
||||
break;
|
||||
|
||||
case MP_BC_LOAD_BUILD_CLASS:
|
||||
printf("LOAD_BUILD_CLASS");
|
||||
break;
|
||||
|
8
py/vm.c
8
py/vm.c
@ -376,6 +376,14 @@ dispatch_loop:
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_SUPER_METHOD): {
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
DECODE_QSTR;
|
||||
sp -= 1;
|
||||
mp_load_super_method(qst, sp - 1);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
ENTRY(MP_BC_LOAD_BUILD_CLASS):
|
||||
MARK_EXC_IP_SELECTIVE();
|
||||
PUSH(mp_load_build_class());
|
||||
|
@ -44,6 +44,7 @@ static const void *const entry_table[256] = {
|
||||
[MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL,
|
||||
[MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR,
|
||||
[MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD,
|
||||
[MP_BC_LOAD_SUPER_METHOD] = &&entry_MP_BC_LOAD_SUPER_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_N] = &&entry_MP_BC_STORE_FAST_N,
|
||||
|
@ -45,6 +45,7 @@
|
||||
// compiler configuration
|
||||
#define MICROPY_COMP_MODULE_CONST (1)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||
|
||||
// optimisations
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (1)
|
||||
@ -123,6 +124,7 @@
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MACHINE_PULSE (1)
|
||||
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_I2C_MAKE_NEW machine_hard_i2c_make_new
|
||||
#define MICROPY_PY_MACHINE_SPI (1)
|
||||
|
@ -245,7 +245,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, mp_uint_t n_args, cons
|
||||
/// \classmethod \constructor(id, ...)
|
||||
/// Create a new Pin object associated with the id. If additional arguments are given,
|
||||
/// they are used to initialise the pin. See `init`.
|
||||
STATIC mp_obj_t pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
|
||||
// Run an argument through the mapper and return the result.
|
||||
@ -567,7 +567,7 @@ const mp_obj_type_t pin_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Pin,
|
||||
.print = pin_print,
|
||||
.make_new = pin_make_new,
|
||||
.make_new = mp_pin_make_new,
|
||||
.call = pin_call,
|
||||
.protocol = &pin_pin_p,
|
||||
.locals_dict = (mp_obj_t)&pin_locals_dict,
|
||||
|
@ -1302,6 +1302,7 @@ STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback)
|
||||
} else if (mp_obj_is_callable(callback)) {
|
||||
self->callback = callback;
|
||||
uint8_t tim_id = self->timer->tim_id;
|
||||
__HAL_TIM_CLEAR_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel));
|
||||
if (tim_id == 1) {
|
||||
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
|
||||
#if defined(TIM8) // STM32F401 doesn't have a TIM8
|
||||
|
@ -20,3 +20,17 @@ class A:
|
||||
def p(self):
|
||||
print(str(super())[:18])
|
||||
A().p()
|
||||
|
||||
|
||||
# test compiler's handling of long expressions with super
|
||||
class A:
|
||||
bar = 123
|
||||
def foo(self):
|
||||
print('A foo')
|
||||
return [1, 2, 3]
|
||||
class B(A):
|
||||
def foo(self):
|
||||
print('B foo')
|
||||
print(super().bar) # accessing attribute after super()
|
||||
return super().foo().count(2) # calling a subsequent method
|
||||
print(B().foo())
|
||||
|
@ -3,7 +3,7 @@
|
||||
tok(4)
|
||||
[ 4] rule(22) (n=4)
|
||||
id(i)
|
||||
[ 4] rule(45) (n=1)
|
||||
[ 4] rule(44) (n=1)
|
||||
NULL
|
||||
[ 5] rule(8) (n=0)
|
||||
NULL
|
||||
|
@ -150,3 +150,7 @@ class Class:
|
||||
|
||||
# delete name
|
||||
del Class
|
||||
|
||||
# load super method
|
||||
def f(self):
|
||||
super().f()
|
||||
|
@ -7,7 +7,7 @@ arg names:
|
||||
(N_EXC_STACK 0)
|
||||
bc=-1 line=1
|
||||
########
|
||||
bc=\\d\+ line=152
|
||||
bc=\\d\+ line=155
|
||||
00 MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
@ -25,6 +25,8 @@ arg names:
|
||||
\\d\+ CALL_FUNCTION n=2 nkw=0
|
||||
\\d\+ STORE_NAME Class
|
||||
\\d\+ DELETE_NAME Class
|
||||
\\d\+ MAKE_FUNCTION \.\+
|
||||
\\d\+ STORE_NAME f
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
@ -428,6 +430,23 @@ arg names:
|
||||
10 STORE_NAME __qualname__
|
||||
13 LOAD_CONST_NONE
|
||||
14 RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
\.\+5b
|
||||
arg names: self
|
||||
(N_STATE 4)
|
||||
(N_EXC_STACK 0)
|
||||
bc=-1 line=1
|
||||
bc=0 line=156
|
||||
00 LOAD_GLOBAL super (cache=0)
|
||||
\\d\+ LOAD_GLOBAL __class__ (cache=0)
|
||||
\\d\+ LOAD_FAST 0
|
||||
\\d\+ LOAD_SUPER_METHOD f
|
||||
\\d\+ CALL_METHOD n=0 nkw=0
|
||||
\\d\+ POP_TOP
|
||||
\\d\+ LOAD_CONST_NONE
|
||||
\\d\+ RETURN_VALUE
|
||||
File cmdline/cmd_showbc.py, code block '<genexpr>' (descriptor: \.\+, bytecode @\.\+ bytes)
|
||||
Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
|
||||
########
|
||||
|
@ -33,7 +33,7 @@ print(p.value(), s.value())
|
||||
|
||||
# test inverted, and using on/off methods
|
||||
p = Pin()
|
||||
s = machine.Signal(p, inverted=True)
|
||||
s = machine.Signal(p, invert=True)
|
||||
s.off()
|
||||
print(p.value(), s.value())
|
||||
s.on()
|
||||
|
54
tests/extmod/uctypes_32bit_intbig.py
Normal file
54
tests/extmod/uctypes_32bit_intbig.py
Normal file
@ -0,0 +1,54 @@
|
||||
# This test checks previously known problem values for 32-bit ports.
|
||||
# It's less useful for 64-bit ports.
|
||||
try:
|
||||
import uctypes
|
||||
except ImportError:
|
||||
import sys
|
||||
print("SKIP")
|
||||
sys.exit()
|
||||
|
||||
buf = b"12345678abcd"
|
||||
struct = uctypes.struct(
|
||||
uctypes.addressof(buf),
|
||||
{"f32": uctypes.UINT32 | 0, "f64": uctypes.UINT64 | 4},
|
||||
uctypes.LITTLE_ENDIAN
|
||||
)
|
||||
|
||||
struct.f32 = 0x7fffffff
|
||||
print(buf)
|
||||
|
||||
struct.f32 = 0x80000000
|
||||
print(buf)
|
||||
|
||||
struct.f32 = 0xff010203
|
||||
print(buf)
|
||||
|
||||
struct.f64 = 0x80000000
|
||||
print(buf)
|
||||
|
||||
struct.f64 = 0x80000000 * 2
|
||||
print(buf)
|
||||
|
||||
print("=")
|
||||
|
||||
buf = b"12345678abcd"
|
||||
struct = uctypes.struct(
|
||||
uctypes.addressof(buf),
|
||||
{"f32": uctypes.UINT32 | 0, "f64": uctypes.UINT64 | 4},
|
||||
uctypes.BIG_ENDIAN
|
||||
)
|
||||
|
||||
struct.f32 = 0x7fffffff
|
||||
print(buf)
|
||||
|
||||
struct.f32 = 0x80000000
|
||||
print(buf)
|
||||
|
||||
struct.f32 = 0xff010203
|
||||
print(buf)
|
||||
|
||||
struct.f64 = 0x80000000
|
||||
print(buf)
|
||||
|
||||
struct.f64 = 0x80000000 * 2
|
||||
print(buf)
|
11
tests/extmod/uctypes_32bit_intbig.py.exp
Normal file
11
tests/extmod/uctypes_32bit_intbig.py.exp
Normal file
@ -0,0 +1,11 @@
|
||||
b'\xff\xff\xff\x7f5678abcd'
|
||||
b'\x00\x00\x00\x805678abcd'
|
||||
b'\x03\x02\x01\xff5678abcd'
|
||||
b'\x03\x02\x01\xff\x00\x00\x00\x80\x00\x00\x00\x00'
|
||||
b'\x03\x02\x01\xff\x00\x00\x00\x00\x01\x00\x00\x00'
|
||||
=
|
||||
b'\x7f\xff\xff\xff5678abcd'
|
||||
b'\x80\x00\x00\x005678abcd'
|
||||
b'\xff\x01\x02\x035678abcd'
|
||||
b'\xff\x01\x02\x03\x00\x00\x00\x00\x80\x00\x00\x00'
|
||||
b'\xff\x01\x02\x03\x00\x00\x00\x01\x00\x00\x00\x00'
|
@ -34,6 +34,41 @@ try:
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
# unsupported unary op
|
||||
try:
|
||||
~h
|
||||
assert False
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# pushing on full queue
|
||||
h = utimeq(1)
|
||||
h.push(1, 0, 0)
|
||||
try:
|
||||
h.push(2, 0, 0)
|
||||
assert False
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
# popping into invalid type
|
||||
try:
|
||||
h.pop([])
|
||||
assert False
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# length
|
||||
assert len(h) == 1
|
||||
|
||||
# peektime
|
||||
assert h.peektime() == 1
|
||||
|
||||
# peektime with empty queue
|
||||
try:
|
||||
utimeq(1).peektime()
|
||||
assert False
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def pop_all(h):
|
||||
l = []
|
||||
|
17
tests/micropython/heapalloc_super.py
Normal file
17
tests/micropython/heapalloc_super.py
Normal file
@ -0,0 +1,17 @@
|
||||
# test super() operations which don't require allocation
|
||||
import micropython
|
||||
|
||||
class A:
|
||||
def foo(self):
|
||||
print('A foo')
|
||||
return 42
|
||||
class B(A):
|
||||
def foo(self):
|
||||
print('B foo')
|
||||
print(super().foo())
|
||||
|
||||
b = B()
|
||||
|
||||
micropython.heap_lock()
|
||||
b.foo()
|
||||
micropython.heap_unlock()
|
3
tests/micropython/heapalloc_super.py.exp
Normal file
3
tests/micropython/heapalloc_super.py.exp
Normal file
@ -0,0 +1,3 @@
|
||||
B foo
|
||||
A foo
|
||||
42
|
13
tests/micropython/kbd_intr.py
Normal file
13
tests/micropython/kbd_intr.py
Normal file
@ -0,0 +1,13 @@
|
||||
# test the micropython.kbd_intr() function
|
||||
|
||||
import micropython
|
||||
|
||||
try:
|
||||
micropython.kbd_intr
|
||||
except AttributeError:
|
||||
print('SKIP')
|
||||
import sys
|
||||
sys.exit()
|
||||
|
||||
# just check we can actually call it
|
||||
micropython.kbd_intr(3)
|
0
tests/micropython/kbd_intr.py.exp
Normal file
0
tests/micropython/kbd_intr.py.exp
Normal file
@ -49,15 +49,15 @@ def convert_regex_escapes(line):
|
||||
return bytes(''.join(cs), 'utf8')
|
||||
|
||||
|
||||
def run_micropython(pyb, args, test_file):
|
||||
def run_micropython(pyb, args, test_file, is_special=False):
|
||||
special_tests = ('micropython/meminfo.py', 'basics/bytes_compare3.py', 'basics/builtin_help.py', 'thread/thread_exc2.py')
|
||||
is_special = False
|
||||
if pyb is None:
|
||||
# run on PC
|
||||
if test_file.startswith(('cmdline/', 'feature_check/')) or test_file in special_tests:
|
||||
# special handling for tests of the unix cmdline program
|
||||
is_special = True
|
||||
|
||||
if is_special:
|
||||
# check for any cmdline options needed for this test
|
||||
args = [MICROPYTHON]
|
||||
with open(test_file, 'rb') as f:
|
||||
@ -145,7 +145,7 @@ def run_micropython(pyb, args, test_file):
|
||||
output_mupy = output_mupy.replace(b'\r\n', b'\n')
|
||||
|
||||
# don't try to convert the output if we should skip this test
|
||||
if output_mupy == b'SKIP\n':
|
||||
if output_mupy in (b'SKIP\n', b'CRASH'):
|
||||
return output_mupy
|
||||
|
||||
if is_special or test_file in special_tests:
|
||||
@ -189,7 +189,12 @@ def run_micropython(pyb, args, test_file):
|
||||
|
||||
return output_mupy
|
||||
|
||||
def run_tests(pyb, tests, args):
|
||||
|
||||
def run_feature_check(pyb, args, base_path, test_file):
|
||||
return run_micropython(pyb, args, base_path + "/feature_check/" + test_file, is_special=True)
|
||||
|
||||
|
||||
def run_tests(pyb, tests, args, base_path="."):
|
||||
test_count = 0
|
||||
testcase_count = 0
|
||||
passed_count = 0
|
||||
@ -204,39 +209,39 @@ def run_tests(pyb, tests, args):
|
||||
skip_const = False
|
||||
|
||||
# Check if micropython.native is supported, and skip such tests if it's not
|
||||
native = run_micropython(pyb, args, 'feature_check/native_check.py')
|
||||
native = run_feature_check(pyb, args, base_path, 'native_check.py')
|
||||
if native == b'CRASH':
|
||||
skip_native = True
|
||||
|
||||
# Check if arbitrary-precision integers are supported, and skip such tests if it's not
|
||||
native = run_micropython(pyb, args, 'feature_check/int_big.py')
|
||||
native = run_feature_check(pyb, args, base_path, 'int_big.py')
|
||||
if native != b'1000000000000000000000000000000000000000000000\n':
|
||||
skip_int_big = True
|
||||
|
||||
# Check if set type (and set literals) is supported, and skip such tests if it's not
|
||||
native = run_micropython(pyb, args, 'feature_check/set_check.py')
|
||||
native = run_feature_check(pyb, args, base_path, 'set_check.py')
|
||||
if native == b'CRASH':
|
||||
skip_set_type = True
|
||||
|
||||
# Check if async/await keywords are supported, and skip such tests if it's not
|
||||
native = run_micropython(pyb, args, 'feature_check/async_check.py')
|
||||
native = run_feature_check(pyb, args, base_path, 'async_check.py')
|
||||
if native == b'CRASH':
|
||||
skip_async = True
|
||||
|
||||
# Check if const keyword (MicroPython extension) is supported, and skip such tests if it's not
|
||||
native = run_micropython(pyb, args, 'feature_check/const.py')
|
||||
native = run_feature_check(pyb, args, base_path, 'const.py')
|
||||
if native == b'CRASH':
|
||||
skip_const = True
|
||||
|
||||
# Check if emacs repl is supported, and skip such tests if it's not
|
||||
t = run_micropython(pyb, args, 'feature_check/repl_emacs_check.py')
|
||||
t = run_feature_check(pyb, args, base_path, 'repl_emacs_check.py')
|
||||
if not 'True' in str(t, 'ascii'):
|
||||
skip_tests.add('cmdline/repl_emacs_keys.py')
|
||||
|
||||
upy_byteorder = run_micropython(pyb, args, 'feature_check/byteorder.py')
|
||||
has_complex = run_micropython(pyb, args, 'feature_check/complex.py') == b'complex\n'
|
||||
has_coverage = run_micropython(pyb, args, 'feature_check/coverage.py') == b'coverage\n'
|
||||
cpy_byteorder = subprocess.check_output([CPYTHON3, 'feature_check/byteorder.py'])
|
||||
upy_byteorder = run_feature_check(pyb, args, base_path, 'byteorder.py')
|
||||
has_complex = run_feature_check(pyb, args, base_path, 'complex.py') == b'complex\n'
|
||||
has_coverage = run_feature_check(pyb, args, base_path, 'coverage.py') == b'coverage\n'
|
||||
cpy_byteorder = subprocess.check_output([CPYTHON3, base_path + '/feature_check/byteorder.py'])
|
||||
skip_endian = (upy_byteorder != cpy_byteorder)
|
||||
|
||||
# Some tests shouldn't be run under Travis CI
|
||||
@ -468,7 +473,11 @@ def main():
|
||||
# clear search path to make sure tests use only builtin modules
|
||||
os.environ['MICROPYPATH'] = ''
|
||||
|
||||
res = run_tests(pyb, tests, args)
|
||||
# Even if we run completely different tests in a different directory,
|
||||
# we need to access feature_check's from the same directory as the
|
||||
# run-tests script itself.
|
||||
base_path = os.path.dirname(sys.argv[0]) or "."
|
||||
res = run_tests(pyb, tests, args, base_path)
|
||||
if pyb:
|
||||
pyb.close()
|
||||
if not res:
|
||||
|
@ -57,7 +57,7 @@ class FreezeError(Exception):
|
||||
return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg)
|
||||
|
||||
class Config:
|
||||
MPY_VERSION = 1
|
||||
MPY_VERSION = 2
|
||||
MICROPY_LONGINT_IMPL_NONE = 0
|
||||
MICROPY_LONGINT_IMPL_LONGLONG = 1
|
||||
MICROPY_LONGINT_IMPL_MPZ = 2
|
||||
@ -94,7 +94,7 @@ def make_opcode_format():
|
||||
OC4(U, U, U, U), # 0x0c-0x0f
|
||||
OC4(B, B, B, U), # 0x10-0x13
|
||||
OC4(V, U, Q, V), # 0x14-0x17
|
||||
OC4(B, U, V, V), # 0x18-0x1b
|
||||
OC4(B, V, V, Q), # 0x18-0x1b
|
||||
OC4(Q, Q, Q, Q), # 0x1c-0x1f
|
||||
OC4(B, B, V, V), # 0x20-0x23
|
||||
OC4(Q, Q, Q, B), # 0x24-0x27
|
||||
|
@ -425,9 +425,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
|
||||
mp_init();
|
||||
|
||||
// create keyboard interrupt object
|
||||
MP_STATE_VM(keyboard_interrupt_obj) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
|
||||
|
||||
char *home = getenv("HOME");
|
||||
char *path = getenv("MICROPYPATH");
|
||||
if (path == NULL) {
|
||||
|
@ -45,6 +45,7 @@
|
||||
#endif
|
||||
#define MICROPY_COMP_MODULE_CONST (1)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_ENABLE_FINALISER (1)
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
@ -156,6 +157,7 @@
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256)
|
||||
#define MICROPY_KBD_EXCEPTION (1)
|
||||
#define MICROPY_ASYNC_KBD_INTR (1)
|
||||
|
||||
extern const struct _mp_obj_module_t mp_module_machine;
|
||||
@ -283,7 +285,6 @@ void mp_unix_mark_exec(void);
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[50]; \
|
||||
mp_obj_t keyboard_interrupt_obj; \
|
||||
void *mmap_region_head; \
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include <mpconfigport.h>
|
||||
|
||||
#define MICROPY_FLOAT_HIGH_QUALITY_HASH (1)
|
||||
#define MICROPY_ENABLE_SCHEDULER (1)
|
||||
#define MICROPY_PY_DELATTR_SETATTR (1)
|
||||
#define MICROPY_PY_BUILTINS_HELP (1)
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_WARNINGS (0)
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
||||
#define MICROPY_KBD_EXCEPTION (1)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||
@ -99,7 +100,6 @@ extern const struct _mp_obj_module_t mp_module_os;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
mp_obj_t keyboard_interrupt_obj;
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Do not change anything beyond this line
|
||||
|
@ -40,20 +40,20 @@
|
||||
STATIC void sighandler(int signum) {
|
||||
if (signum == SIGINT) {
|
||||
#if MICROPY_ASYNC_KBD_INTR
|
||||
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
|
||||
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
// On entry to handler, its signal is blocked, and unblocked on
|
||||
// normal exit. As we instead perform longjmp, unblock it manually.
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
nlr_raise(MP_STATE_VM(keyboard_interrupt_obj));
|
||||
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
#else
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) {
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
|
||||
// this is the second time we are called, so die straight away
|
||||
exit(1);
|
||||
}
|
||||
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj);
|
||||
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -32,17 +32,20 @@
|
||||
#endif
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (260) //see minwindef.h for msvc or limits.h for mingw
|
||||
#define MICROPY_PERSISTENT_CODE_LOAD (1)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (1)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_ENABLE_FINALISER (1)
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
|
||||
#define MICROPY_MEM_STATS (1)
|
||||
#define MICROPY_DEBUG_PRINTERS (1)
|
||||
#define MICROPY_DEBUG_PRINTER_DEST mp_stderr_print
|
||||
#define MICROPY_READER_POSIX (1)
|
||||
#define MICROPY_USE_READLINE_HISTORY (1)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
@ -59,11 +62,14 @@
|
||||
#define MICROPY_PY_FUNCTION_ATTRS (1)
|
||||
#define MICROPY_PY_DESCRIPTORS (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_CENTER (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_COMPILE (1)
|
||||
#define MICROPY_PY_BUILTINS_NOTIMPLEMENTED (1)
|
||||
#define MICROPY_PY_BUILTINS_POW3 (1)
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
|
||||
@ -83,27 +89,35 @@
|
||||
#define MICROPY_STACKLESS (0)
|
||||
#define MICROPY_STACKLESS_STRICT (0)
|
||||
|
||||
#define MICROPY_PY_UTIME (1)
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
#define MICROPY_PY_UERRNO (1)
|
||||
#define MICROPY_PY_UCTYPES (1)
|
||||
#define MICROPY_PY_UZLIB (1)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
#define MICROPY_PY_UTIMEQ (1)
|
||||
#define MICROPY_PY_UHASHLIB (1)
|
||||
#define MICROPY_PY_UBINASCII (1)
|
||||
#define MICROPY_PY_UBINASCII_CRC32 (1)
|
||||
#define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_UTIME (1)
|
||||
#define MICROPY_PY_UTIME_MP_HAL (1)
|
||||
#define MICROPY_PY_MACHINE (1)
|
||||
#define MICROPY_PY_MACHINE_PULSE (1)
|
||||
#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr
|
||||
#define MICROPY_MACHINE_MEM_GET_WRITE_ADDR mod_machine_mem_get_addr
|
||||
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
|
||||
#define MICROPY_WARNINGS (1)
|
||||
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define MICROPY_GCREGS_SETJMP (1)
|
||||
#endif
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256)
|
||||
#define MICROPY_KBD_EXCEPTION (1)
|
||||
|
||||
#define MICROPY_PORT_INIT_FUNC init()
|
||||
#define MICROPY_PORT_DEINIT_FUNC deinit()
|
||||
@ -161,8 +175,7 @@ extern const struct _mp_obj_module_t mp_module_time;
|
||||
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
char *readline_hist[50]; \
|
||||
mp_obj_t keyboard_interrupt_obj;
|
||||
char *readline_hist[50];
|
||||
#endif
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
@ -15,6 +15,7 @@
|
||||
<ClCompile Include="$(PyBaseDir)unix\modmachine.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\machine_mem.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\machine_pinbase.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\machine_pulse.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\machine_signal.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\modubinascii.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\moductypes.c" />
|
||||
@ -23,6 +24,7 @@
|
||||
<ClCompile Include="$(PyBaseDir)extmod\modujson.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\modurandom.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\modure.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\modutimeq.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\moduzlib.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\utime_mphal.c" />
|
||||
<ClCompile Include="$(PyBaseDir)extmod\virtpin.c" />
|
||||
|
@ -79,12 +79,12 @@ void mp_hal_stdio_mode_orig(void) {
|
||||
// the thread created for handling it might not be running yet so we'd miss the notification.
|
||||
BOOL WINAPI console_sighandler(DWORD evt) {
|
||||
if (evt == CTRL_C_EVENT) {
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) {
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
|
||||
// this is the second time we are called, so die straight away
|
||||
exit(1);
|
||||
}
|
||||
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj);
|
||||
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
@ -66,6 +66,10 @@ void init_zephyr(void) {
|
||||
#ifdef CONFIG_NET_IPV4
|
||||
static struct in_addr in4addr_my = {{{192, 0, 2, 1}}};
|
||||
net_if_ipv4_addr_add(net_if_get_default(), &in4addr_my, NET_ADDR_MANUAL, 0);
|
||||
static struct in_addr in4netmask_my = {{{255, 255, 255, 0}}};
|
||||
net_if_ipv4_set_netmask(net_if_get_default(), &in4netmask_my);
|
||||
static struct in_addr in4gw_my = {{{192, 0, 2, 2}}};
|
||||
net_if_ipv4_set_gw(net_if_get_default(), &in4gw_my);
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPV6
|
||||
// 2001:db8::1
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <misc/reboot.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
@ -40,7 +41,8 @@
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
printf("Warning: %s is not implemented\n", __func__);
|
||||
sys_reboot(SYS_REBOOT_COLD);
|
||||
// Won't get here, Zephyr has infiniloop on its side
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
@ -53,7 +55,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
|
||||
#ifdef CONFIG_REBOOT
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
|
||||
|
@ -36,7 +36,8 @@
|
||||
#include <net/net_context.h>
|
||||
#include <net/nbuf.h>
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG 0
|
||||
#if DEBUG // print debugging info
|
||||
#define DEBUG_printf printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
@ -119,8 +120,6 @@ STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct socka
|
||||
// to the fact that it copies data byte by byte).
|
||||
static char *net_buf_gather(struct net_buf *buf, char *to, unsigned max_len) {
|
||||
struct net_buf *tmp = buf->frags;
|
||||
unsigned header_len = net_nbuf_appdata(buf) - tmp->data;
|
||||
net_buf_pull(tmp, header_len);
|
||||
|
||||
while (tmp && max_len) {
|
||||
unsigned len = tmp->len;
|
||||
@ -144,6 +143,9 @@ static void sock_received_cb(struct net_context *context, struct net_buf *net_bu
|
||||
DEBUG_printf(" (sz=%d, l=%d), token: %p", net_buf->size, net_buf->len, net_nbuf_token(net_buf));
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#if DEBUG > 1
|
||||
net_nbuf_print_frags(net_buf);
|
||||
#endif
|
||||
|
||||
// if net_buf == NULL, EOF
|
||||
if (net_buf == NULL) {
|
||||
@ -162,6 +164,10 @@ static void sock_received_cb(struct net_context *context, struct net_buf *net_bu
|
||||
// Make sure that "EOF flag" is not set
|
||||
net_nbuf_set_buf_sent(net_buf, false);
|
||||
|
||||
// We don't care about packet header, so get rid of it asap
|
||||
unsigned header_len = net_nbuf_appdata(net_buf) - net_buf->frags->data;
|
||||
net_buf_pull(net_buf->frags, header_len);
|
||||
|
||||
// net_buf->frags will be overwritten by fifo, so save it
|
||||
net_nbuf_set_token(net_buf, net_buf->frags);
|
||||
k_fifo_put(&socket->recv_q, net_buf);
|
||||
@ -302,14 +308,22 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
struct net_buf *send_buf = net_nbuf_get_tx(socket->ctx, K_FOREVER);
|
||||
// TODO: Probably should limit how much data we send in one call still
|
||||
if (!net_nbuf_append(send_buf, bufinfo.len, bufinfo.buf, K_FOREVER)) {
|
||||
mp_raise_OSError(ENOSPC);
|
||||
|
||||
unsigned len = net_if_get_mtu(net_context_get_iface(socket->ctx));
|
||||
// Arbitrary value to account for protocol headers
|
||||
len -= 64;
|
||||
if (len > bufinfo.len) {
|
||||
len = bufinfo.len;
|
||||
}
|
||||
|
||||
if (!net_nbuf_append(send_buf, len, bufinfo.buf, K_FOREVER)) {
|
||||
len = net_buf_frags_len(send_buf);
|
||||
//mp_raise_OSError(ENOSPC);
|
||||
}
|
||||
|
||||
RAISE_ERRNO(net_context_send(send_buf, /*cb*/NULL, K_FOREVER, NULL, NULL));
|
||||
|
||||
return mp_obj_new_int_from_uint(bufinfo.len);
|
||||
return mp_obj_new_int_from_uint(len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
|
||||
|
||||
@ -346,15 +360,13 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
return mp_const_empty_bytes;
|
||||
}
|
||||
|
||||
unsigned header_len = 0;
|
||||
if (socket->cur_buf == NULL) {
|
||||
DEBUG_printf("TCP recv: no cur_buf, getting\n");
|
||||
struct net_buf *net_buf = k_fifo_get(&socket->recv_q, K_FOREVER);
|
||||
// Restore ->frags overwritten by fifo
|
||||
net_buf->frags = net_nbuf_token(net_buf);
|
||||
|
||||
header_len = net_nbuf_appdata(net_buf) - net_buf->frags->data;
|
||||
DEBUG_printf("TCP recv: new cur_buf: %p, hdr_len: %u\n", net_buf, header_len);
|
||||
DEBUG_printf("TCP recv: new cur_buf: %p\n", net_buf);
|
||||
socket->cur_buf = net_buf;
|
||||
}
|
||||
|
||||
@ -364,7 +376,6 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
net_buf_pull(frag, header_len);
|
||||
unsigned frag_len = frag->len;
|
||||
recv_len = frag_len;
|
||||
if (recv_len > max_len) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
CONFIG_LEGACY_KERNEL=n
|
||||
CONFIG_REBOOT=y
|
||||
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_CONSOLE_HANDLER=y
|
||||
|
Loading…
Reference in New Issue
Block a user