# 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.