mirror of
https://github.com/micropython/micropython.git
synced 2025-12-26 23:00:16 +01:00
Compare commits
679 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55a5b80793 | ||
|
|
cde0ca21bf | ||
|
|
d19c256656 | ||
|
|
6162bea5b2 | ||
|
|
4f449120e1 | ||
|
|
2234c3f23d | ||
|
|
4bcd04bcad | ||
|
|
16ef60fba6 | ||
|
|
b0261341d3 | ||
|
|
ac04a8a56a | ||
|
|
e8ea0724da | ||
|
|
3fafe730d3 | ||
|
|
53d5fa641f | ||
|
|
52b5d76a6b | ||
|
|
d6230f62c7 | ||
|
|
96e20c600f | ||
|
|
5a5555e385 | ||
|
|
9f53275042 | ||
|
|
fa6567a39f | ||
|
|
eaaebf3291 | ||
|
|
8afb9b3863 | ||
|
|
1fae787493 | ||
|
|
8c41920a90 | ||
|
|
2c180f7ccc | ||
|
|
df1e92ba3a | ||
|
|
fa2f1f72e0 | ||
|
|
89e4657c69 | ||
|
|
c95359ecc6 | ||
|
|
0e58c5810d | ||
|
|
becbc87fd7 | ||
|
|
2842945e76 | ||
|
|
8bb44f69f2 | ||
|
|
3d61528fe7 | ||
|
|
612045f53f | ||
|
|
8a9b999f1c | ||
|
|
1d7fb82f0a | ||
|
|
6ff42c54bb | ||
|
|
09de030651 | ||
|
|
d4a799f152 | ||
|
|
b92cbe6129 | ||
|
|
83695596ed | ||
|
|
8594ce2280 | ||
|
|
5c6783496d | ||
|
|
32781cce6d | ||
|
|
5792500ccc | ||
|
|
bb29546868 | ||
|
|
89ab3be0b1 | ||
|
|
20beff9ae3 | ||
|
|
5f0c18e583 | ||
|
|
d60580eb5e | ||
|
|
2b4af54992 | ||
|
|
81b2ddf5d1 | ||
|
|
953074315e | ||
|
|
6eae861685 | ||
|
|
7ff996c237 | ||
|
|
377b80b624 | ||
|
|
5c00757a5c | ||
|
|
013d53c0b4 | ||
|
|
e2a618615d | ||
|
|
c7687ad7e6 | ||
|
|
a2f55fe12b | ||
|
|
6c9c7bc75a | ||
|
|
c8c44a4c2e | ||
|
|
8105736982 | ||
|
|
25d904105c | ||
|
|
91fe0d4880 | ||
|
|
03281b3850 | ||
|
|
c90f59ec3a | ||
|
|
33b50a0217 | ||
|
|
c7a79284bb | ||
|
|
e6ce10a3e7 | ||
|
|
78fde4819c | ||
|
|
722e562736 | ||
|
|
17598d49e1 | ||
|
|
8002d5d2b9 | ||
|
|
9a21d2e070 | ||
|
|
afb1cf75dd | ||
|
|
e191d42188 | ||
|
|
b534e1b9f1 | ||
|
|
dda46460ff | ||
|
|
a669cbc690 | ||
|
|
91fbea2c1e | ||
|
|
b7235b8412 | ||
|
|
fc54250d31 | ||
|
|
27dd910c44 | ||
|
|
e875e3882d | ||
|
|
bc9f34860b | ||
|
|
759138caee | ||
|
|
8c56241c82 | ||
|
|
bad2df3e95 | ||
|
|
bcf041f1a3 | ||
|
|
cdd40f149a | ||
|
|
9091e84454 | ||
|
|
7da9145e47 | ||
|
|
0c0550bff0 | ||
|
|
79d17e3e7d | ||
|
|
812cf62f43 | ||
|
|
71224cb8db | ||
|
|
e07737d202 | ||
|
|
90fad65d2f | ||
|
|
76dd7e180f | ||
|
|
ca6d75f16d | ||
|
|
4abff7500f | ||
|
|
4d91723587 | ||
|
|
d182b98a37 | ||
|
|
9c4cbe2ac0 | ||
|
|
93965e726f | ||
|
|
1c70cbf151 | ||
|
|
ecc88e949c | ||
|
|
4d3fc46326 | ||
|
|
8707ea3421 | ||
|
|
17ae2395c2 | ||
|
|
02d95d7ce9 | ||
|
|
eb4e18f057 | ||
|
|
15d2fe8da4 | ||
|
|
110ba35980 | ||
|
|
1ac6faa732 | ||
|
|
516b09efc3 | ||
|
|
b796e3d848 | ||
|
|
16ee30c6fa | ||
|
|
fe3d16e8c2 | ||
|
|
a97e091d4e | ||
|
|
a75b02ea9b | ||
|
|
ad4c014d46 | ||
|
|
b7f7c655ed | ||
|
|
f3c3010ffc | ||
|
|
b427d6ae86 | ||
|
|
f05b87bd63 | ||
|
|
3b72da674e | ||
|
|
6cf8dd4f51 | ||
|
|
e00fb08f99 | ||
|
|
f4ce26de5c | ||
|
|
db63660c19 | ||
|
|
3bb7efc943 | ||
|
|
cd021bfe56 | ||
|
|
779794a680 | ||
|
|
fa1a9bc9fd | ||
|
|
994bb4a839 | ||
|
|
34e43c7ee9 | ||
|
|
3475b04101 | ||
|
|
29c92a407c | ||
|
|
2bf044442e | ||
|
|
8c0add4eee | ||
|
|
e5cbb70328 | ||
|
|
9480138f0c | ||
|
|
7310fd469a | ||
|
|
1d8a06406a | ||
|
|
2c4e67e32d | ||
|
|
3d945559d4 | ||
|
|
c668d51b08 | ||
|
|
8ba832456e | ||
|
|
6678595e7e | ||
|
|
3c658a4e75 | ||
|
|
25fc41dd31 | ||
|
|
4f9ebade60 | ||
|
|
72b115cbaa | ||
|
|
26a0d4f4f1 | ||
|
|
69b7dae362 | ||
|
|
d5e7f6e37e | ||
|
|
13ec400f28 | ||
|
|
7fe2191c9b | ||
|
|
86de21b810 | ||
|
|
339bdccc58 | ||
|
|
3688414d9d | ||
|
|
8f81b5cb4b | ||
|
|
b63be37be1 | ||
|
|
b0accc8571 | ||
|
|
d779b9642f | ||
|
|
244476e3e6 | ||
|
|
c84aa41990 | ||
|
|
f0c3a7e781 | ||
|
|
6009309c33 | ||
|
|
e6c0dff967 | ||
|
|
a5190a7dac | ||
|
|
2ac4af6946 | ||
|
|
6be0b0a8ec | ||
|
|
bf133f7737 | ||
|
|
2c781eabbd | ||
|
|
9b7a8ee8f1 | ||
|
|
8cce8b7c4c | ||
|
|
9d02780eaf | ||
|
|
1ddd844815 | ||
|
|
5073d3da07 | ||
|
|
8882c20b8f | ||
|
|
510296f25a | ||
|
|
75ec22bf11 | ||
|
|
105e32f1a5 | ||
|
|
f20375eedd | ||
|
|
bb91f1195a | ||
|
|
4c03b3a899 | ||
|
|
69c5fe1df6 | ||
|
|
2eb1f604ee | ||
|
|
7703d71938 | ||
|
|
9749b2fb0d | ||
|
|
2eeeafcba5 | ||
|
|
6e6bcccdc1 | ||
|
|
101d87da6a | ||
|
|
0c5498540b | ||
|
|
ecca53bd34 | ||
|
|
2831a8f800 | ||
|
|
4ef26c14b1 | ||
|
|
30dd23aa7f | ||
|
|
0c64c634ca | ||
|
|
c4ee39dd63 | ||
|
|
5f930337bc | ||
|
|
7133d91773 | ||
|
|
5f47ebbf82 | ||
|
|
2605df3346 | ||
|
|
04019e365f | ||
|
|
590b2abdfc | ||
|
|
ea439e59d9 | ||
|
|
ef7a066c9c | ||
|
|
4162271181 | ||
|
|
b92e7533d3 | ||
|
|
284efa89ae | ||
|
|
4b67463be1 | ||
|
|
5b7c0c437b | ||
|
|
196773505a | ||
|
|
a1d3ee376c | ||
|
|
6f418fc1b0 | ||
|
|
5d9b816449 | ||
|
|
3ef911345c | ||
|
|
8a11d693cf | ||
|
|
2fe2a05f9f | ||
|
|
95ea4f0c95 | ||
|
|
7cc20e7e99 | ||
|
|
56da07dcfa | ||
|
|
dd07023cb7 | ||
|
|
6c70511835 | ||
|
|
0538a203e5 | ||
|
|
2e3e8b2f69 | ||
|
|
ccacdf44b6 | ||
|
|
8dbbbbc793 | ||
|
|
aa6228eaf5 | ||
|
|
ecb5792f88 | ||
|
|
8362bffb2e | ||
|
|
ce23f67d9e | ||
|
|
e40c72210f | ||
|
|
2e41646eb7 | ||
|
|
87bbb388db | ||
|
|
71bed1a9a7 | ||
|
|
8464be15ed | ||
|
|
f8f963a14a | ||
|
|
65dd7bc13d | ||
|
|
5aac6aa445 | ||
|
|
4747becc64 | ||
|
|
8cc2018d47 | ||
|
|
c9aa58e638 | ||
|
|
bb4c6f35c6 | ||
|
|
fa1ecda3fd | ||
|
|
3c4db9f91c | ||
|
|
5f27a7e811 | ||
|
|
94fbe9711a | ||
|
|
07133415d2 | ||
|
|
d0f5e61ab5 | ||
|
|
645582fe14 | ||
|
|
adf0f2ae1a | ||
|
|
5b7fd20fea | ||
|
|
05c255f039 | ||
|
|
ffe911d228 | ||
|
|
1bbdd4ed2a | ||
|
|
4ecb700fe3 | ||
|
|
e1b1abc1e8 | ||
|
|
de993f4573 | ||
|
|
7cfae9693b | ||
|
|
3e0bce3587 | ||
|
|
7a03b5f56a | ||
|
|
86f0b31bcf | ||
|
|
1d8816c36b | ||
|
|
a2e7a1315d | ||
|
|
512465bc66 | ||
|
|
721d6240c9 | ||
|
|
4038f513ea | ||
|
|
951ed9d02f | ||
|
|
1163cb9cb5 | ||
|
|
cb66f41ebc | ||
|
|
04c9fec7d1 | ||
|
|
2c0701101b | ||
|
|
1694bc733d | ||
|
|
02bc882c3d | ||
|
|
0f4ee2e44a | ||
|
|
5467186b0e | ||
|
|
e3737b858a | ||
|
|
a4022c92f0 | ||
|
|
a50494ab68 | ||
|
|
db56ad2915 | ||
|
|
73ab8cc21d | ||
|
|
ef204733d6 | ||
|
|
0429d35f37 | ||
|
|
04f5ae1d1c | ||
|
|
4d9dd26818 | ||
|
|
dce8876dbe | ||
|
|
ac736f15c9 | ||
|
|
122c9db3db | ||
|
|
a1760a56ff | ||
|
|
b82f34edde | ||
|
|
2cf381081a | ||
|
|
564e46452d | ||
|
|
58c9586c34 | ||
|
|
847a6b30b1 | ||
|
|
e687fdbcbc | ||
|
|
2097c8b1e1 | ||
|
|
8215847b4d | ||
|
|
42b6419056 | ||
|
|
594699bc88 | ||
|
|
90ba80dc36 | ||
|
|
5fa5ca40e6 | ||
|
|
539681fffd | ||
|
|
0182385ab0 | ||
|
|
4e0eeebdc2 | ||
|
|
381618269a | ||
|
|
54eb4e723e | ||
|
|
40f3c02682 | ||
|
|
065aba5875 | ||
|
|
e4e55047b3 | ||
|
|
5e6419cb11 | ||
|
|
e70b5dbe58 | ||
|
|
92a47b4dae | ||
|
|
9cd96cf25d | ||
|
|
f83debc716 | ||
|
|
7a37f647a5 | ||
|
|
5fc580475f | ||
|
|
f0b29729aa | ||
|
|
f065344d3b | ||
|
|
aa47f3968b | ||
|
|
2fe841d2fa | ||
|
|
caa7334141 | ||
|
|
e95b6b5e07 | ||
|
|
0d81c133b3 | ||
|
|
5d44e6a92c | ||
|
|
4039a26679 | ||
|
|
b601d9574a | ||
|
|
5813efd634 | ||
|
|
bb35f425f9 | ||
|
|
c10a4405cd | ||
|
|
a23475979b | ||
|
|
ec6fa8732b | ||
|
|
8139494e54 | ||
|
|
9e215fa4c2 | ||
|
|
a62da515af | ||
|
|
5478ed18ea | ||
|
|
b1b840554d | ||
|
|
635b60e299 | ||
|
|
8546ce1e28 | ||
|
|
41736f8201 | ||
|
|
e04a44e2f6 | ||
|
|
b3a50f0f3e | ||
|
|
8993fb6cf0 | ||
|
|
7e4ec3bf4f | ||
|
|
81df1e6c98 | ||
|
|
cb78f862cb | ||
|
|
0a1ea40273 | ||
|
|
8a96ebea75 | ||
|
|
64c58403ef | ||
|
|
a75e382a9b | ||
|
|
3c8ce38d20 | ||
|
|
3659af97c5 | ||
|
|
ed07d035d5 | ||
|
|
f5f6c3b792 | ||
|
|
ce81312d8a | ||
|
|
63143c94ce | ||
|
|
ea2c936c7e | ||
|
|
26fda6dc8e | ||
|
|
00c904b47a | ||
|
|
1044c3dfe6 | ||
|
|
b1949e4c09 | ||
|
|
5048df0b7c | ||
|
|
46d31e9ca9 | ||
|
|
ded0fc77f7 | ||
|
|
17994d1bd3 | ||
|
|
79b7fe2ee5 | ||
|
|
cdc020da4b | ||
|
|
e7f2b4c875 | ||
|
|
86d3898e70 | ||
|
|
d215ee1dc1 | ||
|
|
9731912ccb | ||
|
|
165eb69b86 | ||
|
|
42a52516fe | ||
|
|
2ba2299d28 | ||
|
|
1e3781bc35 | ||
|
|
9a1a4beb56 | ||
|
|
64b468d873 | ||
|
|
83865347db | ||
|
|
c88987c1af | ||
|
|
12bc13eeb8 | ||
|
|
16ac4962ae | ||
|
|
7a8ab5a730 | ||
|
|
23668698cb | ||
|
|
91b576d147 | ||
|
|
f170735b73 | ||
|
|
f3de62e6c2 | ||
|
|
8e01291c18 | ||
|
|
7a2f166949 | ||
|
|
39b6e27944 | ||
|
|
5aa740c3e2 | ||
|
|
e973acde81 | ||
|
|
939c2e7f44 | ||
|
|
3c9b24bebe | ||
|
|
141df2d350 | ||
|
|
780e54cdc3 | ||
|
|
cd590cbfaa | ||
|
|
ff5932a8d8 | ||
|
|
949a49c9da | ||
|
|
69d0a1c540 | ||
|
|
de5ce6d461 | ||
|
|
8abcf666cb | ||
|
|
a96cc824bd | ||
|
|
59c675a64c | ||
|
|
89b38d96c9 | ||
|
|
5c8db48541 | ||
|
|
4c4b9d15ab | ||
|
|
0fc7efb663 | ||
|
|
17a49431d4 | ||
|
|
7cd46a12ae | ||
|
|
7e56e55252 | ||
|
|
eecf3e90c6 | ||
|
|
2099b6897f | ||
|
|
f605172d2b | ||
|
|
3b6f7b95eb | ||
|
|
7efbd325bb | ||
|
|
09e3f8f0d1 | ||
|
|
b6af4c8104 | ||
|
|
74c710187c | ||
|
|
59ced651b5 | ||
|
|
17db096505 | ||
|
|
e53d2197e4 | ||
|
|
f6932d6506 | ||
|
|
bf3366a48b | ||
|
|
fe81eea967 | ||
|
|
b0851e5949 | ||
|
|
c3cabf4e33 | ||
|
|
afc67c6dc5 | ||
|
|
9acb5e4cf0 | ||
|
|
def10cecd1 | ||
|
|
720f55cc4b | ||
|
|
bcb3ab451b | ||
|
|
535b88133c | ||
|
|
bbcea3f62b | ||
|
|
4f1b7fec9f | ||
|
|
2547928148 | ||
|
|
c0711cbefa | ||
|
|
e79c6696c5 | ||
|
|
34ab8dd6dd | ||
|
|
0294661da5 | ||
|
|
812025bd83 | ||
|
|
5f6f47a688 | ||
|
|
00db5c81e1 | ||
|
|
34e7b67d3c | ||
|
|
e3cfc0d33d | ||
|
|
7ddbd1bee7 | ||
|
|
b0bb458810 | ||
|
|
2ec38a17d4 | ||
|
|
e9036c295c | ||
|
|
c037694957 | ||
|
|
63b2237323 | ||
|
|
e22cddbe2a | ||
|
|
f33385f56d | ||
|
|
8340c48389 | ||
|
|
fbdf2f1d63 | ||
|
|
8a0801ad24 | ||
|
|
73c98d8709 | ||
|
|
0c0f446840 | ||
|
|
f4bf065dac | ||
|
|
5f4a667ea4 | ||
|
|
f77d0c5bb3 | ||
|
|
49df795d1d | ||
|
|
820896746c | ||
|
|
b7572ad11b | ||
|
|
58cbb4d661 | ||
|
|
62f7ba7a81 | ||
|
|
1f44e118f0 | ||
|
|
195de3247b | ||
|
|
639863d36e | ||
|
|
57b4dfa9c9 | ||
|
|
26a95ae1e7 | ||
|
|
4297fed1c3 | ||
|
|
70c289a7a6 | ||
|
|
4480cb3711 | ||
|
|
df896eceef | ||
|
|
9e951498b2 | ||
|
|
049a7a8153 | ||
|
|
c06427c019 | ||
|
|
b4efac14cd | ||
|
|
d31a093f9c | ||
|
|
5473f743f3 | ||
|
|
f0778a7ccb | ||
|
|
b9b9354e6c | ||
|
|
7e4a2b0edc | ||
|
|
aabd83ea20 | ||
|
|
82ed3d62f6 | ||
|
|
a9b5248e18 | ||
|
|
dc931934b3 | ||
|
|
585a3394df | ||
|
|
0c90eb1658 | ||
|
|
8ffc02495f | ||
|
|
c61be8e1e1 | ||
|
|
180751fbf3 | ||
|
|
de09caaa37 | ||
|
|
d72bc2713a | ||
|
|
b56a53dfd6 | ||
|
|
8c75bd26e2 | ||
|
|
b69f9fa31f | ||
|
|
380f147d2e | ||
|
|
a3ef8087e8 | ||
|
|
047db2299c | ||
|
|
88b11b50e5 | ||
|
|
755a55f507 | ||
|
|
d4c2bddd0c | ||
|
|
f675ff3957 | ||
|
|
11de8399fe | ||
|
|
daf973ae00 | ||
|
|
c074cd38c3 | ||
|
|
75ce9256b2 | ||
|
|
7a6e09635a | ||
|
|
df3ab07994 | ||
|
|
1e82ef3ae8 | ||
|
|
76c8a4c91b | ||
|
|
9ab8ab2117 | ||
|
|
30583f58d5 | ||
|
|
95fd3528c1 | ||
|
|
9b967dd3cd | ||
|
|
4867413e69 | ||
|
|
82560fce75 | ||
|
|
29bf7393c1 | ||
|
|
0a1dbfe02f | ||
|
|
c3c353d7f1 | ||
|
|
3d5ffa8318 | ||
|
|
b294a7e3c9 | ||
|
|
3f52262465 | ||
|
|
65ec33200a | ||
|
|
bcb6ca4d5e | ||
|
|
07995e9479 | ||
|
|
411732e93b | ||
|
|
b8f117dd32 | ||
|
|
d3439d0c60 | ||
|
|
509c7a7854 | ||
|
|
4e0573e5cf | ||
|
|
f753971e5d | ||
|
|
a4ac5b9f05 | ||
|
|
dd0dee3afc | ||
|
|
2abfeebf4a | ||
|
|
65a97e8d9c | ||
|
|
586f02a015 | ||
|
|
a5892a13b4 | ||
|
|
a7d963d171 | ||
|
|
d7da92a8f0 | ||
|
|
8db7804496 | ||
|
|
569aa90137 | ||
|
|
8bf8404c15 | ||
|
|
b325d25e46 | ||
|
|
62798831be | ||
|
|
b55a59de4c | ||
|
|
517f292c8d | ||
|
|
15a5738e1d | ||
|
|
fcc9cf63f1 | ||
|
|
f1dbd78b30 | ||
|
|
9500e98433 | ||
|
|
f917f06384 | ||
|
|
c49ddb9315 | ||
|
|
3ebd4d0cae | ||
|
|
fb510b3bf9 | ||
|
|
c60a261ef0 | ||
|
|
c7969857f4 | ||
|
|
1b87d1098a | ||
|
|
f94cc975a2 | ||
|
|
fa82aa81c0 | ||
|
|
6c13d7965e | ||
|
|
4d659f566f | ||
|
|
6e18835b94 | ||
|
|
a053e37b2c | ||
|
|
e7412ab37b | ||
|
|
5b5562c1d1 | ||
|
|
049a01d148 | ||
|
|
b4ebad3310 | ||
|
|
b16523aa95 | ||
|
|
ff8da0b835 | ||
|
|
ae9c82d5f3 | ||
|
|
f69b9d379c | ||
|
|
69a8b23651 | ||
|
|
a3f4b83018 | ||
|
|
b5fb9b22e2 | ||
|
|
1f07b7e3c3 | ||
|
|
3dfa76cb85 | ||
|
|
914bcf16d8 | ||
|
|
b30a777ace | ||
|
|
347b3a3d1f | ||
|
|
50b08c920a | ||
|
|
ccd0e0afcd | ||
|
|
25c84643b6 | ||
|
|
8827682b35 | ||
|
|
bcdffe53c6 | ||
|
|
059f95b2cb | ||
|
|
97953f6ce7 | ||
|
|
f55cf10101 | ||
|
|
48d641e41a | ||
|
|
d1e355ea8e | ||
|
|
813ed3bda6 | ||
|
|
503d611033 | ||
|
|
1d567592b1 | ||
|
|
8ac3b578e5 | ||
|
|
168a9ce863 | ||
|
|
ae13758dd7 | ||
|
|
4de2fe10b4 | ||
|
|
34c24a0fc2 | ||
|
|
6e76f7bc90 | ||
|
|
0405b2210d | ||
|
|
d07bf029b7 | ||
|
|
d8675541a9 | ||
|
|
f600a6a085 | ||
|
|
2617eebf2f | ||
|
|
f88fc7bd23 | ||
|
|
5042bce8fb | ||
|
|
5fd5af98d0 | ||
|
|
de4b9329f9 | ||
|
|
3aaabd11a0 | ||
|
|
ff4b6daa4f | ||
|
|
2705f4c782 | ||
|
|
69d081a7cf | ||
|
|
afaaf535e6 | ||
|
|
7a4ddd2428 | ||
|
|
ee3fd46f13 | ||
|
|
d0ceb04b90 | ||
|
|
d098c6bf85 | ||
|
|
561789d718 | ||
|
|
806ea1f6ca | ||
|
|
0c937fa25a | ||
|
|
efaef6eea3 | ||
|
|
90886807a1 | ||
|
|
58ebde4664 | ||
|
|
a8408a8abe | ||
|
|
6a410789b8 | ||
|
|
aa7cf6f72f | ||
|
|
63436ce22e | ||
|
|
0fd01683c6 | ||
|
|
6ac5dced24 | ||
|
|
6d197740cf | ||
|
|
008343f640 | ||
|
|
053765414c | ||
|
|
32acd4b9f1 | ||
|
|
44a949d58c | ||
|
|
9e29666bf9 | ||
|
|
52386cafa0 | ||
|
|
66ab571cca | ||
|
|
13684fd60b | ||
|
|
eee31288dd | ||
|
|
2de4d59171 | ||
|
|
f905ebb173 | ||
|
|
404f7cf902 | ||
|
|
9bf4f7e3d3 | ||
|
|
7ae8e4b679 | ||
|
|
5cdff5fa61 | ||
|
|
7ba0fedf13 | ||
|
|
bf27140193 | ||
|
|
ab7bf28489 | ||
|
|
c18ef2a9dd | ||
|
|
70328e419a | ||
|
|
ad3baec12f | ||
|
|
767e45c290 | ||
|
|
a47b64ae2d | ||
|
|
0c124c3123 | ||
|
|
2a27365854 | ||
|
|
51fab28e94 | ||
|
|
f6e430f77f | ||
|
|
aeeb448eb6 | ||
|
|
da9f0924ef | ||
|
|
7074f25768 | ||
|
|
561e425903 | ||
|
|
cc97446ca5 | ||
|
|
915197a8f9 | ||
|
|
97f9a2813e | ||
|
|
96f137b24a | ||
|
|
f42dbb98d1 | ||
|
|
df94b717b4 | ||
|
|
da1fffaa09 | ||
|
|
ceac71f1f5 | ||
|
|
1b901c320b | ||
|
|
6caae0bcb1 | ||
|
|
9e040b7cd8 | ||
|
|
9e76b1181b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -32,3 +32,6 @@ tests/*.out
|
||||
# Python cache files
|
||||
######################
|
||||
__pycache__/
|
||||
|
||||
# Customized Makefile overrides
|
||||
GNUmakefile
|
||||
|
||||
@@ -15,9 +15,12 @@ script:
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm
|
||||
- make -C stmhal
|
||||
- make -C stmhal BOARD=STM32F4DISC
|
||||
- make -C teensy
|
||||
- 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 $testbase.exp $testbase.out; done)
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
|
||||
@@ -29,15 +29,13 @@ Major components in this repository:
|
||||
- py/ -- the core Python implementation, including compiler and runtime.
|
||||
- unix/ -- a version of Micro Python that runs on Unix.
|
||||
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
|
||||
with an STM32F405RG (using ST's new Cube HAL drivers).
|
||||
with an STM32F405RG (using ST's Cube HAL drivers).
|
||||
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
|
||||
(preliminary but functional).
|
||||
|
||||
Additional components:
|
||||
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Start
|
||||
with this if you want to port Micro Python to another microcontroller.
|
||||
- stm/ -- obsolete version of Micro Python for the Micro Python board
|
||||
that uses ST's old peripheral drivers.
|
||||
- unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing).
|
||||
- tests/ -- test framework and test scripts.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
@@ -94,4 +92,4 @@ You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
|
||||
AUR. If the above does not work it may be because you don't have the
|
||||
correct permissions. Try then:
|
||||
|
||||
$ sudo dfu-util -a 0 -D build-PYBV10/firmware.dfu
|
||||
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu
|
||||
|
||||
@@ -13,7 +13,7 @@ INC += -I$(PY_SRC)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
|
||||
|
||||
#Debugging/Optimization
|
||||
ifeq ($(DEBUG), 1)
|
||||
@@ -22,7 +22,7 @@ else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
endif
|
||||
|
||||
LDFLAGS = --nostdlib -T stm32f405.ld
|
||||
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
|
||||
LIBS =
|
||||
|
||||
SRC_C = \
|
||||
|
||||
@@ -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
|
||||
@@ -53,7 +52,6 @@ void do_str(const char *src) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
qstr_init();
|
||||
mp_init();
|
||||
do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\n')");
|
||||
mp_deinit();
|
||||
|
||||
@@ -2,41 +2,54 @@
|
||||
|
||||
// options to control how Micro Python is built
|
||||
|
||||
#define MICROPY_ALLOC_PATH_MAX (512)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
#define MICROPY_ENABLE_REPL_HELPERS (0)
|
||||
#define MICROPY_ENABLE_LEXER_UNIX (0)
|
||||
#define MICROPY_HELPER_REPL (0)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_ENABLE_MOD_COLLECTIONS (0)
|
||||
#define MICROPY_ENABLE_MOD_MATH (0)
|
||||
#define MICROPY_ENABLE_MOD_CMATH (0)
|
||||
#define MICROPY_ENABLE_MOD_IO (0)
|
||||
#define MICROPY_ENABLE_MOD_STRUCT (0)
|
||||
#define MICROPY_ENABLE_MOD_SYS (0)
|
||||
#define MICROPY_ENABLE_PROPERTY (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (0)
|
||||
#define MICROPY_PY_ARRAY (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
#define MICROPY_PY_IO (0)
|
||||
#define MICROPY_PY_STRUCT (0)
|
||||
#define MICROPY_PY_SYS (0)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_PATH_MAX (512)
|
||||
|
||||
//#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
#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"
|
||||
|
||||
typedef int32_t machine_int_t; // must be pointer size
|
||||
typedef uint32_t machine_uint_t; // must be pointer size
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_native_t mp_builtin_open_obj;
|
||||
#define MICROPY_EXTRA_BUILTINS \
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
177
docs/Makefile
Normal file
177
docs/Makefile
Normal 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
269
docs/conf.py
Normal 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
59
docs/general.rst
Normal 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
43
docs/index.rst
Normal 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
242
docs/make.bat
Normal 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
92
docs/tutorial/accel.rst
Normal 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.
|
||||
65
docs/tutorial/amp_skin.rst
Normal file
65
docs/tutorial/amp_skin.rst
Normal 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
123
docs/tutorial/assembler.rst
Normal 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
35
docs/tutorial/index.rst
Normal 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
54
docs/tutorial/intro.rst
Normal 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.**
|
||||
81
docs/tutorial/lcd_skin.rst
Normal file
81
docs/tutorial/lcd_skin.rst
Normal 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
75
docs/tutorial/leds.rst
Normal 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
107
docs/tutorial/repl.rst
Normal 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
60
docs/tutorial/reset.rst
Normal 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
105
docs/tutorial/script.rst
Normal 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
146
docs/tutorial/servo.rst
Normal 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
101
docs/tutorial/switch.rst
Normal 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
112
docs/tutorial/timer.rst
Normal 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
129
docs/tutorial/usb_mouse.rst
Normal 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
2
drivers/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
This directory contains drivers for specific hardware. The drivers are
|
||||
intended to work across multiple ports.
|
||||
6
drivers/wiznet5k/README.md
Normal file
6
drivers/wiznet5k/README.md
Normal 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
|
||||
703
drivers/wiznet5k/ethernet/socket.c
Normal file
703
drivers/wiznet5k/ethernet/socket.c
Normal 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;
|
||||
}
|
||||
466
drivers/wiznet5k/ethernet/socket.h
Normal file
466
drivers/wiznet5k/ethernet/socket.h
Normal 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_
|
||||
206
drivers/wiznet5k/ethernet/w5200/w5200.c
Normal file
206
drivers/wiznet5k/ethernet/w5200/w5200.c
Normal 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);
|
||||
}
|
||||
2092
drivers/wiznet5k/ethernet/w5200/w5200.h
Normal file
2092
drivers/wiznet5k/ethernet/w5200/w5200.h
Normal file
File diff suppressed because it is too large
Load Diff
237
drivers/wiznet5k/ethernet/w5500/w5500.c
Normal file
237
drivers/wiznet5k/ethernet/w5500/w5500.c
Normal 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);
|
||||
}
|
||||
|
||||
2058
drivers/wiznet5k/ethernet/w5500/w5500.h
Normal file
2058
drivers/wiznet5k/ethernet/w5500/w5500.h
Normal file
File diff suppressed because it is too large
Load Diff
657
drivers/wiznet5k/ethernet/wizchip_conf.c
Normal file
657
drivers/wiznet5k/ethernet/wizchip_conf.c
Normal 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();
|
||||
}
|
||||
552
drivers/wiznet5k/ethernet/wizchip_conf.h
Normal file
552
drivers/wiznet5k/ethernet/wizchip_conf.h
Normal 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_
|
||||
978
drivers/wiznet5k/internet/dhcp/dhcp.c
Normal file
978
drivers/wiznet5k/internet/dhcp/dhcp.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
150
drivers/wiznet5k/internet/dhcp/dhcp.h
Normal file
150
drivers/wiznet5k/internet/dhcp/dhcp.h
Normal 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_ */
|
||||
566
drivers/wiznet5k/internet/dns/dns.c
Normal file
566
drivers/wiznet5k/internet/dns/dns.c
Normal 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;
|
||||
}
|
||||
96
drivers/wiznet5k/internet/dns/dns.h
Normal file
96
drivers/wiznet5k/internet/dns/dns.h
Normal 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_ */
|
||||
@@ -2,9 +2,9 @@ import pyb
|
||||
|
||||
def led_angle(seconds_to_run_for):
|
||||
# make LED objects
|
||||
l1 = pyb.Led(1)
|
||||
l2 = pyb.Led(2)
|
||||
accel = pyb.Accel()
|
||||
l1 = pyb.LED(1)
|
||||
l2 = pyb.LED(2)
|
||||
accel = pyb.Accel()
|
||||
|
||||
for i in range(20 * seconds_to_run_for):
|
||||
# get x-axis
|
||||
|
||||
58
examples/pins.py
Normal file
58
examples/pins.py
Normal 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('')
|
||||
45
examples/switch.py
Normal file
45
examples/switch.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
switch.py
|
||||
=========
|
||||
|
||||
Light up some leds when the USR switch on the pyboard is pressed.
|
||||
|
||||
Example Usage::
|
||||
|
||||
Micro Python v1.0.1 on 2014-05-12; PYBv1.0 with STM32F405RG
|
||||
Type "help()" for more information.
|
||||
>>> import switch
|
||||
>>> switch.run_loop()
|
||||
Loop started.
|
||||
Press Ctrl+C to break out of the loop.
|
||||
|
||||
"""
|
||||
|
||||
import pyb
|
||||
|
||||
switch = pyb.Switch()
|
||||
red_led = pyb.LED(1)
|
||||
green_led = pyb.LED(2)
|
||||
orange_led = pyb.LED(3)
|
||||
blue_led = pyb.LED(4)
|
||||
all_leds = (red_led, green_led, orange_led, blue_led)
|
||||
|
||||
def run_loop(leds=all_leds):
|
||||
"""
|
||||
Start the loop.
|
||||
|
||||
:param `leds`: Which LEDs to light up upon switch press.
|
||||
:type `leds`: sequence of LED objects
|
||||
"""
|
||||
print('Loop started.\nPress Ctrl+C to break out of the loop.')
|
||||
while 1:
|
||||
try:
|
||||
if switch():
|
||||
[led.on() for led in leds]
|
||||
else:
|
||||
[led.off() for led in leds]
|
||||
except OSError: # VCPInterrupt # Ctrl+C in interpreter mode.
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_loop()
|
||||
595
extmod/miniz/tinfl.c
Normal file
595
extmod/miniz/tinfl.c
Normal file
@@ -0,0 +1,595 @@
|
||||
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
|
||||
See "unlicense" statement at the end of this file.
|
||||
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
|
||||
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
|
||||
|
||||
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
|
||||
*/
|
||||
#ifndef TINFL_HEADER_INCLUDED
|
||||
#define TINFL_HEADER_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char mz_uint8;
|
||||
typedef signed short mz_int16;
|
||||
typedef unsigned short mz_uint16;
|
||||
typedef unsigned int mz_uint32;
|
||||
typedef unsigned int mz_uint;
|
||||
typedef unsigned long long mz_uint64;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
|
||||
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
||||
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
|
||||
#define MINIZ_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
||||
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
|
||||
#define MINIZ_HAS_64BIT_REGISTERS 1
|
||||
#endif
|
||||
|
||||
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
|
||||
#ifdef _MSC_VER
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#else
|
||||
#define MZ_MACRO_END while (0)
|
||||
#endif
|
||||
|
||||
// Decompression flags used by tinfl_decompress().
|
||||
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
|
||||
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
|
||||
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
|
||||
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
|
||||
enum
|
||||
{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
|
||||
// On entry:
|
||||
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
|
||||
// On return:
|
||||
// Function returns a pointer to the decompressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must free() the returned block when it's no longer needed.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
|
||||
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
|
||||
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
|
||||
// Max size of LZ dictionary.
|
||||
#define TINFL_LZ_DICT_SIZE 32768
|
||||
|
||||
// Return status.
|
||||
typedef enum
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
} tinfl_status;
|
||||
|
||||
// Initializes the decompressor to its initial state.
|
||||
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
|
||||
#define tinfl_get_adler32(r) (r)->m_check_adler32
|
||||
|
||||
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
|
||||
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
|
||||
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 = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
} tinfl_huff_table;
|
||||
|
||||
#if MINIZ_HAS_64BIT_REGISTERS
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#endif
|
||||
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
#else
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
#endif
|
||||
|
||||
struct tinfl_decompressor_tag
|
||||
{
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
};
|
||||
|
||||
#endif // #ifdef TINFL_HEADER_INCLUDED
|
||||
|
||||
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
|
||||
|
||||
#ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
|
||||
#ifdef MINIZ_NO_MALLOC
|
||||
#define MZ_MALLOC(x) NULL
|
||||
#define MZ_FREE(x) x, ((void)0)
|
||||
#define MZ_REALLOC(p, x) NULL
|
||||
#else
|
||||
#define MZ_MALLOC(x) malloc(x)
|
||||
#define MZ_FREE(x) free(x)
|
||||
#define MZ_REALLOC(p, x) realloc(p, x)
|
||||
#endif
|
||||
|
||||
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
|
||||
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
|
||||
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
|
||||
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
|
||||
#else
|
||||
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
|
||||
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
||||
#endif
|
||||
|
||||
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
|
||||
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
|
||||
|
||||
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
|
||||
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
|
||||
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
|
||||
#define TINFL_CR_FINISH }
|
||||
|
||||
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
|
||||
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
|
||||
#define TINFL_GET_BYTE(state_index, c) do { \
|
||||
if (pIn_buf_cur >= pIn_buf_end) { \
|
||||
for ( ; ; ) { \
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
|
||||
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
|
||||
if (pIn_buf_cur < pIn_buf_end) { \
|
||||
c = *pIn_buf_cur++; \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
c = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else c = *pIn_buf_cur++; } MZ_MACRO_END
|
||||
|
||||
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
|
||||
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
|
||||
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
|
||||
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
|
||||
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
|
||||
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
|
||||
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
|
||||
do { \
|
||||
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
|
||||
if (temp >= 0) { \
|
||||
code_len = temp >> 9; \
|
||||
if ((code_len) && (num_bits >= code_len)) \
|
||||
break; \
|
||||
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; \
|
||||
do { \
|
||||
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
|
||||
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
|
||||
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
|
||||
} while (num_bits < 15);
|
||||
|
||||
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
|
||||
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
|
||||
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
|
||||
// The slow path is only executed at the very end of the input buffer.
|
||||
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
|
||||
int temp; mz_uint code_len, c; \
|
||||
if (num_bits < 15) { \
|
||||
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
|
||||
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
|
||||
} else { \
|
||||
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
|
||||
} \
|
||||
} \
|
||||
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
|
||||
code_len = temp >> 9, temp &= 511; \
|
||||
else { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
|
||||
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
|
||||
|
||||
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 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 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;
|
||||
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
|
||||
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
|
||||
|
||||
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
|
||||
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
|
||||
|
||||
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
|
||||
TINFL_CR_BEGIN
|
||||
|
||||
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
|
||||
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
|
||||
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
|
||||
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
|
||||
if (r->m_type == 0)
|
||||
{
|
||||
TINFL_SKIP_BITS(5, num_bits & 7);
|
||||
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
|
||||
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
|
||||
while ((counter) && (num_bits))
|
||||
{
|
||||
TINFL_GET_BITS(51, dist, 8);
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)dist;
|
||||
counter--;
|
||||
}
|
||||
while (counter)
|
||||
{
|
||||
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
while (pIn_buf_cur >= pIn_buf_end)
|
||||
{
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
|
||||
{
|
||||
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
|
||||
}
|
||||
}
|
||||
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
|
||||
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
|
||||
}
|
||||
}
|
||||
else if (r->m_type == 3)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->m_type == 1)
|
||||
{
|
||||
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
|
||||
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
|
||||
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
|
||||
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
|
||||
r->m_table_sizes[2] = 19;
|
||||
}
|
||||
for ( ; (int)r->m_type >= 0; r->m_type--)
|
||||
{
|
||||
int tree_next, tree_cur; tinfl_huff_table *pTable;
|
||||
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
|
||||
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
|
||||
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
|
||||
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
|
||||
if ((65536 != total) && (used_syms > 1))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
|
||||
}
|
||||
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
|
||||
{
|
||||
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
|
||||
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
|
||||
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
|
||||
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
|
||||
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
|
||||
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
|
||||
{
|
||||
tree_cur -= ((rev_code >>= 1) & 1);
|
||||
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
|
||||
}
|
||||
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
|
||||
}
|
||||
if (r->m_type == 2)
|
||||
{
|
||||
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
|
||||
{
|
||||
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
|
||||
if ((dist == 16) && (!counter))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
|
||||
}
|
||||
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
|
||||
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
|
||||
}
|
||||
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
|
||||
}
|
||||
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
|
||||
}
|
||||
}
|
||||
for ( ; ; )
|
||||
{
|
||||
mz_uint8 *pSrc;
|
||||
for ( ; ; )
|
||||
{
|
||||
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
|
||||
{
|
||||
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
|
||||
if (counter >= 256)
|
||||
break;
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sym2; mz_uint code_len;
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
|
||||
#else
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
|
||||
if (counter & 256)
|
||||
break;
|
||||
|
||||
#if !TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
bit_buf >>= code_len; num_bits -= code_len;
|
||||
|
||||
pOut_buf_cur[0] = (mz_uint8)counter;
|
||||
if (sym2 & 256)
|
||||
{
|
||||
pOut_buf_cur++;
|
||||
counter = sym2;
|
||||
break;
|
||||
}
|
||||
pOut_buf_cur[1] = (mz_uint8)sym2;
|
||||
pOut_buf_cur += 2;
|
||||
}
|
||||
}
|
||||
if ((counter &= 511) == 256) break;
|
||||
|
||||
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
|
||||
|
||||
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
|
||||
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
|
||||
|
||||
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
|
||||
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
|
||||
}
|
||||
|
||||
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
|
||||
|
||||
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
|
||||
{
|
||||
while (counter--)
|
||||
{
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
|
||||
else if ((counter >= 9) && (counter <= dist))
|
||||
{
|
||||
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
|
||||
do
|
||||
{
|
||||
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
|
||||
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
|
||||
pOut_buf_cur += 8;
|
||||
} while ((pSrc += 8) < pSrc_end);
|
||||
if ((counter &= 7) < 3)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if (counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
do
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur[2] = pSrc[2];
|
||||
pOut_buf_cur += 3; pSrc += 3;
|
||||
} while ((int)(counter -= 3) > 2);
|
||||
if ((int)counter > 0)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if ((int)counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(r->m_final & 1));
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
|
||||
}
|
||||
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
|
||||
TINFL_CR_FINISH
|
||||
|
||||
common_exit:
|
||||
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
|
||||
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
|
||||
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
|
||||
{
|
||||
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
|
||||
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
|
||||
while (buf_len)
|
||||
{
|
||||
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
|
||||
{
|
||||
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
|
||||
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
|
||||
}
|
||||
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
|
||||
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
|
||||
}
|
||||
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
|
||||
}
|
||||
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)
|
||||
{
|
||||
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
|
||||
*pOut_len = 0;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
|
||||
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
src_buf_ofs += src_buf_size;
|
||||
*pOut_len += dst_buf_size;
|
||||
if (status == TINFL_STATUS_DONE) break;
|
||||
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
|
||||
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
|
||||
if (!pNew_buf)
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
|
||||
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
|
||||
}
|
||||
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
|
||||
{
|
||||
int result = 0;
|
||||
tinfl_decompressor decomp;
|
||||
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
|
||||
if (!pDict)
|
||||
return TINFL_STATUS_FAILED;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
|
||||
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
|
||||
in_buf_ofs += in_buf_size;
|
||||
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
|
||||
break;
|
||||
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
|
||||
{
|
||||
result = (status == TINFL_STATUS_DONE);
|
||||
break;
|
||||
}
|
||||
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
|
||||
}
|
||||
MZ_FREE(pDict);
|
||||
*pIn_buf_size = in_buf_ofs;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
634
extmod/moductypes.c
Normal file
634
extmod/moductypes.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "objtuple.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// The module also provides convenience functions to access memory buffers
|
||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
||||
/// \constant UINT8_1 - uint8_t value type
|
||||
|
||||
/// \class struct - C-like structure
|
||||
///
|
||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
||||
/// any methods, only attribute access (for structure fields) and
|
||||
/// indexing (for pointer and array fields).
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// # Define layout of a structure with 2 fields
|
||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
||||
/// # they are logically ORed with field type
|
||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
||||
///
|
||||
/// # Example memory buffer to access (contained in bytes object)
|
||||
/// buf = b"\x64\0\0\0\0x14"
|
||||
///
|
||||
/// # Create structure object referring to address of
|
||||
/// # the data in the buffer above
|
||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
||||
///
|
||||
/// # Access fields
|
||||
/// print(s.a, s.b)
|
||||
/// # Result:
|
||||
/// # 100, 20
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
#define LAYOUT_NATIVE (2)
|
||||
|
||||
#define VAL_TYPE_BITS 4
|
||||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#define OFFSET_BITS 17
|
||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||
#error Invalid encoding field length
|
||||
#endif
|
||||
|
||||
enum {
|
||||
UINT8, INT8, UINT16, INT16,
|
||||
UINT32, INT32, UINT64, INT64,
|
||||
|
||||
BFUINT8, BFINT8, BFUINT16, BFINT16,
|
||||
BFUINT32, BFINT32,
|
||||
|
||||
FLOAT32, FLOAT64,
|
||||
};
|
||||
|
||||
#define AGG_TYPE_BITS 2
|
||||
|
||||
enum {
|
||||
STRUCT, PTR, ARRAY, BITFIELD,
|
||||
};
|
||||
|
||||
// Here we need to set sign bit right
|
||||
#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
|
||||
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1));
|
||||
// Bit 0 is "is_signed"
|
||||
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
|
||||
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type;
|
||||
|
||||
typedef struct _mp_obj_uctypes_struct_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t desc;
|
||||
byte *addr;
|
||||
uint32_t flags;
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
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, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
if (n_args < 2 || n_args > 3) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = type_in;
|
||||
o->desc = args[0];
|
||||
o->addr = (void*)mp_obj_get_int(args[1]);
|
||||
o->flags = LAYOUT_NATIVE;
|
||||
if (n_args == 3) {
|
||||
o->flags = mp_obj_get_int(args[2]);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
const char *typen = "unk";
|
||||
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
typen = "STRUCT";
|
||||
} else if (MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
switch (agg_type) {
|
||||
case PTR: typen = "PTR"; break;
|
||||
case ARRAY: typen = "ARRAY"; break;
|
||||
}
|
||||
} else {
|
||||
typen = "ERROR";
|
||||
}
|
||||
print(env, "<struct %s %p>", typen, self->addr);
|
||||
}
|
||||
|
||||
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
|
||||
if (val_type == FLOAT32) {
|
||||
return 4;
|
||||
} else {
|
||||
return GET_SCALAR_SIZE(val_type & 7);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
|
||||
mp_obj_dict_t *d = desc_in;
|
||||
mp_uint_t total_size = 0;
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
for (mp_uint_t i = 0; i < d->map.alloc; i++) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(&d->map, i)) {
|
||||
mp_obj_t v = d->map.table[i].value;
|
||||
if (MP_OBJ_IS_SMALL_INT(v)) {
|
||||
mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t s = uctypes_struct_scalar_size(val_type);
|
||||
if (s > *max_field_size) {
|
||||
*max_field_size = s;
|
||||
}
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(v, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTR: {
|
||||
if (offset + sizeof(void*) > total_size) {
|
||||
total_size = offset + sizeof(void*);
|
||||
}
|
||||
if (sizeof(void*) > *max_field_size) {
|
||||
*max_field_size = sizeof(void*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARRAY: {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
} else {
|
||||
item_s = uctypes_struct_size(t->items[2], max_field_size);
|
||||
}
|
||||
|
||||
mp_uint_t byte_sz = item_s * arr_sz;
|
||||
if (offset + byte_sz > total_size) {
|
||||
total_size = offset + byte_sz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Round size up to alignment of biggest field
|
||||
total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
|
||||
mp_uint_t max_field_size = 0;
|
||||
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
|
||||
mp_obj_uctypes_struct_t *obj = obj_in;
|
||||
obj_in = obj->desc;
|
||||
}
|
||||
mp_uint_t size = uctypes_struct_size(obj_in, &max_field_size);
|
||||
return MP_OBJ_NEW_SMALL_INT(size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_sizeof_obj, uctypes_struct_sizeof);
|
||||
|
||||
STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
|
||||
mp_int_t val = mp_binary_get_int(GET_SCALAR_SIZE(val_type), val_type & 1, big_endian, p);
|
||||
if (val_type == UINT32) {
|
||||
return mp_obj_new_int_from_uint(val);
|
||||
} else {
|
||||
return mp_obj_new_int(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, &p);
|
||||
}
|
||||
|
||||
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return *(uint8_t*)p;
|
||||
case UINT16:
|
||||
return *(uint16_t*)p;
|
||||
case UINT32:
|
||||
return *(uint32_t*)p;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
*(uint8_t*)p = (uint8_t)v; return;
|
||||
case UINT16:
|
||||
*(uint16_t*)p = (uint16_t)v; return;
|
||||
case UINT32:
|
||||
*(uint32_t*)p = (uint32_t)v; return;
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint8_t*)p)[index]);
|
||||
case INT8:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int8_t*)p)[index]);
|
||||
case UINT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((uint16_t*)p)[index]);
|
||||
case INT16:
|
||||
return MP_OBJ_NEW_SMALL_INT(((int16_t*)p)[index]);
|
||||
case UINT32:
|
||||
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
|
||||
case INT32:
|
||||
return mp_obj_new_int(((int32_t*)p)[index]);
|
||||
case UINT64:
|
||||
case INT64:
|
||||
return mp_obj_new_int_from_ll(((int64_t*)p)[index]);
|
||||
case FLOAT32:
|
||||
return mp_obj_new_float(((float*)p)[index]);
|
||||
case FLOAT64:
|
||||
return mp_obj_new_float(((double*)p)[index]);
|
||||
default:
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||
mp_int_t v = mp_obj_get_int(val);
|
||||
switch (val_type) {
|
||||
case UINT8:
|
||||
((uint8_t*)p)[index] = (uint8_t)v; return;
|
||||
case INT8:
|
||||
((int8_t*)p)[index] = (int8_t)v; return;
|
||||
case UINT16:
|
||||
((uint16_t*)p)[index] = (uint16_t)v; return;
|
||||
case INT16:
|
||||
((int16_t*)p)[index] = (int16_t)v; return;
|
||||
case UINT32:
|
||||
((uint32_t*)p)[index] = (uint32_t)v; return;
|
||||
case INT32:
|
||||
((int32_t*)p)[index] = (int32_t)v; return;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
// TODO: Support at least OrderedDict in addition
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: no fields"));
|
||||
}
|
||||
|
||||
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
||||
if (MP_OBJ_IS_SMALL_INT(deref)) {
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
//printf("scalar type=%d offset=%x\n", val_type, offset);
|
||||
|
||||
if (val_type <= INT64) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_aligned(val_type, self->addr + offset, 0);
|
||||
} else {
|
||||
set_aligned(val_type, self->addr + offset, 0, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
} else {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_unaligned(val_type, self->addr + offset, self->flags);
|
||||
} else {
|
||||
set_unaligned(val_type, self->addr + offset, self->flags, set_val);
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||
} else {
|
||||
val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset);
|
||||
}
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
val >>= bit_offset;
|
||||
val &= (1 << bit_len) - 1;
|
||||
// TODO: signed
|
||||
assert((val_type & 1) == 0);
|
||||
return mp_obj_new_int(val);
|
||||
} else {
|
||||
mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val);
|
||||
mp_uint_t mask = (1 << bit_len) - 1;
|
||||
set_val_int &= mask;
|
||||
set_val_int <<= bit_offset;
|
||||
mask <<= bit_offset;
|
||||
val = (val & ~mask) | set_val_int;
|
||||
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
set_aligned_basic(val_type & 6, self->addr + offset, val);
|
||||
} else {
|
||||
mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
|
||||
self->addr + offset, (byte*)&val);
|
||||
}
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(deref, &mp_type_tuple)) {
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
if (set_val != MP_OBJ_NULL) {
|
||||
// Cannot assign to aggregate
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *sub = (mp_obj_tuple_t*)deref;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
//printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub->items[1];
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
case PTR: case ARRAY: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub;
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
//printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
// Should be unreachable once all cases are handled
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL);
|
||||
*dest = val;
|
||||
}
|
||||
|
||||
STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) {
|
||||
return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
|
||||
mp_obj_uctypes_struct_t *self = self_in;
|
||||
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
if (!MP_OBJ_IS_TYPE(self->desc, &mp_type_tuple)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "struct: cannot index"));
|
||||
}
|
||||
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)self->desc;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
|
||||
mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in);
|
||||
|
||||
if (agg_type == ARRAY) {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
if (index >= arr_sz) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range"));
|
||||
}
|
||||
|
||||
if (t->len == 2) {
|
||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[2], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[2];
|
||||
o->addr = self->addr + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
} else if (agg_type == PTR) {
|
||||
byte *p = *(void**)self->addr;
|
||||
if (MP_OBJ_IS_SMALL_INT(t->items[1])) {
|
||||
uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
|
||||
return get_aligned(val_type, p, index);
|
||||
} else {
|
||||
mp_uint_t dummy = 0;
|
||||
mp_uint_t size = uctypes_struct_size(t->items[1], &dummy);
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = t->items[1];
|
||||
o->addr = p + size * index;
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return MP_OBJ_NULL;
|
||||
} else {
|
||||
// store
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
return mp_obj_new_int((mp_int_t)bufinfo.buf);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get(size), (void*)mp_obj_int_get(ptr));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytes((void*)mp_obj_int_get(ptr), mp_obj_int_get(size));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_struct,
|
||||
.print = uctypes_struct_print,
|
||||
.make_new = uctypes_struct_make_new,
|
||||
.load_attr = uctypes_struct_load_attr,
|
||||
.store_attr = uctypes_struct_store_attr,
|
||||
.subscr = uctypes_struct_subscr,
|
||||
};
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uctypes_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uctypes) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&uctypes_struct_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sizeof), (mp_obj_t)&uctypes_struct_sizeof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_addressof), (mp_obj_t)&uctypes_struct_addressof_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes_at), (mp_obj_t)&uctypes_struct_bytes_at_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray_at), (mp_obj_t)&uctypes_struct_bytearray_at_obj },
|
||||
|
||||
/// \moduleref uctypes
|
||||
|
||||
/// \constant NATIVE - Native structure layout - native endianness,
|
||||
/// platform-specific field alignment
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_NATIVE), MP_OBJ_NEW_SMALL_INT(LAYOUT_NATIVE) },
|
||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BIG_ENDIAN), MP_OBJ_NEW_SMALL_INT(LAYOUT_BIG_ENDIAN) },
|
||||
|
||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_VOID), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \constant UINT32 - uint32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
/// \constant INT32 - int32_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
/// \constant UINT64 - uint64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UINT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
/// \constant INT64 - int64_t value type
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_INT64), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT8), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT16), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFUINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BFINT32), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_POS), MP_OBJ_NEW_SMALL_INT(17) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_BF_LEN), MP_OBJ_NEW_SMALL_INT(22) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PTR), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ARRAY), MP_OBJ_NEW_SMALL_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uctypes_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uctypes_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uctypes_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uctypes,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uctypes_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
279
extmod/modujson.c
Normal file
279
extmod/modujson.c
Normal 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
|
||||
108
extmod/modzlibd.c
Normal file
108
extmod/modzlibd.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_ZLIBD
|
||||
|
||||
#include "miniz/tinfl.c"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
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)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
|
||||
|
||||
byte *out = m_new(byte, bufinfo.len);
|
||||
size_t out_len = bufinfo.len;
|
||||
size_t in_buf_ofs = 0, dst_buf_ofs = 0;
|
||||
size_t dst_buf_sz = bufinfo.len;
|
||||
|
||||
while (1) {
|
||||
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,
|
||||
(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);
|
||||
in_buf_ofs += in_buf_sz;
|
||||
dst_buf_ofs += dst_buf_sz;
|
||||
if (st != TINFL_STATUS_HAS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
out = m_renew(byte, out, out_len, dst_buf_ofs + 256);
|
||||
out_len = dst_buf_ofs + 256;
|
||||
dst_buf_sz = out_len - dst_buf_ofs;
|
||||
}
|
||||
|
||||
m_del_obj(tinfl_decompressor, decomp);
|
||||
return mp_obj_new_bytearray_by_ref(dst_buf_ofs, out);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_zlibd_decompress_obj, 1, 3, mod_zlibd_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_zlibd_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_zlibd) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_zlibd_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_zlibd_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_zlibd_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_zlibd = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_zlibd,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_zlibd_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_ZLIBD
|
||||
2
lib/README.md
Normal file
2
lib/README.md
Normal 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
130
lib/libm/asinfacosf.c
Normal 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
89
lib/libm/atan2f.c
Normal 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
100
lib/libm/atanf.c
Normal 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
70
lib/libm/fmodf.c
Normal 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
52
lib/libm/libm.h
Normal 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)
|
||||
@@ -24,8 +24,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "libm.h"
|
||||
|
||||
typedef float float_t;
|
||||
typedef union {
|
||||
@@ -72,6 +71,7 @@ float __attribute__((pcs("aapcs"))) __aeabi_d2f(double x) {
|
||||
fx.m = (dx.m>>(52-23)); // right justify
|
||||
return fx.f;
|
||||
}
|
||||
|
||||
double __aeabi_dmul(double x , double y) {
|
||||
return 0.0;
|
||||
|
||||
@@ -85,10 +85,26 @@ float sqrtf(float x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
float copysignf(float x, float y) {
|
||||
float_s_t fx={.f = x};
|
||||
float_s_t fy={.f = y};
|
||||
|
||||
// copy sign bit;
|
||||
fx.s = fy.s;
|
||||
|
||||
return fx.f;
|
||||
}
|
||||
#endif
|
||||
|
||||
// some compilers define log2f in terms of logf
|
||||
#ifdef log2f
|
||||
#undef log2f
|
||||
#endif
|
||||
// some compilers have _M_LN2 defined in math.h, some don't
|
||||
#ifndef _M_LN2
|
||||
#define _M_LN2 (0.69314718055994530942)
|
||||
#endif
|
||||
float log2f(float x) { return logf(x) / (float)_M_LN2; }
|
||||
|
||||
static const float _M_LN10 = 2.30258509299404; // 0x40135d8e
|
||||
@@ -101,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; }
|
||||
@@ -114,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
|
||||
@@ -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
339
py/asmarm.c
Normal 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
98
py/asmarm.h
Normal 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);
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "asmthumb.h"
|
||||
|
||||
// wrapper around everything in this 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 *)(((machine_uint_t)as->code_base) | 1);
|
||||
return as->code_base;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -378,7 +378,7 @@ void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label) {
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32) {
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) {
|
||||
// movw, movt does it in 8 bytes
|
||||
// ldr [pc, #], dw does it in 6 bytes, but we might not reach to end of code for dw
|
||||
|
||||
@@ -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, (machine_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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -185,7 +179,7 @@ void asm_thumb_ite_ge(asm_thumb_t *as);
|
||||
void asm_thumb_b_n(asm_thumb_t *as, uint label);
|
||||
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
|
||||
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, machine_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32_src); // convenience
|
||||
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32); // convenience
|
||||
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); // convenience
|
||||
|
||||
150
py/asmx64.c
150
py/asmx64.c
@@ -29,34 +29,27 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
// 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
|
||||
|
||||
52
py/asmx64.h
52
py/asmx64.h
@@ -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
528
py/asmx86.c
Normal 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
89
py/asmx86.h
Normal 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
239
py/bc.c
Normal 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);
|
||||
}
|
||||
27
py/bc.h
27
py/bc.h
@@ -36,12 +36,27 @@ typedef struct _mp_exc_stack {
|
||||
byte opcode;
|
||||
} mp_exc_stack_t;
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(const byte *code, const mp_obj_t *args, uint n_args, const mp_obj_t *args2, uint n_args2, mp_obj_t *ret);
|
||||
mp_vm_return_kind_t mp_execute_bytecode2(const byte *code_info, const byte **ip_in_out, mp_obj_t *fastn, mp_obj_t **sp_in_out, mp_exc_stack_t *exc_stack, mp_exc_stack_t **exc_sp_in_out, volatile mp_obj_t inject_exc);
|
||||
void mp_bytecode_print(const byte *code, int len);
|
||||
typedef struct _mp_code_state {
|
||||
const byte *code_info;
|
||||
const byte *ip;
|
||||
mp_obj_t *sp;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
uint n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
// Variable-length, never accessed by name, only as (void*)(state + n_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, 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);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((machine_uint_t)(x) & ~((machine_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((machine_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((machine_uint_t)(ptr) | tag))
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
#define MP_TAGPTR_TAG(x) ((mp_uint_t)(x) & 1)
|
||||
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | tag))
|
||||
|
||||
159
py/binary.c
159
py/binary.c
@@ -26,17 +26,24 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "smallint.h"
|
||||
#include "binary.h"
|
||||
|
||||
// Helpers to work with binary-encoded data
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
#ifndef alignof
|
||||
#define alignof(type) offsetof(struct { char c; type t; }, t)
|
||||
#endif
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
|
||||
int size = 0;
|
||||
int align = 1;
|
||||
switch (struct_type) {
|
||||
@@ -52,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 '@': {
|
||||
@@ -67,16 +76,20 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
case 'b': case 'B':
|
||||
align = size = 1; break;
|
||||
case 'h': case 'H':
|
||||
align = size = sizeof(short); break;
|
||||
align = alignof(short);
|
||||
size = sizeof(short); break;
|
||||
case 'i': case 'I':
|
||||
align = size = sizeof(int); break;
|
||||
align = alignof(int);
|
||||
size = sizeof(int); break;
|
||||
case 'l': case 'L':
|
||||
align = size = sizeof(long); break;
|
||||
align = alignof(long);
|
||||
size = sizeof(long); break;
|
||||
case 'q': case 'Q':
|
||||
// TODO: This is for x86
|
||||
align = sizeof(int); size = sizeof(long long); break;
|
||||
case 'P': case 'O':
|
||||
align = size = sizeof(void*); break;
|
||||
align = alignof(long long);
|
||||
size = sizeof(long long); break;
|
||||
case 'P': case 'O': case 'S':
|
||||
align = alignof(void*);
|
||||
size = sizeof(void*); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +100,7 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
|
||||
}
|
||||
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
machine_int_t val = 0;
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
val = ((int8_t*)p)[index];
|
||||
@@ -114,7 +127,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
// TODO: Explode API more to cover signedness
|
||||
return mp_obj_new_int_from_ll(((long long*)p)[index]);
|
||||
#endif
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
return mp_obj_new_float(((float*)p)[index]);
|
||||
case 'd':
|
||||
@@ -124,32 +137,20 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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 (struct_type == '<') {
|
||||
if (!big_endian) {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
|
||||
machine_int_t val = 0;
|
||||
if (is_signed(val_type) && *p & 0x80) {
|
||||
long long val = 0;
|
||||
if (is_signed && *p & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
@@ -158,35 +159,85 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
p += delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
if (val_type == 'O') {
|
||||
return (mp_obj_t)val;
|
||||
} else if (is_signed(val_type)) {
|
||||
return mp_obj_new_int(val);
|
||||
} else {
|
||||
return mp_obj_new_int_from_uint(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
|
||||
#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 == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
|
||||
|
||||
if (val_type == 'O') {
|
||||
return (mp_obj_t)(mp_uint_t)val;
|
||||
} else if (val_type == 'S') {
|
||||
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)) {
|
||||
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 {
|
||||
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(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr) {
|
||||
int in_delta, out_delta;
|
||||
if (big_endian) {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
val_ptr += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *val_ptr;
|
||||
p += out_delta;
|
||||
val_ptr += in_delta;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
|
||||
byte *p = *ptr;
|
||||
mp_uint_t align;
|
||||
|
||||
int size = mp_binary_get_size(struct_type, val_type, &align);
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#error Not implemented
|
||||
#endif
|
||||
machine_int_t val;
|
||||
mp_int_t val;
|
||||
byte *in = (byte*)&val;
|
||||
switch (val_type) {
|
||||
case 'O':
|
||||
@@ -196,28 +247,12 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
val = mp_obj_get_int(val_in);
|
||||
}
|
||||
|
||||
int in_delta, out_delta;
|
||||
uint val_sz = MIN(size, sizeof(val));
|
||||
if (struct_type == '>') {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
in += val_sz - 1;
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *in;
|
||||
p += out_delta;
|
||||
in += in_delta;
|
||||
}
|
||||
|
||||
*ptr += size;
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
|
||||
switch (typecode) {
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
((float*)p)[index] = mp_obj_float_get(val_in);
|
||||
break;
|
||||
@@ -230,7 +265,7 @@ 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, machine_int_t val) {
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
@@ -260,7 +295,7 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine
|
||||
((long long*)p)[index] = val;
|
||||
break;
|
||||
#endif
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
((float*)p)[index] = val;
|
||||
break;
|
||||
|
||||
@@ -28,9 +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, machine_int_t val);
|
||||
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);
|
||||
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);
|
||||
|
||||
263
py/builtin.c
263
py/builtin.c
@@ -36,15 +36,17 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "stream.h"
|
||||
#include "pfenv.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
// 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
|
||||
@@ -84,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) {
|
||||
@@ -94,17 +95,16 @@ 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__);
|
||||
|
||||
mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
if (MP_OBJ_IS_SMALL_INT(o_in)) {
|
||||
mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
|
||||
if (val < 0) {
|
||||
val = -val;
|
||||
}
|
||||
return MP_OBJ_NEW_SMALL_INT(val);
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_float)) {
|
||||
mp_float_t value = mp_obj_float_get(o_in);
|
||||
// TODO check for NaN etc
|
||||
@@ -113,17 +113,18 @@ mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
|
||||
} else {
|
||||
return o_in;
|
||||
}
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_complex)) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_complex_get(o_in, &real, &imag);
|
||||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(real*real + imag*imag));
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
assert(0);
|
||||
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) {
|
||||
@@ -136,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) {
|
||||
@@ -149,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(ARRAY_SIZE(args), args);
|
||||
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) {
|
||||
@@ -166,22 +164,47 @@ 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) {
|
||||
int ord = mp_obj_get_int(o_in);
|
||||
#if MICROPY_PY_BUILTINS_STR_UNICODE
|
||||
mp_uint_t c = mp_obj_get_int(o_in);
|
||||
char str[4];
|
||||
int len = 0;
|
||||
if (c < 0x80) {
|
||||
*str = c; len = 1;
|
||||
} else if (c < 0x800) {
|
||||
str[0] = (c >> 6) | 0xC0;
|
||||
str[1] = (c & 0x3F) | 0x80;
|
||||
len = 2;
|
||||
} else if (c < 0x10000) {
|
||||
str[0] = (c >> 12) | 0xE0;
|
||||
str[1] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[2] = (c & 0x3F) | 0x80;
|
||||
len = 3;
|
||||
} else if (c < 0x110000) {
|
||||
str[0] = (c >> 18) | 0xF0;
|
||||
str[1] = ((c >> 12) & 0x3F) | 0x80;
|
||||
str[2] = ((c >> 6) & 0x3F) | 0x80;
|
||||
str[3] = (c & 0x3F) | 0x80;
|
||||
len = 4;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
|
||||
}
|
||||
return mp_obj_new_str(str, len, true);
|
||||
#else
|
||||
mp_int_t ord = mp_obj_get_int(o_in);
|
||||
if (0 <= ord && ord <= 0x10ffff) {
|
||||
byte str[1] = {ord};
|
||||
char str[1] = {ord};
|
||||
return mp_obj_new_str(str, 1, true);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"));
|
||||
}
|
||||
#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;
|
||||
@@ -207,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);
|
||||
}
|
||||
@@ -216,111 +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_small_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_small_int_t i2 = MP_OBJ_SMALL_INT_VALUE(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_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in)));
|
||||
} else {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_builtin_len);
|
||||
|
||||
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);
|
||||
@@ -330,75 +345,112 @@ 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);
|
||||
if (charlen == 1) {
|
||||
if (MP_OBJ_IS_STR(o_in) && UTF8_IS_NONASCII(*str)) {
|
||||
mp_int_t ord = *str++ & 0x7F;
|
||||
for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
|
||||
ord &= ~mask;
|
||||
}
|
||||
while (UTF8_IS_CONT(*str)) {
|
||||
ord = (ord << 6) | (*str++ & 0x3F);
|
||||
}
|
||||
return mp_obj_new_int(ord);
|
||||
} else {
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
}
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", charlen));
|
||||
}
|
||||
#else
|
||||
if (len == 1) {
|
||||
// don't sign extend when converting to ord
|
||||
// TODO unicode
|
||||
return mp_obj_new_int(((const byte*)str)[0]);
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "ord() expected a character, but string of length %d found", len));
|
||||
}
|
||||
#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);
|
||||
}
|
||||
if (end_elem != NULL && end_elem->value != mp_const_none) {
|
||||
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_t stream_obj = &mp_sys_stdout_obj;
|
||||
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
|
||||
if (file_elem != NULL && file_elem->value != mp_const_none) {
|
||||
stream_obj = file_elem->value;
|
||||
}
|
||||
|
||||
pfenv_t pfenv;
|
||||
pfenv.data = stream_obj;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
|
||||
#endif
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
printf("%.*s", sep_len, sep_data);
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, sep_data, sep_len);
|
||||
#else
|
||||
printf("%.*s", (int)sep_len, sep_data);
|
||||
#endif
|
||||
}
|
||||
#if MICROPY_PY_IO
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR);
|
||||
#else
|
||||
mp_obj_print(args[i], PRINT_STR);
|
||||
#endif
|
||||
}
|
||||
printf("%.*s", end_len, end_data);
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, end_data, end_len);
|
||||
#else
|
||||
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) {
|
||||
vstr_t *vstr = vstr_new();
|
||||
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
|
||||
mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
|
||||
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -412,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,
|
||||
@@ -426,15 +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) {
|
||||
return mp_obj_new_int((machine_int_t)o_in);
|
||||
}
|
||||
|
||||
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];
|
||||
@@ -451,22 +495,26 @@ 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) {
|
||||
assert(MP_OBJ_IS_QSTR(args[1]));
|
||||
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);
|
||||
} else if (!MP_OBJ_IS_QSTR(attr)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "string required"));
|
||||
}
|
||||
mp_obj_t defval = MP_OBJ_NULL;
|
||||
if (n_args > 2) {
|
||||
defval = args[2];
|
||||
}
|
||||
return mp_load_attr_default(args[0], MP_OBJ_QSTR_VALUE(args[1]), defval);
|
||||
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) {
|
||||
assert(MP_OBJ_IS_QSTR(attr_in));
|
||||
|
||||
mp_obj_t dest[2];
|
||||
// TODO: https://docs.python.org/3.3/library/functions.html?highlight=hasattr#hasattr
|
||||
// TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr
|
||||
// explicitly says "This is implemented by calling getattr(object, name) and seeing
|
||||
// whether it raises an AttributeError or not.", so we should explicitly wrap this
|
||||
// in nlr_push and handle exception.
|
||||
@@ -474,9 +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 two are defined in terms of MicroPython API functions right away
|
||||
// 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);
|
||||
|
||||
13
py/builtin.h
13
py/builtin.h
@@ -24,7 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
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);
|
||||
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);
|
||||
@@ -79,3 +80,13 @@ extern const mp_obj_module_t mp_module_micropython;
|
||||
extern const mp_obj_module_t mp_module_struct;
|
||||
extern const mp_obj_module_t mp_module_sys;
|
||||
extern const mp_obj_module_t mp_module_gc;
|
||||
|
||||
struct _dummy_t;
|
||||
extern struct _dummy_t mp_sys_stdin_obj;
|
||||
extern struct _dummy_t mp_sys_stdout_obj;
|
||||
extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
extern const mp_obj_module_t mp_module_zlibd;
|
||||
extern const mp_obj_module_t mp_module_ujson;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 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
|
||||
@@ -28,7 +29,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
#define PATH_SEP_CHAR '/'
|
||||
|
||||
mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
//printf("stat %s\n", vstr_str(path));
|
||||
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
@@ -68,11 +68,11 @@ mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
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_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
mp_obj_list_get(mp_sys_path, &path_num, &path_items);
|
||||
#endif
|
||||
|
||||
@@ -84,7 +84,7 @@ mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
// 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);
|
||||
@@ -102,7 +102,7 @@ mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *dest) {
|
||||
}
|
||||
}
|
||||
|
||||
void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
|
||||
|
||||
@@ -120,6 +120,9 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
// set the new context
|
||||
mp_locals_set(mp_obj_module_get_globals(module_obj));
|
||||
mp_globals_set(mp_obj_module_get_globals(module_obj));
|
||||
#if MICROPY_PY___FILE__
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false));
|
||||
#endif
|
||||
|
||||
// parse the imported script
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
@@ -138,7 +141,6 @@ 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
|
||||
@@ -162,23 +164,13 @@ void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
mp_globals_set(old_globals);
|
||||
}
|
||||
|
||||
// TODO: Move to objdict?
|
||||
STATIC inline mp_obj_t mp_obj_dict_get(mp_obj_t dict_in, mp_obj_t key) {
|
||||
mp_obj_dict_t *dict = dict_in;
|
||||
mp_map_elem_t *elem = mp_map_lookup(&dict->map, key, MP_MAP_LOOKUP);
|
||||
if (elem == NULL) {
|
||||
return elem;
|
||||
}
|
||||
return elem->value;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -192,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,
|
||||
@@ -206,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;
|
||||
@@ -277,7 +269,7 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
DEBUG_printf("Module not yet loaded\n");
|
||||
|
||||
uint last = 0;
|
||||
VSTR_FIXED(path, MICROPY_PATH_MAX)
|
||||
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
|
||||
module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t top_module_obj = MP_OBJ_NULL;
|
||||
mp_obj_t outer_module_obj = MP_OBJ_NULL;
|
||||
@@ -315,9 +307,9 @@ mp_obj_t mp_builtin___import__(uint n_args, mp_obj_t *args) {
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
DEBUG_printf("%s is dir\n", vstr_str(&path));
|
||||
// https://docs.python.org/3.3/reference/import.html
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
// "Specifically, any module that contains a __path__ attribute is considered a package."
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str((byte*)vstr_str(&path), vstr_len(&path), false));
|
||||
mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false));
|
||||
vstr_add_char(&path, PATH_SEP_CHAR);
|
||||
vstr_add_str(&path, "__init__.py");
|
||||
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
|
||||
@@ -360,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__);
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -43,28 +43,33 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
// built-in types
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bool), (mp_obj_t)&mp_type_bool },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytes), (mp_obj_t)&mp_type_bytes },
|
||||
#if MICROPY_PY_BUILTINS_BYTEARRAY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bytearray), (mp_obj_t)&mp_type_bytearray },
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#endif
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_complex), (mp_obj_t)&mp_type_complex },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dict), (mp_obj_t)&mp_type_dict },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enumerate), (mp_obj_t)&mp_type_enumerate },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_filter), (mp_obj_t)&mp_type_filter },
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_float), (mp_obj_t)&mp_type_float },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_FROZENSET
|
||||
#if MICROPY_PY_BUILTINS_FROZENSET
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_frozenset), (mp_obj_t)&mp_type_frozenset },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
|
||||
#if MICROPY_ENABLE_PROPERTY
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_range), (mp_obj_t)&mp_type_range },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reversed), (mp_obj_t)&mp_type_reversed },
|
||||
#if MICROPY_PY_BUILTINS_SET
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_set), (mp_obj_t)&mp_type_set },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_str), (mp_obj_t)&mp_type_str },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_super), (mp_obj_t)&mp_type_super },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_tuple), (mp_obj_t)&mp_type_tuple },
|
||||
@@ -133,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 },
|
||||
@@ -140,7 +146,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
// TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation
|
||||
|
||||
// Extra builtins as defined by a port
|
||||
MICROPY_EXTRA_BUILTINS
|
||||
MICROPY_PORT_BUILTINS
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_object_dict_obj = {
|
||||
@@ -148,42 +154,65 @@ const mp_obj_dict_t mp_builtin_object_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_object_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_object_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_object_table,
|
||||
},
|
||||
};
|
||||
|
||||
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
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_module_array },
|
||||
#if MICROPY_ENABLE_MOD_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#if MICROPY_PY_IO
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__io), (mp_obj_t)&mp_module_io },
|
||||
#endif
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR__collections), (mp_obj_t)&mp_module_collections },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_STRUCT
|
||||
#if MICROPY_PY_STRUCT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_struct },
|
||||
#endif
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
#if MICROPY_PY_MATH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&mp_module_math },
|
||||
#if MICROPY_ENABLE_MOD_CMATH
|
||||
#endif
|
||||
#if MICROPY_PY_CMATH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_cmath), (mp_obj_t)&mp_module_cmath },
|
||||
#endif
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_SYS
|
||||
#if MICROPY_PY_SYS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sys), (mp_obj_t)&mp_module_sys },
|
||||
#endif
|
||||
#if MICROPY_ENABLE_MOD_GC && MICROPY_ENABLE_GC
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&mp_module_gc },
|
||||
#endif
|
||||
|
||||
// extmod modules
|
||||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
#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_EXTRA_BUILTIN_MODULES
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
@@ -191,8 +220,8 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = ARRAY_SIZE(mp_builtin_module_table),
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_module_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_table,
|
||||
},
|
||||
};
|
||||
|
||||
362
py/compile.c
362
py/compile.c
@@ -31,8 +31,8 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -48,14 +48,13 @@
|
||||
|
||||
// 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,
|
||||
#include "grammar.h"
|
||||
#undef DEF_RULE
|
||||
PN_maximum_number_of,
|
||||
PN_string, // special node for non-interned string
|
||||
} pn_kind_t;
|
||||
|
||||
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
|
||||
@@ -72,8 +71,8 @@ typedef struct _compiler_t {
|
||||
|
||||
uint next_label;
|
||||
|
||||
uint break_label;
|
||||
uint continue_label;
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
int break_continue_except_level;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
|
||||
@@ -94,7 +93,7 @@ typedef struct _compiler_t {
|
||||
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
|
||||
// TODO store the error message to a variable in compiler_t instead of printing it
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (machine_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
} else {
|
||||
printf(" File \"%s\"\n", qstr_str(comp->source_file));
|
||||
}
|
||||
@@ -103,15 +102,18 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
// Extra constants as defined by a port
|
||||
MICROPY_EXTRA_CONSTANTS
|
||||
MICROPY_PORT_CONSTANTS
|
||||
};
|
||||
|
||||
STATIC const mp_map_t mp_constants_map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = ARRAY_SIZE(mp_constants_table),
|
||||
.used = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_constants_table),
|
||||
.table = (mp_map_elem_t*)mp_constants_table,
|
||||
};
|
||||
|
||||
@@ -119,7 +121,7 @@ STATIC const mp_map_t mp_constants_map = {
|
||||
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
|
||||
if (0) {
|
||||
// dummy
|
||||
#if MICROPY_ENABLE_CONST
|
||||
#if MICROPY_COMP_CONST
|
||||
} else if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
// lookup identifier in table of dynamic constants
|
||||
qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
@@ -133,7 +135,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
// fold some parse nodes before folding their arguments
|
||||
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
|
||||
#if MICROPY_ENABLE_CONST
|
||||
#if MICROPY_COMP_CONST
|
||||
case PN_expr_stmt:
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
|
||||
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
|
||||
@@ -157,7 +159,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "constant must be an integer");
|
||||
break;
|
||||
}
|
||||
machine_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
|
||||
|
||||
// store the value in the table of dynamic constants
|
||||
mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(id_qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||
@@ -177,6 +179,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PN_string:
|
||||
return pn;
|
||||
}
|
||||
|
||||
// fold arguments
|
||||
@@ -197,8 +201,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int | int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
|
||||
}
|
||||
break;
|
||||
@@ -206,16 +210,16 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
case PN_and_expr:
|
||||
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
// int & int
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_shift_expr:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
|
||||
// int << int
|
||||
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
|
||||
@@ -232,10 +236,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
break;
|
||||
|
||||
case PN_arith_expr:
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
|
||||
// overflow checking here relies on SMALL_INT being strictly smaller than mp_int_t
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
|
||||
// int + int
|
||||
arg0 += arg1;
|
||||
@@ -246,7 +250,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
// shouldn't happen
|
||||
assert(0);
|
||||
}
|
||||
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
|
||||
if (MP_SMALL_INT_FITS(arg0)) {
|
||||
//printf("%ld + %ld\n", arg0, arg1);
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
|
||||
}
|
||||
@@ -255,13 +259,13 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_term:
|
||||
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
|
||||
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
|
||||
// int * int
|
||||
if (!mp_small_int_mul_overflow(arg0, arg1)) {
|
||||
arg0 *= arg1;
|
||||
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
|
||||
if (MP_SMALL_INT_FITS(arg0)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
|
||||
}
|
||||
}
|
||||
@@ -285,7 +289,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
|
||||
case PN_factor_2:
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
|
||||
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
|
||||
// +int
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
|
||||
@@ -333,8 +337,8 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(elem->value, q_attr, dest);
|
||||
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
|
||||
machine_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_PARSE_FITS_SMALL_INT(val)) {
|
||||
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
|
||||
if (MP_SMALL_INT_FITS(val)) {
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
|
||||
}
|
||||
}
|
||||
@@ -348,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) {
|
||||
@@ -426,6 +430,9 @@ void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
return true;
|
||||
}
|
||||
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
return false;
|
||||
}
|
||||
@@ -435,9 +442,7 @@ STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
|
||||
uint len;
|
||||
const byte *str = qstr_data(qstr, &len);
|
||||
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
@@ -476,6 +481,12 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
|
||||
}
|
||||
|
||||
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(MP_PARSE_NODE_IS_LEAF(pn));
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
|
||||
@@ -487,8 +498,13 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst
|
||||
case MP_PARSE_NODE_ID: assert(0);
|
||||
case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_STRING: cpython_c_print_quoted_str(vstr, arg, false); break;
|
||||
case MP_PARSE_NODE_BYTES: cpython_c_print_quoted_str(vstr, arg, true); break;
|
||||
case MP_PARSE_NODE_STRING:
|
||||
case MP_PARSE_NODE_BYTES: {
|
||||
uint len;
|
||||
const byte *str = qstr_data(arg, &len);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
|
||||
break;
|
||||
}
|
||||
case MP_PARSE_NODE_TOKEN:
|
||||
switch (arg) {
|
||||
case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break;
|
||||
@@ -697,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,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]);
|
||||
}
|
||||
@@ -774,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
|
||||
@@ -814,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);
|
||||
@@ -929,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);
|
||||
|
||||
@@ -942,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;
|
||||
}
|
||||
@@ -964,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
|
||||
@@ -1020,7 +1053,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
|
||||
if (comp->have_star) {
|
||||
comp->num_dict_params += 1;
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
compile_node(comp, pn_equal);
|
||||
#else
|
||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||
if (comp->num_dict_params == 1) {
|
||||
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
||||
@@ -1033,11 +1069,10 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
||||
// first default dict param, so make the map
|
||||
EMIT_ARG(build_map, 0);
|
||||
}
|
||||
#endif
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
|
||||
// compile value then key, then store it to the dict
|
||||
compile_node(comp, pn_equal);
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id), false);
|
||||
EMIT(store_map);
|
||||
#endif
|
||||
} else {
|
||||
@@ -1147,7 +1182,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_
|
||||
|
||||
qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
|
||||
if (attr == MP_QSTR_bytecode) {
|
||||
*emit_options = MP_EMIT_OPT_BYTE_CODE;
|
||||
*emit_options = MP_EMIT_OPT_BYTECODE;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
} else if (attr == MP_QSTR_native) {
|
||||
*emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
|
||||
@@ -1234,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)) {
|
||||
@@ -1386,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;
|
||||
@@ -1446,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;
|
||||
@@ -1725,11 +1760,13 @@ 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
|
||||
|
||||
uint top_label = comp_next_label(comp);
|
||||
uint entry_label = comp_next_label(comp);
|
||||
@@ -1780,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
|
||||
@@ -1828,6 +1866,7 @@ void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#endif
|
||||
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||
|
||||
uint pop_label = comp_next_label(comp);
|
||||
uint end_label = comp_next_label(comp);
|
||||
@@ -1862,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);
|
||||
@@ -1875,7 +1914,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
EMIT_ARG(jump, success_label); // jump over exception handler
|
||||
|
||||
EMIT_ARG(label_assign, l1); // start of exception handler
|
||||
EMIT_ARG(adjust_stack_size, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
EMIT(start_except_handler);
|
||||
|
||||
uint l2 = comp_next_label(comp);
|
||||
|
||||
@@ -1947,14 +1986,14 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except,
|
||||
|
||||
compile_decrease_except_level(comp);
|
||||
EMIT(end_finally);
|
||||
EMIT_ARG(adjust_stack_size, -5); // stack adjust
|
||||
EMIT(end_except_handler);
|
||||
|
||||
EMIT_ARG(label_assign, success_label);
|
||||
compile_node(comp, pn_else); // else block, can be null
|
||||
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);
|
||||
@@ -2006,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);
|
||||
@@ -2058,7 +2097,8 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
} else {
|
||||
// for non-REPL, evaluate then discard the expression
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0])) {
|
||||
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|
||||
// do nothing with a lonely constant
|
||||
} else {
|
||||
compile_node(comp, pns->nodes[0]); // just an expression
|
||||
@@ -2155,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) {
|
||||
@@ -2498,26 +2538,40 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
int n_bytes = 0;
|
||||
int string_kind = MP_PARSE_NODE_NULL;
|
||||
for (int i = 0; i < n; i++) {
|
||||
assert(MP_PARSE_NODE_IS_LEAF(pns->nodes[i]));
|
||||
int pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
|
||||
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
|
||||
int pn_kind;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
pn_kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[i]);
|
||||
assert(pn_kind == MP_PARSE_NODE_STRING || pn_kind == MP_PARSE_NODE_BYTES);
|
||||
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
|
||||
} else {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i]));
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
|
||||
pn_kind = MP_PARSE_NODE_STRING;
|
||||
n_bytes += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
if (i == 0) {
|
||||
string_kind = pn_kind;
|
||||
} else if (pn_kind != string_kind) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "cannot mix bytes and nonbytes literals");
|
||||
return;
|
||||
}
|
||||
n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
|
||||
}
|
||||
|
||||
// concatenate string/bytes
|
||||
byte *q_ptr;
|
||||
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
uint s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
|
||||
memcpy(s_dest, (const char*)pns_string->nodes[0], (mp_uint_t)pns_string->nodes[1]);
|
||||
s_dest += (mp_uint_t)pns_string->nodes[1];
|
||||
}
|
||||
}
|
||||
qstr q = qstr_build_end(q_ptr);
|
||||
|
||||
@@ -2525,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];
|
||||
@@ -2820,14 +2874,14 @@ 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)) {
|
||||
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
|
||||
EMIT_ARG(load_const_small_int, arg);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
machine_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: EMIT_ARG(load_id, arg); break;
|
||||
case MP_PARSE_NODE_INTEGER: EMIT_ARG(load_const_int, arg); break;
|
||||
@@ -2848,24 +2902,27 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) {
|
||||
} else {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
EMIT_ARG(set_line_number, pns->source_line);
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
mp_parse_node_print(pn, 0);
|
||||
#endif
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
|
||||
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
|
||||
} else {
|
||||
f(comp, pns);
|
||||
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
|
||||
if (f == NULL) {
|
||||
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
mp_parse_node_print(pn, 0);
|
||||
#endif
|
||||
compile_syntax_error(comp, pn, "internal compiler error");
|
||||
} else {
|
||||
f(comp, pns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -2880,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;
|
||||
@@ -2916,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);
|
||||
@@ -2929,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?
|
||||
@@ -2941,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) {
|
||||
@@ -2956,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
|
||||
@@ -3033,13 +3111,13 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
|
||||
// check the first statement for a doc string
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_expr_stmt)) {
|
||||
mp_parse_node_struct_t* pns = (mp_parse_node_struct_t*)pn;
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0])) {
|
||||
int kind = MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]);
|
||||
if (kind == MP_PARSE_NODE_STRING) {
|
||||
compile_node(comp, pns->nodes[0]); // a doc string
|
||||
// store doc string
|
||||
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0])
|
||||
&& MP_PARSE_NODE_LEAF_KIND(pns->nodes[0]) == MP_PARSE_NODE_STRING)
|
||||
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|
||||
// compile the doc string
|
||||
compile_node(comp, pns->nodes[0]);
|
||||
// store the doc string
|
||||
EMIT_ARG(store_id, MP_QSTR___doc__);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3087,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
|
||||
@@ -3299,7 +3396,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
return;
|
||||
}
|
||||
if (pass > MP_PASS_SCOPE) {
|
||||
machine_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
|
||||
for (uint i = 1; i < n_args; i++) {
|
||||
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
|
||||
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
|
||||
@@ -3349,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;
|
||||
}
|
||||
@@ -3394,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
|
||||
@@ -3541,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);
|
||||
@@ -3587,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
|
||||
@@ -3599,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;) {
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
// These must fit in 8 bits; see scope.h
|
||||
enum {
|
||||
MP_EMIT_OPT_NONE,
|
||||
MP_EMIT_OPT_BYTE_CODE,
|
||||
MP_EMIT_OPT_BYTECODE,
|
||||
MP_EMIT_OPT_NATIVE_PYTHON,
|
||||
MP_EMIT_OPT_VIPER,
|
||||
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);
|
||||
|
||||
158
py/emit.h
158
py/emit.h
@@ -44,138 +44,154 @@ typedef enum {
|
||||
#define MP_EMIT_STAR_FLAG_SINGLE (0x01)
|
||||
#define MP_EMIT_STAR_FLAG_DOUBLE (0x02)
|
||||
|
||||
#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, machine_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_small_int)(emit_t *emit, mp_int_t arg);
|
||||
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);
|
||||
|
||||
// these methods are used to control entry to/exit from an exception handler
|
||||
// they may or may not emit code
|
||||
void (*start_except_handler)(emit_t *emit);
|
||||
void (*end_except_handler)(emit_t *emit);
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
378
py/emitbc.c
378
py/emitbc.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -49,41 +49,58 @@
|
||||
|
||||
struct _emit_t {
|
||||
pass_kind_t pass : 8;
|
||||
uint last_emit_was_return_value : 8;
|
||||
byte dummy_data[DUMMY_DATA_SIZE];
|
||||
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 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);
|
||||
@@ -99,27 +116,38 @@ STATIC byte* emit_get_cur_to_write_code_info(emit_t* emit, int num_bytes_to_writ
|
||||
}
|
||||
|
||||
STATIC void emit_align_code_info_to_machine_word(emit_t* emit) {
|
||||
emit->code_info_offset = (emit->code_info_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
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) {
|
||||
uint b = MIN(bytes_to_skip, 31);
|
||||
uint l = MIN(lines_to_skip, 7);
|
||||
mp_uint_t b, l;
|
||||
if (lines_to_skip <= 6) {
|
||||
// use 0b0LLBBBBB encoding
|
||||
b = MIN(bytes_to_skip, 0x1f);
|
||||
l = MIN(lines_to_skip, 0x3);
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
} else {
|
||||
// use 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte)
|
||||
b = MIN(bytes_to_skip, 0xf);
|
||||
l = MIN(lines_to_skip, 0x7ff);
|
||||
byte *ci = emit_get_cur_to_write_code_info(emit, 2);
|
||||
ci[0] = 0x80 | b | ((l >> 4) & 0x70);
|
||||
ci[1] = l;
|
||||
}
|
||||
bytes_to_skip -= b;
|
||||
lines_to_skip -= l;
|
||||
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -139,7 +167,7 @@ STATIC byte* emit_get_cur_to_write_bytecode(emit_t* emit, int num_bytes_to_write
|
||||
}
|
||||
|
||||
STATIC void emit_align_bytecode_to_machine_word(emit_t* emit) {
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(machine_uint_t) - 1) & (~(sizeof(machine_uint_t) - 1));
|
||||
emit->bytecode_offset = (emit->bytecode_offset + sizeof(mp_uint_t) - 1) & (~(sizeof(mp_uint_t) - 1));
|
||||
}
|
||||
|
||||
STATIC void emit_write_bytecode_byte(emit_t* emit, byte b1) {
|
||||
@@ -147,31 +175,19 @@ 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, machine_int_t num) {
|
||||
STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, mp_int_t num) {
|
||||
emit_write_bytecode_byte(emit, b1);
|
||||
|
||||
// We store each 7 bits in a separate byte, and that's how many bytes needed
|
||||
@@ -197,34 +213,36 @@ STATIC void emit_write_bytecode_byte_int(emit_t* emit, byte b1, machine_int_t nu
|
||||
*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
|
||||
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
|
||||
emit_write_bytecode_byte(emit, b);
|
||||
emit_align_bytecode_to_machine_word(emit);
|
||||
machine_uint_t *c = (machine_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(machine_uint_t));
|
||||
*c = (machine_uint_t)ptr;
|
||||
mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
|
||||
// Verify thar c is already uint-aligned
|
||||
assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
|
||||
*c = (mp_uint_t)ptr;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
@@ -237,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;
|
||||
@@ -250,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) {
|
||||
@@ -261,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);
|
||||
machine_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
|
||||
@@ -321,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);
|
||||
@@ -332,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,
|
||||
@@ -345,38 +373,41 @@ 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) {
|
||||
// If we compile with -O3, don't store line numbers.
|
||||
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);
|
||||
//printf(" %d %d\n", bytes_to_skip, lines_to_skip);
|
||||
emit->last_source_line_offset = emit->bytecode_offset;
|
||||
emit->last_source_line = 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;
|
||||
@@ -384,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) {
|
||||
@@ -398,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) {
|
||||
@@ -424,27 +455,27 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_bc_pre(emit, 1);
|
||||
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,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) {
|
||||
@@ -464,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) {
|
||||
@@ -499,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) {
|
||||
@@ -510,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) {
|
||||
@@ -535,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) {
|
||||
@@ -590,42 +621,46 @@ 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_jump(emit, label);
|
||||
} else {
|
||||
emit_bc_pre(emit, 0);
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label);
|
||||
emit_write_bytecode_byte(emit, except_depth);
|
||||
if (label & MP_EMIT_BREAK_FROM_FOR) {
|
||||
// need to pop the iterator if we are breaking out of a for loop
|
||||
emit_write_bytecode_byte(emit, MP_BC_POP_TOP);
|
||||
}
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||
} else {
|
||||
emit_write_bytecode_byte_signed_label(emit, MP_BC_UNWIND_JUMP, label & ~MP_EMIT_BREAK_FROM_FOR);
|
||||
emit_write_bytecode_byte(emit, ((label & MP_EMIT_BREAK_FROM_FOR) ? 0x80 : 0) | 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);
|
||||
}
|
||||
@@ -635,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);
|
||||
}
|
||||
@@ -655,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);
|
||||
}
|
||||
@@ -703,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);
|
||||
}
|
||||
@@ -732,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);
|
||||
@@ -778,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);
|
||||
@@ -791,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
|
||||
@@ -801,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);
|
||||
}
|
||||
|
||||
@@ -823,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);
|
||||
@@ -841,8 +866,16 @@ STATIC void emit_bc_yield_from(emit_t *emit) {
|
||||
emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
|
||||
}
|
||||
|
||||
STATIC void emit_bc_start_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, 6); // stack adjust for the 3 exception items, +3 for possible UNWIND_JUMP state
|
||||
}
|
||||
|
||||
STATIC void emit_bc_end_except_handler(emit_t *emit) {
|
||||
emit_bc_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -926,6 +959,9 @@ const emit_method_table_t emit_bc_method_table = {
|
||||
emit_bc_raise_varargs,
|
||||
emit_bc_yield_value,
|
||||
emit_bc_yield_from,
|
||||
|
||||
emit_bc_start_except_handler,
|
||||
emit_bc_end_except_handler,
|
||||
};
|
||||
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
255
py/emitcpy.c
255
py/emitcpy.c
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,29 +173,29 @@ STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, machine_int_t arg) {
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST " INT_FMT "\n", 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,6 +792,14 @@ STATIC void emit_cpy_yield_from(emit_t *emit) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, -5); // stack adjust
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
@@ -799,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,
|
||||
@@ -899,6 +907,9 @@ const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_yield_value,
|
||||
emit_cpy_yield_from,
|
||||
|
||||
emit_cpy_start_except_handler,
|
||||
emit_cpy_end_except_handler,
|
||||
|
||||
// emitcpy specific functions
|
||||
emit_cpy_load_const_verbatim_str,
|
||||
emit_cpy_load_closure,
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
@@ -49,31 +49,13 @@
|
||||
#define DEBUG_OP_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
#ifdef WRITE_CODE
|
||||
FILE *fp_write_code = NULL;
|
||||
#endif
|
||||
|
||||
void mp_emit_glue_init(void) {
|
||||
#ifdef WRITE_CODE
|
||||
fp_write_code = fopen("out-code", "wb");
|
||||
#endif
|
||||
}
|
||||
|
||||
void mp_emit_glue_deinit(void) {
|
||||
#ifdef WRITE_CODE
|
||||
if (fp_write_code != NULL) {
|
||||
fclose(fp_write_code);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
|
||||
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
|
||||
rc->kind = MP_CODE_RESERVED;
|
||||
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;
|
||||
@@ -83,53 +65,54 @@ 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]));
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
for (int i = 0; i < 128 && i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
DEBUG_printf("\n");
|
||||
}
|
||||
DEBUG_printf(" %02x", code[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
#endif
|
||||
#if MICROPY_DEBUG_PRINTERS
|
||||
if (mp_verbose_flag > 0) {
|
||||
mp_bytecode_print(code, len);
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
if (i > 0 && i % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf(" %02x", code[i]);
|
||||
}
|
||||
printf("\n");
|
||||
mp_bytecode_print(rc, code, len);
|
||||
}
|
||||
#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*)(((machine_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
|
||||
if (fp_write_code != NULL) {
|
||||
fwrite(fun_data, len, 1, fp_write_code);
|
||||
fflush(fp_write_code);
|
||||
}
|
||||
FILE *fp_write_code = fopen("out-code", "wb");
|
||||
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);
|
||||
@@ -138,22 +121,28 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
|
||||
// def_args must be MP_OBJ_NULL or a tuple
|
||||
assert(def_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_args, &mp_type_tuple));
|
||||
|
||||
// TODO implement default kw args
|
||||
assert(def_kw_args == MP_OBJ_NULL);
|
||||
// def_kw_args must be MP_OBJ_NULL or a dict
|
||||
assert(def_kw_args == MP_OBJ_NULL || MP_OBJ_IS_TYPE(def_kw_args, &mp_type_dict));
|
||||
|
||||
// make the function, depending on the raw code kind
|
||||
mp_obj_t fun;
|
||||
switch (rc->kind) {
|
||||
case MP_CODE_BYTECODE:
|
||||
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->arg_names, rc->n_pos_args, rc->n_kwonly_args, def_args, rc->u_byte.code);
|
||||
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);
|
||||
@@ -168,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) {
|
||||
|
||||
@@ -37,28 +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;
|
||||
|
||||
void mp_emit_glue_init(void);
|
||||
void mp_emit_glue_deinit(void);
|
||||
|
||||
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);
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -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 < 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 = ®_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 < 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,20 +310,19 @@ 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) {
|
||||
} 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);
|
||||
asm_thumb_format_4(emit->as, op_code, reg_dest, reg_src);
|
||||
// TODO probably uses less ROM if these ops are in a lookup table
|
||||
} else if (strcmp(op_str, "and") == 0) { op_code = ASM_THUMB_FORMAT_4_AND; goto op_format_4;
|
||||
} else if (strcmp(op_str, "eor") == 0) { op_code = ASM_THUMB_FORMAT_4_EOR; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsl") == 0) { op_code = ASM_THUMB_FORMAT_4_LSL; goto op_format_4;
|
||||
} else if (strcmp(op_str, "lsr") == 0) { op_code = ASM_THUMB_FORMAT_4_LSR; goto op_format_4;
|
||||
@@ -344,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);
|
||||
@@ -362,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);
|
||||
@@ -414,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);
|
||||
|
||||
1238
py/emitnative.c
1238
py/emitnative.c
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,8 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
#include "parse.h"
|
||||
@@ -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
|
||||
@@ -214,6 +214,10 @@ const emit_method_table_t emit_pass1_method_table = {
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
(void*)emit_pass1_dummy,
|
||||
(void*)emit_pass1_dummy,
|
||||
|
||||
@@ -75,7 +75,7 @@ int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char s
|
||||
|
||||
if (buf_size < 7) {
|
||||
// Smallest exp notion is -9e+99 which is 6 chars plus terminating
|
||||
// nulll.
|
||||
// null.
|
||||
|
||||
if (buf_size >= 2) {
|
||||
*s++ = '?';
|
||||
|
||||
244
py/gc.c
244
py/gc.c
@@ -33,7 +33,6 @@
|
||||
#include "misc.h"
|
||||
#include "gc.h"
|
||||
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
@@ -47,22 +46,26 @@
|
||||
#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
|
||||
|
||||
STATIC byte *gc_alloc_table_start;
|
||||
STATIC machine_uint_t gc_alloc_table_byte_len;
|
||||
STATIC mp_uint_t gc_alloc_table_byte_len;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
STATIC byte *gc_finaliser_table_start;
|
||||
#endif
|
||||
STATIC machine_uint_t *gc_pool_start;
|
||||
STATIC machine_uint_t *gc_pool_end;
|
||||
STATIC mp_uint_t *gc_pool_start;
|
||||
STATIC mp_uint_t *gc_pool_end;
|
||||
|
||||
STATIC int gc_stack_overflow;
|
||||
STATIC machine_uint_t gc_stack[STACK_SIZE];
|
||||
STATIC machine_uint_t *gc_sp;
|
||||
STATIC machine_uint_t gc_lock_depth;
|
||||
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
|
||||
@@ -94,8 +97,8 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
|
||||
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
|
||||
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (machine_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (machine_uint_t)gc_pool_start))
|
||||
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
|
||||
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
|
||||
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -112,32 +115,35 @@ STATIC machine_uint_t gc_lock_depth;
|
||||
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
|
||||
void gc_init(void *start, void *end) {
|
||||
// align end pointer on block boundary
|
||||
end = (void*)((machine_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, end - start);
|
||||
end = (void*)((mp_uint_t)end & (~(BYTES_PER_BLOCK - 1)));
|
||||
DEBUG_printf("Initializing GC heap: %p..%p = " UINT_FMT " bytes\n", start, end, (byte*)end - (byte*)start);
|
||||
|
||||
// calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
|
||||
// T = A + F + P
|
||||
// F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
|
||||
// P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
|
||||
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
|
||||
machine_uint_t total_byte_len = end - start;
|
||||
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
|
||||
#else
|
||||
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
|
||||
#endif
|
||||
|
||||
|
||||
gc_alloc_table_start = (byte*)start;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
machine_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB) / BLOCKS_PER_FTB;
|
||||
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
|
||||
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
|
||||
#endif
|
||||
|
||||
machine_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = end - gc_pool_block_len * BYTES_PER_BLOCK;
|
||||
gc_pool_end = end;
|
||||
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
|
||||
gc_pool_end = (mp_uint_t*)end;
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
|
||||
#endif
|
||||
|
||||
// clear ATBs
|
||||
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
|
||||
@@ -154,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;
|
||||
|
||||
@@ -173,16 +182,20 @@ void gc_unlock(void) {
|
||||
gc_lock_depth--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return gc_lock_depth != 0;
|
||||
}
|
||||
|
||||
#define VERIFY_PTR(ptr) ( \
|
||||
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
|
||||
&& ptr >= (machine_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (machine_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
|
||||
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
|
||||
)
|
||||
|
||||
#define VERIFY_MARK_AND_PUSH(ptr) \
|
||||
do { \
|
||||
if (VERIFY_PTR(ptr)) { \
|
||||
machine_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
mp_uint_t _block = BLOCK_FROM_PTR(ptr); \
|
||||
if (ATB_GET_KIND(_block) == AT_HEAD) { \
|
||||
/* an unmarked head, mark it, and push it on gc stack */ \
|
||||
ATB_HEAD_TO_MARK(_block); \
|
||||
@@ -198,18 +211,18 @@ void gc_unlock(void) {
|
||||
STATIC void gc_drain_stack(void) {
|
||||
while (gc_sp > gc_stack) {
|
||||
// pop the next block off the stack
|
||||
machine_uint_t block = *--gc_sp;
|
||||
mp_uint_t block = *--gc_sp;
|
||||
|
||||
// work out number of consecutive blocks in the chain starting with this one
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
|
||||
// check this block's children
|
||||
machine_uint_t *scan = (machine_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (machine_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
machine_uint_t ptr2 = *scan;
|
||||
mp_uint_t *scan = (mp_uint_t*)PTR_FROM_BLOCK(block);
|
||||
for (mp_uint_t i = n_blocks * WORDS_PER_BLOCK; i > 0; i--, scan++) {
|
||||
mp_uint_t ptr2 = *scan;
|
||||
VERIFY_MARK_AND_PUSH(ptr2);
|
||||
}
|
||||
}
|
||||
@@ -221,7 +234,7 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
gc_sp = gc_stack;
|
||||
|
||||
// scan entire memory looking for blocks which have been marked but not their children
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
// trace (again) if mark bit set
|
||||
if (ATB_GET_KIND(block) == AT_MARK) {
|
||||
*gc_sp++ = block;
|
||||
@@ -231,10 +244,17 @@ STATIC void gc_deal_with_stack_overflow(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
uint gc_collected;
|
||||
#endif
|
||||
|
||||
STATIC void gc_sweep(void) {
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
gc_collected = 0;
|
||||
#endif
|
||||
// free unmarked heads and their tails
|
||||
int free_tail = 0;
|
||||
for (machine_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
switch (ATB_GET_KIND(block)) {
|
||||
case AT_HEAD:
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
@@ -254,10 +274,14 @@ STATIC void gc_sweep(void) {
|
||||
}
|
||||
#endif
|
||||
free_tail = 1;
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
gc_collected++;
|
||||
#endif
|
||||
// fall through to free the head
|
||||
|
||||
case AT_TAIL:
|
||||
if (free_tail) {
|
||||
DEBUG_printf("gc_sweep(%p)\n",PTR_FROM_BLOCK(block));
|
||||
ATB_ANY_TO_FREE(block);
|
||||
}
|
||||
break;
|
||||
@@ -276,9 +300,9 @@ void gc_collect_start(void) {
|
||||
gc_sp = gc_stack;
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
for (machine_uint_t i = 0; i < len; i++) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptrs[i];
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len) {
|
||||
for (mp_uint_t i = 0; i < len; i++) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptrs[i];
|
||||
VERIFY_MARK_AND_PUSH(ptr);
|
||||
gc_drain_stack();
|
||||
}
|
||||
@@ -287,18 +311,19 @@ void gc_collect_root(void **ptrs, machine_uint_t len) {
|
||||
void gc_collect_end(void) {
|
||||
gc_deal_with_stack_overflow();
|
||||
gc_sweep();
|
||||
gc_last_free_atb_index = 0;
|
||||
gc_unlock();
|
||||
}
|
||||
|
||||
void gc_info(gc_info_t *info) {
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(machine_uint_t);
|
||||
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
|
||||
info->used = 0;
|
||||
info->free = 0;
|
||||
info->num_1block = 0;
|
||||
info->num_2block = 0;
|
||||
info->max_block = 0;
|
||||
for (machine_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
machine_uint_t kind = ATB_GET_KIND(block);
|
||||
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
|
||||
mp_uint_t kind = ATB_GET_KIND(block);
|
||||
if (kind == AT_FREE || kind == AT_HEAD) {
|
||||
if (len == 1) {
|
||||
info->num_1block += 1;
|
||||
@@ -335,8 +360,8 @@ void gc_info(gc_info_t *info) {
|
||||
info->free *= BYTES_PER_BLOCK;
|
||||
}
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
|
||||
mp_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
|
||||
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
|
||||
|
||||
// check if GC is locked
|
||||
@@ -349,15 +374,15 @@ void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
machine_uint_t i;
|
||||
machine_uint_t end_block;
|
||||
machine_uint_t start_block;
|
||||
machine_uint_t n_free = 0;
|
||||
mp_uint_t i;
|
||||
mp_uint_t end_block;
|
||||
mp_uint_t start_block;
|
||||
mp_uint_t n_free = 0;
|
||||
int collected = 0;
|
||||
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; }
|
||||
@@ -380,24 +405,34 @@ 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);
|
||||
|
||||
// mark rest of blocks as used tail
|
||||
// TODO for a run of many blocks can make this more efficient
|
||||
for (machine_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
for (mp_uint_t bl = start_block + 1; bl <= end_block; bl++) {
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// get pointer to first block
|
||||
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
|
||||
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks
|
||||
// This is needed because the blocks may have previously held pointers
|
||||
// to the heap and will not be set to something else if the caller
|
||||
// doesn't actually use the entire block. As such they will continue
|
||||
// to point to the heap and may prevent other blocks from being reclaimed.
|
||||
memset(ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);
|
||||
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
if (has_finaliser) {
|
||||
@@ -408,15 +443,19 @@ found:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
gc_dump_alloc_table();
|
||||
#endif
|
||||
|
||||
return ret_ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
void *gc_alloc(machine_uint_t n_bytes) {
|
||||
void *gc_alloc(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
void *gc_alloc_with_finaliser(machine_uint_t n_bytes) {
|
||||
void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
||||
return _gc_alloc(n_bytes, true);
|
||||
}
|
||||
*/
|
||||
@@ -428,28 +467,38 @@ void gc_free(void *ptr_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
DEBUG_printf("gc_free(%p)\n", ptr);
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t gc_nbytes(void *ptr_in) {
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
// work out number of consecutive blocks in the chain starting with this on
|
||||
machine_uint_t n_blocks = 0;
|
||||
mp_uint_t n_blocks = 0;
|
||||
do {
|
||||
n_blocks += 1;
|
||||
} while (ATB_GET_KIND(block + n_blocks) == AT_TAIL);
|
||||
@@ -463,8 +512,8 @@ machine_uint_t gc_nbytes(void *ptr_in) {
|
||||
|
||||
#if 0
|
||||
// old, simple realloc that didn't expand memory in place
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
machine_uint_t n_existing = gc_nbytes(ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
|
||||
mp_uint_t n_existing = gc_nbytes(ptr);
|
||||
if (n_bytes <= n_existing) {
|
||||
return ptr;
|
||||
} else {
|
||||
@@ -473,7 +522,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
has_finaliser = false;
|
||||
} else {
|
||||
#if MICROPY_ENABLE_FINALISER
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr));
|
||||
has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr));
|
||||
#else
|
||||
has_finaliser = false;
|
||||
#endif
|
||||
@@ -490,7 +539,7 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
|
||||
|
||||
#else // Alternative gc_realloc impl
|
||||
|
||||
void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
|
||||
if (gc_lock_depth > 0) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -500,7 +549,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return gc_alloc(n_bytes, false);
|
||||
}
|
||||
|
||||
machine_uint_t ptr = (machine_uint_t)ptr_in;
|
||||
mp_uint_t ptr = (mp_uint_t)ptr_in;
|
||||
|
||||
// sanity check the ptr
|
||||
if (!VERIFY_PTR(ptr)) {
|
||||
@@ -508,7 +557,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// get first block
|
||||
machine_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
mp_uint_t block = BLOCK_FROM_PTR(ptr);
|
||||
|
||||
// sanity check the ptr is pointing to the head of a block
|
||||
if (ATB_GET_KIND(block) != AT_HEAD) {
|
||||
@@ -516,14 +565,14 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
}
|
||||
|
||||
// compute number of new blocks that are requested
|
||||
machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
|
||||
|
||||
// get the number of consecutive tail blocks and
|
||||
// the number of free blocks after last tail block
|
||||
// stop if we reach (or are at) end of heap
|
||||
machine_uint_t n_free = 0;
|
||||
machine_uint_t n_blocks = 1; // counting HEAD block
|
||||
machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
mp_uint_t n_free = 0;
|
||||
mp_uint_t n_blocks = 1; // counting HEAD block
|
||||
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
|
||||
while (block + n_blocks + n_free < max_block) {
|
||||
if (n_blocks + n_free >= new_blocks) {
|
||||
// stop as soon as we find enough blocks for n_bytes
|
||||
@@ -546,22 +595,36 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
// check if we can shrink the allocated area
|
||||
if (new_blocks < n_blocks) {
|
||||
// free unneeded tail blocks
|
||||
for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
|
||||
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;
|
||||
}
|
||||
|
||||
// check if we can expand in place
|
||||
if (new_blocks <= n_blocks + n_free) {
|
||||
// mark few more blocks as used tail
|
||||
for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
for (mp_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
|
||||
assert(ATB_GET_KIND(bl) == AT_FREE);
|
||||
ATB_FREE_TO_TAIL(bl);
|
||||
}
|
||||
|
||||
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
|
||||
memset(ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes);
|
||||
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;
|
||||
}
|
||||
@@ -580,7 +643,7 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_printf("gc_realloc: allocating new block\n");
|
||||
DEBUG_printf("gc_realloc(%p -> %p)\n", ptr_in, ptr_out);
|
||||
memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
|
||||
gc_free(ptr_in);
|
||||
return ptr_out;
|
||||
@@ -596,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);
|
||||
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % 64 == 0) {
|
||||
#endif
|
||||
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
|
||||
if (bl % DUMP_BYTES_PER_LINE == 0) {
|
||||
// a new line of blocks
|
||||
#if EXTENSIVE_HEAP_PROFILING
|
||||
{
|
||||
// check if this line contains only free blocks
|
||||
bool only_free_blocks = true;
|
||||
for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) {
|
||||
if (ATB_GET_KIND(bl2) != AT_FREE) {
|
||||
|
||||
only_free_blocks = false;
|
||||
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 = ' ';
|
||||
@@ -607,12 +695,12 @@ void gc_dump_alloc_table(void) {
|
||||
case AT_HEAD: c = 'h'; break;
|
||||
/* this prints the uPy object type of the head block
|
||||
case AT_HEAD: {
|
||||
machine_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (machine_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (machine_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
|
||||
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; }
|
||||
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
|
||||
else { c = 'h'; }
|
||||
break;
|
||||
}
|
||||
@@ -627,23 +715,23 @@ void gc_dump_alloc_table(void) {
|
||||
|
||||
#if DEBUG_PRINT
|
||||
void gc_test(void) {
|
||||
machine_uint_t len = 500;
|
||||
machine_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(machine_uint_t));
|
||||
mp_uint_t len = 500;
|
||||
mp_uint_t *heap = malloc(len);
|
||||
gc_init(heap, heap + len / sizeof(mp_uint_t));
|
||||
void *ptrs[100];
|
||||
{
|
||||
machine_uint_t **p = gc_alloc(16, false);
|
||||
mp_uint_t **p = gc_alloc(16, false);
|
||||
p[0] = gc_alloc(64, false);
|
||||
p[1] = gc_alloc(1, false);
|
||||
p[2] = gc_alloc(1, false);
|
||||
p[3] = gc_alloc(1, false);
|
||||
machine_uint_t ***p2 = gc_alloc(16, false);
|
||||
mp_uint_t ***p2 = gc_alloc(16, false);
|
||||
p2[0] = p;
|
||||
p2[1] = p;
|
||||
ptrs[0] = p2;
|
||||
}
|
||||
for (int i = 0; i < 25; i+=2) {
|
||||
machine_uint_t *p = gc_alloc(i, false);
|
||||
mp_uint_t *p = gc_alloc(i, false);
|
||||
printf("p=%p\n", p);
|
||||
if (i & 3) {
|
||||
//ptrs[i] = p;
|
||||
|
||||
21
py/gc.h
21
py/gc.h
@@ -30,25 +30,26 @@ void gc_init(void *start, void *end);
|
||||
// They can be used to prevent the GC from allocating/freeing.
|
||||
void gc_lock(void);
|
||||
void gc_unlock(void);
|
||||
bool gc_is_locked(void);
|
||||
|
||||
// A given port must implement gc_collect by using the other collect functions.
|
||||
void gc_collect(void);
|
||||
void gc_collect_start(void);
|
||||
void gc_collect_root(void **ptrs, machine_uint_t len);
|
||||
void gc_collect_root(void **ptrs, mp_uint_t len);
|
||||
void gc_collect_end(void);
|
||||
|
||||
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser);
|
||||
void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser);
|
||||
void gc_free(void *ptr);
|
||||
machine_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, machine_uint_t n_bytes);
|
||||
mp_uint_t gc_nbytes(void *ptr);
|
||||
void *gc_realloc(void *ptr, mp_uint_t n_bytes);
|
||||
|
||||
typedef struct _gc_info_t {
|
||||
machine_uint_t total;
|
||||
machine_uint_t used;
|
||||
machine_uint_t free;
|
||||
machine_uint_t num_1block;
|
||||
machine_uint_t num_2block;
|
||||
machine_uint_t max_block;
|
||||
mp_uint_t total;
|
||||
mp_uint_t used;
|
||||
mp_uint_t free;
|
||||
mp_uint_t num_1block;
|
||||
mp_uint_t num_2block;
|
||||
mp_uint_t max_block;
|
||||
} gc_info_t;
|
||||
|
||||
void gc_info(gc_info_t *info);
|
||||
|
||||
146
py/lexer.c
146
py/lexer.c
@@ -32,8 +32,8 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
@@ -45,28 +45,30 @@
|
||||
struct _mp_lexer_t {
|
||||
qstr source_name; // name of source
|
||||
void *stream_data; // data for stream
|
||||
mp_lexer_stream_next_char_t stream_next_char; // stream callback to get next char
|
||||
mp_lexer_stream_next_byte_t stream_next_byte; // stream callback to get next byte
|
||||
mp_lexer_stream_close_t stream_close; // stream callback to free
|
||||
|
||||
unichar chr0, chr1, chr2; // current cached characters from source
|
||||
|
||||
uint line; // source line
|
||||
uint column; // source column
|
||||
mp_uint_t line; // source line
|
||||
mp_uint_t column; // source column
|
||||
|
||||
int emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
int nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
mp_int_t emit_dent; // non-zero when there are INDENT/DEDENT tokens to emit
|
||||
mp_int_t nested_bracket_level; // >0 when there are nested brackets over multiple lines
|
||||
|
||||
uint alloc_indent_level;
|
||||
uint num_indent_level;
|
||||
mp_uint_t alloc_indent_level;
|
||||
mp_uint_t num_indent_level;
|
||||
uint16_t *indent_level;
|
||||
|
||||
vstr_t vstr;
|
||||
mp_token_t tok_cur;
|
||||
};
|
||||
|
||||
mp_uint_t mp_optimise_value;
|
||||
|
||||
// TODO replace with a call to a standard function
|
||||
bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
uint i = 0;
|
||||
bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
|
||||
mp_uint_t i = 0;
|
||||
|
||||
while (i < len && *str == *strn) {
|
||||
++i;
|
||||
@@ -79,10 +81,10 @@ bool str_strn_equal(const char *str, const char *strn, int len) {
|
||||
|
||||
#ifdef MICROPY_DEBUG_PRINTERS
|
||||
void mp_token_show(const mp_token_t *tok) {
|
||||
printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:" UINT_FMT, tok->src_line, tok->src_column, tok->kind, tok->str, tok->len);
|
||||
if (tok->str != NULL && tok->len > 0) {
|
||||
const char *i = tok->str;
|
||||
const char *j = i + tok->len;
|
||||
const byte *i = (const byte *)tok->str;
|
||||
const byte *j = (const byte *)i + tok->len;
|
||||
printf(" ");
|
||||
while (i < j) {
|
||||
unichar c = utf8_get_char(i);
|
||||
@@ -101,7 +103,7 @@ void mp_token_show(const mp_token_t *tok) {
|
||||
#define CUR_CHAR(lex) ((lex)->chr0)
|
||||
|
||||
STATIC bool is_end(mp_lexer_t *lex) {
|
||||
return lex->chr0 == MP_LEXER_CHAR_EOF;
|
||||
return lex->chr0 == MP_LEXER_EOF;
|
||||
}
|
||||
|
||||
STATIC bool is_physical_newline(mp_lexer_t *lex) {
|
||||
@@ -169,11 +171,11 @@ STATIC bool is_tail_of_identifier(mp_lexer_t *lex) {
|
||||
}
|
||||
|
||||
STATIC void next_char(mp_lexer_t *lex) {
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
int advance = 1;
|
||||
mp_uint_t advance = 1;
|
||||
|
||||
if (lex->chr0 == '\n') {
|
||||
// LF is a new line
|
||||
@@ -198,26 +200,26 @@ STATIC void next_char(mp_lexer_t *lex) {
|
||||
for (; advance > 0; advance--) {
|
||||
lex->chr0 = lex->chr1;
|
||||
lex->chr1 = lex->chr2;
|
||||
lex->chr2 = lex->stream_next_char(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
lex->chr2 = lex->stream_next_byte(lex->stream_data);
|
||||
if (lex->chr2 == MP_LEXER_EOF) {
|
||||
// EOF
|
||||
if (lex->chr1 != MP_LEXER_CHAR_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
if (lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n'; // insert newline at end of file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void indent_push(mp_lexer_t *lex, uint indent) {
|
||||
void indent_push(mp_lexer_t *lex, mp_uint_t indent) {
|
||||
if (lex->num_indent_level >= lex->alloc_indent_level) {
|
||||
// TODO use m_renew_maybe and somehow indicate an error if it fails... probably by using MP_TOKEN_MEMORY_ERROR
|
||||
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MP_ALLOC_LEXEL_INDENT_INC);
|
||||
lex->alloc_indent_level += MP_ALLOC_LEXEL_INDENT_INC;
|
||||
lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);
|
||||
lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC;
|
||||
}
|
||||
lex->indent_level[lex->num_indent_level++] = indent;
|
||||
}
|
||||
|
||||
uint indent_top(mp_lexer_t *lex) {
|
||||
mp_uint_t indent_top(mp_lexer_t *lex) {
|
||||
return lex->indent_level[lex->num_indent_level - 1];
|
||||
}
|
||||
|
||||
@@ -303,12 +305,12 @@ STATIC const char *tok_kw[] = {
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
NULL,
|
||||
"__debug__",
|
||||
};
|
||||
|
||||
STATIC int hex_digit(unichar c) {
|
||||
STATIC mp_uint_t hex_digit(unichar c) {
|
||||
// c is assumed to be hex digit
|
||||
int n = c - '0';
|
||||
mp_uint_t n = c - '0';
|
||||
if (n > 9) {
|
||||
n &= ~('a' - 'A');
|
||||
n -= ('A' - ('9' + 1));
|
||||
@@ -318,8 +320,9 @@ STATIC int hex_digit(unichar c) {
|
||||
|
||||
// This is called with CUR_CHAR() before first hex digit, and should return with
|
||||
// it pointing to last hex digit
|
||||
STATIC bool get_hex(mp_lexer_t *lex, int num_digits, uint *result) {
|
||||
uint num = 0;
|
||||
// num_digits must be greater than zero
|
||||
STATIC bool get_hex(mp_lexer_t *lex, mp_uint_t num_digits, mp_uint_t *result) {
|
||||
mp_uint_t num = 0;
|
||||
while (num_digits-- != 0) {
|
||||
next_char(lex);
|
||||
unichar c = CUR_CHAR(lex);
|
||||
@@ -392,7 +395,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
} else if (had_physical_newline && lex->nested_bracket_level == 0) {
|
||||
tok->kind = MP_TOKEN_NEWLINE;
|
||||
|
||||
uint num_spaces = lex->column - 1;
|
||||
mp_uint_t num_spaces = lex->column - 1;
|
||||
lex->emit_dent = 0;
|
||||
if (num_spaces == indent_top(lex)) {
|
||||
} else if (num_spaces > indent_top(lex)) {
|
||||
@@ -461,7 +464,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
next_char(lex);
|
||||
|
||||
// work out if it's a single or triple quoted literal
|
||||
int num_quotes;
|
||||
mp_uint_t num_quotes;
|
||||
if (is_char_and(lex, quote_char, quote_char)) {
|
||||
// triple quotes
|
||||
next_char(lex);
|
||||
@@ -473,7 +476,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
}
|
||||
|
||||
// parse the literal
|
||||
int n_closing = 0;
|
||||
mp_uint_t n_closing = 0;
|
||||
while (!is_end(lex) && (num_quotes > 1 || !is_char(lex, '\n')) && n_closing < num_quotes) {
|
||||
if (is_char(lex, quote_char)) {
|
||||
n_closing += 1;
|
||||
@@ -488,8 +491,8 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
} else {
|
||||
switch (c) {
|
||||
case MP_LEXER_CHAR_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_CHAR_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case MP_LEXER_EOF: break; // TODO a proper error message?
|
||||
case '\n': c = MP_LEXER_EOF; break; // TODO check this works correctly (we are supposed to ignore it
|
||||
case '\\': break;
|
||||
case '\'': break;
|
||||
case '"': break;
|
||||
@@ -500,24 +503,37 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
case 'v': c = 0x0b; break;
|
||||
case 'f': c = 0x0c; break;
|
||||
case 'r': c = 0x0d; break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
if (is_bytes) {
|
||||
// b'\u1234' == b'\\u1234'
|
||||
vstr_add_char(&lex->vstr, '\\');
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through.
|
||||
case 'x':
|
||||
{
|
||||
uint num = 0;
|
||||
if (!get_hex(lex, 2, &num)) {
|
||||
mp_uint_t num = 0;
|
||||
if (!get_hex(lex, (c == 'x' ? 2 : c == 'u' ? 4 : 8), &num)) {
|
||||
// TODO error message
|
||||
assert(0);
|
||||
}
|
||||
c = num;
|
||||
break;
|
||||
}
|
||||
case 'N': break; // TODO \N{name} only in strings
|
||||
case 'u': break; // TODO \uxxxx only in strings
|
||||
case 'U': break; // TODO \Uxxxxxxxx only in strings
|
||||
case 'N':
|
||||
// Supporting '\N{LATIN SMALL LETTER A}' == 'a' would require keeping the
|
||||
// entire Unicode name table in the core. As of Unicode 6.3.0, that's nearly
|
||||
// 3MB of text; even gzip-compressed and with minimal structure, it'll take
|
||||
// roughly half a meg of storage. This form of Unicode escape may be added
|
||||
// later on, but it's definitely not a priority right now. -- CJA 20140607
|
||||
assert(!"Unicode name escapes not supported");
|
||||
break;
|
||||
default:
|
||||
if (c >= '0' && c <= '7') {
|
||||
// Octal sequence, 1-3 chars
|
||||
int digits = 3;
|
||||
int num = c - '0';
|
||||
mp_uint_t digits = 3;
|
||||
mp_uint_t num = c - '0';
|
||||
while (is_following_odigit(lex) && --digits != 0) {
|
||||
next_char(lex);
|
||||
num = num * 8 + (CUR_CHAR(lex) - '0');
|
||||
@@ -530,11 +546,19 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c != MP_LEXER_CHAR_EOF) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
if (c != MP_LEXER_EOF) {
|
||||
if (c < 0x110000 && !is_bytes) {
|
||||
vstr_add_char(&lex->vstr, c);
|
||||
} else if (c < 0x100 && is_bytes) {
|
||||
vstr_add_byte(&lex->vstr, c);
|
||||
} else {
|
||||
assert(!"TODO: Throw an error, invalid escape code probably");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
|
||||
// Add the "character" as a byte so that we remain 8-bit clean.
|
||||
// This way, strings are parsed correctly whether or not they contain utf-8 chars.
|
||||
vstr_add_byte(&lex->vstr, CUR_CHAR(lex));
|
||||
}
|
||||
}
|
||||
next_char(lex);
|
||||
@@ -606,7 +630,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
// search for encoded delimiter or operator
|
||||
|
||||
const char *t = tok_enc;
|
||||
uint tok_enc_index = 0;
|
||||
mp_uint_t tok_enc_index = 0;
|
||||
for (; *t != 0 && !is_char(lex, *t); t += 1) {
|
||||
if (*t == 'e' || *t == 'c') {
|
||||
t += 1;
|
||||
@@ -628,7 +652,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
|
||||
// get the maximum characters for a valid token
|
||||
t += 1;
|
||||
uint t_index = tok_enc_index;
|
||||
mp_uint_t t_index = tok_enc_index;
|
||||
for (;;) {
|
||||
for (; *t == 'e'; t += 1) {
|
||||
t += 1;
|
||||
@@ -687,16 +711,26 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, mp_token_t *tok, bool firs
|
||||
|
||||
// check for keywords
|
||||
if (tok->kind == MP_TOKEN_NAME) {
|
||||
for (int i = 0; tok_kw[i] != NULL; i++) {
|
||||
// We check for __debug__ here and convert it to its value. This is so
|
||||
// the parser gives a syntax error on, eg, x.__debug__. Otherwise, we
|
||||
// need to check for this special token in many places in the compiler.
|
||||
// TODO improve speed of these string comparisons
|
||||
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
|
||||
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
|
||||
if (str_strn_equal(tok_kw[i], tok->str, tok->len)) {
|
||||
tok->kind = MP_TOKEN_KW_FALSE + i;
|
||||
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
|
||||
// tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__"
|
||||
tok->kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
|
||||
} else {
|
||||
tok->kind = MP_TOKEN_KW_FALSE + i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close) {
|
||||
mp_lexer_t *lex = m_new_maybe(mp_lexer_t, 1);
|
||||
|
||||
// check for memory allocation error
|
||||
@@ -709,13 +743,13 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
|
||||
|
||||
lex->source_name = src_name;
|
||||
lex->stream_data = stream_data;
|
||||
lex->stream_next_char = stream_next_char;
|
||||
lex->stream_next_byte = stream_next_byte;
|
||||
lex->stream_close = stream_close;
|
||||
lex->line = 1;
|
||||
lex->column = 1;
|
||||
lex->emit_dent = 0;
|
||||
lex->nested_bracket_level = 0;
|
||||
lex->alloc_indent_level = MP_ALLOC_LEXER_INDENT_INIT;
|
||||
lex->alloc_indent_level = MICROPY_ALLOC_LEXER_INDENT_INIT;
|
||||
lex->num_indent_level = 1;
|
||||
lex->indent_level = m_new_maybe(uint16_t, lex->alloc_indent_level);
|
||||
vstr_init(&lex->vstr, 32);
|
||||
@@ -730,18 +764,18 @@ mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_
|
||||
lex->indent_level[0] = 0;
|
||||
|
||||
// preload characters
|
||||
lex->chr0 = stream_next_char(stream_data);
|
||||
lex->chr1 = stream_next_char(stream_data);
|
||||
lex->chr2 = stream_next_char(stream_data);
|
||||
lex->chr0 = stream_next_byte(stream_data);
|
||||
lex->chr1 = stream_next_byte(stream_data);
|
||||
lex->chr2 = stream_next_byte(stream_data);
|
||||
|
||||
// if input stream is 0, 1 or 2 characters long and doesn't end in a newline, then insert a newline at the end
|
||||
if (lex->chr0 == MP_LEXER_CHAR_EOF) {
|
||||
if (lex->chr0 == MP_LEXER_EOF) {
|
||||
lex->chr0 = '\n';
|
||||
} else if (lex->chr1 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr1 == MP_LEXER_EOF) {
|
||||
if (lex->chr0 != '\n' && lex->chr0 != '\r') {
|
||||
lex->chr1 = '\n';
|
||||
}
|
||||
} else if (lex->chr2 == MP_LEXER_CHAR_EOF) {
|
||||
} else if (lex->chr2 == MP_LEXER_EOF) {
|
||||
if (lex->chr1 != '\n' && lex->chr1 != '\r') {
|
||||
lex->chr2 = '\n';
|
||||
}
|
||||
|
||||
22
py/lexer.h
22
py/lexer.h
@@ -131,27 +131,27 @@ typedef enum _mp_token_kind_t {
|
||||
} mp_token_kind_t;
|
||||
|
||||
typedef struct _mp_token_t {
|
||||
uint src_line; // source line
|
||||
uint src_column; // source column
|
||||
mp_uint_t src_line; // source line
|
||||
mp_uint_t src_column; // source column
|
||||
|
||||
mp_token_kind_t kind; // kind of token
|
||||
const char *str; // string of token (valid only while this token is current token)
|
||||
uint len; // (byte) length of string of token
|
||||
mp_uint_t len; // (byte) length of string of token
|
||||
} mp_token_t;
|
||||
|
||||
// the next-char function must return the next character in the stream
|
||||
// it must return MP_LEXER_CHAR_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_CHAR_EOF, and in that case must return MP_LEXER_CHAR_EOF
|
||||
#define MP_LEXER_CHAR_EOF (-1)
|
||||
typedef unichar (*mp_lexer_stream_next_char_t)(void*);
|
||||
// the next-byte function must return the next byte in the stream
|
||||
// it must return MP_LEXER_EOF if end of stream
|
||||
// it can be called again after returning MP_LEXER_EOF, and in that case must return MP_LEXER_EOF
|
||||
#define MP_LEXER_EOF (-1)
|
||||
typedef mp_uint_t (*mp_lexer_stream_next_byte_t)(void*);
|
||||
typedef void (*mp_lexer_stream_close_t)(void*);
|
||||
|
||||
typedef struct _mp_lexer_t mp_lexer_t;
|
||||
|
||||
void mp_token_show(const mp_token_t *tok);
|
||||
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_char_t stream_next_char, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len);
|
||||
mp_lexer_t *mp_lexer_new(qstr src_name, void *stream_data, mp_lexer_stream_next_byte_t stream_next_byte, mp_lexer_stream_close_t stream_close);
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len);
|
||||
|
||||
void mp_lexer_free(mp_lexer_t *lex);
|
||||
qstr mp_lexer_source_name(mp_lexer_t *lex);
|
||||
@@ -176,3 +176,5 @@ typedef enum {
|
||||
|
||||
mp_import_stat_t mp_import_stat(const char *path);
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
|
||||
|
||||
extern mp_uint_t mp_optimise_value;
|
||||
|
||||
@@ -24,23 +24,23 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct _mp_lexer_str_buf_t {
|
||||
uint free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)
|
||||
const char *src_beg; // beginning of source
|
||||
const char *src_cur; // current location in source
|
||||
const char *src_end; // end (exclusive) of source
|
||||
} mp_lexer_str_buf_t;
|
||||
|
||||
STATIC unichar str_buf_next_char(mp_lexer_str_buf_t *sb) {
|
||||
STATIC mp_uint_t str_buf_next_byte(mp_lexer_str_buf_t *sb) {
|
||||
if (sb->src_cur < sb->src_end) {
|
||||
return *sb->src_cur++;
|
||||
} else {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ STATIC void str_buf_free(mp_lexer_str_buf_t *sb) {
|
||||
m_del_obj(mp_lexer_str_buf_t, sb);
|
||||
}
|
||||
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, uint len, uint free_len) {
|
||||
mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) {
|
||||
mp_lexer_str_buf_t *sb = m_new_obj(mp_lexer_str_buf_t);
|
||||
sb->free_len = free_len;
|
||||
sb->src_beg = str;
|
||||
sb->src_cur = str;
|
||||
sb->src_end = str + len;
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_char_t)str_buf_next_char, (mp_lexer_stream_close_t)str_buf_free);
|
||||
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str_buf_next_byte, (mp_lexer_stream_close_t)str_buf_free);
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if MICROPY_ENABLE_LEXER_UNIX
|
||||
#if MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -41,20 +41,20 @@
|
||||
|
||||
typedef struct _mp_lexer_file_buf_t {
|
||||
int fd;
|
||||
char buf[20];
|
||||
uint len;
|
||||
uint pos;
|
||||
byte buf[20];
|
||||
mp_uint_t len;
|
||||
mp_uint_t pos;
|
||||
} mp_lexer_file_buf_t;
|
||||
|
||||
STATIC unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
|
||||
STATIC mp_uint_t file_buf_next_byte(mp_lexer_file_buf_t *fb) {
|
||||
if (fb->pos >= fb->len) {
|
||||
if (fb->len == 0) {
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
} else {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
if (n <= 0) {
|
||||
fb->len = 0;
|
||||
return MP_LEXER_CHAR_EOF;
|
||||
return MP_LEXER_EOF;
|
||||
}
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
@@ -78,7 +78,7 @@ mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
int n = read(fb->fd, fb->buf, sizeof(fb->buf));
|
||||
fb->len = n;
|
||||
fb->pos = 0;
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
|
||||
return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_byte_t)file_buf_next_byte, (mp_lexer_stream_close_t)file_buf_close);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_LEXER_UNIX
|
||||
#endif // MICROPY_HELPER_LEXER_UNIX
|
||||
|
||||
@@ -27,7 +27,8 @@ def compute_hash(qstr):
|
||||
hash = 5381
|
||||
for char in qstr:
|
||||
hash = (hash * 33) ^ ord(char)
|
||||
return hash & 0xffff
|
||||
# Make sure that valid hash is never zero, zero means "hash not computed"
|
||||
return (hash & 0xffff) or 1
|
||||
|
||||
def do_work(infiles):
|
||||
# read the qstrs in from the input files
|
||||
@@ -57,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
|
||||
|
||||
|
||||
44
py/malloc.c
44
py/malloc.c
@@ -28,8 +28,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
@@ -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
|
||||
|
||||
41
py/map.c
41
py/map.c
@@ -24,21 +24,22 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime0.h"
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -167,9 +168,9 @@ mp_map_elem_t* mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
|
||||
}
|
||||
}
|
||||
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % map->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
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);
|
||||
}
|
||||
@@ -270,9 +271,9 @@ mp_obj_t mp_set_lookup(mp_set_t *set, mp_obj_t index, mp_map_lookup_kind_t looku
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
machine_uint_t hash = mp_obj_hash(index);
|
||||
uint pos = hash % set->alloc;
|
||||
uint start_pos = pos;
|
||||
mp_uint_t hash = mp_obj_hash(index);
|
||||
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 {
|
||||
|
||||
92
py/misc.h
92
py/misc.h
@@ -66,44 +66,54 @@ 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 ***********************************************/
|
||||
|
||||
// get the number of elements in a fixed-size array
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
// align ptr to the nearest multiple of "alignment"
|
||||
#define MP_ALIGN(ptr, alignment) (void*)(((mp_uint_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||
|
||||
/** unichar / UTF-8 *********************************************/
|
||||
|
||||
typedef int unichar; // TODO
|
||||
|
||||
unichar utf8_get_char(const char *s);
|
||||
char *utf8_next_char(const char *s);
|
||||
unichar utf8_get_char(const byte *s);
|
||||
const byte *utf8_next_char(const byte *s);
|
||||
|
||||
bool unichar_isspace(unichar c);
|
||||
bool unichar_isalpha(unichar c);
|
||||
bool unichar_isprint(unichar c);
|
||||
bool unichar_isdigit(unichar c);
|
||||
bool unichar_isxdigit(unichar c);
|
||||
bool unichar_isupper(unichar c);
|
||||
bool unichar_islower(unichar c);
|
||||
unichar unichar_tolower(unichar c);
|
||||
unichar unichar_toupper(unichar c);
|
||||
mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
|
||||
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
|
||||
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
|
||||
|
||||
/** 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;
|
||||
@@ -112,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; }
|
||||
@@ -159,6 +167,20 @@ 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 mp_uint_t count_lead_ones(byte val) {
|
||||
mp_uint_t c = 0;
|
||||
for (byte mask = 0x80; val & mask; mask >>= 1) {
|
||||
c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDED_MINILIB_H
|
||||
|
||||
@@ -73,9 +73,9 @@ all: $(PROG)
|
||||
|
||||
$(PROG): $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
$(Q)$(CC) $(COPT) -o $@ $(OBJ) $(LIB) $(LDFLAGS)
|
||||
ifndef DEBUG
|
||||
$(Q)$(STRIP) $(PROG)
|
||||
$(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
|
||||
endif
|
||||
$(Q)$(SIZE) $(PROG)
|
||||
|
||||
@@ -97,4 +97,10 @@ print-cfg:
|
||||
$(ECHO) "OBJ = $(OBJ)"
|
||||
.PHONY: print-cfg
|
||||
|
||||
print-def:
|
||||
@$(ECHO) "The following defines are built into the $(CC) compiler"
|
||||
touch __empty__.c
|
||||
@$(CC) -E -Wp,-dM __empty__.c
|
||||
@$(RM) -f __empty__.c
|
||||
|
||||
-include $(OBJ:.o=.P)
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_PY_ARRAY
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_array_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_array) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&mp_type_array },
|
||||
@@ -40,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_array_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_array_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_array_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -51,3 +53,5 @@ const mp_obj_module_t mp_module_array = {
|
||||
.name = MP_QSTR_array,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_array_globals,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,18 +26,27 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
|
||||
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
/// \module cmath - mathematical functions for complex numbers
|
||||
///
|
||||
/// The `cmath` module provides some basic mathematical funtions for
|
||||
/// working with complex numbers.
|
||||
|
||||
// These are defined in modmath.c
|
||||
/// \constant e - base of the natural logarithm
|
||||
extern const mp_obj_float_t mp_math_e_obj;
|
||||
/// \constant pi - the ratio of a circle's circumference to its diameter
|
||||
extern const mp_obj_float_t mp_math_pi_obj;
|
||||
|
||||
/// \function phase(z)
|
||||
/// Returns the phase of the number `z`, in the range (-pi, +pi].
|
||||
mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -45,6 +54,8 @@ mp_obj_t mp_cmath_phase(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_phase_obj, mp_cmath_phase);
|
||||
|
||||
/// \function polar(z)
|
||||
/// Returns, as a tuple, the polar form of `z`.
|
||||
mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -56,6 +67,8 @@ mp_obj_t mp_cmath_polar(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_polar_obj, mp_cmath_polar);
|
||||
|
||||
/// \function rect(r, phi)
|
||||
/// Returns the complex number with modulus `r` and phase `phi`.
|
||||
mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
mp_float_t r = mp_obj_get_float(r_obj);
|
||||
mp_float_t phi = mp_obj_get_float(phi_obj);
|
||||
@@ -63,6 +76,8 @@ mp_obj_t mp_cmath_rect(mp_obj_t r_obj, mp_obj_t phi_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_cmath_rect_obj, mp_cmath_rect);
|
||||
|
||||
/// \function exp(z)
|
||||
/// Return the exponential of `z`.
|
||||
mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -71,6 +86,8 @@ mp_obj_t mp_cmath_exp(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
|
||||
|
||||
/// \function log(z)
|
||||
/// Return the natural logarithm of `z`. The branch cut is along the negative real axis.
|
||||
// TODO can take second argument, being the base
|
||||
mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
@@ -79,6 +96,8 @@ mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
|
||||
|
||||
/// \function log10(z)
|
||||
/// Return the base-10 logarithm of `z`. The branch cut is along the negative real axis.
|
||||
mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -86,6 +105,8 @@ mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
|
||||
|
||||
/// \function sqrt(z)
|
||||
/// Return the square-root of `z`.
|
||||
mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -95,6 +116,8 @@ mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
|
||||
|
||||
/// \function cos(z)
|
||||
/// Return the cosine of `z`.
|
||||
mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -102,6 +125,8 @@ mp_obj_t mp_cmath_cos(mp_obj_t z_obj) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_cos_obj, mp_cmath_cos);
|
||||
|
||||
/// \function sin(z)
|
||||
/// Return the sine of `z`.
|
||||
mp_obj_t mp_cmath_sin(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
@@ -142,8 +167,8 @@ STATIC const mp_obj_dict_t mp_module_cmath_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_cmath_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_cmath_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -154,4 +179,4 @@ const mp_obj_module_t mp_module_cmath = {
|
||||
.globals = (mp_obj_dict_t*)&mp_module_cmath_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_FLOAT && MICROPY_ENABLE_MOD_CMATH
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#if MICROPY_PY_COLLECTIONS
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_collections_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__collections) },
|
||||
@@ -42,8 +42,8 @@ STATIC const mp_obj_dict_t mp_module_collections_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_collections_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_collections_globals_table,
|
||||
},
|
||||
};
|
||||
@@ -54,4 +54,4 @@ const mp_obj_module_t mp_module_collections = {
|
||||
.globals = (mp_obj_dict_t*)&mp_module_collections_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_MOD_COLLECTIONS
|
||||
#endif // MICROPY_PY_COLLECTIONS
|
||||
|
||||
42
py/modgc.c
42
py/modgc.c
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "misc.h"
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "builtin.h"
|
||||
@@ -35,31 +35,65 @@
|
||||
#include "objstr.h"
|
||||
#include "gc.h"
|
||||
|
||||
#if MICROPY_ENABLE_MOD_GC && MICROPY_ENABLE_GC
|
||||
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
|
||||
|
||||
/// \module gc - control the garbage collector
|
||||
|
||||
extern uint gc_collected;
|
||||
|
||||
/// \function collect()
|
||||
/// Run a garbage collection.
|
||||
STATIC mp_obj_t py_gc_collect(void) {
|
||||
gc_collect();
|
||||
#if MICROPY_PY_GC_COLLECT_RETVAL
|
||||
return MP_OBJ_NEW_SMALL_INT(gc_collected);
|
||||
#else
|
||||
return mp_const_none;
|
||||
#endif
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
|
||||
|
||||
/// \function disable()
|
||||
/// Disable the garbage collector.
|
||||
STATIC mp_obj_t gc_disable(void) {
|
||||
gc_lock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
|
||||
|
||||
/// \function enable()
|
||||
/// Enable the garbage collector.
|
||||
STATIC mp_obj_t gc_enable(void) {
|
||||
gc_unlock();
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
|
||||
|
||||
/// \function mem_free()
|
||||
/// Return the number of bytes of available heap RAM.
|
||||
STATIC mp_obj_t gc_mem_free(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.free);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_free_obj, gc_mem_free);
|
||||
|
||||
/// \function mem_alloc()
|
||||
/// Return the number of bytes of heap RAM that are allocated.
|
||||
STATIC mp_obj_t gc_mem_alloc(void) {
|
||||
gc_info_t info;
|
||||
gc_info(&info);
|
||||
return MP_OBJ_NEW_SMALL_INT(info.used);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(gc_mem_alloc_obj, gc_mem_alloc);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_gc_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gc) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_collect), (mp_obj_t)&gc_collect_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&gc_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&gc_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_free), (mp_obj_t)&gc_mem_free_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_alloc), (mp_obj_t)&gc_mem_alloc_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
@@ -67,8 +101,8 @@ STATIC const mp_obj_dict_t mp_module_gc_globals = {
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.used = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_gc_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_gc_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user