Compare commits

..

181 Commits
v1.3 ... v1.3.2

Author SHA1 Message Date
Damien George
55a5b80793 docs: Make images and youtube video links work for LCD and AMP docs.
Images are currently served from micropython.org/static.  I don't know
if there is a better way to handle images.
2014-09-25 19:42:27 +01:00
Damien George
cde0ca21bf py: Simplify JSON str printing (while still conforming to JSON spec).
The JSON specs are relatively flexible and allow us to use one function
to print strings, be they ascii, bytes or utf-8 encoded.
2014-09-25 17:35:56 +01:00
Damien George
d19c256656 docs: Imported tutorials from previous documentation system. 2014-09-25 17:23:06 +01:00
Damien George
6162bea5b2 docs: Initial commit of Sphinx documentation framework. 2014-09-25 17:23:06 +01:00
blmorris
4f449120e1 Change allows tests/unix/ffi_float.py to pass on OSX 2014-09-25 16:31:30 +01:00
Damien George
2234c3f23d tests: Add test for exception matching of a tuple of exceptions. 2014-09-25 15:49:26 +01:00
Damien George
4bcd04bcad py: Tidy up exception matching; allow matching of tuple of exceptions.
Addresses issue #864.
2014-09-25 15:49:26 +01:00
Damien George
16ef60fba6 Updated CODECONVENTIONS to clarify use of integer types. 2014-09-25 15:49:26 +01:00
Damien George
b0261341d3 py: For malloc and vstr functions, use size_t exclusively for int type.
It seems most sensible to use size_t for measuring "number of bytes" in
malloc and vstr functions (since that's what size_t is for).  We don't
use mp_uint_t because malloc and vstr are not Micro Python specific.
2014-09-25 15:49:26 +01:00
Damien George
ac04a8a56a stmhal: Enable 8-byte stack alignment for IRQ handlers. 2014-09-25 15:47:53 +01:00
Damien George
e8ea0724da stmhal, timer: Factor code to compute PWM percent; improve 32bit case.
Also do the same for teensy timer code.
2014-09-25 15:44:10 +01:00
Damien George
3fafe730d3 Merge pull request #868 from dhylands/fix-teensy-float
Add pulse_width_percent to teensy.
2014-09-25 14:51:44 +01:00
Dave Hylands
53d5fa641f Add pulse_width_percent to teensy.
Fix stmhal and teensy print routines to report actual prescaler an period.
Fix teensy build to use soft-float
Add USE_ARDUINO_TOOLCHAIN option to teensy build
2014-09-23 23:19:36 -07:00
Damien George
52b5d76a6b py: Free non-interned strings in the parser when not needed.
mp_parse_node_free now frees the memory associated with non-interned
strings.  And the parser calls mp_parse_node_free when discarding a
non-used node (such as a doc string).

Also, the compiler now frees the parse tree explicitly just before it
exits (as opposed to relying on the caller to do this).

Addresses issue #708 as best we can.
2014-09-23 15:31:56 +00:00
Damien George
d6230f62c7 py: Make native emitter handle multi-compare and not/is not/not in ops. 2014-09-23 14:15:45 +00:00
Damien George
96e20c600f tests: Fix uctypes tests to run on 64bit arch; enable more native tests. 2014-09-23 14:15:45 +00:00
Damien George
5a5555e385 Merge pull request #869 from stinos/windows-up
windows: Enable input(), sys.maxsize(), ujson module, emergency exceptio...
2014-09-23 14:58:52 +01:00
Damien George
9f53275042 Merge pull request #871 from blmorris/osx_build_fix
Fix unix/Makefile to build on OSX
2014-09-23 14:57:14 +01:00
blmorris
fa6567a39f Clean up logical flow for setting LDFLAGS to build for Linux and OSX
Add more specific comments describing what is going on.
2014-09-23 09:42:18 -04:00
Damien George
eaaebf3291 stmhal: Initialise stack pointer correctly.
Stack is full descending and must be 8-byte aligned.  It must start off
pointing to just above the last byte of RAM.

Previously, stack started pointed to last byte of RAM (eg 0x2001ffff)
and so was not 8-byte aligned.  This caused a bug in combination with
alloca.

This patch also updates some debug printing code.

Addresses issue #872 (among many other undiscovered issues).
2014-09-23 10:59:05 +01:00
blmorris
8afb9b3863 Incorporate change in assignment logic suggested by dhylands 2014-09-22 23:00:42 -04:00
blmorris
1fae787493 Fix unix/Makefile to build on OSX
Force OSX to compile with clang even if gcc is available
Change LDFLAGS syntax to be compatible with clang
Fix questionable syntax on line 90
Remove extraneous tab character
2014-09-22 15:16:14 -04:00
stijn
8c41920a90 windows: Enable input(), sys.maxsize(), ujson module, emergency exception buf, os module 2014-09-22 11:10:27 +02:00
Damien George
2c180f7ccc extmod, ujson: Add test and comment for loads. 2014-09-21 23:43:03 +01:00
Damien George
df1e92ba3a extmod, ujson: Add \uxxxx parsing in json strings. 2014-09-21 23:43:03 +01:00
Damien George
fa2f1f72e0 extmod, ujson: Slight reduction in code size. 2014-09-21 23:43:03 +01:00
Damien George
89e4657c69 extmod: Add loads to ujson module. 2014-09-21 23:43:03 +01:00
Damien George
c95359ecc6 Merge branch 'dhylands-timer-pwm2' 2014-09-21 22:56:07 +01:00
Damien George
0e58c5810d stmhal: Add pulse_width_ratio to timer channel object.
This allows to set the pulse width (for PWM mode) as a ratio relative to
the period of the timer.  Eg, 0.5 is a 50% duty cycle.  You can set the
ratio in the channel init, or using channel.pulse_width_ratio; the
latter can also read the pulse width as a ratio.
2014-09-21 22:54:02 +01:00
Dave Hylands
becbc87fd7 Add Timer support (PWM, OC, IC) for stmhal and teensy 2014-09-19 09:26:13 -07:00
Damien George
2842945e76 stmhal: Fix bugs in documentation so it compiles. 2014-09-17 23:27:42 +00:00
Damien George
8bb44f69f2 lib: Add basic README. 2014-09-18 00:13:03 +01:00
Damien George
3d61528fe7 py: Add 'builtins' module. 2014-09-17 23:17:26 +01:00
Damien George
612045f53f py: Add native json printing using existing print framework.
Also add start of ujson module with dumps implemented.  Enabled in unix
and stmhal ports.  Test passes on both.
2014-09-17 22:56:34 +01:00
Damien George
8a9b999f1c py: Make dict use a bit less RAM when iterating; properly del values.
Heap RAM was being allocated to print dicts and do some other types of
iterating.  Now these iterations use 1 word of state on the stack.

Deleting elements from a dict was not allowing the value to be reclaimed
by the GC.  This is now fixed.
2014-09-17 15:53:03 +01:00
Damien George
1d7fb82f0a stmhal: Change 64-bit arithmetic to 32-bit for SD card block addressing.
By measuring SD card addresses in blocks and not bytes, one can get away
with using 32-bit numbers.

This patch also uses proper atomic lock/unlock around SD card
read/write, adds SD.info() function, and gives error code for failed
read/writes.
2014-09-15 23:49:57 +01:00
Felix Domke
6ff42c54bb stmhal/sdcard.c: add pyb.SD.write 2014-09-15 22:34:16 +01:00
Felix Domke
09de030651 stmhal/hal/src/stm32f4xx_hal_sd.c: fix SDHC card capacity 2014-09-15 22:34:07 +01:00
Damien George
d4a799f152 py: Make asm_arm_less_op take destination register as first arg.
This gets ARM native emitter working againg and addresses issue #858.
2014-09-15 16:39:24 +01:00
Damien George
b92cbe6129 py: Move definition of mp_sys_exit to core.
sys.exit always raises SystemExit so doesn't need a special
implementation for each port.  If C exit() is really needed, use the
standard os._exit function.

Also initialise mp_sys_path and mp_sys_argv in teensy port.
2014-09-15 15:53:09 +01:00
Damien George
83695596ed py: Fix build error when float disabled; add test for divmod. 2014-09-13 19:58:18 +01:00
Damien George
8594ce2280 py: Implement divmod, % and proper // for floating point.
Tested and working on unix and pyboard.
2014-09-13 18:43:09 +01:00
Damien George
5c6783496d Merge branch 'iabdalkader-memcpy' 2014-09-13 00:13:28 +01:00
Damien George
32781cce6d stmhal: Slightly improved memcpy; memset uses word store when aligned. 2014-09-13 00:12:41 +01:00
Damien George
5792500ccc Merge branch 'memcpy' of github.com:iabdalkader/micropython into iabdalkader-memcpy 2014-09-12 23:23:49 +01:00
Damien George
bb29546868 py: Load strings as objects when compiling viper.
Eventually, viper wants to be able to use raw pointers to strings and
arrays for efficient access.  But for now, let's just load strings as a
Python object so they can be used as normal.  This will anyway be
compatible with eventual intended viper behaviour.

Addresses issue #857.
2014-09-12 23:15:06 +01:00
Damien George
89ab3be0b1 Merge branch 'master' of github.com:micropython/micropython 2014-09-11 22:28:58 +01:00
Damien George
20beff9ae3 py and libm: Add asinf,acosf; print higher precision for float.
Also use less stack space when printing single precision float.

Addition of asinf and acosf addresses issue #851.
2014-09-11 22:24:45 +01:00
Damien George
5f0c18e583 Merge pull request #852 from techno/staccel_LIS3DSH
Add LIS3DSH accelometer support to staccel.py
2014-09-11 20:36:44 +01:00
iabdalkader
d60580eb5e Optimize memcpy more 2014-09-11 19:01:48 +02:00
Hirotaka Kawata
2b4af54992 Add LIS3DSH accelometer support to staccel.py 2014-09-11 16:40:53 +09:00
iabdalkader
81b2ddf5d1 Memcpy: copy words 2014-09-11 07:49:21 +02:00
Damien George
953074315e py: Enable struct/binary-helper to parse q and Q sized ints.
Addresses issue #848.
2014-09-10 22:10:33 +01:00
Damien George
6eae861685 py: Put define of x86 argument registers in asmx86.h. 2014-09-08 22:16:35 +00:00
Damien George
7ff996c237 py: Convert [u]int to mp_[u]int_t in emit.h and associated .c files.
Towards resolving issue #50.
2014-09-08 23:05:16 +01:00
Damien George
377b80b624 py: Print imported module's location (__file__) if available. 2014-09-08 10:45:23 +01:00
Damien George
5c00757a5c stmhal: uart ioctl uses EINVAL, and checks TXE bit for write-ability. 2014-09-07 20:57:18 +01:00
Damien George
013d53c0b4 Remove skeletal modselect from extmod and just put it in stmhal. 2014-09-07 20:42:01 +01:00
Damien George
e2a618615d stmhal: Fix modselect so non-hashable objects can be polled. 2014-09-07 20:41:09 +01:00
Damien George
c7687ad7e6 py: Rename mp_builtin_id to mp_obj_id and make it public. 2014-09-07 20:41:09 +01:00
Damien George
a2f55fe12b stmhal: Add polling ability to UART object. 2014-09-07 20:40:32 +01:00
Damien George
6c9c7bc75a stmhal: Implement generic select.select and select.poll. 2014-09-07 20:40:32 +01:00
Damien George
c8c44a4c2e py: Add ioctl method to stream protocol; add initial modselect. 2014-09-07 20:40:10 +01:00
Damien George
8105736982 py: Clean up x86-64 native assembler; allow use of extended regs.
Native x86-64 now has 3 locals in registers.
2014-09-07 01:06:19 +01:00
Damien George
25d904105c py: Adjust regs for x86 so that 1 more local can live in a reg. 2014-09-06 23:24:32 +00:00
Damien George
91fe0d4880 unix: Fix modffi to be able to return double on x86 machines. 2014-09-06 23:04:42 +00:00
Damien George
03281b3850 py: Allow x86 native functions to take arguments.
Fix some bugs with x86 stack and saving registers correctly.
2014-09-06 22:38:50 +00:00
Damien George
c90f59ec3a py: Add support for emitting native x86 machine code. 2014-09-06 23:06:36 +01:00
Damien George
33b50a0217 Merge branch 'master' of github.com:micropython/micropython 2014-09-06 18:39:39 +01:00
Damien George
c7a79284bb tests: Enable misc tests on pyboard; output 4 sig figs in rge_sm. 2014-09-06 18:38:55 +01:00
Damien George
e6ce10a3e7 py: Native emitter now supports delete name & global, and end finally. 2014-09-06 18:38:20 +01:00
Paul Sokolovsky
78fde4819c modstruct: Implement 'O', 'P', 's' types for packed structs.
This is required to deal with, well, packed C structs containing pointers.
2014-09-06 20:22:06 +03:00
Paul Sokolovsky
722e562736 py: Correctly set sys.maxsize value for 64-bit.
Type representing signed size doesn't have to be int, so use special value
which defaults to SSIZE_MAX, but as it's not defined by C standard (but rather
by POSIX), allow ports to set it.
2014-09-06 20:22:06 +03:00
Damien George
17598d49e1 unix: Don't use -Wno-error=cpp or #warning; fix strict alias warning.
For the sake of older versions of gcc (and other compilers), don't use
the #warning CPP directive, nor the -Wno-error=cpp option.

Also, fix a strict alias warning in modffi.c for older compilers, and
add a test for ffi module.

Addresses issue #847.
2014-09-06 17:46:52 +01:00
Damien George
8002d5d2b9 py: Fix definition of sys.maxsize with mpz changes. 2014-09-06 17:37:29 +01:00
Damien George
9a21d2e070 py: Make mpz able to use 16 bits per digit; and 32 on 64-bit arch.
Previously, mpz was restricted to using at most 15 bits in each digit,
where a digit was a uint16_t.

With this patch, mpz can use all 16 bits in the uint16_t (improvement
to mpn_div was required).  This gives small inprovements in speed and
RAM usage.  It also yields savings in ROM code size because all of the
digit masking operations become no-ops.

Also, mpz can now use a uint32_t as the digit type, and hence use 32
bits per digit.  This will give decent improvements in mpz speed on
64-bit machines.

Test for big integer division added.
2014-09-06 17:15:34 +01:00
Damien George
afb1cf75dd py: Convert (u)int to mp_(u)int_t in mpz, and remove unused function. 2014-09-05 20:37:06 +01:00
Damien George
e191d42188 py: Use % str formatting instead of {} in makeqstrdata.py.
Script is equivalent, but now also runs under ancient Python 2.6.
Goes part way to addressing issue #847.
2014-09-05 13:16:19 +01:00
Damien George
b534e1b9f1 py: Use variable length encoded uints in more places in bytecode.
Code-info size, block name, source name, n_state and n_exc_stack now use
variable length encoded uints.  This saves 7-9 bytes per bytecode
function for most functions.
2014-09-04 14:44:01 +01:00
Damien George
dda46460ff Code style/whitespace cleanup; remove obsolete headers.
And move the MAP_ANON redefinition from py/asmx64.c to unix/alloc.c.
2014-09-03 22:47:23 +01:00
Damien George
a669cbc690 unix: Auto-detect MICROPY_EMIT_X64 and MICROPY_GCREGS_SETJMP.
If not set, MICROPY_EMIT_X64 is set only if on x86-64 machine.

If not set, MICROPY_GCREGS_SETJMP is set when on MIPS.
2014-09-03 22:40:15 +01:00
Damien George
91fbea2c1e Merge pull request #845 from Vogtinator/master
Add allocation macros (per platform) and ARM cache flush
2014-09-03 22:31:08 +01:00
Fabian Vogt
b7235b8412 Add cache flush in py/asmarm.c and add new MP_PLAT_ALLOC_EXEC and MP_PLAT_FREE_EXEC macros
Fixes issue #840
2014-09-03 23:07:42 +02:00
Damien George
fc54250d31 Merge pull request #844 from chrisdearman/do_str
Declare do_str() function before the implementation
2014-09-03 21:53:48 +01:00
Damien George
27dd910c44 Merge branch 'stinos-msvc-extmod' 2014-09-02 11:39:12 +01:00
Damien George
e875e3882d extmod: Fix type-punned-ptr error. 2014-09-02 11:38:45 +01:00
Damien George
bc9f34860b Merge branch 'msvc-extmod' of github.com:stinos/micropython into stinos-msvc-extmod 2014-09-02 11:37:47 +01:00
stijn
759138caee msvc: Exclude modtermios, include extmod and fix compilation error 2014-09-02 09:00:20 +02:00
Chris Dearman
8c56241c82 Declare do_str() function before the implementation
This ensures that GCC does not discard the do_str implementation in
some cases eg when compiling tests with debug enabled:
  make RUN_TESTS=1 DEBUG=1
2014-09-01 19:51:12 -07:00
Damien George
bad2df3e95 stmhal, modwiznet5k: Add very minimal documentation. 2014-09-01 22:58:22 +01:00
Damien George
bcf041f1a3 stmhal: Add wiznet5k module, to control WIZnet ethernet adaptor.
Allows to create socket objects that support TCP and UDP in server and
client mode.  Interface is very close to standard Python socket class,
except bind and accept do not work the same (due to hardware not
supporting them in the usual way).

Not compiled by default.  To compile this module, use:
make MICROPY_PY_WIZNET5K=1
2014-09-01 22:52:38 +01:00
Damien George
cdd40f149a drivers, wiznet5k: Make DNS service use HAL sys tick. 2014-09-01 22:52:38 +01:00
Damien George
9091e84454 drivers, wiznet5k: Add HAL_Delay(1) to "infinite" loops. 2014-09-01 22:52:38 +01:00
Damien George
7da9145e47 drivers, wiznet5k: Properly fix ARP bug with W5200 chipset. 2014-09-01 22:52:37 +01:00
Damien George
0c0550bff0 drivers, wiznet5k: Add W5200 support. 2014-09-01 22:52:37 +01:00
Damien George
79d17e3e7d drivers, wiznet5k: Change SPI interface to read/write multiple bytes. 2014-09-01 22:52:37 +01:00
Damien George
812cf62f43 drivers, wiznet5k: Fix IP addr verification. 2014-09-01 22:52:37 +01:00
Damien George
71224cb8db drivers: Initial import of WIZnet5x000 driver. 2014-09-01 22:52:37 +01:00
Damien George
e07737d202 Added 'drivers' directory, intended to hold code for specific hardware. 2014-09-01 22:52:37 +01:00
Damien George
90fad65d2f Merge pull request #841 from dhylands/teensy-README
Update teensy README.md file
2014-08-31 00:36:54 +01:00
Dave Hylands
76dd7e180f Update teensy README.md file
Thanks to Artur Wroblewski for some suggested changes.
I also added the TIPs section at the end while I was updating.
2014-08-30 12:21:08 -07:00
Damien George
ca6d75f16d py: Small simplifications in tuple and list accessors. 2014-08-30 15:17:47 +01:00
Damien George
4abff7500f py: Change uint to mp_uint_t in runtime.h, stackctrl.h, binary.h.
Part of code cleanup, working towards resolving issue #50.
2014-08-30 14:59:21 +01:00
Damien George
4d91723587 py: Remove use of int type in obj.h.
Part of code cleanup, working towards resolving issue #50.
2014-08-30 14:28:06 +01:00
Damien George
d182b98a37 py: Change all uint to mp_uint_t in obj.h.
Part of code cleanup, working towards resolving issue #50.
2014-08-30 14:19:41 +01:00
Damien George
9c4cbe2ac0 py: Make tuple and list use mp_int_t/mp_uint_t.
Part of code cleanup, to resolve issue #50.
2014-08-30 14:04:14 +01:00
Damien George
93965e726f py: Make map, dict, set use mp_int_t/mp_uint_t exclusively.
Part of code cleanup, towards resolving issue #50.
2014-08-30 13:23:35 +01:00
Damien George
1c70cbf151 py: Save about 200 bytes of ROM by using smaller type for static table. 2014-08-30 00:38:16 +01:00
Damien George
ecc88e949c Change some parts of the core API to use mp_uint_t instead of uint/int.
Addressing issue #50, still some way to go yet.
2014-08-30 00:35:11 +01:00
Damien George
4d3fc46326 lib, libm: Add back dummy definition of tanf. 2014-08-29 23:24:00 +01:00
Damien George
8707ea3421 lib: Add lib and libm, moving current files from stmhal.
Top-level lib directory is for standard C libraries that we want to
provide our own versions of (for efficiency and stand-alone reasons).
It currently has libm in it for math functions.

Also add atanf and atan2f, which addresses issue #837.
2014-08-29 22:42:26 +01:00
Damien George
17ae2395c2 py: Use memmove instead of memcpy when appropriate.
Found this bug by running unix/ tests with DEBUG=1 enabled when
compiling.
2014-08-29 21:07:54 +01:00
Damien George
02d95d7ce9 py: Fix 2 bugs in native emitter: jump_or_pop and stack settling.
Addresses issue #838.
2014-08-29 20:05:32 +01:00
Damien George
eb4e18f057 py: Add compiler optimisation for conditions in parenthesis.
Optimises:
    if () -> if False
    if (x,...) -> if True
    if (a and b) -> if a and b
2014-08-29 20:04:01 +01:00
Damien George
15d2fe8da4 tests: Add option to run-tests to enable native emitter. 2014-08-29 19:47:10 +01:00
Damien George
110ba35980 py: Move native glue code from runtime.c to new file nativeglue.c.
This way, the native glue code is only compiled if native code is
enabled (which makes complete sense; thanks to Paul Sokolovsky for
the idea).

Should fix issue #834.
2014-08-28 23:37:02 +01:00
Damien George
1ac6faa732 Merge pull request #833 from Vogtinator/arm-native
Basic native ARM emitter
2014-08-28 23:24:43 +01:00
Damien George
516b09efc3 py, gc: Further reduce heap fragmentation with new, faster gc alloc.
The heap allocation is now exactly as it was before the "faster gc
alloc" patch, but it's still nearly as fast.  It is fixed by being
careful to always update the "last free block" pointer whenever the heap
changes (eg free or realloc).

Tested on all tests by enabling EXTENSIVE_HEAP_PROFILING in py/gc.c:
old and new allocator have exactly the same behaviour, just the new one
is much faster.
2014-08-28 23:06:38 +01:00
Damien George
b796e3d848 py: Reduce fragmentation of GC heap.
Recent speed up of GC allocation made the GC have a fragmented heap.
This patch restores "original fragmentation behaviour" whilst still
retaining relatively fast allocation.  This patch works because there is
always going to be a single block allocated now and then, which advances
the gc_last_free_atb_index pointer often enough so that the whole heap
doesn't need scanning.

Should address issue #836.
2014-08-28 10:18:40 +01:00
Fabian Vogt
16ee30c6fa Clarify copyright on asmarm files 2014-08-28 01:18:56 +02:00
Fabian Vogt
fe3d16e8c2 Basic native ARM emitter 2014-08-27 18:18:50 +02:00
Damien George
a97e091d4e Merge branch 'dhylands-int-bytes' 2014-08-27 09:21:41 +01:00
Damien George
a75b02ea9b py: Improve efficiency of MP_OBJ_IS_STR_OR_BYTES.
Saves ROM (16 on stmhal, 240 on 64-bit unix) and should be quicker since
there is 1 less branch.
2014-08-27 09:20:30 +01:00
Damien George
ad4c014d46 Merge branch 'int-bytes' of https://github.com/dhylands/micropython into dhylands-int-bytes 2014-08-27 09:13:15 +01:00
Dave Hylands
b7f7c655ed Make int(b'123') work properly. 2014-08-26 19:15:04 -07:00
Paul Sokolovsky
f3c3010ffc pip-micropython: Revert to using PIP_MICROPY_DEST environment var.
-t/--target is a pip option. Trying to use pip options for different meanings
in pip-micropython may lead to big confusion. That's why the original passed
any extra parameters using environment variables. "All options belong to pip."
2014-08-27 02:53:06 +03:00
Damien George
b427d6ae86 py: Fix line number printing for file with 1 line.
With a file with 1 line (and an error on that line), used to show the
line as number 0.  Now shows it correctly as line number 1.

But, when line numbers are disabled, it now prints line number 1 for any
line that has an error (instead of 0 as previously).  This might end up
being confusing, but requires extra RAM and/or hack logic to make it
print something special in the case of no line numbers.
2014-08-26 23:35:57 +01:00
Damien George
f05b87bd63 Merge pull request #824 from dhylands/sdcard-power
Fix sdcard_power_on to not do anything if the card is already powered on...
2014-08-26 22:58:54 +01:00
Damien George
3b72da674e stmhal, STM32F4DISC: Small changes to ST accel driver. 2014-08-26 22:41:27 +01:00
Damien George
6cf8dd4f51 Merge branch 'siorpaes-master' 2014-08-26 17:31:21 +01:00
Damien George
e00fb08f99 stmhal, staccel.py: Style cleanup. 2014-08-26 17:30:48 +01:00
David Siorpaes
f4ce26de5c Added LIS302DL ID check 2014-08-26 18:23:00 +02:00
Damien George
db63660c19 Add pip-micropython to unix make install.
Also add -t/--target option to pip-micropython to allowing installing to
the pyboard.

Thanks to turbinenreiter/Sebastian Plamauer for the patch.
2014-08-26 16:03:57 +01:00
Damien George
3bb7efc943 stmhal: Hookup USB_VCP.any().
Thanks to Dave Hylands for this patch.
2014-08-26 14:18:22 +01:00
Damien George
cd021bfe56 stmhal: Fix build issues with (old) CC3000 driver.
Addresses issue #825.
2014-08-26 14:13:53 +01:00
Damien George
779794a680 py: Add dispatch for user defined ==, >, <=, >=.
Addresses issue #827.
2014-08-26 09:31:26 +01:00
Damien George
fa1a9bc9fd tests: Add test for pyb.disable_irq and pyb.enable_irq. 2014-08-25 18:44:10 +01:00
Dave Hylands
994bb4a839 Fix sdcard_power_on to not do anything if the card is already powered on. 2014-08-25 10:16:52 -07:00
Damien George
34e43c7ee9 stmhal: Improve efficiency of SysTick IRQ and HAL_Delay.
SysTick IRQ now increases millisecond counter directly (ie without
calling HAL_IncTick).  Provide our own version of HAL_Delay that does a
wfi while waiting.  This more than halves power consumption when running
a loop containing a pyb.delay call.  It used to be like this, but new
version of HAL library regressed this feature.
2014-08-25 18:12:44 +01:00
Damien George
3475b04101 teensy: Fix multiple definition of irq functions. 2014-08-25 18:12:23 +01:00
Damien George
29c92a407c stmhal: Use MP_OBJ_NEW_SMALL_INT directly in pyb.micros/millis.
Also some whitespace cleanup.
2014-08-25 17:38:55 +01:00
Dave Hylands
2bf044442e Add support for pyb.micros() by using the systick timer.
I also removed trailing spaces from modpyb.c which affected a couple
of lines technically not part of this patch.

Tested using: https://github.com/dhylands/upy-examples/blob/master/micros_test.py

which eventually fails due to wraparound issues (I could fix the test to compensate
but didn't bother)
2014-08-25 17:38:55 +01:00
Dave Hylands
8c0add4eee Add save/restore_irq
Factored irq functions into a separate file.
2014-08-25 17:38:55 +01:00
Damien George
e5cbb70328 stmhal: Make enable_irq and disable_irq inline functions.
These functions are generally 1 machine instruction, and are used in
critical code, so makes sense to have them inline.

Also leave these functions uninverted (ie 0 means enable, 1 means
disable) and provide macro constants if you really need to distinguish
the states.  This makes for smaller code as well (combined with
inlining).

Applied to teensy port as well.
2014-08-25 13:24:33 +01:00
Dave Hylands
9480138f0c Add save/restore_irq
Factored irq functions into a separate file.
2014-08-25 12:22:11 +01:00
Damien George
7310fd469a py: Consolidate min/max functions into one, and add key= argument.
Addresses issue #811.
2014-08-24 19:14:09 +01:00
Damien George
1d8a06406a examples: Added pins.py example script to list pin config/af.
Script is due to Dave Hylands.
2014-08-24 18:34:38 +01:00
Damien George
2c4e67e32d stmhal, pin: Update documentation. 2014-08-24 18:30:22 +01:00
Dave Hylands
3d945559d4 Added python script to map AF to a pin name
Added some functions to Pin class to query mode, pull, and af
2014-08-24 18:21:08 +01:00
Damien George
c668d51b08 Merge branch 'dhylands-localtime' 2014-08-24 17:41:31 +01:00
Damien George
8ba832456e stmhal, modtime: Small changes, reduced code size by around 80 bytes.
Also added test for modtime.
2014-08-24 17:40:24 +01:00
Dave Hylands
6678595e7e Add time.mktime and enhance time.localtime (for stmhal)
Now you can use time.localtime on the timestamps presented by os.stat
2014-08-24 17:00:03 +01:00
Damien George
3c658a4e75 py: Fix bug where GC collected native/viper/asm function data.
Because (for Thumb) a function pointer has the LSB set, pointers to
dynamic functions in RAM (eg native, viper or asm functions) were not
being traced by the GC.  This patch is a comprehensive fix for this.

Addresses issue #820.
2014-08-24 16:28:17 +01:00
Damien George
25fc41dd31 unix, modtermios: Make it properly configurable; fix spelling mistake. 2014-08-24 13:19:22 +01:00
Paul Sokolovsky
4f9ebade60 modtermios: Add "termios" unix module, subset of CPython's.
Also provides setraw() function from "tty" module (which in CPython is
implemented in Python). The idea here is that 95% of "termios" module usage
is to set raw mode to allow access to normal serial devices. Then, instead
of exporting gazillion termios symbols, it's better to implement it in C,
and export minimal number of symbols (mostly baud rates and drain values).
2014-08-23 06:09:46 +03:00
Damien George
72b115cbaa extmod, zlibd: Make some simple ROM and RAM savings.
ROM down by 320 bytes on stmhal.  RAM down by 5.5k for a decompression
object.
2014-08-22 18:38:16 +01:00
Damien George
26a0d4f4f1 py: Change hash and len members of str from 16 bit to full word.
This allows to make strings longer than 64k.  It doesn't use any more
RAM with current GC because a str object still fits in a GC block.
2014-08-22 18:34:28 +01:00
Damien George
69b7dae362 py: Small cleanup in stream.c. 2014-08-22 18:30:02 +01:00
Damien George
d5e7f6e37e py: Speed up GC allocation.
This simple patch gives a very significant speed up for memory allocation
with the GC.

Eg, on PYBv1.0:
tests/basics/dict_del.py: 3.55 seconds -> 1.19 seconds
tests/misc/rge_sm.py:     15.3 seconds -> 2.48 seconds
2014-08-22 18:17:02 +01:00
Paul Sokolovsky
13ec400f28 Merge pull request #796 from turbinenreiter/makeinstall
unix: Added install/uninstall
2014-08-18 22:29:37 +03:00
Damien George
7fe2191c9b py: Code clean-up in native emitter; improve thumb native calls. 2014-08-16 22:31:57 +01:00
Damien George
86de21b810 py: Viper can call functions with native types, and raise exceptions. 2014-08-16 22:06:11 +01:00
Damien George
339bdccc58 Merge pull request #803 from dhylands/ld-opt
Put some code into the first 16K of flash
2014-08-16 16:09:39 +01:00
Dave Hylands
3688414d9d Put some code into the first 16K of flash
This basically shrinks the remaining size of flash in the portion
that goes after the internal flash drive.
2014-08-16 08:00:12 -07:00
Damien George
8f81b5cb4b py: Put SystemExit in builtin namespace.
Also fix unix port so that SystemExit with no arg exits with value 0.
2014-08-16 14:32:06 +01:00
Damien George
b63be37be1 stmhal: In safe mode, still mount SD card and present as MSD over USB.
It's still "safe" because no scripts are run.  Remove the SD card if you
want to access the internal flash filesystem.  Addresses issue #616.

Also: remove obsolete pyb.source_dir setting, and reset pyb.main and
pyb.usb_mode settings on soft-reset.
2014-08-16 14:23:22 +01:00
Damien George
b0accc8571 stmhal: Fix printing of pin name in error message. 2014-08-16 13:56:19 +01:00
Damien George
d779b9642f tests: Wait for just over 1 sec when testing RTC.
Waiting for 1000ms between seconds of RTC is sometimes too quick.
Waiting for 1001ms is enough for the RTC to pass 1 second.
2014-08-16 13:39:14 +01:00
Damien George
244476e3e6 stmhal: For non-debug compile, enable CC/LD opt to remove dead code.
Saves over 35k ROM due to elimination of unused HAL functions.  All
tests pass.

Addresses issue #702.
2014-08-16 13:37:05 +01:00
Damien George
c84aa41990 Merge branch 'danpeirce-master' 2014-08-16 11:56:16 +01:00
Dan Peirce
f0c3a7e781 teensy/README.md (corrected typo) 2014-08-16 11:54:36 +01:00
Dan Peirce
6009309c33 modified: teensy/README.md
Updated teensy/README.md to reflect change in build process (teensyduino is no
longer required for build).
2014-08-16 11:54:36 +01:00
Damien George
e6c0dff967 py: Viper can now store to global. 2014-08-15 23:47:59 +01:00
Damien George
a5190a7dac py: Fix typing of viper locals; allow default types in annotation. 2014-08-15 22:39:08 +01:00
Damien George
2ac4af6946 py: Allow viper to have type annotations.
Viper functions can now be annotated with the type of their arguments
and return value.  Eg:

@micropython.viper
def f(x:int) -> int:
    return x + 1
2014-08-15 16:45:41 +01:00
Damien George
6be0b0a8ec py: Clean up and simplify functions in scope; add STATIC in compiler.
Some small code clean-ups that result in about 80 bytes ROM saving for
stmhal.
2014-08-15 14:30:52 +01:00
Damien George
bf133f7737 stmhal: Resolve question in comment about timer clock. 2014-08-14 00:30:14 +01:00
Damien George
2c781eabbd Merge pull request #798 from stinos/msvc-alignof
msvc: Use built-in alignof
2014-08-13 13:34:41 +01:00
Damien George
9b7a8ee8f1 py: Fix mult by negative number of tuple, list, str, bytes.
Multiplication of a tuple, list, str or bytes now yields an empty
sequence (instead of crashing).  Addresses issue #799

Also added ability to mult bytes on LHS by integer.
2014-08-13 13:22:24 +01:00
stijn
8cce8b7c4c msvc: Use built-in alignof
This also fixes a 'unnamed type definition in parentheses' warning on the
alignof implementation define in binary.c
2014-08-13 10:19:56 +02:00
Sebastian Plamauer
2eeeafcba5 added install/uninstall 2014-08-11 19:47:00 +02:00
266 changed files with 21152 additions and 2869 deletions

View File

@@ -20,6 +20,7 @@ script:
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
- (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests)
- (cd tests && MICROPY_CPYTHON3=python3.3 ./run-tests --emit native)
after_failure:
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)

View File

@@ -40,6 +40,17 @@ Header files:
Type names and declarations:
- When defining a type, put '_t' after it.
Integer types: Micro Python runs on 32 and 64 bit machines (and one day
maybe 16 bit), so it's important to use the correctly-sized (and signed)
integer types. The general guidelines are:
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
integer values. These are guaranteed to be machine-word sized and
therefore big enough to hold the value from a Micro Python small-int
object.
- Use size_t for things that count bytes / sizes of objects.
- You can use int/uint, but remember that they may be 16-bits wide.
- If in doubt, use mp_int_t/mp_uint_t.
Examples
--------

View File

@@ -35,7 +35,6 @@ void do_str(const char *src) {
qstr source_name = mp_lexer_source_name(lex);
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
mp_parse_node_free(pn);
if (module_fun == mp_const_none) {
// compile error

View File

@@ -17,6 +17,7 @@
#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)
@@ -35,6 +36,8 @@
#define BYTES_PER_WORD (4)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
#define UINT_FMT "%lu"
#define INT_FMT "%ld"
@@ -44,7 +47,7 @@ typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
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 },

177
docs/Makefile Normal file
View File

@@ -0,0 +1,177 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/MicroPython.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/MicroPython.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/MicroPython"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/MicroPython"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

269
docs/conf.py Normal file
View File

@@ -0,0 +1,269 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Micro Python documentation build configuration file, created by
# sphinx-quickstart on Sun Sep 21 11:42:03 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
]
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Micro Python'
copyright = '2014, Damien P. George'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.3'
# The full version, including alpha/beta/rc tags.
release = '1.3.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'MicroPythondoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'MicroPython.tex', 'Micro Python Documentation',
'Damien P. George', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'micropython', 'Micro Python Documentation',
['Damien P. George'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'MicroPython', 'Micro Python Documentation',
'Damien P. George', 'MicroPython', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}

59
docs/general.rst Normal file
View File

@@ -0,0 +1,59 @@
General information about the pyboard
=====================================
Local filesystem and SD card
----------------------------
There is a small internal filesystem (a drive) on the pyboard, called ``/flash``,
which is stored within the microcontroller's flash memory. If a micro SD card
is inserted into the slot, it is available as ``/sd``.
When the pyboard boots up, it needs to choose a filesystem to boot from. If
there is no SD card, then it uses the internal filesystem ``/flash`` as the boot
filesystem, otherwise, it uses the SD card ``/sd``.
(Note that on older versions of the board, ``/flash`` is called ``0:/`` and ``/sd``
is called ``1:/``).
The boot filesystem is used for 2 things: it is the filesystem from which
the ``boot.py`` and ``main.py`` files are searched for, and it is the filesystem
which is made available on your PC over the USB cable.
The filesystem will be available as a USB flash drive on your PC. You can
save files to the drive, and edit ``boot.py`` and ``main.py``.
*Remember to eject (on Linux, unmount) the USB drive before you reset your
pyboard.*
Boot modes
----------
If you power up normally, or press the reset button, the pyboard will boot
into standard mode: the ``boot.py`` file will be executed first, then the
USB will be configured, then ``main.py`` will run.
You can override this boot sequence by holding down the user switch as
the board is booting up. Hold down user switch and press reset, and then
as you continue to hold the user switch, the LEDs will count in binary.
When the LEDs have reached the mode you want, let go of the user switch,
the LEDs for the selected mode will flash quickly, and the board will boot.
The modes are:
1. Green LED only, *standard boot*: run ``boot.py`` then ``main.py``.
2. Orange LED only, *safe boot*: don't run any scripts on boot-up.
3. Green and orange LED together, *filesystem reset*: resets the flash
filesystem to its factory state, then boots in safe mode.
If your filesystem becomes corrupt, boot into mode 3 to fix it.
Errors: flashing LEDs
---------------------
There are currently 2 kinds of errors that you might see:
1. If the red and green LEDs flash alternatively, then a Python script
(eg ``main.py``) has an error. Use the REPL to debug it.
2. If all 4 LEDs cycle on and off slowly, then there was a hard fault.
This cannot be recovered from and you need to do a hard reset.

43
docs/index.rst Normal file
View File

@@ -0,0 +1,43 @@
.. Micro Python documentation master file
Micro Python documentation and references
=========================================
Here you can find documentation for Micro Python and the pyboard.
Software
--------
.. toctree::
:maxdepth: 2
general.rst
tutorial/index.rst
..
.. - Reference for the [pyb module](module/pyb/ "pyb module").
.. - Reference for [all modules](module/ "all modules").
.. - [Guide for setting up the pyboard on Windows](/static/doc/Micro-Python-Windows-setup.pdf), including DFU programming (PDF).
The pyboard hardware
--------------------
.. - PYBv1.0 [schematics and layout](/static/doc/PYBv10b.pdf "PYBv1.0") (2.4MiB PDF).
.. - PYBv1.0 [metric dimensions](/static/doc/PYBv10b-metric-dimensions.pdf "metric dimensions") (360KiB PDF).
.. - PYBv1.0 [imperial dimensions](/static/doc/PYBv10b-imperial-dimensions.pdf "imperial dimensions") (360KiB PDF).
Datasheets for the components on the pyboard
--------------------------------------------
.. - The microcontroller: [STM32F405RGT6](http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN1035/PF252144) (external link).
.. - The accelerometer: [Freescale MMA7660](/static/doc/MMA7660FC.pdf) (800kiB PDF).
.. - The LDO voltage regulator: [Microchip MCP1802](/static/doc/MCP1802-22053C.pdf) (400kiB PDF).
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

242
docs/make.bat Normal file
View File

@@ -0,0 +1,242 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\MicroPython.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\MicroPython.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

92
docs/tutorial/accel.rst Normal file
View File

@@ -0,0 +1,92 @@
The accelerometer
=================
Here you will learn how to read the accelerometer and signal using LEDs states like tilt left and tilt right.
Using the accelerometer
-----------------------
The pyboard has an accelerometer (a tiny mass on a tiny spring) that can be used
to detect the angle of the board and motion. There is a different sensor for
each of the x, y, z directions. To get the value of the accelerometer, create a
pyb.Accel() object and then call the x() method. ::
>>> accel = pyb.Accel()
>>> accel.x()
7
This returns a signed integer with a value between around -30 and 30. Note that
the measurement is very noisy, this means that even if you keep the board
perfectly still there will be some variation in the number that you measure.
Because of this, you shouldn't use the exact value of the x() method but see if
it is in a certain range.
We will start by using the accelerometer to turn on a light if it is not flat. ::
accel = pyb.Accel()
light = pyb.LED(3)
SENSITIVITY = 3
while True:
x = accel.x()
if abs(x) > SENSITIVITY:
light.on()
else:
light.off()
pyb.delay(100)
We create Accel and LED objects, then get the value of the x direction of the
accelerometer. If the magnitude of x is bigger than a certain value ``SENSITIVITY``,
then the LED turns on, otherwise it turns off. The loop has a small ``pyb.delay()``
otherwise the LED flashes annoyingly when the value of x is close to
``SENSITIVITY``. Try running this on the pyboard and tilt the board left and right
to make the LED turn on and off.
**Exercise: Change the above script so that the blue LED gets brighter the more
you tilt the pyboard. HINT: You will need to rescale the values, intensity goes
from 0-255.**
Making a spirit level
---------------------
The example above is only sensitive to the angle in the x direction but if we
use the ``y()`` value and more LEDs we can turn the pyboard into a spirit level. ::
xlights = (pyb.LED(2), pyb.LED(3))
ylights = (pyb.LED(1), pyb.LED(4))
accel = pyb.Accel()
SENSITIVITY = 3
while True:
x = accel.x()
if x > SENSITIVITY:
xlights[0].on()
xlights[1].off()
elif x < -SENSITIVITY:
xlights[1].on()
xlights[0].off()
else:
xlights[0].off()
xlights[1].off()
y = accel.y()
if y > SENSITIVITY:
ylights[0].on()
ylights[1].off()
elif y < -SENSITIVITY:
ylights[1].on()
ylights[0].off()
else:
ylights[0].off()
ylights[1].off()
pyb.delay(100)
We start by creating a tuple of LED objects for the x and y directions. Tuples
are immutable objects in python which means they can't be modified once they are
created. We then proceed as before but turn on a different LED for positive and
negative x values. We then do the same for the y direction. This isn't
particularly sophisticated but it does the job. Run this on your pyboard and you
should see different LEDs turning on depending on how you tilt the board.

View File

@@ -0,0 +1,65 @@
The AMP audio skin
==================
Soldering and using the AMP audio skin.
.. image:: http://micropython.org/static/doc/skin-amp-1.jpg
:alt: AMP skin
:width: 250px
.. image:: http://micropython.org/static/doc/skin-amp-3.jpg
:alt: AMP skin
:width: 250px
The following video shows how to solder the headers, microphone and speaker onto the AMP skin.
.. raw:: html
<iframe style="margin-left:3em;" width="560" height="315" src="http://www.youtube.com/embed/fjB1DuZRveo?rel=0" frameborder="0" allowfullscreen></iframe>
Example code
------------
The AMP skin has a speaker which is connected to ``DAC(1)`` via a small
power amplifier. The volume of the amplifier is controlled by a digital
potentiometer, which is an I2C device with address 46 on the ``IC2(1)`` bus.
To set the volume, define the following function::
def volume(val):
pyb.I2C(1, pyb.I2C.MASTER).mem_write(val, 46, 0)
Then you can do::
>>> volume(0) # minimum volume
>>> volume(127) # maximum volume
To play a sound, use the ``write_timed`` method of the ``DAC`` object.
For example::
import math
from pyb import DAC
# create a buffer containing a sine-wave
buf = bytearray(100)
for i in range(len(buf)):
buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))
# output the sine-wave at 400Hz
dac = DAC(1)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
You can also play WAV files using the Python ``wave`` module. You can get
the wave module [here](/static/doc/examples/wave.py) and you will also need
the chunk module available [here](/static/doc/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](/static/doc/examples/test.wav). Then you can do::
>>> import wave
>>> from pyb import DAC
>>> dac = DAC(1)
>>> f = wave.open('test.wav')
>>> dac.write_timed(f.readframes(f.getnframes()), f.getframerate())
This should play the WAV file.

123
docs/tutorial/assembler.rst Normal file
View File

@@ -0,0 +1,123 @@
Inline assembler
================
Here you will learn how to write inline assembler in Micro Python.
**Note**: this is an advanced tutorial, intended for those who already
know a bit about microcontrollers and assembly language.
Micro Python includes an inline assembler. It allows you to write
assembly routines as a Python function, and you can call them as you would
a normal Python function.
Returning a value
-----------------
Inline assembler functions are denoted by a special function decorator.
Let's start with the simplest example::
@micropython.asm_thumb
def fun():
movw(r0, 42)
You can enter this in a script or at the REPL. This function takes no
arguments and returns the number 42. ``r0`` is a register, and the value
in this register when the function returns is the value that is returned.
Micro Python always interprets the ``r0`` as an integer, and converts it to an
integer object for the caller.
If you run ``print(fun())`` you will see it print out 42.
Accessing peripherals
---------------------
For something a bit more complicated, let's turn on an LED::
@micropython.asm_thumb
def led_on():
movwt(r0, stm.GPIOA)
movw(r1, 1 << 13)
strh(r1, [r0, stm.GPIO_BSRRL])
This code uses a few new concepts:
- ``stm`` is a module which provides a set of constants for easy
access to the registers of the pyboard's microcontroller. Try
running ``import stm`` and then ``help(stm)`` at the REPL. It will
give you a list of all the available constants.
- ``stm.GPIOA`` is the address in memory of the GPIOA peripheral.
On the pyboard, the red LED is on port A, pin PA13.
- ``movwt`` moves a 32-bit number into a register. It is a convenience
function that turns into 2 thumb instructions: ``movw`` followed by ``movt``.
The ``movt`` also shifts the immediate value right by 16 bits.
- ``strh`` stores a half-word (16 bits). The instruction above stores
the lower 16-bits of ``r1`` into the memory location ``r0 + stm.GPIO_BSRRL``.
This has the effect of setting high all those pins on port A for which
the corresponding bit in ``r0`` is set. In our example above, the 13th
bit in ``r0`` is set, so PA13 is pulled high. This turns on the red LED.
Accepting arguments
-------------------
Inline assembler functions can accept up to 3 arguments. If they are
used, they must be named ``r0``, ``r1`` and ``r2`` to reflect the registers
and the calling conventions.
Here is a function that adds its arguments::
@micropython.asm_thumb
def asm_add(r0, r1):
add(r0, r0, r1)
This performs the computation ``r0 = r0 + r1``. Since the result is put
in ``r0``, that is what is returned. Try ``asm_add(1, 2)``, it should return
3.
Loops
-----
We can assign labels with ``label(my_label)``, and branch to them using
``b(my_label)``, or a conditional branch like ``bgt(my_label)``.
The following example flashes the green LED. It flashes it ``r0`` times. ::
@micropython.asm_thumb
def flash_led(r0):
# get the GPIOA address in r1
movwt(r1, stm.GPIOA)
# get the bit mask for PA14 (the pin LED #2 is on)
movw(r2, 1 << 14)
b(loop_entry)
label(loop1)
# turn LED on
strh(r2, [r1, stm.GPIO_BSRRL])
# delay for a bit
movwt(r4, 5599900)
label(delay_on)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_on)
# turn LED off
strh(r2, [r1, stm.GPIO_BSRRH])
# delay for a bit
movwt(r4, 5599900)
label(delay_off)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_off)
# loop r0 times
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)

35
docs/tutorial/index.rst Normal file
View File

@@ -0,0 +1,35 @@
.. _tutorial-index:
Micro Python tutorial
=====================
This tutorial is intended to get you started with your pyboard.
All you need is a pyboard and a micro-USB cable to connect it to
your PC. If it is your first time, it is recommended to follow
the tutorial through in the order below.
.. toctree::
:maxdepth: 1
:numbered:
intro.rst
script.rst
repl.rst
leds.rst
switch.rst
accel.rst
reset.rst
usb_mouse.rst
timer.rst
assembler.rst
Tutorials requiring extra components
------------------------------------
.. toctree::
:maxdepth: 1
:numbered:
servo.rst
lcd_skin.rst
amp_skin.rst

54
docs/tutorial/intro.rst Normal file
View File

@@ -0,0 +1,54 @@
Introduction to the pyboard
===========================
To get the most out of your pyboard, there are a few basic things to
understand about how it works.
Caring for your pyboard
-----------------------
Because the pyboard does not have a housing it needs a bit of care:
- Be gentle when plugging/unplugging the USB cable. Whilst the USB connector
is soldered through the board and is relatively strong, if it breaks off
it can be very difficult to fix.
- Static electricity can shock the components on the pyboard and destroy them.
If you experience a lot of static electricity in your area (eg dry and cold
climates), take extra care not to shock the pyboard. If your pyboard came
in a black plastic box, then this box is the best way to store and carry the
pyboard as it is an anti-static box (it is made of a conductive plastic, with
conductive foam inside).
As long as you take care of the hardware, you should be okay. It's almost
impossible to break the software on the pyboard, so feel free to play around
with writing code as much as you like. If the filesystem gets corrupt, see
below on how to reset it. In the worst case you might need to reflash the
Micro Python software, but that can be done over USB.
Layout of the pyboard
---------------------
The micro USB connector is on the top right, the micro SD card slot on
the top left of the board. There are 4 LEDs between the SD slot and
USB connector. The colours are: red on the bottom, then green, orange,
and blue on the top. There are 2 switches: the right one is the reset
switch, the left is the user switch.
Plugging in and powering on
---------------------------
The pyboard can be powered via USB. Connect it to your PC via a micro USB
cable. There is only one way that the cable will fit. Once connected,
the green LED on the board should flash quickly.
Powering by an external power source
------------------------------------
The pyboard can be powered by a battery or other external power source.
**Be sure to connect the positive lead of the power supply to VIN, and
ground to GND. There is no polarity protection on the pyboard so you
must be careful when connecting anything to VIN.**
**The input voltage must be between 3.6V and 10V.**

View File

@@ -0,0 +1,81 @@
The LCD and touch-sensor skin
=============================
Soldering and using the LCD and touch-sensor skin.
.. image:: http://micropython.org/static/doc/skin-lcd-3.jpg
:alt: pyboard with LCD skin
:width: 250px
.. image:: http://micropython.org/static/doc/skin-lcd-1.jpg
:alt: pyboard with LCD skin
:width: 250px
The following video shows how to solder the headers onto the LCD skin.
At the end of the video, it shows you how to correctly connect the LCD skin to the pyboard.
.. raw:: html
<iframe style="margin-left:3em;" width="560" height="315" src="http://www.youtube.com/embed/PowCzdLYbFM?rel=0" frameborder="0" allowfullscreen></iframe>
Using the LCD
-------------
To get started using the LCD, try the following at the Micro Python prompt.
Make sure the LCD skin is attached to the pyboard as pictured at the top of this page. ::
>>> lcd = pyb.LCD('X')
>>> lcd.light(True)
>>> lcd.write('Hello uPy!\n')
You can make a simple animation using the code::
lcd = pyb.LCD('X')
lcd.light(True)
for x in range(-80, 128):
lcd.fill(0)
lcd.text('Hello uPy!', x, 10, 1)
lcd.show()
pyb.delay(25)
Using the touch sensor
----------------------
To read the touch-sensor data you need to use the I2C bus. The
MPR121 capacitive touch sensor has address 90.
To get started, try::
>>> i2c = pyb.I2C(1, pyb.I2C.MASTER)
>>> i2c.mem_write(4, 90, 0x5e)
>>> touch = i2c.mem_read(1, 90, 0)[0]
The first line above makes an I2C object, and the second line
enables the 4 touch sensors. The third line reads the touch
status and the ``touch`` variable holds the state of the 4 touch
buttons (A, B, X, Y).
There is a simple driver [here](/static/doc/examples/mpr121.py)
which allows you to set the threshold and debounce parameters, and
easily read the touch status and electrode voltage levels. Copy
this script to your pyboard (either flash or SD card, in the top
directory or ``lib/`` directory) and then try::
>>> import pyb
>>> import mpr121
>>> m = mpr121.MPR121(pyb.I2C(1, pyb.I2C.MASTER))
>>> for i in range(100):
... print(m.touch_status())
... pyb.delay(100)
...
This will continuously print out the touch status of all electrodes.
Try touching each one in turn.
Note that if you put the LCD skin in the Y-position, then you need to
initialise the I2C bus using::
>>> m = mpr121.MPR121(pyb.I2C(2, pyb.I2C.MASTER))
There is also a demo which uses the LCD and the touch sensors together,
and can be found [here](/static/doc/examples/lcddemo.py).

75
docs/tutorial/leds.rst Normal file
View File

@@ -0,0 +1,75 @@
Turning on LEDs and basic Python concepts
=========================================
The easiest thing to do on the pyboard is to turn on the LEDs attached to the board. Connect the board, and log in as described in tutorial 1. We will start by turning and LED on in the interpreter, type the following ::
>>> myled = pyb.LED(1)
>>> myled.on()
>>> myled.off()
These commands turn the LED on and off.
This is all very well but we would like this process to be automated. Open the file MAIN.PY on the pyboard in your favourite text editor. Write or paste the following lines into the file. If you are new to python, then make sure you get the indentation correct since this matters! ::
led = pyb.LED(2)
while True:
led.toggle()
pyb.delay(1000)
When you save, the red light on the pyboard should turn on for about a second. To run the script, do a soft reset (CTRL-D). The pyboard will then restart and you should see a green light continuously flashing on and off. Success, the first step on your path to building an army of evil robots! When you are bored of the annoying flashing light then press CTRL-C at your terminal to stop it running.
So what does this code do? First we need some terminology. Python is an object-oriented language, almost everything in python is a *class* and when you create an instance of a class you get an *object*. Classes have *methods* associated to them. A method (also called a member function) is used to interact with or control the object.
The first line of code creates an LED object which we have then called led. When we create the object, it takes a single parameter which must be between 1 and 4, corresponding to the 4 LEDs on the board. The pyb.LED class has three important member functions that we will use: on(), off() and toggle(). The other function that we use is pyb.delay() this simply waits for a given time in miliseconds. Once we have created the LED object, the statement while True: creates an infinite loop which toggles the led between on and off and waits for 1 second.
**Exercise: Try changing the time between toggling the led and turning on a different LED.**
**Exercise: Connect to the pyboard directly, create a pyb.LED object and turn it on using the on() method.**
A Disco on your pyboard
-----------------------
So far we have only used a single LED but the pyboard has 4 available. Let's start by creating an object for each LED so we can control each of them. We do that by creating a list of LEDS with a list comprehension. ::
leds = [pyb.LED(i) for i in range(1,5)]
If you call pyb.LED() with a number that isn't 1,2,3,4 you will get an error message.
Next we will set up an infinite loop that cycles through each of the LEDs turning them on and off. ::
n = 0
while True:
n = (n + 1) % 4
leds[n].toggle()
pyb.delay(50)
Here, n keeps track of the current LED and every time the loop is executed we cycle to the next n (the % sign is a modulus operator that keeps n between 0 and 4.) Then we access the nth LED and toggle it. If you run this you should see each of the LEDs turning on then all turning off again in sequence.
One problem you might find is that if you stop the script and then start it again that the LEDs are stuck on from the previous run, ruining our carefully choreographed disco. We can fix this by turning all the LEDs off when we initialise the script and then using a try/finally block. When you press CTRL-C, Micro Python generates a VCPInterrupt exception. Exceptions normally mean something has gone wrong and you can use a try: command to "catch" an exception. In this case it is just the user interrupting the script, so we don't need to catch the error but just tell Micro Python what to do when we exit. The finally block does this, and we use it to make sure all the LEDs are off. The full code is::
leds = [pyb.LED(i) for i in range(1,5)]
for l in leds:
l.off()
n = 0
try:
while True:
n = (n + 1) % 4
leds[n].toggle()
pyb.delay(50)
finally:
for l in leds:
l.off()
The Fourth Special LED
----------------------
The blue LED is special. As well as turning it on and off, you can control the intensity using the intensity() method. This takes a number between 0 and 255 that determines how bright it is. The following script makes the blue LED gradually brighter then turns it off again. ::
led = pyb.LED(4)
intensity = 0
while True:
intensity = (intensity + 1) % 255
led.intensity(intensity)
pyb.delay(20)
You can call intensity() on the other LEDs but they can only be off or on. 0 sets them off and any other number up to 255 turns them on.

107
docs/tutorial/repl.rst Normal file
View File

@@ -0,0 +1,107 @@
Getting a Micro Python REPL prompt
==================================
REPL stands for Read Evaluate Print Loop, and is the name given to the
interactive Micro Python prompt that you can access on the pyboard. Using
the REPL is by far the easiest way to test out your code and run commands.
You can use the REPL in addition to writing scripts in ``main.py``.
To use the REPL, you must connect to the serial USB device on the pyboard.
How you do this depends on your operating system.
Windows
-------
You need to install the pyboard driver to use the serial USB device.
The driver is on the pyboard's USB flash drive, and is called ``pybcdc.inf``.
To install this driver you need to go to Device Manager
for your computer, find the pyboard in the list of devices (it should have
a warning sign next to it because it's not working yet), right click on
the pyboard device, select Properties, then Install Driver. You need to
then select the option to find the driver manually (don't use Windows auto update),
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).
You now need to run your terminal program. You can use HyperTerminal if you
have it installed, or download the free program PuTTY:
[`putty.exe`](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html).
Using your serial program you must connect to the COM port that you found in the
previous step. With PuTTY, click on "Session" in the left-hand panel, then click
the "Serial" radio button on the right, then enter you COM port (eg COM4) in the
"Serial Line" box. Finally, click the "Open" button.
Mac OS X
--------
Open a terminal and run::
screen /dev/tty.usbmodem*
When you are finishend and want to exit screen, type CTRL-A CTRL-\\.
Linux
-----
Open a terminal and run::
screen /dev/ttyACM0
You can also try ``picocom`` or ``minicom`` instead of screen. You may have to
use ``/dev/ttyACM1`` or a higher number for ``ttyACM``. And, you may need to give
yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``,
or use sudo).
Using the REPL prompt
---------------------
Now let's try running some Micro Python code directly on the pyboard.
With your serial program open (PuTTY, screen, picocom, etc) you may see a blank
screen with a flashing cursor. Press Enter and you should be presented with a
Micro Python prompt, i.e. ``>>>``. Let's make sure it is working with the obligatory test::
>>> print("hello pyboard!")
hello pyboard!
In the above, you should not type in the ``>>>`` characters. They are there to
indicate that you should type the text after it at the prompt. In the end, once
you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output
on your screen should look like it does above.
If you already know some python you can now try some basic commands here.
If any of this is not working you can try either a hard reset or a soft reset;
see below.
Go ahead and try typing in some other commands. For example::
>>> pyb.LED(1).on()
>>> pyb.LED(2).on()
>>> 1 + 2
3
>>> 1 / 2
0.5
>>> 20 * 'py'
'pypypypypypypypypypypypypypypypypypypypy'
Resetting the board
-------------------
If something goes wrong, you can reset the board in two ways. The first is to press CTRL-D
at the Micro Python prompt, which performs a soft reset. You will see a message something like ::
>>>
PYB: sync filesystems
PYB: soft reboot
Micro Python v1.0 on 2014-05-03; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>>
If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the RST
switch (the small black button closest to the micro-USB socket on the board). This will end your
session, disconnecting whatever program (PuTTY, screen, etc) that you used to connect to the pyboard.
If you are going to do a hard-reset, it's recommended to first close your serial program and eject/unmount
the pyboard drive.

60
docs/tutorial/reset.rst Normal file
View File

@@ -0,0 +1,60 @@
Safe mode and factory reset
===========================
If something goes wrong with your pyboard, don't panic! It is almost
impossible for you to break the pyboard by programming the wrong thing.
The first thing to try is to enter safe mode: this temporarily skips
execution of ``boot.py`` and ``main.py`` and gives default USB settings.
If you have problems with the filesystem you can do a factory reset,
which restores the filesystem to its original state.
Safe mode
---------
To enter safe mode, do the following steps:
1. Connect the pyboard to USB so it powers up.
2. Hold down the USR switch.
3. While still holding down USR, press and release the RST switch.
4. The LEDs will then cycle green to orange to green+orange and back again.
5. Keep holding down USR until *only the orange LED is lit*, and then let
go of the USR switch.
6. The orange LED should flash quickly 4 times, and then turn off.
7. You are now in safe mode.
In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
the pyboard boots up with default settings. This means you now have access
to the filesystem (the USB drive should appear), and you can edit ``boot.py``
and ``main.py`` to fix any problems.
Entering safe mode is temporary, and does not make any changes to the
files on the pyboard.
Factory reset the filesystem
----------------------------
If you pyboard's filesystem gets corrupted (for example, you forgot to
eject/unmount it), or you have some code in ``boot.py`` or ``main.py`` which
you can't escape from, then you can reset the filesystem.
Resetting the filesystem deletes all files on the internal pyboard storage
(not the SD card), and restores the files ``boot.py``, ``main.py``, ``README.txt``
and ``pybcdc.inf`` back to their original state.
To do a factory reset of the filesystem you follow a similar procedure as
you did to enter safe mode, but release USR on green+orange:
1. Connect the pyboard to USB so it powers up.
2. Hold down the USR switch.
3. While still holding down USR, press and release the RST switch.
4. The LEDs will then cycle green to orange to green+orange and back again.
5. Keep holding down USR until *both the green and orange LEDs are lit*, and
then let go of the USR switch.
6. The green and orange LEDs should flash quickly 4 times.
7. The red LED will turn on (so red, green and orange are now on).
8. The pyboard is now resetting the filesystem (this takes a few seconds).
9. The LEDs all turn off.
10. You now have a reset filesystem, and are in safe mode.
11. Press and release the RST switch to boot normally.

105
docs/tutorial/script.rst Normal file
View File

@@ -0,0 +1,105 @@
Running your first script
=========================
Let's jump right in and get a Python script running on the pyboard. After
all, that's what it's all about!
Connecting your pyboard
-----------------------
Connect your pyboard to your PC (Windows, Mac or Linux) with a micro USB cable.
There is only one way that the cable will connect, so you can't get it wrong.
<img src="/static/doc/pyboard-usb-micro.jpg" alt="pyboard with USB micro cable" style="width:200px; border:1px solid black; display:inline-block;"/>
When the pyboard is connected to your PC it will power on and enter the start up
process (the boot process). The green LED should light up for half a second or
less, and when it turns off it means the boot process has completed.
Opening the pyboard USB drive
-----------------------------
Your PC should now recognise the pyboard. It depends on the type of PC you
have as to what happens next:
- **Windows**: Your pyboard will appear as a removable USB flash drive.
Windows may automatically pop-up a window, or you may need to go there
using Explorer.
Windows will also see that the pyboard has a serial device, and it will
try to automatically configure this device. If it does, cancel the process.
We will get the serial device working in the next tutorial.
- **Mac**: Your pyboard will appear on the desktop as a removable disc.
It will probably be called "NONAME". Click on it to open the pyboard folder.
- **Linux**: Your pyboard will appear as a removable medium. On Ubuntu
it will mount automatically and pop-up a window with the pyboard folder.
On other Linux distributions, the pyboard may be mounted automatically,
or you may need to do it manually. At a terminal command line, type ``lsblk``
to see a list of connected drives, and then ``mount /dev/sdb1`` (replace ``sdb1``
with the appropriate device). You may need to be root to do this.
Okay, so you should now have the pyboard connected as a USB flash drive, and
a window (or command line) should be showing the files on the pyboard drive.
The drive you are looking at is known as ``/flash`` by the pyboard, and should contain
the following 4 files:
- [``boot.py``](/static/doc/fresh-pyboard/boot.py) -- this script is executed when the pyboard boots up. It sets
up various configuration options for the pyboard.
- [``main.py``](/static/doc/fresh-pyboard/main.py) -- this is the main script that will contain your Python program.
It is executed after ``boot.py``.
- [``README.txt``](/static/doc/fresh-pyboard/README.txt) -- this contains some very basic information about getting
started with the pyboard.
- [``pybcdc.inf``](/static/doc/fresh-pyboard/pybcdc.inf) -- this is a Windows driver file to configure the serial USB
device. More about this in the next tutorial.
Editing ``main.py``
-------------------
Now we are going to write our Python program, so open the ``main.py``
file in a text editor. On Windows you can use notepad, or any other editor.
On Mac and Linux, use your favourite text editor. With the file open you will
see it contains 1 line::
# main.py -- put your code here!
This line starts with a # character, which means that it is a *comment*. Such
lines will not do anything, and are there for you to write notes about your
program.
Let's add 2 lines to this ``main.py`` file, to make it look like this::
# main.py -- put your code here!
import pyb
pyb.LED(4).on()
The first line we wrote says that we want to use the ``pyb`` module.
This module contains all the functions and classes to control the features
of the pyboard.
The second line that we wrote turns the blue LED on: it first gets the ``LED``
class from the ``pyb`` module, creates LED number 4 (the blue LED), and then
turns it on.
Resetting the pyboard
---------------------
To run this little script, you need to first save and close the ``main.py`` file,
and then eject (or unmount) the pyboard USB drive. Do this like you would a
normal USB flash drive.
When the drive is safely ejected/unmounted you can get to the fun part:
press the RST switch on the pyboard to reset and run your script. The RST
switch is the small black button just below the USB connector on the board,
on the right edge.
When you press RST the green LED will flash quickly, and then the blue
LED should turn on and stay on.
Congratulations! You have written and run your very first Micro Python
program!

146
docs/tutorial/servo.rst Normal file
View File

@@ -0,0 +1,146 @@
Controlling hobby servo motors
==============================
There are 4 dedicated connection points on the pyboard for connecting up
hobby servo motors (see eg
[Wikipedia](http://en.wikipedia.org/wiki/Servo_%28radio_control%29)).
These motors have 3 wires: ground, power and signal. On the pyboard you
can connect them in the bottom right corner, with the signal pin on the
far right. Pins X1, X2, X3 and X4 are the 4 dedicated servo signal pins.
<img src="/static/doc/pyboard-servo.jpg" alt="pyboard with servo motors" style="width:250px; border:1px solid black; display:inline-block;"/>
In this picture there are male-male double adaptors to connect the servos
to the header pins on the pyboard.
The ground wire on a servo is usually the darkest coloured one, either
black or dark brown. The power wire will most likely be red.
The power pin for the servos (labelled VIN) is connected directly to the
input power source of the pyboard. When powered via USB, VIN is powered
through a diode by the 5V USB power line. Connect to USB, the pyboard can
power at least 4 small to medium sized servo motors.
If using a battery to power the pyboard and run servo motors, make sure it
is not greater than 6V, since this is the maximum voltage most servo motors
can take. (Some motors take only up to 4.8V, so check what type you are
using.)
Creating a Servo object
-----------------------
Plug in a servo to position 1 (the one with pin X1) and create a servo object
using::
>>> servo1 = pyb.Servo(1)
To change the angle of the servo use the ``angle`` method::
>>> servo1.angle(45)
>>> servo1.angle(-60)
The angle here is measured in degrees, and ranges from about -90 to +90,
depending on the motor. Calling ``angle`` without parameters will return
the current angle::
>>> servo1.angle()
-60
Note that for some angles, the returned angle is not exactly the same as
the angle you set, due to rounding errors in setting the pulse width.
You can pass a second parameter to the ``angle`` method, which specifies how
long to take (in milliseconds) to reach the desired angle. For example, to
take 1 second (1000 milliseconds) to go from the current position to 50 degrees,
use ::
>>> servo1.angle(50, 1000)
This command will return straight away and the servo will continue to move
to the desired angle, and stop when it gets there. You can use this feature
as a speed control, or to synchronise 2 or more servo motors. If we have
another servo motor (``servo2 = pyb.Servo(2)``) then we can do ::
>>> servo1.angle(-45, 2000); servo2.angle(60, 2000)
This will move the servos together, making them both take 2 seconds to
reach their final angles.
Note: the semicolon between the 2 expressions above is used so that they
are executed one after the other when you press enter at the REPL prompt.
In a script you don't need to do this, you can just write them one line
after the other.
Continuous rotation servos
--------------------------
So far we have been using standard servos that move to a specific angle
and stay at that angle. These servo motors are useful to create joints
of a robot, or things like pan-tilt mechanisms. Internally, the motor
has a variable resistor (potentiometer) which measures the current angle
and applies power to the motor proportional to how far it is from the
desired angle. The desired angle is set by the width of a high-pulse on
the servo signal wire. A pulse width of 1500 microsecond corresponds
to the centre position (0 degrees). The pulses are sent at 50 Hz, ie
50 pulses per second.
You can also get **continuous rotation** servo motors which turn
continuously clockwise or counterclockwise. The direction and speed of
rotation is set by the pulse width on the signal wire. A pulse width
of 1500 microseconds corresponds to a stopped motor. A pulse width
smaller or larger than this means rotate one way or the other, at a
given speed.
On the pyboard, the servo object for a continuous rotation motor is
the same as before. In fact, using ``angle`` you can set the speed. But
to make it easier to understand what is intended, there is another method
called ``speed`` which sets the speed::
>>> servo1.speed(30)
``speed`` has the same functionality as ``angle``: you can get the speed,
set it, and set it with a time to reach the final speed. ::
>>> servo1.speed()
30
>>> servo1.speed(-20)
>>> servo1.speed(0, 2000)
The final command above will set the motor to stop, but take 2 seconds
to do it. This is essentially a control over the acceleration of the
continuous servo.
A servo speed of 100 (or -100) is considered maximum speed, but actually
you can go a bit faster than that, depending on the particular motor.
The only difference between the ``angle`` and ``speed`` methods (apart from
the name) is the way the input numbers (angle or speed) are converted to
a pulse width.
Calibration
-----------
The conversion from angle or speed to pulse width is done by the servo
object using its calibration values. To get the current calibration,
use ::
>>> servo1.calibration()
(640, 2420, 1500, 2470, 2200)
There are 5 numbers here, which have meaning:
1. Minimum pulse width; the smallest pulse width that the servo accepts.
2. Maximum pulse width; the largest pulse width that the servo accepts.
3. Centre pulse width; the pulse width that puts the servo at 0 degrees
or 0 speed.
4. The pulse width corresponding to 90 degrees. This sets the conversion
in the method ``angle`` of angle to pulse width.
5. The pulse width corresponding to a speed of 100. This sets the conversion
in the method ``speed`` of speed to pulse width.
You can recalibrate the servo (change its default values) by using::
>>> servo1.calibration(700, 2400, 1510, 2500, 2000)
Of course, you would change the above values to suit your particular
servo motor.

101
docs/tutorial/switch.rst Normal file
View File

@@ -0,0 +1,101 @@
The Switch, callbacks and interrupts
====================================
The pyboard has 2 small switches, labelled USR and RST. The RST switch
is a hard-reset switch, and if you press it then it restarts the pyboard
from scratch, equivalent to turning the power off then back on.
The USR switch is for general use, and is controlled via a Switch object.
To make a switch object do::
>>> sw = pyb.Switch()
Remember that you may need to type ``import pyb`` if you get an error that
the name ``pyb`` does not exist.
With the switch object you can get its status::
>>> sw()
False
This will print ``False`` if the switch is not held, or ``True`` if it is held.
Try holding the USR switch down while running the above command.
Switch callbacks
----------------
The switch is a very simple object, but it does have one advanced feature:
the ``sw.callback()`` function. The callback function sets up something to
run when the switch is pressed, and uses an interrupt. It's probably best
to start with an example before understanding how interrupts work. Try
running the following at the prompt::
>>> sw.callback(lambda:print('press!'))
This tells the switch to print ``press!`` each time the switch is pressed
down. Go ahead and try it: press the USR switch and watch the output on
your PC. Note that this print will interrupt anything you are typing, and
is an example of an interrupt routine running asynchronously.
As another example try::
>>> sw.callback(lambda:pyb.LED(1).toggle())
This will toggle the red LED each time the switch is pressed. And it will
even work while other code is running.
To disable the switch callback, pass ``None`` to the callback function::
>>> sw.callback(None)
You can pass any function (that takes zero arguments) to the switch callback.
Above we used the ``lambda`` feature of Python to create an anonymous function
on the fly. But we could equally do::
>>> def f():
... pyb.LED(1).toggle()
...
>>> sw.callback(f)
This creates a function called ``f`` and assigns it to the switch callback.
You can do things this way when your function is more complicated than a
``lambda`` will allow.
Note that your callback functions must not allocate any memory (for example
they cannot create a tuple or list). Callback functions should be relatively
simple. If you need to make a list, make it beforehand and store it in a
global variable (or make it local and close over it). If you need to do
a long, complicated calculation, then use the callback to set a flag which
some other code then responds to.
Technical details of interrupts
-------------------------------
Let's step through the details of what is happening with the switch
callback. When you register a function with ``sw.callback()``, the switch
sets up an external interrupt trigger (falling edge) on the pin that the
switch is connected to. This means that the microcontroller will listen
on the pin for any changes, and the following will occur:
1. When the switch is pressed a change occurs on the pin (the pin goes
from low to high), and the microcontroller registers this change.
2. The microcontroller finishes executing the current machine instruction,
stops execution, and saves its current state (pushes the registers on
the stack). This has the effect of pausing any code, for example your
running Python script.
3. The microcontroller starts executing the special interrupt handler
associated with the switch's external trigger. This interrupt handler
get the function that you registered with ``sw.callback()`` and executes
it.
4. Your callback function is executed until it finishes, returning control
to the switch interrupt handler.
5. The switch interrupt handler returns, and the microcontroller is
notified that the interrupt has been dealt with.
6. The microcontroller restores the state that it saved in step 2.
7. Execution continues of the code that was running at the beginning. Apart
from the pause, this code does not notice that it was interrupted.
The above sequence of events gets a bit more complicated when multiple
interrupts occur at the same time. In that case, the interrupt with the
highest priority goes first, then the others in order of their priority.
The switch interrupt is set at the lowest priority.

112
docs/tutorial/timer.rst Normal file
View File

@@ -0,0 +1,112 @@
The Timers
==========
The pyboard has 14 timers which each consist of an independent counter
running at a user-defined frequency. They can be set up to run a function
at specific intervals.
The 14 timers are numbered 1 through 14, but 3 is reserved
for internal use, and 5 and 6 are used for servo and ADC/DAC control.
Avoid using these timers if possible.
Let's create a timer object::
>>> tim = pyb.Timer(4)
Now let's see what we just created::
>>> tim
Timer(4)
The pyboard is telling us that ``tim`` is attached to timer number 4, but
it's not yet initialised. So let's initialise it to trigger at 10 Hz
(that's 10 times per second)::
>>> tim.init(freq=10)
Now that it's initialised, we can see some information about the timer::
>>> tim
Timer(4, prescaler=255, period=32811, mode=0, div=0)
The information means that this timer is set to run at the peripheral
clock speed divided by 255, and it will count up to 32811, at which point
it triggers an interrupt, and then starts counting again from 0. These
numbers are set to make the timer trigger at 10 Hz.
Timer counter
-------------
So what can we do with our timer? The most basic thing is to get the
current value of its counter::
>>> tim.counter()
21504
This counter will continuously change, and counts up.
Timer callbacks
---------------
The next thing we can do is register a callback function for the timer to
execute when it triggers (see the [switch tutorial](tut-switch) for an
introduction to callback functions)::
>>> tim.callback(lambda t:pyb.LED(1).toggle())
This should start the red LED flashing right away. It will be flashing
at 5 Hz (2 toggle's are needed for 1 flash, so toggling at 10 Hz makes
it flash at 5 Hz). You can change the frequency by re-initialising the
timer::
>>> tim.init(freq=20)
You can disable the callback by passing it the value ``None``::
>>> tim.callback(None)
The function that you pass to callback must take 1 argument, which is
the timer object that triggered. This allows you to control the timer
from within the callback function.
We can create 2 timers and run them independently::
>>> tim4 = pyb.Timer(4, freq=10)
>>> tim7 = pyb.Timer(7, freq=20)
>>> tim4.callback(lambda t: pyb.LED(1).toggle())
>>> tim7.callback(lambda t: pyb.LED(2).toggle())
Because the callbacks are proper hardware interrupts, we can continue
to use the pyboard for other things while these timers are running.
Making a microsecond counter
----------------------------
You can use a timer to create a microsecond counter, which might be
useful when you are doing something which requires accurate timing.
We will use timer 2 for this, since timer 2 has a 32-bit counter (so
does timer 5, but if you use timer 5 then you can't use the Servo
driver at the same time).
We set up timer 2 as follows::
>>> micros = pyb.Timer(2, prescaler=83, period=0x3fffffff)
The prescaler is set at 83, which makes this timer count at 1 MHz.
This is because the CPU clock, running at 168 MHz, is divided by
2 and then by prescaler+1, giving a freqency of 168 MHz/2/(83+1)=1 MHz
for timer 2. The period is set to a large number so that the timer
can count up to a large number before wrapping back around to zero.
In this case it will take about 17 minutes before it cycles back to
zero.
To use this timer, it's best to first reset it to 0::
>>> micros.counter(0)
and then perform your timing::
>>> start_micros = micros.counter()
... do some stuff ...
>>> end_micros = micros.counter()

129
docs/tutorial/usb_mouse.rst Normal file
View File

@@ -0,0 +1,129 @@
Making the pyboard act as a USB mouse
=====================================
The pyboard is a USB device, and can configured to act as a mouse instead
of the default USB flash drive.
To do this we must first edit the ``boot.py`` file to change the USB
configuration. If you have not yet touched your ``boot.py`` file then it
will look something like this::
# boot.py -- run on boot-up
# can run arbitrary Python, but best to keep it minimal
import pyb
#pyb.main('main.py') # main script to run after this one
#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
To enable the mouse mode, uncomment the last line of the file, to
make it look like::
pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
If you already changed your ``boot.py`` file, then the minimum code it
needs to work is::
import pyb
pyb.usb_mode('CDC+HID')
This tells the pyboard to configure itself as a CDC (serial) and HID
(human interface device, in our case a mouse) USB device when it boots
up.
Eject/unmount the pyboard drive and reset it using the RST switch.
Your PC should now detect the pyboard as a mouse!
Sending mouse events by hand
----------------------------
To get the py-mouse to do anything we need to send mouse events to the PC.
We will first do this manually using the REPL prompt. Connect to your
pyboard using your serial program and type the following::
>>> pyb.hid((0, 10, 0, 0))
Your mouse should move 10 pixels to the right! In the command above you
are sending 4 pieces of information: button status, x, y and scroll. The
number 10 is telling the PC that the mouse moved 10 pixels in the x direction.
Let's make the mouse oscillate left and right::
>>> import math
>>> def osc(n, d):
... for i in range(n):
... pyb.hid((0, int(20 * math.sin(i / 10)), 0, 0))
... pyb.delay(d)
...
>>> osc(100, 50)
The first argument to the function ``osc`` is the number of mouse events to send,
and the second argument is the delay (in milliseconds) between events. Try
playing around with different numbers.
**Excercise: make the mouse go around in a circle.**
Making a mouse with the accelerometer
-------------------------------------
Now lets make the mouse move based on the angle of the pyboard, using the
accelerometer. The following code can be typed directly at the REPL prompt,
or put in the ``main.py`` file. Here, we'll put in in ``main.py`` because to do
that we will learn how to go into safe mode.
At the moment the pyboard is acting as a serial USB device and an HID (a mouse).
So you cannot access the filesystem to edit your ``main.py`` file.
You also can't edit your ``boot.py`` to get out of HID-mode and back to normal
mode with a USB drive...
To get around this we need to go into *safe mode*. This was described in
the [safe mode tutorial](tut-reset), but we repeat the instructions here:
1. Hold down the USR switch.
2. While still holding down USR, press and release the RST switch.
3. The LEDs will then cycle green to orange to green+orange and back again.
4. Keep holding down USR until *only the orange LED is lit*, and then let
go of the USR switch.
5. The orange LED should flash quickly 4 times, and then turn off.
6. You are now in safe mode.
In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
the pyboard boots up with default settings. This means you now have access
to the filesystem (the USB drive should appear), and you can edit ``main.py``.
(Leave ``boot.py`` as-is, because we still want to go back to HID-mode after
we finish editting ``main.py``.)
In ``main.py`` put the following code::
import pyb
switch = pyb.Switch()
accel = pyb.Accel()
while not switch():
pyb.hid((0, accel.x(), accel.y(), 0))
pyb.delay(20)
Save your file, eject/unmount your pyboard drive, and reset it using the RST
switch. It should now act as a mouse, and the angle of the board will move
the mouse around. Try it out, and see if you can make the mouse stand still!
Press the USR switch to stop the mouse motion.
You'll note that the y-axis is inverted. That's easy to fix: just put a
minus sign in front of the y-coordinate in the ``pyb.hid()`` line above.
Restoring your pyboard to normal
--------------------------------
If you leave your pyboard as-is, it'll behave as a mouse everytime you plug
it in. You probably want to change it back to normal. To do this you need
to first enter safe mode (see above), and then edit the ``boot.py`` file.
In the ``boot.py`` file, comment out (put a # in front of) the line with the
``CDC+HID`` setting, so it looks like::
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
Save your file, eject/unmount the drive, and reset the pyboard. It is now
back to normal operating mode.

2
drivers/README.md Normal file
View File

@@ -0,0 +1,2 @@
This directory contains drivers for specific hardware. The drivers are
intended to work across multiple ports.

View File

@@ -0,0 +1,6 @@
This is the driver for the WIZnet5x00 series of Ethernet controllers.
Adapted for Micro Python.
Original source: https://github.com/Wiznet/W5500_EVB/tree/master/ioLibrary
Taken on: 30 August 2014

View File

@@ -0,0 +1,703 @@
//*****************************************************************************
//
//! \file socket.c
//! \brief SOCKET APIs Implements file.
//! \details SOCKET APIs like as Berkeley Socket APIs.
//! \version 1.0.3
//! \date 2013/10/21
//! \par Revision history
//! <2014/05/01> V1.0.3. Refer to M20140501
//! 1. Implicit type casting -> Explicit type casting.
//! 2. replace 0x01 with PACK_REMAINED in recvfrom()
//! 3. Validation a destination ip in connect() & sendto():
//! It occurs a fatal error on converting unint32 address if uint8* addr parameter is not aligned by 4byte address.
//! Copy 4 byte addr value into temporary uint32 variable and then compares it.
//! <2013/12/20> V1.0.2 Refer to M20131220
//! Remove Warning.
//! <2013/11/04> V1.0.1 2nd Release. Refer to "20131104".
//! In sendto(), Add to clear timeout interrupt status (Sn_IR_TIMEOUT)
//! <2013/10/21> 1st Release
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#include "socket.h"
extern void HAL_Delay(uint32_t);
#define SOCK_ANY_PORT_NUM 0xC000;
static uint16_t sock_any_port = SOCK_ANY_PORT_NUM;
static uint16_t sock_io_mode = 0;
static uint16_t sock_is_sending = 0;
static uint16_t sock_remained_size[_WIZCHIP_SOCK_NUM_] = {0,0,};
static uint8_t sock_pack_info[_WIZCHIP_SOCK_NUM_] = {0,};
#if _WIZCHIP_ == 5200
static uint16_t sock_next_rd[_WIZCHIP_SOCK_NUM_] ={0,};
#endif
#define CHECK_SOCKNUM() \
do{ \
if(sn > _WIZCHIP_SOCK_NUM_) return SOCKERR_SOCKNUM; \
}while(0); \
#define CHECK_SOCKMODE(mode) \
do{ \
if((getSn_MR(sn) & 0x0F) != mode) return SOCKERR_SOCKMODE; \
}while(0); \
#define CHECK_SOCKINIT() \
do{ \
if((getSn_SR(sn) != SOCK_INIT)) return SOCKERR_SOCKINIT; \
}while(0); \
#define CHECK_SOCKDATA() \
do{ \
if(len == 0) return SOCKERR_DATALEN; \
}while(0); \
int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag)
{
CHECK_SOCKNUM();
switch(protocol)
{
case Sn_MR_TCP :
case Sn_MR_UDP :
case Sn_MR_MACRAW :
break;
#if ( _WIZCHIP_ < 5200 )
case Sn_MR_IPRAW :
case Sn_MR_PPPoE :
break;
#endif
default :
return SOCKERR_SOCKMODE;
}
if((flag & 0x06) != 0) return SOCKERR_SOCKFLAG;
#if _WIZCHIP_ == 5200
if(flag & 0x10) return SOCKERR_SOCKFLAG;
#endif
if(flag != 0)
{
switch(protocol)
{
case Sn_MR_TCP:
if((flag & (SF_TCP_NODELAY|SF_IO_NONBLOCK))==0) return SOCKERR_SOCKFLAG;
break;
case Sn_MR_UDP:
if(flag & SF_IGMP_VER2)
{
if((flag & SF_MULTI_ENABLE)==0) return SOCKERR_SOCKFLAG;
}
#if _WIZCHIP_ == 5500
if(flag & SF_UNI_BLOCK)
{
if((flag & SF_MULTI_ENABLE) == 0) return SOCKERR_SOCKFLAG;
}
#endif
break;
default:
break;
}
}
close(sn);
setSn_MR(sn, (protocol | (flag & 0xF0)));
if(!port)
{
port = sock_any_port++;
if(sock_any_port == 0xFFF0) sock_any_port = SOCK_ANY_PORT_NUM;
}
setSn_PORT(sn,port);
setSn_CR(sn,Sn_CR_OPEN);
while(getSn_CR(sn));
sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn);
sock_is_sending &= ~(1<<sn);
sock_remained_size[sn] = 0;
sock_pack_info[sn] = 0;
while(getSn_SR(sn) == SOCK_CLOSED);
return (int8_t)sn;
}
int8_t close(uint8_t sn)
{
CHECK_SOCKNUM();
setSn_CR(sn,Sn_CR_CLOSE);
/* wait to process the command... */
while( getSn_CR(sn) );
/* clear all interrupt of the socket. */
setSn_IR(sn, 0xFF);
sock_is_sending &= ~(1<<sn);
sock_remained_size[sn] = 0;
sock_pack_info[sn] = 0;
while(getSn_SR(sn) != SOCK_CLOSED);
return SOCK_OK;
}
int8_t listen(uint8_t sn)
{
CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
CHECK_SOCKINIT();
setSn_CR(sn,Sn_CR_LISTEN);
while(getSn_CR(sn));
while(getSn_SR(sn) != SOCK_LISTEN)
{
if(getSn_CR(sn) == SOCK_CLOSED)
{
close(sn);
return SOCKERR_SOCKCLOSED;
}
}
return SOCK_OK;
}
int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port)
{
CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
CHECK_SOCKINIT();
//M20140501 : For avoiding fatal error on memory align mismatched
//if( *((uint32_t*)addr) == 0xFFFFFFFF || *((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
{
uint32_t taddr;
taddr = ((uint32_t)addr[0] & 0x000000FF);
taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
if (taddr == 0xFFFFFFFF || taddr == 0) return SOCKERR_IPINVALID;
}
//
if(port == 0) return SOCKERR_PORTZERO;
setSn_DIPR(sn,addr);
setSn_DPORT(sn,port);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR(wizchip_getsubn());
#endif
setSn_CR(sn,Sn_CR_CONNECT);
while(getSn_CR(sn));
if(sock_io_mode & (1<<sn)) return SOCK_BUSY;
while(getSn_SR(sn) != SOCK_ESTABLISHED)
{
if (getSn_SR(sn) == SOCK_CLOSED) {
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
#endif
return SOCKERR_SOCKCLOSED;
}
if (getSn_IR(sn) & Sn_IR_TIMEOUT)
{
setSn_IR(sn, Sn_IR_TIMEOUT);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
#endif
return SOCKERR_TIMEOUT;
}
HAL_Delay(1);
}
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
#endif
return SOCK_OK;
}
int8_t disconnect(uint8_t sn)
{
CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
setSn_CR(sn,Sn_CR_DISCON);
/* wait to process the command... */
while(getSn_CR(sn));
sock_is_sending &= ~(1<<sn);
if(sock_io_mode & (1<<sn)) return SOCK_BUSY;
while(getSn_SR(sn) != SOCK_CLOSED)
{
if(getSn_IR(sn) & Sn_IR_TIMEOUT)
{
close(sn);
return SOCKERR_TIMEOUT;
}
}
return SOCK_OK;
}
int32_t send(uint8_t sn, uint8_t * buf, uint16_t len)
{
uint8_t tmp=0;
uint16_t freesize=0;
CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
CHECK_SOCKDATA();
tmp = getSn_SR(sn);
if(tmp != SOCK_ESTABLISHED && tmp != SOCK_CLOSE_WAIT) return SOCKERR_SOCKSTATUS;
if( sock_is_sending & (1<<sn) )
{
tmp = getSn_IR(sn);
if(tmp & Sn_IR_SENDOK)
{
setSn_IR(sn, Sn_IR_SENDOK);
#if _WZICHIP_ == 5200
if(getSn_TX_RD(sn) != sock_next_rd[sn])
{
setSn_CR(sn,Sn_CR_SEND);
while(getSn_CR(sn));
return SOCKERR_BUSY;
}
#endif
sock_is_sending &= ~(1<<sn);
}
else if(tmp & Sn_IR_TIMEOUT)
{
close(sn);
return SOCKERR_TIMEOUT;
}
else return SOCK_BUSY;
}
freesize = getSn_TxMAX(sn);
if (len > freesize) len = freesize; // check size not to exceed MAX size.
while(1)
{
freesize = getSn_TX_FSR(sn);
tmp = getSn_SR(sn);
if ((tmp != SOCK_ESTABLISHED) && (tmp != SOCK_CLOSE_WAIT))
{
close(sn);
return SOCKERR_SOCKSTATUS;
}
if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;
if(len <= freesize) break;
}
wiz_send_data(sn, buf, len);
#if _WIZCHIP_ == 5200
sock_next_rd[sn] = getSn_TX_RD(sn) + len;
#endif
setSn_CR(sn,Sn_CR_SEND);
/* wait to process the command... */
while(getSn_CR(sn));
sock_is_sending |= (1 << sn);
return len;
}
int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len)
{
uint8_t tmp = 0;
uint16_t recvsize = 0;
CHECK_SOCKNUM();
CHECK_SOCKMODE(Sn_MR_TCP);
CHECK_SOCKDATA();
recvsize = getSn_RxMAX(sn);
if(recvsize < len) len = recvsize;
while(1)
{
recvsize = getSn_RX_RSR(sn);
tmp = getSn_SR(sn);
if (tmp != SOCK_ESTABLISHED)
{
if(tmp == SOCK_CLOSE_WAIT)
{
if(recvsize != 0) break;
else if(getSn_TX_FSR(sn) == getSn_TxMAX(sn))
{
close(sn);
return SOCKERR_SOCKSTATUS;
}
}
else
{
close(sn);
return SOCKERR_SOCKSTATUS;
}
}
if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
if(recvsize != 0) break;
HAL_Delay(1);
};
if(recvsize < len) len = recvsize;
wiz_recv_data(sn, buf, len);
setSn_CR(sn,Sn_CR_RECV);
while(getSn_CR(sn));
return len;
}
int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port)
{
uint8_t tmp = 0;
uint16_t freesize = 0;
CHECK_SOCKNUM();
switch(getSn_MR(sn) & 0x0F)
{
case Sn_MR_UDP:
case Sn_MR_MACRAW:
break;
default:
return SOCKERR_SOCKMODE;
}
CHECK_SOCKDATA();
//M20140501 : For avoiding fatal error on memory align mismatched
//if(*((uint32_t*)addr) == 0) return SOCKERR_IPINVALID;
{
uint32_t taddr;
taddr = ((uint32_t)addr[0]) & 0x000000FF;
taddr = (taddr << 8) + ((uint32_t)addr[1] & 0x000000FF);
taddr = (taddr << 8) + ((uint32_t)addr[2] & 0x000000FF);
taddr = (taddr << 8) + ((uint32_t)addr[3] & 0x000000FF);
if (taddr == 0xFFFFFFFF || taddr == 0) return SOCKERR_IPINVALID;
}
//
if(port == 0) return SOCKERR_PORTZERO;
tmp = getSn_SR(sn);
if(tmp != SOCK_MACRAW && tmp != SOCK_UDP) return SOCKERR_SOCKSTATUS;
setSn_DIPR(sn,addr);
setSn_DPORT(sn,port);
freesize = getSn_TxMAX(sn);
if (len > freesize) len = freesize; // check size not to exceed MAX size.
while(1)
{
freesize = getSn_TX_FSR(sn);
if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;
if(len <= freesize) break;
HAL_Delay(1);
};
wiz_send_data(sn, buf, len);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR(wizchip_getsubn());
#endif
setSn_CR(sn,Sn_CR_SEND);
/* wait to process the command... */
while(getSn_CR(sn));
while(1)
{
tmp = getSn_IR(sn);
if(tmp & Sn_IR_SENDOK)
{
setSn_IR(sn, Sn_IR_SENDOK);
break;
}
//M:20131104
//else if(tmp & Sn_IR_TIMEOUT) return SOCKERR_TIMEOUT;
else if(tmp & Sn_IR_TIMEOUT)
{
setSn_IR(sn, Sn_IR_TIMEOUT);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
#endif
return SOCKERR_TIMEOUT;
}
////////////
HAL_Delay(1);
}
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
#endif
return len;
}
int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port)
{
uint8_t mr;
uint8_t head[8];
uint16_t pack_len=0;
CHECK_SOCKNUM();
//CHECK_SOCKMODE(Sn_MR_UDP);
switch((mr=getSn_MR(sn)) & 0x0F)
{
case Sn_MR_UDP:
case Sn_MR_MACRAW:
break;
#if ( _WIZCHIP_ < 5200 )
case Sn_MR_IPRAW:
case Sn_MR_PPPoE:
break;
#endif
default:
return SOCKERR_SOCKMODE;
}
CHECK_SOCKDATA();
if(sock_remained_size[sn] == 0)
{
while(1)
{
pack_len = getSn_RX_RSR(sn);
if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
if( (sock_io_mode & (1<<sn)) && (pack_len == 0) ) return SOCK_BUSY;
if(pack_len != 0) break;
};
}
sock_pack_info[sn] = PACK_COMPLETED;
switch (mr & 0x07)
{
case Sn_MR_UDP :
if(sock_remained_size[sn] == 0)
{
wiz_recv_data(sn, head, 8);
setSn_CR(sn,Sn_CR_RECV);
while(getSn_CR(sn));
// read peer's IP address, port number & packet length
addr[0] = head[0];
addr[1] = head[1];
addr[2] = head[2];
addr[3] = head[3];
*port = head[4];
*port = (*port << 8) + head[5];
sock_remained_size[sn] = head[6];
sock_remained_size[sn] = (sock_remained_size[sn] << 8) + head[7];
sock_pack_info[sn] = PACK_FIRST;
}
if(len < sock_remained_size[sn]) pack_len = len;
else pack_len = sock_remained_size[sn];
//
// Need to packet length check (default 1472)
//
wiz_recv_data(sn, buf, pack_len); // data copy.
break;
case Sn_MR_MACRAW :
if(sock_remained_size[sn] == 0)
{
wiz_recv_data(sn, head, 2);
setSn_CR(sn,Sn_CR_RECV);
while(getSn_CR(sn));
// read peer's IP address, port number & packet length
sock_remained_size[sn] = head[0];
sock_remained_size[sn] = (sock_remained_size[sn] <<8) + head[1];
if(sock_remained_size[sn] > 1514)
{
close(sn);
return SOCKFATAL_PACKLEN;
}
sock_pack_info[sn] = PACK_FIRST;
}
if(len < sock_remained_size[sn]) pack_len = len;
else pack_len = sock_remained_size[sn];
wiz_recv_data(sn,buf,pack_len);
break;
#if ( _WIZCHIP_ < 5200 )
case Sn_MR_IPRAW:
if(sock_remained_size[sn] == 0)
{
wiz_recv_data(sn, head, 6);
setSn_CR(sn,Sn_CR_RECV);
while(getSn_CR(sn));
addr[0] = head[0];
addr[1] = head[1];
addr[2] = head[2];
addr[3] = head[3];
sock_remained_size[sn] = head[4];
sock_remaiend_size[sn] = (sock_remained_size[sn] << 8) + head[5];
sock_pack_info[sn] = PACK_FIRST;
}
//
// Need to packet length check
//
if(len < sock_remained_size[sn]) pack_len = len;
else pack_len = sock_remained_size[sn];
wiz_recv_data(sn, buf, pack_len); // data copy.
break;
#endif
default:
wiz_recv_ignore(sn, pack_len); // data copy.
sock_remained_size[sn] = pack_len;
break;
}
setSn_CR(sn,Sn_CR_RECV);
/* wait to process the command... */
while(getSn_CR(sn)) ;
sock_remained_size[sn] -= pack_len;
//M20140501 : replace 0x01 with PACK_REMAINED
//if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= 0x01;
if(sock_remained_size[sn] != 0) sock_pack_info[sn] |= PACK_REMAINED;
//
return pack_len;
}
int8_t ctlsocket(uint8_t sn, ctlsock_type cstype, void* arg)
{
uint8_t tmp = 0;
CHECK_SOCKNUM();
switch(cstype)
{
case CS_SET_IOMODE:
tmp = *((uint8_t*)arg);
if(tmp == SOCK_IO_NONBLOCK) sock_io_mode |= (1<<sn);
else if(tmp == SOCK_IO_BLOCK) sock_io_mode &= ~(1<<sn);
else return SOCKERR_ARG;
break;
case CS_GET_IOMODE:
//M20140501 : implict type casting -> explict type casting
//*((uint8_t*)arg) = (sock_io_mode >> sn) & 0x0001;
*((uint8_t*)arg) = (uint8_t)((sock_io_mode >> sn) & 0x0001);
//
break;
case CS_GET_MAXTXBUF:
*((uint16_t*)arg) = getSn_TxMAX(sn);
break;
case CS_GET_MAXRXBUF:
*((uint16_t*)arg) = getSn_RxMAX(sn);
break;
case CS_CLR_INTERRUPT:
if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG;
setSn_IR(sn,*(uint8_t*)arg);
break;
case CS_GET_INTERRUPT:
*((uint8_t*)arg) = getSn_IR(sn);
break;
case CS_SET_INTMASK:
if( (*(uint8_t*)arg) > SIK_ALL) return SOCKERR_ARG;
setSn_IMR(sn,*(uint8_t*)arg);
break;
case CS_GET_INTMASK:
*((uint8_t*)arg) = getSn_IMR(sn);
default:
return SOCKERR_ARG;
}
return SOCK_OK;
}
int8_t setsockopt(uint8_t sn, sockopt_type sotype, void* arg)
{
// M20131220 : Remove warning
//uint8_t tmp;
CHECK_SOCKNUM();
switch(sotype)
{
case SO_TTL:
setSn_TTL(sn,*(uint8_t*)arg);
break;
case SO_TOS:
setSn_TOS(sn,*(uint8_t*)arg);
break;
case SO_MSS:
setSn_MSSR(sn,*(uint16_t*)arg);
break;
case SO_DESTIP:
setSn_DIPR(sn, (uint8_t*)arg);
break;
case SO_DESTPORT:
setSn_DPORT(sn, *(uint16_t*)arg);
break;
#if _WIZCHIP_ != 5100
case SO_KEEPALIVESEND:
CHECK_SOCKMODE(Sn_MR_TCP);
#if _WIZCHIP_ > 5200
if(getSn_KPALVTR(sn) != 0) return SOCKERR_SOCKOPT;
#endif
setSn_CR(sn,Sn_CR_SEND_KEEP);
while(getSn_CR(sn) != 0)
{
// M20131220
//if ((tmp = getSn_IR(sn)) & Sn_IR_TIMEOUT)
if (getSn_IR(sn) & Sn_IR_TIMEOUT)
{
setSn_IR(sn, Sn_IR_TIMEOUT);
return SOCKERR_TIMEOUT;
}
}
break;
#if _WIZCHIP_ > 5200
case SO_KEEPALIVEAUTO:
CHECK_SOCKMODE(Sn_MR_TCP);
setSn_KPALVTR(sn,*(uint8_t*)arg);
break;
#endif
#endif
default:
return SOCKERR_ARG;
}
return SOCK_OK;
}
int8_t getsockopt(uint8_t sn, sockopt_type sotype, void* arg)
{
CHECK_SOCKNUM();
switch(sotype)
{
case SO_FLAG:
*(uint8_t*)arg = getSn_MR(sn) & 0xF0;
break;
case SO_TTL:
*(uint8_t*) arg = getSn_TTL(sn);
break;
case SO_TOS:
*(uint8_t*) arg = getSn_TOS(sn);
break;
case SO_MSS:
*(uint8_t*) arg = getSn_MSSR(sn);
case SO_DESTIP:
getSn_DIPR(sn, (uint8_t*)arg);
break;
case SO_DESTPORT:
*(uint16_t*) arg = getSn_DPORT(sn);
break;
#if _WIZCHIP_ > 5200
case SO_KEEPALIVEAUTO:
CHECK_SOCKMODE(Sn_MR_TCP);
*(uint16_t*) arg = getSn_KPALVTR(sn);
break;
#endif
case SO_SENDBUF:
*(uint16_t*) arg = getSn_TX_FSR(sn);
case SO_RECVBUF:
*(uint16_t*) arg = getSn_RX_RSR(sn);
case SO_STATUS:
*(uint8_t*) arg = getSn_SR(sn);
break;
case SO_REMAINSIZE:
if(getSn_MR(sn) == Sn_MR_TCP)
*(uint16_t*)arg = getSn_RX_RSR(sn);
else
*(uint16_t*)arg = sock_remained_size[sn];
break;
case SO_PACKINFO:
CHECK_SOCKMODE(Sn_MR_TCP);
*(uint8_t*)arg = sock_pack_info[sn];
break;
default:
return SOCKERR_SOCKOPT;
}
return SOCK_OK;
}

View File

@@ -0,0 +1,466 @@
//*****************************************************************************
//
//! \file socket.h
//! \brief SOCKET APIs Header file.
//! \details SOCKET APIs like as berkeley socket api.
//! \version 1.0.2
//! \date 2013/10/21
//! \par Revision history
//! <2014/05/01> V1.0.2. Refer to M20140501
//! 1. Modify the comment : SO_REMAINED -> PACK_REMAINED
//! 2. Add the comment as zero byte udp data reception in getsockopt().
//! <2013/10/21> 1st Release
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
/**
* @defgroup WIZnet_socket_APIs 1. WIZnet socket APIs
* @brief WIZnet socket APIs are based on Berkeley socket APIs, thus it has much similar name and interface.
* But there is a little bit of difference.
* @details
* <b> Comparison between WIZnet and Berkeley SOCKET APIs </b>
* <table>
* <tr> <td><b>API</b></td> <td><b>WIZnet</b></td> <td><b>Berkeley</b></td> </tr>
* <tr> <td>socket()</td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>bind()</b></td> <td>X</td> <td>O</td> </tr>
* <tr> <td><b>listen()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>connect()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>accept()</b></td> <td>X</td> <td>O</td> </tr>
* <tr> <td><b>recv()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>send()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>recvfrom()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>sendto()</b></td> <td>O</td> <td>O</td> </tr>
* <tr> <td><b>closesocket()</b></td> <td>O<br>close() & disconnect()</td> <td>O</td> </tr>
* </table>
* There are @b bind() and @b accept() functions in @b Berkeley SOCKET API but,
* not in @b WIZnet SOCKET API. Because socket() of WIZnet is not only creating a SOCKET but also binding a local port number,
* and listen() of WIZnet is not only listening to connection request from client but also accepting the connection request. \n
* When you program "TCP SERVER" with Berkeley SOCKET API, you can use only one listen port.
* When the listen SOCKET accepts a connection request from a client, it keeps listening.
* After accepting the connection request, a new SOCKET is created and the new SOCKET is used in communication with the client. \n
* Following figure shows network flow diagram by Berkeley SOCKET API.
* @image html Berkeley_SOCKET.jpg "<Berkeley SOCKET API>"
* But, When you program "TCP SERVER" with WIZnet SOCKET API, you can use as many as 8 listen SOCKET with same port number. \n
* Because there's no accept() in WIZnet SOCKET APIs, when the listen SOCKET accepts a connection request from a client,
* it is changed in order to communicate with the client.
* And the changed SOCKET is not listening any more and is dedicated for communicating with the client. \n
* If there're many listen SOCKET with same listen port number and a client requests a connection,
* the SOCKET which has the smallest SOCKET number accepts the request and is changed as communication SOCKET. \n
* Following figure shows network flow diagram by WIZnet SOCKET API.
* @image html WIZnet_SOCKET.jpg "<WIZnet SOCKET API>"
*/
#ifndef _SOCKET_H_
#define _SOCKET_H_
#include "wizchip_conf.h"
#define SOCKET uint8_t ///< SOCKET type define for legacy driver
#define SOCK_OK 1 ///< Result is OK about socket process.
#define SOCK_BUSY 0 ///< Socket is busy on processing the operation. Valid only Non-block IO Mode.
#define SOCK_FATAL -1000 ///< Result is fatal error about socket process.
#define SOCK_ERROR 0
#define SOCKERR_SOCKNUM (SOCK_ERROR - 1) ///< Invalid socket number
#define SOCKERR_SOCKOPT (SOCK_ERROR - 2) ///< Invalid socket option
#define SOCKERR_SOCKINIT (SOCK_ERROR - 3) ///< Socket is not initialized
#define SOCKERR_SOCKCLOSED (SOCK_ERROR - 4) ///< Socket unexpectedly closed.
#define SOCKERR_SOCKMODE (SOCK_ERROR - 5) ///< Invalid socket mode for socket operation.
#define SOCKERR_SOCKFLAG (SOCK_ERROR - 6) ///< Invalid socket flag
#define SOCKERR_SOCKSTATUS (SOCK_ERROR - 7) ///< Invalid socket status for socket operation.
#define SOCKERR_ARG (SOCK_ERROR - 10) ///< Invalid argument.
#define SOCKERR_PORTZERO (SOCK_ERROR - 11) ///< Port number is zero
#define SOCKERR_IPINVALID (SOCK_ERROR - 12) ///< Invalid IP address
#define SOCKERR_TIMEOUT (SOCK_ERROR - 13) ///< Timeout occurred
#define SOCKERR_DATALEN (SOCK_ERROR - 14) ///< Data length is zero or greater than buffer max size.
#define SOCKERR_BUFFER (SOCK_ERROR - 15) ///< Socket buffer is not enough for data communication.
#define SOCKFATAL_PACKLEN (SOCK_FATAL - 1) ///< Invalid packet length. Fatal Error.
/*
* SOCKET FLAG
*/
#define SF_ETHER_OWN (Sn_MR_MFEN) ///< In \ref Sn_MR_MACRAW, Receive only the packet as broadcast, multicast and own packet
#define SF_IGMP_VER2 (Sn_MR_MC) ///< In \ref Sn_MR_UDP with \ref SF_MULTI_ENABLE, Select IGMP version 2.
#define SF_TCP_NODELAY (Sn_MR_ND) ///< In \ref Sn_MR_TCP, Use to nodelayed ack.
#define SF_MULTI_ENABLE (Sn_MR_MULTI) ///< In \ref Sn_MR_UDP, Enable multicast mode.
#if _WIZCHIP_ == 5500
#define SF_BROAD_BLOCK (Sn_MR_BCASTB) ///< In \ref Sn_MR_UDP or \ref Sn_MR_MACRAW, Block broadcast packet. Valid only in W5500
#define SF_MULTI_BLOCK (Sn_MR_MMB) ///< In \ref Sn_MR_MACRAW, Block multicast packet. Valid only in W5500
#define SF_IPv6_BLOCK (Sn_MR_MIP6B) ///< In \ref Sn_MR_MACRAW, Block IPv6 packet. Valid only in W5500
#define SF_UNI_BLOCK (Sn_MR_UCASTB) ///< In \ref Sn_MR_UDP with \ref SF_MULTI_ENABLE. Valid only in W5500
#endif
#define SF_IO_NONBLOCK 0x01 ///< Socket nonblock io mode. It used parameter in \ref socket().
/*
* UDP & MACRAW Packet Infomation
*/
#define PACK_FIRST 0x80 ///< In Non-TCP packet, It indicates to start receiving a packet.
#define PACK_REMAINED 0x01 ///< In Non-TCP packet, It indicates to remain a packet to be received.
#define PACK_COMPLETED 0x00 ///< In Non-TCP packet, It indicates to complete to receive a packet.
/**
* @ingroup WIZnet_socket_APIs
* @brief Open a socket.
* @details Initializes the socket with 'sn' passed as parameter and open.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param protocol Protocol type to operate such as TCP, UDP and MACRAW.
* @param port Port number to be bined.
* @param flag Socket flags as \ref SF_ETHER_OWN, \ref SF_IGMP_VER2, \ref SF_TCP_NODELAY, \ref SF_MULTI_ENABLE, \ref SF_IO_NONBLOCK and so on.\n
* Valid flags only in W5500 : @ref SF_BROAD_BLOCK, @ref SF_MULTI_BLOCK, @ref SF_IPv6_BLOCK, and @ref SF_UNI_BLOCK.
* @sa Sn_MR
*
* @return @b Success : The socket number @b 'sn' passed as parameter\n
* @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n
* @ref SOCKERR_SOCKMODE - Not support socket mode as TCP, UDP, and so on. \n
* @ref SOCKERR_SOCKFLAG - Invaild socket flag.
*/
int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);
/**
* @ingroup WIZnet_socket_APIs
* @brief Close a socket.
* @details It closes the socket with @b'sn' passed as parameter.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
*
* @return @b Success : @ref SOCK_OK \n
* @b Fail : @ref SOCKERR_SOCKNUM - Invalid socket number
*/
int8_t close(uint8_t sn);
/**
* @ingroup WIZnet_socket_APIs
* @brief Listen to a connection request from a client.
* @details It is listening to a connection request from a client.
* If connection request is accepted successfully, the connection is established. Socket sn is used in passive(server) mode.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @return @b Success : @ref SOCK_OK \n
* @b Fail :\n @ref SOCKERR_SOCKINIT - Socket is not initialized \n
* @ref SOCKERR_SOCKCLOSED - Socket closed unexpectedly.
*/
int8_t listen(uint8_t sn);
/**
* @ingroup WIZnet_socket_APIs
* @brief Try to connect a server.
* @details It requests connection to the server with destination IP address and port number passed as parameter.\n
* @note It is valid only in TCP client mode.
* In block io mode, it does not return until connection is completed.
* In Non-block io mode, it return @ref SOCK_BUSY immediately.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param addr Pointer variable of destination IP address. It should be allocated 4 bytes.
* @param port Destination port number.
*
* @return @b Success : @ref SOCK_OK \n
* @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number\n
* @ref SOCKERR_SOCKMODE - Invalid socket mode\n
* @ref SOCKERR_SOCKINIT - Socket is not initialized\n
* @ref SOCKERR_IPINVALID - Wrong server IP address\n
* @ref SOCKERR_PORTZERO - Server port zero\n
* @ref SOCKERR_TIMEOUT - Timeout occurred during request connection\n
* @ref SOCK_BUSY - In non-block io mode, it returned immediately\n
*/
int8_t connect(uint8_t sn, uint8_t * addr, uint16_t port);
/**
* @ingroup WIZnet_socket_APIs
* @brief Try to disconnect a connection socket.
* @details It sends request message to disconnect the TCP socket 'sn' passed as parameter to the server or client.
* @note It is valid only in TCP server or client mode. \n
* In block io mode, it does not return until disconnection is completed. \n
* In Non-block io mode, it return @ref SOCK_BUSY immediately. \n
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @return @b Success : @ref SOCK_OK \n
* @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n
* @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
* @ref SOCKERR_TIMEOUT - Timeout occurred \n
* @ref SOCK_BUSY - Socket is busy.
*/
int8_t disconnect(uint8_t sn);
/**
* @ingroup WIZnet_socket_APIs
* @brief Send data to the connected peer in TCP socket.
* @details It is used to send outgoing data to the connected socket.
* @note It is valid only in TCP server or client mode. It can't send data greater than socket buffer size. \n
* In block io mode, It doesn't return until data send is completed - socket buffer size is greater than data. \n
* In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough. \n
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param buf Pointer buffer containing data to be sent.
* @param len The byte length of data in buf.
* @return @b Success : The sent data size \n
* @b Fail : \n @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
* @ref SOCKERR_TIMEOUT - Timeout occurred \n
* @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
* @ref SOCKERR_SOCKNUM - Invalid socket number \n
* @ref SOCKERR_DATALEN - zero data length \n
* @ref SOCK_BUSY - Socket is busy.
*/
int32_t send(uint8_t sn, uint8_t * buf, uint16_t len);
/**
* @ingroup WIZnet_socket_APIs
* @brief Receive data from the connected peer.
* @details It is used to read incoming data from the connected socket.\n
* It waits for data as much as the application wants to receive.
* @note It is valid only in TCP server or client mode. It can't receive data greater than socket buffer size. \n
* In block io mode, it doesn't return until data reception is completed - data is filled as <I>len</I> in socket buffer. \n
* In non-block io mode, it return @ref SOCK_BUSY immediately when <I>len</I> is greater than data size in socket buffer. \n
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param buf Pointer buffer to read incoming data.
* @param len The max data length of data in buf.
* @return @b Success : The real received data size \n
* @b Fail :\n
* @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
* @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
* @ref SOCKERR_SOCKNUM - Invalid socket number \n
* @ref SOCKERR_DATALEN - zero data length \n
* @ref SOCK_BUSY - Socket is busy.
*/
int32_t recv(uint8_t sn, uint8_t * buf, uint16_t len);
/**
* @ingroup WIZnet_socket_APIs
* @brief Sends datagram to the peer with destination IP address and port number passed as parameter.
* @details It sends datagram of UDP or MACRAW to the peer with destination IP address and port number passed as parameter.\n
* Even if the connectionless socket has been previously connected to a specific address,
* the address and port number parameters override the destination address for that particular datagram only.
* @note In block io mode, It doesn't return until data send is completed - socket buffer size is greater than <I>len</I>.
* In non-block io mode, It return @ref SOCK_BUSY immediately when socket buffer is not enough.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param buf Pointer buffer to send outgoing data.
* @param len The byte length of data in buf.
* @param addr Pointer variable of destination IP address. It should be allocated 4 bytes.
* @param port Destination port number.
*
* @return @b Success : The sent data size \n
* @b Fail :\n @ref SOCKERR_SOCKNUM - Invalid socket number \n
* @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
* @ref SOCKERR_SOCKSTATUS - Invalid socket status for socket operation \n
* @ref SOCKERR_DATALEN - zero data length \n
* @ref SOCKERR_IPINVALID - Wrong server IP address\n
* @ref SOCKERR_PORTZERO - Server port zero\n
* @ref SOCKERR_SOCKCLOSED - Socket unexpectedly closed \n
* @ref SOCKERR_TIMEOUT - Timeout occurred \n
* @ref SOCK_BUSY - Socket is busy.
*/
int32_t sendto(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port);
/**
* @ingroup WIZnet_socket_APIs
* @brief Receive datagram of UDP or MACRAW
* @details This function is an application I/F function which is used to receive the data in other then TCP mode. \n
* This function is used to receive UDP and MAC_RAW mode, and handle the header as well.
* This function can divide to received the packet data.
* On the MACRAW SOCKET, the addr and port parameters are ignored.
* @note In block io mode, it doesn't return until data reception is completed - data is filled as <I>len</I> in socket buffer
* In non-block io mode, it return @ref SOCK_BUSY immediately when <I>len</I> is greater than data size in socket buffer.
*
* @param sn Socket number. It should be <b>0 ~ @ref \_WIZCHIP_SOCK_NUM_</b>.
* @param buf Pointer buffer to read incoming data.
* @param len The max data length of data in buf.
* When the received packet size <= len, receives data as packet sized.
* When others, receives data as len.
* @param addr Pointer variable of destination IP address. It should be allocated 4 bytes.
* It is valid only when the first call recvfrom for receiving the packet.
* When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo).
* @param port Pointer variable of destination port number.
* It is valid only when the first call recvform for receiving the packet.
* When it is valid, @ref packinfo[7] should be set as '1' after call @ref getsockopt(sn, SO_PACKINFO, &packinfo).
*
* @return @b Success : This function return real received data size for success.\n
* @b Fail : @ref SOCKERR_DATALEN - zero data length \n
* @ref SOCKERR_SOCKMODE - Invalid operation in the socket \n
* @ref SOCKERR_SOCKNUM - Invalid socket number \n
* @ref SOCKBUSY - Socket is busy.
*/
int32_t recvfrom(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port);
/////////////////////////////
// SOCKET CONTROL & OPTION //
/////////////////////////////
#define SOCK_IO_BLOCK 0 ///< Socket Block IO Mode in @ref setsockopt().
#define SOCK_IO_NONBLOCK 1 ///< Socket Non-block IO Mode in @ref setsockopt().
/**
* @defgroup DATA_TYPE DATA TYPE
*/
/**
* @ingroup DATA_TYPE
* @brief The kind of Socket Interrupt.
* @sa Sn_IR, Sn_IMR, setSn_IR(), getSn_IR(), setSn_IMR(), getSn_IMR()
*/
typedef enum
{
SIK_CONNECTED = (1 << 0), ///< connected
SIK_DISCONNECTED = (1 << 1), ///< disconnected
SIK_RECEIVED = (1 << 2), ///< data received
SIK_TIMEOUT = (1 << 3), ///< timeout occurred
SIK_SENT = (1 << 4), ///< send ok
SIK_ALL = 0x1F, ///< all interrupt
}sockint_kind;
/**
* @ingroup DATA_TYPE
* @brief The type of @ref ctlsocket().
*/
typedef enum
{
CS_SET_IOMODE, ///< set socket IO mode with @ref SOCK_IO_BLOCK or @ref SOCK_IO_NONBLOCK
CS_GET_IOMODE, ///< get socket IO mode
CS_GET_MAXTXBUF, ///< get the size of socket buffer allocated in TX memory
CS_GET_MAXRXBUF, ///< get the size of socket buffer allocated in RX memory
CS_CLR_INTERRUPT, ///< clear the interrupt of socket with @ref sockint_kind
CS_GET_INTERRUPT, ///< get the socket interrupt. refer to @ref sockint_kind
CS_SET_INTMASK, ///< set the interrupt mask of socket with @ref sockint_kind
CS_GET_INTMASK ///< get the masked interrupt of socket. refer to @ref sockint_kind
}ctlsock_type;
/**
* @ingroup DATA_TYPE
* @brief The type of socket option in @ref setsockopt() or @ref getsockopt()
*/
typedef enum
{
SO_FLAG, ///< Valid only in getsockopt(), For set flag of socket refer to <I>flag</I> in @ref socket().
SO_TTL, ///< Set/Get TTL. @ref Sn_TTL ( @ref setSn_TTL(), @ref getSn_TTL() )
SO_TOS, ///< Set/Get TOS. @ref Sn_TOS ( @ref setSn_TOS(), @ref getSn_TOS() )
SO_MSS, ///< Set/Get MSS. @ref Sn_MSSR ( @ref setSn_MSSR(), @ref getSn_MSSR() )
SO_DESTIP, ///< Set/Get the destination IP address. @ref Sn_DIPR ( @ref setSn_DIPR(), @ref getSn_DIPR() )
SO_DESTPORT, ///< Set/Get the destination Port number. @ref Sn_DPORT ( @ref setSn_DPORT(), @ref getSn_DPORT() )
#if _WIZCHIP_ != 5100
SO_KEEPALIVESEND, ///< Valid only in setsockopt. Manually send keep-alive packet in TCP mode
#if _WIZCHIP_ > 5200
SO_KEEPALIVEAUTO, ///< Set/Get keep-alive auto transmission timer in TCP mode
#endif
#endif
SO_SENDBUF, ///< Valid only in getsockopt. Get the free data size of Socekt TX buffer. @ref Sn_TX_FSR, @ref getSn_TX_FSR()
SO_RECVBUF, ///< Valid only in getsockopt. Get the received data size in socket RX buffer. @ref Sn_RX_RSR, @ref getSn_RX_RSR()
SO_STATUS, ///< Valid only in getsockopt. Get the socket status. @ref Sn_SR, @ref getSn_SR()
SO_REMAINSIZE, ///< Valid only in getsockopt. Get the remained packet size in other then TCP mode.
SO_PACKINFO ///< Valid only in getsockopt. Get the packet information as @ref PACK_FIRST, @ref PACK_REMAINED, and @ref PACK_COMPLETED in other then TCP mode.
}sockopt_type;
/**
* @ingroup WIZnet_socket_APIs
* @brief Control socket.
* @details Control IO mode, Interrupt & Mask of socket and get the socket buffer information.
* Refer to @ref ctlsock_type.
* @param sn socket number
* @param cstype type of control socket. refer to @ref ctlsock_type.
* @param arg Data type and value is determined according to @ref ctlsock_type. \n
* <table>
* <tr> <td> @b cstype </td> <td> @b data type</td><td>@b value</td></tr>
* <tr> <td> @ref CS_SET_IOMODE \n @ref CS_GET_IOMODE </td> <td> uint8_t </td><td>@ref SOCK_IO_BLOCK @ref SOCK_IO_NONBLOCK</td></tr>
* <tr> <td> @ref CS_GET_MAXTXBUF \n @ref CS_GET_MAXRXBUF </td> <td> uint16_t </td><td> 0 ~ 16K </td></tr>
* <tr> <td> @ref CS_CLR_INTERRUPT \n @ref CS_GET_INTERRUPT \n @ref CS_SET_INTMASK \n @ref CS_GET_INTMASK </td> <td> @ref sockint_kind </td><td> @ref SIK_CONNECTED, etc. </td></tr>
* </table>
* @return @b Success @ref SOCK_OK \n
* @b fail @ref SOCKERR_ARG - Invalid argument\n
*/
int8_t ctlsocket(uint8_t sn, ctlsock_type cstype, void* arg);
/**
* @ingroup WIZnet_socket_APIs
* @brief set socket options
* @details Set socket option like as TTL, MSS, TOS, and so on. Refer to @ref sockopt_type.
*
* @param sn socket number
* @param sotype socket option type. refer to @ref sockopt_type
* @param arg Data type and value is determined according to <I>sotype</I>. \n
* <table>
* <tr> <td> @b sotype </td> <td> @b data type</td><td>@b value</td></tr>
* <tr> <td> @ref SO_TTL </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
* <tr> <td> @ref SO_TOS </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
* <tr> <td> @ref SO_MSS </td> <td> uint16_t </td><td> 0 ~ 65535 </td> </tr>
* <tr> <td> @ref SO_DESTIP </td> <td> uint8_t[4] </td><td> </td></tr>
* <tr> <td> @ref SO_DESTPORT </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
* <tr> <td> @ref SO_KEEPALIVESEND </td> <td> null </td><td> null </td></tr>
* <tr> <td> @ref SO_KEEPALIVEAUTO </td> <td> uint8_t </td><td> 0 ~ 255 </td></tr>
* </table>
* @return
* - @b Success : @ref SOCK_OK \n
* - @b Fail
* - @ref SOCKERR_SOCKNUM - Invalid Socket number \n
* - @ref SOCKERR_SOCKMODE - Invalid socket mode \n
* - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n
* - @ref SOCKERR_TIMEOUT - Timeout occurred when sending keep-alive packet \n
*/
int8_t setsockopt(uint8_t sn, sockopt_type sotype, void* arg);
/**
* @ingroup WIZnet_socket_APIs
* @brief get socket options
* @details Get socket option like as FLAG, TTL, MSS, and so on. Refer to @ref sockopt_type
* @param sn socket number
* @param sotype socket option type. refer to @ref sockopt_type
* @param arg Data type and value is determined according to <I>sotype</I>. \n
* <table>
* <tr> <td> @b sotype </td> <td>@b data type</td><td>@b value</td></tr>
* <tr> <td> @ref SO_FLAG </td> <td> uint8_t </td><td> @ref SF_ETHER_OWN, etc... </td> </tr>
* <tr> <td> @ref SO_TOS </td> <td> uint8_t </td><td> 0 ~ 255 </td> </tr>
* <tr> <td> @ref SO_MSS </td> <td> uint16_t </td><td> 0 ~ 65535 </td> </tr>
* <tr> <td> @ref SO_DESTIP </td> <td> uint8_t[4] </td><td> </td></tr>
* <tr> <td> @ref SO_DESTPORT </td> <td> uint16_t </td><td> </td></tr>
* <tr> <td> @ref SO_KEEPALIVEAUTO </td> <td> uint8_t </td><td> 0 ~ 255 </td></tr>
* <tr> <td> @ref SO_SENDBUF </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
* <tr> <td> @ref SO_RECVBUF </td> <td> uint16_t </td><td> 0 ~ 65535 </td></tr>
* <tr> <td> @ref SO_STATUS </td> <td> uint8_t </td><td> @ref SOCK_ESTABLISHED, etc.. </td></tr>
* <tr> <td> @ref SO_REMAINSIZE </td> <td> uint16_t </td><td> 0~ 65535 </td></tr>
* <tr> <td> @ref SO_PACKINFO </td> <td> uint8_t </td><td> @ref PACK_FIRST, etc... </td></tr>
* </table>
* @return
* - @b Success : @ref SOCK_OK \n
* - @b Fail
* - @ref SOCKERR_SOCKNUM - Invalid Socket number \n
* - @ref SOCKERR_SOCKOPT - Invalid socket option or its value \n
* - @ref SOCKERR_SOCKMODE - Invalid socket mode \n
* @note
* The option as PACK_REMAINED and SO_PACKINFO is valid only in NON-TCP mode and after call @ref recvfrom(). \n
* When SO_PACKINFO value is PACK_FIRST and the return value of recvfrom() is zero,
* This means the zero byte UDP data(UDP Header only) received.
*/
int8_t getsockopt(uint8_t sn, sockopt_type sotype, void* arg);
#endif // _SOCKET_H_

View File

@@ -0,0 +1,206 @@
// dpgeorge: this file taken from w5500/w5500.c and adapted to W5200
//*****************************************************************************
//
//! \file w5500.c
//! \brief W5500 HAL Interface.
//! \version 1.0.1
//! \date 2013/10/21
//! \par Revision history
//! <2014/05/01> V1.0.2
//! 1. Implicit type casting -> Explicit type casting. Refer to M20140501
//! Fixed the problem on porting into under 32bit MCU
//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh
//! Thank for your interesting and serious advices.
//! <2013/10/21> 1st Release
//! <2013/12/20> V1.0.1
//! 1. Remove warning
//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_
//! for loop optimized(removed). refer to M20131220
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#include "w5200.h"
#define SMASK (0x7ff) /* tx buffer mask */
#define RMASK (0x7ff) /* rx buffer mask */
#define SSIZE (2048) /* max tx buffer size */
#define RSIZE (2048) /* max rx buffer size */
#define TXBUF_BASE (0x8000)
#define RXBUF_BASE (0xc000)
#define SBASE(sn) (TXBUF_BASE + SSIZE * (sn)) /* tx buffer base for socket sn */
#define RBASE(sn) (RXBUF_BASE + RSIZE * (sn)) /* rx buffer base for socket sn */
uint8_t WIZCHIP_READ(uint32_t AddrSel) {
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
uint8_t spi_data[4] = {
AddrSel >> 8,
AddrSel,
0x00,
0x01,
};
WIZCHIP.IF.SPI._write_bytes(spi_data, 4);
uint8_t ret;
WIZCHIP.IF.SPI._read_bytes(&ret, 1);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
return ret;
}
void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb) {
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
uint8_t spi_data[5] = {
AddrSel >> 8,
AddrSel,
0x80,
0x01,
wb,
};
WIZCHIP.IF.SPI._write_bytes(spi_data, 5);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
void WIZCHIP_READ_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) {
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
uint8_t spi_data[4] = {
AddrSel >> 8,
AddrSel,
0x00 | ((len >> 8) & 0x7f),
len & 0xff,
};
WIZCHIP.IF.SPI._write_bytes(spi_data, 4);
WIZCHIP.IF.SPI._read_bytes(pBuf, len);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len) {
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
uint8_t spi_data[4] = {
AddrSel >> 8,
AddrSel,
0x80 | ((len >> 8) & 0x7f),
len & 0xff,
};
WIZCHIP.IF.SPI._write_bytes(spi_data, 4);
WIZCHIP.IF.SPI._write_bytes(pBuf, len);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
uint16_t getSn_TX_FSR(uint8_t sn) {
uint16_t val = 0, val1 = 0;
do {
val1 = (WIZCHIP_READ(Sn_TX_FSR(sn)) << 8) | WIZCHIP_READ(Sn_TX_FSR(sn) + 1);
if (val1 != 0) {
val = (WIZCHIP_READ(Sn_TX_FSR(sn)) << 8) | WIZCHIP_READ(Sn_TX_FSR(sn) + 1);
}
} while (val != val1);
return val;
}
uint16_t getSn_RX_RSR(uint8_t sn) {
uint16_t val = 0, val1 = 0;
do {
val1 = (WIZCHIP_READ(Sn_RX_RSR(sn)) << 8) | WIZCHIP_READ(Sn_RX_RSR(sn) + 1);
if (val1 != 0) {
val = (WIZCHIP_READ(Sn_RX_RSR(sn)) << 8) | WIZCHIP_READ(Sn_RX_RSR(sn) + 1);
}
} while (val != val1);
return val;
}
void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len) {
if (len == 0) {
return;
}
uint16_t ptr = getSn_TX_WR(sn);
uint16_t offset = ptr & SMASK;
uint32_t addr = offset + SBASE(sn);
if (offset + len > SSIZE) {
// implement wrap-around circular buffer
uint16_t size = SSIZE - offset;
WIZCHIP_WRITE_BUF(addr, wizdata, size);
WIZCHIP_WRITE_BUF(SBASE(sn), wizdata + size, len - size);
} else {
WIZCHIP_WRITE_BUF(addr, wizdata, len);
}
ptr += len;
setSn_TX_WR(sn, ptr);
}
void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len) {
if (len == 0) {
return;
}
uint16_t ptr = getSn_RX_RD(sn);
uint16_t offset = ptr & RMASK;
uint16_t addr = RBASE(sn) + offset;
if (offset + len > RSIZE) {
// implement wrap-around circular buffer
uint16_t size = RSIZE - offset;
WIZCHIP_READ_BUF(addr, wizdata, size);
WIZCHIP_READ_BUF(RBASE(sn), wizdata + size, len - size);
} else {
WIZCHIP_READ_BUF(addr, wizdata, len);
}
ptr += len;
setSn_RX_RD(sn, ptr);
}
void wiz_recv_ignore(uint8_t sn, uint16_t len) {
uint16_t ptr = getSn_RX_RD(sn);
ptr += len;
setSn_RX_RD(sn, ptr);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,237 @@
//*****************************************************************************
//
//! \file w5500.c
//! \brief W5500 HAL Interface.
//! \version 1.0.1
//! \date 2013/10/21
//! \par Revision history
//! <2014/05/01> V1.0.2
//! 1. Implicit type casting -> Explicit type casting. Refer to M20140501
//! Fixed the problem on porting into under 32bit MCU
//! Issued by Mathias ClauBen, wizwiki forum ID Think01 and bobh
//! Thank for your interesting and serious advices.
//! <2013/10/21> 1st Release
//! <2013/12/20> V1.0.1
//! 1. Remove warning
//! 2. WIZCHIP_READ_BUF WIZCHIP_WRITE_BUF in case _WIZCHIP_IO_MODE_SPI_FDM_
//! for loop optimized(removed). refer to M20131220
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
//#include <stdio.h>
#include "w5500.h"
#define _W5500_SPI_VDM_OP_ 0x00
#define _W5500_SPI_FDM_OP_LEN1_ 0x01
#define _W5500_SPI_FDM_OP_LEN2_ 0x02
#define _W5500_SPI_FDM_OP_LEN4_ 0x03
////////////////////////////////////////////////////
uint8_t WIZCHIP_READ(uint32_t AddrSel)
{
uint8_t ret;
uint8_t spi_data[3];
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
//ret = WIZCHIP.IF.SPI._read_byte();
spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
spi_data[2] = (AddrSel & 0x000000FF) >> 0;
Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3);
Chip_SSP_ReadFrames_Blocking(LPC_SSP0, &ret, 1);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
return ret;
}
void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb )
{
uint8_t spi_data[4];
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
//WIZCHIP.IF.SPI._write_byte(wb);
spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
spi_data[2] = (AddrSel & 0x000000FF) >> 0;
spi_data[3] = wb;
Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 4);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
{
uint8_t spi_data[3];
//uint16_t i;
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
AddrSel |= (_W5500_SPI_READ_ | _W5500_SPI_VDM_OP_);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
//for(i = 0; i < len; i++)
// pBuf[i] = WIZCHIP.IF.SPI._read_byte();
spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
spi_data[2] = (AddrSel & 0x000000FF) >> 0;
Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3);
Chip_SSP_ReadFrames_Blocking(LPC_SSP0, pBuf, len);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, uint16_t len)
{
uint8_t spi_data[3];
//uint16_t i;
WIZCHIP_CRITICAL_ENTER();
WIZCHIP.CS._select();
AddrSel |= (_W5500_SPI_WRITE_ | _W5500_SPI_VDM_OP_);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x00FF0000) >> 16);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x0000FF00) >> 8);
//WIZCHIP.IF.SPI._write_byte((AddrSel & 0x000000FF) >> 0);
//for(i = 0; i < len; i++)
// WIZCHIP.IF.SPI._write_byte(pBuf[i]);
spi_data[0] = (AddrSel & 0x00FF0000) >> 16;
spi_data[1] = (AddrSel & 0x0000FF00) >> 8;
spi_data[2] = (AddrSel & 0x000000FF) >> 0;
Chip_SSP_WriteFrames_Blocking(LPC_SSP0, spi_data, 3);
Chip_SSP_WriteFrames_Blocking(LPC_SSP0, pBuf, len);
WIZCHIP.CS._deselect();
WIZCHIP_CRITICAL_EXIT();
}
uint16_t getSn_TX_FSR(uint8_t sn)
{
uint16_t val=0,val1=0;
do
{
val1 = WIZCHIP_READ(Sn_TX_FSR(sn));
val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1));
if (val1 != 0)
{
val = WIZCHIP_READ(Sn_TX_FSR(sn));
val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn),1));
}
}while (val != val1);
return val;
}
uint16_t getSn_RX_RSR(uint8_t sn)
{
uint16_t val=0,val1=0;
do
{
val1 = WIZCHIP_READ(Sn_RX_RSR(sn));
val1 = (val1 << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1));
if (val1 != 0)
{
val = WIZCHIP_READ(Sn_RX_RSR(sn));
val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn),1));
}
}while (val != val1);
return val;
}
void wiz_send_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
uint16_t ptr = 0;
uint32_t addrsel = 0;
if(len == 0) return;
ptr = getSn_TX_WR(sn);
//M20140501 : implict type casting -> explict type casting
//addrsel = (ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3);
addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_TXBUF_BLOCK(sn) << 3);
//
WIZCHIP_WRITE_BUF(addrsel,wizdata, len);
ptr += len;
setSn_TX_WR(sn,ptr);
}
void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
uint16_t ptr = 0;
uint32_t addrsel = 0;
if(len == 0) return;
ptr = getSn_RX_RD(sn);
//M20140501 : implict type casting -> explict type casting
//addrsel = ((ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
addrsel = ((uint32_t)ptr << 8) + (WIZCHIP_RXBUF_BLOCK(sn) << 3);
//
WIZCHIP_READ_BUF(addrsel, wizdata, len);
ptr += len;
setSn_RX_RD(sn,ptr);
}
void wiz_recv_ignore(uint8_t sn, uint16_t len)
{
uint16_t ptr = 0;
ptr = getSn_RX_RD(sn);
ptr += len;
setSn_RX_RD(sn,ptr);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,657 @@
//****************************************************************************/
//!
//! \file wizchip_conf.c
//! \brief WIZCHIP Config Header File.
//! \version 1.0.1
//! \date 2013/10/21
//! \par Revision history
//! <2014/05/01> V1.0.1 Refer to M20140501
//! 1. Explicit type casting in wizchip_bus_readbyte() & wizchip_bus_writebyte()
// Issued by Mathias ClauBen.
//! uint32_t type converts into ptrdiff_t first. And then recoverting it into uint8_t*
//! For remove the warning when pointer type size is not 32bit.
//! If ptrdiff_t doesn't support in your complier, You should must replace ptrdiff_t into your suitable pointer type.
//! <2013/10/21> 1st Release
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************/
//A20140501 : for use the type - ptrdiff_t
#include <stddef.h>
//
#include "wizchip_conf.h"
/**
* @brief Default function to enable interrupt.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_cris_enter(void) {};
/**
* @brief Default function to disable interrupt.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_cris_exit(void) {};
/**
* @brief Default function to select chip.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_cs_select(void) {};
/**
* @brief Default function to deselect chip.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_cs_deselect(void) {};
/**
* @brief Default function to read in direct or indirect interface.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
//M20140501 : Explict pointer type casting
//uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *) AddrSel); };
uint8_t wizchip_bus_readbyte(uint32_t AddrSel) { return * ((volatile uint8_t *)((ptrdiff_t) AddrSel)); };
/**
* @brief Default function to write in direct or indirect interface.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
//M20140501 : Explict pointer type casting
//void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile uint8_t*) AddrSel) = wb; };
void wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb) { *((volatile uint8_t*)((ptrdiff_t)AddrSel)) = wb; };
/**
* @brief Default function to read in SPI interface.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_spi_readbytes(uint8_t *buf, uint32_t len) {}
/**
* @brief Default function to write in SPI interface.
* @note This function help not to access wrong address. If you do not describe this function or register any functions,
* null function is called.
*/
void wizchip_spi_writebytes(const uint8_t *buf, uint32_t len) {}
/**
* @\ref _WIZCHIP instance
*/
_WIZCHIP WIZCHIP =
{
.id = _WIZCHIP_ID_,
.if_mode = _WIZCHIP_IO_MODE_,
.CRIS._enter = wizchip_cris_enter,
.CRIS._exit = wizchip_cris_exit,
.CS._select = wizchip_cs_select,
.CS._deselect = wizchip_cs_deselect,
.IF.BUS._read_byte = wizchip_bus_readbyte,
.IF.BUS._write_byte = wizchip_bus_writebyte
// .IF.SPI._read_byte = wizchip_spi_readbyte,
// .IF.SPI._write_byte = wizchip_spi_writebyte
};
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
static uint8_t _SUBN_[4]; // subnet
#endif
static uint8_t _DNS_[4]; // DNS server ip address
static dhcp_mode _DHCP_; // DHCP mode
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void))
{
if(!cris_en || !cris_ex)
{
WIZCHIP.CRIS._enter = wizchip_cris_enter;
WIZCHIP.CRIS._exit = wizchip_cris_exit;
}
else
{
WIZCHIP.CRIS._enter = cris_en;
WIZCHIP.CRIS._exit = cris_ex;
}
}
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void))
{
if(!cs_sel || !cs_desel)
{
WIZCHIP.CS._select = wizchip_cs_select;
WIZCHIP.CS._deselect = wizchip_cs_deselect;
}
else
{
WIZCHIP.CS._select = cs_sel;
WIZCHIP.CS._deselect = cs_desel;
}
}
void reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb))
{
while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_BUS_));
if(!bus_rb || !bus_wb)
{
WIZCHIP.IF.BUS._read_byte = wizchip_bus_readbyte;
WIZCHIP.IF.BUS._write_byte = wizchip_bus_writebyte;
}
else
{
WIZCHIP.IF.BUS._read_byte = bus_rb;
WIZCHIP.IF.BUS._write_byte = bus_wb;
}
}
void reg_wizchip_spi_cbfunc(void (*spi_rb)(uint8_t *, uint32_t), void (*spi_wb)(const uint8_t *, uint32_t))
{
while(!(WIZCHIP.if_mode & _WIZCHIP_IO_MODE_SPI_));
if(!spi_rb || !spi_wb)
{
WIZCHIP.IF.SPI._read_bytes = wizchip_spi_readbytes;
WIZCHIP.IF.SPI._write_bytes = wizchip_spi_writebytes;
}
else
{
WIZCHIP.IF.SPI._read_bytes = spi_rb;
WIZCHIP.IF.SPI._write_bytes = spi_wb;
}
}
int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg)
{
uint8_t tmp = 0;
uint8_t* ptmp[2] = {0,0};
switch(cwtype)
{
case CW_RESET_WIZCHIP:
wizchip_sw_reset();
break;
case CW_INIT_WIZCHIP:
if(arg != 0)
{
ptmp[0] = (uint8_t*)arg;
ptmp[1] = ptmp[0] + _WIZCHIP_SOCK_NUM_;
}
return wizchip_init(ptmp[0], ptmp[1]);
case CW_CLR_INTERRUPT:
wizchip_clrinterrupt(*((intr_kind*)arg));
break;
case CW_GET_INTERRUPT:
*((intr_kind*)arg) = wizchip_getinterrupt();
break;
case CW_SET_INTRMASK:
wizchip_setinterruptmask(*((intr_kind*)arg));
break;
case CW_GET_INTRMASK:
*((intr_kind*)arg) = wizchip_getinterruptmask();
break;
#if _WIZCHIP_ > 5100
case CW_SET_INTRTIME:
setINTLEVEL(*(uint16_t*)arg);
break;
case CW_GET_INTRTIME:
*(uint16_t*)arg = getINTLEVEL();
break;
#endif
case CW_GET_ID:
((uint8_t*)arg)[0] = WIZCHIP.id[0];
((uint8_t*)arg)[1] = WIZCHIP.id[1];
((uint8_t*)arg)[2] = WIZCHIP.id[2];
((uint8_t*)arg)[3] = WIZCHIP.id[3];
((uint8_t*)arg)[4] = WIZCHIP.id[4];
((uint8_t*)arg)[5] = 0;
break;
#if _WIZCHIP_ == 5500
case CW_RESET_PHY:
wizphy_reset();
break;
case CW_SET_PHYCONF:
wizphy_setphyconf((wiz_PhyConf*)arg);
break;
case CW_GET_PHYCONF:
wizphy_getphyconf((wiz_PhyConf*)arg);
break;
case CW_GET_PHYSTATUS:
break;
case CW_SET_PHYPOWMODE:
return wizphy_setphypmode(*(uint8_t*)arg);
#endif
case CW_GET_PHYPOWMODE:
tmp = wizphy_getphypmode();
if((int8_t)tmp == -1) return -1;
*(uint8_t*)arg = tmp;
break;
case CW_GET_PHYLINK:
tmp = wizphy_getphylink();
if((int8_t)tmp == -1) return -1;
*(uint8_t*)arg = tmp;
break;
default:
return -1;
}
return 0;
}
int8_t ctlnetwork(ctlnetwork_type cntype, void* arg)
{
switch(cntype)
{
case CN_SET_NETINFO:
wizchip_setnetinfo((wiz_NetInfo*)arg);
break;
case CN_GET_NETINFO:
wizchip_getnetinfo((wiz_NetInfo*)arg);
break;
case CN_SET_NETMODE:
return wizchip_setnetmode(*(netmode_type*)arg);
case CN_GET_NETMODE:
*(netmode_type*)arg = wizchip_getnetmode();
break;
case CN_SET_TIMEOUT:
wizchip_settimeout((wiz_NetTimeout*)arg);
break;
case CN_GET_TIMEOUT:
wizchip_gettimeout((wiz_NetTimeout*)arg);
break;
default:
return -1;
}
return 0;
}
void wizchip_sw_reset(void)
{
uint8_t gw[4], sn[4], sip[4];
uint8_t mac[6];
getSHAR(mac);
getGAR(gw); getSUBR(sn); getSIPR(sip);
setMR(MR_RST);
getMR(); // for delay
setSHAR(mac);
setGAR(gw);
setSUBR(sn);
setSIPR(sip);
}
int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize)
{
int8_t i;
int8_t tmp = 0;
wizchip_sw_reset();
if(txsize)
{
tmp = 0;
for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
tmp += txsize[i];
if(tmp > 16) return -1;
for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
setSn_TXBUF_SIZE(i, txsize[i]);
}
if(rxsize)
{
tmp = 0;
for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
tmp += rxsize[i];
if(tmp > 16) return -1;
for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
setSn_RXBUF_SIZE(i, rxsize[i]);
}
return 0;
}
void wizchip_clrinterrupt(intr_kind intr)
{
uint8_t ir = (uint8_t)intr;
uint8_t sir = (uint8_t)((uint16_t)intr >> 8);
#if _WIZCHIP_ < 5500
ir |= (1<<4); // IK_WOL
#endif
#if _WIZCHIP_ == 5200
ir |= (1 << 6);
#endif
#if _WIZCHIP_ < 5200
sir &= 0x0F;
#endif
#if _WIZCHIP_ == 5100
ir |= sir;
setIR(ir);
#else
setIR(ir);
setSIR(sir);
#endif
}
intr_kind wizchip_getinterrupt(void)
{
uint8_t ir = 0;
uint8_t sir = 0;
uint16_t ret = 0;
#if _WIZCHIP_ == 5100
ir = getIR();
sir = ir 0x0F;
#else
ir = getIR();
sir = getSIR();
#endif
#if _WIZCHIP_ < 5500
ir &= ~(1<<4); // IK_WOL
#endif
#if _WIZCHIP_ == 5200
ir &= ~(1 << 6);
#endif
ret = sir;
ret = (ret << 8) + ir;
return (intr_kind)ret;
}
void wizchip_setinterruptmask(intr_kind intr)
{
uint8_t imr = (uint8_t)intr;
uint8_t simr = (uint8_t)((uint16_t)intr >> 8);
#if _WIZCHIP_ < 5500
imr &= ~(1<<4); // IK_WOL
#endif
#if _WIZCHIP_ == 5200
imr &= ~(1 << 6);
#endif
#if _WIZCHIP_ < 5200
simr &= 0x0F;
#endif
#if _WIZCHIP_ == 5100
imr |= simr;
setIMR(imr);
#else
setIMR(imr);
setSIMR(simr);
#endif
}
intr_kind wizchip_getinterruptmask(void)
{
uint8_t imr = 0;
uint8_t simr = 0;
uint16_t ret = 0;
#if _WIZCHIP_ == 5100
imr = getIMR();
simr = imr 0x0F;
#else
imr = getIMR();
simr = getSIMR();
#endif
#if _WIZCHIP_ < 5500
imr &= ~(1<<4); // IK_WOL
#endif
#if _WIZCHIP_ == 5200
imr &= ~(1 << 6); // IK_DEST_UNREACH
#endif
ret = simr;
ret = (ret << 8) + imr;
return (intr_kind)ret;
}
int8_t wizphy_getphylink(void)
{
int8_t tmp;
#if _WIZCHIP_ == 5200
if(getPHYSTATUS() & PHYSTATUS_LINK)
tmp = PHY_LINK_ON;
else
tmp = PHY_LINK_OFF;
#elif _WIZCHIP_ == 5500
if(getPHYCFGR() & PHYCFGR_LNK_ON)
tmp = PHY_LINK_ON;
else
tmp = PHY_LINK_OFF;
#else
tmp = -1;
#endif
return tmp;
}
#if _WIZCHIP_ > 5100
int8_t wizphy_getphypmode(void)
{
int8_t tmp = 0;
#if _WIZCHIP_ == 5200
if(getPHYSTATUS() & PHYSTATUS_POWERDOWN)
tmp = PHY_POWER_DOWN;
else
tmp = PHY_POWER_NORM;
#elif _WIZCHIP_ == 5500
if(getPHYCFGR() & PHYCFGR_OPMDC_PDOWN)
tmp = PHY_POWER_DOWN;
else
tmp = PHY_POWER_NORM;
#else
tmp = -1;
#endif
return tmp;
}
#endif
#if _WIZCHIP_ == 5500
void wizphy_reset(void)
{
uint8_t tmp = getPHYCFGR();
tmp &= PHYCFGR_RST;
setPHYCFGR(tmp);
tmp = getPHYCFGR();
tmp |= ~PHYCFGR_RST;
setPHYCFGR(tmp);
}
void wizphy_setphyconf(wiz_PhyConf* phyconf)
{
uint8_t tmp = 0;
if(phyconf->by == PHY_CONFBY_SW)
tmp |= PHYCFGR_OPMD;
else
tmp &= ~PHYCFGR_OPMD;
if(phyconf->mode == PHY_MODE_AUTONEGO)
tmp |= PHYCFGR_OPMDC_ALLA;
else
{
if(phyconf->duplex == PHY_DUPLEX_FULL)
{
if(phyconf->speed == PHY_SPEED_100)
tmp |= PHYCFGR_OPMDC_100F;
else
tmp |= PHYCFGR_OPMDC_10F;
}
else
{
if(phyconf->speed == PHY_SPEED_100)
tmp |= PHYCFGR_OPMDC_100H;
else
tmp |= PHYCFGR_OPMDC_10H;
}
}
setPHYCFGR(tmp);
wizphy_reset();
}
void wizphy_getphyconf(wiz_PhyConf* phyconf)
{
uint8_t tmp = 0;
tmp = getPHYCFGR();
phyconf->by = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW;
switch(tmp & PHYCFGR_OPMDC_ALLA)
{
case PHYCFGR_OPMDC_ALLA:
case PHYCFGR_OPMDC_100FA:
phyconf->mode = PHY_MODE_AUTONEGO;
break;
default:
phyconf->mode = PHY_MODE_MANUAL;
break;
}
switch(tmp & PHYCFGR_OPMDC_ALLA)
{
case PHYCFGR_OPMDC_100FA:
case PHYCFGR_OPMDC_100F:
case PHYCFGR_OPMDC_100H:
phyconf->speed = PHY_SPEED_100;
break;
default:
phyconf->speed = PHY_SPEED_10;
break;
}
switch(tmp & PHYCFGR_OPMDC_ALLA)
{
case PHYCFGR_OPMDC_100FA:
case PHYCFGR_OPMDC_100F:
case PHYCFGR_OPMDC_10F:
phyconf->duplex = PHY_DUPLEX_FULL;
break;
default:
phyconf->duplex = PHY_DUPLEX_HALF;
break;
}
}
void wizphy_getphystat(wiz_PhyConf* phyconf)
{
uint8_t tmp = getPHYCFGR();
phyconf->duplex = (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10;
}
int8_t wizphy_setphypmode(uint8_t pmode)
{
uint8_t tmp = 0;
tmp = getPHYCFGR();
if((tmp & PHYCFGR_OPMD)== 0) return -1;
tmp &= ~PHYCFGR_OPMDC_ALLA;
if( pmode == PHY_POWER_DOWN)
tmp |= PHYCFGR_OPMDC_PDOWN;
else
tmp |= PHYCFGR_OPMDC_ALLA;
setPHYCFGR(tmp);
wizphy_reset();
tmp = getPHYCFGR();
if( pmode == PHY_POWER_DOWN)
{
if(tmp & PHYCFGR_OPMDC_PDOWN) return 0;
}
else
{
if(tmp & PHYCFGR_OPMDC_ALLA) return 0;
}
return -1;
}
#endif
void wizchip_setnetinfo(wiz_NetInfo* pnetinfo)
{
setSHAR(pnetinfo->mac);
setGAR(pnetinfo->gw);
setSUBR(pnetinfo->sn);
setSIPR(pnetinfo->ip);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
_SUBN_[0] = pnetinfo->sn[0];
_SUBN_[1] = pnetinfo->sn[1];
_SUBN_[2] = pnetinfo->sn[2];
_SUBN_[3] = pnetinfo->sn[3];
#endif
_DNS_[0] = pnetinfo->dns[0];
_DNS_[1] = pnetinfo->dns[1];
_DNS_[2] = pnetinfo->dns[2];
_DNS_[3] = pnetinfo->dns[3];
_DHCP_ = pnetinfo->dhcp;
}
void wizchip_getnetinfo(wiz_NetInfo* pnetinfo)
{
getSHAR(pnetinfo->mac);
getGAR(pnetinfo->gw);
getSUBR(pnetinfo->sn);
getSIPR(pnetinfo->ip);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
pnetinfo->sn[0] = _SUBN_[0];
pnetinfo->sn[1] = _SUBN_[1];
pnetinfo->sn[2] = _SUBN_[2];
pnetinfo->sn[3] = _SUBN_[3];
#endif
pnetinfo->dns[0]= _DNS_[0];
pnetinfo->dns[1]= _DNS_[1];
pnetinfo->dns[2]= _DNS_[2];
pnetinfo->dns[3]= _DNS_[3];
pnetinfo->dhcp = _DHCP_;
}
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
uint8_t *wizchip_getsubn(void) {
return _SUBN_;
}
#endif
int8_t wizchip_setnetmode(netmode_type netmode)
{
uint8_t tmp = 0;
#if _WIZCHIP_ != 5500
if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK)) return -1;
#else
if(netmode & ~(NM_WAKEONLAN | NM_PPPOE | NM_PINGBLOCK | NM_FORCEARP)) return -1;
#endif
tmp = getMR();
tmp |= (uint8_t)netmode;
setMR(tmp);
return 0;
}
netmode_type wizchip_getnetmode(void)
{
return (netmode_type) getMR();
}
void wizchip_settimeout(wiz_NetTimeout* nettime)
{
setRCR(nettime->retry_cnt);
setRTR(nettime->time_100us);
}
void wizchip_gettimeout(wiz_NetTimeout* nettime)
{
nettime->retry_cnt = getRCR();
nettime->time_100us = getRTR();
}

View File

@@ -0,0 +1,552 @@
//*****************************************************************************
//
//! \file wizchip_conf.h
//! \brief WIZCHIP Config Header File.
//! \version 1.0.0
//! \date 2013/10/21
//! \par Revision history
//! <2013/10/21> 1st Release
//! \author MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
/**
* @defgroup extra_functions 2. WIZnet Extra Functions
*
* @brief These functions is optional function. It could be replaced at WIZCHIP I/O function because they were made by WIZCHIP I/O functions.
* @details There are functions of configuring WIZCHIP, network, interrupt, phy, network information and timer. \n
*
*/
#ifndef _WIZCHIP_CONF_H_
#define _WIZCHIP_CONF_H_
#include <stdint.h>
/**
* @brief Select WIZCHIP.
* @todo You should select one, \b 5100, \b 5200 ,\b 5500 or etc. \n\n
* ex> <code> #define \_WIZCHIP_ 5500 </code>
*/
#define _WIZCHIP_ 5200 // 5100, 5200, 5500
#define _WIZCHIP_IO_MODE_NONE_ 0x0000
#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */
#define _WIZCHIP_IO_MODE_SPI_ 0x0200 /**< SPI interface mode */
//#define _WIZCHIP_IO_MODE_IIC_ 0x0400
//#define _WIZCHIP_IO_MODE_SDIO_ 0x0800
// Add to
//
#define _WIZCHIP_IO_MODE_BUS_DIR_ (_WIZCHIP_IO_MODE_BUS_ + 1) /**< BUS interface mode for direct */
#define _WIZCHIP_IO_MODE_BUS_INDIR_ (_WIZCHIP_IO_MODE_BUS_ + 2) /**< BUS interface mode for indirect */
#define _WIZCHIP_IO_MODE_SPI_VDM_ (_WIZCHIP_IO_MODE_SPI_ + 1) /**< SPI interface mode for variable length data*/
#define _WIZCHIP_IO_MODE_SPI_FDM_ (_WIZCHIP_IO_MODE_SPI_ + 2) /**< SPI interface mode for fixed length data mode*/
#if (_WIZCHIP_ == 5100)
#define _WIZCHIP_ID_ "W5100\0"
/**
* @brief Define interface mode.
* @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ , @ref \_WIZCHIP_IO_MODE_BUS_DIR_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_
*/
// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_DIR_
// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_
#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_
#elif (_WIZCHIP_ == 5200)
#define _WIZCHIP_ID_ "W5200\0"
/**
* @brief Define interface mode.
* @todo you should select interface mode as chip. Select one of @ref \_WIZCHIP_IO_MODE_SPI_ or @ref \_WIZCHIP_IO_MODE_BUS_INDIR_
*/
// #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_BUS_INDIR_
#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_
#include "w5200/w5200.h"
#elif (_WIZCHIP_ == 5500)
#define _WIZCHIP_ID_ "W5500\0"
/**
* @brief Define interface mode. \n
* @todo Should select interface mode as chip.
* - @ref \_WIZCHIP_IO_MODE_SPI_ \n
* -@ref \_WIZCHIP_IO_MODE_SPI_VDM_ : Valid only in @ref \_WIZCHIP_ == 5500 \n
* -@ref \_WIZCHIP_IO_MODE_SPI_FDM_ : Valid only in @ref \_WIZCHIP_ == 5500 \n
* - @ref \_WIZCHIP_IO_MODE_BUS_ \n
* - @ref \_WIZCHIP_IO_MODE_BUS_DIR_ \n
* - @ref \_WIZCHIP_IO_MODE_BUS_INDIR_ \n
* - Others will be defined in future. \n\n
* ex> <code> #define \_WIZCHIP_IO_MODE_ \_WIZCHIP_IO_MODE_SPI_VDM_ </code>
*
*/
//#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_FDM_
#define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_
#include "w5500/w5500.h"
#else
#error "Unknown defined _WIZCHIP_. You should define one of 5100, 5200, and 5500 !!!"
#endif
#ifndef _WIZCHIP_IO_MODE_
#error "Undefined _WIZCHIP_IO_MODE_. You should define it !!!"
#endif
/**
* @brief Define I/O base address when BUS IF mode.
* @todo Should re-define it to fit your system when BUS IF Mode (@ref \_WIZCHIP_IO_MODE_BUS_,
* @ref \_WIZCHIP_IO_MODE_BUS_DIR_, @ref \_WIZCHIP_IO_MODE_BUS_INDIR_). \n\n
* ex> <code> #define \_WIZCHIP_IO_BASE_ 0x00008000 </code>
*/
#define _WIZCHIP_IO_BASE_ 0x00000000 //
#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS
#ifndef _WIZCHIP_IO_BASE_
#error "You should be define _WIZCHIP_IO_BASE to fit your system memory map."
#endif
#endif
#if _WIZCHIP_ > 5100
#define _WIZCHIP_SOCK_NUM_ 8 ///< The count of independant socket of @b WIZCHIP
#else
#define _WIZCHIP_SOCK_NUM_ 4 ///< The count of independant socket of @b WIZCHIP
#endif
/********************************************************
* WIZCHIP BASIC IF functions for SPI, SDIO, I2C , ETC.
*********************************************************/
/**
* @ingroup DATA_TYPE
* @brief The set of callback functions for W5500:@ref WIZCHIP_IO_Functions W5200:@ref WIZCHIP_IO_Functions_W5200
*/
typedef struct __WIZCHIP
{
uint16_t if_mode; ///< host interface mode
uint8_t id[6]; ///< @b WIZCHIP ID such as @b 5100, @b 5200, @b 5500, and so on.
/**
* The set of critical section callback func.
*/
struct _CRIS
{
void (*_enter) (void); ///< crtical section enter
void (*_exit) (void); ///< critial section exit
}CRIS;
/**
* The set of @ref\_WIZCHIP_ select control callback func.
*/
struct _CS
{
void (*_select) (void); ///< @ref \_WIZCHIP_ selected
void (*_deselect)(void); ///< @ref \_WIZCHIP_ deselected
}CS;
/**
* The set of interface IO callback func.
*/
union _IF
{
/**
* For BUS interface IO
*/
struct
{
uint8_t (*_read_byte) (uint32_t AddrSel);
void (*_write_byte) (uint32_t AddrSel, uint8_t wb);
}BUS;
/**
* For SPI interface IO
*/
struct
{
void (*_read_bytes) (uint8_t *buf, uint32_t len);
void (*_write_bytes) (const uint8_t *buf, uint32_t len);
}SPI;
// To be added
//
}IF;
}_WIZCHIP;
extern _WIZCHIP WIZCHIP;
/**
* @ingroup DATA_TYPE
* WIZCHIP control type enumration used in @ref ctlwizchip().
*/
typedef enum
{
CW_RESET_WIZCHIP, ///< Resets WIZCHIP by softly
CW_INIT_WIZCHIP, ///< Inializes to WIZCHIP with SOCKET buffer size 2 or 1 dimension array typed uint8_t.
CW_GET_INTERRUPT, ///< Get Interrupt status of WIZCHIP
CW_CLR_INTERRUPT, ///< Clears interrupt
CW_SET_INTRMASK, ///< Masks interrupt
CW_GET_INTRMASK, ///< Get interrupt mask
CW_SET_INTRTIME, ///< Set interval time between the current and next interrupt.
CW_GET_INTRTIME, ///< Set interval time between the current and next interrupt.
CW_GET_ID, ///< Gets WIZCHIP name.
#if _WIZCHIP_ == 5500
CW_RESET_PHY, ///< Resets internal PHY. Valid Only W5000
CW_SET_PHYCONF, ///< When PHY configured by interal register, PHY operation mode (Manual/Auto, 10/100, Half/Full). Valid Only W5000
CW_GET_PHYCONF, ///< Get PHY operation mode in interal register. Valid Only W5000
CW_GET_PHYSTATUS, ///< Get real PHY status on operating. Valid Only W5000
CW_SET_PHYPOWMODE, ///< Set PHY power mode as noraml and down when PHYSTATUS.OPMD == 1. Valid Only W5000
#endif
CW_GET_PHYPOWMODE, ///< Get PHY Power mode as down or normal
CW_GET_PHYLINK ///< Get PHY Link status
}ctlwizchip_type;
/**
* @ingroup DATA_TYPE
* Network control type enumration used in @ref ctlnetwork().
*/
typedef enum
{
CN_SET_NETINFO, ///< Set Network with @ref wiz_NetInfo
CN_GET_NETINFO, ///< Get Network with @ref wiz_NetInfo
CN_SET_NETMODE, ///< Set network mode as WOL, PPPoE, Ping Block, and Force ARP mode
CN_GET_NETMODE, ///< Get network mode as WOL, PPPoE, Ping Block, and Force ARP mode
CN_SET_TIMEOUT, ///< Set network timeout as retry count and time.
CN_GET_TIMEOUT, ///< Get network timeout as retry count and time.
}ctlnetwork_type;
/**
* @ingroup DATA_TYPE
* Interrupt kind when CW_SET_INTRRUPT, CW_GET_INTERRUPT, CW_SET_INTRMASK
* and CW_GET_INTRMASK is used in @ref ctlnetwork().
* It can be used with OR operation.
*/
typedef enum
{
#if _WIZCHIP_ > 5200
IK_WOL = (1 << 4), ///< Wake On Lan by receiving the magic packet. Valid in W500.
#endif
IK_PPPOE_TERMINATED = (1 << 5), ///< PPPoE Disconnected
#if _WIZCHIP_ != 5200
IK_DEST_UNREACH = (1 << 6), ///< Destination IP & Port Unreable, No use in W5200
#endif
IK_IP_CONFLICT = (1 << 7), ///< IP conflict occurred
IK_SOCK_0 = (1 << 8), ///< Socket 0 interrupt
IK_SOCK_1 = (1 << 9), ///< Socket 1 interrupt
IK_SOCK_2 = (1 << 10), ///< Socket 2 interrupt
IK_SOCK_3 = (1 << 11), ///< Socket 3 interrupt
#if _WIZCHIP_ > 5100
IK_SOCK_4 = (1 << 12), ///< Socket 4 interrupt, No use in 5100
IK_SOCK_5 = (1 << 13), ///< Socket 5 interrupt, No use in 5100
IK_SOCK_6 = (1 << 14), ///< Socket 6 interrupt, No use in 5100
IK_SOCK_7 = (1 << 15), ///< Socket 7 interrupt, No use in 5100
#endif
#if _WIZCHIP_ > 5100
IK_SOCK_ALL = (0xFF << 8) ///< All Socket interrpt
#else
IK_SOCK_ALL = (0x0F << 8) ///< All Socket interrpt
#endif
}intr_kind;
#define PHY_CONFBY_HW 0 ///< Configured PHY operation mode by HW pin
#define PHY_CONFBY_SW 1 ///< Configured PHY operation mode by SW register
#define PHY_MODE_MANUAL 0 ///< Configured PHY operation mode with user setting.
#define PHY_MODE_AUTONEGO 1 ///< Configured PHY operation mode with auto-negotiation
#define PHY_SPEED_10 0 ///< Link Speed 10
#define PHY_SPEED_100 1 ///< Link Speed 100
#define PHY_DUPLEX_HALF 0 ///< Link Half-Duplex
#define PHY_DUPLEX_FULL 1 ///< Link Full-Duplex
#define PHY_LINK_OFF 0 ///< Link Off
#define PHY_LINK_ON 1 ///< Link On
#define PHY_POWER_NORM 0 ///< PHY power normal mode
#define PHY_POWER_DOWN 1 ///< PHY power down mode
#if _WIZCHIP_ == 5500
/**
* @ingroup DATA_TYPE
* It configures PHY configuration when CW_SET PHYCONF or CW_GET_PHYCONF in W5500,
* and it indicates the real PHY status configured by HW or SW in all WIZCHIP. \n
* Valid only in W5500.
*/
typedef struct wiz_PhyConf_t
{
uint8_t by; ///< set by @ref PHY_CONFBY_HW or @ref PHY_CONFBY_SW
uint8_t mode; ///< set by @ref PHY_MODE_MANUAL or @ref PHY_MODE_AUTONEGO
uint8_t speed; ///< set by @ref PHY_SPEED_10 or @ref PHY_SPEED_100
uint8_t duplex; ///< set by @ref PHY_DUPLEX_HALF @ref PHY_DUPLEX_FULL
//uint8_t power; ///< set by @ref PHY_POWER_NORM or @ref PHY_POWER_DOWN
//uint8_t link; ///< Valid only in CW_GET_PHYSTATUS. set by @ref PHY_LINK_ON or PHY_DUPLEX_OFF
}wiz_PhyConf;
#endif
/**
* @ingroup DATA_TYPE
* It used in setting dhcp_mode of @ref wiz_NetInfo.
*/
typedef enum
{
NETINFO_STATIC = 1, ///< Static IP configuration by manually.
NETINFO_DHCP ///< Dynamic IP configruation from a DHCP sever
}dhcp_mode;
/**
* @ingroup DATA_TYPE
* Network Information for WIZCHIP
*/
typedef struct wiz_NetInfo_t
{
uint8_t mac[6]; ///< Source Mac Address
uint8_t ip[4]; ///< Source IP Address
uint8_t sn[4]; ///< Subnet Mask
uint8_t gw[4]; ///< Gateway IP Address
uint8_t dns[4]; ///< DNS server IP Address
dhcp_mode dhcp; ///< 1 - Static, 2 - DHCP
}wiz_NetInfo;
/**
* @ingroup DATA_TYPE
* Network mode
*/
typedef enum
{
#if _WIZCHIP_ == 5500
NM_FORCEARP = (1<<1), ///< Force to APP send whenever udp data is sent. Valid only in W5500
#endif
NM_WAKEONLAN = (1<<5), ///< Wake On Lan
NM_PINGBLOCK = (1<<4), ///< Block ping-request
NM_PPPOE = (1<<3), ///< PPPoE mode
}netmode_type;
/**
* @ingroup DATA_TYPE
* Used in CN_SET_TIMEOUT or CN_GET_TIMEOUT of @ref ctlwizchip() for timeout configruation.
*/
typedef struct wiz_NetTimeout_t
{
uint8_t retry_cnt; ///< retry count
uint16_t time_100us; ///< time unit 100us
}wiz_NetTimeout;
/**
*@brief Registers call back function for critical section of I/O functions such as
*\ref WIZCHIP_READ, @ref WIZCHIP_WRITE, @ref WIZCHIP_READ_BUF and @ref WIZCHIP_WRITE_BUF.
*@param cris_en : callback function for critical section enter.
*@param cris_ex : callback function for critical section exit.
*@todo Describe @ref WIZCHIP_CRITICAL_ENTER and @ref WIZCHIP_CRITICAL_EXIT marco or register your functions.
*@note If you do not describe or register, default functions(@ref wizchip_cris_enter & @ref wizchip_cris_exit) is called.
*/
void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void));
/**
*@brief Registers call back function for WIZCHIP select & deselect.
*@param cs_sel : callback function for WIZCHIP select
*@param cs_desel : callback fucntion for WIZCHIP deselect
*@todo Describe @ref wizchip_cs_select and @ref wizchip_cs_deselect function or register your functions.
*@note If you do not describe or register, null function is called.
*/
void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void));
/**
*@brief Registers call back function for bus interface.
*@param bus_rb : callback function to read byte data using system bus
*@param bus_wb : callback function to write byte data using system bus
*@todo Describe @ref wizchip_bus_readbyte and @ref wizchip_bus_writebyte function
*or register your functions.
*@note If you do not describe or register, null function is called.
*/
void reg_wizchip_bus_cbfunc(uint8_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, uint8_t wb));
/**
*@brief Registers call back function for SPI interface.
*@param spi_rb : callback function to read byte usig SPI
*@param spi_wb : callback function to write byte usig SPI
*@todo Describe \ref wizchip_spi_readbyte and \ref wizchip_spi_writebyte function
*or register your functions.
*@note If you do not describe or register, null function is called.
*/
void reg_wizchip_spi_cbfunc(void (*spi_rb)(uint8_t *, uint32_t), void (*spi_wb)(const uint8_t *, uint32_t));
/**
* @ingroup extra_functions
* @brief Controls to the WIZCHIP.
* @details Resets WIZCHIP & internal PHY, Configures PHY mode, Monitor PHY(Link,Speed,Half/Full/Auto),
* controls interrupt & mask and so on.
* @param cwtype : Decides to the control type
* @param arg : arg type is dependent on cwtype.
* @return 0 : Success \n
* -1 : Fail because of invalid \ref ctlwizchip_type or unsupported \ref ctlwizchip_type in WIZCHIP
*/
int8_t ctlwizchip(ctlwizchip_type cwtype, void* arg);
/**
* @ingroup extra_functions
* @brief Controls to network.
* @details Controls to network environment, mode, timeout and so on.
* @param cntype : Input. Decides to the control type
* @param arg : Inout. arg type is dependent on cntype.
* @return -1 : Fail because of invalid \ref ctlnetwork_type or unsupported \ref ctlnetwork_type in WIZCHIP \n
* 0 : Success
*/
int8_t ctlnetwork(ctlnetwork_type cntype, void* arg);
/*
* The following functions are implemented for internal use.
* but You can call these functions for code size reduction instead of ctlwizchip() and ctlnetwork().
*/
/**
* @ingroup extra_functions
* @brief Reset WIZCHIP by softly.
*/
void wizchip_sw_reset(void);
/**
* @ingroup extra_functions
* @brief Initializes WIZCHIP with socket buffer size
* @param txsize Socket tx buffer sizes. If null, initialized the default size 2KB.
* @param rxsize Socket rx buffer sizes. If null, initialized the default size 2KB.
* @return 0 : succcess \n
* -1 : fail. Invalid buffer size
*/
int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize);
/**
* @ingroup extra_functions
* @brief Clear Interrupt of WIZCHIP.
* @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t.
*/
void wizchip_clrinterrupt(intr_kind intr);
/**
* @ingroup extra_functions
* @brief Get Interrupt of WIZCHIP.
* @return @ref intr_kind value operated OR. It can type-cast to uint16_t.
*/
intr_kind wizchip_getinterrupt(void);
/**
* @ingroup extra_functions
* @brief Mask or Unmask Interrupt of WIZCHIP.
* @param intr : @ref intr_kind value operated OR. It can type-cast to uint16_t.
*/
void wizchip_setinterruptmask(intr_kind intr);
/**
* @ingroup extra_functions
* @brief Get Interrupt mask of WIZCHIP.
* @return : The operated OR vaule of @ref intr_kind. It can type-cast to uint16_t.
*/
intr_kind wizchip_getinterruptmask(void);
#if _WIZCHIP_ > 5100
int8_t wizphy_getphylink(void); ///< get the link status of phy in WIZCHIP. No use in W5100
int8_t wizphy_getphypmode(void); ///< get the power mode of PHY in WIZCHIP. No use in W5100
#endif
#if _WIZCHIP_ == 5500
void wizphy_reset(void); ///< Reset phy. Vailid only in W5500
/**
* @ingroup extra_functions
* @brief Set the phy information for WIZCHIP without power mode
* @param phyconf : @ref wiz_PhyConf
*/
void wizphy_setphyconf(wiz_PhyConf* phyconf);
/**
* @ingroup extra_functions
* @brief Get phy configuration information.
* @param phyconf : @ref wiz_PhyConf
*/
void wizphy_getphyconf(wiz_PhyConf* phyconf);
/**
* @ingroup extra_functions
* @brief Get phy status.
* @param phyconf : @ref wiz_PhyConf
*/
void wizphy_getphystat(wiz_PhyConf* phyconf);
/**
* @ingroup extra_functions
* @brief set the power mode of phy inside WIZCHIP. Refer to @ref PHYCFGR in W5500, @ref PHYSTATUS in W5200
* @param pmode Settig value of power down mode.
*/
int8_t wizphy_setphypmode(uint8_t pmode);
#endif
/**
* @ingroup extra_functions
* @brief Set the network information for WIZCHIP
* @param pnetinfo : @ref wizNetInfo
*/
void wizchip_setnetinfo(wiz_NetInfo* pnetinfo);
/**
* @ingroup extra_functions
* @brief Get the network information for WIZCHIP
* @param pnetinfo : @ref wizNetInfo
*/
void wizchip_getnetinfo(wiz_NetInfo* pnetinfo);
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
uint8_t *wizchip_getsubn(void);
#endif
/**
* @ingroup extra_functions
* @brief Set the network mode such WOL, PPPoE, Ping Block, and etc.
* @param pnetinfo Value of network mode. Refer to @ref netmode_type.
*/
int8_t wizchip_setnetmode(netmode_type netmode);
/**
* @ingroup extra_functions
* @brief Get the network mode such WOL, PPPoE, Ping Block, and etc.
* @return Value of network mode. Refer to @ref netmode_type.
*/
netmode_type wizchip_getnetmode(void);
/**
* @ingroup extra_functions
* @brief Set retry time value(@ref RTR) and retry count(@ref RCR).
* @details @ref RTR configures the retransmission timeout period and @ref RCR configures the number of time of retransmission.
* @param nettime @ref RTR value and @ref RCR value. Refer to @ref wiz_NetTimeout.
*/
void wizchip_settimeout(wiz_NetTimeout* nettime);
/**
* @ingroup extra_functions
* @brief Get retry time value(@ref RTR) and retry count(@ref RCR).
* @details @ref RTR configures the retransmission timeout period and @ref RCR configures the number of time of retransmission.
* @param nettime @ref RTR value and @ref RCR value. Refer to @ref wiz_NetTimeout.
*/
void wizchip_gettimeout(wiz_NetTimeout* nettime);
#endif // _WIZCHIP_CONF_H_

View File

@@ -0,0 +1,978 @@
//*****************************************************************************
//
//! \file dhcp.c
//! \brief DHCP APIs implement file.
//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE.
//! \version 1.1.0
//! \date 2013/11/18
//! \par Revision history
//! <2013/11/18> 1st Release
//! <2012/12/20> V1.1.0
//! 1. Optimize code
//! 2. Add reg_dhcp_cbfunc()
//! 3. Add DHCP_stop()
//! 4. Integrate check_DHCP_state() & DHCP_run() to DHCP_run()
//! 5. Don't care system endian
//! 6. Add comments
//! <2012/12/26> V1.1.1
//! 1. Modify variable declaration: dhcp_tick_1s is declared volatile for code optimization
//! \author Eric Jung & MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
//#include "Ethernet/socket.h"
//#include "Internet/DHCP/dhcp.h"
#include "../../Ethernet/socket.h"
#include "dhcp.h"
/* If you want to display debug & processing message, Define _DHCP_DEBUG_ in dhcp.h */
#ifdef _DHCP_DEBUG_
#include <stdio.h>
#endif
/* DHCP state machine. */
#define STATE_DHCP_INIT 0 ///< Initialize
#define STATE_DHCP_DISCOVER 1 ///< send DISCOVER and wait OFFER
#define STATE_DHCP_REQUEST 2 ///< send REQEUST and wait ACK or NACK
#define STATE_DHCP_LEASED 3 ///< ReceiveD ACK and IP leased
#define STATE_DHCP_REREQUEST 4 ///< send REQUEST for maintaining leased IP
#define STATE_DHCP_RELEASE 5 ///< No use
#define STATE_DHCP_STOP 6 ///< Stop processing DHCP
#define DHCP_FLAGSBROADCAST 0x8000 ///< The broadcast value of flags in @ref RIP_MSG
#define DHCP_FLAGSUNICAST 0x0000 ///< The unicast value of flags in @ref RIP_MSG
/* DHCP message OP code */
#define DHCP_BOOTREQUEST 1 ///< Request Message used in op of @ref RIP_MSG
#define DHCP_BOOTREPLY 2 ///< Reply Message used i op of @ref RIP_MSG
/* DHCP message type */
#define DHCP_DISCOVER 1 ///< DISCOVER message in OPT of @ref RIP_MSG
#define DHCP_OFFER 2 ///< OFFER message in OPT of @ref RIP_MSG
#define DHCP_REQUEST 3 ///< REQUEST message in OPT of @ref RIP_MSG
#define DHCP_DECLINE 4 ///< DECLINE message in OPT of @ref RIP_MSG
#define DHCP_ACK 5 ///< ACK message in OPT of @ref RIP_MSG
#define DHCP_NAK 6 ///< NACK message in OPT of @ref RIP_MSG
#define DHCP_RELEASE 7 ///< RELEASE message in OPT of @ref RIP_MSG. No use
#define DHCP_INFORM 8 ///< INFORM message in OPT of @ref RIP_MSG. No use
#define DHCP_HTYPE10MB 1 ///< Used in type of @ref RIP_MSG
#define DHCP_HTYPE100MB 2 ///< Used in type of @ref RIP_MSG
#define DHCP_HLENETHERNET 6 ///< Used in hlen of @ref RIP_MSG
#define DHCP_HOPS 0 ///< Used in hops of @ref RIP_MSG
#define DHCP_SECS 0 ///< Used in secs of @ref RIP_MSG
#define INFINITE_LEASETIME 0xffffffff ///< Infinite lease time
#define OPT_SIZE 312 /// Max OPT size of @ref RIP_MSG
#define RIP_MSG_SIZE (236+OPT_SIZE) /// Max size of @ref RIP_MSG
/*
* @brief DHCP option and value (cf. RFC1533)
*/
enum
{
padOption = 0,
subnetMask = 1,
timerOffset = 2,
routersOnSubnet = 3,
timeServer = 4,
nameServer = 5,
dns = 6,
logServer = 7,
cookieServer = 8,
lprServer = 9,
impressServer = 10,
resourceLocationServer = 11,
hostName = 12,
bootFileSize = 13,
meritDumpFile = 14,
domainName = 15,
swapServer = 16,
rootPath = 17,
extentionsPath = 18,
IPforwarding = 19,
nonLocalSourceRouting = 20,
policyFilter = 21,
maxDgramReasmSize = 22,
defaultIPTTL = 23,
pathMTUagingTimeout = 24,
pathMTUplateauTable = 25,
ifMTU = 26,
allSubnetsLocal = 27,
broadcastAddr = 28,
performMaskDiscovery = 29,
maskSupplier = 30,
performRouterDiscovery = 31,
routerSolicitationAddr = 32,
staticRoute = 33,
trailerEncapsulation = 34,
arpCacheTimeout = 35,
ethernetEncapsulation = 36,
tcpDefaultTTL = 37,
tcpKeepaliveInterval = 38,
tcpKeepaliveGarbage = 39,
nisDomainName = 40,
nisServers = 41,
ntpServers = 42,
vendorSpecificInfo = 43,
netBIOSnameServer = 44,
netBIOSdgramDistServer = 45,
netBIOSnodeType = 46,
netBIOSscope = 47,
xFontServer = 48,
xDisplayManager = 49,
dhcpRequestedIPaddr = 50,
dhcpIPaddrLeaseTime = 51,
dhcpOptionOverload = 52,
dhcpMessageType = 53,
dhcpServerIdentifier = 54,
dhcpParamRequest = 55,
dhcpMsg = 56,
dhcpMaxMsgSize = 57,
dhcpT1value = 58,
dhcpT2value = 59,
dhcpClassIdentifier = 60,
dhcpClientIdentifier = 61,
endOption = 255
};
/*
* @brief DHCP message format
*/
typedef struct {
uint8_t op; ///< @ref DHCP_BOOTREQUEST or @ref DHCP_BOOTREPLY
uint8_t htype; ///< @ref DHCP_HTYPE10MB or @ref DHCP_HTYPE100MB
uint8_t hlen; ///< @ref DHCP_HLENETHERNET
uint8_t hops; ///< @ref DHCP_HOPS
uint32_t xid; ///< @ref DHCP_XID This increase one every DHCP transaction.
uint16_t secs; ///< @ref DHCP_SECS
uint16_t flags; ///< @ref DHCP_FLAGSBROADCAST or @ref DHCP_FLAGSUNICAST
uint8_t ciaddr[4]; ///< @ref Request IP to DHCP sever
uint8_t yiaddr[4]; ///< @ref Offered IP from DHCP server
uint8_t siaddr[4]; ///< No use
uint8_t giaddr[4]; ///< No use
uint8_t chaddr[16]; ///< DHCP client 6bytes MAC address. Others is filled to zero
uint8_t sname[64]; ///< No use
uint8_t file[128]; ///< No use
uint8_t OPT[OPT_SIZE]; ///< Option
} RIP_MSG;
uint8_t DHCP_SOCKET; // Socket number for DHCP
uint8_t DHCP_SIP[4]; // DHCP Server IP address
// Network information from DHCP Server
uint8_t OLD_allocated_ip[4] = {0, }; // Previous IP address
uint8_t DHCP_allocated_ip[4] = {0, }; // IP address from DHCP
uint8_t DHCP_allocated_gw[4] = {0, }; // Gateway address from DHCP
uint8_t DHCP_allocated_sn[4] = {0, }; // Subnet mask from DHCP
uint8_t DHCP_allocated_dns[4] = {0, }; // DNS address from DHCP
int8_t dhcp_state = STATE_DHCP_INIT; // DHCP state
int8_t dhcp_retry_count = 0;
uint32_t dhcp_lease_time = INFINITE_LEASETIME;
volatile uint32_t dhcp_tick_1s = 0; // unit 1 second
uint32_t dhcp_tick_next = DHCP_WAIT_TIME ;
uint32_t DHCP_XID; // Any number
RIP_MSG* pDHCPMSG; // Buffer pointer for DHCP processing
uint8_t HOST_NAME[] = DCHP_HOST_NAME;
uint8_t DHCP_CHADDR[6]; // DHCP Client MAC address.
/* The default callback function */
void default_ip_assign(void);
void default_ip_update(void);
void default_ip_conflict(void);
/* Callback handler */
void (*dhcp_ip_assign)(void) = default_ip_assign; /* handler to be called when the IP address from DHCP server is first assigned */
void (*dhcp_ip_update)(void) = default_ip_update; /* handler to be called when the IP address from DHCP server is updated */
void (*dhcp_ip_conflict)(void) = default_ip_conflict; /* handler to be called when the IP address from DHCP server is conflict */
void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void));
/* send DISCOVER message to DHCP server */
void send_DHCP_DISCOVER(void);
/* send REQEUST message to DHCP server */
void send_DHCP_REQUEST(void);
/* send DECLINE message to DHCP server */
void send_DHCP_DECLINE(void);
/* IP conflict check by sending ARP-request to leased IP and wait ARP-response. */
int8_t check_DHCP_leasedIP(void);
/* check the timeout in DHCP process */
uint8_t check_DHCP_timeout(void);
/* Intialize to timeout process. */
void reset_DHCP_timeout(void);
/* Parse message as OFFER and ACK and NACK from DHCP server.*/
int8_t parseDHCPCMSG(void);
/* The default handler of ip assign first */
void default_ip_assign(void)
{
setSIPR(DHCP_allocated_ip);
setSUBR(DHCP_allocated_sn);
setGAR (DHCP_allocated_gw);
}
/* The default handler of ip changed */
void default_ip_update(void)
{
/* WIZchip Software Reset */
setMR(MR_RST);
getMR(); // for delay
default_ip_assign();
setSHAR(DHCP_CHADDR);
}
/* The default handler of ip changed */
void default_ip_conflict(void)
{
// WIZchip Software Reset
setMR(MR_RST);
getMR(); // for delay
setSHAR(DHCP_CHADDR);
}
/* register the call back func. */
void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void))
{
dhcp_ip_assign = default_ip_assign;
dhcp_ip_update = default_ip_update;
dhcp_ip_conflict = default_ip_conflict;
if(ip_assign) dhcp_ip_assign = ip_assign;
if(ip_update) dhcp_ip_update = ip_update;
if(ip_conflict) dhcp_ip_conflict = ip_conflict;
}
/* make the common DHCP message */
void makeDHCPMSG(void)
{
uint8_t bk_mac[6];
uint8_t* ptmp;
uint8_t i;
getSHAR(bk_mac);
pDHCPMSG->op = DHCP_BOOTREQUEST;
pDHCPMSG->htype = DHCP_HTYPE10MB;
pDHCPMSG->hlen = DHCP_HLENETHERNET;
pDHCPMSG->hops = DHCP_HOPS;
ptmp = (uint8_t*)(&pDHCPMSG->xid);
*(ptmp+0) = (uint8_t)((DHCP_XID & 0xFF000000) >> 24);
*(ptmp+1) = (uint8_t)((DHCP_XID & 0x00FF0000) >> 16);
*(ptmp+2) = (uint8_t)((DHCP_XID & 0x0000FF00) >> 8);
*(ptmp+3) = (uint8_t)((DHCP_XID & 0x000000FF) >> 0);
pDHCPMSG->secs = DHCP_SECS;
ptmp = (uint8_t*)(&pDHCPMSG->flags);
*(ptmp+0) = (uint8_t)((DHCP_FLAGSBROADCAST & 0xFF00) >> 8);
*(ptmp+1) = (uint8_t)((DHCP_FLAGSBROADCAST & 0x00FF) >> 0);
pDHCPMSG->ciaddr[0] = 0;
pDHCPMSG->ciaddr[1] = 0;
pDHCPMSG->ciaddr[2] = 0;
pDHCPMSG->ciaddr[3] = 0;
pDHCPMSG->yiaddr[0] = 0;
pDHCPMSG->yiaddr[1] = 0;
pDHCPMSG->yiaddr[2] = 0;
pDHCPMSG->yiaddr[3] = 0;
pDHCPMSG->siaddr[0] = 0;
pDHCPMSG->siaddr[1] = 0;
pDHCPMSG->siaddr[2] = 0;
pDHCPMSG->siaddr[3] = 0;
pDHCPMSG->giaddr[0] = 0;
pDHCPMSG->giaddr[1] = 0;
pDHCPMSG->giaddr[2] = 0;
pDHCPMSG->giaddr[3] = 0;
pDHCPMSG->chaddr[0] = DHCP_CHADDR[0];
pDHCPMSG->chaddr[1] = DHCP_CHADDR[1];
pDHCPMSG->chaddr[2] = DHCP_CHADDR[2];
pDHCPMSG->chaddr[3] = DHCP_CHADDR[3];
pDHCPMSG->chaddr[4] = DHCP_CHADDR[4];
pDHCPMSG->chaddr[5] = DHCP_CHADDR[5];
for (i = 6; i < 16; i++) pDHCPMSG->chaddr[i] = 0;
for (i = 0; i < 64; i++) pDHCPMSG->sname[i] = 0;
for (i = 0; i < 128; i++) pDHCPMSG->file[i] = 0;
// MAGIC_COOKIE
pDHCPMSG->OPT[0] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
pDHCPMSG->OPT[1] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
pDHCPMSG->OPT[2] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >> 8);
pDHCPMSG->OPT[3] = (uint8_t) (MAGIC_COOKIE & 0x000000FF) >> 0;
}
/* SEND DHCP DISCOVER */
void send_DHCP_DISCOVER(void)
{
uint16_t i;
uint8_t ip[4];
uint16_t k = 0;
makeDHCPMSG();
k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG()
// Option Request Param
pDHCPMSG->OPT[k++] = dhcpMessageType;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_DISCOVER;
// Client identifier
pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
pDHCPMSG->OPT[k++] = 0x07;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
// host name
pDHCPMSG->OPT[k++] = hostName;
pDHCPMSG->OPT[k++] = 0; // fill zero length of hostname
for(i = 0 ; HOST_NAME[i] != 0; i++)
pDHCPMSG->OPT[k++] = HOST_NAME[i];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname
pDHCPMSG->OPT[k++] = dhcpParamRequest;
pDHCPMSG->OPT[k++] = 0x06; // length of request
pDHCPMSG->OPT[k++] = subnetMask;
pDHCPMSG->OPT[k++] = routersOnSubnet;
pDHCPMSG->OPT[k++] = dns;
pDHCPMSG->OPT[k++] = domainName;
pDHCPMSG->OPT[k++] = dhcpT1value;
pDHCPMSG->OPT[k++] = dhcpT2value;
pDHCPMSG->OPT[k++] = endOption;
for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
// send broadcasting packet
ip[0] = 255;
ip[1] = 255;
ip[2] = 255;
ip[3] = 255;
#ifdef _DHCP_DEBUG_
printf("> Send DHCP_DISCOVER\r\n");
#endif
sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
}
/* SEND DHCP REQUEST */
void send_DHCP_REQUEST(void)
{
int i;
uint8_t ip[4];
uint16_t k = 0;
makeDHCPMSG();
if(dhcp_state == STATE_DHCP_LEASED || dhcp_state == STATE_DHCP_REREQUEST)
{
*((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
*((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
pDHCPMSG->ciaddr[0] = DHCP_allocated_ip[0];
pDHCPMSG->ciaddr[1] = DHCP_allocated_ip[1];
pDHCPMSG->ciaddr[2] = DHCP_allocated_ip[2];
pDHCPMSG->ciaddr[3] = DHCP_allocated_ip[3];
ip[0] = DHCP_SIP[0];
ip[1] = DHCP_SIP[1];
ip[2] = DHCP_SIP[2];
ip[3] = DHCP_SIP[3];
}
else
{
ip[0] = 255;
ip[1] = 255;
ip[2] = 255;
ip[3] = 255;
}
k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG()
// Option Request Param.
pDHCPMSG->OPT[k++] = dhcpMessageType;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_REQUEST;
pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
pDHCPMSG->OPT[k++] = 0x07;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
if(ip[3] == 255) // if(dchp_state == STATE_DHCP_LEASED || dchp_state == DHCP_REREQUEST_STATE)
{
pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
pDHCPMSG->OPT[k++] = 0x04;
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
pDHCPMSG->OPT[k++] = 0x04;
pDHCPMSG->OPT[k++] = DHCP_SIP[0];
pDHCPMSG->OPT[k++] = DHCP_SIP[1];
pDHCPMSG->OPT[k++] = DHCP_SIP[2];
pDHCPMSG->OPT[k++] = DHCP_SIP[3];
}
// host name
pDHCPMSG->OPT[k++] = hostName;
pDHCPMSG->OPT[k++] = 0; // length of hostname
for(i = 0 ; HOST_NAME[i] != 0; i++)
pDHCPMSG->OPT[k++] = HOST_NAME[i];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
pDHCPMSG->OPT[k - (i+3+1)] = i+3; // length of hostname
pDHCPMSG->OPT[k++] = dhcpParamRequest;
pDHCPMSG->OPT[k++] = 0x08;
pDHCPMSG->OPT[k++] = subnetMask;
pDHCPMSG->OPT[k++] = routersOnSubnet;
pDHCPMSG->OPT[k++] = dns;
pDHCPMSG->OPT[k++] = domainName;
pDHCPMSG->OPT[k++] = dhcpT1value;
pDHCPMSG->OPT[k++] = dhcpT2value;
pDHCPMSG->OPT[k++] = performRouterDiscovery;
pDHCPMSG->OPT[k++] = staticRoute;
pDHCPMSG->OPT[k++] = endOption;
for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
#ifdef _DHCP_DEBUG_
printf("> Send DHCP_REQUEST\r\n");
#endif
sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
}
/* SEND DHCP DHCPDECLINE */
void send_DHCP_DECLINE(void)
{
int i;
uint8_t ip[4];
uint16_t k = 0;
makeDHCPMSG();
k = 4; // because MAGIC_COOKIE already made by makeDHCPMSG()
*((uint8_t*)(&pDHCPMSG->flags)) = ((DHCP_FLAGSUNICAST & 0xFF00)>> 8);
*((uint8_t*)(&pDHCPMSG->flags)+1) = (DHCP_FLAGSUNICAST & 0x00FF);
// Option Request Param.
pDHCPMSG->OPT[k++] = dhcpMessageType;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_DECLINE;
pDHCPMSG->OPT[k++] = dhcpClientIdentifier;
pDHCPMSG->OPT[k++] = 0x07;
pDHCPMSG->OPT[k++] = 0x01;
pDHCPMSG->OPT[k++] = DHCP_CHADDR[0];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[1];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[2];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[3];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[4];
pDHCPMSG->OPT[k++] = DHCP_CHADDR[5];
pDHCPMSG->OPT[k++] = dhcpRequestedIPaddr;
pDHCPMSG->OPT[k++] = 0x04;
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[0];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[1];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[2];
pDHCPMSG->OPT[k++] = DHCP_allocated_ip[3];
pDHCPMSG->OPT[k++] = dhcpServerIdentifier;
pDHCPMSG->OPT[k++] = 0x04;
pDHCPMSG->OPT[k++] = DHCP_SIP[0];
pDHCPMSG->OPT[k++] = DHCP_SIP[1];
pDHCPMSG->OPT[k++] = DHCP_SIP[2];
pDHCPMSG->OPT[k++] = DHCP_SIP[3];
pDHCPMSG->OPT[k++] = endOption;
for (i = k; i < OPT_SIZE; i++) pDHCPMSG->OPT[i] = 0;
//send broadcasting packet
ip[0] = 0xFF;
ip[1] = 0xFF;
ip[2] = 0xFF;
ip[3] = 0xFF;
#ifdef _DHCP_DEBUG_
printf("\r\n> Send DHCP_DECLINE\r\n");
#endif
sendto(DHCP_SOCKET, (uint8_t *)pDHCPMSG, RIP_MSG_SIZE, ip, DHCP_SERVER_PORT);
}
/* PARSE REPLY pDHCPMSG */
int8_t parseDHCPMSG(void)
{
uint8_t svr_addr[6];
uint16_t svr_port;
uint16_t len;
uint8_t * p;
uint8_t * e;
uint8_t type;
uint8_t opt_len;
if((len = getSn_RX_RSR(DHCP_SOCKET)) > 0)
{
len = recvfrom(DHCP_SOCKET, (uint8_t *)pDHCPMSG, len, svr_addr, &svr_port);
#ifdef _DHCP_DEBUG_
printf("DHCP message : %d.%d.%d.%d(%d) %d received. \r\n",svr_addr[0],svr_addr[1],svr_addr[2], svr_addr[3],svr_port, len);
#endif
}
else return 0;
if (svr_port == DHCP_SERVER_PORT) {
// compare mac address
if ( (pDHCPMSG->chaddr[0] != DHCP_CHADDR[0]) || (pDHCPMSG->chaddr[1] != DHCP_CHADDR[1]) ||
(pDHCPMSG->chaddr[2] != DHCP_CHADDR[2]) || (pDHCPMSG->chaddr[3] != DHCP_CHADDR[3]) ||
(pDHCPMSG->chaddr[4] != DHCP_CHADDR[4]) || (pDHCPMSG->chaddr[5] != DHCP_CHADDR[5]) )
return 0;
type = 0;
p = (uint8_t *)(&pDHCPMSG->op);
p = p + 240; // 240 = sizeof(RIP_MSG) + MAGIC_COOKIE size in RIP_MSG.opt - sizeof(RIP_MSG.opt)
e = p + (len - 240);
while ( p < e ) {
switch ( *p ) {
case endOption :
p = e; // for break while(p < e)
break;
case padOption :
p++;
break;
case dhcpMessageType :
p++;
p++;
type = *p++;
break;
case subnetMask :
p++;
p++;
DHCP_allocated_sn[0] = *p++;
DHCP_allocated_sn[1] = *p++;
DHCP_allocated_sn[2] = *p++;
DHCP_allocated_sn[3] = *p++;
break;
case routersOnSubnet :
p++;
opt_len = *p++;
DHCP_allocated_gw[0] = *p++;
DHCP_allocated_gw[1] = *p++;
DHCP_allocated_gw[2] = *p++;
DHCP_allocated_gw[3] = *p++;
p = p + (opt_len - 4);
break;
case dns :
p++;
opt_len = *p++;
DHCP_allocated_dns[0] = *p++;
DHCP_allocated_dns[1] = *p++;
DHCP_allocated_dns[2] = *p++;
DHCP_allocated_dns[3] = *p++;
p = p + (opt_len - 4);
break;
case dhcpIPaddrLeaseTime :
p++;
opt_len = *p++;
dhcp_lease_time = *p++;
dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
dhcp_lease_time = (dhcp_lease_time << 8) + *p++;
#ifdef _DHCP_DEBUG_
dhcp_lease_time = 10;
#endif
break;
case dhcpServerIdentifier :
p++;
opt_len = *p++;
DHCP_SIP[0] = *p++;
DHCP_SIP[1] = *p++;
DHCP_SIP[2] = *p++;
DHCP_SIP[3] = *p++;
break;
default :
p++;
opt_len = *p++;
p += opt_len;
break;
} // switch
} // while
} // if
return type;
}
uint8_t DHCP_run(void)
{
uint8_t type;
uint8_t ret;
if(dhcp_state == STATE_DHCP_STOP) return DHCP_STOPPED;
if(getSn_SR(DHCP_SOCKET) != SOCK_UDP)
socket(DHCP_SOCKET, Sn_MR_UDP, DHCP_CLIENT_PORT, 0x00);
ret = DHCP_RUNNING;
type = parseDHCPMSG();
switch ( dhcp_state ) {
case STATE_DHCP_INIT :
DHCP_allocated_ip[0] = 0;
DHCP_allocated_ip[1] = 0;
DHCP_allocated_ip[2] = 0;
DHCP_allocated_ip[3] = 0;
send_DHCP_DISCOVER();
dhcp_state = STATE_DHCP_DISCOVER;
break;
case STATE_DHCP_DISCOVER :
if (type == DHCP_OFFER){
#ifdef _DHCP_DEBUG_
printf("> Receive DHCP_OFFER\r\n");
#endif
DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0];
DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1];
DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2];
DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3];
send_DHCP_REQUEST();
dhcp_state = STATE_DHCP_REQUEST;
} else ret = check_DHCP_timeout();
break;
case STATE_DHCP_REQUEST :
if (type == DHCP_ACK) {
#ifdef _DHCP_DEBUG_
printf("> Receive DHCP_ACK\r\n");
#endif
if (check_DHCP_leasedIP()) {
// Network info assignment from DHCP
dhcp_ip_assign();
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_LEASED;
} else {
// IP address conflict occurred
reset_DHCP_timeout();
dhcp_ip_conflict();
dhcp_state = STATE_DHCP_INIT;
}
} else if (type == DHCP_NAK) {
#ifdef _DHCP_DEBUG_
printf("> Receive DHCP_NACK\r\n");
#endif
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_DISCOVER;
} else ret = check_DHCP_timeout();
break;
case STATE_DHCP_LEASED :
ret = DHCP_IP_LEASED;
if ((dhcp_lease_time != INFINITE_LEASETIME) && ((dhcp_lease_time/2) < dhcp_tick_1s)) {
#ifdef _DHCP_DEBUG_
printf("> Maintains the IP address \r\n");
#endif
type = 0;
OLD_allocated_ip[0] = DHCP_allocated_ip[0];
OLD_allocated_ip[1] = DHCP_allocated_ip[1];
OLD_allocated_ip[2] = DHCP_allocated_ip[2];
OLD_allocated_ip[3] = DHCP_allocated_ip[3];
DHCP_XID++;
send_DHCP_REQUEST();
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_REREQUEST;
}
break;
case STATE_DHCP_REREQUEST :
ret = DHCP_IP_LEASED;
if (type == DHCP_ACK) {
dhcp_retry_count = 0;
if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] ||
OLD_allocated_ip[1] != DHCP_allocated_ip[1] ||
OLD_allocated_ip[2] != DHCP_allocated_ip[2] ||
OLD_allocated_ip[3] != DHCP_allocated_ip[3])
{
ret = DHCP_IP_CHANGED;
dhcp_ip_update();
#ifdef _DHCP_DEBUG_
printf(">IP changed.\r\n");
#endif
}
#ifdef _DHCP_DEBUG_
else printf(">IP is continued.\r\n");
#endif
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_LEASED;
} else if (type == DHCP_NAK) {
#ifdef _DHCP_DEBUG_
printf("> Receive DHCP_NACK, Failed to maintain ip\r\n");
#endif
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_DISCOVER;
} else ret = check_DHCP_timeout();
break;
default :
break;
}
return ret;
}
void DHCP_stop(void)
{
close(DHCP_SOCKET);
dhcp_state = STATE_DHCP_STOP;
}
uint8_t check_DHCP_timeout(void)
{
uint8_t ret = DHCP_RUNNING;
if (dhcp_retry_count < MAX_DHCP_RETRY) {
if (dhcp_tick_next < dhcp_tick_1s) {
switch ( dhcp_state ) {
case STATE_DHCP_DISCOVER :
// printf("<<timeout>> state : STATE_DHCP_DISCOVER\r\n");
send_DHCP_DISCOVER();
break;
case STATE_DHCP_REQUEST :
// printf("<<timeout>> state : STATE_DHCP_REQUEST\r\n");
send_DHCP_REQUEST();
break;
case STATE_DHCP_REREQUEST :
// printf("<<timeout>> state : STATE_DHCP_REREQUEST\r\n");
send_DHCP_REQUEST();
break;
default :
break;
}
dhcp_tick_1s = 0;
dhcp_tick_next = dhcp_tick_1s + DHCP_WAIT_TIME;
dhcp_retry_count++;
}
} else { // timeout occurred
switch(dhcp_state) {
case STATE_DHCP_DISCOVER:
dhcp_state = STATE_DHCP_INIT;
ret = DHCP_FAILED;
break;
case STATE_DHCP_REQUEST:
case STATE_DHCP_REREQUEST:
send_DHCP_DISCOVER();
dhcp_state = STATE_DHCP_DISCOVER;
break;
default :
break;
}
reset_DHCP_timeout();
}
return ret;
}
int8_t check_DHCP_leasedIP(void)
{
uint8_t tmp;
int32_t ret;
//WIZchip RCR value changed for ARP Timeout count control
tmp = getRCR();
setRCR(0x03);
// IP conflict detection : ARP request - ARP reply
// Broadcasting ARP Request for check the IP conflict using UDP sendto() function
ret = sendto(DHCP_SOCKET, (uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000);
// RCR value restore
setRCR(tmp);
if(ret == SOCKERR_TIMEOUT) {
// UDP send Timeout occurred : allocated IP address is unique, DHCP Success
#ifdef _DHCP_DEBUG_
printf("\r\n> Check leased IP - OK\r\n");
#endif
return 1;
} else {
// Received ARP reply or etc : IP address conflict occur, DHCP Failed
send_DHCP_DECLINE();
ret = dhcp_tick_1s;
while((dhcp_tick_1s - ret) < 2) ; // wait for 1s over; wait to complete to send DECLINE message;
return 0;
}
}
void DHCP_init(uint8_t s, uint8_t * buf)
{
uint8_t zeroip[4] = {0,0,0,0};
getSHAR(DHCP_CHADDR);
if((DHCP_CHADDR[0] | DHCP_CHADDR[1] | DHCP_CHADDR[2] | DHCP_CHADDR[3] | DHCP_CHADDR[4] | DHCP_CHADDR[5]) == 0x00)
{
// assign temporary mac address, you should be set SHAR before call this function.
DHCP_CHADDR[0] = 0x00;
DHCP_CHADDR[1] = 0x08;
DHCP_CHADDR[2] = 0xdc;
DHCP_CHADDR[3] = 0x00;
DHCP_CHADDR[4] = 0x00;
DHCP_CHADDR[5] = 0x00;
setSHAR(DHCP_CHADDR);
}
DHCP_SOCKET = s; // SOCK_DHCP
pDHCPMSG = (RIP_MSG*)buf;
DHCP_XID = 0x12345678;
// WIZchip Netinfo Clear
setSIPR(zeroip);
setSIPR(zeroip);
setGAR(zeroip);
reset_DHCP_timeout();
dhcp_state = STATE_DHCP_INIT;
}
/* Rset the DHCP timeout count and retry count. */
void reset_DHCP_timeout(void)
{
dhcp_tick_1s = 0;
dhcp_tick_next = DHCP_WAIT_TIME;
dhcp_retry_count = 0;
}
void DHCP_time_handler(void)
{
dhcp_tick_1s++;
}
void getIPfromDHCP(uint8_t* ip)
{
ip[0] = DHCP_allocated_ip[0];
ip[1] = DHCP_allocated_ip[1];
ip[2] = DHCP_allocated_ip[2];
ip[3] = DHCP_allocated_ip[3];
}
void getGWfromDHCP(uint8_t* ip)
{
ip[0] =DHCP_allocated_gw[0];
ip[1] =DHCP_allocated_gw[1];
ip[2] =DHCP_allocated_gw[2];
ip[3] =DHCP_allocated_gw[3];
}
void getSNfromDHCP(uint8_t* ip)
{
ip[0] = DHCP_allocated_sn[0];
ip[1] = DHCP_allocated_sn[1];
ip[2] = DHCP_allocated_sn[2];
ip[3] = DHCP_allocated_sn[3];
}
void getDNSfromDHCP(uint8_t* ip)
{
ip[0] = DHCP_allocated_dns[0];
ip[1] = DHCP_allocated_dns[1];
ip[2] = DHCP_allocated_dns[2];
ip[3] = DHCP_allocated_dns[3];
}
uint32_t getDHCPLeasetime(void)
{
return dhcp_lease_time;
}

View File

@@ -0,0 +1,150 @@
//*****************************************************************************
//
//! \file dhcp.h
//! \brief DHCP APIs Header file.
//! \details Processig DHCP protocol as DISCOVER, OFFER, REQUEST, ACK, NACK and DECLINE.
//! \version 1.1.0
//! \date 2013/11/18
//! \par Revision history
//! <2013/11/18> 1st Release
//! <2012/12/20> V1.1.0
//! 1. Move unreferenced DEFINE to dhcp.c
//! <2012/12/26> V1.1.1
//! \author Eric Jung & MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#ifndef _DHCP_H_
#define _DHCP_H_
/*
* @brief
* @details If you want to display debug & processing message, Define _DHCP_DEBUG_
* @note If defined, it depends on <stdio.h>
*/
//#define _DHCP_DEBUG_
/* Retry to processing DHCP */
#define MAX_DHCP_RETRY 2 ///< Maximum retry count
#define DHCP_WAIT_TIME 10 ///< Wait Time 10s
/* UDP port numbers for DHCP */
#define DHCP_SERVER_PORT 67 ///< DHCP server port number
#define DHCP_CLIENT_PORT 68 ///< DHCP client port number
#define MAGIC_COOKIE 0x63825363 ///< Any number. You can be modified it any number
#define DCHP_HOST_NAME "WIZnet\0"
/*
* @brief return value of @ref DHCP_run()
*/
enum
{
DHCP_FAILED = 0, ///< Processing Fail
DHCP_RUNNING, ///< Processing DHCP protocol
DHCP_IP_ASSIGN, ///< First Occupy IP from DHPC server (if cbfunc == null, act as default default_ip_assign)
DHCP_IP_CHANGED, ///< Change IP address by new IP address from DHCP (if cbfunc == null, act as default default_ip_update)
DHCP_IP_LEASED, ///< Stand by
DHCP_STOPPED ///< Stop processing DHCP protocol
};
/*
* @brief DHCP client initialization (outside of the main loop)
* @param s - socket number
* @param buf - buffer for processing DHCP message
*/
void DHCP_init(uint8_t s, uint8_t * buf);
/*
* @brief DHCP 1s Tick Timer handler
* @note SHOULD BE register to your system 1s Tick timer handler
*/
void DHCP_time_handler(void);
/*
* @brief Register call back function
* @param ip_assign - callback func when IP is assigned from DHCP server first
* @param ip_update - callback func when IP is changed
* @prarm ip_conflict - callback func when the assigned IP is conflict with others.
*/
void reg_dhcp_cbfunc(void(*ip_assign)(void), void(*ip_update)(void), void(*ip_conflict)(void));
/*
* @brief DHCP client in the main loop
* @return The value is as the follow \n
* @ref DHCP_FAILED \n
* @ref DHCP_RUNNING \n
* @ref DHCP_IP_ASSIGN \n
* @ref DHCP_IP_CHANGED \n
* @ref DHCP_IP_LEASED \n
* @ref DHCP_STOPPED \n
*
* @note This function is always called by you main task.
*/
uint8_t DHCP_run(void);
/*
* @brief Stop DHCP processing
* @note If you want to restart. call DHCP_init() and DHCP_run()
*/
void DHCP_stop(void);
/* Get Network information assigned from DHCP server */
/*
* @brief Get IP address
* @param ip - IP address to be returned
*/
void getIPfromDHCP(uint8_t* ip);
/*
* @brief Get Gateway address
* @param ip - Gateway address to be returned
*/
void getGWfromDHCP(uint8_t* ip);
/*
* @brief Get Subnet mask value
* @param ip - Subnet mask to be returned
*/
void getSNfromDHCP(uint8_t* ip);
/*
* @brief Get DNS address
* @param ip - DNS address to be returned
*/
void getDNSfromDHCP(uint8_t* ip);
/*
* @brief Get the leased time by DHCP sever
* @return unit 1s
*/
uint32_t getDHCPLeasetime(void);
#endif /* _DHCP_H_ */

View File

@@ -0,0 +1,566 @@
//*****************************************************************************
//
//! \file dns.c
//! \brief DNS APIs Implement file.
//! \details Send DNS query & Receive DNS reponse. \n
//! It depends on stdlib.h & string.h in ansi-c library
//! \version 1.1.0
//! \date 2013/11/18
//! \par Revision history
//! <2013/10/21> 1st Release
//! <2013/12/20> V1.1.0
//! 1. Remove secondary DNS server in DNS_run
//! If 1st DNS_run failed, call DNS_run with 2nd DNS again
//! 2. DNS_timerHandler -> DNS_time_handler
//! 3. Remove the unused define
//! 4. Integrated dns.h dns.c & dns_parse.h dns_parse.c into dns.h & dns.c
//! <2013/12/20> V1.1.0
//!
//! \author Eric Jung & MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#include <string.h>
#include <stdlib.h>
//#include "Ethernet/socket.h"
//#include "Internet/DNS/dns.h"
#include "../../ethernet/socket.h"
#include "dns.h"
#ifdef _DNS_DEBUG_
#include <stdio.h>
#endif
#define INITRTT 2000L /* Initial smoothed response time */
#define MAXCNAME (MAX_DOMAIN_NAME + (MAX_DOMAIN_NAME>>1)) /* Maximum amount of cname recursion */
#define TYPE_A 1 /* Host address */
#define TYPE_NS 2 /* Name server */
#define TYPE_MD 3 /* Mail destination (obsolete) */
#define TYPE_MF 4 /* Mail forwarder (obsolete) */
#define TYPE_CNAME 5 /* Canonical name */
#define TYPE_SOA 6 /* Start of Authority */
#define TYPE_MB 7 /* Mailbox name (experimental) */
#define TYPE_MG 8 /* Mail group member (experimental) */
#define TYPE_MR 9 /* Mail rename name (experimental) */
#define TYPE_NULL 10 /* Null (experimental) */
#define TYPE_WKS 11 /* Well-known sockets */
#define TYPE_PTR 12 /* Pointer record */
#define TYPE_HINFO 13 /* Host information */
#define TYPE_MINFO 14 /* Mailbox information (experimental)*/
#define TYPE_MX 15 /* Mail exchanger */
#define TYPE_TXT 16 /* Text strings */
#define TYPE_ANY 255 /* Matches any type */
#define CLASS_IN 1 /* The ARPA Internet */
/* Round trip timing parameters */
#define AGAIN 8 /* Average RTT gain = 1/8 */
#define LAGAIN 3 /* Log2(AGAIN) */
#define DGAIN 4 /* Mean deviation gain = 1/4 */
#define LDGAIN 2 /* log2(DGAIN) */
/* Header for all domain messages */
struct dhdr
{
uint16_t id; /* Identification */
uint8_t qr; /* Query/Response */
#define QUERY 0
#define RESPONSE 1
uint8_t opcode;
#define IQUERY 1
uint8_t aa; /* Authoratative answer */
uint8_t tc; /* Truncation */
uint8_t rd; /* Recursion desired */
uint8_t ra; /* Recursion available */
uint8_t rcode; /* Response code */
#define NO_ERROR 0
#define FORMAT_ERROR 1
#define SERVER_FAIL 2
#define NAME_ERROR 3
#define NOT_IMPL 4
#define REFUSED 5
uint16_t qdcount; /* Question count */
uint16_t ancount; /* Answer count */
uint16_t nscount; /* Authority (name server) count */
uint16_t arcount; /* Additional record count */
};
uint8_t* pDNSMSG; // DNS message buffer
uint8_t DNS_SOCKET; // SOCKET number for DNS
uint16_t DNS_MSGID; // DNS message ID
extern uint32_t HAL_GetTick(void);
uint32_t hal_sys_tick;
/* converts uint16_t from network buffer to a host byte order integer. */
uint16_t get16(uint8_t * s)
{
uint16_t i;
i = *s++ << 8;
i = i + *s;
return i;
}
/* copies uint16_t to the network buffer with network byte order. */
uint8_t * put16(uint8_t * s, uint16_t i)
{
*s++ = i >> 8;
*s++ = i;
return s;
}
/*
* CONVERT A DOMAIN NAME TO THE HUMAN-READABLE FORM
*
* Description : This function converts a compressed domain name to the human-readable form
* Arguments : msg - is a pointer to the reply message
* compressed - is a pointer to the domain name in reply message.
* buf - is a pointer to the buffer for the human-readable form name.
* len - is the MAX. size of buffer.
* Returns : the length of compressed message
*/
int parse_name(uint8_t * msg, uint8_t * compressed, char * buf, int16_t len)
{
uint16_t slen; /* Length of current segment */
uint8_t * cp;
int clen = 0; /* Total length of compressed name */
int indirect = 0; /* Set if indirection encountered */
int nseg = 0; /* Total number of segments in name */
cp = compressed;
for (;;)
{
slen = *cp++; /* Length of this segment */
if (!indirect) clen++;
if ((slen & 0xc0) == 0xc0)
{
if (!indirect)
clen++;
indirect = 1;
/* Follow indirection */
cp = &msg[((slen & 0x3f)<<8) + *cp];
slen = *cp++;
}
if (slen == 0) /* zero length == all done */
break;
len -= slen + 1;
if (len < 0) return -1;
if (!indirect) clen += slen;
while (slen-- != 0) *buf++ = (char)*cp++;
*buf++ = '.';
nseg++;
}
if (nseg == 0)
{
/* Root name; represent as single dot */
*buf++ = '.';
len--;
}
*buf++ = '\0';
len--;
return clen; /* Length of compressed message */
}
/*
* PARSE QUESTION SECTION
*
* Description : This function parses the question record of the reply message.
* Arguments : msg - is a pointer to the reply message
* cp - is a pointer to the question record.
* Returns : a pointer the to next record.
*/
uint8_t * dns_question(uint8_t * msg, uint8_t * cp)
{
int len;
char name[MAXCNAME];
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
cp += 2; /* type */
cp += 2; /* class */
return cp;
}
/*
* PARSE ANSER SECTION
*
* Description : This function parses the answer record of the reply message.
* Arguments : msg - is a pointer to the reply message
* cp - is a pointer to the answer record.
* Returns : a pointer the to next record.
*/
uint8_t * dns_answer(uint8_t * msg, uint8_t * cp, uint8_t * ip_from_dns)
{
int len, type;
char name[MAXCNAME];
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
type = get16(cp);
cp += 2; /* type */
cp += 2; /* class */
cp += 4; /* ttl */
cp += 2; /* len */
switch (type)
{
case TYPE_A:
/* Just read the address directly into the structure */
ip_from_dns[0] = *cp++;
ip_from_dns[1] = *cp++;
ip_from_dns[2] = *cp++;
ip_from_dns[3] = *cp++;
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
/* These types all consist of a single domain name */
/* convert it to ASCII format */
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
break;
case TYPE_HINFO:
len = *cp++;
cp += len;
len = *cp++;
cp += len;
break;
case TYPE_MX:
cp += 2;
/* Get domain name of exchanger */
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
break;
case TYPE_SOA:
/* Get domain name of name server */
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
/* Get domain name of responsible person */
len = parse_name(msg, cp, name, MAXCNAME);
if (len == -1) return 0;
cp += len;
cp += 4;
cp += 4;
cp += 4;
cp += 4;
cp += 4;
break;
case TYPE_TXT:
/* Just stash */
break;
default:
/* Ignore */
break;
}
return cp;
}
/*
* PARSE THE DNS REPLY
*
* Description : This function parses the reply message from DNS server.
* Arguments : dhdr - is a pointer to the header for DNS message
* buf - is a pointer to the reply message.
* len - is the size of reply message.
* Returns : -1 - Domain name length is too big
* 0 - Fail (Timeout or parse error)
* 1 - Success,
*/
int8_t parseDNSMSG(struct dhdr * pdhdr, uint8_t * pbuf, uint8_t * ip_from_dns)
{
uint16_t tmp;
uint16_t i;
uint8_t * msg;
uint8_t * cp;
msg = pbuf;
memset(pdhdr, 0, sizeof(*pdhdr));
pdhdr->id = get16(&msg[0]);
tmp = get16(&msg[2]);
if (tmp & 0x8000) pdhdr->qr = 1;
pdhdr->opcode = (tmp >> 11) & 0xf;
if (tmp & 0x0400) pdhdr->aa = 1;
if (tmp & 0x0200) pdhdr->tc = 1;
if (tmp & 0x0100) pdhdr->rd = 1;
if (tmp & 0x0080) pdhdr->ra = 1;
pdhdr->rcode = tmp & 0xf;
pdhdr->qdcount = get16(&msg[4]);
pdhdr->ancount = get16(&msg[6]);
pdhdr->nscount = get16(&msg[8]);
pdhdr->arcount = get16(&msg[10]);
/* Now parse the variable length sections */
cp = &msg[12];
/* Question section */
for (i = 0; i < pdhdr->qdcount; i++)
{
cp = dns_question(msg, cp);
if(!cp)
{
#ifdef _DNS_DEBUG_
printf("MAX_DOMAIN_NAME is too small, it should be redefined in dns.h\r\n");
#endif
return -1;
}
}
/* Answer section */
for (i = 0; i < pdhdr->ancount; i++)
{
cp = dns_answer(msg, cp, ip_from_dns);
if(!cp)
{
#ifdef _DNS_DEBUG_
printf("MAX_DOMAIN_NAME is too small, it should be redefined in dns.h\r\n");
#endif
return -1;
}
}
/* Name server (authority) section */
for (i = 0; i < pdhdr->nscount; i++)
{
;
}
/* Additional section */
for (i = 0; i < pdhdr->arcount; i++)
{
;
}
if(pdhdr->rcode == 0) return 1; // No error
else return 0;
}
/*
* MAKE DNS QUERY MESSAGE
*
* Description : This function makes DNS query message.
* Arguments : op - Recursion desired
* name - is a pointer to the domain name.
* buf - is a pointer to the buffer for DNS message.
* len - is the MAX. size of buffer.
* Returns : the pointer to the DNS message.
*/
int16_t dns_makequery(uint16_t op, char * name, uint8_t * buf, uint16_t len)
{
uint8_t *cp;
char *cp1;
char sname[MAXCNAME];
char *dname;
uint16_t p;
uint16_t dlen;
cp = buf;
DNS_MSGID++;
cp = put16(cp, DNS_MSGID);
p = (op << 11) | 0x0100; /* Recursion desired */
cp = put16(cp, p);
cp = put16(cp, 1);
cp = put16(cp, 0);
cp = put16(cp, 0);
cp = put16(cp, 0);
strcpy(sname, name);
dname = sname;
dlen = strlen(dname);
for (;;)
{
/* Look for next dot */
cp1 = strchr(dname, '.');
if (cp1 != NULL) len = cp1 - dname; /* More to come */
else len = dlen; /* Last component */
*cp++ = len; /* Write length of component */
if (len == 0) break;
/* Copy component up to (but not including) dot */
memcpy(cp, dname, len);
cp += len;
if (cp1 == NULL)
{
*cp++ = 0; /* Last one; write null and finish */
break;
}
dname += len+1;
dlen -= len+1;
}
cp = put16(cp, 0x0001); /* type */
cp = put16(cp, 0x0001); /* class */
return ((int16_t)((uint32_t)(cp) - (uint32_t)(buf)));
}
/*
* CHECK DNS TIMEOUT
*
* Description : This function check the DNS timeout
* Arguments : None.
* Returns : -1 - timeout occurred, 0 - timer over, but no timeout, 1 - no timer over, no timeout occur
* Note : timeout : retry count and timer both over.
*/
int8_t check_DNS_timeout(void)
{
static uint8_t retry_count;
uint32_t tick = HAL_GetTick();
if(tick - hal_sys_tick >= DNS_WAIT_TIME * 1000)
{
hal_sys_tick = tick;
if(retry_count >= MAX_DNS_RETRY) {
retry_count = 0;
return -1; // timeout occurred
}
retry_count++;
return 0; // timer over, but no timeout
}
return 1; // no timer over, no timeout occur
}
/* DNS CLIENT INIT */
void DNS_init(uint8_t s, uint8_t * buf)
{
DNS_SOCKET = s; // SOCK_DNS
pDNSMSG = buf; // User's shared buffer
DNS_MSGID = DNS_MSG_ID;
}
/* DNS CLIENT RUN */
int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns)
{
int8_t ret;
struct dhdr dhp;
uint8_t ip[4];
uint16_t len, port;
int8_t ret_check_timeout;
hal_sys_tick = HAL_GetTick();
// Socket open
socket(DNS_SOCKET, Sn_MR_UDP, 0, 0);
#ifdef _DNS_DEBUG_
printf("> DNS Query to DNS Server : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
#endif
len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE);
sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
while (1)
{
if ((len = getSn_RX_RSR(DNS_SOCKET)) > 0)
{
if (len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE;
len = recvfrom(DNS_SOCKET, pDNSMSG, len, ip, &port);
#ifdef _DNS_DEBUG_
printf("> Receive DNS message from %d.%d.%d.%d(%d). len = %d\r\n", ip[0], ip[1], ip[2], ip[3],port,len);
#endif
ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns);
break;
}
// Check Timeout
ret_check_timeout = check_DNS_timeout();
if (ret_check_timeout < 0) {
#ifdef _DNS_DEBUG_
printf("> DNS Server is not responding : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
#endif
return 0; // timeout occurred
}
else if (ret_check_timeout == 0) {
#ifdef _DNS_DEBUG_
printf("> DNS Timeout\r\n");
#endif
sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
}
}
close(DNS_SOCKET);
// Return value
// 0 > : failed / 1 - success
return ret;
}

View File

@@ -0,0 +1,96 @@
//*****************************************************************************
//
//! \file dns.h
//! \brief DNS APIs Header file.
//! \details Send DNS query & Receive DNS reponse.
//! \version 1.1.0
//! \date 2013/11/18
//! \par Revision history
//! <2013/10/21> 1st Release
//! <2013/12/20> V1.1.0
//! 1. Remove secondary DNS server in DNS_run
//! If 1st DNS_run failed, call DNS_run with 2nd DNS again
//! 2. DNS_timerHandler -> DNS_time_handler
//! 3. Move the no reference define to dns.c
//! 4. Integrated dns.h dns.c & dns_parse.h dns_parse.c into dns.h & dns.c
//! <2013/12/20> V1.1.0
//!
//! \author Eric Jung & MidnightCow
//! \copyright
//!
//! Copyright (c) 2013, WIZnet Co., LTD.
//! All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//! * Redistributions of source code must retain the above copyright
//! notice, this list of conditions and the following disclaimer.
//! * Redistributions in binary form must reproduce the above copyright
//! notice, this list of conditions and the following disclaimer in the
//! documentation and/or other materials provided with the distribution.
//! * Neither the name of the <ORGANIZATION> nor the names of its
//! contributors may be used to endorse or promote products derived
//! from this software without specific prior written permission.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
//! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
//! THE POSSIBILITY OF SUCH DAMAGE.
//
//*****************************************************************************
#ifndef _DNS_H_
#define _DNS_H_
#include <stdint.h>
/*
* @brief Define it for Debug & Monitor DNS processing.
* @note If defined, it depends on <stdio.h>
*/
//#define _DNS_DEBUG_
#define MAX_DNS_BUF_SIZE 256 ///< maximum size of DNS buffer. */
/*
* @brief Maximum length of your queried Domain name
* @todo SHOULD BE defined it equal as or greater than your Domain name length + null character(1)
* @note SHOULD BE careful to stack overflow because it is allocated 1.5 times as MAX_DOMAIN_NAME in stack.
*/
#define MAX_DOMAIN_NAME 32 // for example "www.google.com"
#define MAX_DNS_RETRY 2 ///< Requery Count
#define DNS_WAIT_TIME 4 ///< Wait response time. unit 1s.
#define IPPORT_DOMAIN 53 ///< DNS server port number
#define DNS_MSG_ID 0x1122 ///< ID for DNS message. You can be modified it any number
/*
* @brief DNS process initialize
* @param s : Socket number for DNS
* @param buf : Buffer for DNS message
*/
void DNS_init(uint8_t s, uint8_t * buf);
/*
* @brief DNS process
* @details Send DNS query and receive DNS response
* @param dns_ip : DNS server ip address
* @param name : Domain name to be queried
* @param ip_from_dns : IP address from DNS server
* @return -1 : failed. @ref MAX_DOMIN_NAME is too small \n
* 0 : failed (Timeout or Parse error)\n
* 1 : success
* @note This function blocks until success or fail. max time = @ref MAX_DNS_RETRY * @ref DNS_WAIT_TIME
*/
int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns);
#endif /* _DNS_H_ */

58
examples/pins.py Normal file
View File

@@ -0,0 +1,58 @@
# Print a nice list of pins, their current settings, and available afs.
# Requires pins_af.py from stmhal/build-PYBV10/ directory.
import pyb
import pins_af
def af():
max_name_width = 0
max_af_width = 0
for pin_entry in pins_af.PINS_AF:
max_name_width = max(max_name_width, len(pin_entry[0]))
for af_entry in pin_entry[1:]:
max_af_width = max(max_af_width, len(af_entry[1]))
for pin_entry in pins_af.PINS_AF:
pin_name = pin_entry[0]
print('%-*s ' % (max_name_width, pin_name), end='')
for af_entry in pin_entry[1:]:
print('%2d: %-*s ' % (af_entry[0], max_af_width, af_entry[1]), end='')
print('')
def pins():
mode_str = { pyb.Pin.IN : 'IN',
pyb.Pin.OUT_PP : 'OUT_PP',
pyb.Pin.OUT_OD : 'OUT_OD',
pyb.Pin.AF_PP : 'AF_PP',
pyb.Pin.AF_OD : 'AF_OD',
pyb.Pin.ANALOG : 'ANALOG' }
pull_str = { pyb.Pin.PULL_NONE : '',
pyb.Pin.PULL_UP : 'PULL_UP',
pyb.Pin.PULL_DOWN : 'PULL_DOWN' }
width = [0, 0, 0, 0]
rows = []
for pin_entry in pins_af.PINS_AF:
row = []
pin_name = pin_entry[0]
pin = pyb.Pin(pin_name)
pin_mode = pin.mode()
row.append(pin_name)
row.append(mode_str[pin_mode])
row.append(pull_str[pin.pull()])
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
pin_af = pin.af()
for af_entry in pin_entry[1:]:
if pin_af == af_entry[0]:
af_str = '%d: %s' % (pin_af, af_entry[1])
break
else:
af_str = '%d' % pin_af
else:
af_str = ''
row.append(af_str)
for col in range(len(width)):
width[col] = max(width[col], len(row[col]))
rows.append(row)
for row in rows:
for col in range(len(width)):
print('%-*s ' % (width[col], row[col]), end='')
print('')

View File

@@ -94,10 +94,11 @@ typedef enum
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
// Internal/private bits follow.
// dpgeorge: TINFL_FAST_LOOKUP_BITS can be adjusted to trade off RAM usage against speed.
enum
{
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
TINFL_FAST_LOOKUP_BITS = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
};
typedef struct
@@ -228,12 +229,12 @@ struct tinfl_decompressor_tag
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
{
static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static const mz_uint16 s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
static const mz_uint8 s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static const mz_uint16 s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static const mz_uint8 s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
static const int s_min_table_sizes[3] = { 257, 1, 4 };
static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 };
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
@@ -498,6 +499,7 @@ common_exit:
return status;
}
#if 0
// Higher level helper functions.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
{
@@ -561,6 +563,7 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
*pIn_buf_size = in_buf_ofs;
return result;
}
#endif
#endif // #ifndef TINFL_HEADER_FILE_ONLY

View File

@@ -119,7 +119,7 @@ STATIC NORETURN void syntax_error() {
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, uint n_args, uint n_kw, const mp_obj_t *args) {
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) {
if (n_args < 2 || n_args > 3) {
syntax_error();
}
@@ -261,10 +261,10 @@ STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
}
}
STATIC inline void set_unaligned(uint val_type, void *p, int big_endian, mp_obj_t val) {
STATIC inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
char struct_type = big_endian ? '>' : '<';
static const char type2char[8] = "BbHhIiQq";
mp_binary_set_val(struct_type, type2char[val_type], val, (byte**)&p);
mp_binary_set_val(struct_type, type2char[val_type], val, &p);
}
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {

279
extmod/modujson.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#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"
#if MICROPY_PY_UJSON
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
vstr_t vstr;
vstr_init(&vstr, 8);
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, obj, PRINT_JSON);
mp_obj_t ret = mp_obj_new_str(vstr.buf, vstr.len, false);
vstr_clear(&vstr);
return ret;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
// This function implements a simple non-recursive JSON parser.
//
// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt
// The parser here will parse any valid JSON and return the correct
// corresponding Python object. It allows through a superset of JSON, since
// it treats commas and colons as "whitespace", and doesn't care if
// brackets/braces are correctly paired. It will raise a ValueError if the
// input is outside it's specs.
//
// Most of the work is parsing the primitives (null, false, true, numbers,
// strings). It does 1 pass over the input string and so is easily extended to
// being able to parse from a non-seekable stream. It tries to be fast and
// small in code size, while not using more RAM than necessary.
STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
mp_uint_t len;
const char *s = mp_obj_str_get_data(obj, &len);
const char *top = s + len;
vstr_t vstr;
vstr_init(&vstr, 8);
mp_obj_list_t stack; // we use a list as a simple stack for nested JSON
stack.len = 0;
stack.items = NULL;
mp_obj_t stack_top = MP_OBJ_NULL;
mp_obj_type_t *stack_top_type = NULL;
mp_obj_t stack_key = MP_OBJ_NULL;
for (;;) {
cont:
if (s == top) {
break;
}
mp_obj_t next = MP_OBJ_NULL;
bool enter = false;
switch (*s) {
case ',':
case ':':
case ' ':
s += 1;
goto cont;
case 'n':
if (s + 3 < top && s[1] == 'u' && s[2] == 'l' && s[3] == 'l') {
s += 4;
next = mp_const_none;
} else {
goto fail;
}
break;
case 'f':
if (s + 4 < top && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e') {
s += 5;
next = mp_const_false;
} else {
goto fail;
}
break;
case 't':
if (s + 3 < top && s[1] == 'r' && s[2] == 'u' && s[3] == 'e') {
s += 4;
next = mp_const_true;
} else {
goto fail;
}
break;
case '"':
vstr_reset(&vstr);
for (s++; s < top && *s != '"';) {
byte c = *s;
if (c == '\\') {
s++;
c = *s;
switch (c) {
case 'b': c = 0x08; break;
case 'f': c = 0x0c; break;
case 'n': c = 0x0a; break;
case 'r': c = 0x0d; break;
case 't': c = 0x09; break;
case 'u': {
if (s + 4 >= top) { goto fail; }
mp_uint_t num = 0;
for (int i = 0; i < 4; i++) {
c = (*++s | 0x20) - '0';
if (c > 9) {
c -= ('a' - ('9' + 1));
}
num = (num << 4) | c;
}
vstr_add_char(&vstr, num);
goto str_cont;
}
}
}
vstr_add_byte(&vstr, c);
str_cont:
s++;
}
if (s == top) {
goto fail;
}
s++;
next = mp_obj_new_str(vstr.buf, vstr.len, false);
break;
case '-':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
bool flt = false;
vstr_reset(&vstr);
for (; s < top; s++) {
if (*s == '.' || *s == 'E' || *s == 'e') {
flt = true;
} else if (*s == '-' || unichar_isdigit(*s)) {
// pass
} else {
break;
}
vstr_add_byte(&vstr, *s);
}
if (flt) {
next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false);
} else {
next = mp_parse_num_integer(vstr.buf, vstr.len, 10);
}
break;
}
case '[':
next = mp_obj_new_list(0, NULL);
enter = true;
s += 1;
break;
case '{':
next = mp_obj_new_dict(0);
enter = true;
s += 1;
break;
case '}':
case ']': {
s += 1;
if (stack_top == MP_OBJ_NULL) {
// no object at all
goto fail;
}
if (stack.len == 0) {
// finished; compound object
goto success;
}
stack.len -= 1;
stack_top = stack.items[stack.len];
stack_top_type = mp_obj_get_type(stack_top);
goto cont;
}
default:
goto fail;
}
if (stack_top == MP_OBJ_NULL) {
stack_top = next;
stack_top_type = mp_obj_get_type(stack_top);
if (!enter) {
// finished; single primitive only
goto success;
}
} else {
// append to list or dict
if (stack_top_type == &mp_type_list) {
mp_obj_list_append(stack_top, next);
} else {
if (stack_key == MP_OBJ_NULL) {
stack_key = next;
if (enter) {
goto fail;
}
} else {
mp_obj_dict_store(stack_top, stack_key, next);
stack_key = MP_OBJ_NULL;
}
}
if (enter) {
if (stack.items == NULL) {
mp_obj_list_init(&stack, 1);
stack.items[0] = stack_top;
} else {
mp_obj_list_append(&stack, stack_top);
}
stack_top = next;
stack_top_type = mp_obj_get_type(stack_top);
}
}
}
success:
// eat trailing whitespace
while (s < top && unichar_isspace(*s)) {
s++;
}
if (s < top) {
// unexpected chars
goto fail;
}
if (stack.len != 0) {
goto fail;
}
vstr_clear(&vstr);
return stack_top;
fail:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "syntax error in JSON"));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
STATIC const mp_map_elem_t mp_module_ujson_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ujson) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_dumps), (mp_obj_t)&mod_ujson_dumps_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_loads), (mp_obj_t)&mod_ujson_loads_obj },
};
STATIC const mp_obj_dict_t mp_module_ujson_globals = {
.base = {&mp_type_dict},
.map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
.alloc = MP_ARRAY_SIZE(mp_module_ujson_globals_table),
.table = (mp_map_elem_t*)mp_module_ujson_globals_table,
},
};
const mp_obj_module_t mp_module_ujson = {
.base = { &mp_type_module },
.name = MP_QSTR_ujson,
.globals = (mp_obj_dict_t*)&mp_module_ujson_globals,
};
#endif //MICROPY_PY_UJSON

View File

@@ -53,7 +53,7 @@ STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
tinfl_decompressor *decomp = m_new_obj(tinfl_decompressor);
tinfl_init(decomp);
DEBUG_printf("sizeof(tinfl_decompressor)=%d\n", sizeof(tinfl_decompressor));
DEBUG_printf("sizeof(tinfl_decompressor)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
byte *out = m_new(byte, bufinfo.len);
size_t out_len = bufinfo.len;
@@ -64,7 +64,7 @@ STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
size_t in_buf_sz = bufinfo.len - in_buf_ofs;
DEBUG_printf("tinfl in: in_ofs=%d in_sz=%d dst_ofs=%d, dst_sz=%d\n", in_buf_ofs, in_buf_sz, dst_buf_ofs, dst_buf_sz);
tinfl_status st = tinfl_decompress(decomp,
bufinfo.buf + in_buf_ofs, &in_buf_sz,
(mz_uint8*) bufinfo.buf + in_buf_ofs, &in_buf_sz,
out, out + dst_buf_ofs, &dst_buf_sz,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER);
DEBUG_printf("tinfl out: st=%d, in_sz=%d, out_sz=%d\n", st, in_buf_sz, dst_buf_sz);

2
lib/README.md Normal file
View File

@@ -0,0 +1,2 @@
This directory contains standard, low-level C libraries with emphasis on
being independent and efficient. They can be used by any port.

130
lib/libm/asinfacosf.c Normal file
View File

@@ -0,0 +1,130 @@
/*****************************************************************************/
/*****************************************************************************/
// asinf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.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 "libm.h"
// dpgeorge: pio2 was double in original implementation of asinf
static const float
pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
pio2_lo = 7.5497894159e-08; /* 0x33a22168 */
static const float
/* coefficients for R(x^2) */
pS0 = 1.6666586697e-01,
pS1 = -4.2743422091e-02,
pS2 = -8.6563630030e-03,
qS1 = -7.0662963390e-01;
static float R(float z)
{
float_t p, q;
p = z*(pS0+z*(pS1+z*pS2));
q = 1.0f+z*qS1;
return p/q;
}
float asinf(float x)
{
// dpgeorge: s was double in original implementation
float s,z;
uint32_t hx,ix;
GET_FLOAT_WORD(hx, x);
ix = hx & 0x7fffffff;
if (ix >= 0x3f800000) { /* |x| >= 1 */
if (ix == 0x3f800000) /* |x| == 1 */
return x*pio2_hi + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */
return 0/(x-x); /* asin(|x|>1) is NaN */
}
if (ix < 0x3f000000) { /* |x| < 0.5 */
/* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */
if (ix < 0x39800000 && ix >= 0x00800000)
return x;
return x + x*R(x*x);
}
/* 1 > |x| >= 0.5 */
z = (1 - fabsf(x))*0.5f;
s = sqrtf(z);
x = pio2_hi - (2*(s+s*R(z)) - pio2_lo); // dpgeorge: use pio2_hi and pio2_lo
if (hx >> 31)
return -x;
return x;
}
/*****************************************************************************/
/*****************************************************************************/
// acosf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
float acosf(float x)
{
float z,w,s,c,df;
uint32_t hx,ix;
GET_FLOAT_WORD(hx, x);
ix = hx & 0x7fffffff;
/* |x| >= 1 or nan */
if (ix >= 0x3f800000) {
if (ix == 0x3f800000) {
if (hx >> 31)
return 2*pio2_hi + 0x1p-120f;
return 0;
}
return 0/(x-x);
}
/* |x| < 0.5 */
if (ix < 0x3f000000) {
if (ix <= 0x32800000) /* |x| < 2**-26 */
return pio2_hi + 0x1p-120f;
return pio2_hi - (x - (pio2_lo-x*R(x*x)));
}
/* x < -0.5 */
if (hx >> 31) {
z = (1+x)*0.5f;
s = sqrtf(z);
w = R(z)*s-pio2_lo;
return 2*(pio2_hi - (s+w));
}
/* x > 0.5 */
z = (1-x)*0.5f;
s = sqrtf(z);
GET_FLOAT_WORD(hx,s);
SET_FLOAT_WORD(df,hx&0xfffff000);
c = (z-df*df)/(s+df);
w = R(z)*s+c;
return 2*(df+w);
}

89
lib/libm/atan2f.c Normal file
View File

@@ -0,0 +1,89 @@
/*****************************************************************************/
/*****************************************************************************/
// atan2f from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.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 "libm.h"
static const float
pi = 3.1415927410e+00, /* 0x40490fdb */
pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */
float atan2f(float y, float x)
{
float z;
uint32_t m,ix,iy;
if (isnan(x) || isnan(y))
return x+y;
GET_FLOAT_WORD(ix, x);
GET_FLOAT_WORD(iy, y);
if (ix == 0x3f800000) /* x=1.0 */
return atanf(y);
m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */
ix &= 0x7fffffff;
iy &= 0x7fffffff;
/* when y = 0 */
if (iy == 0) {
switch (m) {
case 0:
case 1: return y; /* atan(+-0,+anything)=+-0 */
case 2: return pi; /* atan(+0,-anything) = pi */
case 3: return -pi; /* atan(-0,-anything) =-pi */
}
}
/* when x = 0 */
if (ix == 0)
return m&1 ? -pi/2 : pi/2;
/* when x is INF */
if (ix == 0x7f800000) {
if (iy == 0x7f800000) {
switch (m) {
case 0: return pi/4; /* atan(+INF,+INF) */
case 1: return -pi/4; /* atan(-INF,+INF) */
case 2: return 3*pi/4; /*atan(+INF,-INF)*/
case 3: return -3*pi/4; /*atan(-INF,-INF)*/
}
} else {
switch (m) {
case 0: return 0.0f; /* atan(+...,+INF) */
case 1: return -0.0f; /* atan(-...,+INF) */
case 2: return pi; /* atan(+...,-INF) */
case 3: return -pi; /* atan(-...,-INF) */
}
}
}
/* |y/x| > 0x1p26 */
if (ix+(26<<23) < iy || iy == 0x7f800000)
return m&1 ? -pi/2 : pi/2;
/* z = atan(|y/x|) with correct underflow */
if ((m&2) && iy+(26<<23) < ix) /*|y/x| < 0x1p-26, x < 0 */
z = 0.0;
else
z = atanf(fabsf(y/x));
switch (m) {
case 0: return z; /* atan(+,+) */
case 1: return -z; /* atan(-,+) */
case 2: return pi - (z-pi_lo); /* atan(+,-) */
default: /* case 3 */
return (z-pi_lo) - pi; /* atan(-,-) */
}
}

100
lib/libm/atanf.c Normal file
View File

@@ -0,0 +1,100 @@
/*****************************************************************************/
/*****************************************************************************/
// atanf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.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 "libm.h"
static const float atanhi[] = {
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
};
static const float atanlo[] = {
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
};
static const float aT[] = {
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,
-1.0648017377e-01,
6.1687607318e-02,
};
float atanf(float x)
{
float_t w,s1,s2,z;
uint32_t ix,sign;
int id;
GET_FLOAT_WORD(ix, x);
sign = ix>>31;
ix &= 0x7fffffff;
if (ix >= 0x4c800000) { /* if |x| >= 2**26 */
if (isnan(x))
return x;
z = atanhi[3] + 0x1p-120f;
return sign ? -z : z;
}
if (ix < 0x3ee00000) { /* |x| < 0.4375 */
if (ix < 0x39800000) { /* |x| < 2**-12 */
if (ix < 0x00800000)
/* raise underflow for subnormal x */
FORCE_EVAL(x*x);
return x;
}
id = -1;
} else {
x = fabsf(x);
if (ix < 0x3f980000) { /* |x| < 1.1875 */
if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */
id = 0;
x = (2.0f*x - 1.0f)/(2.0f + x);
} else { /* 11/16 <= |x| < 19/16 */
id = 1;
x = (x - 1.0f)/(x + 1.0f);
}
} else {
if (ix < 0x401c0000) { /* |x| < 2.4375 */
id = 2;
x = (x - 1.5f)/(1.0f + 1.5f*x);
} else { /* 2.4375 <= |x| < 2**26 */
id = 3;
x = -1.0f/x;
}
}
}
/* end of argument reduction */
z = x*x;
w = z*z;
/* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
s1 = z*(aT[0]+w*(aT[2]+w*aT[4]));
s2 = w*(aT[1]+w*aT[3]);
if (id < 0)
return x - x*(s1+s2);
z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
return sign ? -z : z;
}

70
lib/libm/fmodf.c Normal file
View File

@@ -0,0 +1,70 @@
/*****************************************************************************/
/*****************************************************************************/
// fmodf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
#include "libm.h"
float fmodf(float x, float y)
{
union {float f; uint32_t i;} ux = {x}, uy = {y};
int ex = ux.i>>23 & 0xff;
int ey = uy.i>>23 & 0xff;
uint32_t sx = ux.i & 0x80000000;
uint32_t i;
uint32_t uxi = ux.i;
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
return (x*y)/(x*y);
if (uxi<<1 <= uy.i<<1) {
if (uxi<<1 == uy.i<<1)
return 0*x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1U >> 9;
uxi |= 1U << 23;
}
if (!ey) {
for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1U >> 9;
uy.i |= 1U << 23;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
for (; uxi>>23 == 0; uxi <<= 1, ex--);
/* scale result up */
if (ex > 0) {
uxi -= 1U << 23;
uxi |= (uint32_t)ex << 23;
} else {
uxi >>= -ex + 1;
}
uxi |= sx;
ux.i = uxi;
return ux.f;
}

52
lib/libm/libm.h Normal file
View File

@@ -0,0 +1,52 @@
/*****************************************************************************/
/*****************************************************************************/
// portions extracted from musl-0.9.15 libm.h
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
/*
* ====================================================
* 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 <stdint.h>
#include <math.h>
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
__x = (x); \
(void)__x; \
} else if (sizeof(x) == sizeof(double)) { \
volatile double __x; \
__x = (x); \
(void)__x; \
} else { \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while(0)
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(w,d) \
do { \
union {float f; uint32_t i;} __u; \
__u.f = (d); \
(w) = __u.i; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,w) \
do { \
union {float f; uint32_t i;} __u; \
__u.i = (w); \
(d) = __u.f; \
} while (0)

View File

@@ -24,8 +24,7 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <math.h>
#include "libm.h"
typedef float float_t;
typedef union {
@@ -118,11 +117,6 @@ float acoshf(float x) { return 0.0; }
float asinhf(float x) { return 0.0; }
float atanhf(float x) { return 0.0; }
float tanf(float x) { return 0.0; }
float acosf(float x) { return 0.0; }
float asinf(float x) { return 0.0; }
float atanf(float x) { return 0.0; }
float atan2f(float x, float y) { return 0.0; }
float fmodf(float x, float y) { return 0.0; }
float tgammaf(float x) { return 0.0; }
float lgammaf(float x) { return 0.0; }
float erff(float x) { return 0.0; }
@@ -131,56 +125,6 @@ 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; }
/*****************************************************************************/
/*****************************************************************************/
// from musl-0.9.15 libm.h
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
__x = (x); \
(void)__x; \
} else if (sizeof(x) == sizeof(double)) { \
volatile double __x; \
__x = (x); \
(void)__x; \
} else { \
volatile long double __x; \
__x = (x); \
(void)__x; \
} \
} while(0)
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(w,d) \
do { \
union {float f; uint32_t i;} __u; \
__u.f = (d); \
(w) = __u.i; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,w) \
do { \
union {float f; uint32_t i;} __u; \
__u.i = (w); \
(d) = __u.f; \
} while (0)
/*****************************************************************************/
/*****************************************************************************/
// __fpclassifyf from musl-0.9.15

View File

@@ -34,7 +34,7 @@
#include "obj.h"
#include "runtime.h"
void mp_arg_check_num(uint n_args, uint n_kw, uint n_args_min, uint n_args_max, bool takes_kw) {
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) {
@@ -60,9 +60,9 @@ void mp_arg_check_num(uint n_args, uint n_kw, uint n_args_min, uint n_args_max,
}
}
void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
uint pos_found = 0, kws_found = 0;
for (uint i = 0; i < n_allowed; i++) {
void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_uint_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
mp_uint_t pos_found = 0, kws_found = 0;
for (mp_uint_t i = 0; i < n_allowed; i++) {
mp_obj_t given_arg;
if (i < n_pos) {
if (allowed[i].flags & MP_ARG_KW_ONLY) {
@@ -104,7 +104,7 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all
}
}
void mp_arg_parse_all_kw_array(uint n_pos, uint n_kw, const mp_obj_t *args, uint n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
void mp_arg_parse_all_kw_array(mp_uint_t n_pos, mp_uint_t n_kw, const mp_obj_t *args, mp_uint_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals) {
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_pos);
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);

339
py/asmarm.c Normal file
View File

@@ -0,0 +1,339 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Fabian Vogt
* 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 <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "asmarm.h"
// wrapper around everything in this file
#if MICROPY_EMIT_ARM
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
struct _asm_arm_t {
uint pass;
mp_uint_t code_offset;
mp_uint_t code_size;
byte *code_base;
byte dummy_data[4];
uint max_num_labels;
int *label_offsets;
int num_locals;
uint push_reglist;
uint stack_adjust;
};
asm_arm_t *asm_arm_new(uint max_num_labels) {
asm_arm_t *as;
as = m_new0(asm_arm_t, 1);
as->max_num_labels = max_num_labels;
as->label_offsets = m_new(int, max_num_labels);
return as;
}
void asm_arm_free(asm_arm_t *as, bool free_code) {
if (free_code) {
MP_PLAT_FREE_EXEC(as->code_base, as->code_size);
}
m_del_obj(asm_arm_t, as);
}
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(int));
}
}
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) {
#ifdef __arm__
// flush I- and D-cache
asm volatile(
"0:"
"mrc p15, 0, r15, c7, c10, 3\n"
"bne 0b\n"
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c7, 0\n"
: : : "r0", "cc");
#endif
}
}
// all functions must go through this one to emit bytes
// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length
STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) {
if (as->pass < ASM_ARM_PASS_EMIT) {
as->code_offset += num_bytes_to_write;
return as->dummy_data;
} else {
assert(as->code_offset + num_bytes_to_write <= as->code_size);
byte *c = as->code_base + as->code_offset;
as->code_offset += num_bytes_to_write;
return c;
}
}
uint asm_arm_get_code_size(asm_arm_t *as) {
return as->code_size;
}
void *asm_arm_get_code(asm_arm_t *as) {
return as->code_base;
}
// Insert word into instruction flow
STATIC void emit(asm_arm_t *as, uint op) {
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
}
// Insert word into instruction flow, add "ALWAYS" condition code
STATIC void emit_al(asm_arm_t *as, uint op) {
emit(as, op | ARM_CC_AL);
}
// Basic instructions without condition code
STATIC uint asm_arm_op_push(uint reglist) {
// stmfd sp!, {reglist}
return 0x92d0000 | (reglist & 0xFFFF);
}
STATIC uint asm_arm_op_pop(uint reglist) {
// ldmfd sp!, {reglist}
return 0x8bd0000 | (reglist & 0xFFFF);
}
STATIC uint asm_arm_op_mov_reg(uint rd, uint rn) {
// mov rd, rn
return 0x1a00000 | (rd << 12) | rn;
}
STATIC uint asm_arm_op_mov_imm(uint rd, uint imm) {
// mov rd, #imm
return 0x3a00000 | (rd << 12) | imm;
}
STATIC uint asm_arm_op_mvn_imm(uint rd, uint imm) {
// mvn rd, #imm
return 0x3e00000 | (rd << 12) | imm;
}
STATIC uint asm_arm_op_add_imm(uint rd, uint rn, uint imm) {
// add rd, rn, #imm
return 0x2800000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
}
STATIC uint asm_arm_op_add_reg(uint rd, uint rn, uint rm) {
// add rd, rn, rm
return 0x0800000 | (rn << 16) | (rd << 12) | rm;
}
STATIC uint asm_arm_op_sub_imm(uint rd, uint rn, uint imm) {
// sub rd, rn, #imm
return 0x2400000 | (rn << 16) | (rd << 12) | (imm & 0xFF);
}
void asm_arm_bkpt(asm_arm_t *as) {
// bkpt #0
emit_al(as, 0x1200070);
}
// locals:
// - stored on the stack in ascending order
// - numbered 0 through as->num_locals-1
// - SP points to first local
//
// | SP
// v
// l0 l1 l2 ... l(n-1)
// ^ ^
// | low address | high address in RAM
void asm_arm_entry(asm_arm_t *as, int num_locals) {
if (num_locals < 0) {
num_locals = 0;
}
as->stack_adjust = 0;
as->num_locals = num_locals;
as->push_reglist = 1 << REG_R1 | 1 << REG_R2 | 1 << REG_R3 | 1 << REG_R4
| 1 << REG_R5 | 1 << REG_R6 | 1 << REG_R7 | 1 << REG_R8;
// Only adjust the stack if there are more locals than usable registers
if(num_locals > 3) {
as->stack_adjust = num_locals * 4;
// Align stack to 8 bytes
if(as->num_locals & 1)
as->stack_adjust += 4;
}
emit_al(as, asm_arm_op_push(as->push_reglist | 1 << REG_LR));
if (as->stack_adjust > 0) {
emit_al(as, asm_arm_op_sub_imm(REG_SP, REG_SP, as->stack_adjust));
}
}
void asm_arm_exit(asm_arm_t *as) {
if (as->stack_adjust > 0) {
emit_al(as, asm_arm_op_add_imm(REG_SP, REG_SP, as->stack_adjust));
}
emit_al(as, asm_arm_op_pop(as->push_reglist | (1 << REG_PC)));
}
void asm_arm_label_assign(asm_arm_t *as, uint label) {
assert(label < as->max_num_labels);
if (as->pass < ASM_ARM_PASS_EMIT) {
// assign label offset
assert(as->label_offsets[label] == -1);
as->label_offsets[label] = as->code_offset;
} else {
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
assert(as->label_offsets[label] == as->code_offset);
}
}
void asm_arm_align(asm_arm_t* as, uint align) {
// TODO fill unused data with NOPs?
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
}
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) {
byte *c = asm_arm_get_cur_to_write_bytes(as, bytesize);
// only write to the buffer in the emit pass (otherwise we overflow dummy_data)
if (as->pass == ASM_ARM_PASS_EMIT) {
// little endian
for (uint i = 0; i < bytesize; i++) {
*c++ = val;
val >>= 8;
}
}
}
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) {
emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
}
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm) {
// TODO: There are more variants of immediate values
if ((imm & 0xFF) == imm) {
emit_al(as, asm_arm_op_mov_imm(rd, imm));
} else if (imm < 0 && ((-imm) & 0xFF) == -imm) {
emit_al(as, asm_arm_op_mvn_imm(rd, -imm));
} else {
//Insert immediate into code and jump over it
emit_al(as, 0x59f0000 | (rd << 12)); // ldr rd, [pc]
emit_al(as, 0xa000000); // b pc
emit(as, imm);
}
}
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd) {
// str rd, [sp, #local_num*4]
emit_al(as, 0x58d0000 | (rd << 12) | (local_num << 2));
}
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num) {
// ldr rd, [sp, #local_num*4]
emit_al(as, 0x59d0000 | (rd << 12) | (local_num << 2));
}
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm) {
// cmp rd, #imm
emit_al(as, 0x3500000 | (rd << 16) | (imm & 0xFF));
}
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
// cmp rd, rn
emit_al(as, 0x1500000 | (rd << 16) | rn);
}
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn, uint rm) {
asm_arm_cmp_reg_reg(as, rn, rm); // cmp rn, rm
emit(as, asm_arm_op_mov_imm(rd, 1) | ARM_CC_LT); // movlt rd, #1
emit(as, asm_arm_op_mov_imm(rd, 0) | ARM_CC_GE); // movge rd, #0
}
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
// add rd, rn, rm
emit_al(as, asm_arm_op_add_reg(rd, rn, rm));
}
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {
// add rd, sp, #local_num*4
emit_al(as, asm_arm_op_add_imm(rd, REG_SP, local_num << 2));
}
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
assert(label < as->max_num_labels);
int dest = as->label_offsets[label];
int rel = dest - as->code_offset;
rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction
rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted
if (SIGNED_FIT24(rel)) {
emit(as, cond | 0xa000000 | (rel & 0xffffff));
} else {
printf("asm_arm_bcc: branch does not fit in 24 bits\n");
}
}
void asm_arm_b_label(asm_arm_t *as, uint label) {
asm_arm_bcc_label(as, ARM_CC_AL, label);
}
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
// If the table offset fits into the ldr instruction
if(fun_id < (0x1000 / 4)) {
emit_al(as, asm_arm_op_mov_reg(REG_LR, REG_PC)); // mov lr, pc
emit_al(as, 0x597f000 | (fun_id << 2)); // ldr pc, [r7, #fun_id*4]
return;
}
emit_al(as, 0x59f0004 | (reg_temp << 12)); // ldr rd, [pc, #4]
// Set lr after fun_ptr
emit_al(as, asm_arm_op_add_imm(REG_LR, REG_PC, 4)); // add lr, pc, #4
emit_al(as, asm_arm_op_mov_reg(REG_PC, reg_temp)); // mov pc, reg_temp
emit(as, (uint) fun_ptr);
}
#endif // MICROPY_EMIT_ARM

98
py/asmarm.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Fabian Vogt
* 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.
*/
#define ASM_ARM_PASS_COMPUTE (1)
#define ASM_ARM_PASS_EMIT (2)
#define REG_R0 (0)
#define REG_R1 (1)
#define REG_R2 (2)
#define REG_R3 (3)
#define REG_R4 (4)
#define REG_R5 (5)
#define REG_R6 (6)
#define REG_R7 (7)
#define REG_R8 (8)
#define REG_R9 (9)
#define REG_R10 (10)
#define REG_R11 (11)
#define REG_R12 (12)
#define REG_R13 (13)
#define REG_R14 (14)
#define REG_R15 (15)
#define REG_SP (REG_R13)
#define REG_LR (REG_R14)
#define REG_PC (REG_R15)
#define ARM_CC_EQ (0x0 << 28)
#define ARM_CC_NE (0x1 << 28)
#define ARM_CC_CS (0x2 << 28)
#define ARM_CC_CC (0x3 << 28)
#define ARM_CC_MI (0x4 << 28)
#define ARM_CC_PL (0x5 << 28)
#define ARM_CC_VS (0x6 << 28)
#define ARM_CC_VC (0x7 << 28)
#define ARM_CC_HI (0x8 << 28)
#define ARM_CC_LS (0x9 << 28)
#define ARM_CC_GE (0xa << 28)
#define ARM_CC_LT (0xb << 28)
#define ARM_CC_GT (0xc << 28)
#define ARM_CC_LE (0xd << 28)
#define ARM_CC_AL (0xe << 28)
typedef struct _asm_arm_t asm_arm_t;
asm_arm_t *asm_arm_new(uint max_num_labels);
void asm_arm_free(asm_arm_t *as, bool free_code);
void asm_arm_start_pass(asm_arm_t *as, uint pass);
void asm_arm_end_pass(asm_arm_t *as);
uint asm_arm_get_code_size(asm_arm_t *as);
void *asm_arm_get_code(asm_arm_t *as);
void asm_arm_entry(asm_arm_t *as, int num_locals);
void asm_arm_exit(asm_arm_t *as);
void asm_arm_label_assign(asm_arm_t *as, uint label);
void asm_arm_align(asm_arm_t* as, uint align);
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val);
void asm_arm_bkpt(asm_arm_t *as);
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn, uint rm);
void asm_arm_add_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
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);

View File

@@ -67,7 +67,7 @@ asm_thumb_t *asm_thumb_new(uint max_num_labels) {
void asm_thumb_free(asm_thumb_t *as, bool free_code) {
if (free_code) {
m_del(byte, as->code_base, as->code_size);
MP_PLAT_FREE_EXEC(as->code_base, as->code_size);
}
/*
if (as->label != NULL) {
@@ -94,9 +94,10 @@ void asm_thumb_start_pass(asm_thumb_t *as, uint pass) {
void asm_thumb_end_pass(asm_thumb_t *as) {
if (as->pass == ASM_THUMB_PASS_COMPUTE) {
// calculate size of code in bytes
as->code_size = as->code_offset;
as->code_base = m_new(byte, as->code_size);
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);
}
@@ -132,8 +133,7 @@ uint asm_thumb_get_code_size(asm_thumb_t *as) {
}
void *asm_thumb_get_code(asm_thumb_t *as) {
// need to set low bit to indicate that it's thumb code
return (void *)(((mp_uint_t)as->code_base) | 1);
return as->code_base;
}
/*
@@ -496,17 +496,14 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
asm_thumb_op16(as, 0x4780 | (REG_R9 << 3)); // blx reg
*/
if (0) {
// load ptr to function into register using immediate, then branch
// not relocatable
asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
asm_thumb_op16(as, OP_BLX(reg_temp));
} else if (1) {
if (fun_id < 32) {
// load ptr to function from table, indexed by fun_id (must be in range 0-31); 4 bytes
asm_thumb_op16(as, OP_FORMAT_9_10(ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, reg_temp, REG_R7, fun_id));
asm_thumb_op16(as, OP_BLX(reg_temp));
} else {
// use SVC
asm_thumb_op16(as, OP_SVC(fun_id));
// load ptr to function into register using immediate; 6 bytes
asm_thumb_mov_reg_i32(as, reg_temp, (mp_uint_t)fun_ptr);
asm_thumb_op16(as, OP_BLX(reg_temp));
}
}

View File

@@ -45,12 +45,6 @@
#define REG_R15 (15)
#define REG_LR (REG_R14)
#define REG_RET REG_R0
#define REG_ARG_1 REG_R0
#define REG_ARG_2 REG_R1
#define REG_ARG_3 REG_R2
#define REG_ARG_4 REG_R3
#define THUMB_CC_EQ (0x0)
#define THUMB_CC_NE (0x1)
#define THUMB_CC_CS (0x2)

View File

@@ -35,28 +35,21 @@
// wrapper around everything in this file
#if MICROPY_EMIT_X64
#include <sys/types.h>
#include <sys/mman.h>
#include "asmx64.h"
#if defined(__OpenBSD__) || defined(__MACH__)
#define MAP_ANONYMOUS MAP_ANON
#endif
/* all offsets are measured in multiples of 8 bytes */
#define WORD_SIZE (8)
#define OPCODE_NOP (0x90)
#define OPCODE_PUSH_R64 (0x50)
#define OPCODE_PUSH_R64 (0x50) /* +rq */
#define OPCODE_PUSH_I64 (0x68)
#define OPCODE_PUSH_M64 (0xff) /* /6 */
#define OPCODE_POP_R64 (0x58)
#define OPCODE_POP_R64 (0x58) /* +rq */
#define OPCODE_RET (0xc3)
#define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */
#define OPCODE_MOV_I64_TO_R64 (0xb8)
#define OPCODE_MOV_I64_TO_R64 (0xb8) /* +rq */
#define OPCODE_MOV_I32_TO_RM32 (0xc7)
#define OPCODE_MOV_R64_TO_RM64 (0x89)
#define OPCODE_MOV_R64_TO_RM64 (0x89) /* /r */
#define OPCODE_MOV_RM64_TO_R64 (0x8b)
#define OPCODE_LEA_MEM_TO_R64 (0x8d) /* /r */
#define OPCODE_XOR_R64_TO_RM64 (0x31) /* /r */
@@ -85,12 +78,12 @@
#define OPCODE_CALL_RM32 (0xff) /* /2 */
#define OPCODE_LEAVE (0xc9)
#define MODRM_R64(x) ((x) << 3)
#define MODRM_R64(x) (((x) & 0x7) << 3)
#define MODRM_RM_DISP0 (0x00)
#define MODRM_RM_DISP8 (0x40)
#define MODRM_RM_DISP32 (0x80)
#define MODRM_RM_REG (0xc0)
#define MODRM_RM_R64(x) (x)
#define MODRM_RM_R64(x) ((x) & 0x7)
#define REX_PREFIX (0x40)
#define REX_W (0x08) // width
@@ -113,8 +106,8 @@
struct _asm_x64_t {
uint pass;
uint code_offset;
uint code_size;
mp_uint_t code_offset;
mp_uint_t code_size;
byte *code_base;
byte dummy_data[8];
@@ -123,18 +116,6 @@ struct _asm_x64_t {
int num_locals;
};
// for allocating memory, see src/v8/src/platform-linux.cc
void *alloc_mem(uint req_size, uint *alloc_size, bool is_exec) {
req_size = (req_size + 0xfff) & (~0xfff);
int prot = PROT_READ | PROT_WRITE | (is_exec ? PROT_EXEC : 0);
void *ptr = mmap(NULL, req_size, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == MAP_FAILED) {
assert(0);
}
*alloc_size = req_size;
return ptr;
}
asm_x64_t *asm_x64_new(uint max_num_labels) {
asm_x64_t *as;
@@ -147,8 +128,7 @@ asm_x64_t *asm_x64_new(uint max_num_labels) {
void asm_x64_free(asm_x64_t *as, bool free_code) {
if (free_code) {
// need to un-mmap
//m_free(as->code_base);
MP_PLAT_FREE_EXEC(as->code_base, as->code_size);
}
/*
if (as->label != NULL) {
@@ -176,11 +156,10 @@ void asm_x64_start_pass(asm_x64_t *as, uint pass) {
void asm_x64_end_pass(asm_x64_t *as) {
if (as->pass == ASM_X64_PASS_COMPUTE) {
// calculate size of code in bytes
as->code_size = as->code_offset;
//as->code_base = m_new(byte, as->code_size); need to allocale executable memory
uint actual_alloc;
as->code_base = alloc_mem(as->code_size, &actual_alloc, true);
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);
}
@@ -269,6 +248,7 @@ STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {
*/
STATIC void asm_x64_write_r64_disp(asm_x64_t *as, int r64, int disp_r64, int disp_offset) {
assert(disp_r64 < 8);
assert(disp_r64 != REG_RSP);
if (disp_offset == 0 && disp_r64 != REG_RBP) {
@@ -286,21 +266,32 @@ void asm_x64_nop(asm_x64_t *as) {
}
void asm_x64_push_r64(asm_x64_t *as, int src_r64) {
asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64);
if (src_r64 < 8) {
asm_x64_write_byte_1(as, OPCODE_PUSH_R64 | src_r64);
} else {
asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_PUSH_R64 | (src_r64 & 7));
}
}
/*
void asm_x64_push_i32(asm_x64_t *as, int src_i32) {
asm_x64_write_byte_1(as, OPCODE_PUSH_I64);
asm_x64_write_word32(as, src_i32); // will be sign extended to 64 bits
}
*/
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) {
asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64);
if (dest_r64 < 8) {
asm_x64_write_byte_1(as, OPCODE_POP_R64 | dest_r64);
} else {
asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_POP_R64 | (dest_r64 & 7));
}
}
STATIC void asm_x64_ret(asm_x64_t *as) {
@@ -309,45 +300,57 @@ STATIC void asm_x64_ret(asm_x64_t *as) {
void asm_x64_mov_r32_to_r32(asm_x64_t *as, int src_r32, int dest_r32) {
// defaults to 32 bit operation
assert(src_r32 < 8);
assert(dest_r32 < 8);
asm_x64_write_byte_2(as, OPCODE_MOV_R64_TO_RM64, MODRM_R64(src_r32) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));
}
void asm_x64_mov_r64_to_r64(asm_x64_t *as, int src_r64, int dest_r64) {
// use REX prefix for 64 bit operation
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_MOV_R64_TO_RM64, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
asm_x64_write_byte_3(as, REX_PREFIX | REX_W | (src_r64 < 8 ? 0 : REX_R) | (dest_r64 < 8 ? 0 : REX_B), OPCODE_MOV_R64_TO_RM64, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
}
void asm_x64_mov_r64_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
// use REX prefix for 64 bit operation
asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_MOV_R64_TO_RM64);
assert(dest_r64 < 8);
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (src_r64 < 8 ? 0 : REX_R), OPCODE_MOV_R64_TO_RM64);
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
}
void asm_x64_mov_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
// use REX prefix for 64 bit operation
asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_MOV_RM64_TO_R64);
assert(src_r64 < 8);
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_R), OPCODE_MOV_RM64_TO_R64);
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) {
// use REX prefix for 64 bit operation
assert(src_r64 < 8);
assert(dest_r64 < 8);
asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_LEA_MEM_TO_R64);
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);
}
void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) {
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
asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64);
if (dest_r64 < 8) {
asm_x64_write_byte_1(as, OPCODE_MOV_I64_TO_R64 | dest_r64);
} else {
asm_x64_write_byte_2(as, REX_PREFIX | REX_B, OPCODE_MOV_I64_TO_R64 | (dest_r64 & 7));
}
asm_x64_write_word32(as, src_i32);
}
void asm_x64_mov_i64_to_r64(asm_x64_t *as, int64_t src_i64, int dest_r64) {
// cpu defaults to i32 to r64
// to mov i64 to r64 need to use REX prefix
assert(dest_r64 < 8);
asm_x64_write_byte_2(as, REX_PREFIX | REX_W, OPCODE_MOV_I64_TO_R64 | dest_r64);
asm_x64_write_word64(as, src_i64);
}
@@ -371,22 +374,19 @@ void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64
asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);
}
void asm_x64_mov_i32_to_disp(asm_x64_t *as, int src_i32, int dest_r32, int dest_disp)
{
assert(0);
asm_x64_write_byte_1(as, OPCODE_MOV_I32_TO_RM32);
//asm_x64_write_r32_disp(as, 0, dest_r32, dest_disp);
asm_x64_write_word32(as, src_i32);
}
void asm_x64_xor_r64_to_r64(asm_x64_t *as, int src_r64, int dest_r64) {
assert(src_r64 < 8);
assert(dest_r64 < 8);
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_XOR_R64_TO_RM64, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
}
void asm_x64_add_r64_to_r64(asm_x64_t *as, int src_r64, int dest_r64) {
assert(src_r64 < 8);
assert(dest_r64 < 8);
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_ADD_R64_TO_RM64, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
}
/*
void asm_x64_add_i32_to_r32(asm_x64_t *as, int src_i32, int dest_r32)
{
assert(dest_r32 != REG_RSP); // in this case i think src_i32 must be 64 bits
@@ -401,17 +401,23 @@ void asm_x64_add_i32_to_r32(asm_x64_t *as, int src_i32, int dest_r32)
asm_x64_write_word32(as, src_i32);
}
}
*/
/*
void asm_x64_sub_r32_from_r32(asm_x64_t *as, int src_r32, int dest_r32) {
// defaults to 32 bit operation
asm_x64_write_byte_2(as, OPCODE_SUB_R64_FROM_RM64, MODRM_R64(src_r32) | MODRM_RM_REG | MODRM_RM_R64(dest_r32));
}
*/
void asm_x64_sub_r64_from_r64(asm_x64_t *as, int src_r64, int dest_r64) {
// use REX prefix for 64 bit operation
assert(src_r64 < 8);
assert(dest_r64 < 8);
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_R64_FROM_RM64, MODRM_R64(src_r64) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
}
/*
void asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) {
if (SIGNED_FIT8(src_i32)) {
// defaults to 32 bit operation
@@ -423,8 +429,10 @@ void asm_x64_sub_i32_from_r32(asm_x64_t *as, int src_i32, int dest_r32) {
asm_x64_write_word32(as, src_i32);
}
}
*/
void asm_x64_sub_i32_from_r64(asm_x64_t *as, int src_i32, int dest_r64) {
assert(dest_r64 < 8);
if (SIGNED_FIT8(src_i32)) {
// use REX prefix for 64 bit operation
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_SUB_I8_FROM_RM64, MODRM_R64(5) | MODRM_RM_REG | MODRM_RM_R64(dest_r64));
@@ -436,7 +444,7 @@ void asm_x64_sub_i32_from_r64(asm_x64_t *as, int src_i32, int dest_r64) {
}
}
/* shifts not tested */
/*
void asm_x64_shl_r32_by_imm(asm_x64_t *as, int r32, int imm) {
asm_x64_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R64(4) | MODRM_RM_REG | MODRM_RM_R64(r32));
asm_x64_write_byte_1(as, imm);
@@ -451,23 +459,15 @@ void asm_x64_sar_r32_by_imm(asm_x64_t *as, int r32, int imm) {
asm_x64_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(r32));
asm_x64_write_byte_1(as, imm);
}
*/
void asm_x64_cmp_r64_with_r64(asm_x64_t *as, int src_r64_a, int src_r64_b) {
assert(src_r64_a < 8);
assert(src_r64_b < 8);
asm_x64_write_byte_3(as, REX_PREFIX | REX_W, OPCODE_CMP_R64_WITH_RM64, MODRM_R64(src_r64_a) | MODRM_RM_REG | MODRM_RM_R64(src_r64_b));
}
void asm_x64_cmp_r32_with_disp(asm_x64_t *as, int src_r32_a, int src_r32_b, int src_disp_b) {
assert(0);
asm_x64_write_byte_1(as, OPCODE_CMP_R64_WITH_RM64);
//asm_x64_write_r32_disp(as, src_r32_a, src_r32_b, src_disp_b);
}
void asm_x64_cmp_disp_with_r32(asm_x64_t *as, int src_r32_a, int src_disp_a, int src_r32_b) {
assert(0);
asm_x64_write_byte_1(as, OPCODE_CMP_RM32_WITH_R32);
//asm_x64_write_r32_disp(as, src_r32_b, src_r32_a, src_disp_a);
}
/*
void asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) {
if (SIGNED_FIT8(src_i32)) {
asm_x64_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R64(7) | MODRM_RM_REG | MODRM_RM_R64(src_r32));
@@ -477,6 +477,7 @@ void asm_x64_cmp_i32_with_r32(asm_x64_t *as, int src_i32, int src_r32) {
asm_x64_write_word32(as, src_i32);
}
}
*/
void asm_x64_test_r8_with_r8(asm_x64_t *as, int src_r64_a, int src_r64_b) {
// TODO implement for other registers
@@ -486,6 +487,7 @@ 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) {
assert(dest_r8 < 8);
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));
}
@@ -560,30 +562,19 @@ void asm_x64_entry(asm_x64_t *as, int num_locals) {
num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary
asm_x64_sub_i32_from_r64(as, num_locals * WORD_SIZE, REG_RSP);
asm_x64_push_r64(as, REG_RBX);
asm_x64_push_r64(as, REG_R12);
asm_x64_push_r64(as, REG_R13);
as->num_locals = num_locals;
}
void asm_x64_exit(asm_x64_t *as) {
asm_x64_pop_r64(as, REG_R13);
asm_x64_pop_r64(as, REG_R12);
asm_x64_pop_r64(as, REG_RBX);
asm_x64_write_byte_1(as, OPCODE_LEAVE);
asm_x64_ret(as);
}
void asm_x64_push_arg(asm_x64_t *as, int src_arg_num) {
assert(0);
asm_x64_push_disp(as, REG_RBP, 8 + src_arg_num * WORD_SIZE);
}
void asm_x64_mov_arg_to_r32(asm_x64_t *as, int src_arg_num, int dest_r32) {
assert(0);
//asm_x64_mov_disp_to_r32(as, REG_RBP, 8 + src_arg_num * WORD_SIZE, dest_r32);
}
void asm_x64_mov_r32_to_arg(asm_x64_t *as, int src_r32, int dest_arg_num) {
assert(0);
//asm_x64_mov_r32_to_disp(as, src_r32, REG_RBP, 8 + dest_arg_num * WORD_SIZE);
}
// locals:
// - stored on the stack in ascending order
// - numbered 0 through as->num_locals-1
@@ -616,6 +607,7 @@ void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) {
}
}
/*
void asm_x64_push_local(asm_x64_t *as, int local_num) {
asm_x64_push_disp(as, REG_RBP, asm_x64_local_offset_from_ebp(as, local_num));
}
@@ -626,6 +618,7 @@ void asm_x64_push_local_addr(asm_x64_t *as, int local_num, int temp_r64)
asm_x64_add_i32_to_r32(as, asm_x64_local_offset_from_ebp(as, local_num), temp_r64);
asm_x64_push_r64(as, temp_r64);
}
*/
/*
can't use these because code might be relocated when resized
@@ -651,6 +644,7 @@ void asm_x64_call_i1(asm_x64_t *as, void* func, int i1)
*/
void asm_x64_call_ind(asm_x64_t *as, void *ptr, int temp_r64) {
assert(temp_r64 < 8);
#ifdef __LP64__
asm_x64_mov_i64_to_r64_optimised(as, (int64_t)ptr, temp_r64);
#else

View File

@@ -24,6 +24,13 @@
* THE SOFTWARE.
*/
// AMD64 calling convention is:
// - args pass in: RDI, RSI, RDX, RCX, R08, R09
// - return value in RAX
// - stack must be aligned on a 16-byte boundary before all calls
// - RAX, RCX, RDX, RSI, RDI, R08, R09, R10, R11 are caller-save
// - RBX, RBP, R12, R13, R14, R15 are callee-save
#define ASM_X64_PASS_COMPUTE (1)
#define ASM_X64_PASS_EMIT (2)
@@ -35,19 +42,22 @@
#define REG_RBP (5)
#define REG_RSI (6)
#define REG_RDI (7)
#define REG_R08 (8)
#define REG_R09 (9)
#define REG_R10 (10)
#define REG_R11 (11)
#define REG_R12 (12)
#define REG_R13 (13)
#define REG_R14 (14)
#define REG_R15 (15)
// condition codes, used for jcc and setcc (despite their j-name!)
#define JCC_JB (0x2) // below, unsigned
#define JCC_JZ (0x4)
#define JCC_JE (0x4)
#define JCC_JNZ (0x5)
#define JCC_JNE (0x5)
#define JCC_JL (0xc) // less, signed
#define REG_RET REG_RAX
#define REG_ARG_1 REG_RDI
#define REG_ARG_2 REG_RSI
#define REG_ARG_3 REG_RDX
#define ASM_X64_CC_JB (0x2) // below, unsigned
#define ASM_X64_CC_JZ (0x4)
#define ASM_X64_CC_JE (0x4)
#define ASM_X64_CC_JNZ (0x5)
#define ASM_X64_CC_JNE (0x5)
#define ASM_X64_CC_JL (0xc) // less, signed
typedef struct _asm_x64_t asm_x64_t;
@@ -60,29 +70,14 @@ void* asm_x64_get_code(asm_x64_t* as);
void asm_x64_nop(asm_x64_t* as);
void asm_x64_push_r64(asm_x64_t* as, int src_r64);
void asm_x64_push_i32(asm_x64_t* as, int src_i32); // will be sign extended to 64 bits
void asm_x64_push_disp(asm_x64_t* as, int src_r32, int src_offset);
void asm_x64_pop_r64(asm_x64_t* as, int dest_r64);
void asm_x64_mov_r64_to_r64(asm_x64_t* as, int src_r64, int dest_r64);
void asm_x64_mov_r32_to_disp(asm_x64_t* as, int src_r32, int dest_r32, int dest_disp);
void asm_x64_mov_disp_to_r32(asm_x64_t* as, int src_r32, int src_disp, int dest_r32);
void asm_x64_mov_i32_to_r64(asm_x64_t* as, int src_i32, int dest_r64);
void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64);
void asm_x64_mov_i32_to_disp(asm_x64_t* as, int src_i32, int dest_r32, int dest_disp);
void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);
void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64);
void asm_x64_xor_r64_to_r64(asm_x64_t *as, int src_r64, int dest_r64);
void asm_x64_add_r64_to_r64(asm_x64_t* as, int src_r64, int dest_r64);
void asm_x64_add_i32_to_r32(asm_x64_t* as, int src_i32, int dest_r32);
void asm_x64_sub_r32_from_r32(asm_x64_t* as, int src_r32, int dest_r32);
void asm_x64_sub_i32_from_r32(asm_x64_t* as, int src_i32, int dest_r32);
void asm_x64_shl_r32_by_imm(asm_x64_t* as, int r32, int imm);
void asm_x64_shr_r32_by_imm(asm_x64_t* as, int r32, int imm);
void asm_x64_sar_r32_by_imm(asm_x64_t* as, int r32, int imm);
void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b);
void asm_x64_cmp_r32_with_disp(asm_x64_t* as, int src_r32_a, int src_r32_b, int src_disp_b);
void asm_x64_cmp_disp_with_r32(asm_x64_t* as, int src_r32_a, int src_disp_a, int src_r32_b);
void asm_x64_cmp_i32_with_r32(asm_x64_t* as, int src_i32, int src_r32);
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);
@@ -90,12 +85,7 @@ 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_entry(asm_x64_t* as, int num_locals);
void asm_x64_exit(asm_x64_t* as);
void asm_x64_push_arg(asm_x64_t* as, int src_arg_num);
void asm_x64_mov_arg_to_r32(asm_x64_t* as, int src_arg_num, int dest_r32);
void asm_x64_mov_r32_to_arg(asm_x64_t* as, int src_r32, int dest_arg_num);
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_push_local(asm_x64_t* as, int local_num);
void asm_x64_push_local_addr(asm_x64_t* as, int local_num, int temp_r32);
void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32);

528
py/asmx86.c Normal file
View File

@@ -0,0 +1,528 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
// wrapper around everything in this file
#if MICROPY_EMIT_X86
#include "asmx86.h"
/* all offsets are measured in multiples of 4 bytes */
#define WORD_SIZE (4)
#define OPCODE_NOP (0x90)
#define OPCODE_PUSH_R32 (0x50)
//#define OPCODE_PUSH_I32 (0x68)
//#define OPCODE_PUSH_M32 (0xff) /* /6 */
#define OPCODE_POP_R32 (0x58)
#define OPCODE_RET (0xc3)
//#define OPCODE_MOV_I8_TO_R8 (0xb0) /* +rb */
#define OPCODE_MOV_I32_TO_R32 (0xb8)
//#define OPCODE_MOV_I32_TO_RM32 (0xc7)
#define OPCODE_MOV_R32_TO_RM32 (0x89)
#define OPCODE_MOV_RM32_TO_R32 (0x8b)
#define OPCODE_LEA_MEM_TO_R32 (0x8d) /* /r */
#define OPCODE_XOR_R32_TO_RM32 (0x31) /* /r */
#define OPCODE_ADD_R32_TO_RM32 (0x01)
#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
#define OPCODE_ADD_I8_TO_RM32 (0x83) /* /0 */
//#define OPCODE_SUB_R32_FROM_RM32 (0x29)
#define OPCODE_SUB_I32_FROM_RM32 (0x81) /* /5 */
#define OPCODE_SUB_I8_FROM_RM32 (0x83) /* /5 */
//#define OPCODE_SHL_RM32_BY_I8 (0xc1) /* /4 */
//#define OPCODE_SHR_RM32_BY_I8 (0xc1) /* /5 */
//#define OPCODE_SAR_RM32_BY_I8 (0xc1) /* /7 */
//#define OPCODE_CMP_I32_WITH_RM32 (0x81) /* /7 */
//#define OPCODE_CMP_I8_WITH_RM32 (0x83) /* /7 */
#define OPCODE_CMP_R32_WITH_RM32 (0x39)
//#define OPCODE_CMP_RM32_WITH_R32 (0x3b)
#define OPCODE_TEST_R8_WITH_RM8 (0x84) /* /r */
#define OPCODE_JMP_REL8 (0xeb)
#define OPCODE_JMP_REL32 (0xe9)
#define OPCODE_JCC_REL8 (0x70) /* | jcc type */
#define OPCODE_JCC_REL32_A (0x0f)
#define OPCODE_JCC_REL32_B (0x80) /* | jcc type */
#define OPCODE_SETCC_RM8_A (0x0f)
#define OPCODE_SETCC_RM8_B (0x90) /* | jcc type, /0 */
#define OPCODE_CALL_REL32 (0xe8)
#define OPCODE_CALL_RM32 (0xff) /* /2 */
#define OPCODE_LEAVE (0xc9)
#define MODRM_R32(x) ((x) << 3)
#define MODRM_RM_DISP0 (0x00)
#define MODRM_RM_DISP8 (0x40)
#define MODRM_RM_DISP32 (0x80)
#define MODRM_RM_REG (0xc0)
#define MODRM_RM_R32(x) (x)
#define IMM32_L0(x) ((x) & 0xff)
#define IMM32_L1(x) (((x) >> 8) & 0xff)
#define IMM32_L2(x) (((x) >> 16) & 0xff)
#define IMM32_L3(x) (((x) >> 24) & 0xff)
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
struct _asm_x86_t {
uint pass;
mp_uint_t code_offset;
mp_uint_t code_size;
byte *code_base;
byte dummy_data[8];
uint max_num_labels;
int *label_offsets;
int num_locals;
};
asm_x86_t *asm_x86_new(mp_uint_t max_num_labels) {
asm_x86_t *as;
as = m_new0(asm_x86_t, 1);
as->max_num_labels = max_num_labels;
as->label_offsets = m_new(int, max_num_labels);
return as;
}
void asm_x86_free(asm_x86_t *as, bool free_code) {
if (free_code) {
MP_PLAT_FREE_EXEC(as->code_base, as->code_size);
}
m_del_obj(asm_x86_t, as);
}
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(int));
}
}
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) {
assert(0);
}
}
}
// all functions must go through this one to emit bytes
STATIC byte *asm_x86_get_cur_to_write_bytes(asm_x86_t *as, int num_bytes_to_write) {
//printf("emit %d\n", num_bytes_to_write);
if (as->pass < ASM_X86_PASS_EMIT) {
as->code_offset += num_bytes_to_write;
return as->dummy_data;
} else {
assert(as->code_offset + num_bytes_to_write <= as->code_size);
byte *c = as->code_base + as->code_offset;
as->code_offset += num_bytes_to_write;
return c;
}
}
mp_uint_t asm_x86_get_code_size(asm_x86_t *as) {
return as->code_size;
}
void *asm_x86_get_code(asm_x86_t *as) {
return as->code_base;
}
STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) {
byte* c = asm_x86_get_cur_to_write_bytes(as, 1);
c[0] = b1;
}
STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) {
byte* c = asm_x86_get_cur_to_write_bytes(as, 2);
c[0] = b1;
c[1] = b2;
}
STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) {
byte* c = asm_x86_get_cur_to_write_bytes(as, 3);
c[0] = b1;
c[1] = b2;
c[2] = b3;
}
STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
byte* c = asm_x86_get_cur_to_write_bytes(as, 4);
c[0] = IMM32_L0(w32);
c[1] = IMM32_L1(w32);
c[2] = IMM32_L2(w32);
c[3] = IMM32_L3(w32);
}
STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) {
assert(disp_r32 != REG_ESP);
if (disp_offset == 0 && disp_r32 != REG_EBP) {
asm_x86_write_byte_1(as, MODRM_R32(r32) | MODRM_RM_DISP0 | MODRM_RM_R32(disp_r32));
} else if (SIGNED_FIT8(disp_offset)) {
asm_x86_write_byte_2(as, MODRM_R32(r32) | MODRM_RM_DISP8 | MODRM_RM_R32(disp_r32), IMM32_L0(disp_offset));
} else {
asm_x86_write_byte_1(as, MODRM_R32(r32) | MODRM_RM_DISP32 | MODRM_RM_R32(disp_r32));
asm_x86_write_word32(as, disp_offset);
}
}
STATIC void asm_x86_nop(asm_x86_t *as) {
asm_x86_write_byte_1(as, OPCODE_NOP);
}
STATIC void asm_x86_push_r32(asm_x86_t *as, int src_r32) {
asm_x86_write_byte_1(as, OPCODE_PUSH_R32 | src_r32);
}
#if 0
void asm_x86_push_i32(asm_x86_t *as, int src_i32) {
asm_x86_write_byte_1(as, OPCODE_PUSH_I32);
asm_x86_write_word32(as, src_i32);
}
void asm_x86_push_disp(asm_x86_t *as, int src_r32, int src_offset) {
asm_x86_write_byte_1(as, OPCODE_PUSH_M32);
asm_x86_write_r32_disp(as, 6, src_r32, src_offset);
}
#endif
STATIC void asm_x86_pop_r32(asm_x86_t *as, int dest_r32) {
asm_x86_write_byte_1(as, OPCODE_POP_R32 | dest_r32);
}
STATIC void asm_x86_ret(asm_x86_t *as) {
asm_x86_write_byte_1(as, OPCODE_RET);
}
void asm_x86_mov_r32_to_r32(asm_x86_t *as, int src_r32, int dest_r32) {
asm_x86_write_byte_2(as, OPCODE_MOV_R32_TO_RM32, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
}
STATIC void asm_x86_mov_r32_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
asm_x86_write_byte_1(as, OPCODE_MOV_R32_TO_RM32);
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
}
STATIC void asm_x86_mov_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
asm_x86_write_byte_1(as, OPCODE_MOV_RM32_TO_R32);
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
}
STATIC void asm_x86_lea_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
asm_x86_write_byte_1(as, OPCODE_LEA_MEM_TO_R32);
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
}
#if 0
void asm_x86_mov_i8_to_r8(asm_x86_t *as, int src_i8, int dest_r32) {
asm_x86_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r32, src_i8);
}
#endif
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int src_i32, int dest_r32) {
asm_x86_write_byte_1(as, OPCODE_MOV_I32_TO_R32 | dest_r32);
asm_x86_write_word32(as, src_i32);
}
// src_i32 is stored as a full word in the code, and aligned to machine-word boundary
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32) {
// mov instruction uses 1 byte for the instruction, before the i32
while (((as->code_offset + 1) & (WORD_SIZE - 1)) != 0) {
asm_x86_nop(as);
}
asm_x86_mov_i32_to_r32(as, src_i32, dest_r32);
}
void asm_x86_xor_r32_to_r32(asm_x86_t *as, int src_r32, int dest_r32) {
asm_x86_write_byte_2(as, OPCODE_XOR_R32_TO_RM32, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
}
void asm_x86_add_r32_to_r32(asm_x86_t *as, int src_r32, int dest_r32) {
asm_x86_write_byte_2(as, OPCODE_ADD_R32_TO_RM32, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
}
void asm_x86_add_i32_to_r32(asm_x86_t *as, int src_i32, int dest_r32) {
if (SIGNED_FIT8(src_i32)) {
asm_x86_write_byte_2(as, OPCODE_ADD_I8_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
asm_x86_write_byte_1(as, src_i32 & 0xff);
} else {
asm_x86_write_byte_2(as, OPCODE_ADD_I32_TO_RM32, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
asm_x86_write_word32(as, src_i32);
}
}
#if 0
void asm_x86_sub_r32_from_r32(asm_x86_t *as, int src_r32, int dest_r32) {
asm_x86_write_byte_2(as, OPCODE_SUB_R32_FROM_RM32, MODRM_R32(src_r32) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
}
#endif
void asm_x86_sub_i32_from_r32(asm_x86_t *as, int src_i32, int dest_r32) {
if (SIGNED_FIT8(src_i32)) {
// defaults to 32 bit operation
asm_x86_write_byte_2(as, OPCODE_SUB_I8_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
asm_x86_write_byte_1(as, src_i32 & 0xff);
} else {
// defaults to 32 bit operation
asm_x86_write_byte_2(as, OPCODE_SUB_I32_FROM_RM32, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(dest_r32));
asm_x86_write_word32(as, src_i32);
}
}
#if 0
/* shifts not tested */
void asm_x86_shl_r32_by_imm(asm_x86_t *as, int r32, int imm) {
asm_x86_write_byte_2(as, OPCODE_SHL_RM32_BY_I8, MODRM_R32(4) | MODRM_RM_REG | MODRM_RM_R32(r32));
asm_x86_write_byte_1(as, imm);
}
void asm_x86_shr_r32_by_imm(asm_x86_t *as, int r32, int imm) {
asm_x86_write_byte_2(as, OPCODE_SHR_RM32_BY_I8, MODRM_R32(5) | MODRM_RM_REG | MODRM_RM_R32(r32));
asm_x86_write_byte_1(as, imm);
}
void asm_x86_sar_r32_by_imm(asm_x86_t *as, int r32, int imm) {
asm_x86_write_byte_2(as, OPCODE_SAR_RM32_BY_I8, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(r32));
asm_x86_write_byte_1(as, imm);
}
#endif
void asm_x86_cmp_r32_with_r32(asm_x86_t *as, int src_r32_a, int src_r32_b) {
asm_x86_write_byte_2(as, OPCODE_CMP_R32_WITH_RM32, MODRM_R32(src_r32_a) | MODRM_RM_REG | MODRM_RM_R32(src_r32_b));
}
#if 0
void asm_x86_cmp_i32_with_r32(asm_x86_t *as, int src_i32, int src_r32) {
if (SIGNED_FIT8(src_i32)) {
asm_x86_write_byte_2(as, OPCODE_CMP_I8_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32));
asm_x86_write_byte_1(as, src_i32 & 0xff);
} else {
asm_x86_write_byte_2(as, OPCODE_CMP_I32_WITH_RM32, MODRM_R32(7) | MODRM_RM_REG | MODRM_RM_R32(src_r32));
asm_x86_write_word32(as, src_i32);
}
}
#endif
void asm_x86_test_r8_with_r8(asm_x86_t *as, int src_r32_a, int src_r32_b) {
// TODO implement for other registers
assert(src_r32_a == REG_EAX);
assert(src_r32_b == REG_EAX);
asm_x86_write_byte_2(as, OPCODE_TEST_R8_WITH_RM8, MODRM_R32(src_r32_a) | MODRM_RM_REG | MODRM_RM_R32(src_r32_b));
}
void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) {
asm_x86_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r8));
}
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);
as->label_offsets[label] = as->code_offset;
} else {
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
//printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset);
assert(as->label_offsets[label] == as->code_offset);
}
}
STATIC int get_label_dest(asm_x86_t *as, int label) {
assert(label < as->max_num_labels);
return as->label_offsets[label];
}
void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
if (dest >= 0 && 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;
if (SIGNED_FIT8(rel)) {
asm_x86_write_byte_2(as, OPCODE_JMP_REL8, rel & 0xff);
} else {
rel += 2;
goto large_jump;
}
} else {
// is a forwards jump, so need to assume it's large
large_jump:
rel -= 5;
asm_x86_write_byte_1(as, OPCODE_JMP_REL32);
asm_x86_write_word32(as, rel);
}
}
void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {
int dest = get_label_dest(as, label);
int rel = dest - as->code_offset;
if (dest >= 0 && 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;
if (SIGNED_FIT8(rel)) {
asm_x86_write_byte_2(as, OPCODE_JCC_REL8 | jcc_type, rel & 0xff);
} else {
rel += 2;
goto large_jump;
}
} else {
// is a forwards jump, so need to assume it's large
large_jump:
rel -= 6;
asm_x86_write_byte_2(as, OPCODE_JCC_REL32_A, OPCODE_JCC_REL32_B | jcc_type);
asm_x86_write_word32(as, rel);
}
}
void asm_x86_entry(asm_x86_t *as, mp_uint_t num_locals) {
asm_x86_push_r32(as, REG_EBP);
asm_x86_mov_r32_to_r32(as, REG_ESP, REG_EBP);
if (num_locals > 0) {
asm_x86_sub_i32_from_r32(as, num_locals * WORD_SIZE, REG_ESP);
}
asm_x86_push_r32(as, REG_EBX);
asm_x86_push_r32(as, REG_ESI);
asm_x86_push_r32(as, REG_EDI);
// TODO align stack on 16-byte boundary
as->num_locals = num_locals;
}
void asm_x86_exit(asm_x86_t *as) {
asm_x86_pop_r32(as, REG_EDI);
asm_x86_pop_r32(as, REG_ESI);
asm_x86_pop_r32(as, REG_EBX);
asm_x86_write_byte_1(as, OPCODE_LEAVE);
asm_x86_ret(as);
}
#if 0
void asm_x86_push_arg(asm_x86_t *as, int src_arg_num) {
asm_x86_push_disp(as, REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE);
}
#endif
void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32) {
asm_x86_mov_disp_to_r32(as, REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE, dest_r32);
}
#if 0
void asm_x86_mov_r32_to_arg(asm_x86_t *as, int src_r32, int dest_arg_num) {
asm_x86_mov_r32_to_disp(as, src_r32, REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE);
}
#endif
// locals:
// - stored on the stack in ascending order
// - numbered 0 through as->num_locals-1
// - EBP points above the last local
//
// | EPB
// v
// l0 l1 l2 ... l(n-1)
// ^ ^
// | low address | high address in RAM
//
STATIC int asm_x86_local_offset_from_ebp(asm_x86_t *as, int local_num) {
return (-as->num_locals + local_num) * WORD_SIZE;
}
void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32) {
asm_x86_mov_disp_to_r32(as, REG_EBP, asm_x86_local_offset_from_ebp(as, src_local_num), dest_r32);
}
void asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num) {
asm_x86_mov_r32_to_disp(as, src_r32, REG_EBP, asm_x86_local_offset_from_ebp(as, dest_local_num));
}
void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) {
int offset = asm_x86_local_offset_from_ebp(as, local_num);
if (offset == 0) {
asm_x86_mov_r32_to_r32(as, REG_EBP, dest_r32);
} else {
asm_x86_lea_disp_to_r32(as, REG_EBP, offset, dest_r32);
}
}
#if 0
void asm_x86_push_local(asm_x86_t *as, int local_num) {
asm_x86_push_disp(as, REG_EBP, asm_x86_local_offset_from_ebp(as, local_num));
}
void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
{
asm_x86_mov_r32_to_r32(as, REG_EBP, temp_r32);
asm_x86_add_i32_to_r32(as, asm_x86_local_offset_from_ebp(as, local_num), temp_r32);
asm_x86_push_r32(as, temp_r32);
}
#endif
void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) {
// TODO align stack on 16-byte boundary before the call
assert(n_args <= 3);
if (n_args > 2) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_3);
}
if (n_args > 1) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_2);
}
if (n_args > 0) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_1);
}
#ifdef __LP64__
// We wouldn't run x86 code on an x64 machine. This is here to enable
// testing of the x86 emitter only.
asm_x86_mov_i32_to_r32(as, (int32_t)(int64_t)ptr, temp_r32);
#else
// If we get here, sizeof(int) == sizeof(void*).
asm_x86_mov_i32_to_r32(as, (int32_t)ptr, temp_r32);
#endif
asm_x86_write_byte_2(as, OPCODE_CALL_RM32, MODRM_R32(2) | MODRM_RM_REG | MODRM_RM_R32(temp_r32));
// this reduces code size by 2 bytes per call, but doesn't seem to speed it up at all
/*
asm_x86_write_byte_1(as, OPCODE_CALL_REL32);
asm_x86_write_word32(as, ptr - (void*)(as->code_base + as->code_offset + 4));
*/
// the caller must clean up the stack
if (n_args > 0) {
asm_x86_add_i32_to_r32(as, WORD_SIZE * n_args, REG_ESP);
}
}
#endif // MICROPY_EMIT_X86

89
py/asmx86.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* 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.
*/
// x86 cdecl calling convention is:
// - args passed on the stack in reverse order
// - return value in EAX
// - caller cleans up the stack after a call
// - stack must be aligned to 16-byte boundary before all calls
// - EAX, ECX, EDX are caller-save
// - EBX, ESI, EDI, EBP, ESP, EIP are callee-save
#define ASM_X86_PASS_COMPUTE (1)
#define ASM_X86_PASS_EMIT (2)
#define REG_EAX (0)
#define REG_ECX (1)
#define REG_EDX (2)
#define REG_EBX (3)
#define REG_ESP (4)
#define REG_EBP (5)
#define REG_ESI (6)
#define REG_EDI (7)
// x86 passes values on the stack, but the emitter is register based, so we need
// to define registers that can temporarily hold the function arguments. They
// need to be defined here so that asm_x86_call_ind can push them onto the stack
// before the call.
#define ASM_X86_REG_ARG_1 REG_EAX
#define ASM_X86_REG_ARG_2 REG_ECX
#define ASM_X86_REG_ARG_3 REG_EDX
// condition codes, used for jcc and setcc (despite their j-name!)
#define ASM_X86_CC_JB (0x2) // below, unsigned
#define ASM_X86_CC_JZ (0x4)
#define ASM_X86_CC_JE (0x4)
#define ASM_X86_CC_JNZ (0x5)
#define ASM_X86_CC_JNE (0x5)
#define ASM_X86_CC_JL (0xc) // less, signed
typedef struct _asm_x86_t asm_x86_t;
asm_x86_t* asm_x86_new(mp_uint_t max_num_labels);
void asm_x86_free(asm_x86_t* as, bool free_code);
void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass);
void asm_x86_end_pass(asm_x86_t *as);
mp_uint_t asm_x86_get_code_size(asm_x86_t* as);
void* asm_x86_get_code(asm_x86_t* as);
void asm_x86_mov_r32_to_r32(asm_x86_t* as, int src_r32, int dest_r32);
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32);
void asm_x86_xor_r32_to_r32(asm_x86_t *as, int src_r32, int dest_r32);
void asm_x86_add_r32_to_r32(asm_x86_t* as, int src_r32, int dest_r32);
void asm_x86_cmp_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b);
void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b);
void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8);
void asm_x86_label_assign(asm_x86_t* as, mp_uint_t label);
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);
void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals);
void asm_x86_exit(asm_x86_t* as);
void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32);
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);

239
py/bc.c Normal file
View File

@@ -0,0 +1,239 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
* Copyright (c) 2014 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 <stdbool.h>
#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"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
mp_uint_t mp_decode_uint(const byte **ptr) {
mp_uint_t unum = 0;
byte val;
const byte *p = *ptr;
do {
val = *p++;
unum = (unum << 7) | (val & 0x7f);
} while ((val & 0x80) != 0);
*ptr = p;
return unum;
}
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"));
#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));
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"%s() takes %d positional arguments but %d were given",
mp_obj_fun_get_name(f), expected, given));
#endif
}
#if DEBUG_PRINT
STATIC void dump_args(const mp_obj_t *a, int sz) {
DEBUG_printf("%p: ", a);
for (int i = 0; i < sz; i++) {
DEBUG_printf("%p ", a[i]);
}
DEBUG_printf("\n");
}
#else
#define dump_args(...) (void)0
#endif
// code_state should have ->ip filled in (pointing past code info block),
// as well as ->n_state.
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
// usage for the common case of positional only args.
mp_obj_fun_bc_t *self = self_in;
mp_uint_t n_state = code_state->n_state;
const byte *ip = code_state->ip;
code_state->code_info = self->bytecode;
code_state->sp = &code_state->state[0] - 1;
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
// zero out the local stack to begin with
memset(code_state->state, 0, n_state * sizeof(*code_state->state));
const mp_obj_t *kwargs = args + n_args;
// var_pos_kw_args points to the stack where the var-args tuple, and var-kw dict, should go (if they are needed)
mp_obj_t *var_pos_kw_args = &code_state->state[n_state - 1 - self->n_pos_args - self->n_kwonly_args];
// check positional arguments
if (n_args > self->n_pos_args) {
// given more than enough arguments
if (!self->takes_var_args) {
fun_pos_args_mismatch(self, self->n_pos_args, n_args);
}
// put extra arguments in varargs tuple
*var_pos_kw_args-- = mp_obj_new_tuple(n_args - self->n_pos_args, args + self->n_pos_args);
n_args = self->n_pos_args;
} else {
if (self->takes_var_args) {
DEBUG_printf("passing empty tuple as *args\n");
*var_pos_kw_args-- = mp_const_empty_tuple;
}
// 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) {
// 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)];
}
} else {
fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args);
}
}
}
// copy positional args into state
for (mp_uint_t i = 0; i < n_args; i++) {
code_state->state[n_state - 1 - i] = args[i];
}
// check keyword arguments
if (n_kw != 0 || self->has_def_kw_args) {
DEBUG_printf("Initial args: ");
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
mp_obj_t dict = MP_OBJ_NULL;
if (self->takes_kw_args) {
dict = mp_obj_new_dict(n_kw); // TODO: better go conservative with 0?
*var_pos_kw_args = dict;
}
for (mp_uint_t i = 0; i < n_kw; i++) {
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
if (arg_name == self->args[j]) {
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function got multiple values for argument '%s'", qstr_str(arg_name)));
}
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
goto continue2;
}
}
// Didn't find name match with positional args
if (!self->takes_kw_args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments"));
}
mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]);
continue2:;
}
DEBUG_printf("Args with kws flattened: ");
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
// fill in defaults for positional args
mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
for (int i = self->n_def_args; i > 0; i--, d++, s--) {
if (*d == MP_OBJ_NULL) {
*d = *s;
}
}
DEBUG_printf("Args after filling default positional: ");
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
// Check that all mandatory positional args are specified
while (d < &code_state->state[n_state]) {
if (*d++ == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required positional argument #%d", &code_state->state[n_state] - d));
}
}
// Check that all mandatory keyword args are specified
// Fill in default kw args if we have them
for (mp_uint_t i = 0; i < self->n_kwonly_args; i++) {
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
mp_map_elem_t *elem = NULL;
if (self->has_def_kw_args) {
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
}
if (elem != NULL) {
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
}
}
}
} else {
// no keyword arguments given
if (self->n_kwonly_args != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"function missing keyword-only argument"));
}
if (self->takes_kw_args) {
*var_pos_kw_args = mp_obj_new_dict(0);
}
}
// bytecode prelude: initialise closed over variables
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
mp_uint_t local_num = *ip++;
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
}
// now that we skipped over the prelude, set the ip for the VM
code_state->ip = ip;
DEBUG_printf("Calling: n_pos_args=%d, n_kwonly_args=%d\n", self->n_pos_args, self->n_kwonly_args);
dump_args(code_state->state + n_state - self->n_pos_args - self->n_kwonly_args, self->n_pos_args + self->n_kwonly_args);
dump_args(code_state->state, n_state);
}

View File

@@ -49,8 +49,10 @@ typedef struct _mp_code_state {
//mp_exc_stack_t exc_state[0];
} mp_code_state;
mp_uint_t mp_decode_uint(const byte **ptr);
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
void mp_bytecode_print(const void *descr, const byte *code, int len);
void mp_bytecode_print2(const byte *code, int len);

View File

@@ -34,6 +34,7 @@
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "smallint.h"
#include "binary.h"
// Helpers to work with binary-encoded data
@@ -42,7 +43,7 @@
#define alignof(type) offsetof(struct { char c; type t; }, t)
#endif
int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
int size = 0;
int align = 1;
switch (struct_type) {
@@ -58,6 +59,8 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
size = 4; break;
case 'q': case 'Q':
size = 8; break;
case 'P': case 'O': case 'S':
size = sizeof(void*); break;
}
break;
case '@': {
@@ -134,7 +137,10 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
return MP_OBJ_NEW_SMALL_INT(val);
}
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) {
// The long long type is guaranteed to hold at least 64 bits, and size is at
// most 8 (for q and Q), so we will always be able to parse the given data
// and fit it into a long long.
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p) {
int delta;
if (!big_endian) {
delta = -1;
@@ -143,7 +149,7 @@ mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p)
delta = 1;
}
mp_int_t val = 0;
long long val = 0;
if (is_signed && *p & 0x80) {
val = -1;
}
@@ -159,7 +165,7 @@ mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p)
#define is_signed(typecode) (typecode > 'Z')
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
byte *p = *ptr;
uint align;
mp_uint_t align;
int size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {
@@ -173,20 +179,29 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
}
*ptr = p + size;
mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
if (val_type == 'O') {
return (mp_obj_t)val;
return (mp_obj_t)(mp_uint_t)val;
} else if (val_type == 'S') {
return mp_obj_new_str((char*)val, strlen((char*)val), false);
const char *s_val = (const char*)(mp_uint_t)val;
return mp_obj_new_str(s_val, strlen(s_val), false);
} else if (is_signed(val_type)) {
return mp_obj_new_int(val);
if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
return mp_obj_new_int((mp_int_t)val);
} else {
return mp_obj_new_int_from_ll(val);
}
} else {
return mp_obj_new_int_from_uint(val);
if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {
return mp_obj_new_int_from_uint((mp_uint_t)val);
} else {
return mp_obj_new_int_from_ull(val);
}
}
}
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr) {
int in_delta, out_delta;
if (big_endian) {
in_delta = -1;
@@ -205,7 +220,7 @@ void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
byte *p = *ptr;
uint align;
mp_uint_t align;
int size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {

View File

@@ -28,11 +28,11 @@
// (underlyingly they're same).
#define BYTEARRAY_TYPECODE 0
int mp_binary_get_size(char struct_type, char val_type, uint *palign);
int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign);
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val);
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);
mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p);
void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr);
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p);
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr);

View File

@@ -46,7 +46,7 @@
// args[0] is function from class body
// args[1] is class name
// args[2:] are base objects
STATIC mp_obj_t mp_builtin___build_class__(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin___build_class__(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args);
// set the new classes __locals__ object
@@ -86,7 +86,6 @@ STATIC mp_obj_t mp_builtin___build_class__(uint n_args, const mp_obj_t *args) {
return new_class;
}
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__);
STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
@@ -96,7 +95,6 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
@@ -127,7 +125,6 @@ STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
return mp_const_none;
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs);
STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) {
@@ -140,7 +137,6 @@ STATIC mp_obj_t mp_builtin_all(mp_obj_t o_in) {
}
return mp_const_true;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_all_obj, mp_builtin_all);
STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {
@@ -153,14 +149,12 @@ STATIC mp_obj_t mp_builtin_any(mp_obj_t o_in) {
}
return mp_const_false;
}
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);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
@@ -170,7 +164,6 @@ STATIC mp_obj_t mp_builtin_callable(mp_obj_t o_in) {
return mp_const_false;
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
@@ -209,10 +202,9 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
}
#endif
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_dir(mp_uint_t n_args, const mp_obj_t *args) {
// TODO make this function more general and less of a hack
mp_obj_dict_t *dict = NULL;
@@ -238,7 +230,7 @@ STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
mp_obj_t dir = mp_obj_new_list(0, NULL);
if (dict != NULL) {
for (uint i = 0; i < dict->map.alloc; i++) {
for (mp_uint_t i = 0; i < dict->map.alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
mp_obj_list_append(dir, dict->map.table[i].key);
}
@@ -247,100 +239,103 @@ STATIC mp_obj_t mp_builtin_dir(uint n_args, const mp_obj_t *args) {
return dir;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
// TODO handle big int
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
if (i2 == 0) {
#if MICROPY_PY_BUILTINS_FLOAT
zero_division_error:
#endif
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
}
mp_obj_t args[2];
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
return mp_obj_new_tuple(2, args);
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {
mp_float_t f1 = mp_obj_get_float(o1_in);
mp_float_t f2 = mp_obj_get_float(o2_in);
if (f2 == 0.0) {
goto zero_division_error;
}
mp_obj_float_divmod(&f1, &f2);
mp_obj_t tuple[2] = {
mp_obj_new_float(f1),
mp_obj_new_float(f2),
};
return mp_obj_new_tuple(2, tuple);
#endif
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported operand type(s) for divmod(): '%s' and '%s'", mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
}
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod);
STATIC mp_obj_t mp_builtin_hash(mp_obj_t o_in) {
// TODO hash will generally overflow small integer; can we safely truncate it?
return mp_obj_new_int(mp_obj_hash(o_in));
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hash_obj, mp_builtin_hash);
STATIC mp_obj_t mp_builtin_hex(mp_obj_t o_in) {
return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_x), o_in);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_hex_obj, mp_builtin_hex);
STATIC mp_obj_t mp_builtin_iter(mp_obj_t o_in) {
return mp_getiter(o_in);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_iter_obj, mp_builtin_iter);
STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_min_max(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs, mp_uint_t op) {
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_key), MP_MAP_LOOKUP);
mp_obj_t key_fn = key_elem == NULL ? MP_OBJ_NULL : key_elem->value;
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_t max_obj = NULL;
mp_obj_t best_key = MP_OBJ_NULL;
mp_obj_t best_obj = MP_OBJ_NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (max_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, max_obj, item) == mp_const_true)) {
max_obj = item;
mp_obj_t key = key_fn == MP_OBJ_NULL ? item : mp_call_function_1(key_fn, item);
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
best_key = key;
best_obj = item;
}
}
if (max_obj == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "max() arg is an empty sequence"));
if (best_obj == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence"));
}
return max_obj;
return best_obj;
} else {
// given many args
mp_obj_t max_obj = args[0];
for (int i = 1; i < n_args; i++) {
if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i]) == mp_const_true) {
max_obj = args[i];
mp_obj_t best_key = MP_OBJ_NULL;
mp_obj_t best_obj = MP_OBJ_NULL;
for (mp_uint_t i = 0; i < n_args; i++) {
mp_obj_t key = key_fn == MP_OBJ_NULL ? args[i] : mp_call_function_1(key_fn, args[i]);
if (best_obj == MP_OBJ_NULL || (mp_binary_op(op, key, best_key) == mp_const_true)) {
best_key = key;
best_obj = args[i];
}
}
return max_obj;
return best_obj;
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_max_obj, 1, mp_builtin_max);
STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) {
if (n_args == 1) {
// given an iterable
mp_obj_t iterable = mp_getiter(args[0]);
mp_obj_t min_obj = NULL;
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (min_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, item, min_obj) == mp_const_true)) {
min_obj = item;
}
}
if (min_obj == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "min() arg is an empty sequence"));
}
return min_obj;
} else {
// given many args
mp_obj_t min_obj = args[0];
for (int i = 1; i < n_args; i++) {
if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj) == mp_const_true) {
min_obj = args[i];
}
}
return min_obj;
}
STATIC mp_obj_t mp_builtin_max(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_MORE);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_max_obj, 1, mp_builtin_max);
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_min(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_builtin_min_max(n_args, args, kwargs, MP_BINARY_OP_LESS);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_min_obj, 1, mp_builtin_min);
STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
mp_obj_t ret = mp_iternext_allow_raise(o);
@@ -350,17 +345,15 @@ STATIC mp_obj_t mp_builtin_next(mp_obj_t o) {
return ret;
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_next_obj, mp_builtin_next);
STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) {
return mp_binary_op(MP_BINARY_OP_MODULO, MP_OBJ_NEW_QSTR(MP_QSTR__percent__hash_o), o_in);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
uint len;
mp_uint_t len;
const char *str = mp_obj_str_get_data(o_in, &len);
#if MICROPY_PY_BUILTINS_STR_UNICODE
mp_uint_t charlen = unichar_charlen(str, len);
@@ -389,26 +382,24 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
}
#endif
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord);
STATIC mp_obj_t mp_builtin_pow(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_pow(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args && n_args <= 3);
switch (n_args) {
case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]);
default: return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise...
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP);
mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP);
const char *sep_data = " ";
uint sep_len = 1;
mp_uint_t sep_len = 1;
const char *end_data = "\n";
uint end_len = 1;
mp_uint_t end_len = 1;
if (sep_elem != NULL && sep_elem->value != mp_const_none) {
sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len);
}
@@ -431,7 +422,7 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
#if MICROPY_PY_IO
mp_stream_write(stream_obj, sep_data, sep_len);
#else
printf("%.*s", sep_len, sep_data);
printf("%.*s", (int)sep_len, sep_data);
#endif
}
#if MICROPY_PY_IO
@@ -443,11 +434,10 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw
#if MICROPY_PY_IO
mp_stream_write(stream_obj, end_data, end_len);
#else
printf("%.*s", end_len, end_data);
printf("%.*s", (int)end_len, end_data);
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print);
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
@@ -460,7 +450,7 @@ STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);
STATIC mp_obj_t mp_builtin_sum(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_sum(mp_uint_t n_args, const mp_obj_t *args) {
assert(1 <= n_args && n_args <= 2);
mp_obj_t value;
switch (n_args) {
@@ -474,10 +464,9 @@ STATIC mp_obj_t mp_builtin_sum(uint n_args, const mp_obj_t *args) {
}
return value;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum);
STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
STATIC mp_obj_t mp_builtin_sorted(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
assert(n_args >= 1);
if (n_args > 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
@@ -488,29 +477,8 @@ STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *k
return self;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) {
mp_int_t id = (mp_int_t)o_in;
if (!MP_OBJ_IS_OBJ(o_in)) {
return mp_obj_new_int(id);
} else if (id >= 0) {
// Many OSes and CPUs have affinity for putting "user" memories
// into low half of address space, and "system" into upper half.
// We're going to take advantage of that and return small int
// (signed) for such "user" addresses.
return MP_OBJ_NEW_SMALL_INT(id);
} else {
// If that didn't work, well, let's return long int, just as
// a (big) positve value, so it will never clash with the range
// of small int returned in previous case.
return mp_obj_new_int_from_uint((mp_uint_t)id);
}
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_builtin_id);
// See mp_load_attr() if making any changes
STATIC inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) {
mp_obj_t dest[2];
@@ -527,7 +495,7 @@ STATIC inline mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t d
}
}
STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t mp_builtin_getattr(mp_uint_t n_args, const mp_obj_t *args) {
mp_obj_t attr = args[1];
if (MP_OBJ_IS_TYPE(attr, &mp_type_str)) {
attr = mp_obj_str_intern(attr);
@@ -540,7 +508,6 @@ STATIC mp_obj_t mp_builtin_getattr(uint n_args, const mp_obj_t *args) {
}
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(attr), defval);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj, 2, 3, mp_builtin_getattr);
STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
@@ -555,10 +522,10 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
return MP_BOOL(dest[0] != MP_OBJ_NULL);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
// These are defined in terms of MicroPython API functions right away
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id);
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get);
MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get);

View File

@@ -24,9 +24,8 @@
* THE SOFTWARE.
*/
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args);
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args);
mp_obj_t mp_builtin_len(mp_obj_t o);
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args);
mp_obj_t mp_builtin_open(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);
@@ -90,3 +89,4 @@ extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules
extern const mp_obj_module_t mp_module_uctypes;
extern const mp_obj_module_t mp_module_zlibd;
extern const mp_obj_module_t mp_module_ujson;

View File

@@ -41,7 +41,7 @@
#include "builtin.h"
STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse_input_kind) {
uint str_len;
mp_uint_t str_len;
const char *str = mp_obj_str_get_data(o_in, &str_len);
// create the lexer
@@ -63,7 +63,6 @@ STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse
// compile the string
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
mp_parse_node_free(pn);
if (module_fun == mp_const_none) {
// TODO handle compile error correctly

View File

@@ -70,7 +70,7 @@ STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
// extract the list of paths
uint path_num = 0;
mp_uint_t path_num = 0;
mp_obj_t *path_items;
#if MICROPY_PY_SYS
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
@@ -84,7 +84,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
// go through each path looking for a directory or file
for (int i = 0; i < path_num; i++) {
vstr_reset(dest);
uint p_len;
mp_uint_t p_len;
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
if (p_len > 0) {
vstr_add_strn(dest, p, p_len);
@@ -141,7 +141,6 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// compile the imported script
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
mp_parse_node_free(pn);
if (module_fun == mp_const_none) {
// TODO handle compile error correctly
@@ -165,13 +164,13 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
mp_globals_set(old_globals);
}
mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
#if DEBUG_PRINT
printf("__import__:\n");
DEBUG_printf("__import__:\n");
for (int i = 0; i < n_args; i++) {
printf(" ");
DEBUG_printf(" ");
mp_obj_print(args[i], PRINT_REPR);
printf("\n");
DEBUG_printf("\n");
}
#endif
@@ -185,8 +184,8 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
}
}
uint mod_len;
const char *mod_str = (const char*)mp_obj_str_get_data(module_name, &mod_len);
mp_uint_t mod_len;
const char *mod_str = mp_obj_str_get_data(module_name, &mod_len);
if (level != 0) {
// What we want to do here is to take name of current module,
@@ -199,13 +198,13 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
mp_obj_t this_name_q = mp_obj_dict_get(mp_globals_get(), MP_OBJ_NEW_QSTR(MP_QSTR___name__));
assert(this_name_q != MP_OBJ_NULL);
#if DEBUG_PRINT
printf("Current module: ");
DEBUG_printf("Current module: ");
mp_obj_print(this_name_q, PRINT_REPR);
printf("\n");
DEBUG_printf("\n");
#endif
uint this_name_l;
const char *this_name = (const char*)mp_obj_str_get_data(this_name_q, &this_name_l);
mp_uint_t this_name_l;
const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l);
uint dots_seen = 0;
const char *p = this_name + this_name_l - 1;
@@ -353,5 +352,4 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
// Otherwise, we need to return top-level package
return top_module_obj;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__);

View File

@@ -138,6 +138,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ZeroDivisionError), (mp_obj_t)&mp_type_ZeroDivisionError },
@@ -159,8 +160,15 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = {
},
};
STATIC const mp_obj_module_t mp_module_builtins = {
.base = { &mp_type_module },
.name = MP_QSTR_builtins,
.globals = (mp_obj_dict_t*)&mp_builtin_object_dict_obj,
};
STATIC const mp_map_elem_t mp_builtin_module_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___main__), (mp_obj_t)&mp_module___main__ },
{ MP_OBJ_NEW_QSTR(MP_QSTR_builtins), (mp_obj_t)&mp_module_builtins },
{ MP_OBJ_NEW_QSTR(MP_QSTR_micropython), (mp_obj_t)&mp_module_micropython },
#if MICROPY_PY_ARRAY
@@ -199,6 +207,9 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
#if MICROPY_PY_ZLIBD
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
#endif
#if MICROPY_PY_UJSON
{ MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
#endif
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES

View File

@@ -48,8 +48,6 @@
// TODO need to mangle __attr names
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)
typedef enum {
PN_none = 0,
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
@@ -354,7 +352,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
}
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
STATIC uint comp_next_label(compiler_t *comp) {
@@ -715,6 +713,23 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
c_if_cond(comp, pns->nodes[0], !jump_if, label);
return;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_atom_paren) {
// cond is something in parenthesis
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// empty tuple, acts as false for the condition
if (jump_if == false) {
EMIT_ARG(jump, label);
}
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
// non-empty tuple, acts as true for the condition
if (jump_if == true) {
EMIT_ARG(jump, label);
}
} else {
// parenthesis around 1 item, is just that item
c_if_cond(comp, pns->nodes[0], jump_if, label);
}
return;
}
}
@@ -729,9 +744,9 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
}
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
if (assign_kind != ASSIGN_AUG_STORE) {
compile_node(comp, pns->nodes[0]);
}
@@ -792,7 +807,7 @@ cannot_assign:
}
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
// look for star expression
@@ -832,7 +847,7 @@ void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail,
}
// assigns top of stack to pn
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
tail_recursion:
if (MP_PARSE_NODE_IS_NULL(pn)) {
assert(0);
@@ -947,7 +962,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults
// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults
// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)
void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
assert(n_pos_defaults >= 0);
assert(n_kw_defaults >= 0);
@@ -960,12 +975,12 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
for (int j = 0; j < this_scope->id_info_len; j++) {
id_info_t *id2 = &this_scope->id_info[j];
if (id2->kind == ID_INFO_KIND_FREE && id->qstr == id2->qstr) {
if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
#if MICROPY_EMIT_CPYTHON
EMIT_ARG(load_closure, id->qstr, id->local_num);
EMIT_ARG(load_closure, id->qst, id->local_num);
#else
// in Micro Python we load closures using LOAD_FAST
EMIT_ARG(load_fast, id->qstr, id->flags, id->local_num);
EMIT_ARG(load_fast, id->qst, id->flags, id->local_num);
#endif
nfree += 1;
}
@@ -982,7 +997,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d
}
}
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
comp->have_star = true;
/* don't need to distinguish bare from named star
@@ -1254,7 +1269,7 @@ void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(store_id, fname);
}
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_ID(pn)) {
EMIT_ARG(delete_id, MP_PARSE_NODE_LEAF_ARG(pn));
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
@@ -1406,7 +1421,7 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// q_base holds the base of the name
// eg a -> q_base=a
// a.b.c -> q_base=a
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
bool is_as = false;
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
@@ -1466,7 +1481,7 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
}
}
void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
EMIT_ARG(load_const_small_int, 0); // level 0 import
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything
qstr q_base;
@@ -1745,10 +1760,11 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(label_assign, break_label);
}
#if !MICROPY_EMIT_CPYTHON
// TODO preload end and step onto stack if they are not constants
// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
// And, if the loop never runs, the loop variable should never be assigned
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
START_BREAK_CONTINUE_BLOCK
// note that we don't need to pop anything when breaking from an optimise for loop
@@ -1801,6 +1817,7 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
EMIT_ARG(label_assign, break_label);
}
#endif
void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
#if !MICROPY_EMIT_CPYTHON
@@ -1884,7 +1901,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT_ARG(label_assign, end_label);
}
void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_excepts, mp_parse_node_t pn_else) {
// setup code
uint l1 = comp_next_label(comp);
uint success_label = comp_next_label(comp);
@@ -1976,7 +1993,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
EMIT_ARG(label_assign, l2);
}
void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
uint l_finally_block = comp_next_label(comp);
EMIT_ARG(setup_finally, l_finally_block);
@@ -2028,7 +2045,7 @@ void compile_try_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *nodes, mp_parse_node_t body) {
if (n == 0) {
// no more pre-bits, compile the body of the with
compile_node(comp, body);
@@ -2178,7 +2195,7 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
compile_node(comp, pns->nodes[0]);
for (int i = 1; i < num_nodes; i += 1) {
@@ -2562,7 +2579,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind) {
assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 2);
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));
mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1];
@@ -2857,7 +2874,7 @@ STATIC compile_function_t compile_function[] = {
#undef DEF_RULE
};
void compile_node(compiler_t *comp, mp_parse_node_t pn) {
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_NULL(pn)) {
// pass
} else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
@@ -2902,11 +2919,10 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
}
}
void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star, bool allow_annotations) {
STATIC void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_name, pn_kind_t pn_star, pn_kind_t pn_dbl_star) {
// TODO verify that *k and **k are last etc
qstr param_name = MP_QSTR_NULL;
uint param_flag = ID_FLAG_IS_PARAM;
mp_parse_node_t pn_annotation = MP_PARSE_NODE_NULL;
if (MP_PARSE_NODE_IS_ID(pn)) {
param_name = MP_PARSE_NODE_LEAF_ARG(pn);
if (comp->have_star) {
@@ -2921,24 +2937,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_name) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
//int node_index = 1; unused
if (allow_annotations) {
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
// this parameter has an annotation
pn_annotation = pns->nodes[1];
}
//node_index = 2; unused
}
/* this is obsolete now that num dict/default params are calculated in compile_funcdef_param
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[node_index])) {
// this parameter has a default value
if (comp->have_star) {
comp->scope_cur->num_dict_params += 1;
} else {
comp->scope_cur->num_default_params += 1;
}
}
*/
if (comp->have_star) {
// comes after a star, so counts as a keyword-only parameter
comp->scope_cur->num_kwonly_args += 1;
@@ -2957,12 +2955,11 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
// named star
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
} else if (allow_annotations && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
// named star with possible annotation
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARARGS;
pns = (mp_parse_node_struct_t*)pns->nodes[0];
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
pn_annotation = pns->nodes[1];
} else {
// shouldn't happen
assert(0);
@@ -2970,10 +2967,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == pn_dbl_star) {
param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
param_flag = ID_FLAG_IS_PARAM | ID_FLAG_IS_DBL_STAR_PARAM;
if (allow_annotations && !MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
// this parameter has an annotation
pn_annotation = pns->nodes[1];
}
comp->scope_cur->scope_flags |= MP_SCOPE_FLAG_VARKEYWORDS;
} else {
// TODO anything to implement?
@@ -2982,9 +2975,6 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
}
if (param_name != MP_QSTR_NULL) {
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
// TODO this parameter has an annotation
}
bool added;
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added);
if (!added) {
@@ -2997,14 +2987,61 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki
}
STATIC void compile_scope_func_param(compiler_t *comp, mp_parse_node_t pn) {
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star, true);
compile_scope_func_lambda_param(comp, pn, PN_typedargslist_name, PN_typedargslist_star, PN_typedargslist_dbl_star);
}
STATIC void compile_scope_lambda_param(compiler_t *comp, mp_parse_node_t pn) {
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star, false);
compile_scope_func_lambda_param(comp, pn, PN_varargslist_name, PN_varargslist_star, PN_varargslist_dbl_star);
}
void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) {
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
// no annotation
return;
}
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_name) {
// named parameter with possible annotation
// fallthrough
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_star) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_tfpdef)) {
// named star with possible annotation
pns = (mp_parse_node_struct_t*)pns->nodes[0];
// fallthrough
} else {
// no annotation
return;
}
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star) {
// double star with possible annotation
// fallthrough
} else {
// no annotation
return;
}
mp_parse_node_t pn_annotation = pns->nodes[1];
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
#if MICROPY_EMIT_NATIVE
qstr param_name = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
id_info_t *id_info = scope_find(comp->scope_cur, param_name);
assert(id_info != NULL);
if (comp->scope_cur->emit_options == MP_EMIT_OPT_VIPER) {
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
qstr arg_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ARG, id_info->local_num, arg_type);
} else {
compile_syntax_error(comp, pn_annotation, "parameter annotation must be an identifier");
}
}
#endif // MICROPY_EMIT_NATIVE
}
}
STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, mp_parse_node_t pn_inner_expr, int l_top, int for_depth) {
tail_recursion:
if (MP_PARSE_NODE_IS_NULL(pn_iter)) {
// no more nested if/for; compile inner expression
@@ -3128,9 +3165,28 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
if (comp->pass == MP_PASS_SCOPE) {
comp->have_star = false;
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
}
} else {
// compile annotations; only needed on latter compiler passes
// pns->nodes[2] is return/whole function annotation
// argument annotations
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_annotations);
// pns->nodes[2] is return/whole function annotation
mp_parse_node_t pn_annotation = pns->nodes[2];
if (!MP_PARSE_NODE_IS_NULL(pn_annotation)) {
#if MICROPY_EMIT_NATIVE
if (scope->emit_options == MP_EMIT_OPT_VIPER) {
// nodes[2] can be null or a test-expr
if (MP_PARSE_NODE_IS_ID(pn_annotation)) {
qstr ret_type = MP_PARSE_NODE_LEAF_ARG(pn_annotation);
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_RETURN, 0, ret_type);
} else {
compile_syntax_error(comp, pn_annotation, "return annotation must be an identifier");
}
}
#endif // MICROPY_EMIT_NATIVE
}
}
compile_node(comp, pns->nodes[3]); // 3 is function body
// emit return if it wasn't the last opcode
@@ -3390,7 +3446,7 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
scope->num_locals = 0;
for (int i = 0; i < scope->id_info_len; i++) {
id_info_t *id = &scope->id_info[i];
if (scope->kind == SCOPE_CLASS && id->qstr == MP_QSTR___class__) {
if (scope->kind == SCOPE_CLASS && id->qst == MP_QSTR___class__) {
// __class__ is not counted as a local; if it's used then it becomes a ID_INFO_KIND_CELL
continue;
}
@@ -3435,7 +3491,7 @@ STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
for (int j = 0; j < scope->id_info_len; j++) {
id_info_t *id2 = &scope->id_info[j];
if (id2->kind == ID_INFO_KIND_FREE && id->qstr == id2->qstr) {
if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params
#if MICROPY_EMIT_CPYTHON
// in CPython the frees are numbered after the cells
@@ -3582,14 +3638,24 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
emit_native = emit_native_x64_new(max_num_labels);
}
comp->emit_method_table = &emit_native_x64_method_table;
#elif MICROPY_EMIT_X86
if (emit_native == NULL) {
emit_native = emit_native_x86_new(max_num_labels);
}
comp->emit_method_table = &emit_native_x86_method_table;
#elif MICROPY_EMIT_THUMB
if (emit_native == NULL) {
emit_native = emit_native_thumb_new(max_num_labels);
}
comp->emit_method_table = &emit_native_thumb_method_table;
#elif MICROPY_EMIT_ARM
if (emit_native == NULL) {
emit_native = emit_native_arm_new(max_num_labels);
}
comp->emit_method_table = &emit_native_arm_method_table;
#endif
comp->emit = emit_native;
comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
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);
@@ -3628,8 +3694,12 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
if (emit_native != NULL) {
#if MICROPY_EMIT_X64
emit_native_x64_free(emit_native);
#elif MICROPY_EMIT_X86
emit_native_x86_free(emit_native);
#elif MICROPY_EMIT_THUMB
emit_native_thumb_free(emit_native);
#elif MICROPY_EMIT_ARM
emit_native_arm_free(emit_native);
#endif
}
#endif
@@ -3640,6 +3710,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
#endif
#endif // !MICROPY_EMIT_CPYTHON
// free the parse tree
mp_parse_node_free(pn);
// free the scopes
mp_raw_code_t *outer_raw_code = module_scope->raw_code;
for (scope_t *s = module_scope; s;) {

View File

@@ -33,4 +33,5 @@ enum {
MP_EMIT_OPT_ASM_THUMB,
};
// the compiler will free the parse tree (pn) before it returns
mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is_repl);

149
py/emit.h
View File

@@ -46,91 +46,95 @@ typedef enum {
#define MP_EMIT_BREAK_FROM_FOR (0x8000)
#define MP_EMIT_NATIVE_TYPE_ENABLE (0)
#define MP_EMIT_NATIVE_TYPE_RETURN (1)
#define MP_EMIT_NATIVE_TYPE_ARG (2)
typedef struct _emit_t emit_t;
typedef struct _emit_method_table_t {
void (*set_native_types)(emit_t *emit, bool do_native_types);
void (*set_native_type)(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2);
void (*start_pass)(emit_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_t *emit);
bool (*last_emit_was_return_value)(emit_t *emit);
void (*adjust_stack_size)(emit_t *emit, int delta);
void (*set_line_number)(emit_t *emit, int line);
void (*adjust_stack_size)(emit_t *emit, mp_int_t delta);
void (*set_line_number)(emit_t *emit, mp_uint_t line);
void (*load_id)(emit_t *emit, qstr qstr);
void (*store_id)(emit_t *emit, qstr qstr);
void (*delete_id)(emit_t *emit, qstr qstr);
void (*load_id)(emit_t *emit, qstr qst);
void (*store_id)(emit_t *emit, qstr qst);
void (*delete_id)(emit_t *emit, qstr qst);
void (*label_assign)(emit_t *emit, uint l);
void (*import_name)(emit_t *emit, qstr qstr);
void (*import_from)(emit_t *emit, qstr qstr);
void (*label_assign)(emit_t *emit, mp_uint_t l);
void (*import_name)(emit_t *emit, qstr qst);
void (*import_from)(emit_t *emit, qstr qst);
void (*import_star)(emit_t *emit);
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
void (*load_const_small_int)(emit_t *emit, mp_int_t arg);
void (*load_const_int)(emit_t *emit, qstr qstr);
void (*load_const_dec)(emit_t *emit, qstr qstr);
void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes);
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_null)(emit_t *emit);
void (*load_fast)(emit_t *emit, qstr qstr, uint id_flags, int local_num);
void (*load_deref)(emit_t *emit, qstr qstr, int local_num);
void (*load_name)(emit_t *emit, qstr qstr);
void (*load_global)(emit_t *emit, qstr qstr);
void (*load_attr)(emit_t *emit, qstr qstr);
void (*load_method)(emit_t *emit, qstr qstr);
void (*load_fast)(emit_t *emit, qstr qst, mp_uint_t id_flags, 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);
void (*load_attr)(emit_t *emit, qstr qst);
void (*load_method)(emit_t *emit, qstr qst);
void (*load_build_class)(emit_t *emit);
void (*load_subscr)(emit_t *emit);
void (*store_fast)(emit_t *emit, qstr qstr, int local_num);
void (*store_deref)(emit_t *emit, qstr qstr, int local_num);
void (*store_name)(emit_t *emit, qstr qstr);
void (*store_global)(emit_t *emit, qstr qstr);
void (*store_attr)(emit_t *emit, qstr qstr);
void (*store_fast)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*store_deref)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*store_name)(emit_t *emit, qstr qst);
void (*store_global)(emit_t *emit, qstr qst);
void (*store_attr)(emit_t *emit, qstr qst);
void (*store_subscr)(emit_t *emit);
void (*delete_fast)(emit_t *emit, qstr qstr, int local_num);
void (*delete_deref)(emit_t *emit, qstr qstr, int local_num);
void (*delete_name)(emit_t *emit, qstr qstr);
void (*delete_global)(emit_t *emit, qstr qstr);
void (*delete_attr)(emit_t *emit, qstr qstr);
void (*delete_fast)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*delete_deref)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*delete_name)(emit_t *emit, qstr qst);
void (*delete_global)(emit_t *emit, qstr qst);
void (*delete_attr)(emit_t *emit, qstr qst);
void (*delete_subscr)(emit_t *emit);
void (*dup_top)(emit_t *emit);
void (*dup_top_two)(emit_t *emit);
void (*pop_top)(emit_t *emit);
void (*rot_two)(emit_t *emit);
void (*rot_three)(emit_t *emit);
void (*jump)(emit_t *emit, uint label);
void (*pop_jump_if_true)(emit_t *emit, uint label);
void (*pop_jump_if_false)(emit_t *emit, uint label);
void (*jump_if_true_or_pop)(emit_t *emit, uint label);
void (*jump_if_false_or_pop)(emit_t *emit, uint label);
void (*break_loop)(emit_t *emit, uint label, int except_depth);
void (*continue_loop)(emit_t *emit, uint label, int except_depth);
void (*setup_with)(emit_t *emit, uint label);
void (*jump)(emit_t *emit, mp_uint_t label);
void (*pop_jump_if_true)(emit_t *emit, mp_uint_t label);
void (*pop_jump_if_false)(emit_t *emit, mp_uint_t label);
void (*jump_if_true_or_pop)(emit_t *emit, mp_uint_t label);
void (*jump_if_false_or_pop)(emit_t *emit, mp_uint_t label);
void (*break_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
void (*continue_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
void (*setup_with)(emit_t *emit, mp_uint_t label);
void (*with_cleanup)(emit_t *emit);
void (*setup_except)(emit_t *emit, uint label);
void (*setup_finally)(emit_t *emit, uint label);
void (*setup_except)(emit_t *emit, mp_uint_t label);
void (*setup_finally)(emit_t *emit, mp_uint_t label);
void (*end_finally)(emit_t *emit);
void (*get_iter)(emit_t *emit);
void (*for_iter)(emit_t *emit, uint label);
void (*for_iter)(emit_t *emit, mp_uint_t label);
void (*for_iter_end)(emit_t *emit);
void (*pop_block)(emit_t *emit);
void (*pop_except)(emit_t *emit);
void (*unary_op)(emit_t *emit, mp_unary_op_t op);
void (*binary_op)(emit_t *emit, mp_binary_op_t op);
void (*build_tuple)(emit_t *emit, int n_args);
void (*build_list)(emit_t *emit, int n_args);
void (*list_append)(emit_t *emit, int list_stack_index);
void (*build_map)(emit_t *emit, int n_args);
void (*build_tuple)(emit_t *emit, mp_uint_t n_args);
void (*build_list)(emit_t *emit, mp_uint_t n_args);
void (*list_append)(emit_t *emit, mp_uint_t list_stack_index);
void (*build_map)(emit_t *emit, mp_uint_t n_args);
void (*store_map)(emit_t *emit);
void (*map_add)(emit_t *emit, int map_stack_index);
void (*build_set)(emit_t *emit, int n_args);
void (*set_add)(emit_t *emit, int set_stack_index);
void (*build_slice)(emit_t *emit, int n_args);
void (*unpack_sequence)(emit_t *emit, int n_args);
void (*unpack_ex)(emit_t *emit, int n_left, int n_right);
void (*make_function)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults);
void (*make_closure)(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults);
void (*call_function)(emit_t *emit, int n_positional, int n_keyword, uint star_flags);
void (*call_method)(emit_t *emit, int n_positional, int n_keyword, uint star_flags);
void (*map_add)(emit_t *emit, mp_uint_t map_stack_index);
void (*build_set)(emit_t *emit, mp_uint_t n_args);
void (*set_add)(emit_t *emit, mp_uint_t set_stack_index);
void (*build_slice)(emit_t *emit, mp_uint_t n_args);
void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args);
void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right);
void (*make_function)(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults);
void (*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 (*call_function)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);
void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);
void (*return_value)(emit_t *emit);
void (*raise_varargs)(emit_t *emit, int n_args);
void (*raise_varargs)(emit_t *emit, mp_uint_t n_args);
void (*yield_value)(emit_t *emit);
void (*yield_from)(emit_t *emit);
@@ -142,47 +146,52 @@ typedef struct _emit_method_table_t {
#if MICROPY_EMIT_CPYTHON
// these methods are only needed for emitcpy
void (*load_const_verbatim_str)(emit_t *emit, const char *str);
void (*load_closure)(emit_t *emit, qstr qstr, int local_num);
void (*setup_loop)(emit_t *emit, uint label);
void (*load_closure)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*setup_loop)(emit_t *emit, mp_uint_t label);
#endif
} emit_method_table_t;
void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
void emit_common_store_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
void emit_common_delete_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst);
void emit_common_store_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst);
void emit_common_delete_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst);
extern const emit_method_table_t emit_pass1_method_table;
extern const emit_method_table_t emit_cpython_method_table;
extern const emit_method_table_t emit_bc_method_table;
extern const emit_method_table_t emit_native_x64_method_table;
extern const emit_method_table_t emit_native_x86_method_table;
extern const emit_method_table_t emit_native_thumb_method_table;
extern const emit_method_table_t emit_native_arm_method_table;
emit_t *emit_pass1_new(void);
emit_t *emit_cpython_new(uint max_num_labels);
emit_t *emit_bc_new(uint max_num_labels);
emit_t *emit_native_x64_new(uint max_num_labels);
emit_t *emit_native_thumb_new(uint max_num_labels);
emit_t *emit_cpython_new(mp_uint_t max_num_labels);
emit_t *emit_bc_new(mp_uint_t max_num_labels);
emit_t *emit_native_x64_new(mp_uint_t max_num_labels);
emit_t *emit_native_x86_new(mp_uint_t max_num_labels);
emit_t *emit_native_thumb_new(mp_uint_t max_num_labels);
emit_t *emit_native_arm_new(mp_uint_t max_num_labels);
void emit_pass1_free(emit_t *emit);
void emit_bc_free(emit_t *emit);
void emit_native_x64_free(emit_t *emit);
void emit_native_x86_free(emit_t *emit);
void emit_native_thumb_free(emit_t *emit);
void emit_native_arm_free(emit_t *emit);
typedef struct _emit_inline_asm_t emit_inline_asm_t;
typedef struct _emit_inline_asm_method_table_t {
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope);
bool (*end_pass)(emit_inline_asm_t *emit);
int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params);
void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id);
void (*align)(emit_inline_asm_t *emit, uint align);
void (*data)(emit_inline_asm_t *emit, uint bytesize, uint val);
void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args);
mp_uint_t (*count_params)(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params);
void (*label)(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id);
void (*align)(emit_inline_asm_t *emit, mp_uint_t align);
void (*data)(emit_inline_asm_t *emit, mp_uint_t bytesize, mp_uint_t val);
void (*op)(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args);
} emit_inline_asm_method_table_t;
extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table;
emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels);
emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels);
void emit_inline_thumb_free(emit_inline_asm_t *emit);

View File

@@ -49,42 +49,58 @@
struct _emit_t {
pass_kind_t pass : 8;
uint last_emit_was_return_value : 8;
mp_uint_t last_emit_was_return_value : 8;
int stack_size;
scope_t *scope;
uint last_source_line_offset;
uint last_source_line;
mp_uint_t last_source_line_offset;
mp_uint_t last_source_line;
uint max_num_labels;
uint *label_offsets;
mp_uint_t max_num_labels;
mp_uint_t *label_offsets;
uint code_info_offset;
uint code_info_size;
uint bytecode_offset;
uint bytecode_size;
mp_uint_t code_info_offset;
mp_uint_t code_info_size;
mp_uint_t bytecode_offset;
mp_uint_t bytecode_size;
byte *code_base; // stores both byte code and code info
// Accessed as uint, so must be aligned as such
// Accessed as mp_uint_t, so must be aligned as such
byte dummy_data[DUMMY_DATA_SIZE];
};
STATIC void emit_bc_rot_two(emit_t *emit);
STATIC void emit_bc_rot_three(emit_t *emit);
emit_t *emit_bc_new(uint max_num_labels) {
emit_t *emit_bc_new(mp_uint_t max_num_labels) {
emit_t *emit = m_new0(emit_t, 1);
emit->max_num_labels = max_num_labels;
emit->label_offsets = m_new(uint, emit->max_num_labels);
emit->label_offsets = m_new(mp_uint_t, emit->max_num_labels);
return emit;
}
void emit_bc_free(emit_t *emit) {
m_del(uint, emit->label_offsets, emit->max_num_labels);
m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels);
m_del_obj(emit_t, emit);
}
STATIC void emit_write_uint(emit_t* emit, byte*(*allocator)(emit_t*, int), mp_uint_t val) {
// We store each 7 bits in a separate byte, and that's how many bytes needed
byte buf[BYTES_FOR_INT];
byte *p = buf + sizeof(buf);
// We encode in little-ending order, but store in big-endian, to help decoding
do {
*--p = val & 0x7f;
val >>= 7;
} while (val != 0);
byte* c = allocator(emit, buf + sizeof(buf) - p);
while (p != buf + sizeof(buf) - 1) {
*c++ = *p++ | 0x80;
}
*c = *p;
}
// all functions must go through this one to emit code info
STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_write) {
//printf("emit %d\n", num_bytes_to_write);
@@ -103,17 +119,16 @@ STATIC void emit_align_code_info_to_machine_word(emit_t* emit) {
emit->code_info_offset = (emit->code_info_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
}
STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qstr) {
byte* c = emit_get_cur_to_write_code_info(emit, 4);
// TODO variable length encoding for qstr
c[0] = qstr & 0xff;
c[1] = (qstr >> 8) & 0xff;
c[2] = (qstr >> 16) & 0xff;
c[3] = (qstr >> 24) & 0xff;
STATIC void emit_write_code_info_uint(emit_t* emit, mp_uint_t val) {
emit_write_uint(emit, emit_get_cur_to_write_code_info, val);
}
STATIC void emit_write_code_info_qstr(emit_t* emit, qstr qst) {
emit_write_uint(emit, emit_get_cur_to_write_code_info, qst);
}
#if MICROPY_ENABLE_SOURCE_LINE
STATIC void emit_write_code_info_bytes_lines(emit_t* emit, uint bytes_to_skip, uint lines_to_skip) {
STATIC void emit_write_code_info_bytes_lines(emit_t* emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {
assert(bytes_to_skip > 0 || lines_to_skip > 0);
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
while (bytes_to_skip > 0 || lines_to_skip > 0) {
@@ -160,29 +175,17 @@ STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
c[0] = b1;
}
STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, uint b2) {
STATIC void emit_write_bytecode_uint(emit_t* emit, mp_uint_t val) {
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
}
STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) {
assert((b2 & (~0xff)) == 0);
byte* c = emit_get_cur_to_write_bytecode(emit, 2);
c[0] = b1;
c[1] = b2;
}
STATIC void emit_write_bytecode_uint(emit_t* emit, uint num) {
// We store each 7 bits in a separate byte, and that's how many bytes needed
byte buf[BYTES_FOR_INT];
byte *p = buf + sizeof(buf);
// We encode in little-ending order, but store in big-endian, to help decoding
do {
*--p = num & 0x7f;
num >>= 7;
} while (num != 0);
byte* c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
while (p != buf + sizeof(buf) - 1) {
*c++ = *p++ | 0x80;
}
*c = *p;
}
// Similar to emit_write_bytecode_uint(), just some extra handling to encode sign
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
emit_write_bytecode_byte(emit, b1);
@@ -210,9 +213,9 @@ STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
*c = *p;
}
STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, uint num) {
STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, mp_uint_t val) {
emit_write_bytecode_byte(emit, b);
emit_write_bytecode_uint(emit, num);
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
}
// aligns the pointer so it is friendly to GC
@@ -226,20 +229,20 @@ STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
}
/* currently unused
STATIC void emit_write_bytecode_byte_uint_uint(emit_t* emit, byte b, uint num1, uint num2) {
STATIC void emit_write_bytecode_byte_uint_uint(emit_t* emit, byte b, mp_uint_t num1, mp_uint_t num2) {
emit_write_bytecode_byte(emit, b);
emit_write_bytecode_byte_uint(emit, num1);
emit_write_bytecode_byte_uint(emit, num2);
}
*/
STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qstr) {
emit_write_bytecode_byte_uint(emit, b, qstr);
STATIC void emit_write_bytecode_byte_qstr(emit_t* emit, byte b, qstr qst) {
emit_write_bytecode_byte_uint(emit, b, qst);
}
// unsigned labels are relative to ip following this instruction, stored as 16 bits
STATIC void emit_write_bytecode_byte_unsigned_label(emit_t* emit, byte b1, uint label) {
uint bytecode_offset;
STATIC void emit_write_bytecode_byte_unsigned_label(emit_t* emit, byte b1, mp_uint_t label) {
mp_uint_t bytecode_offset;
if (emit->pass < MP_PASS_EMIT) {
bytecode_offset = 0;
} else {
@@ -252,7 +255,7 @@ STATIC void emit_write_bytecode_byte_unsigned_label(emit_t* emit, byte b1, uint
}
// signed labels are relative to ip following this instruction, stored as 16 bits, in excess
STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint label) {
STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, mp_uint_t label) {
int bytecode_offset;
if (emit->pass < MP_PASS_EMIT) {
bytecode_offset = 0;
@@ -265,7 +268,7 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, uint la
c[2] = bytecode_offset >> 8;
}
STATIC void emit_bc_set_native_types(emit_t *emit, bool do_native_types) {
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -276,39 +279,32 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
emit->last_source_line_offset = 0;
emit->last_source_line = 1;
if (pass < MP_PASS_EMIT) {
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(uint));
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));
}
emit->bytecode_offset = 0;
emit->code_info_offset = 0;
// write code info size; use maximum space (4 bytes) to write it; TODO possible optimise this
{
byte* c = emit_get_cur_to_write_code_info(emit, 4);
mp_uint_t s = emit->code_info_size;
c[0] = s & 0xff;
c[1] = (s >> 8) & 0xff;
c[2] = (s >> 16) & 0xff;
c[3] = (s >> 24) & 0xff;
// Write code info size as compressed uint. If we are not in the final pass
// then space for this uint is reserved in emit_bc_end_pass.
if (pass == MP_PASS_EMIT) {
emit_write_code_info_uint(emit, emit->code_info_size);
}
// code info
emit_write_code_info_qstr(emit, scope->source_file);
// write the name and source file of this function
emit_write_code_info_qstr(emit, scope->simple_name);
emit_write_code_info_qstr(emit, scope->source_file);
// bytecode prelude: local state size and exception stack size; 16 bit uints for now
{
byte* c = emit_get_cur_to_write_bytecode(emit, 4);
uint n_state = scope->num_locals + scope->stack_size;
mp_uint_t n_state = scope->num_locals + scope->stack_size;
if (n_state == 0) {
// Need at least 1 entry in the state, in the case an exception is
// propagated through this function, the exception is returned in
// the highest slot in the state (fastn[0], see vm.c).
n_state = 1;
}
c[0] = n_state & 0xff;
c[1] = (n_state >> 8) & 0xff;
c[2] = scope->exc_stack_size & 0xff;
c[3] = (scope->exc_stack_size >> 8) & 0xff;
emit_write_bytecode_uint(emit, n_state);
emit_write_bytecode_uint(emit, scope->exc_stack_size);
}
// bytecode prelude: initialise closed over variables
@@ -336,10 +332,27 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
}
*emit_get_cur_to_write_code_info(emit, 1) = 0; // end of line number info
emit_align_code_info_to_machine_word(emit); // align so that following bytecode is aligned
if (emit->pass == MP_PASS_CODE_SIZE) {
// calculate size of code in bytes
// Need to make sure we have enough room in the code-info block to write
// the size of the code-info block. Since the size is written as a
// compressed uint, we don't know its size until we write it! Thus, we
// take the biggest possible value it could be and write that here.
// Then there will be enough room to write the value, and any leftover
// space will be absorbed in the alignment at the end of the code-info
// block.
mp_uint_t max_code_info_size =
emit->code_info_offset // current code-info size
+ BYTES_FOR_INT // maximum space for compressed uint
+ BYTES_PER_WORD - 1; // maximum space for alignment padding
emit_write_code_info_uint(emit, max_code_info_size);
// Align code-info so that following bytecode is aligned on a machine word.
// We don't need to write anything here, it's just dead space between the
// code-info block and the bytecode block that follows it.
emit_align_code_info_to_machine_word(emit);
// calculate size of total code-info + bytecode, in bytes
emit->code_info_size = emit->code_info_offset;
emit->bytecode_size = emit->bytecode_offset;
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
@@ -347,7 +360,7 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
} else if (emit->pass == MP_PASS_EMIT) {
qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
arg_names[i] = emit->scope->id_info[i].qstr;
arg_names[i] = emit->scope->id_info[i].qst;
}
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
emit->code_info_size + emit->bytecode_size,
@@ -360,11 +373,11 @@ STATIC bool emit_bc_last_emit_was_return_value(emit_t *emit) {
return emit->last_emit_was_return_value;
}
STATIC void emit_bc_adjust_stack_size(emit_t *emit, int delta) {
STATIC void emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
emit->stack_size += delta;
}
STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
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) {
@@ -372,8 +385,8 @@ STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
return;
}
if (source_line > emit->last_source_line) {
uint bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
uint lines_to_skip = source_line - emit->last_source_line;
mp_uint_t bytes_to_skip = emit->bytecode_offset - emit->last_source_line_offset;
mp_uint_t lines_to_skip = source_line - emit->last_source_line;
emit_write_code_info_bytes_lines(emit, bytes_to_skip, lines_to_skip);
emit->last_source_line_offset = emit->bytecode_offset;
emit->last_source_line = source_line;
@@ -381,20 +394,20 @@ STATIC void emit_bc_set_source_line(emit_t *emit, int source_line) {
#endif
}
STATIC void emit_bc_load_id(emit_t *emit, qstr qstr) {
emit_common_load_id(emit, &emit_bc_method_table, emit->scope, qstr);
STATIC void emit_bc_load_id(emit_t *emit, qstr qst) {
emit_common_load_id(emit, &emit_bc_method_table, emit->scope, qst);
}
STATIC void emit_bc_store_id(emit_t *emit, qstr qstr) {
emit_common_store_id(emit, &emit_bc_method_table, emit->scope, qstr);
STATIC void emit_bc_store_id(emit_t *emit, qstr qst) {
emit_common_store_id(emit, &emit_bc_method_table, emit->scope, qst);
}
STATIC void emit_bc_delete_id(emit_t *emit, qstr qstr) {
emit_common_delete_id(emit, &emit_bc_method_table, emit->scope, qstr);
STATIC void emit_bc_delete_id(emit_t *emit, qstr qst) {
emit_common_delete_id(emit, &emit_bc_method_table, emit->scope, qst);
}
STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) {
assert((int)emit->stack_size + stack_size_delta >= 0);
STATIC void emit_bc_pre(emit_t *emit, mp_int_t stack_size_delta) {
assert((mp_int_t)emit->stack_size + stack_size_delta >= 0);
emit->stack_size += stack_size_delta;
if (emit->stack_size > emit->scope->stack_size) {
emit->scope->stack_size = emit->stack_size;
@@ -402,7 +415,7 @@ STATIC void emit_bc_pre(emit_t *emit, int stack_size_delta) {
emit->last_emit_was_return_value = false;
}
STATIC void emit_bc_label_assign(emit_t *emit, uint l) {
STATIC void emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
emit_bc_pre(emit, 0);
assert(l < emit->max_num_labels);
if (emit->pass < MP_PASS_EMIT) {
@@ -416,14 +429,14 @@ STATIC void emit_bc_label_assign(emit_t *emit, uint l) {
}
}
STATIC void emit_bc_import_name(emit_t *emit, qstr qstr) {
STATIC void emit_bc_import_name(emit_t *emit, qstr qst) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst);
}
STATIC void emit_bc_import_from(emit_t *emit, qstr qstr) {
STATIC void emit_bc_import_from(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst);
}
STATIC void emit_bc_import_star(emit_t *emit) {
@@ -447,22 +460,22 @@ STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
}
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qstr) {
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_INT, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_INT, qst);
}
STATIC void emit_bc_load_const_dec(emit_t *emit, qstr qstr) {
STATIC void emit_bc_load_const_dec(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_DEC, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_DEC, qst);
}
STATIC void emit_bc_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
STATIC void emit_bc_load_const_str(emit_t *emit, qstr qst, bool bytes) {
emit_bc_pre(emit, 1);
if (bytes) {
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_BYTES, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_BYTES, qst);
} else {
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_CONST_STRING, qst);
}
}
@@ -471,7 +484,7 @@ STATIC void emit_bc_load_null(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
};
STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, 1);
switch (local_num) {
@@ -482,29 +495,29 @@ STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_
}
}
STATIC void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
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 qstr) {
STATIC void emit_bc_load_name(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst);
}
STATIC void emit_bc_load_global(emit_t *emit, qstr qstr) {
STATIC void emit_bc_load_global(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst);
}
STATIC void emit_bc_load_attr(emit_t *emit, qstr qstr) {
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, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
}
STATIC void emit_bc_load_method(emit_t *emit, qstr qstr) {
STATIC void emit_bc_load_method(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qst);
}
STATIC void emit_bc_load_build_class(emit_t *emit) {
@@ -517,7 +530,7 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR);
}
STATIC void emit_bc_store_fast(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, -1);
switch (local_num) {
@@ -528,24 +541,24 @@ STATIC void emit_bc_store_fast(emit_t *emit, qstr qstr, int local_num) {
}
}
STATIC void emit_bc_store_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
}
STATIC void emit_bc_store_name(emit_t *emit, qstr qstr) {
STATIC void emit_bc_store_name(emit_t *emit, qstr qst) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst);
}
STATIC void emit_bc_store_global(emit_t *emit, qstr qstr) {
STATIC void emit_bc_store_global(emit_t *emit, qstr qst) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst);
}
STATIC void emit_bc_store_attr(emit_t *emit, qstr qstr) {
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, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
}
STATIC void emit_bc_store_subscr(emit_t *emit) {
@@ -553,28 +566,28 @@ STATIC void emit_bc_store_subscr(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR);
}
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
}
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
}
STATIC void emit_bc_delete_name(emit_t *emit, qstr qstr) {
STATIC void emit_bc_delete_name(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst);
}
STATIC void emit_bc_delete_global(emit_t *emit, qstr qstr) {
STATIC void emit_bc_delete_global(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qstr);
emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst);
}
STATIC void emit_bc_delete_attr(emit_t *emit, qstr qstr) {
STATIC void emit_bc_delete_attr(emit_t *emit, qstr qst) {
emit_bc_load_null(emit);
emit_bc_rot_two(emit);
emit_bc_store_attr(emit, qstr);
emit_bc_store_attr(emit, qst);
}
STATIC void emit_bc_delete_subscr(emit_t *emit) {
@@ -608,32 +621,32 @@ STATIC void emit_bc_rot_three(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_ROT_THREE);
}
STATIC void emit_bc_jump(emit_t *emit, uint label) {
STATIC void emit_bc_jump(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label);
}
STATIC void emit_bc_pop_jump_if_true(emit_t *emit, uint label) {
STATIC void emit_bc_pop_jump_if_true(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_TRUE, label);
}
STATIC void emit_bc_pop_jump_if_false(emit_t *emit, uint label) {
STATIC void emit_bc_pop_jump_if_false(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_signed_label(emit, MP_BC_POP_JUMP_IF_FALSE, label);
}
STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, uint label) {
STATIC void emit_bc_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_TRUE_OR_POP, label);
}
STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) {
STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label);
}
STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
STATIC void emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
if (except_depth == 0) {
emit_bc_pre(emit, 0);
if (label & MP_EMIT_BREAK_FROM_FOR) {
@@ -647,7 +660,7 @@ STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) {
}
}
STATIC void emit_bc_setup_with(emit_t *emit, uint label) {
STATIC void emit_bc_setup_with(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, 7);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
}
@@ -657,12 +670,12 @@ STATIC void emit_bc_with_cleanup(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
}
STATIC void emit_bc_setup_except(emit_t *emit, uint label) {
STATIC void emit_bc_setup_except(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
}
STATIC void emit_bc_setup_finally(emit_t *emit, uint label) {
STATIC void emit_bc_setup_finally(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
}
@@ -677,7 +690,7 @@ STATIC void emit_bc_get_iter(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_GET_ITER);
}
STATIC void emit_bc_for_iter(emit_t *emit, uint label) {
STATIC void emit_bc_for_iter(emit_t *emit, mp_uint_t label) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_unsigned_label(emit, MP_BC_FOR_ITER, label);
}
@@ -725,26 +738,22 @@ STATIC void emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
}
}
STATIC void emit_bc_build_tuple(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, 1 - n_args);
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args);
}
STATIC void emit_bc_build_list(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_build_list(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, 1 - n_args);
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args);
}
STATIC void emit_bc_list_append(emit_t *emit, int list_stack_index) {
assert(list_stack_index >= 0);
STATIC void emit_bc_list_append(emit_t *emit, mp_uint_t list_stack_index) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_uint(emit, MP_BC_LIST_APPEND, list_stack_index);
}
STATIC void emit_bc_build_map(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_build_map(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args);
}
@@ -754,43 +763,37 @@ STATIC void emit_bc_store_map(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_STORE_MAP);
}
STATIC void emit_bc_map_add(emit_t *emit, int map_stack_index) {
assert(map_stack_index >= 0);
STATIC void emit_bc_map_add(emit_t *emit, mp_uint_t map_stack_index) {
emit_bc_pre(emit, -2);
emit_write_bytecode_byte_uint(emit, MP_BC_MAP_ADD, map_stack_index);
}
STATIC void emit_bc_build_set(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_build_set(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, 1 - n_args);
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args);
}
STATIC void emit_bc_set_add(emit_t *emit, int set_stack_index) {
assert(set_stack_index >= 0);
STATIC void emit_bc_set_add(emit_t *emit, mp_uint_t set_stack_index) {
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_uint(emit, MP_BC_SET_ADD, set_stack_index);
}
STATIC void emit_bc_build_slice(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, 1 - n_args);
emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args);
}
STATIC void emit_bc_unpack_sequence(emit_t *emit, int n_args) {
assert(n_args >= 0);
STATIC void emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
emit_bc_pre(emit, -1 + n_args);
emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_SEQUENCE, n_args);
}
STATIC void emit_bc_unpack_ex(emit_t *emit, int n_left, int n_right) {
assert(n_left >=0 && n_right >= 0);
STATIC void emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
emit_bc_pre(emit, -1 + n_left + n_right + 1);
emit_write_bytecode_byte_uint(emit, MP_BC_UNPACK_EX, n_left | (n_right << 8));
}
STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_FUNCTION, scope->raw_code);
@@ -800,7 +803,7 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defau
}
}
STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
STATIC void emit_bc_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) {
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
emit_bc_pre(emit, -n_closed_over + 1);
emit_write_bytecode_byte_ptr(emit, MP_BC_MAKE_CLOSURE, scope->raw_code);
@@ -813,7 +816,7 @@ STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_closed_ove
}
}
STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uint bytecode_base, int n_positional, int n_keyword, uint star_flags) {
STATIC void emit_bc_call_function_method_helper(emit_t *emit, mp_int_t stack_adj, mp_uint_t bytecode_base, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
if (star_flags) {
if (!(star_flags & MP_EMIT_STAR_FLAG_SINGLE)) {
// load dummy entry for non-existent pos_seq
@@ -823,19 +826,19 @@ STATIC void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, uin
// load dummy entry for non-existent kw_dict
emit_bc_load_null(emit);
}
emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword - 2);
emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - 2);
emit_write_bytecode_byte_uint(emit, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
} else {
emit_bc_pre(emit, stack_adj - n_positional - 2 * n_keyword);
emit_bc_pre(emit, stack_adj - (mp_int_t)n_positional - 2 * (mp_int_t)n_keyword);
emit_write_bytecode_byte_uint(emit, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints?
}
}
STATIC void emit_bc_call_function(emit_t *emit, int n_positional, int n_keyword, uint star_flags) {
STATIC void emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
emit_bc_call_function_method_helper(emit, 0, MP_BC_CALL_FUNCTION, n_positional, n_keyword, star_flags);
}
STATIC void emit_bc_call_method(emit_t *emit, int n_positional, int n_keyword, uint star_flags) {
STATIC void emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
emit_bc_call_function_method_helper(emit, -1, MP_BC_CALL_METHOD, n_positional, n_keyword, star_flags);
}
@@ -845,7 +848,7 @@ STATIC void emit_bc_return_value(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_RETURN_VALUE);
}
STATIC void emit_bc_raise_varargs(emit_t *emit, int n_args) {
STATIC void emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) {
assert(0 <= n_args && n_args <= 2);
emit_bc_pre(emit, -n_args);
emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args);
@@ -872,7 +875,7 @@ STATIC void emit_bc_end_except_handler(emit_t *emit) {
}
const emit_method_table_t emit_bc_method_table = {
emit_bc_set_native_types,
emit_bc_set_native_type,
emit_bc_start_pass,
emit_bc_end_pass,
emit_bc_last_emit_was_return_value,

View File

@@ -41,61 +41,61 @@
#define EMIT(fun, ...) (emit_method_table->fun(emit, __VA_ARGS__))
void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr) {
void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst) {
// assumes pass is greater than 1, ie that all identifiers are defined in the scope
id_info_t *id = scope_find(scope, qstr);
id_info_t *id = scope_find(scope, qst);
assert(id != NULL); // TODO can this ever fail?
// call the emit backend with the correct code
if (id == NULL || id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
EMIT(load_name, qstr);
EMIT(load_name, qst);
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
EMIT(load_global, qstr);
EMIT(load_global, qst);
} else if (id->kind == ID_INFO_KIND_LOCAL) {
EMIT(load_fast, qstr, id->flags, id->local_num);
EMIT(load_fast, qst, id->flags, id->local_num);
} else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
EMIT(load_deref, qstr, id->local_num);
EMIT(load_deref, qst, id->local_num);
} else {
assert(0);
}
}
void emit_common_store_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr) {
void emit_common_store_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst) {
// assumes pass is greater than 1, ie that all identifiers are defined in the scope
id_info_t *id = scope_find(scope, qstr);
id_info_t *id = scope_find(scope, qst);
assert(id != NULL); // TODO can this ever fail?
// call the emit backend with the correct code
if (id == NULL || id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
EMIT(store_name, qstr);
EMIT(store_name, qst);
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
EMIT(store_global, qstr);
EMIT(store_global, qst);
} else if (id->kind == ID_INFO_KIND_LOCAL) {
EMIT(store_fast, qstr, id->local_num);
EMIT(store_fast, qst, id->local_num);
} else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
EMIT(store_deref, qstr, id->local_num);
EMIT(store_deref, qst, id->local_num);
} else {
assert(0);
}
}
void emit_common_delete_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr) {
void emit_common_delete_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qst) {
// assumes pass is greater than 1, ie that all identifiers are defined in the scope
id_info_t *id = scope_find(scope, qstr);
id_info_t *id = scope_find(scope, qst);
assert(id != NULL); // TODO can this ever fail?
// call the emit backend with the correct code
if (id == NULL || id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
EMIT(delete_name, qstr);
EMIT(delete_name, qst);
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
EMIT(delete_global, qstr);
EMIT(delete_global, qst);
} else if (id->kind == ID_INFO_KIND_LOCAL) {
EMIT(delete_fast, qstr, id->local_num);
EMIT(delete_fast, qst, id->local_num);
} else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
EMIT(delete_deref, qstr, id->local_num);
EMIT(delete_deref, qst, id->local_num);
} else {
assert(0);
}

View File

@@ -52,18 +52,18 @@ struct _emit_t {
scope_t *scope;
uint max_num_labels;
int *label_offsets;
mp_uint_t max_num_labels;
mp_uint_t *label_offsets;
};
emit_t *emit_cpython_new(uint max_num_labels) {
emit_t *emit_cpython_new(mp_uint_t max_num_labels) {
emit_t *emit = m_new(emit_t, 1);
emit->max_num_labels = max_num_labels;
emit->label_offsets = m_new(int, max_num_labels);
emit->label_offsets = m_new(mp_uint_t, max_num_labels);
return emit;
}
STATIC void emit_cpy_set_native_types(emit_t *emit, bool do_native_types) {
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
}
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -73,7 +73,7 @@ STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope)
emit->last_emit_was_return_value = false;
emit->scope = scope;
if (pass < MP_PASS_EMIT) {
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(int));
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));
}
}
@@ -88,23 +88,23 @@ STATIC bool emit_cpy_last_emit_was_return_value(emit_t *emit) {
return emit->last_emit_was_return_value;
}
STATIC void emit_cpy_adjust_stack_size(emit_t *emit, int delta) {
STATIC void emit_cpy_adjust_stack_size(emit_t *emit, mp_int_t delta) {
emit->stack_size += delta;
}
STATIC void emit_cpy_set_source_line(emit_t *emit, int source_line) {
STATIC void emit_cpy_set_source_line(emit_t *emit, mp_uint_t source_line) {
}
STATIC void emit_cpy_load_id(emit_t *emit, qstr qstr) {
emit_common_load_id(emit, &emit_cpython_method_table, emit->scope, qstr);
STATIC void emit_cpy_load_id(emit_t *emit, qstr qst) {
emit_common_load_id(emit, &emit_cpython_method_table, emit->scope, qst);
}
STATIC void emit_cpy_store_id(emit_t *emit, qstr qstr) {
emit_common_store_id(emit, &emit_cpython_method_table, emit->scope, qstr);
STATIC void emit_cpy_store_id(emit_t *emit, qstr qst) {
emit_common_store_id(emit, &emit_cpython_method_table, emit->scope, qst);
}
STATIC void emit_cpy_delete_id(emit_t *emit, qstr qstr) {
emit_common_delete_id(emit, &emit_cpython_method_table, emit->scope, qstr);
STATIC void emit_cpy_delete_id(emit_t *emit, qstr qst) {
emit_common_delete_id(emit, &emit_cpython_method_table, emit->scope, qst);
}
// TODO: module-polymorphic function (read: name clash if made global)
@@ -124,7 +124,7 @@ static void emit_pre(emit_t *emit, int stack_size_delta, int bytecode_size) {
emit->bytecode_offset += bytecode_size;
}
STATIC void emit_cpy_label_assign(emit_t *emit, uint l) {
STATIC void emit_cpy_label_assign(emit_t *emit, mp_uint_t l) {
emit_pre(emit, 0, 0);
assert(l < emit->max_num_labels);
if (emit->pass < MP_PASS_EMIT) {
@@ -138,17 +138,17 @@ STATIC void emit_cpy_label_assign(emit_t *emit, uint l) {
}
}
STATIC void emit_cpy_import_name(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_import_name(emit_t *emit, qstr qst) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("IMPORT_NAME %s\n", qstr_str(qstr));
printf("IMPORT_NAME %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_import_from(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_import_from(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("IMPORT_FROM %s\n", qstr_str(qstr));
printf("IMPORT_FROM %s\n", qstr_str(qst));
}
}
@@ -180,22 +180,22 @@ STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
}
}
STATIC void emit_cpy_load_const_int(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_load_const_int(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST %s\n", qstr_str(qstr));
printf("LOAD_CONST %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_load_const_dec(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_load_const_dec(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST %s\n", qstr_str(qstr));
printf("LOAD_CONST %s\n", qstr_str(qst));
}
}
STATIC void print_quoted_str(qstr qstr, bool bytes) {
const char *str = qstr_str(qstr);
STATIC void print_quoted_str(qstr qst, bool bytes) {
const char *str = qstr_str(qst);
int len = strlen(str);
bool has_single_quote = false;
bool has_double_quote = false;
@@ -231,11 +231,11 @@ STATIC void print_quoted_str(qstr qstr, bool bytes) {
printf("%c", quote_char);
}
STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qstr, bool bytes) {
STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qst, bool bytes) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST ");
print_quoted_str(qstr, bytes);
print_quoted_str(qst, bytes);
printf("\n");
}
}
@@ -245,43 +245,43 @@ STATIC void emit_cpy_load_null(emit_t *emit) {
assert(0);
}
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_FAST %d %s\n", local_num, qstr_str(qstr));
printf("LOAD_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_load_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_DEREF %d %s\n", local_num, qstr_str(qstr));
printf("LOAD_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_load_name(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_load_name(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_NAME %s\n", qstr_str(qstr));
printf("LOAD_NAME %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_load_global(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_load_global(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_GLOBAL %s\n", qstr_str(qstr));
printf("LOAD_GLOBAL %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_load_attr(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_load_attr(emit_t *emit, qstr qst) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_ATTR %s\n", qstr_str(qstr));
printf("LOAD_ATTR %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_load_method(emit_t *emit, qstr qstr) {
emit_cpy_load_attr(emit, qstr);
STATIC void emit_cpy_load_method(emit_t *emit, qstr qst) {
emit_cpy_load_attr(emit, qst);
}
STATIC void emit_cpy_load_build_class(emit_t *emit) {
@@ -298,38 +298,38 @@ STATIC void emit_cpy_load_subscr(emit_t *emit) {
}
}
STATIC void emit_cpy_store_fast(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("STORE_FAST %d %s\n", local_num, qstr_str(qstr));
printf("STORE_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_store_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("STORE_DEREF %d %s\n", local_num, qstr_str(qstr));
printf("STORE_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_store_name(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_store_name(emit_t *emit, qstr qst) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("STORE_NAME %s\n", qstr_str(qstr));
printf("STORE_NAME %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_store_global(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_store_global(emit_t *emit, qstr qst) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("STORE_GLOBAL %s\n", qstr_str(qstr));
printf("STORE_GLOBAL %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_store_attr(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_store_attr(emit_t *emit, qstr qst) {
emit_pre(emit, -2, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("STORE_ATTR %s\n", qstr_str(qstr));
printf("STORE_ATTR %s\n", qstr_str(qst));
}
}
@@ -340,38 +340,38 @@ STATIC void emit_cpy_store_subscr(emit_t *emit) {
}
}
STATIC void emit_cpy_delete_fast(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("DELETE_FAST %d %s\n", local_num, qstr_str(qstr));
printf("DELETE_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_delete_deref(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("DELETE_DEREF %d %s\n", local_num, qstr_str(qstr));
printf("DELETE_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_delete_name(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_delete_name(emit_t *emit, qstr qst) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("DELETE_NAME %s\n", qstr_str(qstr));
printf("DELETE_NAME %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_delete_global(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_delete_global(emit_t *emit, qstr qst) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("DELETE_GLOBAL %s\n", qstr_str(qstr));
printf("DELETE_GLOBAL %s\n", qstr_str(qst));
}
}
STATIC void emit_cpy_delete_attr(emit_t *emit, qstr qstr) {
STATIC void emit_cpy_delete_attr(emit_t *emit, qstr qst) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("DELETE_ATTR %s\n", qstr_str(qstr));
printf("DELETE_ATTR %s\n", qstr_str(qst));
}
}
@@ -417,68 +417,68 @@ STATIC void emit_cpy_rot_three(emit_t *emit) {
}
}
STATIC void emit_cpy_jump(emit_t *emit, uint label) {
STATIC void emit_cpy_jump(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
int dest = emit->label_offsets[label];
if (dest < emit->bytecode_offset) {
printf("JUMP_ABSOLUTE %d\n", emit->label_offsets[label]);
printf("JUMP_ABSOLUTE " UINT_FMT "\n", emit->label_offsets[label]);
} else {
printf("JUMP_FORWARD %d\n", emit->label_offsets[label]);
printf("JUMP_FORWARD " UINT_FMT "\n", emit->label_offsets[label]);
}
}
}
STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, uint label) {
STATIC void emit_cpy_pop_jump_if_true(emit_t *emit, mp_uint_t label) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("POP_JUMP_IF_TRUE %d\n", emit->label_offsets[label]);
printf("POP_JUMP_IF_TRUE " UINT_FMT "\n", emit->label_offsets[label]);
}
}
STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, uint label) {
STATIC void emit_cpy_pop_jump_if_false(emit_t *emit, mp_uint_t label) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("POP_JUMP_IF_FALSE %d\n", emit->label_offsets[label]);
printf("POP_JUMP_IF_FALSE " UINT_FMT "\n", emit->label_offsets[label]);
}
}
STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, uint label) {
STATIC void emit_cpy_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("JUMP_IF_TRUE_OR_POP %d\n", emit->label_offsets[label]);
printf("JUMP_IF_TRUE_OR_POP " UINT_FMT "\n", emit->label_offsets[label]);
}
}
STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) {
STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, mp_uint_t label) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("JUMP_IF_FALSE_OR_POP %d\n", emit->label_offsets[label]);
printf("JUMP_IF_FALSE_OR_POP " UINT_FMT "\n", emit->label_offsets[label]);
}
}
STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) {
STATIC void emit_cpy_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
emit_pre(emit, 0, 1);
if (emit->pass == MP_PASS_EMIT) {
printf("BREAK_LOOP\n");
}
}
STATIC void emit_cpy_continue_loop(emit_t *emit, uint label, int except_depth) {
STATIC void emit_cpy_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
if (except_depth == 0) {
emit_cpy_jump(emit, label);
} else {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("CONTINUE_LOOP %d\n", emit->label_offsets[label]);
printf("CONTINUE_LOOP " UINT_FMT "\n", emit->label_offsets[label]);
}
}
}
STATIC void emit_cpy_setup_with(emit_t *emit, uint label) {
STATIC void emit_cpy_setup_with(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 7, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("SETUP_WITH %d\n", emit->label_offsets[label]);
printf("SETUP_WITH " UINT_FMT "\n", emit->label_offsets[label]);
}
}
@@ -489,17 +489,17 @@ STATIC void emit_cpy_with_cleanup(emit_t *emit) {
}
}
STATIC void emit_cpy_setup_except(emit_t *emit, uint label) {
STATIC void emit_cpy_setup_except(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("SETUP_EXCEPT %d\n", emit->label_offsets[label]);
printf("SETUP_EXCEPT " UINT_FMT "\n", emit->label_offsets[label]);
}
}
STATIC void emit_cpy_setup_finally(emit_t *emit, uint label) {
STATIC void emit_cpy_setup_finally(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("SETUP_FINALLY %d\n", emit->label_offsets[label]);
printf("SETUP_FINALLY " UINT_FMT "\n", emit->label_offsets[label]);
}
}
@@ -517,10 +517,10 @@ STATIC void emit_cpy_get_iter(emit_t *emit) {
}
}
STATIC void emit_cpy_for_iter(emit_t *emit, uint label) {
STATIC void emit_cpy_for_iter(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("FOR_ITER %d\n", emit->label_offsets[label]);
printf("FOR_ITER " UINT_FMT "\n", emit->label_offsets[label]);
}
}
@@ -605,31 +605,31 @@ STATIC void emit_cpy_binary_op(emit_t *emit, mp_binary_op_t op) {
}
}
STATIC void emit_cpy_build_tuple(emit_t *emit, int n_args) {
STATIC void emit_cpy_build_tuple(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, 1 - n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("BUILD_TUPLE %d\n", n_args);
printf("BUILD_TUPLE " UINT_FMT "\n", n_args);
}
}
STATIC void emit_cpy_build_list(emit_t *emit, int n_args) {
STATIC void emit_cpy_build_list(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, 1 - n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("BUILD_LIST %d\n", n_args);
printf("BUILD_LIST " UINT_FMT "\n", n_args);
}
}
STATIC void emit_cpy_list_append(emit_t *emit, int list_index) {
STATIC void emit_cpy_list_append(emit_t *emit, mp_uint_t list_index) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LIST_APPEND %d\n", list_index);
printf("LIST_APPEND " UINT_FMT "\n", list_index);
}
}
STATIC void emit_cpy_build_map(emit_t *emit, int n_args) {
STATIC void emit_cpy_build_map(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("BUILD_MAP %d\n", n_args);
printf("BUILD_MAP " UINT_FMT "\n", n_args);
}
}
@@ -640,57 +640,57 @@ STATIC void emit_cpy_store_map(emit_t *emit) {
}
}
STATIC void emit_cpy_map_add(emit_t *emit, int map_index) {
STATIC void emit_cpy_map_add(emit_t *emit, mp_uint_t map_index) {
emit_pre(emit, -2, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("MAP_ADD %d\n", map_index);
printf("MAP_ADD " UINT_FMT "\n", map_index);
}
}
STATIC void emit_cpy_build_set(emit_t *emit, int n_args) {
STATIC void emit_cpy_build_set(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, 1 - n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("BUILD_SET %d\n", n_args);
printf("BUILD_SET " UINT_FMT "\n", n_args);
}
}
STATIC void emit_cpy_set_add(emit_t *emit, int set_index) {
STATIC void emit_cpy_set_add(emit_t *emit, mp_uint_t set_index) {
emit_pre(emit, -1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("SET_ADD %d\n", set_index);
printf("SET_ADD " UINT_FMT "\n", set_index);
}
}
STATIC void emit_cpy_build_slice(emit_t *emit, int n_args) {
STATIC void emit_cpy_build_slice(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, 1 - n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("BUILD_SLICE %d\n", n_args);
printf("BUILD_SLICE " UINT_FMT "\n", n_args);
}
}
STATIC void emit_cpy_unpack_sequence(emit_t *emit, int n_args) {
STATIC void emit_cpy_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, -1 + n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("UNPACK_SEQUENCE %d\n", n_args);
printf("UNPACK_SEQUENCE " UINT_FMT "\n", n_args);
}
}
STATIC void emit_cpy_unpack_ex(emit_t *emit, int n_left, int n_right) {
STATIC void emit_cpy_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
emit_pre(emit, -1 + n_left + n_right + 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("UNPACK_EX %d\n", n_left | (n_right << 8));
printf("UNPACK_EX " UINT_FMT "\n", n_left | (n_right << 8));
}
}
STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword, uint star_flags) {
int s = 0;
STATIC void emit_cpy_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
mp_int_t s = 0;
if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {
s += 1;
}
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
s += 1;
}
emit_pre(emit, -n_positional - 2 * n_keyword - s, 3);
emit_pre(emit, -(mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - s, 3);
if (emit->pass == MP_PASS_EMIT) {
if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
@@ -705,11 +705,11 @@ STATIC void emit_cpy_call_function(emit_t *emit, int n_positional, int n_keyword
printf("CALL_FUNCTION");
}
}
printf(" %d, %d\n", n_positional, n_keyword);
printf(" " UINT_FMT ", " UINT_FMT "\n", n_positional, n_keyword);
}
}
STATIC void emit_cpy_call_method(emit_t *emit, int n_positional, int n_keyword, uint star_flags) {
STATIC void emit_cpy_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
emit_cpy_call_function(emit, n_positional, n_keyword, star_flags);
}
@@ -721,17 +721,17 @@ STATIC void emit_cpy_return_value(emit_t *emit) {
}
}
STATIC void emit_cpy_raise_varargs(emit_t *emit, int n_args) {
STATIC void emit_cpy_raise_varargs(emit_t *emit, mp_uint_t n_args) {
emit_pre(emit, -n_args, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("RAISE_VARARGS %d\n", n_args);
printf("RAISE_VARARGS " UINT_FMT "\n", n_args);
}
}
STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qstr) {
STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qst) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST code %s\n", qstr_str(qstr));
printf("LOAD_CONST code %s\n", qstr_str(qst));
}
// load qualified name
emit_pre(emit, 1, 3);
@@ -755,24 +755,24 @@ STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qstr) {
}
}
}
printf("%s'\n", qstr_str(qstr));
printf("%s'\n", qstr_str(qst));
}
}
STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
load_cpy_const_code_and_name(emit, scope->simple_name);
emit_pre(emit, -1 - n_pos_defaults - 2 * n_kw_defaults, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("MAKE_FUNCTION %d\n", (n_kw_defaults << 8) | n_pos_defaults);
printf("MAKE_FUNCTION " UINT_FMT "\n", (n_kw_defaults << 8) | n_pos_defaults);
}
}
STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) {
STATIC void emit_cpy_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) {
emit_cpy_build_tuple(emit, n_closed_over);
load_cpy_const_code_and_name(emit, scope->simple_name);
emit_pre(emit, -2 - n_pos_defaults - 2 * n_kw_defaults, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("MAKE_CLOSURE %d\n", (n_kw_defaults << 8) | n_pos_defaults);
printf("MAKE_CLOSURE " UINT_FMT "\n", (n_kw_defaults << 8) | n_pos_defaults);
}
}
@@ -807,22 +807,22 @@ STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
}
}
STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_cpy_load_closure(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr));
printf("LOAD_CLOSURE " UINT_FMT " %s\n", local_num, qstr_str(qst));
}
}
STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) {
STATIC void emit_cpy_setup_loop(emit_t *emit, mp_uint_t label) {
emit_pre(emit, 0, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("SETUP_LOOP %d\n", emit->label_offsets[label]);
printf("SETUP_LOOP " UINT_FMT "\n", emit->label_offsets[label]);
}
}
const emit_method_table_t emit_cpython_method_table = {
emit_cpy_set_native_types,
emit_cpy_set_native_type,
emit_cpy_start_pass,
emit_cpy_end_pass,
emit_cpy_last_emit_was_return_value,

View File

@@ -55,7 +55,7 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
return rc;
}
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags) {
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags) {
rc->kind = MP_CODE_BYTECODE;
rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args;
@@ -65,7 +65,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
rc->u_byte.len = len;
#ifdef DEBUG_PRINT
DEBUG_printf("assign byte code: code=%p len=%u n_pos_args=%d n_kwonly_args=%d flags=%x\n", code, len, n_pos_args, n_kwonly_args, scope_flags);
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
DEBUG_printf(" arg names:");
for (int i = 0; i < n_pos_args + n_kwonly_args; i++) {
DEBUG_printf(" %s", qstr_str(arg_names[i]));
@@ -74,7 +74,7 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
#endif
#if MICROPY_DEBUG_PRINTERS
if (mp_verbose_flag > 0) {
for (int i = 0; i < 128 && i < len; i++) {
for (mp_uint_t i = 0; i < len; i++) {
if (i > 0 && i % 16 == 0) {
printf("\n");
}
@@ -86,31 +86,33 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint
#endif
}
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun, uint len, int n_args) {
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
rc->kind = kind;
rc->scope_flags = 0;
rc->n_pos_args = n_args;
rc->u_native.fun = fun;
rc->u_native.fun_data = fun_data;
rc->u_native.type_sig = type_sig;
#ifdef DEBUG_PRINT
DEBUG_printf("assign native: kind=%d fun=%p len=%u n_args=%d\n", kind, fun, len, n_args);
byte *fun_data = (byte*)(((mp_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
for (int i = 0; i < 128 && i < len; i++) {
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
for (mp_uint_t i = 0; i < fun_len; i++) {
if (i > 0 && i % 16 == 0) {
DEBUG_printf("\n");
}
DEBUG_printf(" %02x", fun_data[i]);
DEBUG_printf(" %02x", ((byte*)fun_data)[i]);
}
DEBUG_printf("\n");
#ifdef WRITE_CODE
FILE *fp_write_code = fopen("out-code", "wb");
fwrite(fun_data, len, 1, fp_write_code);
fwrite(fun_data, fun_len, 1, fp_write_code);
fclose(fp_write_code);
#endif
#endif
}
#endif
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args) {
DEBUG_OP_printf("make_function_from_raw_code %p\n", rc);
@@ -128,13 +130,19 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
break;
#if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:
fun = mp_make_function_n(rc->n_pos_args, rc->u_native.fun);
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
break;
case MP_CODE_NATIVE_VIPER:
case MP_CODE_NATIVE_ASM:
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun);
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->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);
break;
#endif
default:
// raw code was never set (this should not happen)
assert(0);
@@ -149,8 +157,8 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
return fun;
}
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) {
DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args) {
DEBUG_OP_printf("make_closure_from_raw_code %p " UINT_FMT " %p\n", rc, n_closed_over, args);
// make function object
mp_obj_t ffun;
if (n_closed_over & 0x100) {

View File

@@ -37,25 +37,26 @@ typedef enum {
typedef struct _mp_code_t {
mp_raw_code_kind_t kind : 3;
uint scope_flags : 7;
uint n_pos_args : 11;
uint n_kwonly_args : 11;
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
mp_uint_t n_kwonly_args : 11;
qstr *arg_names;
union {
struct {
byte *code;
uint len;
mp_uint_t len;
} u_byte;
struct {
void *fun;
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;
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, uint len, uint n_pos_args, uint n_kwonly_args, qstr *arg_names, uint scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *f, uint len, int n_args);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, qstr *arg_names, mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);

View File

@@ -56,7 +56,7 @@ struct _emit_inline_asm_t {
uint16_t pass;
uint16_t success;
scope_t *scope;
uint max_num_labels;
mp_uint_t max_num_labels;
qstr *label_lookup;
asm_thumb_t *as;
};
@@ -70,7 +70,7 @@ void emit_inline_thumb_error(emit_inline_asm_t *emit, const char *fmt, ...) {
va_end(ap);
}
emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels) {
emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) {
emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
emit->max_num_labels = max_num_labels;
emit->label_lookup = m_new(qstr, max_num_labels);
@@ -99,18 +99,18 @@ STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
if (emit->pass == MP_PASS_EMIT) {
void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
}
return emit->success;
}
STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params) {
STATIC mp_uint_t emit_inline_thumb_count_params(emit_inline_asm_t *emit, mp_uint_t n_params, mp_parse_node_t *pn_params) {
if (n_params > 4) {
emit_inline_thumb_error(emit, "can only have up to 4 parameters to inline thumb assembly\n");
return 0;
}
for (int i = 0; i < n_params; i++) {
for (mp_uint_t i = 0; i < n_params; i++) {
if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
emit_inline_thumb_error(emit, "parameter to inline assembler must be an identifier\n");
return 0;
@@ -124,17 +124,17 @@ STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params,
return n_params;
}
STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qstr label_id) {
STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num, qstr label_id) {
assert(label_num < emit->max_num_labels);
emit->label_lookup[label_num] = label_id;
asm_thumb_label_assign(emit->as, label_num);
}
STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, uint align) {
STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, mp_uint_t align) {
asm_thumb_align(emit->as, align);
}
STATIC void emit_inline_thumb_data(emit_inline_asm_t *emit, uint bytesize, uint val) {
STATIC void emit_inline_thumb_data(emit_inline_asm_t *emit, mp_uint_t bytesize, mp_uint_t val) {
asm_thumb_data(emit->as, bytesize, val);
}
@@ -163,11 +163,11 @@ STATIC const reg_name_t reg_name_table[] = {
{15, "pc\0"},
};
STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, uint max_reg) {
STATIC mp_uint_t get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn, mp_uint_t max_reg) {
if (MP_PARSE_NODE_IS_ID(pn)) {
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn);
const char *reg_str = qstr_str(reg_qstr);
for (uint i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(reg_name_table); i++) {
const reg_name_t *r = &reg_name_table[i];
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
if (r->reg > max_reg) {
@@ -254,7 +254,7 @@ STATIC const cc_name_t cc_name_table[] = {
{THUMB_CC_LE, "le"},
};
STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) {
STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {
// TODO perhaps make two tables:
// one_args =
// "b", LAB, asm_thumb_b_n,
@@ -266,7 +266,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
// "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3
const char *op_str = qstr_str(op);
uint op_len = strlen(op_str);
mp_uint_t op_len = strlen(op_str);
if (n_args == 0) {
if (strcmp(op_str, "nop") == 0) {
@@ -285,8 +285,8 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
// TODO check that this succeeded, ie branch was within range
asm_thumb_b_n(emit->as, label_num);
} else if (op_str[0] == 'b' && op_len == 3) {
uint cc = -1;
for (uint i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
mp_uint_t cc = -1;
for (mp_uint_t i = 0; i < MP_ARRAY_SIZE(cc_name_table); i++) {
if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
cc = cc_name_table[i].cc;
}
@@ -310,14 +310,14 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
} else if (n_args == 2) {
if (MP_PARSE_NODE_IS_ID(pn_args[1])) {
// second arg is a register (or should be)
uint op_code;
mp_uint_t op_code;
if (strcmp(op_str, "mov") == 0) {
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
uint reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
mp_uint_t reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
asm_thumb_mov_reg_reg(emit->as, reg_dest, reg_src);
} else if (strcmp(op_str, "and_") == 0) {
op_code = ASM_THUMB_FORMAT_4_AND;
uint reg_dest, reg_src;
mp_uint_t reg_dest, reg_src;
op_format_4:
reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
@@ -343,10 +343,10 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
}
} else {
// second arg is not a register
uint op_code;
mp_uint_t op_code;
if (strcmp(op_str, "mov") == 0) {
op_code = ASM_THUMB_FORMAT_3_MOV;
uint rlo_dest, i8_src;
mp_uint_t rlo_dest, i8_src;
op_format_3:
rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff);
@@ -361,23 +361,23 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
op_code = ASM_THUMB_FORMAT_3_SUB;
goto op_format_3;
} else if (strcmp(op_str, "movw") == 0) {
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src);
} else if (strcmp(op_str, "movt") == 0) {
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
asm_thumb_movt_reg_i16(emit->as, reg_dest, i_src);
} else if (strcmp(op_str, "movwt") == 0) {
// this is a convenience instruction
// we clear the MSB since it might be set from extracting the small int value
uint reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src & 0xffff);
asm_thumb_movt_reg_i16(emit->as, reg_dest, (i_src >> 16) & 0x7fff);
} else if (strcmp(op_str, "ldr") == 0) {
op_code = ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER;
uint rlo_dest, rlo_base, i5;
mp_uint_t rlo_dest, rlo_base, i5;
mp_parse_node_t pn_base, pn_offset;
op_format_9_10:
rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
@@ -413,10 +413,10 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
}
} else if (n_args == 3) {
uint op_code;
mp_uint_t op_code;
if (strcmp(op_str, "add") == 0) {
op_code = ASM_THUMB_FORMAT_2_ADD;
uint rlo_dest, rlo_src;
mp_uint_t rlo_dest, rlo_src;
op_format_2:
rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);

File diff suppressed because it is too large Load Diff

View File

@@ -67,13 +67,13 @@ STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
return false;
}
STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) {
STATIC void emit_pass1_load_id(emit_t *emit, qstr qst) {
// name adding/lookup
bool added;
id_info_t *id = scope_find_or_add_id(emit->scope, qstr, &added);
id_info_t *id = scope_find_or_add_id(emit->scope, qst, &added);
if (added) {
#if MICROPY_EMIT_CPYTHON
if (qstr == MP_QSTR_super && emit->scope->kind == SCOPE_FUNCTION) {
if (qst == MP_QSTR_super && emit->scope->kind == SCOPE_FUNCTION) {
// special case, super is a global, and also counts as use of __class__
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
id_info_t *id2 = scope_find_local_in_parent(emit->scope, MP_QSTR___class__);
@@ -87,10 +87,10 @@ STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) {
} else
#endif
{
id_info_t *id2 = scope_find_local_in_parent(emit->scope, qstr);
id_info_t *id2 = scope_find_local_in_parent(emit->scope, qst);
if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) {
id->kind = ID_INFO_KIND_FREE;
scope_close_over_in_parents(emit->scope, qstr);
scope_close_over_in_parents(emit->scope, qst);
} else {
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
}
@@ -98,10 +98,10 @@ STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) {
}
}
STATIC id_info_t *get_id_for_modification(scope_t *scope, qstr qstr) {
STATIC id_info_t *get_id_for_modification(scope_t *scope, qstr qst) {
// name adding/lookup
bool added;
id_info_t *id = scope_find_or_add_id(scope, qstr, &added);
id_info_t *id = scope_find_or_add_id(scope, qst, &added);
if (added) {
if (scope->kind == SCOPE_MODULE || scope->kind == SCOPE_CLASS) {
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
@@ -118,12 +118,12 @@ STATIC id_info_t *get_id_for_modification(scope_t *scope, qstr qstr) {
return id;
}
STATIC void emit_pass1_store_id(emit_t *emit, qstr qstr) {
get_id_for_modification(emit->scope, qstr);
STATIC void emit_pass1_store_id(emit_t *emit, qstr qst) {
get_id_for_modification(emit->scope, qst);
}
STATIC void emit_pass1_delete_id(emit_t *emit, qstr qstr) {
id_info_t *id = get_id_for_modification(emit->scope, qstr);
STATIC void emit_pass1_delete_id(emit_t *emit, qstr qst) {
id_info_t *id = get_id_for_modification(emit->scope, qst);
// this flag is unused
//id->flags |= ID_FLAG_IS_DELETED;
(void)id; // suppress compiler warning

73
py/gc.c
View File

@@ -46,6 +46,9 @@
#define DEBUG_printf(...) (void)0
#endif
// make this 1 to dump the heap each time it changes
#define EXTENSIVE_HEAP_PROFILING (0)
#define WORDS_PER_BLOCK (4)
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
#define STACK_SIZE (64) // tunable; minimum is 1
@@ -62,6 +65,7 @@ STATIC int gc_stack_overflow;
STATIC mp_uint_t gc_stack[STACK_SIZE];
STATIC mp_uint_t *gc_sp;
STATIC mp_uint_t gc_lock_depth;
STATIC mp_uint_t gc_last_free_atb_index;
// ATB = allocation table byte
// 0b00 = FREE -- free block
@@ -156,6 +160,9 @@ void gc_init(void *start, void *end) {
gc_pool_start[i] = 0;
}
// set last free ATB index to start of heap
gc_last_free_atb_index = 0;
// unlock the GC
gc_lock_depth = 0;
@@ -304,6 +311,7 @@ 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;
gc_unlock();
}
@@ -374,7 +382,7 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
for (;;) {
// look for a run of n_blocks available blocks
for (i = 0; i < gc_alloc_table_byte_len; i++) {
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
byte a = 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; }
@@ -397,6 +405,15 @@ found:
end_block = i;
start_block = i - n_free + 1;
// Set last free ATB index to block after last block we found, for start of
// next scan. To reduce fragmentation, we only do this if we were looking
// for a single free block, which guarantees that there are no free blocks
// 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;
}
// mark first block as used head
ATB_FREE_TO_HEAD(start_block);
@@ -426,6 +443,10 @@ found:
}
#endif
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ret_ptr;
}
@@ -452,11 +473,20 @@ void gc_free(void *ptr_in) {
if (VERIFY_PTR(ptr)) {
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;
}
// free head and all of its tail blocks
do {
ATB_ANY_TO_FREE(block);
block += 1;
} while (ATB_GET_KIND(block) == AT_TAIL);
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
}
}
}
@@ -568,6 +598,16 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
ATB_ANY_TO_FREE(bl);
}
// 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 EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ptr_in;
}
@@ -582,6 +622,10 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
#if EXTENSIVE_HEAP_PROFILING
gc_dump_alloc_table();
#endif
return ptr_in;
}
@@ -615,9 +659,34 @@ void gc_dump_info() {
}
void gc_dump_alloc_table(void) {
static const mp_uint_t DUMP_BYTES_PER_LINE = 64;
#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);
#endif
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
if (bl % 64 == 0) {
if (bl % DUMP_BYTES_PER_LINE == 0) {
// a new line of blocks
#if EXTENSIVE_HEAP_PROFILING
{
// check if this line contains only free blocks
bool only_free_blocks = true;
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
if (ATB_GET_KIND(bl2) != AT_FREE) {
only_free_blocks = false;
break;
}
}
if (only_free_blocks) {
// line contains only free blocks, so skip printing it
bl += DUMP_BYTES_PER_LINE - 1;
continue;
}
}
#endif
// print header for new line of blocks
printf("\n%04x: ", (uint)bl);
}
int c = ' ';

View File

@@ -58,7 +58,7 @@ def do_work(infiles):
for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
qhash = compute_hash(qstr)
qlen = len(qstr)
print('Q({}, (const byte*)"\\x{:02x}\\x{:02x}\\x{:02x}\\x{:02x}" "{}")'.format(ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, 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))
return True

View File

@@ -38,9 +38,9 @@
#endif
#if MICROPY_MEM_STATS
STATIC int total_bytes_allocated = 0;
STATIC int current_bytes_allocated = 0;
STATIC int peak_bytes_allocated = 0;
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; }
#endif
@@ -62,7 +62,7 @@ STATIC int peak_bytes_allocated = 0;
#define realloc gc_realloc
#endif // MICROPY_ENABLE_GC
void *m_malloc(int num_bytes) {
void *m_malloc(size_t num_bytes) {
if (num_bytes == 0) {
return NULL;
}
@@ -79,7 +79,7 @@ void *m_malloc(int num_bytes) {
return ptr;
}
void *m_malloc_maybe(int num_bytes) {
void *m_malloc_maybe(size_t num_bytes) {
void *ptr = malloc(num_bytes);
if (ptr == NULL) {
return NULL;
@@ -94,7 +94,7 @@ void *m_malloc_maybe(int num_bytes) {
}
#if MICROPY_ENABLE_FINALISER
void *m_malloc_with_finaliser(int num_bytes) {
void *m_malloc_with_finaliser(size_t num_bytes) {
if (num_bytes == 0) {
return NULL;
}
@@ -112,7 +112,7 @@ void *m_malloc_with_finaliser(int num_bytes) {
}
#endif
void *m_malloc0(int num_bytes) {
void *m_malloc0(size_t num_bytes) {
void *ptr = m_malloc(num_bytes);
if (ptr != NULL) {
memset(ptr, 0, num_bytes);
@@ -120,7 +120,7 @@ void *m_malloc0(int num_bytes) {
return ptr;
}
void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
if (new_num_bytes == 0) {
free(ptr);
return NULL;
@@ -135,7 +135,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
// shrunk to 1K and then grown to 2K again. It's still 2K
// allocated total. If we process only positive increments,
// we'll count 3K.
int diff = new_num_bytes - old_num_bytes;
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
UPDATE_PEAK();
@@ -144,7 +144,7 @@ void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes) {
return new_ptr;
}
void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes) {
void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
void *new_ptr = realloc(ptr, new_num_bytes);
if (new_ptr == NULL) {
return NULL;
@@ -155,7 +155,7 @@ void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes) {
// shrunk to 1K and then grown to 2K again. It's still 2K
// allocated total. If we process only positive increments,
// we'll count 3K.
int diff = new_num_bytes - old_num_bytes;
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
UPDATE_PEAK();
@@ -164,7 +164,7 @@ void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes) {
return new_ptr;
}
void m_free(void *ptr, int num_bytes) {
void m_free(void *ptr, size_t num_bytes) {
if (ptr != NULL) {
free(ptr);
}
@@ -174,26 +174,16 @@ void m_free(void *ptr, int num_bytes) {
DEBUG_printf("free %p, %d\n", ptr, num_bytes);
}
int m_get_total_bytes_allocated(void) {
#if MICROPY_MEM_STATS
size_t m_get_total_bytes_allocated(void) {
return total_bytes_allocated;
#else
return -1;
#endif
}
int m_get_current_bytes_allocated(void) {
#if MICROPY_MEM_STATS
size_t m_get_current_bytes_allocated(void) {
return current_bytes_allocated;
#else
return -1;
#endif
}
int m_get_peak_bytes_allocated(void) {
#if MICROPY_MEM_STATS
size_t m_get_peak_bytes_allocated(void) {
return peak_bytes_allocated;
#else
return -1;
#endif
}
#endif

View File

@@ -24,6 +24,7 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
@@ -35,10 +36,10 @@
// approximatelly doubling primes; made with Mathematica command: Table[Prime[Floor[(1.7)^n]], {n, 3, 24}]
// prefixed with zero for the empty case.
STATIC int 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 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 int get_doubling_prime_greater_or_equal_to(int x) {
for (int i = 0; i < sizeof(doubling_primes) / sizeof(int); i++) {
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++) {
if (doubling_primes[i] >= x) {
return doubling_primes[i];
}
@@ -51,7 +52,7 @@ STATIC int get_doubling_prime_greater_or_equal_to(int x) {
/******************************************************************************/
/* map */
void mp_map_init(mp_map_t *map, int n) {
void mp_map_init(mp_map_t *map, mp_uint_t n) {
if (n == 0) {
map->alloc = 0;
map->table = NULL;
@@ -64,7 +65,7 @@ void mp_map_init(mp_map_t *map, int n) {
map->table_is_fixed_array = 0;
}
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table) {
void mp_map_init_fixed_table(mp_map_t *map, mp_uint_t n, const mp_obj_t *table) {
map->alloc = n;
map->used = n;
map->all_keys_are_qstrs = 1;
@@ -72,7 +73,7 @@ void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table) {
map->table = (mp_map_elem_t*)table;
}
mp_map_t *mp_map_new(int n) {
mp_map_t *mp_map_new(mp_uint_t n) {
mp_map_t *map = m_new(mp_map_t, 1);
mp_map_init(map, n);
return map;
@@ -103,13 +104,13 @@ void mp_map_clear(mp_map_t *map) {
}
STATIC void mp_map_rehash(mp_map_t *map) {
int old_alloc = map->alloc;
mp_uint_t old_alloc = map->alloc;
mp_map_elem_t *old_table = map->table;
map->alloc = get_doubling_prime_greater_or_equal_to(map->alloc + 1);
map->used = 0;
map->all_keys_are_qstrs = 1;
map->table = m_new0(mp_map_elem_t, map->alloc);
for (int i = 0; i < old_alloc; i++) {
for (mp_uint_t i = 0; i < old_alloc; i++) {
if (old_table[i].key != MP_OBJ_NULL && old_table[i].key != MP_OBJ_SENTINEL) {
mp_map_lookup(map, old_table[i].key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = old_table[i].value;
}
@@ -168,8 +169,8 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
}
mp_uint_t hash = mp_obj_hash(index);
uint pos = hash % map->alloc;
uint start_pos = pos;
mp_uint_t pos = hash % map->alloc;
mp_uint_t start_pos = pos;
mp_map_elem_t *avail_slot = NULL;
for (;;) {
mp_map_elem_t *slot = &map->table[pos];
@@ -242,19 +243,19 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
/******************************************************************************/
/* set */
void mp_set_init(mp_set_t *set, int n) {
void mp_set_init(mp_set_t *set, mp_uint_t n) {
set->alloc = n;
set->used = 0;
set->table = m_new0(mp_obj_t, set->alloc);
}
STATIC void mp_set_rehash(mp_set_t *set) {
int old_alloc = set->alloc;
mp_uint_t old_alloc = set->alloc;
mp_obj_t *old_table = set->table;
set->alloc = get_doubling_prime_greater_or_equal_to(set->alloc + 1);
set->used = 0;
set->table = m_new0(mp_obj_t, set->alloc);
for (int i = 0; i < old_alloc; i++) {
for (mp_uint_t i = 0; i < old_alloc; i++) {
if (old_table[i] != MP_OBJ_NULL && old_table[i] != MP_OBJ_SENTINEL) {
mp_set_lookup(set, old_table[i], MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
@@ -271,8 +272,8 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
}
}
mp_uint_t hash = mp_obj_hash(index);
uint pos = hash % set->alloc;
uint start_pos = pos;
mp_uint_t pos = hash % set->alloc;
mp_uint_t start_pos = pos;
mp_obj_t *avail_slot = NULL;
for (;;) {
mp_obj_t elem = set->table[pos];
@@ -333,7 +334,7 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
}
mp_obj_t mp_set_remove_first(mp_set_t *set) {
for (uint pos = 0; pos < set->alloc; pos++) {
for (mp_uint_t pos = 0; pos < set->alloc; pos++) {
if (MP_SET_SLOT_IS_FILLED(set, pos)) {
mp_obj_t elem = set->table[pos];
// delete element
@@ -359,7 +360,7 @@ void mp_set_clear(mp_set_t *set) {
#if DEBUG_PRINT
void mp_map_dump(mp_map_t *map) {
for (int i = 0; i < map->alloc; i++) {
for (mp_uint_t i = 0; i < map->alloc; i++) {
if (map->table[i].key != NULL) {
mp_obj_print(map->table[i].key, PRINT_REPR);
} else {

View File

@@ -66,18 +66,20 @@ typedef unsigned int uint;
#define m_del_obj(type, ptr) (m_del(type, ptr, 1))
#define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
void *m_malloc(int num_bytes);
void *m_malloc_maybe(int num_bytes);
void *m_malloc_with_finaliser(int num_bytes);
void *m_malloc0(int num_bytes);
void *m_realloc(void *ptr, int old_num_bytes, int new_num_bytes);
void *m_realloc_maybe(void *ptr, int old_num_bytes, int new_num_bytes);
void m_free(void *ptr, int num_bytes);
void *m_malloc_fail(int num_bytes);
void *m_malloc(size_t num_bytes);
void *m_malloc_maybe(size_t num_bytes);
void *m_malloc_with_finaliser(size_t num_bytes);
void *m_malloc0(size_t num_bytes);
void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes);
void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes);
void m_free(void *ptr, size_t num_bytes);
void *m_malloc_fail(size_t num_bytes);
int m_get_total_bytes_allocated(void);
int m_get_current_bytes_allocated(void);
int m_get_peak_bytes_allocated(void);
#if MICROPY_MEM_STATS
size_t m_get_total_bytes_allocated(void);
size_t m_get_current_bytes_allocated(void);
size_t m_get_peak_bytes_allocated(void);
#endif
/** array helpers ***********************************************/
@@ -110,8 +112,8 @@ mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
/** variable string *********************************************/
typedef struct _vstr_t {
uint alloc;
uint len;
size_t alloc;
size_t len;
char *buf;
bool had_error : 1;
bool fixed_buf : 1;
@@ -120,40 +122,38 @@ typedef struct _vstr_t {
// convenience macro to declare a vstr with a fixed size buffer on the stack
#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, int alloc);
void vstr_init_fixed_buf(vstr_t *vstr, int alloc, char *buf);
void vstr_init(vstr_t *vstr, size_t alloc);
void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
void vstr_clear(vstr_t *vstr);
vstr_t *vstr_new(void);
vstr_t *vstr_new_size(int alloc);
vstr_t *vstr_new_size(size_t alloc);
void vstr_free(vstr_t *vstr);
void vstr_reset(vstr_t *vstr);
bool vstr_had_error(vstr_t *vstr);
char *vstr_str(vstr_t *vstr);
int vstr_len(vstr_t *vstr);
void vstr_hint_size(vstr_t *vstr, int size);
char *vstr_extend(vstr_t *vstr, int size);
bool vstr_set_size(vstr_t *vstr, int size);
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, int len);
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);
void vstr_add_str(vstr_t *vstr, const char *str);
void vstr_add_strn(vstr_t *vstr, const char *str, int len);
//void vstr_add_le16(vstr_t *vstr, unsigned short v);
//void vstr_add_le32(vstr_t *vstr, unsigned int v);
void vstr_ins_byte(vstr_t *vstr, uint byte_pos, byte b);
void vstr_ins_char(vstr_t *vstr, uint char_pos, unichar chr);
void vstr_cut_head_bytes(vstr_t *vstr, uint bytes_to_cut);
void vstr_cut_tail_bytes(vstr_t *vstr, uint bytes_to_cut);
void vstr_cut_out_bytes(vstr_t *vstr, uint byte_pos, uint bytes_to_cut);
void vstr_add_strn(vstr_t *vstr, const char *str, size_t len);
void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b);
void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr);
void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut);
void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut);
void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut);
void vstr_printf(vstr_t *vstr, const char *fmt, ...);
/** non-dynamic size-bounded variable buffer/string *************/
#define CHECKBUF(buf, max_size) char buf[max_size + 1]; uint buf##_len = max_size; char *buf##_p = buf;
#define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf;
#define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf;
#define CHECKBUF_APPEND(buf, src, src_len) \
{ int l = MIN(src_len, buf##_len); \
{ size_t l = MIN(src_len, buf##_len); \
memcpy(buf##_p, src, l); \
buf##_len -= l; \
buf##_p += l; }
@@ -167,15 +167,15 @@ void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap);
// Debugging helpers
int DEBUG_printf(const char *fmt, ...);
extern uint mp_verbose_flag;
extern mp_uint_t mp_verbose_flag;
// This is useful for unicode handling. Some CPU archs has
// special instructions for efficient implentation of this
// function (e.g. CLZ on ARM).
// NOTE: this function is unused at the moment
#ifndef count_lead_ones
static inline uint count_lead_ones(byte val) {
uint c = 0;
static inline mp_uint_t count_lead_ones(byte val) {
mp_uint_t c = 0;
for (byte mask = 0x80; val & mask; mask >>= 1) {
c++;
}

View File

@@ -101,7 +101,7 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
char fmt_type = get_fmt_type(&fmt);
mp_uint_t size;
for (size = 0; *fmt; fmt++) {
uint align = 1;
mp_uint_t align = 1;
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);

View File

@@ -25,8 +25,9 @@
*/
#include <stdint.h>
#include <limits.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
@@ -42,13 +43,7 @@
/// \module sys - system specific functions
// These should be implemented by ports, specific types don't matter,
// only addresses.
struct _dummy_t;
extern struct _dummy_t mp_sys_exit_obj;
extern mp_obj_int_t mp_maxsize_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
mp_obj_list_t mp_sys_path_obj;
@@ -69,6 +64,20 @@ STATIC const mp_obj_tuple_t mp_sys_version_info_obj = {{&mp_type_tuple}, 3, {I(3
STATIC const MP_DEFINE_STR_OBJ(platform_obj, MICROPY_PY_SYS_PLATFORM);
#endif
/// \function exit([retval])
/// Raise a `SystemExit` exception. If an argument is given, it is the
/// value given to `SystemExit`.
STATIC mp_obj_t mp_sys_exit(mp_uint_t n_args, const mp_obj_t *args) {
mp_obj_t exc;
if (n_args == 0) {
exc = mp_obj_new_exception(&mp_type_SystemExit);
} else {
exc = mp_obj_new_exception_arg1(&mp_type_SystemExit, args[0]);
}
nlr_raise(exc);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj, 0, 1, mp_sys_exit);
STATIC const mp_map_elem_t mp_module_sys_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_sys) },

View File

@@ -101,6 +101,11 @@
#define MICROPY_EMIT_X64 (0)
#endif
// Whether to emit x86 native code
#ifndef MICROPY_EMIT_X86
#define MICROPY_EMIT_X86 (0)
#endif
// Whether to emit thumb native code
#ifndef MICROPY_EMIT_THUMB
#define MICROPY_EMIT_THUMB (0)
@@ -111,6 +116,14 @@
#define MICROPY_EMIT_INLINE_THUMB (0)
#endif
// Whether to emit ARM native code
#ifndef MICROPY_EMIT_ARM
#define MICROPY_EMIT_ARM (0)
#endif
// Convenience definition for whether any native emitter is enabled
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM)
/*****************************************************************************/
/* Compiler configuration */
@@ -377,6 +390,10 @@ typedef double mp_float_t;
#define MICROPY_PY_ZLIBD (0)
#endif
#ifndef MICROPY_PY_UJSON
#define MICROPY_PY_UJSON (0)
#endif
/*****************************************************************************/
/* Hooks for a port to add builtins */
@@ -426,6 +443,24 @@ typedef double mp_float_t;
#define MP_ENDIANNESS_LITTLE (0)
#endif
// Make a pointer to RAM callable (eg set lower bit for Thumb code)
// (This scheme won't work if we want to mix Thumb and normal ARM code.)
#ifndef MICROPY_MAKE_POINTER_CALLABLE
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
#endif
#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
#ifndef MP_PLAT_FREE_EXEC
#define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size)
#endif
#ifndef MP_SSIZE_MAX
#define MP_SSIZE_MAX SSIZE_MAX
#endif
// printf format spec to use for mp_int_t and friends
#ifndef INT_FMT
#ifdef __LP64__

192
py/mpz.c
View File

@@ -37,7 +37,9 @@
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
#define DIG_SIZE (MPZ_DIG_SIZE)
#define DIG_MASK ((1 << DIG_SIZE) - 1)
#define DIG_MASK ((1L << DIG_SIZE) - 1)
#define DIG_MSB (1L << (DIG_SIZE - 1))
#define DIG_BASE (1L << DIG_SIZE)
/*
mpz is an arbitrary precision integer type with a public API.
@@ -56,12 +58,12 @@
returns sign(i - j)
assumes i, j are normalised
*/
STATIC int mpn_cmp(const mpz_dig_t *idig, uint ilen, const mpz_dig_t *jdig, uint jlen) {
STATIC mp_int_t mpn_cmp(const mpz_dig_t *idig, mp_uint_t ilen, const mpz_dig_t *jdig, mp_uint_t jlen) {
if (ilen < jlen) { return -1; }
if (ilen > jlen) { return 1; }
for (idig += ilen, jdig += ilen; ilen > 0; --ilen) {
int cmp = *(--idig) - *(--jdig);
mpz_dbl_dig_signed_t cmp = (mpz_dbl_dig_t)*(--idig) - (mpz_dbl_dig_t)*(--jdig);
if (cmp < 0) { return -1; }
if (cmp > 0) { return 1; }
}
@@ -74,9 +76,9 @@ STATIC int mpn_cmp(const mpz_dig_t *idig, uint ilen, const mpz_dig_t *jdig, uint
assumes enough memory in i; assumes normalised j; assumes n > 0
can have i, j pointing to same memory
*/
STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
uint n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
uint n_part = n % DIG_SIZE;
STATIC mp_uint_t mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
mp_uint_t n_whole = (n + DIG_SIZE - 1) / DIG_SIZE;
mp_uint_t n_part = n % DIG_SIZE;
if (n_part == 0) {
n_part = DIG_SIZE;
}
@@ -87,7 +89,7 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
// shift the digits
mpz_dbl_dig_t d = 0;
for (uint i = jlen; i > 0; i--, idig--, jdig--) {
for (mp_uint_t i = jlen; i > 0; i--, idig--, jdig--) {
d |= *jdig;
*idig = (d >> (DIG_SIZE - n_part)) & DIG_MASK;
d <<= DIG_SIZE;
@@ -113,9 +115,9 @@ STATIC uint mpn_shl(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
assumes enough memory in i; assumes normalised j; assumes n > 0
can have i, j pointing to same memory
*/
STATIC uint mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
uint n_whole = n / DIG_SIZE;
uint n_part = n % DIG_SIZE;
STATIC mp_uint_t mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mp_uint_t n) {
mp_uint_t n_whole = n / DIG_SIZE;
mp_uint_t n_part = n % DIG_SIZE;
if (n_whole >= jlen) {
return 0;
@@ -124,10 +126,10 @@ STATIC uint mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
jdig += n_whole;
jlen -= n_whole;
for (uint i = jlen; i > 0; i--, idig++, jdig++) {
for (mp_uint_t i = jlen; i > 0; i--, idig++, jdig++) {
mpz_dbl_dig_t d = *jdig;
if (i > 1) {
d |= jdig[1] << DIG_SIZE;
d |= (mpz_dbl_dig_t)jdig[1] << DIG_SIZE;
}
d >>= n_part;
*idig = d & DIG_MASK;
@@ -145,14 +147,14 @@ STATIC uint mpn_shr(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, uint n) {
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
can have i, j, k pointing to same memory
*/
STATIC uint mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = 0;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
carry += *jdig + *kdig;
carry += (mpz_dbl_dig_t)*jdig + (mpz_dbl_dig_t)*kdig;
*idig = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
@@ -175,14 +177,14 @@ STATIC uint mpn_add(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
assumes enough memory in i; assumes normalised j, k; assumes j >= k
can have i, j, k pointing to same memory
*/
STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_signed_t borrow = 0;
jlen -= klen;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
borrow += *jdig - *kdig;
borrow += (mpz_dbl_dig_t)*jdig - (mpz_dbl_dig_t)*kdig;
*idig = borrow & DIG_MASK;
borrow >>= DIG_SIZE;
}
@@ -204,7 +206,7 @@ STATIC uint mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
can have i, j, k pointing to same memory
*/
STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
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) {
mpz_dig_t *oidig = idig;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
@@ -223,7 +225,7 @@ STATIC uint mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
assumes enough memory in i; assumes normalised j, k
can have i, j, k pointing to same memory
*/
STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = 1;
@@ -255,7 +257,7 @@ STATIC uint mpn_and_neg(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
can have i, j, k pointing to same memory
*/
STATIC uint mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
jlen -= klen;
@@ -276,7 +278,7 @@ STATIC uint mpn_or(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
can have i, j, k pointing to same memory
*/
STATIC uint mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
jlen -= klen;
@@ -296,12 +298,12 @@ STATIC uint mpn_xor(mpz_dig_t *idig, const mpz_dig_t *jdig, uint jlen, const mpz
returns number of digits in i
assumes enough memory in i; assumes normalised i; assumes dmul != 0
*/
STATIC uint mpn_mul_dig_add_dig(mpz_dig_t *idig, uint ilen, mpz_dig_t dmul, mpz_dig_t dadd) {
STATIC mp_uint_t mpn_mul_dig_add_dig(mpz_dig_t *idig, mp_uint_t ilen, mpz_dig_t dmul, mpz_dig_t dadd) {
mpz_dig_t *oidig = idig;
mpz_dbl_dig_t carry = dadd;
for (; ilen > 0; --ilen, ++idig) {
carry += *idig * dmul; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
carry += (mpz_dbl_dig_t)*idig * (mpz_dbl_dig_t)dmul; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2
*idig = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
@@ -318,17 +320,17 @@ STATIC uint mpn_mul_dig_add_dig(mpz_dig_t *idig, uint ilen, mpz_dig_t dmul, mpz_
assumes enough memory in i; assumes i is zeroed; assumes normalised j, k
can have j, k point to same memory
*/
STATIC uint mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, uint jlen, mpz_dig_t *kdig, uint klen) {
STATIC mp_uint_t mpn_mul(mpz_dig_t *idig, mpz_dig_t *jdig, mp_uint_t jlen, mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
uint ilen = 0;
mp_uint_t ilen = 0;
for (; klen > 0; --klen, ++idig, ++kdig) {
mpz_dig_t *id = idig;
mpz_dbl_dig_t carry = 0;
uint jl = jlen;
mp_uint_t jl = jlen;
for (mpz_dig_t *jd = jdig; jl > 0; --jl, ++jd, ++id) {
carry += *id + *jd * *kdig; // will never overflow so long as DIG_SIZE <= WORD_SIZE / 2
carry += (mpz_dbl_dig_t)*id + (mpz_dbl_dig_t)*jd * (mpz_dbl_dig_t)*kdig; // will never overflow so long as DIG_SIZE <= 8*sizeof(mpz_dbl_dig_t)/2
*id = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
@@ -359,7 +361,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
// handle simple cases
{
int cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
mp_int_t cmp = mpn_cmp(num_dig, *num_len, den_dig, den_len);
if (cmp == 0) {
*num_len = 0;
quo_dig[0] = 1;
@@ -375,7 +377,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
// count number of leading zeros in leading digit of denominator
{
mpz_dig_t d = den_dig[den_len - 1];
while ((d & (1 << (DIG_SIZE - 1))) == 0) {
while ((d & DIG_MSB) == 0) {
d <<= 1;
++norm_shift;
}
@@ -412,21 +414,36 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
// keep going while we have enough digits to divide
while (*num_len > den_len) {
mpz_dbl_dig_t quo = (*num_dig << DIG_SIZE) | num_dig[-1];
mpz_dbl_dig_t quo = ((mpz_dbl_dig_t)*num_dig << DIG_SIZE) | num_dig[-1];
// get approximate quotient
quo /= lead_den_digit;
// multiply quo by den and subtract from num get remainder
{
// Multiply quo by den and subtract from num to get remainder.
// We have different code here to handle different compile-time
// configurations of mpz:
//
// 1. DIG_SIZE is stricly less than half the number of bits
// available in mpz_dbl_dig_t. In this case we can use a
// slightly more optimal (in time and space) routine that
// uses the extra bits in mpz_dbl_dig_signed_t to store a
// sign bit.
//
// 2. DIG_SIZE is exactly half the number of bits available in
// mpz_dbl_dig_t. In this (common) case we need to be careful
// not to overflow the borrow variable. And the shifting of
// borrow needs some special logic (it's a shift right with
// round up).
if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
mpz_dbl_dig_signed_t borrow = 0;
for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
borrow += *n - quo * *d; // will overflow if DIG_SIZE >= 16
borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)*d; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
*n = borrow & DIG_MASK;
borrow >>= DIG_SIZE;
}
borrow += *num_dig; // will overflow if DIG_SIZE >= 16
borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
*num_dig = borrow & DIG_MASK;
borrow >>= DIG_SIZE;
@@ -434,7 +451,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
for (; borrow != 0; --quo) {
mpz_dbl_dig_t carry = 0;
for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
carry += *n + *d;
carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
*n = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
@@ -444,6 +461,44 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
borrow += carry;
}
} else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
mpz_dbl_dig_t borrow = 0;
for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (mpz_dbl_dig_t)(*d);
if (x >= *n || *n - x <= borrow) {
borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
*n = (-borrow) & DIG_MASK;
borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
} else {
*n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
borrow = 0;
}
}
if (borrow >= *num_dig) {
borrow -= (mpz_dbl_dig_t)*num_dig;
*num_dig = (-borrow) & DIG_MASK;
borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
} else {
*num_dig = (*num_dig - borrow) & DIG_MASK;
borrow = 0;
}
// adjust quotient if it is too big
for (; borrow != 0; --quo) {
mpz_dbl_dig_t carry = 0;
for (mpz_dig_t *n = num_dig - den_len, *d = den_dig; n < num_dig; ++n, ++d) {
carry += (mpz_dbl_dig_t)*n + (mpz_dbl_dig_t)*d;
*n = carry & DIG_MASK;
carry >>= DIG_SIZE;
}
carry += (mpz_dbl_dig_t)*num_dig;
*num_dig = carry & DIG_MASK;
carry >>= DIG_SIZE;
//assert(borrow >= carry); // enable this to check the logic
borrow -= carry;
}
}
// store this digit of the quotient
@@ -482,7 +537,7 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, mpz_dig_t *den_dig,
#define MIN_ALLOC (2)
static const uint log_base2_floor[] = {
STATIC const uint8_t log_base2_floor[] = {
0,
0, 1, 1, 2,
2, 2, 2, 3,
@@ -507,7 +562,7 @@ void mpz_init_from_int(mpz_t *z, mp_int_t val) {
mpz_set_from_int(z, val);
}
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint alloc, mp_int_t val) {
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, mp_uint_t alloc, mp_int_t val) {
z->neg = 0;
z->fixed_dig = 1;
z->alloc = alloc;
@@ -534,13 +589,13 @@ mpz_t *mpz_from_int(mp_int_t val) {
return z;
}
mpz_t *mpz_from_ll(long long val) {
mpz_t *mpz_from_ll(long long val, bool is_signed) {
mpz_t *z = mpz_zero();
mpz_set_from_ll(z, val);
mpz_set_from_ll(z, val, is_signed);
return z;
}
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base) {
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);
return z;
@@ -553,7 +608,7 @@ void mpz_free(mpz_t *z) {
}
}
STATIC void mpz_need_dig(mpz_t *z, uint need) {
STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) {
if (need < MIN_ALLOC) {
need = MIN_ALLOC;
}
@@ -613,11 +668,11 @@ void mpz_set_from_int(mpz_t *z, mp_int_t val) {
}
}
void mpz_set_from_ll(mpz_t *z, long long val) {
void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
mpz_need_dig(z, MPZ_NUM_DIG_FOR_LL);
unsigned long long uval;
if (val < 0) {
if (is_signed && val < 0) {
z->neg = 1;
uval = -val;
} else {
@@ -633,7 +688,7 @@ void mpz_set_from_ll(mpz_t *z, long long val) {
}
// returns number of bytes from str that were processed
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base) {
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);
const char *cur = str;
@@ -649,8 +704,8 @@ uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base)
z->len = 0;
for (; cur < top; ++cur) { // XXX UTF8 next char
//uint v = char_to_numeric(cur#); // XXX UTF8 get char
uint v = *cur;
//mp_uint_t v = char_to_numeric(cur#); // XXX UTF8 get char
mp_uint_t v = *cur;
if ('0' <= v && v <= '9') {
v -= '0';
} else if ('A' <= v && v <= 'Z') {
@@ -689,8 +744,8 @@ bool mpz_is_even(const mpz_t *z) {
return z->len == 0 || (z->dig[0] & 1) == 0;
}
int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
int cmp = z2->neg - z1->neg;
mp_int_t mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
mp_int_t cmp = z2->neg - z1->neg;
if (cmp != 0) {
return cmp;
}
@@ -704,8 +759,8 @@ int mpz_cmp(const mpz_t *z1, const mpz_t *z2) {
#if 0
// obsolete
// compares mpz with an integer that fits within DIG_SIZE bits
int mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
int cmp;
mp_int_t mpz_cmp_sml_int(const mpz_t *z, mp_int_t sml_int) {
mp_int_t cmp;
if (z->neg == 0) {
if (sml_int < 0) return 1;
if (sml_int == 0) {
@@ -856,10 +911,10 @@ void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
dest->neg = lhs->neg;
if (dest->neg) {
// arithmetic shift right, rounding to negative infinity
uint n_whole = rhs / DIG_SIZE;
uint n_part = rhs % DIG_SIZE;
mp_uint_t n_whole = rhs / DIG_SIZE;
mp_uint_t n_part = rhs % DIG_SIZE;
mpz_dig_t round_up = 0;
for (uint i = 0; i < lhs->len && i < n_whole; i++) {
for (mp_uint_t i = 0; i < lhs->len && i < n_whole; i++) {
if (lhs->dig[i] != 0) {
round_up = 1;
break;
@@ -1256,7 +1311,7 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
if (val > ((~0) >> DIG_SIZE)) {
if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
// will overflow
return false;
}
@@ -1273,7 +1328,7 @@ mp_float_t mpz_as_float(const mpz_t *i) {
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
val = val * (1 << DIG_SIZE) + *d;
val = val * DIG_BASE + *d;
}
if (i->neg != 0) {
@@ -1284,41 +1339,36 @@ mp_float_t mpz_as_float(const mpz_t *i) {
}
#endif
uint mpz_as_str_size(const mpz_t *i, uint base) {
mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma) {
if (base < 2 || base > 32) {
return 0;
}
return i->len * DIG_SIZE / log_base2_floor[base] + 2 + 1; // +1 for null byte termination
}
uint mpz_as_str_size_formatted(const mpz_t *i, uint base, const char *prefix, char comma) {
if (base < 2 || base > 32) {
return 0;
}
uint num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
uint num_commas = comma ? num_digits / 3: 0;
uint prefix_len = prefix ? strlen(prefix) : 0;
mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
mp_uint_t num_commas = comma ? num_digits / 3: 0;
mp_uint_t prefix_len = prefix ? strlen(prefix) : 0;
return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
}
char *mpz_as_str(const mpz_t *i, uint base) {
char *s = m_new(char, mpz_as_str_size(i, base));
mpz_as_str_inpl(i, base, "", 'a', 0, s);
#if 0
this function is unused
char *mpz_as_str(const mpz_t *i, mp_uint_t base) {
char *s = m_new(char, mpz_as_str_size(i, base, NULL, '\0'));
mpz_as_str_inpl(i, base, NULL, 'a', '\0', s);
return s;
}
#endif
// assumes enough space as calculated by mpz_as_str_size
// returns length of string, not including null byte
uint mpz_as_str_inpl(const mpz_t *i, uint base, const char *prefix, char base_char, char comma, char *str) {
mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) {
if (str == NULL || base < 2 || base > 32) {
str[0] = 0;
return 0;
}
uint ilen = i->len;
mp_uint_t ilen = i->len;
char *s = str;
if (ilen == 0) {

View File

@@ -24,9 +24,34 @@
* THE SOFTWARE.
*/
// This mpz module implements arbitrary precision integers.
//
// The storage for each digit is defined by mpz_dig_t. The actual number of
// bits in mpz_dig_t that are used is defined by MPZ_DIG_SIZE. The machine must
// also provide a type that is twice as wide as mpz_dig_t, in both signed and
// unsigned versions.
//
// MPZ_DIG_SIZE can be between 4 and 8*sizeof(mpz_dig_t), but it makes most
// sense to have it as large as possible. Below, the type is auto-detected
// depending on the machine, but it (and MPZ_DIG_SIZE) can be freely changed so
// long as the constraints mentioned above are met.
#if defined(__x86_64__)
// 64-bit machine, using 32-bit storage for digits
typedef uint32_t mpz_dig_t;
typedef uint64_t mpz_dbl_dig_t;
typedef int64_t mpz_dbl_dig_signed_t;
#define MPZ_DIG_SIZE (32)
#else
// 32-bit machine, using 16-bit storage for digits
typedef uint16_t mpz_dig_t;
typedef uint32_t mpz_dbl_dig_t;
typedef int32_t mpz_dbl_dig_signed_t;
#define MPZ_DIG_SIZE (16)
#endif
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
typedef struct _mpz_t {
mp_uint_t neg : 1;
@@ -36,30 +61,26 @@ typedef struct _mpz_t {
mpz_dig_t *dig;
} mpz_t;
#define MPZ_DIG_SIZE (15) // see mpn_div for why this needs to be at most 15
#define MPZ_NUM_DIG_FOR_INT (sizeof(mp_int_t) * 8 / MPZ_DIG_SIZE + 1)
#define MPZ_NUM_DIG_FOR_LL (sizeof(long long) * 8 / MPZ_DIG_SIZE + 1)
// convenience macro to declare an mpz with a digit array from the stack, initialised by an integer
#define MPZ_CONST_INT(z, val) mpz_t z; mpz_dig_t z ## _digits[MPZ_NUM_DIG_FOR_INT]; mpz_init_fixed_from_int(&z, z_digits, MPZ_NUM_DIG_FOR_INT, val);
void mpz_init_zero(mpz_t *z);
void mpz_init_from_int(mpz_t *z, mp_int_t val);
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, uint dig_alloc, mp_int_t val);
void mpz_init_fixed_from_int(mpz_t *z, mpz_dig_t *dig, mp_uint_t dig_alloc, mp_int_t val);
void mpz_deinit(mpz_t *z);
mpz_t *mpz_zero();
mpz_t *mpz_from_int(mp_int_t i);
mpz_t *mpz_from_ll(long long i);
mpz_t *mpz_from_str(const char *str, uint len, bool neg, uint base);
mpz_t *mpz_from_ll(long long i, bool is_signed);
mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base);
void mpz_free(mpz_t *z);
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);
uint mpz_set_from_str(mpz_t *z, const char *str, uint len, bool neg, uint base);
void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed);
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);
bool mpz_is_pos(const mpz_t *z);
@@ -67,7 +88,7 @@ bool mpz_is_neg(const mpz_t *z);
bool mpz_is_odd(const mpz_t *z);
bool mpz_is_even(const mpz_t *z);
int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
mp_int_t mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
mpz_t *mpz_abs(const mpz_t *z);
mpz_t *mpz_neg(const mpz_t *z);
@@ -102,7 +123,5 @@ bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);
#if MICROPY_PY_BUILTINS_FLOAT
mp_float_t mpz_as_float(const mpz_t *z);
#endif
uint mpz_as_str_size(const mpz_t *z, uint base);
uint mpz_as_str_size_formatted(const mpz_t *i, uint base, const char *prefix, char comma);
char *mpz_as_str(const mpz_t *z, uint base);
uint mpz_as_str_inpl(const mpz_t *z, uint base, const char *prefix, char base_char, char comma, char *str);
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);

138
py/nativeglue.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#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"
#if MICROPY_EMIT_NATIVE
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
// convert a Micro Python object to a valid native value based on type
mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type) {
DEBUG_printf("mp_convert_obj_to_native(%p, " UINT_FMT ")\n", obj, type);
switch (type & 3) {
case MP_NATIVE_TYPE_OBJ: return (mp_uint_t)obj;
case MP_NATIVE_TYPE_BOOL:
case MP_NATIVE_TYPE_INT:
case MP_NATIVE_TYPE_UINT: return mp_obj_get_int(obj);
default: assert(0); return 0;
}
}
// convert a native value to a Micro Python object based on type
mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type) {
DEBUG_printf("mp_convert_native_to_obj(" UINT_FMT ", " UINT_FMT ")\n", val, type);
switch (type & 3) {
case MP_NATIVE_TYPE_OBJ: return (mp_obj_t)val;
case MP_NATIVE_TYPE_BOOL: return MP_BOOL(val);
case MP_NATIVE_TYPE_INT: return mp_obj_new_int(val);
case MP_NATIVE_TYPE_UINT: return mp_obj_new_int_from_uint(val);
default: assert(0); return mp_const_none;
}
}
// wrapper that accepts n_args and n_kw in one argument
// (native emitter can only pass at most 3 arguments to a function)
mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, const mp_obj_t *args) {
return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
}
// wrapper that makes raise obj and raises it
NORETURN void mp_native_raise(mp_obj_t o) {
nlr_raise(mp_make_raise_obj(o));
}
// these must correspond to the respective enum in runtime0.h
void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_convert_obj_to_native,
mp_convert_native_to_obj,
mp_load_const_int,
mp_load_const_dec,
mp_load_const_str,
mp_load_const_bytes,
mp_load_name,
mp_load_global,
mp_load_build_class,
mp_load_attr,
mp_load_method,
mp_store_name,
mp_store_global,
mp_store_attr,
mp_obj_subscr,
mp_obj_is_true,
mp_unary_op,
mp_binary_op,
mp_obj_new_tuple,
mp_obj_new_list,
mp_obj_list_append,
mp_obj_new_dict,
mp_obj_dict_store,
#if MICROPY_PY_BUILTINS_SET
mp_obj_new_set,
mp_obj_set_store,
#endif
mp_make_function_from_raw_code,
mp_native_call_function_n_kw,
mp_call_method_n_kw,
mp_getiter,
mp_iternext,
nlr_push,
nlr_pop,
mp_native_raise,
mp_import_name,
mp_import_from,
mp_import_all,
#if MICROPY_PY_BUILTINS_SLICE
mp_obj_new_slice,
#endif
mp_unpack_sequence,
mp_unpack_ex,
mp_delete_name,
mp_delete_global,
};
/*
void mp_f_vector(mp_fun_kind_t fun_kind) {
(mp_f_table[fun_kind])();
}
*/
#endif // MICROPY_EMIT_NATIVE

View File

@@ -111,7 +111,7 @@ void mp_obj_print_exception(mp_obj_t exc) {
printf("\n");
}
int mp_obj_is_true(mp_obj_t arg) {
bool mp_obj_is_true(mp_obj_t arg) {
if (arg == mp_const_false) {
return 0;
} else if (arg == mp_const_true) {
@@ -161,7 +161,7 @@ mp_int_t mp_obj_hash(mp_obj_t o_in) {
return mp_obj_str_get_hash(o_in);
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {
return (mp_int_t)o_in;
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_fun_native) || MP_OBJ_IS_TYPE(o_in, &mp_type_fun_bc)) {
} else if (MP_OBJ_IS_FUN(o_in)) {
return (mp_int_t)o_in;
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_tuple)) {
return mp_obj_tuple_hash(o_in);
@@ -308,7 +308,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
#endif
#endif
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) {
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
mp_obj_tuple_get(o, len, items);
} else if (MP_OBJ_IS_TYPE(o, &mp_type_list)) {
@@ -318,24 +318,16 @@ void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items) {
}
}
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items) {
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple) || MP_OBJ_IS_TYPE(o, &mp_type_list)) {
uint seq_len;
if (MP_OBJ_IS_TYPE(o, &mp_type_tuple)) {
mp_obj_tuple_get(o, &seq_len, items);
} else {
mp_obj_list_get(o, &seq_len, items);
}
if (seq_len != len) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", len, seq_len));
}
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o)));
void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) {
mp_uint_t seq_len;
mp_obj_get_array(o, &seq_len, items);
if (seq_len != len) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", len, seq_len));
}
}
// is_slice determines whether the index is a slice index
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) {
mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice) {
mp_int_t i;
if (MP_OBJ_IS_SMALL_INT(index)) {
i = MP_OBJ_SMALL_INT_VALUE(index);
@@ -360,6 +352,24 @@ uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool
return i;
}
mp_obj_t mp_obj_id(mp_obj_t o_in) {
mp_int_t id = (mp_int_t)o_in;
if (!MP_OBJ_IS_OBJ(o_in)) {
return mp_obj_new_int(id);
} else if (id >= 0) {
// Many OSes and CPUs have affinity for putting "user" memories
// into low half of address space, and "system" into upper half.
// We're going to take advantage of that and return small int
// (signed) for such "user" addresses.
return MP_OBJ_NEW_SMALL_INT(id);
} else {
// If that didn't work, well, let's return long int, just as
// a (big) positve value, so it will never clash with the range
// of small int returned in previous case.
return mp_obj_new_int_from_uint((mp_uint_t)id);
}
}
// will raise a TypeError if object has no length
mp_obj_t mp_obj_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in);
@@ -414,7 +424,7 @@ mp_obj_t mp_identity(mp_obj_t self) {
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
mp_obj_type_t *type = mp_obj_get_type(obj);
if (type->buffer_p.get_buffer == NULL) {
return false;
@@ -426,7 +436,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
return true;
}
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags) {
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
if (!mp_get_buffer(obj, bufinfo, flags)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "object with buffer protocol required"));
}

151
py/obj.h
View File

@@ -71,9 +71,11 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
//#define MP_OBJ_IS_SMALL_INT(o) ((((mp_int_t)(o)) & 1) != 0)
//#define MP_OBJ_IS_QSTR(o) ((((mp_int_t)(o)) & 3) == 2)
//#define MP_OBJ_IS_OBJ(o) ((((mp_int_t)(o)) & 3) == 0)
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking a string, use below macro for that
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
#define MP_OBJ_IS_STR(o) (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str))
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)(o))->type->binary_op == mp_obj_str_binary_op))
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type->binary_op == mp_obj_fun_binary_op))
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_int_t)(small_int)) << 1) | 1))
@@ -84,9 +86,9 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
// These macros are used to declare and define constant function objects
// You can put "static" in front of the definitions to make them local
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_native_t obj_name
#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_native_t obj_name = {{&mp_type_fun_native}, is_kw, n_args_min, n_args_max, (void *)fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_builtin_t obj_name = {{&mp_type_fun_builtin}, is_kw, n_args_min, n_args_max, (void *)fun_name}
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 0, 0, (mp_fun_0_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 1, 1, (mp_fun_1_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 2, 2, (mp_fun_2_t)fun_name)
@@ -148,9 +150,9 @@ typedef enum _mp_map_lookup_kind_t {
static inline bool MP_MAP_SLOT_IS_FILLED(const mp_map_t *map, mp_uint_t pos) { return ((map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL); }
void mp_map_init(mp_map_t *map, int n);
void mp_map_init_fixed_table(mp_map_t *map, int n, const mp_obj_t *table);
mp_map_t *mp_map_new(int n);
void mp_map_init(mp_map_t *map, mp_uint_t n);
void mp_map_init_fixed_table(mp_map_t *map, mp_uint_t n, const mp_obj_t *table);
mp_map_t *mp_map_new(mp_uint_t n);
void mp_map_deinit(mp_map_t *map);
void mp_map_free(mp_map_t *map);
mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
@@ -167,7 +169,7 @@ typedef struct _mp_set_t {
static inline bool MP_SET_SLOT_IS_FILLED(const mp_set_t *set, mp_uint_t pos) { return ((set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL); }
void mp_set_init(mp_set_t *set, int n);
void mp_set_init(mp_set_t *set, mp_uint_t n);
mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t lookup_kind);
mp_obj_t mp_set_remove_first(mp_set_t *set);
void mp_set_clear(mp_set_t *set);
@@ -178,22 +180,22 @@ typedef mp_obj_t (*mp_fun_0_t)(void);
typedef mp_obj_t (*mp_fun_1_t)(mp_obj_t);
typedef mp_obj_t (*mp_fun_2_t)(mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_fun_t)(void);
typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *);
typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *);
typedef mp_obj_t (*mp_fun_var_t)(mp_uint_t n, const mp_obj_t *);
typedef mp_obj_t (*mp_fun_kw_t)(mp_uint_t n, const mp_obj_t *, mp_map_t *);
typedef enum {
PRINT_STR = 0,
PRINT_REPR = 1,
PRINT_EXC = 2, // Special format for printing exception in unhandled exception message
PRINT_EXC_SUBCLASS = 4, // Internal flag for printing exception subclasses
PRINT_JSON = 3,
PRINT_EXC_SUBCLASS = 0x80, // Internal flag for printing exception subclasses
} mp_print_kind_t;
typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind);
typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, uint n_args, uint n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_unary_op_fun_t)(int op, mp_obj_t);
typedef mp_obj_t (*mp_binary_op_fun_t)(int op, mp_obj_t, mp_obj_t);
typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t);
typedef mp_obj_t (*mp_binary_op_fun_t)(mp_uint_t op, mp_obj_t, mp_obj_t);
typedef void (*mp_load_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded; if value==MP_OBJ_NULL then delete
typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
@@ -211,8 +213,8 @@ typedef struct _mp_buffer_info_t {
//int ver; // ?
void *buf; // can be NULL if len == 0
mp_int_t len; // in bytes
int typecode; // as per binary.h
mp_int_t len; // in bytes; TODO should it be mp_uint_t?
int typecode; // as per binary.h; TODO what is the correct type to use?
// Rationale: to load arbitrary-sized sprites directly to LCD
// Cons: a bit adhoc usecase
@@ -222,20 +224,22 @@ typedef struct _mp_buffer_info_t {
#define MP_BUFFER_WRITE (2)
#define MP_BUFFER_RW (MP_BUFFER_READ | MP_BUFFER_WRITE)
typedef struct _mp_buffer_p_t {
mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
mp_int_t (*get_buffer)(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
} mp_buffer_p_t;
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, int flags);
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
// Stream protocol
#define MP_STREAM_ERROR (-1)
#define MP_STREAM_FLUSH (1)
#define MP_STREAM_POLL (2)
typedef struct _mp_stream_p_t {
// On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
// are implementation-dependent, but will be exposed to user, e.g. via exception).
mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
// add seek() ?
int is_text : 1; // default is bytes, set this for text stream
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, int *errcode, ...);
mp_uint_t is_text : 1; // default is bytes, set this for text stream
} mp_stream_p_t;
struct _mp_obj_type_t {
@@ -304,7 +308,7 @@ extern const mp_obj_type_t mp_type_zip;
extern const mp_obj_type_t mp_type_array;
extern const mp_obj_type_t mp_type_super;
extern const mp_obj_type_t mp_type_gen_instance;
extern const mp_obj_type_t mp_type_fun_native;
extern const mp_obj_type_t mp_type_fun_builtin;
extern const mp_obj_type_t mp_type_fun_bc;
extern const mp_obj_type_t mp_type_module;
extern const mp_obj_type_t mp_type_staticmethod;
@@ -364,27 +368,30 @@ mp_obj_t mp_obj_new_bool(bool value);
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
mp_obj_t mp_obj_new_int(mp_int_t value);
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base);
mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base);
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
mp_obj_t mp_obj_new_str(const char* data, uint len, bool make_qstr_if_not_already);
mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception)
mp_obj_t mp_obj_new_str(const char* data, mp_uint_t len, bool make_qstr_if_not_already);
mp_obj_t mp_obj_new_bytes(const byte* data, mp_uint_t len);
#if MICROPY_PY_BUILTINS_FLOAT
mp_obj_t mp_obj_new_float(mp_float_t val);
mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
#endif
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, uint n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_pos_args, uint n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun);
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, qstr *args, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed);
mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items);
mp_obj_t mp_obj_new_list(uint n, mp_obj_t *items);
mp_obj_t mp_obj_new_dict(int n_args);
mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items);
mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_uint_t n_closed, const mp_obj_t *closed);
mp_obj_t mp_obj_new_tuple(mp_uint_t n, const mp_obj_t *items);
mp_obj_t mp_obj_new_list(mp_uint_t n, mp_obj_t *items);
mp_obj_t mp_obj_new_dict(mp_uint_t n_args);
mp_obj_t mp_obj_new_set(mp_uint_t n_args, mp_obj_t *items);
mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj);
mp_obj_t mp_obj_new_bound_meth(mp_obj_t meth, mp_obj_t self);
@@ -400,7 +407,7 @@ void mp_obj_print_helper(void (*print)(void *env, const char *fmt, ...), void *e
void mp_obj_print(mp_obj_t o, mp_print_kind_t kind);
void mp_obj_print_exception(mp_obj_t exc);
int mp_obj_is_true(mp_obj_t arg);
bool mp_obj_is_true(mp_obj_t arg);
// TODO make these all lower case when they have proven themselves
static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 0); }
@@ -422,9 +429,10 @@ mp_float_t mp_obj_get_float(mp_obj_t self_in);
void mp_obj_get_complex(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
#endif
//qstr mp_obj_get_qstr(mp_obj_t arg);
void mp_obj_get_array(mp_obj_t o, uint *len, mp_obj_t **items);
void mp_obj_get_array_fixed_n(mp_obj_t o, uint len, mp_obj_t **items);
uint mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice);
void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items);
void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items);
mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, bool is_slice);
mp_obj_t mp_obj_id(mp_obj_t o_in);
mp_obj_t mp_obj_len(mp_obj_t o_in);
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in); /* may return MP_OBJ_NULL */
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t val);
@@ -450,27 +458,27 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in);
#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new)
bool mp_obj_is_exception_type(mp_obj_t self_in);
bool mp_obj_is_exception_instance(mp_obj_t self_in);
bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type);
bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type);
void mp_obj_exception_clear_traceback(mp_obj_t self_in);
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, mp_uint_t line, qstr block);
void mp_obj_exception_get_traceback(mp_obj_t self_in, mp_uint_t *n, mp_uint_t **values);
mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args);
mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
void mp_init_emergency_exception_buf(void);
// str
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data);
mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, mp_uint_t len, byte **data);
mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in);
mp_obj_t mp_obj_str_builder_end_with_len(mp_obj_t o_in, mp_uint_t len);
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2);
uint mp_obj_str_get_hash(mp_obj_t self_in);
uint mp_obj_str_get_len(mp_obj_t self_in);
mp_uint_t mp_obj_str_get_hash(mp_obj_t self_in);
mp_uint_t mp_obj_str_get_len(mp_obj_t self_in);
qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
const char *mp_obj_str_get_data(mp_obj_t self_in, uint *len);
const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len);
mp_obj_t mp_obj_str_intern(mp_obj_t str);
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len, bool is_bytes);
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len, bool is_bytes);
#if MICROPY_PY_BUILTINS_FLOAT
// float
@@ -479,34 +487,35 @@ typedef struct _mp_obj_float_t {
mp_float_t value;
} mp_obj_float_t;
mp_float_t mp_obj_float_get(mp_obj_t self_in);
mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y);
// complex
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported
mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in); // can return MP_OBJ_NULL if op not supported
#endif
// tuple
void mp_obj_tuple_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
void mp_obj_tuple_get(mp_obj_t self_in, mp_uint_t *len, mp_obj_t **items);
void mp_obj_tuple_del(mp_obj_t self_in);
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
// list
struct _mp_obj_list_t;
void mp_obj_list_init(struct _mp_obj_list_t *o, uint n);
void mp_obj_list_init(struct _mp_obj_list_t *o, mp_uint_t n);
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items);
void mp_obj_list_set_len(mp_obj_t self_in, uint len);
void mp_obj_list_get(mp_obj_t self_in, mp_uint_t *len, mp_obj_t **items);
void mp_obj_list_set_len(mp_obj_t self_in, mp_uint_t len);
void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
mp_obj_t mp_obj_list_sort(uint n_args, const mp_obj_t *args, mp_map_t *kwargs);
mp_obj_t mp_obj_list_sort(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
// dict
typedef struct _mp_obj_dict_t {
mp_obj_base_t base;
mp_map_t map;
} mp_obj_dict_t;
void mp_obj_dict_init(mp_obj_dict_t *dict, int n_args);
uint mp_obj_dict_len(mp_obj_t self_in);
void mp_obj_dict_init(mp_obj_dict_t *dict, mp_uint_t n_args);
mp_uint_t mp_obj_dict_len(mp_obj_t self_in);
mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
@@ -519,22 +528,20 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step);
// array
uint mp_obj_array_len(mp_obj_t self_in);
mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items);
mp_uint_t mp_obj_array_len(mp_obj_t self_in);
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items);
// functions
#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below
typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM
mp_obj_base_t base;
bool is_kw : 1;
uint n_args_min : 15; // inclusive
uint n_args_max : 16; // inclusive
void *fun;
// TODO add mp_map_t *globals
// for const function objects, make an empty, const map
// such functions won't be able to access the global scope, but that's probably okay
} mp_obj_fun_native_t;
mp_uint_t n_args_min : 15; // inclusive
mp_uint_t n_args_max : 16; // inclusive
void *fun; // must be a pointer to a callable function in ROM
} mp_obj_fun_builtin_t;
mp_obj_t mp_obj_fun_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);
const char *mp_obj_fun_get_name(mp_const_obj_t fun);
const char *mp_obj_code_get_name(const byte *code_info);
@@ -568,24 +575,24 @@ typedef struct {
mp_int_t step;
} mp_bound_slice_t;
void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest);
void mp_seq_multiply(const void *items, mp_uint_t item_sz, mp_uint_t len, mp_uint_t times, void *dest);
#if MICROPY_PY_BUILTINS_SLICE
bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes);
#endif
#define mp_seq_copy(dest, src, len, item_t) memcpy(dest, src, len * sizeof(item_t))
#define mp_seq_cat(dest, src1, len1, src2, len2, item_t) { memcpy(dest, src1, (len1) * sizeof(item_t)); memcpy(dest + (len1), src2, (len2) * sizeof(item_t)); }
bool mp_seq_cmp_bytes(int op, const byte *data1, uint len1, const byte *data2, uint len2);
bool mp_seq_cmp_objs(int op, const mp_obj_t *items1, uint len1, const mp_obj_t *items2, uint len2);
mp_obj_t mp_seq_index_obj(const mp_obj_t *items, uint len, uint n_args, const mp_obj_t *args);
mp_obj_t mp_seq_count_obj(const mp_obj_t *items, uint len, mp_obj_t value);
mp_obj_t mp_seq_extract_slice(uint len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, mp_uint_t len1, const byte *data2, mp_uint_t len2);
bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, mp_uint_t len1, const mp_obj_t *items2, mp_uint_t len2);
mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value);
mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes);
// Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems
#define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte*)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz))
#define mp_seq_replace_slice_no_grow(dest, dest_len, beg, end, slice, slice_len, item_t) \
/*printf("memcpy(%p, %p, %d)\n", dest + beg, slice, slice_len * sizeof(item_t));*/ \
memcpy(dest + beg, slice, slice_len * sizeof(item_t)); \
/*printf("memcpy(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
memcpy(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
/*printf("memmove(%p, %p, %d)\n", dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));*/ \
memmove(dest + (beg + slice_len), dest + end, (dest_len - end) * sizeof(item_t));
#define mp_seq_replace_slice_grow_inplace(dest, dest_len, beg, end, slice, slice_len, len_adj, item_t) \
/*printf("memmove(%p, %p, %d)\n", dest + beg + len_adj, dest + beg, (dest_len - beg) * sizeof(item_t));*/ \

View File

@@ -50,9 +50,9 @@ typedef struct _mp_obj_array_t {
} mp_obj_array_t;
STATIC mp_obj_t array_iterator_new(mp_obj_t array_in);
STATIC mp_obj_array_t *array_new(char typecode, uint n);
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n);
STATIC mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags);
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags);
/******************************************************************************/
/* array */
@@ -104,11 +104,11 @@ STATIC mp_obj_t array_construct(char typecode, mp_obj_t initializer) {
return array;
}
STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t array_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
// get typecode
uint l;
mp_uint_t l;
const char *typecode = mp_obj_str_get_data(args[0], &l);
if (n_args == 1) {
@@ -120,7 +120,7 @@ STATIC mp_obj_t array_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
}
}
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
if (n_args == 0) {
@@ -138,7 +138,7 @@ STATIC mp_obj_t bytearray_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
}
}
STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
STATIC mp_obj_t array_unary_op(mp_uint_t op, mp_obj_t o_in) {
mp_obj_array_t *o = o_in;
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->len != 0);
@@ -147,7 +147,7 @@ STATIC mp_obj_t array_unary_op(int op, mp_obj_t o_in) {
}
}
STATIC mp_obj_t array_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC mp_obj_t array_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
switch (op) {
case MP_BINARY_OP_EQUAL: {
mp_buffer_info_t lhs_bufinfo;
@@ -223,7 +223,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
}
}
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, int flags) {
STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
mp_obj_array_t *o = o_in;
bufinfo->buf = o->items;
bufinfo->len = o->len * mp_binary_get_size('@', o->typecode, NULL);
@@ -263,7 +263,7 @@ const mp_obj_type_t mp_type_bytearray = {
.locals_dict = (mp_obj_t)&array_locals_dict,
};
STATIC mp_obj_array_t *array_new(char typecode, uint n) {
STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) {
int typecode_size = mp_binary_get_size('@', typecode, NULL);
if (typecode_size <= 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode"));
@@ -277,18 +277,18 @@ STATIC mp_obj_array_t *array_new(char typecode, uint n) {
return o;
}
uint mp_obj_array_len(mp_obj_t self_in) {
mp_uint_t mp_obj_array_len(mp_obj_t self_in) {
return ((mp_obj_array_t *)self_in)->len;
}
mp_obj_t mp_obj_new_bytearray(uint n, void *items) {
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items) {
mp_obj_array_t *o = array_new(BYTEARRAY_TYPECODE, n);
memcpy(o->items, items, n);
return o;
}
// Create bytearray which references specified memory area
mp_obj_t mp_obj_new_bytearray_by_ref(uint n, void *items) {
mp_obj_t mp_obj_new_bytearray_by_ref(mp_uint_t n, void *items) {
mp_obj_array_t *o = m_new_obj(mp_obj_array_t);
o->base.type = &mp_type_array;
o->typecode = BYTEARRAY_TYPECODE;

View File

@@ -24,4 +24,4 @@
* THE SOFTWARE.
*/
mp_obj_t mp_obj_new_bytearray(uint n, void *items);
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items);

View File

@@ -41,14 +41,22 @@ typedef struct _mp_obj_bool_t {
STATIC void bool_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bool_t *self = self_in;
if (self->value) {
print(env, "True");
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
if (self->value) {
print(env, "true");
} else {
print(env, "false");
}
} else {
print(env, "False");
if (self->value) {
print(env, "True");
} else {
print(env, "False");
}
}
}
STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t bool_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
switch (n_args) {
@@ -60,19 +68,26 @@ STATIC mp_obj_t bool_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
}
}
STATIC mp_obj_t bool_unary_op(int op, mp_obj_t o_in) {
STATIC mp_obj_t bool_unary_op(mp_uint_t op, mp_obj_t o_in) {
mp_int_t value = ((mp_obj_bool_t*)o_in)->value;
switch (op) {
case MP_UNARY_OP_BOOL: return o_in;
case MP_UNARY_OP_POSITIVE: return MP_OBJ_NEW_SMALL_INT(value);
case MP_UNARY_OP_NEGATIVE: return MP_OBJ_NEW_SMALL_INT(-value);
case MP_UNARY_OP_INVERT:
case MP_UNARY_OP_INVERT: return MP_OBJ_NEW_SMALL_INT(~value);
// only bool needs to implement MP_UNARY_OP_NOT
case MP_UNARY_OP_NOT:
default: // no other cases
return MP_OBJ_NEW_SMALL_INT(~value);
if (value) {
return mp_const_false;
} else {
return mp_const_true;
}
}
}
STATIC mp_obj_t bool_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC mp_obj_t bool_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
if (MP_BINARY_OP_OR <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(mp_obj_is_true(lhs_in)), rhs_in);
}

View File

@@ -50,7 +50,7 @@ STATIC void bound_meth_print(void (*print)(void *env, const char *fmt, ...), voi
}
#endif
mp_obj_t bound_meth_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_t bound_meth_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_obj_bound_meth_t *self = self_in;
// need to insert self->self before all other args and then call self->meth

View File

@@ -41,7 +41,7 @@ typedef struct _mp_obj_closure_t {
mp_obj_t closed[];
} mp_obj_closure_t;
mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
mp_obj_t closure_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_obj_closure_t *self = self_in;
// need to concatenate closed-over-vars and args
@@ -89,7 +89,7 @@ const mp_obj_type_t closure_type = {
.call = closure_call,
};
mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed_over, const mp_obj_t *closed) {
mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_uint_t n_closed_over, const mp_obj_t *closed) {
mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over);
o->base.type = &closure_type;
o->fun = fun;

View File

@@ -25,6 +25,7 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "mpconfig.h"
@@ -55,26 +56,31 @@ mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag);
STATIC void complex_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_complex_t *o = o_in;
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
char buf[32];
char buf[16];
if (o->real == 0) {
format_float(o->imag, buf, sizeof(buf), 'g', 6, '\0');
format_float(o->imag, buf, sizeof(buf), 'g', 7, '\0');
print(env, "%sj", buf);
} else {
format_float(o->real, buf, sizeof(buf), 'g', 6, '\0');
format_float(o->real, buf, sizeof(buf), 'g', 7, '\0');
print(env, "(%s+", buf);
format_float(o->imag, buf, sizeof(buf), 'g', 6, '\0');
format_float(o->imag, buf, sizeof(buf), 'g', 7, '\0');
print(env, "%sj)", buf);
}
#else
char buf[32];
if (o->real == 0) {
print(env, "%.8gj", (double) o->imag);
sprintf(buf, "%.16g", (double)o->imag);
print(env, "%sj", buf);
} else {
print(env, "(%.8g+%.8gj)", (double) o->real, (double) o->imag);
sprintf(buf, "%.16g", (double)o->real);
print(env, "(%s+", buf);
sprintf(buf, "%.16g", (double)o->imag);
print(env, "%sj)", buf);
}
#endif
}
STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t complex_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 2, false);
switch (n_args) {
@@ -84,7 +90,7 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
case 1:
if (MP_OBJ_IS_STR(args[0])) {
// a string, parse it
uint l;
mp_uint_t l;
const char *s = mp_obj_str_get_data(args[0], &l);
return mp_parse_num_decimal(s, l, true, true);
} else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
@@ -117,7 +123,7 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
}
}
STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
STATIC mp_obj_t complex_unary_op(mp_uint_t op, mp_obj_t o_in) {
mp_obj_complex_t *o = o_in;
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(o->real != 0 || o->imag != 0);
@@ -127,7 +133,7 @@ STATIC mp_obj_t complex_unary_op(int op, mp_obj_t o_in) {
}
}
STATIC mp_obj_t complex_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC mp_obj_t complex_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_complex_t *lhs = lhs_in;
return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
}
@@ -166,7 +172,7 @@ void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) {
*imag = self->imag;
}
mp_obj_t mp_obj_complex_binary_op(int op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) {
mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) {
mp_float_t rhs_real, rhs_imag;
mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible)
switch (op) {

View File

@@ -38,29 +38,47 @@
#include "runtime.h"
#include "builtin.h"
STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur);
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in);
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs);
STATIC mp_obj_t dict_update(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
// This is a helper function to iterate through a dictionary. The state of
// the iteration is held in *cur and should be initialised with zero for the
// first call. Will return NULL when no more elements are available.
STATIC mp_map_elem_t *dict_iter_next(mp_obj_dict_t *dict, mp_uint_t *cur) {
mp_uint_t max = dict->map.alloc;
mp_map_t *map = &dict->map;
for (mp_uint_t i = *cur; i < max; i++) {
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
*cur = i + 1;
return &(map->table[i]);
}
}
return NULL;
}
STATIC void dict_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_dict_t *self = self_in;
bool first = true;
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
}
print(env, "{");
mp_obj_t *dict_iter = mp_obj_new_dict_iterator(self, 0);
mp_uint_t cur = 0;
mp_map_elem_t *next = NULL;
while ((next = dict_it_iternext_elem(dict_iter)) != MP_OBJ_STOP_ITERATION) {
while ((next = dict_iter_next(self, &cur)) != NULL) {
if (!first) {
print(env, ", ");
}
first = false;
mp_obj_print_helper(print, env, next->key, PRINT_REPR);
mp_obj_print_helper(print, env, next->key, kind);
print(env, ": ");
mp_obj_print_helper(print, env, next->value, PRINT_REPR);
mp_obj_print_helper(print, env, next->value, kind);
}
print(env, "}");
}
STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t dict_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_obj_t dict = mp_obj_new_dict(0);
if (n_args > 0 || n_kw > 0) {
mp_obj_t args2[2] = {dict, args[0]}; // args[0] is always valid, even if it's not a positional arg
@@ -71,7 +89,7 @@ STATIC mp_obj_t dict_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp
return dict;
}
STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
STATIC mp_obj_t dict_unary_op(mp_uint_t op, mp_obj_t self_in) {
mp_obj_dict_t *self = self_in;
switch (op) {
case MP_UNARY_OP_BOOL: return MP_BOOL(self->map.used != 0);
@@ -80,7 +98,7 @@ STATIC mp_obj_t dict_unary_op(int op, mp_obj_t self_in) {
}
}
STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC mp_obj_t dict_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_dict_t *o = lhs_in;
switch (op) {
case MP_BINARY_OP_IN: {
@@ -94,15 +112,12 @@ STATIC mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
return mp_const_false;
}
mp_uint_t size = o->map.alloc;
mp_map_t *map = &o->map;
for (mp_uint_t i = 0; i < size; i++) {
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, map->table[i].key, MP_MAP_LOOKUP);
if (elem == NULL || !mp_obj_equal(map->table[i].value, elem->value)) {
return mp_const_false;
}
mp_uint_t cur = 0;
mp_map_elem_t *next = NULL;
while ((next = dict_iter_next(o, &cur)) != NULL) {
mp_map_elem_t *elem = mp_map_lookup(&rhs->map, next->key, MP_MAP_LOOKUP);
if (elem == NULL || !mp_obj_equal(next->value, elem->value)) {
return mp_const_false;
}
}
return mp_const_true;
@@ -158,28 +173,14 @@ typedef struct _mp_obj_dict_it_t {
mp_uint_t cur;
} mp_obj_dict_it_t;
STATIC mp_map_elem_t *dict_it_iternext_elem(mp_obj_t self_in) {
STATIC mp_obj_t dict_it_iternext(mp_obj_t self_in) {
mp_obj_dict_it_t *self = self_in;
mp_uint_t max = self->dict->map.alloc;
mp_map_t *map = &self->dict->map;
mp_map_elem_t *next = dict_iter_next(self->dict, &self->cur);
for (int i = self->cur; i < max; i++) {
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
self->cur = i + 1;
return &(map->table[i]);
}
}
return MP_OBJ_STOP_ITERATION;
}
mp_obj_t dict_it_iternext(mp_obj_t self_in) {
mp_map_elem_t *next = dict_it_iternext_elem(self_in);
if (next != MP_OBJ_STOP_ITERATION) {
return next->key;
} else {
if (next == NULL) {
return MP_OBJ_STOP_ITERATION;
} else {
return next->key;
}
}
@@ -190,18 +191,14 @@ STATIC const mp_obj_type_t mp_type_dict_it = {
.iternext = dict_it_iternext,
};
STATIC mp_obj_t mp_obj_new_dict_iterator(mp_obj_dict_t *dict, int cur) {
STATIC mp_obj_t dict_getiter(mp_obj_t o_in) {
mp_obj_dict_it_t *o = m_new_obj(mp_obj_dict_it_t);
o->base.type = &mp_type_dict_it;
o->dict = dict;
o->cur = cur;
o->dict = o_in;
o->cur = 0;
return o;
}
STATIC mp_obj_t dict_getiter(mp_obj_t o_in) {
return mp_obj_new_dict_iterator(o_in, 0);
}
/******************************************************************************/
/* dict methods */
@@ -228,7 +225,7 @@ STATIC mp_obj_t dict_copy(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
// this is a classmethod
STATIC mp_obj_t dict_fromkeys(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t dict_fromkeys(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args && n_args <= 3);
mp_obj_t iter = mp_getiter(args[1]);
mp_obj_t len = mp_obj_len_maybe(iter);
@@ -259,8 +256,8 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, (const mp_obj_t)&dict_
STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp_map_lookup_kind_t lookup_kind) {
mp_map_elem_t *elem = mp_map_lookup(self, key, lookup_kind);
mp_obj_t value;
if (elem == NULL || elem->value == NULL) {
if (deflt == NULL) {
if (elem == NULL || elem->value == MP_OBJ_NULL) {
if (deflt == MP_OBJ_NULL) {
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "<value>"));
} else {
@@ -269,45 +266,48 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp
} else {
value = deflt;
}
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
elem->value = value;
}
} else {
value = elem->value;
}
if (lookup_kind == MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
elem->value = value;
if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) {
elem->value = MP_OBJ_NULL; // so that GC can collect the deleted value
}
}
return value;
}
STATIC mp_obj_t dict_get(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t dict_get(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args && n_args <= 3);
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
args[1],
n_args == 3 ? args[2] : NULL,
n_args == 3 ? args[2] : MP_OBJ_NULL,
MP_MAP_LOOKUP);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get);
STATIC mp_obj_t dict_pop(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t dict_pop(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args && n_args <= 3);
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
args[1],
n_args == 3 ? args[2] : NULL,
n_args == 3 ? args[2] : MP_OBJ_NULL,
MP_MAP_LOOKUP_REMOVE_IF_FOUND);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop);
STATIC mp_obj_t dict_setdefault(uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t dict_setdefault(mp_uint_t n_args, const mp_obj_t *args) {
assert(2 <= n_args && n_args <= 3);
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
return dict_get_helper(&((mp_obj_dict_t *)args[0])->map,
args[1],
n_args == 3 ? args[2] : NULL,
n_args == 3 ? args[2] : MP_OBJ_NULL,
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setdefault);
@@ -316,23 +316,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde
STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict));
mp_obj_dict_t *self = self_in;
if (self->map.used == 0) {
mp_uint_t cur = 0;
mp_map_elem_t *next = dict_iter_next(self, &cur);
if (next == NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty"));
}
mp_obj_dict_it_t *iter = mp_obj_new_dict_iterator(self, 0);
mp_map_elem_t *next = dict_it_iternext_elem(iter);
self->map.used--;
mp_obj_t items[] = {next->key, next->value};
next->key = NULL;
next->value = NULL;
next->key = MP_OBJ_SENTINEL; // must mark key as sentinel to indicate that it was deleted
next->value = MP_OBJ_NULL;
mp_obj_t tuple = mp_obj_new_tuple(2, items);
return tuple;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
STATIC mp_obj_t dict_update(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
assert(MP_OBJ_IS_TYPE(args[0], &mp_type_dict));
mp_obj_dict_t *self = args[0];
@@ -344,10 +343,9 @@ STATIC mp_obj_t dict_update(uint n_args, const mp_obj_t *args, mp_map_t *kwargs)
if (MP_OBJ_IS_TYPE(args[1], &mp_type_dict)) {
// update from other dictionary (make sure other is not self)
if (args[1] != self) {
// TODO don't allocate heap object for this iterator
mp_obj_t *dict_iter = mp_obj_new_dict_iterator(args[1], 0);
mp_uint_t cur = 0;
mp_map_elem_t *elem = NULL;
while ((elem = dict_it_iternext_elem(dict_iter)) != MP_OBJ_STOP_ITERATION) {
while ((elem = dict_iter_next((mp_obj_dict_t*)args[1], &cur)) != NULL) {
mp_map_lookup(&self->map, elem->key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = elem->value;
}
}
@@ -402,7 +400,7 @@ STATIC char *mp_dict_view_names[] = {"dict_items", "dict_keys", "dict_values"};
typedef struct _mp_obj_dict_view_it_t {
mp_obj_base_t base;
mp_dict_view_kind_t kind;
mp_obj_dict_it_t *iter;
mp_obj_dict_t *dict;
mp_uint_t cur;
} mp_obj_dict_view_it_t;
@@ -415,9 +413,11 @@ typedef struct _mp_obj_dict_view_t {
STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type));
mp_obj_dict_view_it_t *self = self_in;
mp_map_elem_t *next = dict_it_iternext_elem(self->iter);
mp_map_elem_t *next = dict_iter_next(self->dict, &self->cur);
if (next != MP_OBJ_STOP_ITERATION) {
if (next == NULL) {
return MP_OBJ_STOP_ITERATION;
} else {
switch (self->kind) {
case MP_DICT_VIEW_ITEMS:
{
@@ -432,8 +432,6 @@ STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
assert(0); /* can't happen */
return mp_const_none;
}
} else {
return MP_OBJ_STOP_ITERATION;
}
}
@@ -450,7 +448,8 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in) {
mp_obj_dict_view_it_t *o = m_new_obj(mp_obj_dict_view_it_t);
o->base.type = &dict_view_it_type;
o->kind = view->kind;
o->iter = mp_obj_new_dict_iterator(view->dict, 0);
o->dict = view->dict;
o->cur = 0;
return o;
}
@@ -472,7 +471,7 @@ STATIC void dict_view_print(void (*print)(void *env, const char *fmt, ...), void
print(env, "])");
}
STATIC mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
STATIC mp_obj_t dict_view_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// only supported for the 'keys' kind until sets and dicts are refactored
mp_obj_dict_view_t *o = lhs_in;
if (o->kind != MP_DICT_VIEW_KEYS) {
@@ -555,18 +554,18 @@ const mp_obj_type_t mp_type_dict = {
.locals_dict = (mp_obj_t)&dict_locals_dict,
};
void mp_obj_dict_init(mp_obj_dict_t *dict, int n_args) {
void mp_obj_dict_init(mp_obj_dict_t *dict, mp_uint_t n_args) {
dict->base.type = &mp_type_dict;
mp_map_init(&dict->map, n_args);
}
mp_obj_t mp_obj_new_dict(int n_args) {
mp_obj_t mp_obj_new_dict(mp_uint_t n_args) {
mp_obj_dict_t *o = m_new_obj(mp_obj_dict_t);
mp_obj_dict_init(o, n_args);
return o;
}
uint mp_obj_dict_len(mp_obj_t self_in) {
mp_uint_t mp_obj_dict_len(mp_obj_t self_in) {
return ((mp_obj_dict_t *)self_in)->map.used;
}
@@ -580,7 +579,7 @@ mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_dict));
mp_obj_dict_t *self = self_in;
dict_get_helper(&self->map, key, NULL, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
dict_get_helper(&self->map, key, MP_OBJ_NULL, MP_MAP_LOOKUP_REMOVE_IF_FOUND);
return self_in;
}

View File

@@ -47,7 +47,7 @@ STATIC const mp_arg_t enumerate_make_new_args[] = {
};
#define ENUMERATE_MAKE_NEW_NUM_ARGS MP_ARRAY_SIZE(enumerate_make_new_args)
STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
STATIC mp_obj_t enumerate_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
#if MICROPY_CPYTHON_COMPAT
// parse args
mp_arg_val_t vals[ENUMERATE_MAKE_NEW_NUM_ARGS];

Some files were not shown because too many files have changed in this diff Show More