freedos-micro-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. freedos_micro_python/__init__.py +8 -0
  2. freedos_micro_python/cli.py +106 -0
  3. freedos_micro_python/gen_qstrdefs.py +275 -0
  4. freedos_micro_python/port/arch/bpstruct.h +2 -0
  5. freedos_micro_python/port/arch/cc.h +4 -0
  6. freedos_micro_python/port/arch/epstruct.h +1 -0
  7. freedos_micro_python/port/base64_uc386dos.c +164 -0
  8. freedos_micro_python/port/file_uc386dos.c +228 -0
  9. freedos_micro_python/port/lib/axtls/crypto/crypto.h +45 -0
  10. freedos_micro_python/port/lwip-arch-cc.h +46 -0
  11. freedos_micro_python/port/lwip_uc386dos.c +248 -0
  12. freedos_micro_python/port/lwipopts.h +117 -0
  13. freedos_micro_python/port/math_gamma.c +63 -0
  14. freedos_micro_python/port/modtime_uc386dos.c +60 -0
  15. freedos_micro_python/port/modtls_axtls_uc386dos.c +461 -0
  16. freedos_micro_python/port/mpconfigport.h +358 -0
  17. freedos_micro_python/port/mphal_uc386dos.c +103 -0
  18. freedos_micro_python/port/mphalport.h +11 -0
  19. freedos_micro_python/port/os_uc386dos.c +264 -0
  20. freedos_micro_python/port/path_uc386dos.c +307 -0
  21. freedos_micro_python/port/pktdrv_uc386dos.c +650 -0
  22. freedos_micro_python/port/qstrdefsport.h +2 -0
  23. freedos_micro_python/port/shutil_uc386dos.c +111 -0
  24. freedos_micro_python/port/tempfile_uc386dos.c +129 -0
  25. freedos_micro_python/port/time_real_uc386dos.c +77 -0
  26. freedos_micro_python/port/uc386_net_uc386dos.c +126 -0
  27. freedos_micro_python/port/urllib_parse_uc386dos.c +360 -0
  28. freedos_micro_python/port/urllib_uc386dos.c +29 -0
  29. freedos_micro_python/scripts/build.sh +641 -0
  30. freedos_micro_python/scripts/build_port.sh +241 -0
  31. freedos_micro_python/scripts/fetch.sh +238 -0
  32. freedos_micro_python-0.1.0.dist-info/METADATA +131 -0
  33. freedos_micro_python-0.1.0.dist-info/RECORD +37 -0
  34. freedos_micro_python-0.1.0.dist-info/WHEEL +5 -0
  35. freedos_micro_python-0.1.0.dist-info/entry_points.txt +2 -0
  36. freedos_micro_python-0.1.0.dist-info/licenses/LICENSE +25 -0
  37. freedos_micro_python-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,241 @@
1
+ #!/bin/sh
2
+ # Multi-TU build of MicroPython through uc386 — produces a runnable
3
+ # `build/micropython.bin` that boots to the REPL banner under
4
+ # `uc386.dos_emu.run`.
5
+ #
6
+ # Sources:
7
+ # - upstream/py/*.c (132)
8
+ # - upstream/shared/libc/printf.c
9
+ # /string0.c
10
+ # /__errno.c
11
+ # /abort_.c
12
+ # - upstream/shared/readline/readline.c
13
+ # - upstream/shared/runtime/pyexec.c
14
+ # /stdout_helpers.c
15
+ # /interrupt_char.c
16
+ # /sys_stdio_mphal.c
17
+ # - upstream/ports/minimal/main.c (REPL driver)
18
+ # - upstream/ports/minimal/uart_core.c (mp_hal_stdin/stdout)
19
+ #
20
+ # Includes:
21
+ # - lib/include (uc386 libc)
22
+ # - upstream (py/, shared/)
23
+ # - uc386-dos (mpconfigport.h, mphalport.h)
24
+ # - build (genhdr/qstrdefs.generated.h,
25
+ # moduledefs.h, mpversion.h,
26
+ # root_pointers.h — emitted
27
+ # by ./build.sh during the
28
+ # per-file triage pass)
29
+ #
30
+ # Defines:
31
+ # -D__linux__=1 triggers the minimal port's
32
+ # MICROPY_MIN_USE_STDOUT path
33
+ # (read(STDIN_FILENO)/write(...))
34
+ # — uc386 lowers those into
35
+ # INT 21h DOS syscalls.
36
+ #
37
+ # Wall-clock: ~14 minutes on the dev Mac (Apple Silicon, Python 3.12,
38
+ # uc386 in-process). Multi-TU is heavy because uc_core's preprocessor
39
+ # runs once per TU.
40
+ #
41
+ # Outputs:
42
+ # build/micropython.asm — NASM-syntax assembly (1.5 MB+)
43
+ # build/micropython.bin — flat 32-bit DOS bin (170 KB)
44
+ #
45
+ # Run:
46
+ # .venv/bin/python -c "from pathlib import Path; \
47
+ # from uc386.dos_emu import run; \
48
+ # r = run(Path('addons/gnu/micropython/build/micropython.bin'), \
49
+ # timeout_seconds=10.0); \
50
+ # print(r.stdout)"
51
+ #
52
+ # The REPL banner ("MicroPython uc386-triage on ...; uc386-dos with i386")
53
+ # should appear, followed by `>>> ` and the boot waits on stdin.
54
+ set -eu
55
+
56
+
57
+ if [ ! -d upstream ]; then
58
+ echo "micropython: run ./fetch.sh first." >&2
59
+ exit 1
60
+ fi
61
+
62
+ # build.sh emits the genhdr/* stubs (qstrdefs.generated.h,
63
+ # moduledefs.h, mpversion.h, root_pointers.h) that py/*.c expects.
64
+ # Run it first if those aren't here yet.
65
+ if [ ! -f build/genhdr/qstrdefs.generated.h ]; then
66
+ echo "micropython: stub headers missing; running ./build.sh first." >&2
67
+ ./build.sh > /dev/null
68
+ fi
69
+
70
+ # Two ways this script gets its uc386 paths:
71
+ # 1. Invoked via `freedos-micropython port` — the Python CLI exports
72
+ # UC386_LIB_INCLUDE (and FREEDOS_MP_PORT_DIR) from the installed
73
+ # uc386 / freedos_micro_python packages, and pre-symlinks the
74
+ # port files into cwd as ./uc386-dos.
75
+ # 2. Invoked standalone from a uc386 source checkout — falls back
76
+ # to walking up to the uc386 repo root.
77
+ if [ -z "${UC386_LIB_INCLUDE:-}" ]; then
78
+ REPO="$(cd ../../.. && pwd)"
79
+ UC386_LIB_INCLUDE="$REPO/src/uc386/lib/include"
80
+ fi
81
+ if [ -n "${PYTHON:-}" ]; then
82
+ :
83
+ elif [ -n "${REPO:-}" ] && [ -x "$REPO/.venv/bin/python" ]; then
84
+ PYTHON="$REPO/.venv/bin/python"
85
+ else
86
+ PYTHON="$(command -v python3.12 || command -v python3 || command -v python)"
87
+ fi
88
+ INCLUDE="$UC386_LIB_INCLUDE"
89
+
90
+ SOURCES_FILE="build/_port_sources.txt"
91
+ {
92
+ find upstream/py -name '*.c' | sort
93
+ echo upstream/shared/libc/__errno.c
94
+ echo upstream/shared/libc/abort_.c
95
+ echo upstream/shared/libc/printf.c
96
+ echo upstream/shared/libc/string0.c
97
+ echo upstream/shared/readline/readline.c
98
+ echo upstream/shared/runtime/pyexec.c
99
+ echo upstream/shared/runtime/stdout_helpers.c
100
+ echo upstream/shared/runtime/interrupt_char.c
101
+ echo upstream/shared/runtime/sys_stdio_mphal.c
102
+ echo upstream/shared/timeutils/timeutils.c
103
+ echo upstream/extmod/modtime.c
104
+ echo upstream/extmod/moductypes.c
105
+ echo upstream/extmod/modrandom.c
106
+ echo upstream/extmod/modbinascii.c
107
+ echo upstream/extmod/modhashlib.c
108
+ echo upstream/extmod/modre.c
109
+ echo upstream/extmod/modheapq.c
110
+ # moddeflate.c inline-#includes all the uzlib sources
111
+ # (tinflate.c, header.c, adler32.c, crc32.c, lz77.c → defl_static.c)
112
+ # so don't add them to the source list — that would duplicate
113
+ # symbols.
114
+ echo upstream/extmod/moddeflate.c
115
+ echo upstream/extmod/modjson.c
116
+ echo upstream/extmod/modplatform.c
117
+ echo upstream/extmod/modselect.c
118
+ # MD5 + SHA1 are now from upstream/lib/axtls/crypto/ (added below
119
+ # in the axtls section). B-Con's MD5 + SHA1 sources are still
120
+ # fetched by fetch.sh's `fetch_b_con_crypto` hook so the legacy
121
+ # shim at uc386-dos/lib/axtls/crypto/crypto.h still resolves
122
+ # cleanly if you flip MICROPY_PY_SSL=0 + drop axtls from this
123
+ # list, but they aren't compiled in the SSL build to avoid
124
+ # carrying two MD5 implementations.
125
+ # lwIP — IPv4-only TCP/UDP/DNS stack with loopback for testing.
126
+ # Phase 1: just core + ipv4 + netif/ethernet. DHCP / IPv6 / SLIP /
127
+ # PPP are off in lwipopts.h so their sources don't pull in.
128
+ # axtls — real TLS via upstream/lib/axtls/. The MP glue is our
129
+ # vendored fork at uc386-dos/modtls_axtls_uc386dos.c (which adds
130
+ # real verify_mode + load_verify_locations on top of upstream's
131
+ # minimal version). axtls library sources mirror upstream/extmod/
132
+ # extmod.mk's AXTLS_DIR list.
133
+ echo uc386-dos/modtls_axtls_uc386dos.c
134
+ echo upstream/lib/axtls/ssl/asn1.c
135
+ echo upstream/lib/axtls/ssl/loader.c
136
+ echo upstream/lib/axtls/ssl/tls1.c
137
+ echo upstream/lib/axtls/ssl/tls1_svr.c
138
+ echo upstream/lib/axtls/ssl/tls1_clnt.c
139
+ echo upstream/lib/axtls/ssl/x509.c
140
+ echo upstream/lib/axtls/crypto/aes.c
141
+ echo upstream/lib/axtls/crypto/bigint.c
142
+ echo upstream/lib/axtls/crypto/crypto_misc.c
143
+ echo upstream/lib/axtls/crypto/hmac.c
144
+ echo upstream/lib/axtls/crypto/md5.c
145
+ echo upstream/lib/axtls/crypto/sha1.c
146
+ # SHA384/SHA512 — needed for cert chain verification when the CA
147
+ # signs with those algorithms (RSA-SHA384 / RSA-SHA512 are common
148
+ # on modern X.509 chains). Upstream MP's extmod.mk doesn't pull
149
+ # these because their config has CONFIG_SSL_CERT_VERIFICATION
150
+ # off; we have it on (uc386-dos has the room) so we need them.
151
+ echo upstream/lib/axtls/crypto/sha384.c
152
+ echo upstream/lib/axtls/crypto/sha512.c
153
+ echo upstream/lib/axtls/crypto/rsa.c
154
+ echo upstream/extmod/modlwip.c
155
+ echo upstream/lib/lwip/src/core/init.c
156
+ echo upstream/lib/lwip/src/core/def.c
157
+ echo upstream/lib/lwip/src/core/dns.c
158
+ echo upstream/lib/lwip/src/core/inet_chksum.c
159
+ echo upstream/lib/lwip/src/core/ip.c
160
+ echo upstream/lib/lwip/src/core/mem.c
161
+ echo upstream/lib/lwip/src/core/memp.c
162
+ echo upstream/lib/lwip/src/core/netif.c
163
+ echo upstream/lib/lwip/src/core/pbuf.c
164
+ echo upstream/lib/lwip/src/core/raw.c
165
+ echo upstream/lib/lwip/src/core/stats.c
166
+ echo upstream/lib/lwip/src/core/sys.c
167
+ echo upstream/lib/lwip/src/core/tcp.c
168
+ echo upstream/lib/lwip/src/core/tcp_in.c
169
+ echo upstream/lib/lwip/src/core/tcp_out.c
170
+ echo upstream/lib/lwip/src/core/timeouts.c
171
+ echo upstream/lib/lwip/src/core/udp.c
172
+ echo upstream/lib/lwip/src/core/ipv4/dhcp.c
173
+ echo upstream/lib/lwip/src/core/ipv4/etharp.c
174
+ echo upstream/lib/lwip/src/core/ipv4/icmp.c
175
+ echo upstream/lib/lwip/src/core/ipv4/igmp.c
176
+ echo upstream/lib/lwip/src/core/ipv4/ip4.c
177
+ echo upstream/lib/lwip/src/core/ipv4/ip4_addr.c
178
+ echo upstream/lib/lwip/src/core/ipv4/ip4_frag.c
179
+ echo upstream/lib/lwip/src/netif/ethernet.c
180
+ echo uc386-dos/lwip_uc386dos.c
181
+ echo upstream/ports/minimal/main.c
182
+ echo upstream/ports/minimal/uart_core.c
183
+ echo uc386-dos/mphal_uc386dos.c
184
+ echo uc386-dos/file_uc386dos.c
185
+ echo uc386-dos/os_uc386dos.c
186
+ echo uc386-dos/path_uc386dos.c
187
+ echo uc386-dos/base64_uc386dos.c
188
+ echo uc386-dos/shutil_uc386dos.c
189
+ echo uc386-dos/tempfile_uc386dos.c
190
+ echo uc386-dos/urllib_parse_uc386dos.c
191
+ echo uc386-dos/urllib_uc386dos.c
192
+ echo uc386-dos/uc386_net_uc386dos.c
193
+ echo uc386-dos/pktdrv_uc386dos.c
194
+ echo uc386-dos/math_gamma.c
195
+ # Real time(), mktime(), gettimeofday() backed by the DOS RTC —
196
+ # replaces the libc.asm stubs (now removed). Required by axtls
197
+ # cert verification (notBefore/notAfter window check).
198
+ echo uc386-dos/time_real_uc386dos.c
199
+ } > "$SOURCES_FILE"
200
+
201
+ n_sources="$(wc -l < "$SOURCES_FILE")"
202
+ echo "micropython: compiling $n_sources sources via uc386 (multi-TU; ~14 min) …"
203
+
204
+ # tr+xargs delivery so the source list survives without arg-list overflow.
205
+ # `set -e` would abort on uc386 failure; we want to surface it explicitly.
206
+ set +e
207
+ tr '\n' '\0' < "$SOURCES_FILE" \
208
+ | xargs -0 "$PYTHON" -m uc386.main \
209
+ -I "$INCLUDE" \
210
+ -I upstream \
211
+ -I upstream/lib/lwip/src/include \
212
+ -I upstream/extmod/lwip-include \
213
+ -I upstream/lib/axtls/ssl \
214
+ -I upstream/lib/axtls/crypto \
215
+ -I upstream/extmod/axtls-include \
216
+ -I uc386-dos \
217
+ -I build \
218
+ -D__linux__=1 \
219
+ -DNDEBUG=1 \
220
+ -DMICROPY_SSL_AXTLS=1 \
221
+ -DMICROPY_PY_SSL=1 \
222
+ -Dmp_stream_errno=errno \
223
+ -o build/micropython.asm
224
+ rc=$?
225
+ set -e
226
+ if [ $rc -ne 0 ]; then
227
+ echo "micropython: uc386 returned $rc; not assembling." >&2
228
+ exit $rc
229
+ fi
230
+
231
+ asm_size="$(wc -c < build/micropython.asm | tr -d ' ')"
232
+ echo "micropython: wrote build/micropython.asm ($asm_size bytes)"
233
+ echo "micropython: assembling via nasm …"
234
+ # `-w-error=label-redef-late`: same convergence warning we suppress for
235
+ # DOOM. Long programs hit short/long jump promotion edge cases NASM 3.x
236
+ # now warns about; the binary's correct after convergence.
237
+ nasm -f bin -w-error=label-redef-late \
238
+ build/micropython.asm -o build/micropython.bin
239
+ bin_size="$(wc -c < build/micropython.bin | tr -d ' ')"
240
+ echo "micropython: built build/micropython.bin ($bin_size bytes)"
241
+ ls -l build/micropython.bin
@@ -0,0 +1,238 @@
1
+ #!/bin/sh
2
+ # Fetch MicroPython upstream into upstream/.
3
+ # Idempotent: a second run is a no-op once upstream/ exists.
4
+ set -eu
5
+
6
+ # B-Con public-domain crypto reference impls used by hashlib's
7
+ # md5/sha1 (sha256 is already in upstream's tarball). Pull these
8
+ # even when upstream/ already exists, so an older fetch that
9
+ # pre-dates the crypto-algorithms additions self-heals on next run.
10
+ fetch_b_con_crypto() {
11
+ CA_BASE="https://raw.githubusercontent.com/B-Con/crypto-algorithms/master"
12
+ mkdir -p upstream/lib/crypto-algorithms
13
+ for f in md5.c md5.h sha1.c sha1.h; do
14
+ if [ ! -f "upstream/lib/crypto-algorithms/$f" ]; then
15
+ echo "micropython: fetching crypto-algorithms/$f …"
16
+ curl -fsSL "$CA_BASE/$f" -o "upstream/lib/crypto-algorithms/$f"
17
+ fi
18
+ done
19
+ }
20
+
21
+ # axtls — TLS library, submodule in upstream/.gitmodules pointing at
22
+ # micropython/axtls (a fork of axtls-2.1.x maintained for MP). Pinned
23
+ # to the SHA the upstream MP tarball references (gitlinks aren't pulled
24
+ # by the tarball, so we fetch a tree archive directly). The MP-extmod
25
+ # glue at upstream/extmod/modtls_axtls.c expects this tree at
26
+ # upstream/lib/axtls/.
27
+ fetch_axtls() {
28
+ AXTLS_SHA="531cab9c278c947d268bd4c94ecab9153a961b43"
29
+ AXTLS_DIR="upstream/lib/axtls"
30
+ if [ -d "$AXTLS_DIR/ssl" ]; then
31
+ return 0
32
+ fi
33
+ echo "micropython: fetching axtls $AXTLS_SHA …"
34
+ AXTLS_TMP="$(mktemp -d)"
35
+ trap 'rm -rf "$AXTLS_TMP"' RETURN 2>/dev/null || true
36
+ curl -fsSL \
37
+ "https://github.com/micropython/axtls/archive/${AXTLS_SHA}.tar.gz" \
38
+ -o "$AXTLS_TMP/axtls.tgz"
39
+ tar -xzf "$AXTLS_TMP/axtls.tgz" -C "$AXTLS_TMP"
40
+ mkdir -p "$AXTLS_DIR"
41
+ cp -r "$AXTLS_TMP"/axtls-*/ssl "$AXTLS_DIR/"
42
+ cp -r "$AXTLS_TMP"/axtls-*/crypto "$AXTLS_DIR/"
43
+ rm -rf "$AXTLS_TMP"
44
+ }
45
+
46
+ # lwIP — submodule in upstream/.gitmodules but not pulled by the
47
+ # tarball. Fetch a pinned release tarball into upstream/lib/lwip/
48
+ # alongside the existing crypto-algorithms stash. STABLE-2_2_1 is
49
+ # the latest tagged release as of mid-2026 and is what our port
50
+ # integration targets.
51
+ fetch_lwip() {
52
+ LWIP_TAG="STABLE-2_2_1_RELEASE"
53
+ LWIP_DIR="upstream/lib/lwip"
54
+ if [ -d "$LWIP_DIR/src/core" ]; then
55
+ return 0
56
+ fi
57
+ echo "micropython: fetching lwIP $LWIP_TAG …"
58
+ LWIP_TMP="$(mktemp -d)"
59
+ trap 'rm -rf "$LWIP_TMP"' RETURN 2>/dev/null || true
60
+ curl -fsSL \
61
+ "https://github.com/lwip-tcpip/lwip/archive/refs/tags/${LWIP_TAG}.tar.gz" \
62
+ -o "$LWIP_TMP/lwip.tgz"
63
+ tar -xzf "$LWIP_TMP/lwip.tgz" -C "$LWIP_TMP"
64
+ mkdir -p "$LWIP_DIR"
65
+ cp -r "$LWIP_TMP"/lwip-*/src "$LWIP_DIR/"
66
+ rm -rf "$LWIP_TMP"
67
+ }
68
+
69
+ # Patch upstream's `mod_lwip_reset` to register our loopback packet
70
+ # pump as the poll callback (instead of nulling it). LWIP_NETIF_LOOPBACK=1
71
+ # with NO_SYS=1 needs manual netif_poll(netif_default) per tick to
72
+ # deliver packets; uc386dos_loopback_poll (in uc386-dos/lwip_uc386dos.c)
73
+ # does that. Idempotent: skips when the patched line is already present.
74
+ patch_modlwip_loopback_poll() {
75
+ F="upstream/extmod/modlwip.c"
76
+ if [ ! -f "$F" ]; then return 0; fi
77
+ if grep -q "uc386dos_loopback_poll" "$F"; then return 0; fi
78
+ if ! grep -q "lwip_poll_list.poll = NULL;" "$F"; then
79
+ echo "micropython: warn: modlwip.c reset shape changed — skipping loopback patch." >&2
80
+ return 0
81
+ fi
82
+ echo "micropython: patching modlwip.c mod_lwip_reset for loopback poll …"
83
+ awk '
84
+ /static mp_obj_t mod_lwip_reset/ { in_reset = 1 }
85
+ in_reset && /lwip_poll_list\.poll = NULL;/ {
86
+ print " extern void uc386dos_loopback_poll(void *arg);"
87
+ print " lwip_poll_list.poll = uc386dos_loopback_poll;"
88
+ print " lwip_poll_list.poll_arg = NULL;"
89
+ in_reset = 0
90
+ next
91
+ }
92
+ in_reset && /^}/ { in_reset = 0 }
93
+ { print }
94
+ ' "$F" > "$F.tmp" && mv "$F.tmp" "$F"
95
+ }
96
+
97
+ # Inject write(1, ...) checkpoints into ports/minimal/main.c so the
98
+ # rig can see how far MP startup gets. write() goes through libc's
99
+ # INT 21h AH=0x40 BX=1 — which respects DOS file-handle redirection
100
+ # (the > MP_OUT.TXT in autoexec.bat). printf() uses INT 21h AH=02h
101
+ # which writes to the console regardless of redirect, so under
102
+ # `dosbox-x -silent` it lands in /dev/null. The MP REPL itself uses
103
+ # mp_hal_stdout_tx_strn -> write(STDOUT_FILENO, ...), so these
104
+ # markers exercise the same redirect path as the MP banner. The
105
+ # last-seen marker in RIG.LOG identifies the statement that
106
+ # silently aborts. Idempotent: skip if the markers are already in
107
+ # place.
108
+ patch_main_startup_markers() {
109
+ F="upstream/ports/minimal/main.c"
110
+ if [ ! -f "$F" ]; then return 0; fi
111
+ if grep -q "mp-startup-marker" "$F"; then
112
+ # Old printf-based markers from a prior fetch.sh? Strip them
113
+ # so the new write()-based markers are what gets compiled.
114
+ if grep -q "printf(\"\[mp-" "$F"; then
115
+ echo "micropython: stripping stale printf startup markers from ports/minimal/main.c …"
116
+ grep -v "mp-startup-marker\|printf(\"\[mp-\|fflush(stdout)" "$F" > "$F.tmp" && mv "$F.tmp" "$F"
117
+ else
118
+ return 0
119
+ fi
120
+ fi
121
+ echo "micropython: patching ports/minimal/main.c with write() startup markers …"
122
+ awk '
123
+ /^#include "shared\/runtime\/pyexec.h"/ {
124
+ print
125
+ print "#include <unistd.h> /* mp-startup-marker: write() */"
126
+ next
127
+ }
128
+ /^int main\(int argc, char \*\*argv\) \{/ {
129
+ print
130
+ print " /* mp-startup-marker injected by addons/gnu/micropython/fetch.sh */"
131
+ print " write(1, \"[mp-main-entered]\\n\", 18);"
132
+ in_main = 1
133
+ next
134
+ }
135
+ in_main && /mp_stack_ctrl_init\(\);/ {
136
+ print " write(1, \"[mp-before-stack-ctrl]\\n\", 23);"
137
+ print
138
+ next
139
+ }
140
+ in_main && /mp_init\(\);/ {
141
+ print " write(1, \"[mp-before-mp-init]\\n\", 20);"
142
+ print
143
+ print " write(1, \"[mp-after-mp-init]\\n\", 19);"
144
+ next
145
+ }
146
+ in_main && /pyexec_friendly_repl\(\);/ {
147
+ print " write(1, \"[mp-before-repl]\\n\", 17);"
148
+ print
149
+ print " write(1, \"[mp-after-repl]\\n\", 16);"
150
+ next
151
+ }
152
+ in_main && /mp_deinit\(\);/ {
153
+ print " write(1, \"[mp-before-deinit]\\n\", 19);"
154
+ print
155
+ in_main = 0
156
+ next
157
+ }
158
+ { print }
159
+ ' "$F" > "$F.tmp" && mv "$F.tmp" "$F"
160
+ }
161
+
162
+ # Patch upstream/extmod/axtls-include/config.h to flip CONFIG_SSL_HAS_PEM
163
+ # and CONFIG_SSL_CERT_VERIFICATION from undef to defined. Upstream MP
164
+ # ports compile axtls in skeleton mode without verification because
165
+ # CA bundles don't fit on most embedded targets; uc386-dos has the
166
+ # room and wants real authentication. The flips engage axtls's
167
+ # x509_dn_compare / signature checking / notBefore-notAfter window
168
+ # checks and make `ssl.SSLContext.load_verify_locations` meaningful.
169
+ # Idempotent: leaves the flips in place once applied.
170
+ patch_axtls_config_verify() {
171
+ F="upstream/extmod/axtls-include/config.h"
172
+ if [ ! -f "$F" ]; then return 0; fi
173
+ if grep -q "^#define CONFIG_SSL_CERT_VERIFICATION 1$" "$F"; then
174
+ return 0
175
+ fi
176
+ echo "micropython: enabling axtls cert verification + PEM in $F …"
177
+ sed -i.bak \
178
+ -e 's|^#undef CONFIG_SSL_HAS_PEM$|#define CONFIG_SSL_HAS_PEM 1|' \
179
+ -e 's|^#undef CONFIG_SSL_CERT_VERIFICATION$|#define CONFIG_SSL_CERT_VERIFICATION 1|' \
180
+ "$F"
181
+ rm -f "$F.bak"
182
+ }
183
+
184
+ # Add `#include <endian.h>` at the top of upstream/extmod/axtls-include/
185
+ # axtls_os_port.h. axtls's sha512.c uses be64toh() but doesn't include
186
+ # the header itself — on Linux glibc's <sys/time.h> transitively pulls
187
+ # in endian.h, on uc386's libc it doesn't. Adding the include via
188
+ # axtls_os_port.h (which every axtls TU pulls through os_port.h) is
189
+ # the minimal-blast-radius fix. Idempotent.
190
+ patch_axtls_endian_include() {
191
+ F="upstream/extmod/axtls-include/axtls_os_port.h"
192
+ if [ ! -f "$F" ]; then return 0; fi
193
+ if grep -q "<endian.h>" "$F"; then
194
+ return 0
195
+ fi
196
+ echo "micropython: adding endian.h include to $F …"
197
+ sed -i.bak \
198
+ 's|^#include <errno.h>$|#include <errno.h>\
199
+ #include <endian.h>|' \
200
+ "$F"
201
+ rm -f "$F.bak"
202
+ }
203
+
204
+ if [ -d upstream ]; then
205
+ echo "micropython: upstream/ already present — skipping main fetch."
206
+ fetch_b_con_crypto
207
+ fetch_lwip
208
+ fetch_axtls
209
+ patch_modlwip_loopback_poll
210
+ patch_main_startup_markers
211
+ patch_axtls_config_verify
212
+ patch_axtls_endian_include
213
+ exit 0
214
+ fi
215
+
216
+ # Pinned to a specific upstream commit so the source we ship in the
217
+ # tarball alongside the binary always matches what was built. The
218
+ # port currently targets v1.26-era APIs; bump with
219
+ # `git ls-remote https://github.com/micropython/micropython HEAD`
220
+ # and re-run the build cycle when promoting to a newer revision.
221
+ SHA="9f396bba8d675ffb53f7fb047def21c7a581948e" # 2025-08-01
222
+ URL="https://github.com/micropython/micropython/archive/${SHA}.tar.gz"
223
+ TMP="$(mktemp -d)"
224
+ trap 'rm -rf "$TMP"' EXIT
225
+
226
+ echo "micropython: fetching $URL …"
227
+ curl -fsSL "$URL" -o "$TMP/micropython.tar.gz"
228
+ tar -xzf "$TMP/micropython.tar.gz" -C "$TMP"
229
+ mv "$TMP"/micropython-* upstream
230
+ echo "micropython: upstream tree at $(pwd)/upstream/"
231
+
232
+ fetch_b_con_crypto
233
+ fetch_lwip
234
+ fetch_axtls
235
+ patch_modlwip_loopback_poll
236
+ patch_main_startup_markers
237
+ patch_axtls_config_verify
238
+ patch_axtls_endian_include
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: freedos_micro_python
3
+ Version: 0.1.0
4
+ Summary: MicroPython port for FreeDOS / i386 — built end-to-end through the uc386 C23 compiler
5
+ Author: freedos_micro_python contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/avwohl/freedos_micro_python
8
+ Project-URL: Repository, https://github.com/avwohl/freedos_micro_python
9
+ Project-URL: Issues, https://github.com/avwohl/freedos_micro_python/issues
10
+ Keywords: micropython,python,freedos,dos,i386,retro-computing,embedded,interpreter
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Compilers
20
+ Classifier: Topic :: System :: Emulators
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: uc386>=0.1.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # freedos_micro_python
30
+
31
+ [MicroPython](https://github.com/micropython/micropython) port for
32
+ **FreeDOS / i386**, built end-to-end through the
33
+ [uc386](https://pypi.org/project/uc386/) C23 compiler. Produces a
34
+ runnable flat-binary or PMODE/W `.exe` with a fully-functional
35
+ Python REPL — arithmetic, control flow, classes, list comprehensions,
36
+ exception handling, and ~25 named builtins all work.
37
+
38
+ ```
39
+ MicroPython uc386-triage on 2026-05-01; uc386-dos with i386
40
+ Type "help()" for more information.
41
+ >>> def fib(n):
42
+ ... if n < 2: return n
43
+ ... return fib(n-1) + fib(n-2)
44
+ ...
45
+ >>> print([fib(i) for i in range(10)])
46
+ [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
47
+ ```
48
+
49
+ ## Status
50
+
51
+ - ~444 KB binary at the EXTRA_FEATURES + axtls TLS configuration
52
+ - ~70 smoke tests pin REPL banner, builtins, comprehensions, exceptions,
53
+ module imports (`os`, `time`, `re`, `json`, `hashlib`, `ssl`, ...),
54
+ and the long-int / float code paths
55
+ - See [`NOTES.md`](NOTES.md) for the full per-slice development log
56
+
57
+ ## Install
58
+
59
+ ```
60
+ pip install freedos_micro_python
61
+ ```
62
+
63
+ This pulls in `uc386` (the compiler) automatically. You also need:
64
+
65
+ - a Unix-y shell to drive the `build_port.sh` script (macOS / Linux)
66
+ - `git` (for fetching the upstream MicroPython sources)
67
+ - `make` is **not** required
68
+
69
+ ## Quick start
70
+
71
+ ```bash
72
+ mkdir mp-build && cd mp-build
73
+ freedos-micropython fetch # clones upstream MicroPython into ./upstream
74
+ freedos-micropython build # per-TU triage build (generates qstrdefs)
75
+ freedos-micropython port # multi-TU build → ./build/micropython.bin
76
+ ```
77
+
78
+ Wall-clock for the `port` step is ~14 minutes on a recent Mac. The
79
+ output is `./build/micropython.bin`, a flat i386 DOS binary runnable
80
+ under uc386's emulator:
81
+
82
+ ```python
83
+ from uc386.dos_emu import run
84
+ res = run("build/micropython.bin", timeout_seconds=10.0,
85
+ instruction_limit=2_000_000_000)
86
+ print(res.stdout) # → "MicroPython uc386-triage on ...\n..."
87
+ ```
88
+
89
+ To produce a real DOS `.exe` (PMODE/W bound, ~12 KB stub overhead):
90
+ use uc386's `addons/harness/exe.py`.
91
+
92
+ ## Testing
93
+
94
+ After a successful `port` build:
95
+
96
+ ```bash
97
+ pytest --pyargs freedos_micro_python # parametric: tests live in tests/
98
+ # or, against a checkout:
99
+ pytest tests/
100
+ ```
101
+
102
+ The smoke tests skip cleanly if `build/micropython.bin` doesn't exist.
103
+
104
+ ## Layout
105
+
106
+ - `src/freedos_micro_python/scripts/` — the three shell scripts
107
+ (`fetch.sh`, `build.sh`, `build_port.sh`); invoked via the CLI
108
+ wrapper, which sets `UC386_LIB_INCLUDE` from the installed `uc386`
109
+ - `src/freedos_micro_python/port/` — the FreeDOS port files
110
+ (`mpconfigport.h`, `*_uc386dos.c`, lwIP + axtls glue)
111
+ - `src/freedos_micro_python/gen_qstrdefs.py` — qstr table generator
112
+ (mirrors upstream's `tools/makeqstrdata.py`)
113
+ - `src/freedos_micro_python/cli.py` — the `freedos-micropython` CLI
114
+ - `tests/` — pytest smoke tests + qstr unit tests
115
+ - `rigs/dosbox-x-rig/` — DOSBox-X regression rig (network packet driver)
116
+ - `rigs/tls-rig/` — axtls TLS regression rig
117
+
118
+ ## License
119
+
120
+ [MIT](LICENSE), matching upstream MicroPython. The integration glue
121
+ (scripts, port files, CLI, tests) is what's covered here; the
122
+ upstream MicroPython sources fetched by `build_port.sh` retain their
123
+ own MIT license.
124
+
125
+ ## Related projects
126
+
127
+ - [uc386](https://github.com/avwohl/uc386) — the C23 compiler that
128
+ builds this port. Hosts the `dos_emu` test harness.
129
+ - [uc_core](https://github.com/avwohl/uc_core) — shared C23 frontend
130
+ used by uc386 (and the Z80 sibling, uc80).
131
+ - [MicroPython](https://github.com/micropython/micropython) — upstream.
@@ -0,0 +1,37 @@
1
+ freedos_micro_python/__init__.py,sha256=--xMyQE4FSZY0nZlOgZRFOj1y75MTj6ZxMShA63RJSU,257
2
+ freedos_micro_python/cli.py,sha256=nm8J6nrTkQo-VFS39B_PEDwhxBdNyhwfEtlnmBRrdwg,3519
3
+ freedos_micro_python/gen_qstrdefs.py,sha256=jMV5-7nYazwNKpCEWsGx8WabBuZ715TL77j2PryYSYQ,11392
4
+ freedos_micro_python/port/base64_uc386dos.c,sha256=s175D2z9hkzoDtIXL8paQ7bsMNrRIyhrRcSUeO-65_0,5823
5
+ freedos_micro_python/port/file_uc386dos.c,sha256=Wb7qRuNcxpRnQ6BWhNYWO-mmC22fHtU2m1igXNhQSq8,7631
6
+ freedos_micro_python/port/lwip-arch-cc.h,sha256=cMs_iQ3OEbO4FdTRGANJpdmpOYEhZWTstlDO0pHbqzE,1655
7
+ freedos_micro_python/port/lwip_uc386dos.c,sha256=50jOUUsHycy3QfL-ebwAsW4T-gl5cEGw9i1gsBqwqJ4,9966
8
+ freedos_micro_python/port/lwipopts.h,sha256=3pIDgAlFHpzDDxC7Xk8CejrzvQMlcJKJGKdLkN7SsjQ,5422
9
+ freedos_micro_python/port/math_gamma.c,sha256=hSD3i4ZcJ5Eo1NqOZMo71WMOkU_uKTKMnmYoNEgo0DY,2042
10
+ freedos_micro_python/port/modtime_uc386dos.c,sha256=HvHYeq_bIGaK8GdX-UtJI18N-IV9RIJ7ZFPWms6H-tA,2384
11
+ freedos_micro_python/port/modtls_axtls_uc386dos.c,sha256=bYH8eF6IneFX5tqNQYzGSJWMp74YbWRcxqRUWqA76SU,17582
12
+ freedos_micro_python/port/mpconfigport.h,sha256=tF2o-Ln0S7y0d3t81EuijR4qa50mP0b047aXArmY5F4,18657
13
+ freedos_micro_python/port/mphal_uc386dos.c,sha256=1kbKEj9JKphPNgo-AheDLMzHUz7KuJ30l_aw0PPi8GA,3775
14
+ freedos_micro_python/port/mphalport.h,sha256=eg7gM8DUj7Ib_Df-BicrzXBPeF5Mho5rgeSWptLpjM0,456
15
+ freedos_micro_python/port/os_uc386dos.c,sha256=E-YWNB7LPUECLjaq7c5lYVphXQuiVRzi0jiZ0N6XVMQ,10391
16
+ freedos_micro_python/port/path_uc386dos.c,sha256=S0ruBU4_TrYB-RkXiVifTC1brd49rZq7usvdGERlEHE,11401
17
+ freedos_micro_python/port/pktdrv_uc386dos.c,sha256=WygcMSgJRnS5AvAv_SfUeQmf5_8NLANvlnxpD_Z3OAc,26564
18
+ freedos_micro_python/port/qstrdefsport.h,sha256=HihE94Cf8aRNcmOuD0-MqoRG5IDOW_KoDyp1nBkT6tU,101
19
+ freedos_micro_python/port/shutil_uc386dos.c,sha256=bqywTyER2jIZUnv1RDsTKu1m-NB0969IEmTbo8KzfPo,3897
20
+ freedos_micro_python/port/tempfile_uc386dos.c,sha256=HVcU7l9YUtolkPueMy3Sr0fg28wRVkxe4YPqbSq1WDM,4899
21
+ freedos_micro_python/port/time_real_uc386dos.c,sha256=xeuJTR5EmZ0OHYwLDJahZNl539RsNTEzqKLwXuim_XE,2778
22
+ freedos_micro_python/port/uc386_net_uc386dos.c,sha256=g6AN_kDuatlrAwAvcaamMlKSnyxhzKW3QYFuZISLYOg,5071
23
+ freedos_micro_python/port/urllib_parse_uc386dos.c,sha256=1EAM6_iZYMhHO7FjV4ZVpfNvLcyJl68GwQVOI4koJ4Y,13489
24
+ freedos_micro_python/port/urllib_uc386dos.c,sha256=T2-WclQnsKBnQsyLGicYbFj7AqhOpx1TquslUDh-gg4,1218
25
+ freedos_micro_python/port/arch/bpstruct.h,sha256=ozGLp9D4wIl6vP48isExUE5a1PP-r360ZQIQKp1DOWs,141
26
+ freedos_micro_python/port/arch/cc.h,sha256=IRm8Z6GzV1BWZYSSLisoRuUIs7VIxDOwX_mfbS-VUTA,222
27
+ freedos_micro_python/port/arch/epstruct.h,sha256=XoxKvRvdXZbWxFJRCb6ROTAQu6YN4AL_6icQnEPcNug,33
28
+ freedos_micro_python/port/lib/axtls/crypto/crypto.h,sha256=JURkZnHeNjv856FfmLIoJTTbplFKT9ilfr_zMfUnarM,1657
29
+ freedos_micro_python/scripts/build.sh,sha256=YcQHRoZ5-T5n6_lUD4-WXiZWcMRdMFHnvmoyN4QYNVU,28574
30
+ freedos_micro_python/scripts/build_port.sh,sha256=WFDF3Q9QVD2FIYr374DpN-CA2u7Kx91p65lDTBJHu9U,10211
31
+ freedos_micro_python/scripts/fetch.sh,sha256=zzyYf_9J9mBjwRV6F7iov3VINkwrZsH7hCR1kOA-CdA,9519
32
+ freedos_micro_python-0.1.0.dist-info/licenses/LICENSE,sha256=2LLG0iwPCJSbyBl2S_A-2S44bhxI9ebRYaiAGeC6Zh0,1337
33
+ freedos_micro_python-0.1.0.dist-info/METADATA,sha256=ehF8LhedRJdWSiBmlkhw9gjBQm75-_mZw_8nzdeLO4w,4725
34
+ freedos_micro_python-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
35
+ freedos_micro_python-0.1.0.dist-info/entry_points.txt,sha256=DCCG64mGnGhyCVkYRIWCl5yNwi_2XcvNc2ineYRqSIU,70
36
+ freedos_micro_python-0.1.0.dist-info/top_level.txt,sha256=NB5PoXRRCfPJfnv7pEoSIiELl4b12Ka-zaU299QqhzQ,21
37
+ freedos_micro_python-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ freedos-micropython = freedos_micro_python.cli:main