mirror of
https://github.com/micropython/micropython.git
synced 2025-12-28 07:40:14 +01:00
Compare commits
164 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
552f7c40a0 | ||
|
|
ad33e2465c | ||
|
|
31c1f1300e | ||
|
|
32444b759a | ||
|
|
5c670acb1f | ||
|
|
4c1a7e0d6a | ||
|
|
0fb17f6ef4 | ||
|
|
ca377b10de | ||
|
|
8d427b7ab7 | ||
|
|
c585ad1020 | ||
|
|
6b636738b2 | ||
|
|
23342c09ff | ||
|
|
91232d3850 | ||
|
|
ca3dbb8d8b | ||
|
|
66b060f3e6 | ||
|
|
444331c07f | ||
|
|
1f04336b23 | ||
|
|
425f952a1e | ||
|
|
220d21e1bf | ||
|
|
344e15b1ae | ||
|
|
6113eb2f33 | ||
|
|
e5bcbcdebd | ||
|
|
6d1f5070ce | ||
|
|
bd9c1ad601 | ||
|
|
8b77e3dd2f | ||
|
|
77089bebd4 | ||
|
|
05005f679e | ||
|
|
0b9ee86133 | ||
|
|
2e526ff1a1 | ||
|
|
8064892c9b | ||
|
|
b6e6b5277f | ||
|
|
962a5d50c9 | ||
|
|
d7f199465f | ||
|
|
73533247cb | ||
|
|
bf19541f46 | ||
|
|
0ab3fc3805 | ||
|
|
50149a5730 | ||
|
|
ff8dd3f486 | ||
|
|
50912e7f5d | ||
|
|
640e0b221e | ||
|
|
438b3d26b5 | ||
|
|
f1700a5154 | ||
|
|
51ef28a9d6 | ||
|
|
3926c72dd2 | ||
|
|
963a5a3e82 | ||
|
|
f12ea7c7ed | ||
|
|
0abb5609b0 | ||
|
|
2276eb8084 | ||
|
|
d7337f288e | ||
|
|
87bc8e2b3d | ||
|
|
c6b8750c14 | ||
|
|
d2d64f00fb | ||
|
|
65ef6b768c | ||
|
|
d95b519aa1 | ||
|
|
d9dc6fff21 | ||
|
|
bc47c287df | ||
|
|
1e1779eacf | ||
|
|
2127e9a844 | ||
|
|
c935d69f74 | ||
|
|
d6ed6702f7 | ||
|
|
4c81ba8015 | ||
|
|
dab1385177 | ||
|
|
d710cef661 | ||
|
|
a45b042e59 | ||
|
|
f41df1e611 | ||
|
|
5ebabcda41 | ||
|
|
d511a20a6b | ||
|
|
bbf5cd01e3 | ||
|
|
30d8a82220 | ||
|
|
abc1959e2c | ||
|
|
cd34207409 | ||
|
|
3dd1c0a88a | ||
|
|
0178aa9a11 | ||
|
|
b58da9420c | ||
|
|
131185a2b8 | ||
|
|
7630d9ca0e | ||
|
|
5b76e3b75e | ||
|
|
99dde4ed1f | ||
|
|
3f9f9cac75 | ||
|
|
708574b082 | ||
|
|
06e9cb688b | ||
|
|
a7bcb218fe | ||
|
|
99ab64ffd4 | ||
|
|
95836f8439 | ||
|
|
6942f80a8f | ||
|
|
e233a55a29 | ||
|
|
c38dc3ccc7 | ||
|
|
ec21405821 | ||
|
|
56e1f99ca1 | ||
|
|
01418e9690 | ||
|
|
ddd1e18801 | ||
|
|
7bfe4b21b9 | ||
|
|
58056b0f43 | ||
|
|
f5465b9eb0 | ||
|
|
5d48f234d2 | ||
|
|
a9a0862078 | ||
|
|
89deec0bab | ||
|
|
4a5895c4eb | ||
|
|
85e8e2ed5b | ||
|
|
3990dcfcd7 | ||
|
|
14fab60baf | ||
|
|
d2d0648ad0 | ||
|
|
7a53ac8ec2 | ||
|
|
c33ecb83ba | ||
|
|
5b7aa294e0 | ||
|
|
19b3fea6a8 | ||
|
|
115187f7ce | ||
|
|
afd6c8e1d2 | ||
|
|
181bfb6db2 | ||
|
|
c223df5113 | ||
|
|
3b51b3e90f | ||
|
|
7a0636e80a | ||
|
|
7ee91cf861 | ||
|
|
b4b10fd350 | ||
|
|
ad2307c92c | ||
|
|
d8bfd77ad5 | ||
|
|
b27c9876ea | ||
|
|
343ca1e63a | ||
|
|
51af362e31 | ||
|
|
ed3b20aae8 | ||
|
|
ff8e35b42e | ||
|
|
c114496641 | ||
|
|
ae58795c44 | ||
|
|
6fd4b36bc5 | ||
|
|
6e0b6d02db | ||
|
|
ffc96a901a | ||
|
|
fbfd3554fa | ||
|
|
8dec62a1a4 | ||
|
|
fd40a9c38e | ||
|
|
872a82970d | ||
|
|
8a2347723e | ||
|
|
0b2a60acbe | ||
|
|
fe7d542352 | ||
|
|
4ef4ffe1c5 | ||
|
|
c2e22d66da | ||
|
|
b68d98d61c | ||
|
|
2cf6dfa280 | ||
|
|
b36be5ff51 | ||
|
|
6d7e47087f | ||
|
|
3765ea419a | ||
|
|
51dfcb4bb7 | ||
|
|
db1ac360c3 | ||
|
|
8a8c1fc82f | ||
|
|
ebde3c694f | ||
|
|
ddbcc79550 | ||
|
|
ce5b5caf8c | ||
|
|
84e0cf0d21 | ||
|
|
7f23384d49 | ||
|
|
276159e5dd | ||
|
|
021dc44009 | ||
|
|
12340147b0 | ||
|
|
8422cac088 | ||
|
|
e0ac194f4f | ||
|
|
816a46a4ab | ||
|
|
2c75665445 | ||
|
|
8a2cc1c7e4 | ||
|
|
5f68094e10 | ||
|
|
f79cd6a233 | ||
|
|
12033df511 | ||
|
|
e3fa8278b4 | ||
|
|
9ddbe291c4 | ||
|
|
f89d659e3b | ||
|
|
23f1b5ff66 | ||
|
|
96e22154d7 |
@@ -7,15 +7,16 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system mingw32
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-multilib gcc-arm-none-eabi qemu-system mingw32
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
|
||||
script:
|
||||
- make -C minimal test
|
||||
- make -C unix CC=gcc-4.7
|
||||
- make -C unix-cpy CC=gcc-4.7
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm
|
||||
- make -C qemu-arm test
|
||||
- make -C stmhal
|
||||
- make -C stmhal -B MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1
|
||||
- make -C stmhal BOARD=STM32F4DISC
|
||||
@@ -27,3 +28,4 @@ script:
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
- (grep "FAIL" qemu-arm/build/console.out)
|
||||
|
||||
@@ -10,7 +10,6 @@ CROSS_COMPILE = arm-none-eabi-
|
||||
|
||||
INC = -I.
|
||||
INC += -I..
|
||||
INC += -I$(PY_SRC)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
|
||||
@@ -2,19 +2,12 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "repl.h"
|
||||
#include "pfenv.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/parsehelper.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/repl.h"
|
||||
#include "py/pfenv.h"
|
||||
|
||||
void do_str(const char *src) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#define MICROPY_COMP_CONST (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
|
||||
@@ -60,7 +60,7 @@ copyright = '2014, Damien P. George'
|
||||
# The short X.Y version.
|
||||
version = '1.3'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.3.7'
|
||||
release = '1.3.9'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -39,6 +39,7 @@ it will fallback to loading the built-in ``ujson`` module.
|
||||
:maxdepth: 1
|
||||
|
||||
ubinascii.rst
|
||||
uctypes.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
ujson.rst
|
||||
|
||||
@@ -53,7 +53,7 @@ Methods
|
||||
|
||||
Generate a triangle wave. The value on the DAC output changes at
|
||||
the given frequency, and the frequence of the repeating triangle wave
|
||||
itself is 256 (or 1024, need to check) times smaller.
|
||||
itself is 2048 times smaller.
|
||||
|
||||
.. method:: dac.write(value)
|
||||
|
||||
|
||||
@@ -1,15 +1,37 @@
|
||||
.. _pyb.Servo:
|
||||
|
||||
class Servo -- 3-wire hobby servo driver
|
||||
========================================
|
||||
|
||||
Servo controls standard hobby servos with 3-wires (ground, power, signal).
|
||||
Servo objects control standard hobby servo motors with 3-wires (ground, power,
|
||||
signal). There are 4 positions on the pyboard where these motors can be plugged
|
||||
in: pins X1 through X4 are the signal pins, and next to them are 4 sets of power
|
||||
and ground pins.
|
||||
|
||||
Example usage::
|
||||
|
||||
import pyb
|
||||
|
||||
s1 = pyb.Servo(1) # create a servo object on position X1
|
||||
s2 = pyb.Servo(2) # create a servo object on position X2
|
||||
|
||||
s1.angle(45) # move servo 1 to 45 degrees
|
||||
s2.angle(0) # move servo 2 to 0 degrees
|
||||
|
||||
# move servo1 and servo2 synchronously, taking 1500ms
|
||||
s1.angle(-60, 1500)
|
||||
s2.angle(30, 1500)
|
||||
|
||||
.. note:: The Servo objects use Timer(5) to produce the PWM output. You can
|
||||
use Timer(5) for Servo control, or your own purposes, but not both at the
|
||||
same time.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Servo(id)
|
||||
|
||||
Create a servo object. ``id`` is 1-4.
|
||||
Create a servo object. ``id`` is 1-4, and corresponds to pins X1 through X4.
|
||||
|
||||
|
||||
Methods
|
||||
@@ -17,22 +39,41 @@ Methods
|
||||
|
||||
.. method:: servo.angle([angle, time=0])
|
||||
|
||||
Get or set the angle of the servo.
|
||||
|
||||
If no arguments are given, this function returns the current angle.
|
||||
|
||||
If arguments are given, this function sets the angle of the servo:
|
||||
|
||||
- ``angle`` is the angle to move to in degrees.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified angle.
|
||||
|
||||
.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
|
||||
|
||||
Get or set the calibration of the servo timing.
|
||||
|
||||
.. method:: servo.pulse_width([value])
|
||||
|
||||
Get or set the pulse width in milliseconds.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified
|
||||
angle. If omitted, then the servo moves as quickly as possible to its
|
||||
new position.
|
||||
|
||||
.. method:: servo.speed([speed, time=0])
|
||||
|
||||
Get or set the speed of a continuous rotation servo.
|
||||
|
||||
- ``speed`` is the speed to move to change to, between -100 and 100.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified speed.
|
||||
If no arguments are given, this function returns the current speed.
|
||||
|
||||
If arguments are given, this function sets the speed of the servo:
|
||||
|
||||
- ``speed`` is the speed to change to, between -100 and 100.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified
|
||||
speed. If omitted, then the servo accelerates as quickly as possible.
|
||||
|
||||
.. method:: servo.pulse_width([value])
|
||||
|
||||
If no arguments are given, this function returns the current raw pulse-width
|
||||
value.
|
||||
|
||||
If an argument is given, this function sets the raw pulse-width value.
|
||||
|
||||
.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
|
||||
|
||||
If no arguments are given, this function returns the current calibration
|
||||
data, as a 5-tuple.
|
||||
|
||||
If arguments are given, this function sets the timing calibration:
|
||||
|
||||
- ``pulse_min`` is the minimum allowed pulse width.
|
||||
- ``pulse_max`` is the maximum allowed pulse width.
|
||||
- ``pulse_centre`` is the pulse width corresponding to the centre/zero position.
|
||||
- ``pulse_angle_90`` is the pulse width corresponding to 90 degrees.
|
||||
- ``pulse_speed_100`` is the pulse width corresponding to a speed of 100.
|
||||
|
||||
@@ -98,6 +98,7 @@ Power related functions
|
||||
If given no arguments, returns a tuple of clock frequencies:
|
||||
(sysclk, hclk, pclk1, pclk2).
|
||||
These correspond to:
|
||||
|
||||
- sysclk: frequency of the CPU
|
||||
- hclk: frequency of the AHB bus, core memory and DMA
|
||||
- pclk1: frequency of the APB1 bus
|
||||
@@ -112,6 +113,9 @@ Power related functions
|
||||
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
|
||||
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
|
||||
|
||||
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
|
||||
84MHz. Be sure not to set frequencies above these values.
|
||||
|
||||
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
|
||||
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
|
||||
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
|
||||
|
||||
138
docs/library/uctypes.rst
Normal file
138
docs/library/uctypes.rst
Normal file
@@ -0,0 +1,138 @@
|
||||
:mod:`uctypes` -- access C structures
|
||||
=====================================
|
||||
|
||||
.. module:: uctypes
|
||||
:synopsis: access C structures
|
||||
|
||||
This module implements "foreign data interface" for MicroPython. The idea
|
||||
behind it is similar to CPython's ``ctypes`` modules, but actual API is
|
||||
different, steamlined and optimized for small size.
|
||||
|
||||
Defining structure layout
|
||||
-------------------------
|
||||
|
||||
Structure layout is defined by a "descriptor" - a Python dictionary which
|
||||
encodes field names as keys and other properties required to access them as
|
||||
an associated values. Currently, uctypes requires explicit specification of
|
||||
offsets for each field. Offset are given in bytes from structure start.
|
||||
|
||||
Following are encoding examples for various field types:
|
||||
|
||||
Scalar types::
|
||||
|
||||
"field_name": uctypes.UINT32 | 0
|
||||
|
||||
in other words, value is scalar type identifier ORed with field offset
|
||||
(in bytes) from the start of the structure.
|
||||
|
||||
Recursive structures::
|
||||
|
||||
"sub": (2, {
|
||||
"b0": uctypes.UINT8 | 0,
|
||||
"b1": uctypes.UINT8 | 1,
|
||||
})
|
||||
|
||||
i.e. value is a 2-tuple, first element of which is offset, and second is
|
||||
a structure descriptor dictionary (note: offsets in recursive descriptors
|
||||
are relative to a structure it defines).
|
||||
|
||||
Arrays of primitive types::
|
||||
|
||||
"arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
|
||||
|
||||
i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
|
||||
with offset, and second is scalar element type ORed number of elements
|
||||
in array.
|
||||
|
||||
Arrays of aggregate types::
|
||||
|
||||
"arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
|
||||
|
||||
i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
|
||||
with offset, second is a number of elements in array, and third is
|
||||
descriptor of element type.
|
||||
|
||||
Pointer to a primitive type::
|
||||
|
||||
"ptr": (uctypes.PTR | 0, uctypes.UINT8),
|
||||
|
||||
i.e. value is a 2-tuple, first element of which is PTR flag ORed
|
||||
with offset, and second is scalar element type.
|
||||
|
||||
Pointer to aggregate type::
|
||||
|
||||
"ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}),
|
||||
|
||||
i.e. value is a 2-tuple, first element of which is PTR flag ORed
|
||||
with offset, second is descriptor of type pointed to.
|
||||
|
||||
Bitfields::
|
||||
|
||||
"bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN,
|
||||
|
||||
i.e. value is type of scalar value containing given bitfield (typenames are
|
||||
similar to scalar types, but prefixes with "BF"), ORed with offset for
|
||||
scalar value containing the bitfield, and further ORed with values for
|
||||
bit offset and bit length of the bitfield within scalar value, shifted by
|
||||
BF_POS and BF_LEN positions, respectively. Bitfield position is counted
|
||||
from the least significant bit, and is the number of right-most bit of a
|
||||
field (in other words, it's a number of bits a scalar needs to be shifted
|
||||
right to extra the bitfield).
|
||||
|
||||
In the example above, first UINT16 value will be extracted at offset 0
|
||||
(this detail may be important when accessing hardware registers, where
|
||||
particular access size and alignment are required), and then bitfield
|
||||
whose rightmost bit is least-significant bit of this UINT16, and length
|
||||
is 8 bits, will be extracted - effectively, this will access
|
||||
least-significant byte of UINT16.
|
||||
|
||||
Note that bitfield operations are independent of target byte endianness,
|
||||
in particular, example above will access least-significant byte of UINT16
|
||||
in both little- and big-endian structures. But it depends on the least
|
||||
significant bit being numbered 0. Some targets may use different
|
||||
numbering in their native ABI, but ``uctypes`` always uses normalized
|
||||
numbering described above.
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. class:: struct(descriptor, layout_type)
|
||||
|
||||
Create a "foreign data structure" object based on its descriptor (encoded
|
||||
as a dictionary) and layout type.
|
||||
|
||||
.. data:: LITTLE_ENDIAN
|
||||
|
||||
Little-endian packed structure. (Packed means that every field occupies
|
||||
exactly many bytes as defined in the descriptor, i.e. alignment is 1).
|
||||
|
||||
.. data:: BIG_ENDIAN
|
||||
|
||||
Big-endian packed structure.
|
||||
|
||||
.. data:: NATIVE
|
||||
|
||||
Native structure - with data endianness and alignment conforming to
|
||||
the target ABI.
|
||||
|
||||
(to be continued)
|
||||
|
||||
Structure objects
|
||||
-----------------
|
||||
|
||||
Structure objects allow accessing individual fields using standard dot
|
||||
notation: ``my_struct.field1``. If a field is of scalar type, getting
|
||||
it will produce primitive value (Python integer or float) corresponding
|
||||
to value contained in a field. Scalar field can also be assigned to.
|
||||
|
||||
If a field is an array, its individual elements can be accessed with
|
||||
standard subscript operator - both read and assigned to.
|
||||
|
||||
If a field is a pointer, it can be dereferenced using ``[0]`` syntax
|
||||
(corresponding to C ``*`` operator, though ``[0]`` works in C too).
|
||||
Subscripting pointer with other integer values but 0 are supported too,
|
||||
with the same semantics as in C.
|
||||
|
||||
Summing up, accessing structure fields generally follows C syntax,
|
||||
except for pointer derefence, you need to use ``[0]`` operator instead
|
||||
of ``*``.
|
||||
@@ -48,6 +48,18 @@ See :ref:`pyb.Pin <pyb.Pin>`. ::
|
||||
p_in = Pin('X2', Pin.IN, Pin.PULL_UP)
|
||||
p_in.value() # get value, 0 or 1
|
||||
|
||||
Servo control
|
||||
-------------
|
||||
|
||||
See :ref:`pyb.Servo <pyb.Servo>`. ::
|
||||
|
||||
from pyb import Servo
|
||||
|
||||
s1 = Servo(1) # servo on position 1 (X1, VIN, GND)
|
||||
s1.angle(45) # move to 45 degrees
|
||||
s1.angle(-60, 1500) # move to -60 degrees in 1500ms
|
||||
s1.speed(50) # for continuous rotation servos
|
||||
|
||||
External interrupts
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -55,9 +55,13 @@ For example::
|
||||
You can also play WAV files using the Python ``wave`` module. You can get
|
||||
the wave module `here <http://micropython.org/resources/examples/wave.py>`_ and you will also need
|
||||
the chunk module available `here <http://micropython.org/resources/examples/chunk.py>`_. Put these
|
||||
on your pyboard (either on the flash or the SD card in the top-level
|
||||
directory). You will need an 8-bit WAV file to play, such as
|
||||
`this one <http://micropython.org/resources/examples/test.wav>`_. Then you can do::
|
||||
on your pyboard (either on the flash or the SD card in the top-level directory). You will need an
|
||||
8-bit WAV file to play, such as `this one <http://micropython.org/resources/examples/test.wav>`_,
|
||||
or to convert any file you have with the command::
|
||||
|
||||
avconv -i original.wav -ar 22050 -codec pcm_u8 test.wav
|
||||
|
||||
Then you can do::
|
||||
|
||||
>>> import wave
|
||||
>>> from pyb import DAC
|
||||
|
||||
@@ -23,6 +23,9 @@ then select the option to find the driver manually (don't use Windows auto updat
|
||||
navigate to the pyboard's USB drive, and select that. It should then install.
|
||||
After installing, go back to the Device Manager to find the installed pyboard,
|
||||
and see which COM port it is (eg COM4).
|
||||
More comprehensive instructions can be found in the
|
||||
`Guide for pyboard on Windows (PDF) <http://micropython.org/resources/Micro-Python-Windows-setup.pdf>`_.
|
||||
Please consult this guide if you are having problems installing the driver.
|
||||
|
||||
You now need to run your terminal program. You can use HyperTerminal if you
|
||||
have it installed, or download the free program PuTTY:
|
||||
|
||||
@@ -34,13 +34,9 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "pin.h"
|
||||
#include "led.h"
|
||||
#include "extint.h"
|
||||
@@ -177,7 +173,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler)
|
||||
CS_HIGH();
|
||||
|
||||
// register EXTI
|
||||
extint_register((mp_obj_t)PIN_IRQ, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t)&irq_callback_obj, true, NULL);
|
||||
extint_register((mp_obj_t)PIN_IRQ, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t)&irq_callback_obj, true);
|
||||
extint_enable(PIN_IRQ->pin);
|
||||
|
||||
DEBUG_printf("SpiOpen finished; IRQ.pin=%d IRQ_LINE=%d\n", PIN_IRQ->pin, PIN_IRQ->pin);
|
||||
|
||||
@@ -11,8 +11,9 @@ CROSS_COMPILE = xtensa-lx106-elf-
|
||||
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
|
||||
|
||||
INC = -I.
|
||||
INC += -I$(PY_SRC)
|
||||
INC += -I..
|
||||
INC += -I../stmhal
|
||||
INC += -I../lib/mp-readline
|
||||
INC += -I$(BUILD)
|
||||
INC += -I$(ESP_SDK)/include
|
||||
|
||||
@@ -52,7 +53,10 @@ STM_SRC_C = $(addprefix stmhal/,\
|
||||
printf.c \
|
||||
string0.c \
|
||||
pyexec.c \
|
||||
readline.c \
|
||||
)
|
||||
|
||||
LIB_SRC_C = $(addprefix lib/,\
|
||||
mp-readline/readline.c \
|
||||
)
|
||||
|
||||
SRC_S = \
|
||||
@@ -63,6 +67,7 @@ OBJ += $(PY_O)
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
|
||||
#OBJ += $(BUILD)/pins_$(BOARD).o
|
||||
|
||||
all: $(BUILD)/firmware-combined.bin
|
||||
|
||||
@@ -40,4 +40,7 @@ void HAL_Delay(uint32_t Delay);
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
uint32_t mp_hal_get_cpu_freq(void);
|
||||
|
||||
#define UART_TASK_ID 0
|
||||
void uart_task_init();
|
||||
|
||||
#endif // _INCLUDED_MPHAL_H_
|
||||
|
||||
@@ -25,13 +25,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "gc.h"
|
||||
#include "py/gc.h"
|
||||
#include "gccollect.h"
|
||||
|
||||
STATIC uint32_t stack_end;
|
||||
|
||||
@@ -27,27 +27,24 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "gc.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/parsehelper.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/gc.h"
|
||||
#include "pyexec.h"
|
||||
#include "gccollect.h"
|
||||
#include MICROPY_HAL_H
|
||||
|
||||
STATIC char heap[16384];
|
||||
|
||||
void user_init(void) {
|
||||
soft_reset:
|
||||
//mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 1024);
|
||||
mp_stack_set_limit(10240);
|
||||
mp_hal_init();
|
||||
gc_init(&_heap_start, &_heap_end);
|
||||
gc_init(heap, heap + sizeof(heap));
|
||||
gc_collect_init();
|
||||
mp_init();
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
@@ -55,6 +52,12 @@ soft_reset:
|
||||
|
||||
printf("\n");
|
||||
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_friendly_repl_init();
|
||||
uart_task_init();
|
||||
return;
|
||||
goto soft_reset;
|
||||
#else
|
||||
for (;;) {
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||
if (pyexec_raw_repl() != 0) {
|
||||
@@ -68,6 +71,7 @@ soft_reset:
|
||||
}
|
||||
|
||||
goto soft_reset;
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
|
||||
@@ -24,19 +24,16 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "gc.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/gc.h"
|
||||
#include "gccollect.h"
|
||||
#include "pyexec.h"
|
||||
#include "pybstdio.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "user_interface.h"
|
||||
|
||||
STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// print info about memory
|
||||
@@ -140,6 +137,12 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
|
||||
|
||||
STATIC mp_obj_t pyb_hard_reset(void) {
|
||||
system_restart();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_hard_reset_obj, pyb_hard_reset);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
|
||||
|
||||
@@ -153,6 +156,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_STACK_CHECK (0)
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (1)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
@@ -61,6 +63,11 @@ extern const struct _mp_obj_module_t pyb_module;
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8];
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
|
||||
@@ -25,16 +25,11 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "misc.h"
|
||||
#include "obj.h"
|
||||
#include "stream.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/stream.h"
|
||||
#include "pybstdio.h"
|
||||
#include MICROPY_HAL_H
|
||||
|
||||
|
||||
@@ -39,3 +39,4 @@ Q(elapsed_micros)
|
||||
Q(delay)
|
||||
Q(udelay)
|
||||
Q(sync)
|
||||
Q(hard_reset)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "uart_register.h"
|
||||
#include "etshal.h"
|
||||
#include "c_types.h"
|
||||
#include "user_interface.h"
|
||||
#include "esp_mphal.h"
|
||||
|
||||
#define RX_BUF_SIZE (256)
|
||||
|
||||
@@ -27,6 +29,8 @@ static uint16_t rx_buf_in;
|
||||
static uint16_t rx_buf_out;
|
||||
static uint8_t rx_buf[RX_BUF_SIZE];
|
||||
|
||||
static os_event_t uart_evt_queue[16];
|
||||
|
||||
static void uart0_rx_intr_handler(void *para);
|
||||
|
||||
/******************************************************************************
|
||||
@@ -148,11 +152,15 @@ static void uart0_rx_intr_handler(void *para) {
|
||||
read_chars:
|
||||
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
||||
RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
|
||||
#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
|
||||
system_os_post(UART_TASK_ID, 0, RcvChar);
|
||||
#else
|
||||
uint16_t rx_buf_in_next = (rx_buf_in + 1) % RX_BUF_SIZE;
|
||||
if (rx_buf_in_next != rx_buf_out) {
|
||||
rx_buf[rx_buf_in] = RcvChar;
|
||||
rx_buf_in = rx_buf_in_next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,3 +197,15 @@ void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
|
||||
void ICACHE_FLASH_ATTR uart_reattach() {
|
||||
uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
|
||||
}
|
||||
|
||||
// Task-based UART interface
|
||||
|
||||
int pyexec_friendly_repl_process_char(int c);
|
||||
|
||||
void uart_task_handler(os_event_t *evt) {
|
||||
pyexec_friendly_repl_process_char(evt->par);
|
||||
}
|
||||
|
||||
void uart_task_init() {
|
||||
system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
|
||||
}
|
||||
|
||||
@@ -28,22 +28,20 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
|
||||
#if MICROPY_PY_UBINASCII
|
||||
|
||||
STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
byte *in = bufinfo.buf, *out;
|
||||
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, bufinfo.len * 2, &out);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, bufinfo.len * 2);
|
||||
byte *in = bufinfo.buf, *out = (byte*)vstr.buf;
|
||||
for (mp_uint_t i = bufinfo.len; i--;) {
|
||||
byte d = (*in >> 4);
|
||||
if (d > 9) {
|
||||
@@ -56,7 +54,7 @@ STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
*out++ = d + '0';
|
||||
}
|
||||
return mp_obj_str_builder_end(o);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);
|
||||
|
||||
|
||||
@@ -27,14 +27,11 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "objtuple.h"
|
||||
#include "binary.h"
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/binary.h"
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
@@ -120,11 +117,12 @@ typedef struct _mp_obj_uctypes_struct_t {
|
||||
uint32_t flags;
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
STATIC NORETURN void syntax_error() {
|
||||
STATIC NORETURN void syntax_error(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
(void)n_kw;
|
||||
if (n_args < 2 || n_args > 3) {
|
||||
syntax_error();
|
||||
}
|
||||
@@ -140,6 +138,7 @@ STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_u
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
const char *typen = "unk";
|
||||
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
|
||||
@@ -27,12 +27,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_UHASHLIB
|
||||
|
||||
@@ -67,14 +63,15 @@ MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
|
||||
|
||||
STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = self_in;
|
||||
byte *hash;
|
||||
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, SHA256_BLOCK_SIZE, &hash);
|
||||
sha256_final((SHA256_CTX*)self->state, hash);
|
||||
return mp_obj_str_builder_end(o);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||
sha256_final((SHA256_CTX*)self->state, (byte*)vstr.buf);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
|
||||
|
||||
STATIC mp_obj_t hash_hexdigest(mp_obj_t self_in) {
|
||||
(void)self_in;
|
||||
mp_not_implemented("");
|
||||
#if 0
|
||||
mp_obj_hash_t *self = self_in;
|
||||
|
||||
@@ -26,14 +26,10 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
|
||||
|
||||
@@ -28,14 +28,10 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "parsenum.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/parsenum.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_UJSON
|
||||
|
||||
@@ -85,6 +81,9 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
case ',':
|
||||
case ':':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
s += 1;
|
||||
goto cont;
|
||||
case 'n':
|
||||
|
||||
@@ -28,13 +28,9 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
|
||||
#if MICROPY_PY_URE
|
||||
|
||||
@@ -56,6 +52,7 @@ typedef struct _mp_obj_match_t {
|
||||
|
||||
|
||||
STATIC void match_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_match_t *self = self_in;
|
||||
print(env, "<match num=%d @%p>", self->num_matches);
|
||||
}
|
||||
@@ -86,11 +83,13 @@ STATIC const mp_obj_type_t match_type = {
|
||||
};
|
||||
|
||||
STATIC void re_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_re_t *self = self_in;
|
||||
print(env, "<re %p>", self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_re_t *self = args[0];
|
||||
Subject subj;
|
||||
mp_uint_t len;
|
||||
@@ -196,6 +195,7 @@ STATIC mp_obj_t mod_re_compile(uint n_args, const mp_obj_t *args) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
|
||||
|
||||
STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_re_t *self = mod_re_compile(1, args);
|
||||
|
||||
const mp_obj_t args2[] = {self, args[1]};
|
||||
|
||||
@@ -31,12 +31,8 @@
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "nlr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_UZLIB
|
||||
|
||||
@@ -59,6 +55,7 @@ STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) {
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uzlib_decompress(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
@@ -49,6 +49,11 @@ double __attribute__((pcs("aapcs"))) __aeabi_i2d(int32_t x) {
|
||||
return (float)x;
|
||||
}
|
||||
|
||||
// TODO
|
||||
long long __attribute__((pcs("aapcs"))) __aeabi_f2lz(float x) {
|
||||
return (long)x;
|
||||
}
|
||||
|
||||
double __attribute__((pcs("aapcs"))) __aeabi_f2d(float x) {
|
||||
float_s_t fx={0};
|
||||
double_s_t dx={0};
|
||||
@@ -117,8 +122,6 @@ float tgammaf(float x) { return 0.0; }
|
||||
float lgammaf(float x) { return 0.0; }
|
||||
float erff(float x) { return 0.0; }
|
||||
float erfcf(float x) { return 0.0; }
|
||||
float modff(float x, float *y) { return 0.0; }
|
||||
float frexpf(float x, int *exp) { return 0.0; }
|
||||
float ldexpf(float x, int exp) { return 0.0; }
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
70
lib/libm/sf_frexp.c
Normal file
70
lib/libm/sf_frexp.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* These math functions are taken from newlib-nano-2, the newlib/libm/math
|
||||
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
|
||||
*
|
||||
* Appropriate copyright headers are reproduced below.
|
||||
*/
|
||||
|
||||
/* sf_frexp.c -- float version of s_frexp.c.
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#include "fdlibm.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
two25 = 3.3554432000e+07; /* 0x4c000000 */
|
||||
|
||||
#ifdef __STDC__
|
||||
float frexpf(float x, int *eptr)
|
||||
#else
|
||||
float frexpf(x, eptr)
|
||||
float x; int *eptr;
|
||||
#endif
|
||||
{
|
||||
__int32_t hx, ix;
|
||||
GET_FLOAT_WORD(hx,x);
|
||||
ix = 0x7fffffff&hx;
|
||||
*eptr = 0;
|
||||
if(!FLT_UWORD_IS_FINITE(ix)||FLT_UWORD_IS_ZERO(ix)) return x; /* 0,inf,nan */
|
||||
if (FLT_UWORD_IS_SUBNORMAL(ix)) { /* subnormal */
|
||||
x *= two25;
|
||||
GET_FLOAT_WORD(hx,x);
|
||||
ix = hx&0x7fffffff;
|
||||
*eptr = -25;
|
||||
}
|
||||
*eptr += (ix>>23)-126;
|
||||
hx = (hx&0x807fffff)|0x3f000000;
|
||||
SET_FLOAT_WORD(x,hx);
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef _DOUBLE_IS_32BITS
|
||||
|
||||
#ifdef __STDC__
|
||||
double frexp(double x, int *eptr)
|
||||
#else
|
||||
double frexp(x, eptr)
|
||||
double x; int *eptr;
|
||||
#endif
|
||||
{
|
||||
return (double) frexpf((float) x, eptr);
|
||||
}
|
||||
|
||||
#endif /* defined(_DOUBLE_IS_32BITS) */
|
||||
82
lib/libm/sf_modf.c
Normal file
82
lib/libm/sf_modf.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* These math functions are taken from newlib-nano-2, the newlib/libm/common
|
||||
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
|
||||
*
|
||||
* Appropriate copyright headers are reproduced below.
|
||||
*/
|
||||
|
||||
/* sf_modf.c -- float version of s_modf.c.
|
||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#include "fdlibm.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
static const float one = 1.0;
|
||||
#else
|
||||
static float one = 1.0;
|
||||
#endif
|
||||
|
||||
#ifdef __STDC__
|
||||
float modff(float x, float *iptr)
|
||||
#else
|
||||
float modff(x, iptr)
|
||||
float x,*iptr;
|
||||
#endif
|
||||
{
|
||||
__int32_t i0,j0;
|
||||
__uint32_t i;
|
||||
GET_FLOAT_WORD(i0,x);
|
||||
j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */
|
||||
if(j0<23) { /* integer part in x */
|
||||
if(j0<0) { /* |x|<1 */
|
||||
SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */
|
||||
return x;
|
||||
} else {
|
||||
i = (0x007fffff)>>j0;
|
||||
if((i0&i)==0) { /* x is integral */
|
||||
__uint32_t ix;
|
||||
*iptr = x;
|
||||
GET_FLOAT_WORD(ix,x);
|
||||
SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
|
||||
return x;
|
||||
} else {
|
||||
SET_FLOAT_WORD(*iptr,i0&(~i));
|
||||
return x - *iptr;
|
||||
}
|
||||
}
|
||||
} else { /* no fraction part */
|
||||
__uint32_t ix;
|
||||
*iptr = x*one;
|
||||
GET_FLOAT_WORD(ix,x);
|
||||
SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DOUBLE_IS_32BITS
|
||||
|
||||
#ifdef __STDC__
|
||||
double modf(double x, double *iptr)
|
||||
#else
|
||||
double modf(x, iptr)
|
||||
double x,*iptr;
|
||||
#endif
|
||||
{
|
||||
return (double) modff((float) x, (float *) iptr);
|
||||
}
|
||||
|
||||
#endif /* defined(_DOUBLE_IS_32BITS) */
|
||||
276
lib/mp-readline/readline.c
Normal file
276
lib/mp-readline/readline.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "readline.h"
|
||||
#include "pybstdio.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
#define DEBUG_printf printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)))
|
||||
|
||||
enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O };
|
||||
|
||||
void readline_init0(void) {
|
||||
memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*));
|
||||
}
|
||||
|
||||
STATIC char *str_dup_maybe(const char *str) {
|
||||
uint32_t len = strlen(str);
|
||||
char *s2 = m_new_maybe(char, len + 1);
|
||||
if (s2 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(s2, str, len + 1);
|
||||
return s2;
|
||||
}
|
||||
|
||||
typedef struct _readline_t {
|
||||
vstr_t *line;
|
||||
int orig_line_len;
|
||||
int escape_seq;
|
||||
int hist_cur;
|
||||
int cursor_pos;
|
||||
char escape_seq_buf[1];
|
||||
} readline_t;
|
||||
|
||||
readline_t rl;
|
||||
|
||||
int readline_process_char(int c) {
|
||||
int last_line_len = rl.line->len;
|
||||
int redraw_step_back = 0;
|
||||
bool redraw_from_cursor = false;
|
||||
int redraw_step_forward = 0;
|
||||
if (rl.escape_seq == ESEQ_NONE) {
|
||||
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_D && vstr_len(rl.line) == rl.orig_line_len) {
|
||||
// control character with empty line
|
||||
return c;
|
||||
} else if (c == CHAR_CTRL_A) {
|
||||
// CTRL-A with non-empty line is go-to-start-of-line
|
||||
goto home_key;
|
||||
} else if (c == CHAR_CTRL_C) {
|
||||
// CTRL-C with non-empty line is cancel
|
||||
return c;
|
||||
} else if (c == CHAR_CTRL_E) {
|
||||
// CTRL-E is go-to-end-of-line
|
||||
goto end_key;
|
||||
} else if (c == '\r') {
|
||||
// newline
|
||||
stdout_tx_str("\r\n");
|
||||
if (rl.line->len > rl.orig_line_len && (MP_STATE_PORT(readline_hist)[0] == NULL || strcmp(MP_STATE_PORT(readline_hist)[0], rl.line->buf + rl.orig_line_len) != 0)) {
|
||||
// a line which is not empty and different from the last one
|
||||
// so update the history
|
||||
char *most_recent_hist = str_dup_maybe(rl.line->buf + rl.orig_line_len);
|
||||
if (most_recent_hist != NULL) {
|
||||
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
|
||||
MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];
|
||||
}
|
||||
MP_STATE_PORT(readline_hist)[0] = most_recent_hist;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else if (c == 27) {
|
||||
// escape sequence
|
||||
rl.escape_seq = ESEQ_ESC;
|
||||
} else if (c == 8 || c == 127) {
|
||||
// backspace/delete
|
||||
if (rl.cursor_pos > rl.orig_line_len) {
|
||||
vstr_cut_out_bytes(rl.line, rl.cursor_pos - 1, 1);
|
||||
// set redraw parameters
|
||||
redraw_step_back = 1;
|
||||
redraw_from_cursor = true;
|
||||
}
|
||||
} else if (32 <= c && c <= 126) {
|
||||
// printable character
|
||||
vstr_ins_char(rl.line, rl.cursor_pos, c);
|
||||
// set redraw parameters
|
||||
redraw_from_cursor = true;
|
||||
redraw_step_forward = 1;
|
||||
}
|
||||
} else if (rl.escape_seq == ESEQ_ESC) {
|
||||
switch (c) {
|
||||
case '[':
|
||||
rl.escape_seq = ESEQ_ESC_BRACKET;
|
||||
break;
|
||||
case 'O':
|
||||
rl.escape_seq = ESEQ_ESC_O;
|
||||
break;
|
||||
default:
|
||||
DEBUG_printf("(ESC %d)", c);
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
}
|
||||
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
rl.escape_seq = ESEQ_ESC_BRACKET_DIGIT;
|
||||
rl.escape_seq_buf[0] = c;
|
||||
} else {
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
if (c == 'A') {
|
||||
// up arrow
|
||||
if (rl.hist_cur + 1 < READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[rl.hist_cur + 1] != NULL) {
|
||||
// increase hist num
|
||||
rl.hist_cur += 1;
|
||||
// set line to history
|
||||
rl.line->len = rl.orig_line_len;
|
||||
vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);
|
||||
// set redraw parameters
|
||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||
redraw_from_cursor = true;
|
||||
redraw_step_forward = rl.line->len - rl.orig_line_len;
|
||||
}
|
||||
} else if (c == 'B') {
|
||||
// down arrow
|
||||
if (rl.hist_cur >= 0) {
|
||||
// decrease hist num
|
||||
rl.hist_cur -= 1;
|
||||
// set line to history
|
||||
vstr_cut_tail_bytes(rl.line, rl.line->len - rl.orig_line_len);
|
||||
if (rl.hist_cur >= 0) {
|
||||
vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);
|
||||
}
|
||||
// set redraw parameters
|
||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||
redraw_from_cursor = true;
|
||||
redraw_step_forward = rl.line->len - rl.orig_line_len;
|
||||
}
|
||||
} else if (c == 'C') {
|
||||
// right arrow
|
||||
if (rl.cursor_pos < rl.line->len) {
|
||||
redraw_step_forward = 1;
|
||||
}
|
||||
} else if (c == 'D') {
|
||||
// left arrow
|
||||
if (rl.cursor_pos > rl.orig_line_len) {
|
||||
redraw_step_back = 1;
|
||||
}
|
||||
} else if (c == 'H') {
|
||||
// home
|
||||
goto home_key;
|
||||
} else if (c == 'F') {
|
||||
// end
|
||||
goto end_key;
|
||||
} else {
|
||||
DEBUG_printf("(ESC [ %d)", c);
|
||||
}
|
||||
}
|
||||
} else if (rl.escape_seq == ESEQ_ESC_BRACKET_DIGIT) {
|
||||
if (c == '~') {
|
||||
if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') {
|
||||
home_key:
|
||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||
} else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') {
|
||||
end_key:
|
||||
redraw_step_forward = rl.line->len - rl.cursor_pos;
|
||||
} else {
|
||||
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
||||
}
|
||||
} else {
|
||||
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
||||
}
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
} else if (rl.escape_seq == ESEQ_ESC_O) {
|
||||
switch (c) {
|
||||
case 'H':
|
||||
goto home_key;
|
||||
case 'F':
|
||||
goto end_key;
|
||||
default:
|
||||
DEBUG_printf("(ESC O %d)", c);
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
}
|
||||
} else {
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
}
|
||||
|
||||
// redraw command prompt, efficiently
|
||||
// TODO we can probably use some more sophisticated VT100 commands here
|
||||
if (redraw_step_back > 0) {
|
||||
for (int i = 0; i < redraw_step_back; i++) {
|
||||
stdout_tx_str("\b");
|
||||
}
|
||||
rl.cursor_pos -= redraw_step_back;
|
||||
}
|
||||
if (redraw_from_cursor) {
|
||||
if (rl.line->len < last_line_len) {
|
||||
// erase old chars
|
||||
for (int i = rl.cursor_pos; i < last_line_len; i++) {
|
||||
stdout_tx_str(" ");
|
||||
}
|
||||
// step back
|
||||
for (int i = rl.cursor_pos; i < last_line_len; i++) {
|
||||
stdout_tx_str("\b");
|
||||
}
|
||||
}
|
||||
// draw new chars
|
||||
stdout_tx_strn(rl.line->buf + rl.cursor_pos, rl.line->len - rl.cursor_pos);
|
||||
// move cursor forward if needed (already moved forward by length of line, so move it back)
|
||||
for (int i = rl.cursor_pos + redraw_step_forward; i < rl.line->len; i++) {
|
||||
stdout_tx_str("\b");
|
||||
}
|
||||
rl.cursor_pos += redraw_step_forward;
|
||||
} else if (redraw_step_forward > 0) {
|
||||
// draw over old chars to move cursor forwards
|
||||
stdout_tx_strn(rl.line->buf + rl.cursor_pos, redraw_step_forward);
|
||||
rl.cursor_pos += redraw_step_forward;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void readline_note_newline(void) {
|
||||
rl.orig_line_len = rl.line->len;
|
||||
rl.cursor_pos = rl.orig_line_len;
|
||||
}
|
||||
|
||||
void readline_init(vstr_t *line) {
|
||||
rl.line = line;
|
||||
rl.orig_line_len = line->len;
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
rl.escape_seq_buf[0] = 0;
|
||||
rl.hist_cur = -1;
|
||||
rl.cursor_pos = rl.orig_line_len;
|
||||
}
|
||||
|
||||
int readline(vstr_t *line, const char *prompt) {
|
||||
stdout_tx_str(prompt);
|
||||
readline_init(line);
|
||||
for (;;) {
|
||||
int c = stdin_rx_chr();
|
||||
int r = readline_process_char(c);
|
||||
if (r >= 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,3 +32,7 @@
|
||||
|
||||
void readline_init0(void);
|
||||
int readline(vstr_t *line, const char *prompt);
|
||||
|
||||
void readline_init(vstr_t *line);
|
||||
void readline_note_newline(void);
|
||||
int readline_process_char(int c);
|
||||
77
minimal/Makefile
Normal file
77
minimal/Makefile
Normal file
@@ -0,0 +1,77 @@
|
||||
include ../py/mkenv.mk
|
||||
|
||||
CROSS = 0
|
||||
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h
|
||||
|
||||
# include py core make definitions
|
||||
include ../py/py.mk
|
||||
|
||||
ifeq ($(CROSS), 1)
|
||||
CROSS_COMPILE = arm-none-eabi-
|
||||
endif
|
||||
|
||||
INC = -I.
|
||||
INC += -I..
|
||||
INC += -I../lib/mp-readline
|
||||
INC += -I../stmhal
|
||||
INC += -I$(BUILD)
|
||||
|
||||
ifeq ($(CROSS), 1)
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
else
|
||||
CFLAGS = -m32 $(INC) -Wall -Werror -ansi -std=gnu99 $(COPT)
|
||||
endif
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -ggdb
|
||||
else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(CROSS), 1)
|
||||
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
|
||||
else
|
||||
LD = gcc
|
||||
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref
|
||||
endif
|
||||
LIBS =
|
||||
|
||||
SRC_C = \
|
||||
main.c \
|
||||
uart_core.c \
|
||||
uart_extra.c \
|
||||
stmhal/printf.c \
|
||||
stmhal/string0.c \
|
||||
stmhal/pyexec.c \
|
||||
lib/mp-readline/readline.c \
|
||||
|
||||
SRC_S = \
|
||||
# startup_stm32f40xx.s \
|
||||
gchelper.s \
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
|
||||
|
||||
all: $(BUILD)/firmware.elf
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
# Run emulation build on a POSIX system with suitable terminal settings
|
||||
run:
|
||||
stty raw opost -echo
|
||||
build/firmware.elf
|
||||
@echo Resetting terminal...
|
||||
# This sleep is useful to spot segfaults
|
||||
sleep 1
|
||||
reset
|
||||
|
||||
test: $(BUILD)/firmware.elf
|
||||
$(Q)/bin/echo -e "print('hello world!', list(x+1 for x in range(10)), end='eol\\\\n')\\r\\n\\x04" | $(BUILD)/firmware.elf | tail -n2 | grep "^hello world! \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]eol"
|
||||
|
||||
include ../py/mkrules.mk
|
||||
118
minimal/main.c
Normal file
118
minimal/main.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/parsehelper.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/repl.h"
|
||||
#include "py/pfenv.h"
|
||||
#include "py/gc.h"
|
||||
#include "pyexec.h"
|
||||
#include "pybstdio.h"
|
||||
|
||||
void do_str(const char *src) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
if (lex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind);
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error
|
||||
mp_parse_show_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse okay
|
||||
qstr source_name = lex->source_name;
|
||||
mp_lexer_free(lex);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
|
||||
if (mp_obj_is_exception_instance(module_fun)) {
|
||||
// compile error
|
||||
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
|
||||
return;
|
||||
}
|
||||
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
// uncaught exception
|
||||
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
static char *stack_top;
|
||||
static char heap[2048];
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int stack_dummy;
|
||||
stack_top = (char*)&stack_dummy;
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
gc_init(heap, heap + sizeof(heap));
|
||||
#endif
|
||||
mp_init();
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_friendly_repl_init();
|
||||
for (;;) {
|
||||
int c = stdin_rx_chr();
|
||||
if (pyexec_friendly_repl_process_char(c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
pyexec_friendly_repl();
|
||||
#endif
|
||||
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')");
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gc_collect(void) {
|
||||
// WARNING: This gc_collect implementation doesn't try to get root
|
||||
// pointers from CPU registers, and thus may function incorrectly.
|
||||
void *dummy;
|
||||
gc_collect_start();
|
||||
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
|
||||
gc_collect_end();
|
||||
gc_dump_info();
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
}
|
||||
|
||||
void NORETURN __fatal_error(const char *msg) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
|
||||
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
|
||||
__fatal_error("Assertion failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !MICROPY_MIN_USE_STDOUT
|
||||
void _start(void) {main(0, NULL);}
|
||||
#endif
|
||||
81
minimal/mpconfigport.h
Normal file
81
minimal/mpconfigport.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (256)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#define MICROPY_COMP_CONST (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (0)
|
||||
#define MICROPY_PY_STRUCT (0)
|
||||
#define MICROPY_PY_SYS (0)
|
||||
#define MICROPY_MODULE_FROZEN (0)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#define BYTES_PER_WORD (4)
|
||||
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
|
||||
|
||||
// This port is intended to be 32-bit, but unfortunately, int32_t for
|
||||
// different targets may be defined in different ways - either as int
|
||||
// or as long. This requires different printf formatting specifiers
|
||||
// to print such value. So, we avoid int32_t and use int directly.
|
||||
#define UINT_FMT "%u"
|
||||
#define INT_FMT "%d"
|
||||
typedef int mp_int_t; // must be pointer size
|
||||
typedef unsigned mp_uint_t; // must be pointer size
|
||||
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
#define HAL_GetTick() 0
|
||||
|
||||
static inline void mp_hal_set_interrupt_char(char c) {}
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "minimal"
|
||||
#define MICROPY_HW_MCU_NAME "unknown-cpu"
|
||||
|
||||
#ifdef __linux__
|
||||
#define MICROPY_MIN_USE_STDOUT (1)
|
||||
#endif
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8];
|
||||
1
minimal/qstrdefsport.h
Normal file
1
minimal/qstrdefsport.h
Normal file
@@ -0,0 +1 @@
|
||||
// qstrs specific to this port
|
||||
117
minimal/stm32f405.ld
Normal file
117
minimal/stm32f405.ld
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
GNU linker script for STM32F405
|
||||
*/
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */
|
||||
FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
|
||||
FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */
|
||||
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */
|
||||
}
|
||||
|
||||
/* top end of the stack */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_heap_end = 0x2001c000; /* tunable */
|
||||
|
||||
/* define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
/* The startup code goes first into FLASH */
|
||||
.isr_vector :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
|
||||
. = ALIGN(4);
|
||||
} >FLASH_ISR
|
||||
|
||||
/* The program code and other data goes into FLASH */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
/* *(.glue_7) */ /* glue arm to thumb code */
|
||||
/* *(.glue_7t) */ /* glue thumb to arm code */
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .; /* define a global symbol at end of code */
|
||||
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
|
||||
} >FLASH_TEXT
|
||||
|
||||
/*
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} >FLASH
|
||||
|
||||
.ARM :
|
||||
{
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
} >FLASH
|
||||
*/
|
||||
|
||||
/* This is the initialized data section
|
||||
The program executes knowing that the data is in the RAM
|
||||
but the loader puts the initial values in the FLASH (inidata).
|
||||
It is one task of the startup to copy the initial values from FLASH to RAM. */
|
||||
.data : AT ( _sidata )
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
|
||||
_ram_start = .; /* create a global symbol at ram start for garbage collector */
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
|
||||
} >RAM
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .; /* define a global symbol at bss start; used by startup code */
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .; /* define a global symbol at bss end; used by startup code */
|
||||
} >RAM
|
||||
|
||||
/* this is to define the start of the heap, and make sure we have a minimum size */
|
||||
.heap :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_heap_start = .; /* define a global symbol at heap start */
|
||||
} >RAM
|
||||
|
||||
/* this just checks there is enough RAM for the stack */
|
||||
.stack :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
} >RAM
|
||||
|
||||
/* Remove information from the standard libraries */
|
||||
/*
|
||||
/DISCARD/ :
|
||||
{
|
||||
libc.a ( * )
|
||||
libm.a ( * )
|
||||
libgcc.a ( * )
|
||||
}
|
||||
*/
|
||||
|
||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||
}
|
||||
24
minimal/uart_core.c
Normal file
24
minimal/uart_core.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <unistd.h>
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
/*
|
||||
* Core UART functions to implement for a port
|
||||
*/
|
||||
|
||||
// Receive single character
|
||||
int stdin_rx_chr(void) {
|
||||
unsigned char c = 0;
|
||||
#if MICROPY_MIN_USE_STDOUT
|
||||
int r = read(0, &c, 1);
|
||||
(void)r;
|
||||
#endif
|
||||
return c;
|
||||
}
|
||||
|
||||
// Send string of given length
|
||||
void stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||
#if MICROPY_MIN_USE_STDOUT
|
||||
int r = write(1, str, len);
|
||||
(void)r;
|
||||
#endif
|
||||
}
|
||||
26
minimal/uart_extra.c
Normal file
26
minimal/uart_extra.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "py/mpconfig.h"
|
||||
#include "pybstdio.h"
|
||||
|
||||
/*
|
||||
* Extra UART functions
|
||||
* These can be either optimized for a particular port, or reference,
|
||||
* not very optimal implementation below can be used.
|
||||
*/
|
||||
|
||||
// Send "cooked" string of length, where every occurance of
|
||||
// LF character is replaced with CR LF.
|
||||
void stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
|
||||
while (len--) {
|
||||
if (*str == '\n') {
|
||||
stdout_tx_strn("\r", 1);
|
||||
}
|
||||
stdout_tx_strn(str++, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Send zero-terminated string
|
||||
void stdout_tx_str(const char *str) {
|
||||
stdout_tx_strn(str, strlen(str));
|
||||
}
|
||||
@@ -27,23 +27,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
STATIC NORETURN void terse_arg_mismatch(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch"));
|
||||
}
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp_uint_t n_args_max, bool takes_kw) {
|
||||
// TODO maybe take the function name as an argument so we can print nicer error messages
|
||||
|
||||
if (n_kw && !takes_kw) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"function does not take keyword arguments"));
|
||||
@@ -53,7 +45,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
|
||||
if (n_args_min == n_args_max) {
|
||||
if (n_args != n_args_min) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function takes %d positional arguments but %d were given",
|
||||
@@ -63,7 +55,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
|
||||
} else {
|
||||
if (n_args < n_args_min) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing %d required positional arguments",
|
||||
@@ -71,7 +63,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
|
||||
}
|
||||
} else if (n_args > n_args_max) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function expected at most %d arguments, got %d",
|
||||
@@ -92,15 +84,15 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
|
||||
pos_found++;
|
||||
given_arg = pos[i];
|
||||
} else {
|
||||
mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qstr), MP_MAP_LOOKUP);
|
||||
mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP);
|
||||
if (kw == NULL) {
|
||||
if (allowed[i].flags & MP_ARG_REQUIRED) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"'%s' argument required",
|
||||
qstr_str(allowed[i].qstr)));
|
||||
qstr_str(allowed[i].qst)));
|
||||
}
|
||||
}
|
||||
out_vals[i] = allowed[i].defval;
|
||||
@@ -123,7 +115,7 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
|
||||
if (pos_found < n_pos) {
|
||||
extra_positional:
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
// TODO better error message
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
@@ -132,7 +124,7 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
|
||||
}
|
||||
if (kws_found < kws->used) {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
terse_arg_mismatch();
|
||||
mp_arg_error_terse_mismatch();
|
||||
} else {
|
||||
// TODO better error message
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
@@ -147,6 +139,12 @@ void mp_arg_parse_all_kw_array(mp_uint_t n_pos, mp_uint_t n_kw, const mp_obj_t *
|
||||
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER
|
||||
NORETURN void mp_arg_error_terse_mismatch(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
NORETURN void mp_arg_error_unimpl_kw(void) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,
|
||||
|
||||
22
py/asmarm.c
22
py/asmarm.c
@@ -29,13 +29,13 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmarm.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_ARM
|
||||
|
||||
#include "py/asmarm.h"
|
||||
|
||||
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
|
||||
|
||||
struct _asm_arm_t {
|
||||
@@ -70,20 +70,20 @@ void asm_arm_free(asm_arm_t *as, bool free_code) {
|
||||
}
|
||||
|
||||
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_ARM_PASS_COMPUTE) {
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
|
||||
} else if (pass == ASM_ARM_PASS_EMIT) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
|
||||
if (as->code_base == NULL) {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
}
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as) {
|
||||
if (as->pass == ASM_ARM_PASS_COMPUTE) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
|
||||
if(as->code_base == NULL) {
|
||||
assert(0);
|
||||
}
|
||||
} else if(as->pass == ASM_ARM_PASS_EMIT) {
|
||||
if (as->pass == ASM_ARM_PASS_EMIT) {
|
||||
#ifdef __arm__
|
||||
// flush I- and D-cache
|
||||
asm volatile(
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_ASMARM_H__
|
||||
#define __MICROPY_INCLUDED_PY_ASMARM_H__
|
||||
|
||||
#include "py/misc.h"
|
||||
|
||||
#define ASM_ARM_PASS_COMPUTE (1)
|
||||
#define ASM_ARM_PASS_EMIT (2)
|
||||
@@ -120,3 +124,4 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label);
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_ASMARM_H__
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmthumb.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
#include "py/asmthumb.h"
|
||||
|
||||
#define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0)
|
||||
#define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0)
|
||||
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
|
||||
@@ -73,32 +73,21 @@ void asm_thumb_free(asm_thumb_t *as, bool free_code) {
|
||||
}
|
||||
|
||||
void asm_thumb_start_pass(asm_thumb_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_THUMB_PASS_COMPUTE) {
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
if (as->pass == ASM_THUMB_PASS_COMPUTE) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
|
||||
if(as->code_base == NULL) {
|
||||
} else if (pass == ASM_THUMB_PASS_EMIT) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
|
||||
if (as->code_base == NULL) {
|
||||
assert(0);
|
||||
}
|
||||
//printf("code_size: %u\n", as->code_size);
|
||||
}
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// check labels are resolved
|
||||
if (as->label != NULL)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < as->label->len; ++i)
|
||||
if (g_array_index(as->label, Label, i).unresolved != NULL)
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
// could check labels are resolved...
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_ASMTHUMB_H__
|
||||
#define __MICROPY_INCLUDED_PY_ASMTHUMB_H__
|
||||
|
||||
#include "py/misc.h"
|
||||
|
||||
#define ASM_THUMB_PASS_COMPUTE (1)
|
||||
#define ASM_THUMB_PASS_EMIT (2)
|
||||
@@ -200,3 +204,5 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
|
||||
void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience ?
|
||||
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
|
||||
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ?
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_ASMTHUMB_H__
|
||||
|
||||
53
py/asmx64.c
53
py/asmx64.c
@@ -29,13 +29,12 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_X64
|
||||
|
||||
#include "asmx64.h"
|
||||
#include "py/asmx64.h"
|
||||
|
||||
/* all offsets are measured in multiples of 8 bytes */
|
||||
#define WORD_SIZE (8)
|
||||
@@ -144,33 +143,23 @@ void asm_x64_free(asm_x64_t *as, bool free_code) {
|
||||
}
|
||||
|
||||
void asm_x64_start_pass(asm_x64_t *as, uint pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_X64_PASS_COMPUTE) {
|
||||
// reset all labels
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_x64_end_pass(asm_x64_t *as) {
|
||||
if (as->pass == ASM_X64_PASS_COMPUTE) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
|
||||
if(as->code_base == NULL) {
|
||||
} if (pass == ASM_X64_PASS_EMIT) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
|
||||
if (as->code_base == NULL) {
|
||||
assert(0);
|
||||
}
|
||||
//printf("code_size: %u\n", as->code_size);
|
||||
}
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// check labels are resolved
|
||||
if (as->label != NULL)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < as->label->len; ++i)
|
||||
if (g_array_index(as->label, Label, i).unresolved != NULL)
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
void asm_x64_end_pass(asm_x64_t *as) {
|
||||
// could check labels are resolved...
|
||||
(void)as;
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
@@ -282,11 +271,13 @@ void asm_x64_push_i32(asm_x64_t *as, int src_i32) {
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) {
|
||||
assert(src_r64 < 8);
|
||||
asm_x64_write_byte_1(as, OPCODE_PUSH_M64);
|
||||
asm_x64_write_r64_disp(as, 6, src_r64, src_offset);
|
||||
}
|
||||
*/
|
||||
|
||||
void asm_x64_pop_r64(asm_x64_t *as, int dest_r64) {
|
||||
if (dest_r64 < 8) {
|
||||
@@ -358,7 +349,7 @@ void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
STATIC void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
// use REX prefix for 64 bit operation
|
||||
assert(src_r64 < 8);
|
||||
assert(dest_r64 < 8);
|
||||
@@ -366,10 +357,12 @@ void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
/*
|
||||
void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) {
|
||||
assert(dest_r64 < 8);
|
||||
asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8);
|
||||
}
|
||||
*/
|
||||
|
||||
STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) {
|
||||
// cpu defaults to i32 to r64, with zero extension
|
||||
@@ -509,11 +502,11 @@ void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) {
|
||||
asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8));
|
||||
}
|
||||
|
||||
void asm_x64_label_assign(asm_x64_t *as, int label) {
|
||||
void asm_x64_label_assign(asm_x64_t *as, mp_uint_t label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass < ASM_X64_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
assert(as->label_offsets[label] == (mp_uint_t)-1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
@@ -522,15 +515,15 @@ void asm_x64_label_assign(asm_x64_t *as, int label) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t get_label_dest(asm_x64_t *as, int label) {
|
||||
STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) {
|
||||
assert(label < as->max_num_labels);
|
||||
return as->label_offsets[label];
|
||||
}
|
||||
|
||||
void asm_x64_jmp_label(asm_x64_t *as, int label) {
|
||||
void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {
|
||||
mp_uint_t dest = get_label_dest(as, label);
|
||||
mp_int_t rel = dest - as->code_offset;
|
||||
if (dest != -1 && rel < 0) {
|
||||
if (dest != (mp_uint_t)-1 && rel < 0) {
|
||||
// is a backwards jump, so we know the size of the jump on the first pass
|
||||
// calculate rel assuming 8 bit relative jump
|
||||
rel -= 2;
|
||||
@@ -549,10 +542,10 @@ void asm_x64_jmp_label(asm_x64_t *as, int label) {
|
||||
}
|
||||
}
|
||||
|
||||
void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, int label) {
|
||||
void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {
|
||||
mp_uint_t dest = get_label_dest(as, label);
|
||||
mp_int_t rel = dest - as->code_offset;
|
||||
if (dest != -1 && rel < 0) {
|
||||
if (dest != (mp_uint_t)-1 && rel < 0) {
|
||||
// is a backwards jump, so we know the size of the jump on the first pass
|
||||
// calculate rel assuming 8 bit relative jump
|
||||
rel -= 2;
|
||||
|
||||
13
py/asmx64.h
13
py/asmx64.h
@@ -23,6 +23,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_ASMX64_H__
|
||||
#define __MICROPY_INCLUDED_PY_ASMX64_H__
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
// AMD64 calling convention is:
|
||||
// - args pass in: RDI, RSI, RDX, RCX, R08, R09
|
||||
@@ -99,12 +104,14 @@ void asm_x64_sub_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
|
||||
void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b);
|
||||
void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b);
|
||||
void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8);
|
||||
void asm_x64_label_assign(asm_x64_t* as, int label);
|
||||
void asm_x64_jmp_label(asm_x64_t* as, int label);
|
||||
void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, int label);
|
||||
void asm_x64_label_assign(asm_x64_t* as, mp_uint_t label);
|
||||
void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label);
|
||||
void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label);
|
||||
void asm_x64_entry(asm_x64_t* as, int num_locals);
|
||||
void asm_x64_exit(asm_x64_t* as);
|
||||
void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64);
|
||||
void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num);
|
||||
void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64);
|
||||
void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_ASMX64_H__
|
||||
|
||||
31
py/asmx86.c
31
py/asmx86.c
@@ -29,13 +29,12 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_X86
|
||||
|
||||
#include "asmx86.h"
|
||||
#include "py/asmx86.h"
|
||||
|
||||
/* all offsets are measured in multiples of 4 bytes */
|
||||
#define WORD_SIZE (4)
|
||||
@@ -132,21 +131,21 @@ void asm_x86_free(asm_x86_t *as, bool free_code) {
|
||||
}
|
||||
|
||||
void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass) {
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
if (pass == ASM_X86_PASS_COMPUTE) {
|
||||
// reset all labels
|
||||
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
|
||||
}
|
||||
}
|
||||
|
||||
void asm_x86_end_pass(asm_x86_t *as) {
|
||||
if (as->pass == ASM_X86_PASS_COMPUTE) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
|
||||
if(as->code_base == NULL) {
|
||||
} else if (pass == ASM_X86_PASS_EMIT) {
|
||||
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
|
||||
if (as->code_base == NULL) {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
as->pass = pass;
|
||||
as->code_offset = 0;
|
||||
}
|
||||
|
||||
void asm_x86_end_pass(asm_x86_t *as) {
|
||||
(void)as;
|
||||
}
|
||||
|
||||
// all functions must go through this one to emit bytes
|
||||
@@ -400,7 +399,7 @@ void asm_x86_label_assign(asm_x86_t *as, mp_uint_t label) {
|
||||
assert(label < as->max_num_labels);
|
||||
if (as->pass < ASM_X86_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(as->label_offsets[label] == -1);
|
||||
assert(as->label_offsets[label] == (mp_uint_t)-1);
|
||||
as->label_offsets[label] = as->code_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
|
||||
@@ -409,7 +408,7 @@ void asm_x86_label_assign(asm_x86_t *as, mp_uint_t label) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t get_label_dest(asm_x86_t *as, int label) {
|
||||
STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) {
|
||||
assert(label < as->max_num_labels);
|
||||
return as->label_offsets[label];
|
||||
}
|
||||
@@ -417,7 +416,7 @@ STATIC mp_uint_t get_label_dest(asm_x86_t *as, int label) {
|
||||
void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
|
||||
mp_uint_t dest = get_label_dest(as, label);
|
||||
mp_int_t rel = dest - as->code_offset;
|
||||
if (dest != -1 && rel < 0) {
|
||||
if (dest != (mp_uint_t)-1 && rel < 0) {
|
||||
// is a backwards jump, so we know the size of the jump on the first pass
|
||||
// calculate rel assuming 8 bit relative jump
|
||||
rel -= 2;
|
||||
@@ -439,7 +438,7 @@ void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
|
||||
void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {
|
||||
mp_uint_t dest = get_label_dest(as, label);
|
||||
mp_int_t rel = dest - as->code_offset;
|
||||
if (dest != -1 && rel < 0) {
|
||||
if (dest != (mp_uint_t)-1 && rel < 0) {
|
||||
// is a backwards jump, so we know the size of the jump on the first pass
|
||||
// calculate rel assuming 8 bit relative jump
|
||||
rel -= 2;
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_ASMX86_H__
|
||||
#define __MICROPY_INCLUDED_PY_ASMX86_H__
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
// x86 cdecl calling convention is:
|
||||
// - args passed on the stack in reverse order
|
||||
@@ -106,3 +111,5 @@ void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32);
|
||||
void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num);
|
||||
void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32);
|
||||
void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_ASMX86_H__
|
||||
|
||||
21
py/bc.c
21
py/bc.c
@@ -29,17 +29,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objtuple.h"
|
||||
#include "objfun.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "bc.h"
|
||||
#include "stackctrl.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/bc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -62,9 +54,8 @@ mp_uint_t mp_decode_uint(const byte **ptr) {
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
// Generic message, to be reused for other argument issues
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"argument num/types mismatch"));
|
||||
// generic message, used also for other argument issues
|
||||
mp_arg_error_terse_mismatch();
|
||||
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function takes %d positional arguments but %d were given", expected, given));
|
||||
@@ -125,7 +116,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
// Apply processing and check below only if we don't have kwargs,
|
||||
// otherwise, kw handling code below has own extensive checks.
|
||||
if (n_kw == 0 && !self->has_def_kw_args) {
|
||||
if (n_args >= self->n_pos_args - self->n_def_args) {
|
||||
if (n_args >= (mp_uint_t)(self->n_pos_args - self->n_def_args)) {
|
||||
// given enough arguments, but may need to use some default arguments
|
||||
for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
|
||||
code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];
|
||||
|
||||
7
py/bc.h
7
py/bc.h
@@ -23,6 +23,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_BC_H__
|
||||
#define __MICROPY_INCLUDED_PY_BC_H__
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
// Exception stack entry
|
||||
typedef struct _mp_exc_stack {
|
||||
@@ -61,3 +66,5 @@ const byte *mp_bytecode_print_str(const byte *ip);
|
||||
#define MP_TAGPTR_TAG0(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_TAG1(x) ((mp_uint_t)(x) & 2)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | (tag)))
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_BC_H__
|
||||
|
||||
5
py/bc0.h
5
py/bc0.h
@@ -23,6 +23,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_BC0_H__
|
||||
#define __MICROPY_INCLUDED_PY_BC0_H__
|
||||
|
||||
// Micro Python byte-codes.
|
||||
// The comment at the end of the line (if it exists) tells the arguments to the byte-code.
|
||||
@@ -36,6 +38,7 @@
|
||||
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
|
||||
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
|
||||
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
|
||||
#define MP_BC_LOAD_CONST_OBJ (0x09) // ptr; TODO renumber to be in order
|
||||
#define MP_BC_LOAD_NULL (0x19)
|
||||
|
||||
#define MP_BC_LOAD_FAST_N (0x1a) // uint
|
||||
@@ -118,3 +121,5 @@
|
||||
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
|
||||
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
|
||||
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_BC0_H__
|
||||
|
||||
44
py/binary.c
44
py/binary.c
@@ -30,12 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "smallint.h"
|
||||
#include "binary.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/smallint.h"
|
||||
|
||||
// Helpers to work with binary-encoded data
|
||||
|
||||
@@ -113,24 +109,26 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
val = ((int8_t*)p)[index];
|
||||
val = ((signed char*)p)[index];
|
||||
break;
|
||||
case BYTEARRAY_TYPECODE:
|
||||
case 'B':
|
||||
val = ((uint8_t*)p)[index];
|
||||
val = ((unsigned char*)p)[index];
|
||||
break;
|
||||
case 'h':
|
||||
val = ((int16_t*)p)[index];
|
||||
val = ((short*)p)[index];
|
||||
break;
|
||||
case 'H':
|
||||
val = ((uint16_t*)p)[index];
|
||||
val = ((unsigned short*)p)[index];
|
||||
break;
|
||||
case 'i':
|
||||
case 'l':
|
||||
return mp_obj_new_int(((int32_t*)p)[index]);
|
||||
return mp_obj_new_int(((int*)p)[index]);
|
||||
case 'I':
|
||||
return mp_obj_new_int_from_uint(((unsigned int*)p)[index]);
|
||||
case 'l':
|
||||
return mp_obj_new_int(((long*)p)[index]);
|
||||
case 'L':
|
||||
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
|
||||
return mp_obj_new_int_from_uint(((unsigned long*)p)[index]);
|
||||
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||
case 'q':
|
||||
case 'Q':
|
||||
@@ -260,7 +258,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
}
|
||||
}
|
||||
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, val);
|
||||
mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
|
||||
@@ -281,25 +279,29 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
((signed char*)p)[index] = val;
|
||||
break;
|
||||
case BYTEARRAY_TYPECODE:
|
||||
case 'B':
|
||||
val = ((uint8_t*)p)[index] = val;
|
||||
((unsigned char*)p)[index] = val;
|
||||
break;
|
||||
case 'h':
|
||||
val = ((int16_t*)p)[index] = val;
|
||||
((short*)p)[index] = val;
|
||||
break;
|
||||
case 'H':
|
||||
val = ((uint16_t*)p)[index] = val;
|
||||
((unsigned short*)p)[index] = val;
|
||||
break;
|
||||
case 'i':
|
||||
case 'l':
|
||||
((int32_t*)p)[index] = val;
|
||||
((int*)p)[index] = val;
|
||||
break;
|
||||
case 'I':
|
||||
((unsigned int*)p)[index] = val;
|
||||
break;
|
||||
case 'l':
|
||||
((long*)p)[index] = val;
|
||||
break;
|
||||
case 'L':
|
||||
((uint32_t*)p)[index] = val;
|
||||
((unsigned long*)p)[index] = val;
|
||||
break;
|
||||
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||
case 'q':
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_BINARY_H__
|
||||
#define __MICROPY_INCLUDED_PY_BINARY_H__
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// Use special typecode to differentiate repr() of bytearray vs array.array('B')
|
||||
// (underlyingly they're same).
|
||||
@@ -36,3 +40,5 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src);
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_BINARY_H__
|
||||
|
||||
13
py/builtin.h
13
py/builtin.h
@@ -23,9 +23,14 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_BUILTIN_H__
|
||||
#define __MICROPY_INCLUDED_PY_BUILTIN_H__
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
|
||||
mp_obj_t mp_micropython_mem_info(mp_uint_t n_args, const mp_obj_t *args);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -86,12 +91,6 @@ extern const mp_obj_module_t mp_module_sys;
|
||||
extern const mp_obj_module_t mp_module_gc;
|
||||
|
||||
extern const mp_obj_dict_t mp_module_builtins_globals;
|
||||
extern mp_obj_dict_t *mp_module_builtins_override_dict;
|
||||
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
@@ -101,3 +100,5 @@ extern const mp_obj_module_t mp_module_ure;
|
||||
extern const mp_obj_module_t mp_module_uheapq;
|
||||
extern const mp_obj_module_t mp_module_uhashlib;
|
||||
extern const mp_obj_module_t mp_module_ubinascii;
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_BUILTIN_H__
|
||||
|
||||
@@ -26,20 +26,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "lexerunix.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "objfun.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/objfun.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
|
||||
@@ -84,6 +75,8 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t loc
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
// get the source
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||
|
||||
@@ -25,25 +25,16 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "lexerunix.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "objmodule.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/objmodule.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
#include "py/frozenmod.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -119,9 +110,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
|
||||
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) {
|
||||
|
||||
if (lex == NULL) {
|
||||
// we verified the file exists using stat, but lexer could still fail
|
||||
@@ -129,7 +118,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found"));
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
|
||||
"no module named '%s'", vstr_str(file)));
|
||||
"no module named '%s'", fname));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +132,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
|
||||
}
|
||||
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
|
||||
do_load_from_lexer(module_obj, lex, vstr_str(file));
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
#if DEBUG_PRINT
|
||||
DEBUG_printf("__import__:\n");
|
||||
@@ -213,7 +208,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import"));
|
||||
}
|
||||
|
||||
uint new_mod_l = (mod_len == 0 ? p - this_name : p - this_name + 1 + mod_len);
|
||||
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
|
||||
char *new_mod = alloca(new_mod_l);
|
||||
memcpy(new_mod, this_name, p - this_name);
|
||||
if (mod_len != 0) {
|
||||
@@ -229,7 +224,8 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
|
||||
// check if module already exists
|
||||
mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(module_name));
|
||||
qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
|
||||
mp_obj_t module_obj = mp_module_get(module_name_qstr);
|
||||
if (module_obj != MP_OBJ_NULL) {
|
||||
DEBUG_printf("Module already loaded\n");
|
||||
// If it's not a package, return module right away
|
||||
@@ -247,6 +243,15 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
DEBUG_printf("Module not yet loaded\n");
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len);
|
||||
if (lex != NULL) {
|
||||
module_obj = mp_obj_new_module(module_name_qstr);
|
||||
do_load_from_lexer(module_obj, lex, mod_str);
|
||||
return module_obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint last = 0;
|
||||
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
|
||||
module_obj = MP_OBJ_NULL;
|
||||
@@ -323,7 +328,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
vstr_add_str(&path, "__init__.py");
|
||||
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
|
||||
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
|
||||
printf("Notice: %s is imported as namespace package\n", vstr_str(&path));
|
||||
mp_warning("%s is imported as namespace package", vstr_str(&path));
|
||||
} else {
|
||||
do_load(module_obj, &path);
|
||||
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
|
||||
|
||||
184
py/compile.c
184
py/compile.c
@@ -31,29 +31,22 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "runtime0.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "emit.h"
|
||||
#include "compile.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "smallint.h"
|
||||
#include "py/scope.h"
|
||||
#include "py/emit.h"
|
||||
#include "py/compile.h"
|
||||
#include "py/smallint.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
// TODO need to mangle __attr names
|
||||
|
||||
typedef enum {
|
||||
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
|
||||
#include "grammar.h"
|
||||
#include "py/grammar.h"
|
||||
#undef DEF_RULE
|
||||
PN_maximum_number_of,
|
||||
PN_string, // special node for non-interned string
|
||||
PN_bytes, // special node for non-interned bytes
|
||||
} pn_kind_t;
|
||||
|
||||
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
|
||||
@@ -106,6 +99,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
|
||||
comp->compile_error = exc;
|
||||
}
|
||||
|
||||
#if MICROPY_COMP_MODULE_CONST
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
@@ -113,14 +107,8 @@ STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
// Extra constants as defined by a port
|
||||
MICROPY_PORT_CONSTANTS
|
||||
};
|
||||
|
||||
STATIC const mp_map_t mp_constants_map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.table = (mp_map_elem_t*)mp_constants_table,
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);
|
||||
#endif
|
||||
|
||||
// this function is essentially a simple preprocessor
|
||||
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
|
||||
@@ -185,6 +173,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
break;
|
||||
#endif
|
||||
case PN_string:
|
||||
case PN_bytes:
|
||||
return pn;
|
||||
}
|
||||
|
||||
@@ -227,12 +216,12 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
|
||||
// int << int
|
||||
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
|
||||
if (!(arg1 >= (mp_int_t)BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
|
||||
}
|
||||
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
|
||||
// int >> int
|
||||
if (arg1 >= BITS_PER_WORD) {
|
||||
if (arg1 >= (mp_int_t)BITS_PER_WORD) {
|
||||
// Shifting to big amounts is underfined behavior
|
||||
// in C and is CPU-dependent; propagate sign bit.
|
||||
arg1 = BITS_PER_WORD - 1;
|
||||
@@ -335,6 +324,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_COMP_MODULE_CONST
|
||||
} else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
|
||||
// id.id
|
||||
// look it up in constant table, see if it can be replaced with an integer
|
||||
@@ -348,11 +338,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
mp_load_method_maybe(elem->value, q_attr, dest);
|
||||
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_SMALL_INT_FITS(val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -397,8 +386,8 @@ STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse
|
||||
return scope;
|
||||
}
|
||||
|
||||
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, int pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn) && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn) == pn_list_kind) {
|
||||
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
@@ -409,7 +398,7 @@ STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, int pn
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
|
||||
STATIC int list_get(mp_parse_node_t *pn, pn_kind_t pn_kind, mp_parse_node_t **nodes) {
|
||||
if (MP_PARSE_NODE_IS_NULL(*pn)) {
|
||||
*nodes = NULL;
|
||||
return 0;
|
||||
@@ -440,6 +429,9 @@ STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
return true;
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
|
||||
return true;
|
||||
}
|
||||
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
return false;
|
||||
}
|
||||
@@ -488,9 +480,9 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len,
|
||||
}
|
||||
|
||||
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string) || MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -819,14 +811,14 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
|
||||
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
|
||||
|
||||
// look for star expression
|
||||
int have_star_index = -1;
|
||||
uint have_star_index = -1;
|
||||
if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
|
||||
EMIT_ARG(unpack_ex, 0, num_tail);
|
||||
have_star_index = 0;
|
||||
}
|
||||
for (int i = 0; i < num_tail; i++) {
|
||||
for (uint i = 0; i < num_tail; i++) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
|
||||
if (have_star_index < 0) {
|
||||
if (have_star_index == (uint)-1) {
|
||||
EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
|
||||
have_star_index = num_head + i;
|
||||
} else {
|
||||
@@ -835,7 +827,7 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
|
||||
}
|
||||
}
|
||||
}
|
||||
if (have_star_index < 0) {
|
||||
if (have_star_index == (uint)-1) {
|
||||
EMIT_ARG(unpack_sequence, num_head + num_tail);
|
||||
}
|
||||
if (num_head != 0) {
|
||||
@@ -845,7 +837,7 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
|
||||
c_assign(comp, node_head, ASSIGN_STORE);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_tail; i++) {
|
||||
for (uint i = 0; i < num_tail; i++) {
|
||||
if (num_head + i == have_star_index) {
|
||||
c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE);
|
||||
} else {
|
||||
@@ -868,6 +860,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
EMIT_ARG(store_id, arg);
|
||||
break;
|
||||
case ASSIGN_AUG_LOAD:
|
||||
default:
|
||||
EMIT_ARG(load_id, arg);
|
||||
break;
|
||||
}
|
||||
@@ -988,7 +981,7 @@ STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int
|
||||
EMIT_ARG(load_closure, id->qst, id->local_num);
|
||||
#else
|
||||
// in Micro Python we load closures using LOAD_FAST
|
||||
EMIT_ARG(load_fast, id->qst, id->flags, id->local_num);
|
||||
EMIT_ARG(load_fast, id->qst, id->local_num);
|
||||
#endif
|
||||
nfree += 1;
|
||||
}
|
||||
@@ -1236,9 +1229,9 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
// compile the decorator function
|
||||
compile_node(comp, name_nodes[0]);
|
||||
for (int i = 1; i < name_len; i++) {
|
||||
assert(MP_PARSE_NODE_IS_ID(name_nodes[i])); // should be
|
||||
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[i]));
|
||||
for (int j = 1; j < name_len; j++) {
|
||||
assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be
|
||||
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]));
|
||||
}
|
||||
|
||||
// nodes[1] contains arguments to the decorator function, if any
|
||||
@@ -1995,6 +1988,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
|
||||
// this is a catch all exception handler
|
||||
if (i + 1 != n_except) {
|
||||
compile_syntax_error(comp, pn_excepts[i], "default 'except:' must be last");
|
||||
compile_decrease_except_level(comp);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -2164,7 +2158,8 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
} else {
|
||||
// for non-REPL, evaluate then discard the expression
|
||||
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_bytes)) {
|
||||
// do nothing with a lonely constant
|
||||
} else {
|
||||
compile_node(comp, pns->nodes[0]); // just an expression
|
||||
@@ -2191,8 +2186,7 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break;
|
||||
case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break;
|
||||
case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break;
|
||||
case MP_TOKEN_DEL_DBL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_POWER; break;
|
||||
default: assert(0); op = MP_BINARY_OP_INPLACE_OR; // shouldn't happen
|
||||
case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break;
|
||||
}
|
||||
EMIT_ARG(binary_op, op);
|
||||
c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign
|
||||
@@ -2356,8 +2350,7 @@ STATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break;
|
||||
case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break;
|
||||
case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break;
|
||||
case MP_TOKEN_KW_IN: op = MP_BINARY_OP_IN; break;
|
||||
default: assert(0); op = MP_BINARY_OP_LESS; // shouldn't happen
|
||||
case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break;
|
||||
}
|
||||
EMIT_ARG(binary_op, op);
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])) {
|
||||
@@ -2494,7 +2487,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
|
||||
for (int i = 0; i < comp->scope_cur->id_info_len; i++) {
|
||||
if (comp->scope_cur->id_info[i].flags & ID_FLAG_IS_PARAM) {
|
||||
// first argument found; load it and call super
|
||||
EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].flags, comp->scope_cur->id_info[i].local_num);
|
||||
EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].local_num);
|
||||
EMIT_ARG(call_function, 2, 0, 0);
|
||||
return;
|
||||
}
|
||||
@@ -2608,8 +2601,12 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i]));
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
|
||||
pn_kind = MP_PARSE_NODE_STRING;
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string) {
|
||||
pn_kind = MP_PARSE_NODE_STRING;
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_bytes);
|
||||
pn_kind = MP_PARSE_NODE_BYTES;
|
||||
}
|
||||
n_bytes += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
if (i == 0) {
|
||||
@@ -2620,9 +2617,16 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
}
|
||||
|
||||
// if we are not in the last pass, just load a dummy object
|
||||
if (comp->pass != MP_PASS_EMIT) {
|
||||
EMIT_ARG(load_const_obj, mp_const_none);
|
||||
return;
|
||||
}
|
||||
|
||||
// concatenate string/bytes
|
||||
byte *q_ptr;
|
||||
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, n_bytes);
|
||||
byte *s_dest = (byte*)vstr.buf;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
mp_uint_t s_len;
|
||||
@@ -2635,9 +2639,9 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
s_dest += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
}
|
||||
qstr q = qstr_build_end(q_ptr);
|
||||
|
||||
EMIT_ARG(load_const_str, q, string_kind == MP_PARSE_NODE_BYTES);
|
||||
// load the object
|
||||
EMIT_ARG(load_const_obj, mp_obj_new_str_from_vstr(string_kind == MP_PARSE_NODE_STRING ? &mp_type_str : &mp_type_bytes, &vstr));
|
||||
}
|
||||
|
||||
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
|
||||
@@ -2775,9 +2779,9 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
// process rest of elements
|
||||
for (int i = 0; i < n; i++) {
|
||||
mp_parse_node_t pn = nodes[i];
|
||||
bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dictorsetmaker_item);
|
||||
compile_node(comp, pn);
|
||||
mp_parse_node_t pn_i = nodes[i];
|
||||
bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn_i, PN_dictorsetmaker_item);
|
||||
compile_node(comp, pn_i);
|
||||
if (is_dict) {
|
||||
if (!is_key_value) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dictionary");
|
||||
@@ -2932,15 +2936,36 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void compile_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// only create and load the actual str object on the last pass
|
||||
if (comp->pass != MP_PASS_EMIT) {
|
||||
EMIT_ARG(load_const_obj, mp_const_none);
|
||||
} else {
|
||||
EMIT_ARG(load_const_obj, mp_obj_new_str((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void compile_bytes(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// only create and load the actual bytes object on the last pass
|
||||
if (comp->pass != MP_PASS_EMIT) {
|
||||
EMIT_ARG(load_const_obj, mp_const_none);
|
||||
} else {
|
||||
EMIT_ARG(load_const_obj, mp_obj_new_bytes((const byte*)pns->nodes[0], (mp_uint_t)pns->nodes[1]));
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*);
|
||||
STATIC compile_function_t compile_function[] = {
|
||||
#define nc NULL
|
||||
#define c(f) compile_##f
|
||||
#define DEF_RULE(rule, comp, kind, ...) comp,
|
||||
#include "grammar.h"
|
||||
#include "py/grammar.h"
|
||||
#undef nc
|
||||
#undef c
|
||||
#undef DEF_RULE
|
||||
NULL,
|
||||
compile_string,
|
||||
compile_bytes,
|
||||
};
|
||||
|
||||
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
@@ -2957,7 +2982,7 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
case MP_PARSE_NODE_DECIMAL: EMIT_ARG(load_const_dec, arg); break;
|
||||
case MP_PARSE_NODE_STRING: EMIT_ARG(load_const_str, arg, false); break;
|
||||
case MP_PARSE_NODE_BYTES: EMIT_ARG(load_const_str, arg, true); break;
|
||||
case MP_PARSE_NODE_TOKEN:
|
||||
case MP_PARSE_NODE_TOKEN: default:
|
||||
if (arg == MP_TOKEN_NEWLINE) {
|
||||
// this can occur when file_input lets through a NEWLINE (eg if file starts with a newline)
|
||||
// or when single_input lets through a NEWLINE (user enters a blank line)
|
||||
@@ -2966,24 +2991,19 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
EMIT_ARG(load_const_tok, arg);
|
||||
}
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
EMIT_ARG(set_line_number, pns->source_line);
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
|
||||
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
|
||||
} else {
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
mp_parse_node_print(pn, 0);
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
mp_parse_node_print(pn, 0);
|
||||
#endif
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
} else {
|
||||
f(comp, pns);
|
||||
}
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
} else {
|
||||
f(comp, pns);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3191,6 +3211,9 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
|
||||
EMIT_ARG(store_id, MP_QSTR___doc__);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)comp;
|
||||
(void)pn;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3365,7 +3388,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_closure, MP_QSTR___class__, 0); // XXX check this is the correct local num
|
||||
#else
|
||||
EMIT_ARG(load_fast, MP_QSTR___class__, id->flags, id->local_num);
|
||||
EMIT_ARG(load_fast, MP_QSTR___class__, id->local_num);
|
||||
#endif
|
||||
}
|
||||
EMIT(return_value);
|
||||
@@ -3470,12 +3493,12 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
}
|
||||
if (pass > MP_PASS_SCOPE) {
|
||||
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
|
||||
for (uint j = 1; j < n_args; j++) {
|
||||
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) {
|
||||
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
|
||||
return;
|
||||
}
|
||||
EMIT_INLINE_ASM_ARG(data, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[i]));
|
||||
EMIT_INLINE_ASM_ARG(data, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -3495,7 +3518,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
|
||||
STATIC void scope_compute_things(scope_t *scope) {
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python we put the *x parameter after all other parameters (except **y)
|
||||
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
|
||||
@@ -3659,7 +3682,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
|
||||
// compute some things related to scope and identifiers
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
compile_scope_compute_things(comp, s);
|
||||
scope_compute_things(s);
|
||||
}
|
||||
|
||||
// finish with pass 1
|
||||
@@ -3731,10 +3754,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
#endif
|
||||
comp->emit = emit_native;
|
||||
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0);
|
||||
|
||||
// native emitters need an extra pass to compute stack size
|
||||
compile_scope(comp, s, MP_PASS_STACK_SIZE);
|
||||
|
||||
break;
|
||||
#endif // MICROPY_EMIT_NATIVE
|
||||
|
||||
@@ -3748,6 +3767,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
}
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
// need a pass to compute stack size
|
||||
compile_scope(comp, s, MP_PASS_STACK_SIZE);
|
||||
|
||||
// second last pass: compute code size
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_CODE_SIZE);
|
||||
|
||||
20
py/emit.h
20
py/emit.h
@@ -24,6 +24,13 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_PY_EMIT_H__
|
||||
#define __MICROPY_INCLUDED_PY_EMIT_H__
|
||||
|
||||
#include "py/lexer.h"
|
||||
#include "py/scope.h"
|
||||
#include "py/runtime0.h"
|
||||
|
||||
/* Notes on passes:
|
||||
* We don't know exactly the opcodes in pass 1 because they depend on the
|
||||
* closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which
|
||||
@@ -33,10 +40,6 @@
|
||||
* This is problematic for some emitters (x64) since they need to know the maximum
|
||||
* stack size to compile the entry to the function, and this affects code size.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_EMIT_H__
|
||||
#define __MICROPY_INCLUDED_PY_EMIT_H__
|
||||
|
||||
#include "py/runtime0.h"
|
||||
|
||||
typedef enum {
|
||||
MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels
|
||||
@@ -77,8 +80,9 @@ typedef struct _emit_method_table_t {
|
||||
void (*load_const_int)(emit_t *emit, qstr qst);
|
||||
void (*load_const_dec)(emit_t *emit, qstr qst);
|
||||
void (*load_const_str)(emit_t *emit, qstr qst, bool bytes);
|
||||
void (*load_const_obj)(emit_t *emit, void *obj);
|
||||
void (*load_null)(emit_t *emit);
|
||||
void (*load_fast)(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num);
|
||||
void (*load_fast)(emit_t *emit, qstr qst, mp_uint_t local_num);
|
||||
void (*load_deref)(emit_t *emit, qstr qst, mp_uint_t local_num);
|
||||
void (*load_name)(emit_t *emit, qstr qst);
|
||||
void (*load_global)(emit_t *emit, qstr qst);
|
||||
@@ -204,4 +208,10 @@ extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table;
|
||||
emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels);
|
||||
void emit_inline_thumb_free(emit_inline_asm_t *emit);
|
||||
|
||||
#if MICROPY_WARNINGS
|
||||
void mp_emitter_warning(pass_kind_t pass, const char *msg);
|
||||
#else
|
||||
#define mp_emitter_warning(pass, msg)
|
||||
#endif
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_EMIT_H__
|
||||
|
||||
53
py/emitbc.c
53
py/emitbc.c
@@ -30,17 +30,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "runtime0.h"
|
||||
#include "emit.h"
|
||||
#include "bc0.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/emit.h"
|
||||
#include "py/bc0.h"
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
|
||||
@@ -276,6 +268,10 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, mp_uint
|
||||
}
|
||||
|
||||
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
(void)emit;
|
||||
(void)op;
|
||||
(void)arg1;
|
||||
(void)arg2;
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
@@ -392,7 +388,7 @@ STATIC void emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
|
||||
STATIC void emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
|
||||
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
|
||||
#if MICROPY_ENABLE_SOURCE_LINE
|
||||
if (mp_optimise_value >= 3) {
|
||||
if (MP_STATE_VM(mp_optimise_value) >= 3) {
|
||||
// If we compile with -O3, don't store line numbers.
|
||||
return;
|
||||
}
|
||||
@@ -432,7 +428,7 @@ STATIC void emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(emit->label_offsets[l] == -1);
|
||||
assert(emit->label_offsets[l] == (mp_uint_t)-1);
|
||||
emit->label_offsets[l] = emit->bytecode_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
|
||||
@@ -462,8 +458,9 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
|
||||
case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break;
|
||||
case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
|
||||
no_other_choice:
|
||||
case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_ELLIPSIS); break;
|
||||
default: assert(0);
|
||||
default: assert(0); goto no_other_choice; // to help flow control analysis
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,12 +492,18 @@ STATIC void emit_bc_load_const_str(emit_t *emit, qstr qst, bool bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_obj(emit_t *emit, void *obj) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_ptr(emit, MP_BC_LOAD_CONST_OBJ, obj);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_null(emit_t *emit) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
|
||||
};
|
||||
|
||||
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
|
||||
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, 1);
|
||||
if (local_num <= 15) {
|
||||
@@ -511,23 +514,35 @@ STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uin
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_name(emit_t *emit, qstr qst) {
|
||||
(void)qst;
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
emit_write_bytecode_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_global(emit_t *emit, qstr qst) {
|
||||
(void)qst;
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
emit_write_bytecode_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_attr(emit_t *emit, qstr qst) {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
emit_write_bytecode_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_method(emit_t *emit, qstr qst) {
|
||||
@@ -546,6 +561,7 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
assert(local_num >= 0);
|
||||
emit_bc_pre(emit, -1);
|
||||
if (local_num <= 15) {
|
||||
@@ -556,6 +572,7 @@ STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
emit_bc_pre(emit, -1);
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
|
||||
}
|
||||
@@ -573,6 +590,9 @@ STATIC void emit_bc_store_global(emit_t *emit, qstr qst) {
|
||||
STATIC void emit_bc_store_attr(emit_t *emit, qstr qst) {
|
||||
emit_bc_pre(emit, -2);
|
||||
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
|
||||
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
|
||||
emit_write_bytecode_byte(emit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_store_subscr(emit_t *emit) {
|
||||
@@ -581,10 +601,12 @@ STATIC void emit_bc_store_subscr(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
(void)qst;
|
||||
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
|
||||
}
|
||||
|
||||
@@ -913,6 +935,7 @@ const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_load_const_int,
|
||||
emit_bc_load_const_dec,
|
||||
emit_bc_load_const_str,
|
||||
emit_bc_load_const_obj,
|
||||
emit_bc_load_null,
|
||||
emit_bc_load_fast,
|
||||
emit_bc_load_deref,
|
||||
|
||||
@@ -28,16 +28,7 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "runtime0.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "emit.h"
|
||||
#include "py/emit.h"
|
||||
|
||||
#define EMIT(fun, ...) (emit_method_table->fun(emit, __VA_ARGS__))
|
||||
|
||||
@@ -53,7 +44,7 @@ void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_ta
|
||||
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
|
||||
EMIT(load_global, qst);
|
||||
} else if (id->kind == ID_INFO_KIND_LOCAL) {
|
||||
EMIT(load_fast, qst, id->flags, id->local_num);
|
||||
EMIT(load_fast, qst, id->local_num);
|
||||
} else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
|
||||
EMIT(load_deref, qst, id->local_num);
|
||||
} else {
|
||||
|
||||
23
py/emitcpy.c
23
py/emitcpy.c
@@ -30,16 +30,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "runtime0.h"
|
||||
#include "emit.h"
|
||||
#include "py/emit.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
@@ -240,12 +231,21 @@ STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qst, bool bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_obj(emit_t *emit, void *obj) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
mp_obj_print(obj, PRINT_REPR);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_null(emit_t *emit) {
|
||||
// unused for cpy
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
|
||||
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
@@ -842,6 +842,7 @@ const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_load_const_int,
|
||||
emit_cpy_load_const_dec,
|
||||
emit_cpy_load_const_str,
|
||||
emit_cpy_load_const_obj,
|
||||
emit_cpy_load_null,
|
||||
emit_cpy_load_fast,
|
||||
emit_cpy_load_deref,
|
||||
|
||||
@@ -30,14 +30,9 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "emitglue.h"
|
||||
#include "bc.h"
|
||||
#include "py/emitglue.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/bc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -49,6 +44,23 @@
|
||||
#define DEBUG_OP_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
struct _mp_raw_code_t {
|
||||
mp_raw_code_kind_t kind : 3;
|
||||
mp_uint_t scope_flags : 7;
|
||||
mp_uint_t n_pos_args : 11;
|
||||
mp_uint_t n_kwonly_args : 11;
|
||||
union {
|
||||
struct {
|
||||
byte *code;
|
||||
mp_uint_t len;
|
||||
} u_byte;
|
||||
struct {
|
||||
void *fun_data;
|
||||
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
|
||||
} u_native;
|
||||
} data;
|
||||
};
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
|
||||
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
|
||||
rc->kind = MP_CODE_RESERVED;
|
||||
@@ -60,8 +72,8 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len,
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
rc->n_kwonly_args = n_kwonly_args;
|
||||
rc->u_byte.code = code;
|
||||
rc->u_byte.len = len;
|
||||
rc->data.u_byte.code = code;
|
||||
rc->data.u_byte.len = len;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
|
||||
@@ -79,8 +91,8 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = 0;
|
||||
rc->n_pos_args = n_args;
|
||||
rc->u_native.fun_data = fun_data;
|
||||
rc->u_native.type_sig = type_sig;
|
||||
rc->data.u_native.fun_data = fun_data;
|
||||
rc->data.u_native.type_sig = type_sig;
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
|
||||
@@ -97,6 +109,8 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
||||
fwrite(fun_data, fun_len, 1, fp_write_code);
|
||||
fclose(fp_write_code);
|
||||
#endif
|
||||
#else
|
||||
(void)fun_len;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -115,25 +129,26 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
mp_obj_t fun;
|
||||
switch (rc->kind) {
|
||||
case MP_CODE_BYTECODE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
|
||||
no_other_choice:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->data.u_byte.code);
|
||||
break;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
case MP_CODE_NATIVE_PY:
|
||||
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
|
||||
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->data.u_native.fun_data);
|
||||
break;
|
||||
case MP_CODE_NATIVE_VIPER:
|
||||
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->u_native.type_sig);
|
||||
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);
|
||||
break;
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
case MP_CODE_NATIVE_ASM:
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun_data);
|
||||
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// raw code was never set (this should not happen)
|
||||
assert(0);
|
||||
return mp_const_none;
|
||||
goto no_other_choice; // to help flow control analysis
|
||||
}
|
||||
|
||||
// check for generator functions and if so wrap in generator object
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#ifndef __MICROPY_INCLUDED_PY_EMITGLUE_H__
|
||||
#define __MICROPY_INCLUDED_PY_EMITGLUE_H__
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// These variables and functions glue the code emitters to the runtime.
|
||||
|
||||
typedef enum {
|
||||
@@ -37,22 +39,7 @@ typedef enum {
|
||||
MP_CODE_NATIVE_ASM,
|
||||
} mp_raw_code_kind_t;
|
||||
|
||||
typedef struct _mp_raw_code_t {
|
||||
mp_raw_code_kind_t kind : 3;
|
||||
mp_uint_t scope_flags : 7;
|
||||
mp_uint_t n_pos_args : 11;
|
||||
mp_uint_t n_kwonly_args : 11;
|
||||
union {
|
||||
struct {
|
||||
byte *code;
|
||||
mp_uint_t len;
|
||||
} u_byte;
|
||||
struct {
|
||||
void *fun_data;
|
||||
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
|
||||
} u_native;
|
||||
};
|
||||
} mp_raw_code_t;
|
||||
typedef struct _mp_raw_code_t mp_raw_code_t;
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
|
||||
|
||||
|
||||
@@ -30,23 +30,14 @@
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "runtime0.h"
|
||||
#include "emit.h"
|
||||
#include "asmthumb.h"
|
||||
#include "py/emit.h"
|
||||
#include "py/asmthumb.h"
|
||||
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
|
||||
typedef enum {
|
||||
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
|
||||
#include "grammar.h"
|
||||
#include "py/grammar.h"
|
||||
#undef DEF_RULE
|
||||
PN_maximum_number_of,
|
||||
} pn_kind_t;
|
||||
|
||||
134
py/emitnative.c
134
py/emitnative.c
@@ -42,24 +42,12 @@
|
||||
|
||||
// for x in l[0:8]: can be compiled into a native loop if l has pointer type
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "runtime0.h"
|
||||
#include "emit.h"
|
||||
#include "runtime.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/emit.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -78,7 +66,7 @@
|
||||
|
||||
// x64 specific stuff
|
||||
|
||||
#include "asmx64.h"
|
||||
#include "py/asmx64.h"
|
||||
|
||||
#define EXPORT_FUN(name) emit_native_x64_##name
|
||||
|
||||
@@ -163,7 +151,7 @@
|
||||
|
||||
// x86 specific stuff
|
||||
|
||||
#include "asmx86.h"
|
||||
#include "py/asmx86.h"
|
||||
|
||||
STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
[MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
|
||||
@@ -295,7 +283,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
|
||||
// thumb specific stuff
|
||||
|
||||
#include "asmthumb.h"
|
||||
#include "py/asmthumb.h"
|
||||
|
||||
#define EXPORT_FUN(name) emit_native_thumb_##name
|
||||
|
||||
@@ -378,7 +366,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
|
||||
|
||||
// ARM specific stuff
|
||||
|
||||
#include "asmarm.h"
|
||||
#include "py/asmarm.h"
|
||||
|
||||
#define EXPORT_FUN(name) emit_native_arm_##name
|
||||
|
||||
@@ -492,7 +480,7 @@ typedef struct _stack_info_t {
|
||||
union {
|
||||
int u_reg;
|
||||
mp_int_t u_imm;
|
||||
};
|
||||
} data;
|
||||
} stack_info_t;
|
||||
|
||||
struct _emit_t {
|
||||
@@ -724,7 +712,7 @@ STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
|
||||
DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
|
||||
for (int i = 0; i < emit->stack_size; i++) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->u_reg);
|
||||
DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
@@ -752,6 +740,8 @@ STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {
|
||||
(void)emit;
|
||||
(void)source_line;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -775,7 +765,7 @@ STATIC void emit_native_pre(emit_t *emit) {
|
||||
case STACK_REG:
|
||||
// TODO only push reg if in regs_needed
|
||||
emit->stack_info[i].kind = STACK_VALUE;
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].u_reg, emit->stack_start + i);
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].data.u_reg, emit->stack_start + i);
|
||||
break;
|
||||
|
||||
case STACK_IMM:
|
||||
@@ -805,9 +795,9 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
|
||||
for (int i = 0; i < emit->stack_size; i++) {
|
||||
if (i != skip_stack_pos) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
if (si->kind == STACK_REG && si->u_reg == reg_needed) {
|
||||
if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {
|
||||
si->kind = STACK_VALUE;
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -818,7 +808,7 @@ STATIC void need_reg_all(emit_t *emit) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
if (si->kind == STACK_REG) {
|
||||
si->kind = STACK_VALUE;
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -828,17 +818,17 @@ STATIC void need_stack_settled(emit_t *emit) {
|
||||
for (int i = 0; i < emit->stack_size; i++) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
if (si->kind == STACK_REG) {
|
||||
DEBUG_printf(" reg(%u) to local(%u)\n", si->u_reg, emit->stack_start + i);
|
||||
DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
|
||||
si->kind = STACK_VALUE;
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
|
||||
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < emit->stack_size; i++) {
|
||||
stack_info_t *si = &emit->stack_info[i];
|
||||
if (si->kind == STACK_IMM) {
|
||||
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->u_imm, emit->stack_start + i);
|
||||
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
|
||||
si->kind = STACK_VALUE;
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + i, REG_TEMP0);
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -854,13 +844,13 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re
|
||||
break;
|
||||
|
||||
case STACK_REG:
|
||||
if (si->u_reg != reg_dest) {
|
||||
ASM_MOV_REG_REG(emit->as, reg_dest, si->u_reg);
|
||||
if (si->data.u_reg != reg_dest) {
|
||||
ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg);
|
||||
}
|
||||
break;
|
||||
|
||||
case STACK_IMM:
|
||||
ASM_MOV_IMM_TO_REG(emit->as, si->u_imm, reg_dest);
|
||||
ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -874,7 +864,7 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
|
||||
// if folded element was on the stack we need to put it in a register
|
||||
ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest);
|
||||
si->kind = STACK_REG;
|
||||
si->u_reg = reg_dest;
|
||||
si->data.u_reg = reg_dest;
|
||||
}
|
||||
adjust_stack(emit, -1);
|
||||
}
|
||||
@@ -884,9 +874,9 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
|
||||
STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) {
|
||||
emit->last_emit_was_return_value = false;
|
||||
stack_info_t *si = peek_stack(emit, 0);
|
||||
if (si->kind == STACK_REG && si->u_reg != not_r1 && si->u_reg != not_r2) {
|
||||
if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) {
|
||||
*vtype = si->vtype;
|
||||
*reg_dest = si->u_reg;
|
||||
*reg_dest = si->data.u_reg;
|
||||
need_reg_single(emit, *reg_dest, 1);
|
||||
} else {
|
||||
emit_access_stack(emit, 1, vtype, *reg_dest);
|
||||
@@ -917,6 +907,7 @@ STATIC void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int reg
|
||||
}
|
||||
|
||||
STATIC void emit_post(emit_t *emit) {
|
||||
(void)emit;
|
||||
}
|
||||
|
||||
STATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) {
|
||||
@@ -928,7 +919,7 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
|
||||
stack_info_t *si = &emit->stack_info[emit->stack_size];
|
||||
si->vtype = vtype;
|
||||
si->kind = STACK_REG;
|
||||
si->u_reg = reg;
|
||||
si->data.u_reg = reg;
|
||||
adjust_stack(emit, 1);
|
||||
}
|
||||
|
||||
@@ -936,7 +927,7 @@ STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
|
||||
stack_info_t *si = &emit->stack_info[emit->stack_size];
|
||||
si->vtype = vtype;
|
||||
si->kind = STACK_IMM;
|
||||
si->u_imm = imm;
|
||||
si->data.u_imm = imm;
|
||||
adjust_stack(emit, 1);
|
||||
}
|
||||
|
||||
@@ -1008,10 +999,10 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
|
||||
si->kind = STACK_VALUE;
|
||||
switch (si->vtype) {
|
||||
case VTYPE_PYOBJ:
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
break;
|
||||
case VTYPE_BOOL:
|
||||
if (si->u_imm == 0) {
|
||||
if (si->data.u_imm == 0) {
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
} else {
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
@@ -1020,7 +1011,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
|
||||
break;
|
||||
case VTYPE_INT:
|
||||
case VTYPE_UINT:
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->data.u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
|
||||
si->vtype = VTYPE_PYOBJ;
|
||||
break;
|
||||
default:
|
||||
@@ -1184,13 +1175,20 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst, bool bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_const_obj(emit_t *emit, void *obj) {
|
||||
emit_native_pre(emit);
|
||||
need_reg_single(emit, REG_RET, 0);
|
||||
ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_null(emit_t *emit) {
|
||||
emit_native_pre(emit);
|
||||
emit_post_push_imm(emit, VTYPE_PYOBJ, 0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
|
||||
DEBUG_printf("load_fast(%s, " UINT_FMT ", " UINT_FMT ")\n", qstr_str(qst), id_flags, local_num);
|
||||
STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
|
||||
vtype_kind_t vtype = emit->local_vtype[local_num];
|
||||
if (vtype == VTYPE_UNBOUND) {
|
||||
printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
|
||||
@@ -1252,6 +1250,9 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp
|
||||
STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
// not implemented
|
||||
// in principle could support this quite easily (ldr r0, [r0, #0]) and then get closed over variables!
|
||||
(void)emit;
|
||||
(void)qst;
|
||||
(void)local_num;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -1331,7 +1332,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
|
||||
stack_info_t *top = peek_stack(emit, 0);
|
||||
if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
|
||||
// index is an immediate
|
||||
mp_int_t index_value = top->u_imm;
|
||||
mp_int_t index_value = top->data.u_imm;
|
||||
emit_pre_pop_discard(emit); // discard index
|
||||
int reg_base = REG_ARG_1;
|
||||
int reg_index = REG_ARG_2;
|
||||
@@ -1470,6 +1471,9 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num)
|
||||
|
||||
STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
// not implemented
|
||||
(void)emit;
|
||||
(void)qst;
|
||||
(void)local_num;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -1527,7 +1531,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
stack_info_t *top = peek_stack(emit, 0);
|
||||
if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
|
||||
// index is an immediate
|
||||
mp_int_t index_value = top->u_imm;
|
||||
mp_int_t index_value = top->data.u_imm;
|
||||
emit_pre_pop_discard(emit); // discard index
|
||||
vtype_kind_t vtype_value;
|
||||
int reg_base = REG_ARG_1;
|
||||
@@ -1636,10 +1640,19 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
||||
STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
// TODO implement me!
|
||||
// could support for Python types, just set to None (so GC can reclaim it)
|
||||
// local is automatically deleted for exception block "as" var, and the message
|
||||
// breaks tests.
|
||||
//mp_emitter_warning(emit->pass, "Native codegeneration doesn't support deleting local");
|
||||
(void)emit;
|
||||
(void)qst;
|
||||
(void)local_num;
|
||||
}
|
||||
|
||||
STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
// TODO implement me!
|
||||
(void)emit;
|
||||
(void)qst;
|
||||
(void)local_num;
|
||||
}
|
||||
|
||||
STATIC void emit_native_delete_name(emit_t *emit, qstr qst) {
|
||||
@@ -1713,7 +1726,7 @@ STATIC void emit_native_jump(emit_t *emit, mp_uint_t label) {
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_jump_helper(emit_t *emit, mp_uint_t label, bool pop) {
|
||||
STATIC void emit_native_jump_helper(emit_t *emit, bool pop) {
|
||||
vtype_kind_t vtype = peek_vtype(emit, 0);
|
||||
switch (vtype) {
|
||||
case VTYPE_PYOBJ:
|
||||
@@ -1746,21 +1759,21 @@ STATIC void emit_native_jump_helper(emit_t *emit, mp_uint_t label, bool pop) {
|
||||
|
||||
STATIC void emit_native_pop_jump_if_true(emit_t *emit, mp_uint_t label) {
|
||||
DEBUG_printf("pop_jump_if_true(label=" UINT_FMT ")\n", label);
|
||||
emit_native_jump_helper(emit, label, true);
|
||||
emit_native_jump_helper(emit, true);
|
||||
ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_pop_jump_if_false(emit_t *emit, mp_uint_t label) {
|
||||
DEBUG_printf("pop_jump_if_false(label=" UINT_FMT ")\n", label);
|
||||
emit_native_jump_helper(emit, label, true);
|
||||
emit_native_jump_helper(emit, true);
|
||||
ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
|
||||
DEBUG_printf("jump_if_true_or_pop(label=" UINT_FMT ")\n", label);
|
||||
emit_native_jump_helper(emit, label, false);
|
||||
emit_native_jump_helper(emit, false);
|
||||
ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
|
||||
adjust_stack(emit, -1);
|
||||
emit_post(emit);
|
||||
@@ -1768,26 +1781,31 @@ STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
|
||||
|
||||
STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, mp_uint_t label) {
|
||||
DEBUG_printf("jump_if_false_or_pop(label=" UINT_FMT ")\n", label);
|
||||
emit_native_jump_helper(emit, label, false);
|
||||
emit_native_jump_helper(emit, false);
|
||||
ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
|
||||
adjust_stack(emit, -1);
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
|
||||
(void)except_depth;
|
||||
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
|
||||
}
|
||||
|
||||
STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
|
||||
(void)except_depth;
|
||||
emit_native_jump(emit, label); // TODO properly
|
||||
}
|
||||
|
||||
STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
|
||||
// not supported, or could be with runtime call
|
||||
(void)emit;
|
||||
(void)label;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_native_with_cleanup(emit_t *emit) {
|
||||
(void)emit;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -1806,7 +1824,14 @@ STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_end_finally(emit_t *emit) {
|
||||
emit_pre_pop_discard(emit);
|
||||
// logic:
|
||||
// exc = pop_stack
|
||||
// if exc == None: pass
|
||||
// else: raise exc
|
||||
// the check if exc is None is done in the MP_F_NATIVE_RAISE stub
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
|
||||
emit_call(emit, MP_F_NATIVE_RAISE);
|
||||
emit_post(emit);
|
||||
}
|
||||
|
||||
@@ -1847,6 +1872,7 @@ STATIC void emit_native_pop_block(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_native_pop_except(emit_t *emit) {
|
||||
(void)emit;
|
||||
/*
|
||||
emit_native_pre(emit);
|
||||
emit_call(emit, MP_F_NLR_POP);
|
||||
@@ -2141,6 +2167,11 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_
|
||||
}
|
||||
|
||||
STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
(void)emit;
|
||||
(void)scope;
|
||||
(void)n_closed_over;
|
||||
(void)n_pos_defaults;
|
||||
(void)n_kw_defaults;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -2158,7 +2189,7 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u
|
||||
// casting operator
|
||||
assert(n_positional == 1 && n_keyword == 0);
|
||||
DEBUG_printf(" cast to %d\n", vtype_fun);
|
||||
vtype_kind_t vtype_cast = peek_stack(emit, 1)->u_imm;
|
||||
vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm;
|
||||
switch (peek_vtype(emit, 0)) {
|
||||
case VTYPE_PYOBJ: {
|
||||
vtype_kind_t vtype;
|
||||
@@ -2240,10 +2271,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
|
||||
|
||||
STATIC void emit_native_yield_value(emit_t *emit) {
|
||||
// not supported (for now)
|
||||
(void)emit;
|
||||
assert(0);
|
||||
}
|
||||
STATIC void emit_native_yield_from(emit_t *emit) {
|
||||
// not supported (for now)
|
||||
(void)emit;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -2283,6 +2316,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
|
||||
emit_native_load_const_int,
|
||||
emit_native_load_const_dec,
|
||||
emit_native_load_const_str,
|
||||
emit_native_load_const_obj,
|
||||
emit_native_load_null,
|
||||
emit_native_load_fast,
|
||||
emit_native_load_deref,
|
||||
|
||||
@@ -24,20 +24,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "emitglue.h"
|
||||
#include "scope.h"
|
||||
#include "runtime0.h"
|
||||
#include "emit.h"
|
||||
#include "py/emit.h"
|
||||
|
||||
struct _emit_t {
|
||||
scope_t *scope;
|
||||
@@ -53,6 +42,7 @@ void emit_pass1_free(emit_t *emit) {
|
||||
}
|
||||
|
||||
STATIC void emit_pass1_dummy(emit_t *emit) {
|
||||
(void)emit;
|
||||
}
|
||||
|
||||
STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
@@ -61,9 +51,11 @@ STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope
|
||||
}
|
||||
|
||||
STATIC void emit_pass1_end_pass(emit_t *emit) {
|
||||
(void)emit;
|
||||
}
|
||||
|
||||
STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
|
||||
(void)emit;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,6 +193,7 @@ const emit_method_table_t emit_pass1_method_table = {
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
@@ -42,10 +42,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#include "formatfloat.h"
|
||||
|
||||
#include "py/formatfloat.h"
|
||||
|
||||
// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
|
||||
// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
|
||||
@@ -63,7 +64,7 @@ static const float g_neg_pow[] = {
|
||||
1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
|
||||
};
|
||||
|
||||
int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
|
||||
int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
|
||||
|
||||
char *s = buf;
|
||||
int buf_remaining = buf_size - 1;
|
||||
|
||||
@@ -23,5 +23,9 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_FORMATFLOAT_H__
|
||||
#define __MICROPY_INCLUDED_PY_FORMATFLOAT_H__
|
||||
|
||||
int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
|
||||
int mp_format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_FORMATFLOAT_H__
|
||||
|
||||
53
py/frozenmod.c
Normal file
53
py/frozenmod.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/lexer.h"
|
||||
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
|
||||
extern const uint16_t mp_frozen_sizes[];
|
||||
extern const char mp_frozen_content[];
|
||||
|
||||
mp_lexer_t *mp_find_frozen_module(const char *str, int len) {
|
||||
const uint16_t *sz_ptr = mp_frozen_sizes;
|
||||
const char *s = mp_frozen_content;
|
||||
|
||||
while (*sz_ptr) {
|
||||
int l = strlen(s);
|
||||
if (l == len && !memcmp(str, s, l)) {
|
||||
s += l + 1;
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR_, s, *sz_ptr, 0);
|
||||
return lex;
|
||||
}
|
||||
s += l + 1 + *sz_ptr++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // MICROPY_MODULE_FROZEN
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,4 +24,4 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items);
|
||||
mp_lexer_t *mp_find_frozen_module(const char *str, int len);
|
||||
203
py/gc.c
203
py/gc.c
@@ -27,16 +27,11 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
|
||||
@@ -53,26 +48,6 @@
|
||||
|
||||
#define WORDS_PER_BLOCK (4)
|
||||
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
|
||||
#define STACK_SIZE (64) // tunable; minimum is 1
|
||||
|
||||
STATIC byte *gc_alloc_table_start;
|
||||
STATIC mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
STATIC byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
// We initialise gc_pool_start to a dummy value so it stays out of the bss
|
||||
// section. This makes sure we don't trace this pointer in a collect cycle.
|
||||
// If we did trace it, it would make the first block of the heap always
|
||||
// reachable, and hence we can never free that block.
|
||||
STATIC mp_uint_t *gc_pool_start = (void*)4;
|
||||
STATIC mp_uint_t *gc_pool_end;
|
||||
|
||||
STATIC int gc_stack_overflow;
|
||||
STATIC mp_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC mp_uint_t *gc_sp;
|
||||
STATIC uint16_t gc_lock_depth;
|
||||
uint16_t gc_auto_collect_enabled;
|
||||
STATIC mp_uint_t gc_last_free_atb_index;
|
||||
|
||||
// ATB = allocation table byte
|
||||
// 0b00 = FREE -- free block
|
||||
@@ -97,15 +72,15 @@ STATIC mp_uint_t gc_last_free_atb_index;
|
||||
#define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0)
|
||||
|
||||
#define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1)))
|
||||
#define ATB_GET_KIND(block) ((gc_alloc_table_start[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)
|
||||
#define ATB_ANY_TO_FREE(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0)
|
||||
#define ATB_FREE_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_FREE_TO_TAIL(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
|
||||
#define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)
|
||||
#define ATB_ANY_TO_FREE(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0)
|
||||
#define ATB_FREE_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_FREE_TO_TAIL(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
|
||||
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)MP_STATE_MEM(gc_pool_start)))
|
||||
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -114,9 +89,9 @@ STATIC mp_uint_t gc_last_free_atb_index;
|
||||
|
||||
#define BLOCKS_PER_FTB (8)
|
||||
|
||||
#define FTB_GET(block) ((gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
|
||||
#define FTB_SET(block) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
|
||||
#define FTB_CLEAR(block) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
|
||||
#define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
|
||||
#define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
|
||||
#define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
|
||||
#endif
|
||||
|
||||
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
|
||||
@@ -132,67 +107,67 @@ void gc_init(void *start, void *end) {
|
||||
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
|
||||
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
|
||||
MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
|
||||
#else
|
||||
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
|
||||
MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
|
||||
#endif
|
||||
|
||||
gc_alloc_table_start = (byte*)start;
|
||||
MP_STATE_MEM(gc_alloc_table_start) = (byte*)start;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
|
||||
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
|
||||
mp_uint_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
|
||||
MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len);
|
||||
#endif
|
||||
|
||||
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
|
||||
gc_pool_end = (mp_uint_t*)end;
|
||||
mp_uint_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
|
||||
MP_STATE_MEM(gc_pool_start) = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
|
||||
MP_STATE_MEM(gc_pool_end) = (mp_uint_t*)end;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
|
||||
assert((byte*)MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// clear ATBs
|
||||
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
|
||||
memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len));
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
// clear FTBs
|
||||
memset(gc_finaliser_table_start, 0, gc_finaliser_table_byte_len);
|
||||
memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// set last free ATB index to start of heap
|
||||
gc_last_free_atb_index = 0;
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = 0;
|
||||
|
||||
// unlock the GC
|
||||
gc_lock_depth = 0;
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
|
||||
// allow auto collection
|
||||
gc_auto_collect_enabled = 1;
|
||||
MP_STATE_MEM(gc_auto_collect_enabled) = 1;
|
||||
|
||||
DEBUG_printf("GC layout:\n");
|
||||
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_alloc_table_start, gc_alloc_table_byte_len, gc_alloc_table_byte_len * BLOCKS_PER_ATB);
|
||||
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_finaliser_table_start, gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
|
||||
DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
|
||||
#endif
|
||||
DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_pool_start, gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
|
||||
DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
|
||||
}
|
||||
|
||||
void gc_lock(void) {
|
||||
gc_lock_depth++;
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
}
|
||||
|
||||
void gc_unlock(void) {
|
||||
gc_lock_depth--;
|
||||
MP_STATE_MEM(gc_lock_depth)--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return gc_lock_depth != 0;
|
||||
return MP_STATE_MEM(gc_lock_depth) != 0;
|
||||
}
|
||||
|
||||
#define VERIFY_PTR(ptr) ( \
|
||||
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
||||
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
&& ptr >= (mp_uint_t)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \
|
||||
&& ptr < (mp_uint_t)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
|
||||
)
|
||||
|
||||
#define VERIFY_MARK_AND_PUSH(ptr) \
|
||||
@@ -202,19 +177,19 @@ bool gc_is_locked(void) {
|
||||
if (ATB_GET_KIND(_block) == AT_HEAD) { \
|
||||
/* an unmarked head, mark it, and push it on gc stack */ \
|
||||
ATB_HEAD_TO_MARK(_block); \
|
||||
if (gc_sp < &gc_stack[STACK_SIZE]) { \
|
||||
*gc_sp++ = _block; \
|
||||
if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \
|
||||
*MP_STATE_MEM(gc_sp)++ = _block; \
|
||||
} else { \
|
||||
gc_stack_overflow = 1; \
|
||||
MP_STATE_MEM(gc_stack_overflow) = 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
STATIC void gc_drain_stack(void) {
|
||||
while (gc_sp > gc_stack) {
|
||||
while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) {
|
||||
// pop the next block off the stack
|
||||
mp_uint_t block = *--gc_sp;
|
||||
mp_uint_t block = *--MP_STATE_MEM(gc_sp);
|
||||
|
||||
// work out number of consecutive blocks in the chain starting with this one
|
||||
mp_uint_t n_blocks = 0;
|
||||
@@ -232,15 +207,15 @@ STATIC void gc_drain_stack(void) {
|
||||
}
|
||||
|
||||
STATIC void gc_deal_with_stack_overflow(void) {
|
||||
while (gc_stack_overflow) {
|
||||
gc_stack_overflow = 0;
|
||||
gc_sp = gc_stack;
|
||||
while (MP_STATE_MEM(gc_stack_overflow)) {
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
|
||||
|
||||
// scan entire memory looking for blocks which have been marked but not their children
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
|
||||
// trace (again) if mark bit set
|
||||
if (ATB_GET_KIND(block) == AT_MARK) {
|
||||
*gc_sp++ = block;
|
||||
*MP_STATE_MEM(gc_sp)++ = block;
|
||||
gc_drain_stack();
|
||||
}
|
||||
}
|
||||
@@ -257,7 +232,7 @@ STATIC void gc_sweep(void) {
|
||||
#endif
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
|
||||
switch (ATB_GET_KIND(block)) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -299,8 +274,13 @@ STATIC void gc_sweep(void) {
|
||||
|
||||
void gc_collect_start(void) {
|
||||
gc_lock();
|
||||
gc_stack_overflow = 0;
|
||||
gc_sp = gc_stack;
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
|
||||
// Trace root pointers. This relies on the root pointers being organised
|
||||
// correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
|
||||
// dict_globals, then the root pointer section of mp_state_vm.
|
||||
void **ptrs = (void**)(void*)&mp_state_ctx;
|
||||
gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t));
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len) {
|
||||
@@ -314,18 +294,18 @@ void gc_collect_root(void **ptrs, mp_uint_t len) {
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep();
|
||||
gc_last_free_atb_index = 0;
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = 0;
|
||||
gc_unlock();
|
||||
}
|
||||
|
||||
void gc_info(gc_info_t *info) {
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
|
||||
info->total = (MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start)) * sizeof(mp_uint_t);
|
||||
info->used = 0;
|
||||
info->free = 0;
|
||||
info->num_1block = 0;
|
||||
info->num_2block = 0;
|
||||
info->max_block = 0;
|
||||
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0, len = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
|
||||
mp_uint_t kind = ATB_GET_KIND(block);
|
||||
if (kind == AT_FREE || kind == AT_HEAD) {
|
||||
if (len == 1) {
|
||||
@@ -368,7 +348,7 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
|
||||
|
||||
// check if GC is locked
|
||||
if (gc_lock_depth > 0) {
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -381,12 +361,12 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||
mp_uint_t end_block;
|
||||
mp_uint_t start_block;
|
||||
mp_uint_t n_free = 0;
|
||||
int collected = !gc_auto_collect_enabled;
|
||||
int collected = !MP_STATE_MEM(gc_auto_collect_enabled);
|
||||
for (;;) {
|
||||
|
||||
// look for a run of n_blocks available blocks
|
||||
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
|
||||
byte a = gc_alloc_table_start[i];
|
||||
for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {
|
||||
byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
|
||||
if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
|
||||
if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
|
||||
if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
|
||||
@@ -414,7 +394,7 @@ found:
|
||||
// before this one. Also, whenever we free or shink a block we must check
|
||||
// if this index needs adjusting (see gc_realloc and gc_free).
|
||||
if (n_free == 1) {
|
||||
gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// mark first block as used head
|
||||
@@ -427,7 +407,7 @@ found:
|
||||
}
|
||||
|
||||
// get pointer to first block
|
||||
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
|
||||
void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * WORDS_PER_BLOCK);
|
||||
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks
|
||||
@@ -465,7 +445,7 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
||||
|
||||
// force the freeing of a piece of memory
|
||||
void gc_free(void *ptr_in) {
|
||||
if (gc_lock_depth > 0) {
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
// TODO how to deal with this error?
|
||||
return;
|
||||
}
|
||||
@@ -477,8 +457,8 @@ void gc_free(void *ptr_in) {
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// set the last_free pointer to this block if it's earlier in the heap
|
||||
if (block / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = block / BLOCKS_PER_ATB;
|
||||
if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
// free head and all of its tail blocks
|
||||
@@ -547,7 +527,7 @@ void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
|
||||
#else // Alternative gc_realloc impl
|
||||
|
||||
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
if (gc_lock_depth > 0) {
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -588,7 +568,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
// efficiently shrink it (see below for shrinking code).
|
||||
mp_uint_t n_free = 0;
|
||||
mp_uint_t n_blocks = 1; // counting HEAD block
|
||||
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
mp_uint_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
|
||||
for (mp_uint_t bl = block + n_blocks; bl < max_block; bl++) {
|
||||
byte block_type = ATB_GET_KIND(bl);
|
||||
if (block_type == AT_TAIL) {
|
||||
@@ -619,8 +599,8 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// set the last_free pointer to end of this block if it's earlier in the heap
|
||||
if ((block + new_blocks) / BLOCKS_PER_ATB < gc_last_free_atb_index) {
|
||||
gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
|
||||
if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
|
||||
}
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
@@ -669,7 +649,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
}
|
||||
#endif // Alternative gc_realloc impl
|
||||
|
||||
void gc_dump_info() {
|
||||
void gc_dump_info(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
printf("GC: total: " UINT_FMT ", used: " UINT_FMT ", free: " UINT_FMT "\n", info.total, info.used, info.free);
|
||||
@@ -682,22 +662,22 @@ void gc_dump_alloc_table(void) {
|
||||
#if !EXTENSIVE_HEAP_PROFILING
|
||||
// When comparing heap output we don't want to print the starting
|
||||
// pointer of the heap because it changes from run to run.
|
||||
printf("GC memory layout; from %p:", gc_pool_start);
|
||||
printf("GC memory layout; from %p:", MP_STATE_MEM(gc_pool_start));
|
||||
#endif
|
||||
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
for (mp_uint_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % DUMP_BYTES_PER_LINE == 0) {
|
||||
// a new line of blocks
|
||||
{
|
||||
// check if this line contains only free blocks
|
||||
mp_uint_t bl2 = bl;
|
||||
while (bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
|
||||
while (bl2 < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
|
||||
bl2++;
|
||||
}
|
||||
if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {
|
||||
// there are at least 2 lines containing only free blocks, so abbreviate their printing
|
||||
printf("\n (" UINT_FMT " lines all free)", (bl2 - bl) / DUMP_BYTES_PER_LINE);
|
||||
bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));
|
||||
if (bl >= gc_alloc_table_byte_len * BLOCKS_PER_ATB) {
|
||||
if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) {
|
||||
// got to end of heap
|
||||
break;
|
||||
}
|
||||
@@ -715,11 +695,9 @@ void gc_dump_alloc_table(void) {
|
||||
case AT_FREE: c = '.'; break;
|
||||
/* this prints out if the object is reachable from BSS or STACK (for unix only)
|
||||
case AT_HEAD: {
|
||||
extern char __bss_start, _end;
|
||||
extern char *stack_top;
|
||||
c = 'h';
|
||||
void **ptrs = (void**)&__bss_start;
|
||||
mp_uint_t len = ((mp_uint_t)&_end - (mp_uint_t)&__bss_start) / sizeof(mp_uint_t);
|
||||
void **ptrs = (void**)(void*)&mp_state_ctx;
|
||||
mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
|
||||
@@ -729,7 +707,7 @@ void gc_dump_alloc_table(void) {
|
||||
}
|
||||
if (c == 'h') {
|
||||
ptrs = (void**)&c;
|
||||
len = ((mp_uint_t)stack_top - (mp_uint_t)&c) / sizeof(mp_uint_t);
|
||||
len = ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
|
||||
@@ -743,7 +721,7 @@ void gc_dump_alloc_table(void) {
|
||||
*/
|
||||
/* this prints the uPy object type of the head block */
|
||||
case AT_HEAD: {
|
||||
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
mp_uint_t *ptr = MP_STATE_MEM(gc_pool_start) + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
@@ -752,7 +730,26 @@ void gc_dump_alloc_table(void) {
|
||||
#endif
|
||||
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_module) { c = 'M'; }
|
||||
else { c = 'h'; }
|
||||
else {
|
||||
c = 'h';
|
||||
#if 0
|
||||
// This code prints "Q" for qstr-pool data, and "q" for qstr-str
|
||||
// data. It can be useful to see how qstrs are being allocated,
|
||||
// but is disabled by default because it is very slow.
|
||||
for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) {
|
||||
if ((qstr_pool_t*)ptr == pool) {
|
||||
c = 'Q';
|
||||
break;
|
||||
}
|
||||
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
|
||||
if ((const byte*)ptr == *q) {
|
||||
c = 'q';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AT_TAIL: c = 't'; break;
|
||||
|
||||
14
py/gc.h
14
py/gc.h
@@ -23,6 +23,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_GC_H__
|
||||
#define __MICROPY_INCLUDED_PY_GC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
void gc_init(void *start, void *end);
|
||||
|
||||
@@ -32,11 +39,6 @@ void gc_lock(void);
|
||||
void gc_unlock(void);
|
||||
bool gc_is_locked(void);
|
||||
|
||||
// This variable controls auto garbage collection. If set to 0 then the
|
||||
// GC won't automatically run when gc_alloc can't find enough blocks. But
|
||||
// you can still allocate/free memory and also explicitly call gc_collect.
|
||||
extern uint16_t gc_auto_collect_enabled;
|
||||
|
||||
// A given port must implement gc_collect by using the other collect functions.
|
||||
void gc_collect(void);
|
||||
void gc_collect_start(void);
|
||||
@@ -60,3 +62,5 @@ typedef struct _gc_info_t {
|
||||
void gc_info(gc_info_t *info);
|
||||
void gc_dump_info(void);
|
||||
void gc_dump_alloc_table(void);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_GC_H__
|
||||
|
||||
17
py/lexer.c
17
py/lexer.c
@@ -24,26 +24,17 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* lexer.c -- simple tokeniser for Python implementation
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/lexer.h"
|
||||
|
||||
#define TAB_SIZE (8)
|
||||
|
||||
// TODO seems that CPython allows NULL byte in the input stream
|
||||
// don't know if that's intentional or not, but we don't allow it
|
||||
|
||||
mp_uint_t mp_optimise_value;
|
||||
|
||||
// TODO replace with a call to a standard function
|
||||
STATIC bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
|
||||
mp_uint_t i = 0;
|
||||
@@ -666,11 +657,11 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) {
|
||||
// need to check for this special token in many places in the compiler.
|
||||
// TODO improve speed of these string comparisons
|
||||
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
|
||||
if (str_strn_equal(tok_kw[i], lex->vstr.buf, lex->vstr.len)) {
|
||||
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__"
|
||||
lex->tok_kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
|
||||
lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
|
||||
} else {
|
||||
lex->tok_kind = MP_TOKEN_KW_FALSE + i;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
#ifndef __MICROPY_INCLUDED_PY_LEXER_H__
|
||||
#define __MICROPY_INCLUDED_PY_LEXER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/qstr.h"
|
||||
|
||||
/* lexer.h -- simple tokeniser for Micro Python
|
||||
*
|
||||
* Uses (byte) length instead of null termination.
|
||||
@@ -187,6 +192,4 @@ typedef enum {
|
||||
mp_import_stat_t mp_import_stat(const char *path);
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
|
||||
extern mp_uint_t mp_optimise_value;
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_LEXER_H__
|
||||
|
||||
@@ -24,12 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "py/lexer.h"
|
||||
|
||||
typedef struct _mp_lexer_str_buf_t {
|
||||
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
#if MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -36,9 +35,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "lexerunix.h"
|
||||
#include "py/lexer.h"
|
||||
|
||||
typedef struct _mp_lexer_file_buf_t {
|
||||
int fd;
|
||||
|
||||
@@ -13,14 +13,22 @@ elif platform.python_version_tuple()[0] == '3':
|
||||
codepoint2name[ord('-')] = 'hyphen';
|
||||
|
||||
# add some custom names to map characters that aren't in HTML
|
||||
codepoint2name[ord(' ')] = 'space'
|
||||
codepoint2name[ord('\'')] = 'squot'
|
||||
codepoint2name[ord(',')] = 'comma'
|
||||
codepoint2name[ord('.')] = 'dot'
|
||||
codepoint2name[ord(':')] = 'colon'
|
||||
codepoint2name[ord('/')] = 'slash'
|
||||
codepoint2name[ord('%')] = 'percent'
|
||||
codepoint2name[ord('#')] = 'hash'
|
||||
codepoint2name[ord('(')] = 'paren_open'
|
||||
codepoint2name[ord(')')] = 'paren_close'
|
||||
codepoint2name[ord('[')] = 'bracket_open'
|
||||
codepoint2name[ord(']')] = 'bracket_close'
|
||||
codepoint2name[ord('{')] = 'brace_open'
|
||||
codepoint2name[ord('}')] = 'brace_close'
|
||||
codepoint2name[ord('*')] = 'star'
|
||||
codepoint2name[ord('!')] = 'bang'
|
||||
|
||||
# this must match the equivalent function in qstr.c
|
||||
def compute_hash(qstr):
|
||||
@@ -32,12 +40,25 @@ def compute_hash(qstr):
|
||||
|
||||
def do_work(infiles):
|
||||
# read the qstrs in from the input files
|
||||
qcfgs = {}
|
||||
qstrs = {}
|
||||
for infile in infiles:
|
||||
with open(infile, 'rt') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
|
||||
# is this a config line?
|
||||
match = re.match(r'^QCFG\((.+), (.+)\)', line)
|
||||
if match:
|
||||
value = match.group(2)
|
||||
if value[0] == '(' and value[-1] == ')':
|
||||
# strip parenthesis from config value
|
||||
value = value[1:-1]
|
||||
qcfgs[match.group(1)] = value
|
||||
continue
|
||||
|
||||
# is this a QSTR line?
|
||||
match = re.match(r'^Q\((.+)\)$', line.strip())
|
||||
match = re.match(r'^Q\((.*)\)$', line)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
@@ -52,13 +73,27 @@ def do_work(infiles):
|
||||
# add the qstr to the list, with order number to retain original order in file
|
||||
qstrs[ident] = (len(qstrs), ident, qstr)
|
||||
|
||||
# process the qstrs, printing out the generated C header file
|
||||
# get config variables
|
||||
cfg_bytes_len = int(qcfgs['BYTES_IN_LEN'])
|
||||
cfg_max_len = 1 << (8 * cfg_bytes_len)
|
||||
|
||||
# print out the starte of the generated C header file
|
||||
print('// This file was automatically generated by makeqstrdata.py')
|
||||
print('')
|
||||
|
||||
# add NULL qstr with no hash or data
|
||||
print('QDEF(MP_QSTR_NULL, (const byte*)"\\x00\\x00%s" "")' % ('\\x00' * cfg_bytes_len))
|
||||
|
||||
# go through each qstr and print it out
|
||||
for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
|
||||
qhash = compute_hash(qstr)
|
||||
qlen = len(qstr)
|
||||
print('Q(%s, (const byte*)"\\x%02x\\x%02x\\x%02x\\x%02x" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, qstr))
|
||||
qdata = qstr.replace('"', '\\"')
|
||||
if qlen >= cfg_max_len:
|
||||
print('qstr is too long:', qstr)
|
||||
assert False
|
||||
qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))
|
||||
print('QDEF(MP_QSTR_%s, (const byte*)"\\x%02x\\x%02x%s" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen_str, qdata))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
42
py/malloc.c
42
py/malloc.c
@@ -27,10 +27,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/mpstate.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
@@ -39,15 +39,11 @@
|
||||
#endif
|
||||
|
||||
#if MICROPY_MEM_STATS
|
||||
STATIC size_t total_bytes_allocated = 0;
|
||||
STATIC size_t current_bytes_allocated = 0;
|
||||
STATIC size_t peak_bytes_allocated = 0;
|
||||
|
||||
#define UPDATE_PEAK() { if (current_bytes_allocated > peak_bytes_allocated) peak_bytes_allocated = current_bytes_allocated; }
|
||||
#define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); }
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_GC
|
||||
#include "gc.h"
|
||||
#include "py/gc.h"
|
||||
|
||||
// We redirect standard alloc functions to GC heap - just for the rest of
|
||||
// this module. In the rest of micropython source, system malloc can be
|
||||
@@ -69,8 +65,8 @@ void *m_malloc(size_t num_bytes) {
|
||||
return m_malloc_fail(num_bytes);
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
total_bytes_allocated += num_bytes;
|
||||
current_bytes_allocated += num_bytes;
|
||||
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
|
||||
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
|
||||
UPDATE_PEAK();
|
||||
#endif
|
||||
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
|
||||
@@ -80,8 +76,8 @@ void *m_malloc(size_t num_bytes) {
|
||||
void *m_malloc_maybe(size_t num_bytes) {
|
||||
void *ptr = malloc(num_bytes);
|
||||
#if MICROPY_MEM_STATS
|
||||
total_bytes_allocated += num_bytes;
|
||||
current_bytes_allocated += num_bytes;
|
||||
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
|
||||
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
|
||||
UPDATE_PEAK();
|
||||
#endif
|
||||
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
|
||||
@@ -95,8 +91,8 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
|
||||
return m_malloc_fail(num_bytes);
|
||||
}
|
||||
#if MICROPY_MEM_STATS
|
||||
total_bytes_allocated += num_bytes;
|
||||
current_bytes_allocated += num_bytes;
|
||||
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
|
||||
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
|
||||
UPDATE_PEAK();
|
||||
#endif
|
||||
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
|
||||
@@ -125,8 +121,8 @@ void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
// allocated total. If we process only positive increments,
|
||||
// we'll count 3K.
|
||||
size_t diff = new_num_bytes - old_num_bytes;
|
||||
total_bytes_allocated += diff;
|
||||
current_bytes_allocated += diff;
|
||||
MP_STATE_MEM(total_bytes_allocated) += diff;
|
||||
MP_STATE_MEM(current_bytes_allocated) += diff;
|
||||
UPDATE_PEAK();
|
||||
#endif
|
||||
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
|
||||
@@ -144,8 +140,8 @@ void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
// Also, don't count failed reallocs.
|
||||
if (!(new_ptr == NULL && new_num_bytes != 0)) {
|
||||
size_t diff = new_num_bytes - old_num_bytes;
|
||||
total_bytes_allocated += diff;
|
||||
current_bytes_allocated += diff;
|
||||
MP_STATE_MEM(total_bytes_allocated) += diff;
|
||||
MP_STATE_MEM(current_bytes_allocated) += diff;
|
||||
UPDATE_PEAK();
|
||||
}
|
||||
#endif
|
||||
@@ -156,21 +152,21 @@ void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
|
||||
void m_free(void *ptr, size_t num_bytes) {
|
||||
free(ptr);
|
||||
#if MICROPY_MEM_STATS
|
||||
current_bytes_allocated -= num_bytes;
|
||||
MP_STATE_MEM(current_bytes_allocated) -= num_bytes;
|
||||
#endif
|
||||
DEBUG_printf("free %p, %d\n", ptr, num_bytes);
|
||||
}
|
||||
|
||||
#if MICROPY_MEM_STATS
|
||||
size_t m_get_total_bytes_allocated(void) {
|
||||
return total_bytes_allocated;
|
||||
return MP_STATE_MEM(total_bytes_allocated);
|
||||
}
|
||||
|
||||
size_t m_get_current_bytes_allocated(void) {
|
||||
return current_bytes_allocated;
|
||||
return MP_STATE_MEM(current_bytes_allocated);
|
||||
}
|
||||
|
||||
size_t m_get_peak_bytes_allocated(void) {
|
||||
return peak_bytes_allocated;
|
||||
return MP_STATE_MEM(peak_bytes_allocated);
|
||||
}
|
||||
#endif
|
||||
|
||||
10
py/map.c
10
py/map.c
@@ -28,11 +28,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
// Fixed empty map. Useful when need to call kw-receiving functions
|
||||
// without any keywords from C, etc.
|
||||
@@ -49,7 +47,7 @@ const mp_map_t mp_const_empty_map = {
|
||||
STATIC uint32_t doubling_primes[] = {0, 7, 19, 43, 89, 179, 347, 647, 1229, 2297, 4243, 7829, 14347, 26017, 47149, 84947, 152443, 273253, 488399, 869927, 1547173, 2745121, 4861607};
|
||||
|
||||
STATIC mp_uint_t get_doubling_prime_greater_or_equal_to(mp_uint_t x) {
|
||||
for (int i = 0; i < MP_ARRAY_SIZE(doubling_primes); i++) {
|
||||
for (size_t i = 0; i < MP_ARRAY_SIZE(doubling_primes); i++) {
|
||||
if (doubling_primes[i] >= x) {
|
||||
return doubling_primes[i];
|
||||
}
|
||||
|
||||
23
py/misc.h
23
py/misc.h
@@ -23,12 +23,11 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_MISC_H__
|
||||
#define __MICROPY_INCLUDED_PY_MISC_H__
|
||||
|
||||
// a mini library of useful types and functions
|
||||
|
||||
#ifndef _INCLUDED_MINILIB_H
|
||||
#define _INCLUDED_MINILIB_H
|
||||
|
||||
/** types *******************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -125,6 +124,7 @@ typedef struct _vstr_t {
|
||||
#define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf);
|
||||
|
||||
void vstr_init(vstr_t *vstr, size_t alloc);
|
||||
void vstr_init_len(vstr_t *vstr, size_t len);
|
||||
void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
|
||||
void vstr_clear(vstr_t *vstr);
|
||||
vstr_t *vstr_new(void);
|
||||
@@ -136,8 +136,6 @@ char *vstr_str(vstr_t *vstr);
|
||||
size_t vstr_len(vstr_t *vstr);
|
||||
void vstr_hint_size(vstr_t *vstr, size_t size);
|
||||
char *vstr_extend(vstr_t *vstr, size_t size);
|
||||
bool vstr_set_size(vstr_t *vstr, size_t size);
|
||||
bool vstr_shrink(vstr_t *vstr);
|
||||
char *vstr_add_len(vstr_t *vstr, size_t len);
|
||||
void vstr_add_byte(vstr_t *vstr, byte v);
|
||||
void vstr_add_char(vstr_t *vstr, unichar chr);
|
||||
@@ -185,4 +183,17 @@ static inline mp_uint_t count_lead_ones(byte val) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDED_MINILIB_H
|
||||
/** float internals *************/
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
#define MP_FLOAT_EXP_BITS (11)
|
||||
#define MP_FLOAT_FRAC_BITS (52)
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#define MP_FLOAT_EXP_BITS (8)
|
||||
#define MP_FLOAT_FRAC_BITS (23)
|
||||
#endif
|
||||
#define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_MISC_H__
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
|
||||
|
||||
@@ -27,18 +27,14 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objstr.h"
|
||||
#include "smallint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "stream.h"
|
||||
#include "pfenv.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/smallint.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/pfenv.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
@@ -145,7 +141,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
|
||||
mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
|
||||
return mp_obj_str_format(MP_ARRAY_SIZE(args), args);
|
||||
return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
|
||||
|
||||
@@ -410,6 +406,7 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
|
||||
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
extern mp_uint_t mp_sys_stdout_obj; // type is irrelevant, just need pointer
|
||||
mp_obj_t stream_obj = &mp_sys_stdout_obj;
|
||||
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
|
||||
if (file_elem != NULL && file_elem->value != mp_const_none) {
|
||||
@@ -452,11 +449,10 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
|
||||
vstr_t *vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 16);
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, o_in, PRINT_REPR);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);
|
||||
|
||||
|
||||
@@ -24,16 +24,12 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/// \module cmath - mathematical functions for complex numbers
|
||||
///
|
||||
/// The `cmath` module provides some basic mathematical funtions for
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
|
||||
|
||||
17
py/modgc.c
17
py/modgc.c
@@ -24,14 +24,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "gc.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/gc.h"
|
||||
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
|
||||
@@ -54,7 +49,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
/// \function disable()
|
||||
/// Disable the garbage collector.
|
||||
STATIC mp_obj_t gc_disable(void) {
|
||||
gc_auto_collect_enabled = 0;
|
||||
MP_STATE_MEM(gc_auto_collect_enabled) = 0;
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||
@@ -62,13 +57,13 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||
/// \function enable()
|
||||
/// Enable the garbage collector.
|
||||
STATIC mp_obj_t gc_enable(void) {
|
||||
gc_auto_collect_enabled = 1;
|
||||
MP_STATE_MEM(gc_auto_collect_enabled) = 1;
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||
|
||||
STATIC mp_obj_t gc_isenabled(void) {
|
||||
return MP_BOOL(gc_auto_collect_enabled);
|
||||
return MP_BOOL(MP_STATE_MEM(gc_auto_collect_enabled));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled);
|
||||
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_IO
|
||||
|
||||
|
||||
10
py/modmath.c
10
py/modmath.c
@@ -24,16 +24,12 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "py/builtin.h"
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/// \module math - mathematical functions
|
||||
///
|
||||
/// The `math` module provides some basic mathematical funtions for
|
||||
|
||||
@@ -24,45 +24,54 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "stackctrl.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/builtin.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/gc.h"
|
||||
|
||||
// Various builtins specific to MicroPython runtime,
|
||||
// living in micropython module
|
||||
|
||||
#if MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
|
||||
#if MICROPY_MEM_STATS
|
||||
STATIC mp_obj_t mp_micropython_mem_total() {
|
||||
STATIC mp_obj_t mp_micropython_mem_total(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_current() {
|
||||
STATIC mp_obj_t mp_micropython_mem_current(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_mem_current);
|
||||
|
||||
STATIC mp_obj_t mp_micropython_mem_peak() {
|
||||
STATIC mp_obj_t mp_micropython_mem_peak(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
|
||||
#endif
|
||||
|
||||
mp_obj_t mp_micropython_mem_info(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
(void)args;
|
||||
#if MICROPY_MEM_STATS
|
||||
printf("mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n",
|
||||
m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
|
||||
#endif
|
||||
#if MICROPY_STACK_CHECK
|
||||
printf("stack: " UINT_FMT " out of " INT_FMT "\n", mp_stack_usage(), MP_STATE_VM(stack_limit));
|
||||
#else
|
||||
printf("stack: " UINT_FMT "\n", mp_stack_usage());
|
||||
#endif
|
||||
#if MICROPY_ENABLE_GC
|
||||
gc_dump_info();
|
||||
if (n_args == 1) {
|
||||
// arg given means dump gc allocation table
|
||||
gc_dump_alloc_table();
|
||||
}
|
||||
#else
|
||||
(void)n_args;
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
@@ -76,7 +85,8 @@ STATIC mp_obj_t qstr_info(void) {
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_qstr_info_obj, qstr_info);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
|
||||
@@ -84,10 +94,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
|
||||
#if MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
#if MICROPY_MEM_STATS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_total), (mp_obj_t)&mp_micropython_mem_total_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_info), (mp_obj_t)&mp_micropython_mem_info_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_qstr_info), (mp_obj_t)&mp_micropython_qstr_info_obj },
|
||||
#endif
|
||||
|
||||
@@ -27,15 +27,11 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "binary.h"
|
||||
#include "parsenum.h"
|
||||
|
||||
#include "py/builtin.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/parsenum.h"
|
||||
|
||||
#if MICROPY_PY_STRUCT
|
||||
|
||||
@@ -165,8 +161,9 @@ STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
const char *fmt = mp_obj_str_get_str(args[0]);
|
||||
char fmt_type = get_fmt_type(&fmt);
|
||||
mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
|
||||
byte *p;
|
||||
mp_obj_t res = mp_obj_str_builder_start(&mp_type_bytes, size, &p);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, size);
|
||||
byte *p = (byte*)vstr.buf;
|
||||
memset(p, 0, size);
|
||||
|
||||
for (mp_uint_t i = 1; i < n_args; i++) {
|
||||
@@ -194,7 +191,8 @@ STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);
|
||||
|
||||
|
||||
29
py/modsys.c
29
py/modsys.c
@@ -24,27 +24,24 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
#include "runtime.h"
|
||||
#include "objlist.h"
|
||||
#include "objtuple.h"
|
||||
#include "objstr.h"
|
||||
#include "mpz.h"
|
||||
#include "objint.h"
|
||||
#include "pfenv.h"
|
||||
#include "stream.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/builtin.h"
|
||||
#include "py/objlist.h"
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/objint.h"
|
||||
#include "py/pfenv.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_SYS
|
||||
|
||||
/// \module sys - system specific functions
|
||||
|
||||
// defined per port; type of these is irrelevant, just need pointer
|
||||
extern mp_uint_t mp_sys_stdin_obj;
|
||||
extern mp_uint_t mp_sys_stdout_obj;
|
||||
extern mp_uint_t mp_sys_stderr_obj;
|
||||
|
||||
// These two lists must be initialised per port (after the call to mp_init).
|
||||
// TODO document these properly, they aren't constants or functions...
|
||||
/// \constant path - a mutable list of directories to search for imported modules
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_MPCONFIG_H__
|
||||
#define __MICROPY_INCLUDED_PY_MPCONFIG_H__
|
||||
|
||||
// This file contains default configuration settings for MicroPython.
|
||||
// You can override any of the options below using mpconfigport.h file
|
||||
@@ -49,6 +51,11 @@
|
||||
/*****************************************************************************/
|
||||
/* Memory allocation policy */
|
||||
|
||||
// Number of words allocated (in BSS) to the GC stack (minimum is 1)
|
||||
#ifndef MICROPY_ALLOC_GC_STACK_SIZE
|
||||
#define MICROPY_ALLOC_GC_STACK_SIZE (64)
|
||||
#endif
|
||||
|
||||
// Initial amount for lexer indentation level
|
||||
#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT
|
||||
#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)
|
||||
@@ -105,6 +112,13 @@
|
||||
#define MICROPY_MODULE_DICT_SIZE (1)
|
||||
#endif
|
||||
|
||||
// Number of bytes used to store qstr length
|
||||
// Dictates hard limit on maximum Python identifier length, but 1 byte
|
||||
// (limit of 255 bytes in an identifier) should be enough for everyone
|
||||
#ifndef MICROPY_QSTR_BYTES_IN_LEN
|
||||
#define MICROPY_QSTR_BYTES_IN_LEN (1)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Micro Python emitters */
|
||||
|
||||
@@ -145,6 +159,11 @@
|
||||
/*****************************************************************************/
|
||||
/* Compiler configuration */
|
||||
|
||||
// Whether to enable lookup of constants in modules; eg module.CONST
|
||||
#ifndef MICROPY_COMP_MODULE_CONST
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable constant optimisation; id = const(value)
|
||||
#ifndef MICROPY_COMP_CONST
|
||||
#define MICROPY_COMP_CONST (1)
|
||||
@@ -175,6 +194,13 @@
|
||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||
#endif
|
||||
|
||||
// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,
|
||||
// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and
|
||||
// uses a bit of extra code ROM, but greatly improves lookup speed.
|
||||
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
|
||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python internal features */
|
||||
|
||||
@@ -191,7 +217,7 @@
|
||||
// Whether to check C stack usage. C stack used for calling Python functions,
|
||||
// etc. Not checking means segfault on overflow.
|
||||
#ifndef MICROPY_STACK_CHECK
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_STACK_CHECK (0)
|
||||
#endif
|
||||
|
||||
// Whether to have an emergency exception buffer
|
||||
@@ -209,6 +235,11 @@
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#endif
|
||||
|
||||
// Whether port requires event-driven REPL functions
|
||||
#ifndef MICROPY_REPL_EVENT_DRIVEN
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||
#endif
|
||||
|
||||
// Whether to include lexer helper function for unix
|
||||
#ifndef MICROPY_HELPER_LEXER_UNIX
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
@@ -249,6 +280,11 @@ typedef long long mp_longint_impl_t;
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
|
||||
#endif
|
||||
|
||||
// Whether issue warnings during compiling/execution
|
||||
#ifndef MICROPY_WARNINGS
|
||||
#define MICROPY_WARNINGS (0)
|
||||
#endif
|
||||
|
||||
// Float and complex implementation
|
||||
#define MICROPY_FLOAT_IMPL_NONE (0)
|
||||
#define MICROPY_FLOAT_IMPL_FLOAT (1)
|
||||
@@ -292,6 +328,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_MODULE_WEAK_LINKS (0)
|
||||
#endif
|
||||
|
||||
// Whether frozen modules are supported
|
||||
#ifndef MICROPY_MODULE_FROZEN
|
||||
#define MICROPY_MODULE_FROZEN (0)
|
||||
#endif
|
||||
|
||||
// Whether you can override builtins in the builtins module
|
||||
#ifndef MICROPY_CAN_OVERRIDE_BUILTINS
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
|
||||
@@ -350,6 +391,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PY___FILE__ (1)
|
||||
#endif
|
||||
|
||||
// Whether to provide mem-info related functions in micropython module
|
||||
#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
|
||||
#endif
|
||||
|
||||
// Whether to provide "array" module. Note that large chunk of the
|
||||
// underlying code is shared with "bytearray" builtin type, so to
|
||||
// get real savings, it should be disabled too.
|
||||
@@ -476,6 +522,11 @@ typedef double mp_float_t;
|
||||
#define MICROPY_PORT_CONSTANTS
|
||||
#endif
|
||||
|
||||
// Any root pointers for GC scanning - see mpstate.c
|
||||
#ifndef MICROPY_PORT_ROOT_POINTERS
|
||||
#define MICROPY_PORT_ROOT_POINTERS
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Miscellaneous settings */
|
||||
|
||||
@@ -528,6 +579,9 @@ typedef double mp_float_t;
|
||||
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
|
||||
#endif
|
||||
|
||||
// If these MP_PLAT_* macros are overridden then the memory allocated by them
|
||||
// must be somehow reachable for marking by the GC, since the native code
|
||||
// generators store pointers to GC managed memory in the code.
|
||||
#ifndef MP_PLAT_ALLOC_EXEC
|
||||
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while(0)
|
||||
#endif
|
||||
@@ -572,3 +626,5 @@ typedef double mp_float_t;
|
||||
#ifndef MP_UNLIKELY
|
||||
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#endif
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_MPCONFIG_H__
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,6 +24,6 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
#include "py/mpstate.h"
|
||||
|
||||
void mp_import_set_directory(const char *dir);
|
||||
mp_state_ctx_t mp_state_ctx;
|
||||
156
py/mpstate.h
Normal file
156
py/mpstate.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_MPSTATE_H__
|
||||
#define __MICROPY_INCLUDED_PY_MPSTATE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/objlist.h" // in case port needs mp_obj_list_t in root pointers
|
||||
#include "py/objexcept.h"
|
||||
|
||||
// This file contains structures defining the state of the Micro Python
|
||||
// memory system, runtime and virtual machine. The state is a global
|
||||
// variable, but in the future it is hoped that the state can become local.
|
||||
|
||||
// This structure hold information about the memory allocation system.
|
||||
typedef struct _mp_state_mem_t {
|
||||
#if MICROPY_MEM_STATS
|
||||
size_t total_bytes_allocated;
|
||||
size_t current_bytes_allocated;
|
||||
size_t peak_bytes_allocated;
|
||||
#endif
|
||||
|
||||
byte *gc_alloc_table_start;
|
||||
mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
mp_uint_t *gc_pool_start;
|
||||
mp_uint_t *gc_pool_end;
|
||||
|
||||
int gc_stack_overflow;
|
||||
mp_uint_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
|
||||
mp_uint_t *gc_sp;
|
||||
uint16_t gc_lock_depth;
|
||||
|
||||
// This variable controls auto garbage collection. If set to 0 then the
|
||||
// GC won't automatically run when gc_alloc can't find enough blocks. But
|
||||
// you can still allocate/free memory and also explicitly call gc_collect.
|
||||
uint16_t gc_auto_collect_enabled;
|
||||
|
||||
mp_uint_t gc_last_free_atb_index;
|
||||
} mp_state_mem_t;
|
||||
|
||||
// This structure hold runtime and VM information. It includes a section
|
||||
// which contains root pointers that must be scanned by the GC.
|
||||
typedef struct _mp_state_vm_t {
|
||||
////////////////////////////////////////////////////////////
|
||||
// START ROOT POINTER SECTION
|
||||
// everything that needs GC scanning must go here
|
||||
// this must start at the start of this structure
|
||||
//
|
||||
|
||||
// Note: nlr asm code has the offset of this hard-coded
|
||||
nlr_buf_t *nlr_top;
|
||||
|
||||
qstr_pool_t *last_pool;
|
||||
|
||||
// non-heap memory for creating an exception if we can't allocate RAM
|
||||
mp_obj_exception_t mp_emergency_exception_obj;
|
||||
|
||||
// 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];
|
||||
#else
|
||||
// dynamically allocated buf
|
||||
byte *mp_emergency_exception_buf;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// map with loaded modules
|
||||
// TODO: expose as sys.modules
|
||||
mp_map_t mp_loaded_modules_map;
|
||||
|
||||
// pending exception object (MP_OBJ_NULL if not pending)
|
||||
mp_obj_t mp_pending_exception;
|
||||
|
||||
// dictionary for the __main__ module
|
||||
mp_obj_dict_t dict_main;
|
||||
|
||||
// dictionary for overridden builtins
|
||||
#if MICROPY_CAN_OVERRIDE_BUILTINS
|
||||
mp_obj_dict_t *mp_module_builtins_override_dict;
|
||||
#endif
|
||||
|
||||
// include any root pointers defined by a port
|
||||
MICROPY_PORT_ROOT_POINTERS
|
||||
|
||||
//
|
||||
// END ROOT POINTER SECTION
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Stack top at the start of program
|
||||
// Note: this entry is used to locate the end of the root pointer section.
|
||||
char *stack_top;
|
||||
|
||||
#if MICROPY_STACK_CHECK
|
||||
mp_uint_t stack_limit;
|
||||
#endif
|
||||
|
||||
mp_uint_t mp_optimise_value;
|
||||
|
||||
// size of the emergency exception buf, if it's dynamically allocated
|
||||
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0
|
||||
mp_int_t mp_emergency_exception_buf_size;
|
||||
#endif
|
||||
} mp_state_vm_t;
|
||||
|
||||
// This structure combines the above 2 structures, and adds the local
|
||||
// and global dicts.
|
||||
// Note: if this structure changes then revisit all nlr asm code since they
|
||||
// have the offset of nlr_top hard-coded.
|
||||
typedef struct _mp_state_ctx_t {
|
||||
// these must come first for root pointer scanning in GC to work
|
||||
mp_obj_dict_t *dict_locals;
|
||||
mp_obj_dict_t *dict_globals;
|
||||
// this must come next for root pointer scanning in GC to work
|
||||
mp_state_vm_t vm;
|
||||
mp_state_mem_t mem;
|
||||
} mp_state_ctx_t;
|
||||
|
||||
extern mp_state_ctx_t mp_state_ctx;
|
||||
|
||||
#define MP_STATE_CTX(x) (mp_state_ctx.x)
|
||||
#define MP_STATE_VM(x) (mp_state_ctx.vm.x)
|
||||
#define MP_STATE_MEM(x) (mp_state_ctx.mem.x)
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_MPSTATE_H__
|
||||
120
py/mpz.c
120
py/mpz.c
@@ -24,15 +24,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "mpz.h"
|
||||
#include "py/mpz.h"
|
||||
|
||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
|
||||
|
||||
@@ -203,10 +198,10 @@ STATIC mp_uint_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen,
|
||||
|
||||
/* computes i = j & k
|
||||
returns number of digits in i
|
||||
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
|
||||
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed)
|
||||
can have i, j, k pointing to same memory
|
||||
*/
|
||||
STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
|
||||
STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, mp_uint_t klen) {
|
||||
mpz_dig_t *oidig = idig;
|
||||
|
||||
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
|
||||
@@ -595,6 +590,14 @@ mpz_t *mpz_from_ll(long long val, bool is_signed) {
|
||||
return z;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mpz_t *mpz_from_float(mp_float_t val) {
|
||||
mpz_t *z = mpz_zero();
|
||||
mpz_set_from_float(z, val);
|
||||
return z;
|
||||
}
|
||||
#endif
|
||||
|
||||
mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
|
||||
mpz_t *z = mpz_zero();
|
||||
mpz_set_from_str(z, str, len, neg, base);
|
||||
@@ -650,6 +653,11 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
|
||||
}
|
||||
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
|
||||
if (val == 0) {
|
||||
z->len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
|
||||
|
||||
mp_uint_t uval;
|
||||
@@ -687,6 +695,73 @@ void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
void mpz_set_from_float(mpz_t *z, mp_float_t src) {
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
typedef uint64_t mp_float_int_t;
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
typedef uint32_t mp_float_int_t;
|
||||
#endif
|
||||
union {
|
||||
mp_float_t f;
|
||||
struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
|
||||
} u = {src};
|
||||
|
||||
z->neg = u.p.sgn;
|
||||
if (u.p.exp == 0) {
|
||||
// value == 0 || value < 1
|
||||
mpz_set_from_int(z, 0);
|
||||
} else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
|
||||
// u.p.frc == 0 indicates inf, else NaN
|
||||
// should be handled by caller
|
||||
mpz_set_from_int(z, 0);
|
||||
} else {
|
||||
const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
|
||||
if (adj_exp < 0) {
|
||||
// value < 1 , truncates to 0
|
||||
mpz_set_from_int(z, 0);
|
||||
} else if (adj_exp == 0) {
|
||||
// 1 <= value < 2 , so truncates to 1
|
||||
mpz_set_from_int(z, 1);
|
||||
} else {
|
||||
// 2 <= value
|
||||
const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
|
||||
const unsigned int rem = adj_exp % DIG_SIZE;
|
||||
int dig_ind, shft;
|
||||
mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
|
||||
|
||||
if (adj_exp < MP_FLOAT_FRAC_BITS) {
|
||||
shft = 0;
|
||||
dig_ind = 0;
|
||||
frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
|
||||
} else {
|
||||
shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
|
||||
dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
|
||||
}
|
||||
mpz_need_dig(z, dig_cnt);
|
||||
z->len = dig_cnt;
|
||||
if (dig_ind != 0) {
|
||||
memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
|
||||
}
|
||||
if (shft != 0) {
|
||||
z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
|
||||
frc >>= DIG_SIZE - shft;
|
||||
}
|
||||
#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
|
||||
while (dig_ind != dig_cnt) {
|
||||
z->dig[dig_ind++] = frc & DIG_MASK;
|
||||
frc >>= DIG_SIZE;
|
||||
}
|
||||
#else
|
||||
if (dig_ind != dig_cnt) {
|
||||
z->dig[dig_ind] = frc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// returns number of bytes from str that were processed
|
||||
mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
|
||||
assert(base < 36);
|
||||
@@ -871,11 +946,17 @@ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
|
||||
if (dest != z) {
|
||||
mpz_set(dest, z);
|
||||
}
|
||||
if (dest->neg) {
|
||||
if (dest->len == 0) {
|
||||
mpz_need_dig(dest, 1);
|
||||
dest->dig[0] = 1;
|
||||
dest->len = 1;
|
||||
dest->neg = 1;
|
||||
} else if (dest->neg) {
|
||||
dest->neg = 0;
|
||||
mpz_dig_t k = 1;
|
||||
dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
|
||||
} else {
|
||||
mpz_need_dig(dest, dest->len + 1);
|
||||
mpz_dig_t k = 1;
|
||||
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
|
||||
dest->neg = 1;
|
||||
@@ -924,7 +1005,14 @@ void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
|
||||
round_up = 1;
|
||||
}
|
||||
if (round_up) {
|
||||
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
|
||||
if (dest->len == 0) {
|
||||
// dest == 0, so need to add 1 by hand (answer will be -1)
|
||||
dest->dig[0] = 1;
|
||||
dest->len = 1;
|
||||
} else {
|
||||
// dest > 0, so can use mpn_add to add 1
|
||||
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -993,7 +1081,7 @@ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
|
||||
}
|
||||
// do the and'ing
|
||||
mpz_need_dig(dest, rhs->len);
|
||||
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
|
||||
dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
|
||||
dest->neg = 0;
|
||||
} else {
|
||||
// TODO both args are negative
|
||||
@@ -1270,7 +1358,7 @@ mp_int_t mpz_hash(const mpz_t *z) {
|
||||
mp_int_t val = 0;
|
||||
mpz_dig_t *d = z->dig + z->len;
|
||||
|
||||
while (--d >= z->dig) {
|
||||
while (d-- > z->dig) {
|
||||
val = (val << DIG_SIZE) | *d;
|
||||
}
|
||||
|
||||
@@ -1282,10 +1370,10 @@ mp_int_t mpz_hash(const mpz_t *z) {
|
||||
}
|
||||
|
||||
bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
|
||||
mp_int_t val = 0;
|
||||
mp_uint_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
while (d-- > i->dig) {
|
||||
if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
|
||||
// will overflow
|
||||
return false;
|
||||
@@ -1310,7 +1398,7 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
|
||||
mp_uint_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
while (d-- > i->dig) {
|
||||
if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
|
||||
// will overflow
|
||||
return false;
|
||||
@@ -1327,7 +1415,7 @@ mp_float_t mpz_as_float(const mpz_t *i) {
|
||||
mp_float_t val = 0;
|
||||
mpz_dig_t *d = i->dig + i->len;
|
||||
|
||||
while (--d >= i->dig) {
|
||||
while (d-- > i->dig) {
|
||||
val = val * DIG_BASE + *d;
|
||||
}
|
||||
|
||||
|
||||
17
py/mpz.h
17
py/mpz.h
@@ -23,6 +23,13 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_MPZ_H__
|
||||
#define __MICROPY_INCLUDED_PY_MPZ_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
// This mpz module implements arbitrary precision integers.
|
||||
//
|
||||
@@ -62,7 +69,7 @@ typedef int32_t mpz_dbl_dig_signed_t;
|
||||
typedef struct _mpz_t {
|
||||
mp_uint_t neg : 1;
|
||||
mp_uint_t fixed_dig : 1;
|
||||
mp_uint_t alloc : 30;
|
||||
mp_uint_t alloc : BITS_PER_WORD - 2;
|
||||
mp_uint_t len;
|
||||
mpz_dig_t *dig;
|
||||
} mpz_t;
|
||||
@@ -78,6 +85,9 @@ void mpz_deinit(mpz_t *z);
|
||||
mpz_t *mpz_zero(void);
|
||||
mpz_t *mpz_from_int(mp_int_t i);
|
||||
mpz_t *mpz_from_ll(long long i, bool is_signed);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mpz_t *mpz_from_float(mp_float_t i);
|
||||
#endif
|
||||
mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base);
|
||||
void mpz_free(mpz_t *z);
|
||||
|
||||
@@ -86,6 +96,9 @@ mpz_t *mpz_clone(const mpz_t *src);
|
||||
void mpz_set(mpz_t *dest, const mpz_t *src);
|
||||
void mpz_set_from_int(mpz_t *z, mp_int_t src);
|
||||
void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
void mpz_set_from_float(mpz_t *z, mp_float_t src);
|
||||
#endif
|
||||
mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base);
|
||||
|
||||
bool mpz_is_zero(const mpz_t *z);
|
||||
@@ -131,3 +144,5 @@ mp_float_t mpz_as_float(const mpz_t *z);
|
||||
#endif
|
||||
mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma);
|
||||
mp_uint_t mpz_as_str_inpl(const mpz_t *z, mp_uint_t base, const char *prefix, char base_char, char comma, char *str);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_MPZ_H__
|
||||
|
||||
@@ -28,14 +28,10 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "emitglue.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime0.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/emitglue.h"
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
@@ -84,8 +80,11 @@ mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, cons
|
||||
}
|
||||
|
||||
// wrapper that makes raise obj and raises it
|
||||
NORETURN void mp_native_raise(mp_obj_t o) {
|
||||
nlr_raise(mp_make_raise_obj(o));
|
||||
// END_FINALLY opcode requires that we don't raise if o==None
|
||||
void mp_native_raise(mp_obj_t o) {
|
||||
if (o != mp_const_none) {
|
||||
nlr_raise(mp_make_raise_obj(o));
|
||||
}
|
||||
}
|
||||
|
||||
// these must correspond to the respective enum in runtime0.h
|
||||
|
||||
13
py/nlr.h
13
py/nlr.h
@@ -23,6 +23,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __MICROPY_INCLUDED_PY_NLR_H__
|
||||
#define __MICROPY_INCLUDED_PY_NLR_H__
|
||||
|
||||
// non-local return
|
||||
// exception handling, basically a stack of setjmp/longjmp buffers
|
||||
@@ -31,6 +33,8 @@
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
typedef struct _nlr_buf_t nlr_buf_t;
|
||||
struct _nlr_buf_t {
|
||||
// the entries here must all be machine word size
|
||||
@@ -61,12 +65,13 @@ struct _nlr_buf_t {
|
||||
};
|
||||
|
||||
#if MICROPY_NLR_SETJMP
|
||||
extern nlr_buf_t *nlr_setjmp_top;
|
||||
#include "py/mpstate.h"
|
||||
|
||||
NORETURN void nlr_setjmp_jump(void *val);
|
||||
// nlr_push() must be defined as a macro, because "The stack context will be
|
||||
// invalidated if the function which called setjmp() returns."
|
||||
#define nlr_push(buf) ((buf)->prev = nlr_setjmp_top, nlr_setjmp_top = (buf), setjmp((buf)->jmpbuf))
|
||||
#define nlr_pop() { nlr_setjmp_top = nlr_setjmp_top->prev; }
|
||||
#define nlr_push(buf) ((buf)->prev = MP_STATE_VM(nlr_top), MP_STATE_VM(nlr_top) = (buf), setjmp((buf)->jmpbuf))
|
||||
#define nlr_pop() { MP_STATE_VM(nlr_top) = MP_STATE_VM(nlr_top)->prev; }
|
||||
#define nlr_jump(val) nlr_setjmp_jump(val)
|
||||
#else
|
||||
unsigned int nlr_push(nlr_buf_t *);
|
||||
@@ -91,3 +96,5 @@ void nlr_jump_fail(void *val);
|
||||
nlr_jump(_val); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_NLR_H__
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user