# Workabout MX — reverse-engineering toolchain & documentation plan

Goal: reverse-engineer the Workabout MX ROM (`w2mx_v7.20f_eng.bin`, v7.20f) and
produce complete programming documentation for the device, since none exists for
the MX specifically.

## Toolchain (reproducible, headless)

ROM identifies as MAME machine **`psionwamx`** ("Workabout mx"), CPU NEC V30MX
(`psion_asic9mx`), with `psion_asic5` (barcode/UART) and the SIBO expansion slots.

Setup:
```
mkdir -p roms/psionwamx && cp w2mx_v7.20f_eng.bin roms/psionwamx/w2mx_v7.20f.bin
mame psionwamx -rompath roms -verifyroms          # -> "romset psionwamx is good"
```

**Dynamic RE (MAME debugger, headless via xvfb):**
```
xvfb-run -a mame psionwamx -rompath roms -debug \
         -debugscript CMDS.txt -sound none -seconds_to_run N
```
Useful `CMDS.txt` debugger commands:
- `trace FILE` then `go` — log every executed instruction (correct bank mapping).
- `dasm FILE,ADDR,LEN` — disassemble a region as currently mapped.
- `dump FILE,ADDR,LEN` — hex dump memory.
- `bpset ADDR,1,{commands}` — breakpoint with actions (e.g. dump then continue).
- `wpset ADDR,LEN,rw` — watchpoint (catch who reads/writes a driver global).

This resolves the segment/relocation mapping that flat static disassembly of the
ROM could not (e.g. `SCANNER.DYL` / `SCANAPP` code).


**Decompilation (Ghidra headless):** extract the DYL region to a slice and load
as 16-bit real-mode x86:
```
ghidra-analyzeHeadless PROJ NAME -import slice.bin -processor "x86:LE:16:Real Mode" \
  -scriptPath SCRIPTS -postScript decomp.java -deleteProject
```
`SCANNER.DYL`/`SCANAPP` decompile to readable pseudo-C this way (Ghidra 12 needs
a Java GhidraScript, not Python). Caveat: TopSpeed C uses the register-based
`jpi` calling convention, so argument recovery may need convention hints, but
control flow, struct access and the `int` service calls read clearly.

**Static RE:** `radare2 -e asm.arch=x86 -e asm.bits=16 w2mx_v7.20f_eng.bin`
(good for strings, byte-pattern search, and clean fixed-mapped regions).

## What "complete documentation" covers

1. **Hardware** (largely in the HDK, to be confirmed/extended for the MX):
   memory map & banking, ASIC1/2/4/5/9MX register maps, I/O ports, interrupts.
2. **Boot & OS**: reset path, hardware init sequence, the `int 0xCF` OS/executive
   call and its function table, the `int 0xD9`/etc. service vectors.
3. **I/O & drivers**: the device model, `p_open`/`p_iow` function codes per driver,
   and each driver: `TTY`, `WL2` (scanner), `MCR`, `PAR`, `SND`, IR, etc.
4. **Scanner** (immediate priority, partly done — see SCANNER-API.md): `WL2:D`,
   Symbol2 decoder, the 11-byte param block, trigger (ops 6/7), and the
   still-open **data-retrieval** path — to be nailed by tracing `SCANAPP` live.
5. **System services / libraries**: file system (DBF), window server, HWIM/FORM.

## RE order

1. Nail the scanner data-retrieval by running `SCANAPP`/`DEMMAN` under MAME,
   breakpointing the `WL2` code, and tracing how the decoded bytes are delivered.
2. Map the `int 0xCF` OS call table (breakpoint the vector, log CL/BX/DX per call).
3. Document the boot + ASIC init (already partly traced).
4. Work outward to the drivers and system services.

Findings land in `docs/` as they are confirmed (e.g. `SCANNER-API.md`), each
marked confirmed-on-emulator / confirmed-on-device / inferred.

## Notes

- `int 0xCF` convention (from traced code): `CL` = I/O function code, `BX` =
  channel handle, `DX` = argument; result in `AX`. This is the `p_iow` layer.
- MAME cannot inject a real barcode into the laser, so scanner *decode* may not
  reproduce in emulation; but the *code path* (open/config/enable/read structure)
  traces fully, which is what we need to write correct client code.
