102 lines
5.3 KiB
Markdown
102 lines
5.3 KiB
Markdown
# Ghidra project analysis — Orion-MSXBASIC / MZBAS$.BRU
|
||
|
||
Program: **MZBAS$** — MSX BASIC for the Orion-128 (Z80), tape image loaded at `0x0000`.
|
||
Banner in the image: `MSX system / version 1.2/M / MSX BASIC / Copyright 1983,1993 by Microsoft,OBERON Inc`
|
||
i.e. the MSX BASIC 2.1 codebase ported to Orion-128 (64K RAM, Z80).
|
||
|
||
## Source file format (`MZBAS$.BRU`)
|
||
|
||
Cassette-style image, 33664 (0x8380) bytes:
|
||
|
||
| Offset | Size | Content |
|
||
|--------|------|---------|
|
||
| 0x0000 | 8 | name `MZBAS$··` |
|
||
| 0x0008 | 2 | load address `0x0000` (LE) |
|
||
| 0x000A | 2 | length field `0x8300` (LE; payload is actually 0x8370) |
|
||
| 0x000C | 4 | unknown/reserved (`00 49 53 D4`) |
|
||
| 0x0010 | 0x8370 | program image → `ram:0x0000–0x836F` |
|
||
|
||
Mapping verified: file offset 0x10 = `ram:0000`, banner at file 0x8251 = `ram:08241`.
|
||
The tape image contains **only** the BASIC program (0x0000–0x836F); high memory in the
|
||
Ghidra project was modeled separately.
|
||
|
||
## Memory map (as modeled in Ghidra)
|
||
|
||
| Block | Range | Size | Notes |
|
||
|-------|-------|------|-------|
|
||
| MB | 0000–BFFF | 48K | BASIC program image (real data ends at 0x836F) |
|
||
| SCREEN | C000–EFFF | 12K | MSX screen RAM (uninitialized in image) |
|
||
| MON_RAM | F000–F2FF | 768B | character generator (`MON_CHARGEN`) |
|
||
| ORI_F300_CODE | F300–F3FF | 256B | Orion I/O patch code — **duplicated in the project from its in-image home at 0x0C22** (bytes identical) |
|
||
| IOPORTS | F400–F7FF | 1K | `PORT_F400_KBD` (keyboard, 10 xrefs), USR1 F500, USR2 F600, EXT F700, FDC regs F701–F708 |
|
||
| MONITOR | F800–FFFF | 2K | zeroed in the image; real monitor lives in Orion ROM. `SYSINIT` does `CALL 0xF830` into it |
|
||
| PORTS (io space) | 0000–00FE | 255B | e.g. `P_SW_MEM` io:00F9 (14 xrefs), `P_SW_SCR` io:00FA |
|
||
|
||
## Entry point and startup
|
||
|
||
- **Entry**: `SYSINIT` at `0x0000` = `JP 0x24A2`.
|
||
- `0x24A2`: `CALL 0xF830` (Orion monitor), sets `SP`, saves it to `0x8D01`, then
|
||
initializes the keyboard port (`LD A,0xAA / LD HL,0xF400 ...`), calls `0x0C0A`,
|
||
does a wait-loop on BC/DE counters, and hands control onward.
|
||
|
||
## Major structures found
|
||
|
||
### 1. Vector table, `0x0000–~0x00EC`
|
||
~78 entries of `JP nn`. The first ~15 slots are 3-byte-aligned with NOP padding
|
||
(`0x0000 JP 24A2`, `0x0008 JP 24C6`, `0x0010 JP 24C9`, `0x0018 JP 2111`,
|
||
`0x0020 JP 1B55`, `0x0028 JP 24CC`, …), then densely packed JPs from `0x0038`
|
||
(`JP 03AB, 1AA1, 0228, 022E, 028D, 01EB, 0207, 0241, 1B5B, 04AC, 04F6, 0CE8, …`).
|
||
This is the built-in command/statement dispatch table; real code starts at ~`0x00ED`.
|
||
|
||
### 2. Command-prefix table, `0x1AAD–~0x1B50`
|
||
Fixed 16-byte records: 8-byte text + 8 zero bytes:
|
||
`LOAD"`, `AUTO `, `GOTO `, `LIST `, `RUN␍`, `SAVE"`, `CLOAD"`, `CONT␍`, `LIST.␍`, …
|
||
Used to recognize whole-line commands. Table is pointed to from code at `0x1AA1`
|
||
(`LD HL,0x1AAD / CALL 0x0FF0`).
|
||
|
||
### 3. Keyword/function lookup table, `~0x3AF5–0x3DA8`
|
||
Variable-length entries: a short distinguishing fragment of the keyword (1–5 chars)
|
||
followed by a 2-byte handler address. Fragments include:
|
||
`NKEY`(INKEY$), `PRIN`(PRINT), `ETUR`(RETURN), `ESTOR`(RESTORE), `ESUM`(RESUME),
|
||
`IGHT`(RIGHT$), `CREE`(DECLARE), `TRING`(STRING), `PACE`(SPACE$), `ARPT`(VARPTR),
|
||
`EFST/EFIN/EFSN/EFDB`, `ELET`, `OCAT`, `FILE`, `RESE`, …
|
||
|
||
### 4. Error table, `0x3DAB–~0x4070` (`MB_ERRTAB`)
|
||
Zero-terminated messages, indexed by error code — matches `errors.inc`:
|
||
1 `NEXT without FOR`, 2 `Syntax error`, … 19 `Line buffer overflow`,
|
||
0x32 `FIELD overflow`, 0x33 `Internal error`, 0x34–0x3B file errors,
|
||
plus Orion-specific additions. Followed by `" in "`, `"Ok␍␊"`, `"Break"`.
|
||
|
||
### 5. Character tables, `0x07E2–0x089A`
|
||
Digit/upper/lower case conversion tables (`;1234567890-:`, `-@abcdefghijklmn`, …).
|
||
|
||
### 6. Banner & workspace, `~0x8200–0x836F`
|
||
Code for memory allocation/stack setup (refs to `0x8CC2/0x8CC4`, `0x8EAF/0x8EB0/0x8EB2`)
|
||
immediately followed by the banner strings at `0x8241` and end-of-image code at `0x836F`.
|
||
|
||
### 7. Orion patch code, image copy at `0x0C22` (= project block F300)
|
||
Small I/O routines writing port `0xF9` (`LD A,1 / OUT (F9),A`) with HL-based loops —
|
||
the Orion-128 hardware glue that replaces MSX I/O calls.
|
||
|
||
## Project state / gaps
|
||
|
||
- **2006 symbols** (original Microsoft label names) are present, but:
|
||
- **0 functions** defined, and no instruction listing outside the few ranges
|
||
disassembled in this session (`0x0000–0x005F`, `0x1A80–0x1B47`, `0x24A2–0x2501`,
|
||
`0xF830–0xF86F`).
|
||
- Auto-analysis is marked complete (nothing left to run); scripts are disabled
|
||
(`GHIDRA_MCP_ALLOW_SCRIPTS` not set), so bulk work must go through individual tools.
|
||
- High memory (SCREEN/MON_RAM/MONITOR) is placeholder; only F300 patch code and
|
||
port labels carry real content.
|
||
|
||
## Suggested next steps (for the reconstruction in `mzbas.asm`)
|
||
|
||
1. Run `reanalyze` or create functions at the vector-table targets to get call graphs.
|
||
2. Walk the dispatch table at `0x0038+` — each JP target is a statement handler;
|
||
naming them from the MSX BASIC 2.1 source (`MB_*` labels) will anchor the rest.
|
||
3. Reconstruct the global variable block around `0x8C00–0x8F60` (pointers seen:
|
||
`0x8CC2/0x8CC4`, `0x8D01`, `0x8EAF/0x8EB0/0x8EB2`) — these are the BASIC workspace
|
||
(`MB_BASLIM`, program pointer, stack, etc. in the original).
|
||
4. The 16-byte command records at `0x1AAD` and the fragment table at `0x3AF5`
|
||
translate directly into assembler tables for sjasmplus.
|