Skip to content

Commit b164c29

Browse files
committed
docs: Update amiga.md for completed Phase 5 native emitter.
Fix stale frame layout description (ascending locals, not descending), and remove the now-resolved big-endian n_state limitation note.
1 parent 65f01cb commit b164c29

1 file changed

Lines changed: 47 additions & 9 deletions

File tree

docs/amiga.md

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This document describes a plan to port MicroPython to AmigaOS 3.x running on Mot
1111
- Phase 2 ✅ File system access and `import` from AmigaDOS volumes
1212
- Phase 3 ✅ Standard MicroPython library modules
1313
- Phase 4 ✅ Amiga-specific `amiga` C module (exec/dos library bindings)
14-
- Phase 5 (stretch): 68k native code emitter
14+
- Phase 5 68k native code emitter (`--emit native` / `@micropython.native`)
1515

1616
### Non-goals (initially)
1717

@@ -349,16 +349,54 @@ amiga.MEMF_CLEAR # 0x10000
349349

350350
---
351351

352-
## Phase 5 (Stretch) — 68k Native Code Emitter
352+
## Phase 5 — 68k Native Code Emitter
353353

354-
MicroPython has native code emitters for x64, ARM/Thumb, AArch64, Xtensa, RISC-V. Adding 68k requires:
354+
`@micropython.native` and `--emit native` are now supported via the GENERIC_ASM_API.
355355

356-
1. `py/asm68k.h` / `py/asm68k.c` — 68k instruction encoder (MOVEx, ADD, SUB, LINK/UNLK, JSR, RTS, etc.)
357-
2. `py/emit68k.c` — native emitter translating MicroPython IR to 68k, following `py/emitx64.c`
358-
3. Register mapping: `d0``d7` (data), `a0``a6` (address), `a7` = SP; use `a5` or `a4` as the code-state pointer
359-
4. Add `MICROPY_EMIT_68K` config macro and wire into `py/compile.c`
356+
### Files added
360357

361-
Significant work (several thousand lines); defer until phases 1–4 are solid.
358+
| File | Role |
359+
|------|------|
360+
| `py/asm68k.h` | 68k instruction encoder: MOVE, ADD/SUB/MUL, logical, shift, CMP, Scc, LEA, Bcc/BRA, JSR/RTS, LINK/UNLK, MOVEM |
361+
| `py/asm68k.c` | Non-inline implementations: entry/exit, call_ind, branches, local access, load/store |
362+
| `py/emit68k.c` | Thin wrapper: `#define N_68K 1` + `GENERIC_ASM_API`, then `#include "py/emitnative.c"` |
363+
364+
### Design decisions
365+
366+
**Register allocation:**
367+
368+
| Role | Register | Note |
369+
|------|----------|------|
370+
| REG_RET / REG_ARG_1 | D0 | Also return value |
371+
| REG_ARG_2 | D1 | |
372+
| REG_ARG_3 | D2 | Callee-saved; loaded from 16(A5) in prologue |
373+
| REG_ARG_4 | D3 | Callee-saved; loaded from 20(A5) in prologue |
374+
| REG_TEMP0/1/2 | D4, D5, D6 | Scratch |
375+
| REG_LOCAL_1 | D7 | Only cached-local register (data reg safe for arithmetic) |
376+
| REG_LOCAL_2 | A2 | Address register; used for REG_GENERATOR_STATE |
377+
| REG_LOCAL_3 | A3 | Address register; used for REG_QSTR_TABLE |
378+
| REG_FUN_TABLE | A4 | Points to `mp_fun_table` |
379+
| Frame pointer | A5 | LINK/UNLK; locals at (local-n_locals)*4(A5) |
380+
| A0 | scratch | Used by `asm_68k_ensure_areg` when base is Dn |
381+
382+
**Calling convention:** AmigaOS/cdecl — args pushed right-to-left.
383+
- Entry prologue: `LINK A5, #-N; MOVEM.L D2-D7/A2-A4, -(SP)` then load 4 args from stack.
384+
- `ASM_CALL_IND`: push D3/D2/D1/D0; `MOVEA.L (idx*4, A4), A0; JSR (A0); ADDA.L #16, SP`.
385+
- Branches: always `.W` form (4 bytes: opcode + int16 displacement); displacement = target − (instruction + 2).
386+
- Comparisons: `CMP.L reg_rhs, REG_ARG_2; Scc REG_RET; ANDI.L #1, REG_RET`.
387+
- `MAX_REGS_FOR_LOCAL_VARS = 1`: only D7 used for register-cached locals; A2/A3 are address registers and cannot be used for general arithmetic by `emitnative.c`.
388+
389+
### Known limitations
390+
391+
- **try/except in native mode is broken.** With `MICROPY_NLR_SETJMP = 1`, the `nlr_buf_t` slot used by `NLR_BUF_IDX_LOCAL_1` falls inside the `jmp_buf`, which is overwritten by `setjmp`. Functions using exceptions are unsafe in native/viper mode. Non-exceptional native functions work correctly.
392+
- **Viper integer arithmetic on address registers** is prevented by `MAX_REGS_FOR_LOCAL_VARS = 1`. Viper `int`/`uint` locals beyond the first will always use stack slots.
393+
394+
### Configuration
395+
396+
```c
397+
// mpconfigport.h
398+
#define MICROPY_EMIT_68K (1)
399+
```
362400
363401
---
364402
@@ -393,4 +431,4 @@ Significant work (several thousand lines); defer until phases 1–4 are solid.
393431
| 2 — File I/O | ✅ Done | `open()`, `import`, context manager; newlib stdio (no NDK needed) |
394432
| 3 — Stdlib | ✅ Done | math, struct, json, re, hashlib, float; json.loads via port-local modjson.c |
395433
| 4 — `amiga` module | ✅ Done | os_version, find_task, alloc_vec, free_vec, execute; SystemTagList for exit codes |
396-
| 5 — 68k emitter | Not started | `--emit native` support |
434+
| 5 — 68k emitter | ✅ Done | `@micropython.native` via `MICROPY_EMIT_68K`; try/except in native mode is a known limitation |

0 commit comments

Comments
 (0)