commit c99ef06056575f4261a7c26c2761acbdd02df6e9 Author: Roman Boykov Date: Thu Oct 8 16:52:36 2026 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ef29f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.labels +*.obj +*.OBJ +*.COM +*.com +*.bin +*.tmp +tmp/ +build/ +.pi/ +*.lst +*.sld +*.bak +*.BAK +*.BRU diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..37cb1de --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "maziac.asm-code-lens", + "maziac.dezog", + "maziac.hex-hover-converter", + "maziac.z80-instruction-set" + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..2cca520 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,67 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "make Orion-128 MSX-BASIC (sjasmplus)", + "type": "shell", + "command": "sjasmplus", + "args": [ + "--fullpath", + "--nofakes", + "--sld=mzbas.sld", + "mzbas.asm" + ], + "problemMatcher": { + "owner": "sjasmplus", + "fileLocation": "autoDetect", + "pattern": { + "regexp": "^(.*)\\((\\d+)\\):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "message": 4 + } + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + + { + "label": "Optimize Orion-128 MSX-BASIC (MDL)", + "type": "shell", + "command": "/opt/java21/bin/java -jar ~/Soft/MDL/mdl.jar mzbas.asm -cpu z80 -po -dialect sjasmplus", + "problemMatcher": { + "applyTo": "allDocuments", + "fileLocation": [ + "autoDetect", + "${workspaceFolder}" + ], + "owner": "mdl", + "pattern": [ + { + "regexp": "^(\\w+): (.+) in (.+)#([0-9]+): (.+)$", + "file": 3, + "line": 4, + "severity": 1, + "message": 5, + "code": 2 + } + ] + }, + "presentation": { + "echo": false, + "focus": false, + "panel": "dedicated", + "showReuseMessage": false, + "clear": true, + "revealProblems": "onProblem" + }, + "group": { + "kind": "build", + "isDefault": false + } + } + ] +} \ No newline at end of file diff --git a/ANALYSIS.md b/ANALYSIS.md new file mode 100644 index 0000000..d34bd50 --- /dev/null +++ b/ANALYSIS.md @@ -0,0 +1,101 @@ +# 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b79bb2e --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# MSX Basic for Orion-128 computer + +Source codes of MSX Basic-80, for Orion-128 computer (i8080 or Z80 CPU, 64k RAM). +Application was loading from the tape at address 0x0000. + +I tried to preserve the original label names exactly as they appear in the source code published by Microsoft. + +## Compile + +To compile sources, use [sjasmplus Z80 assembler](https://github.com/z00m128/sjasmplus). diff --git a/errors.inc b/errors.inc new file mode 100644 index 0000000..6ae3eb0 --- /dev/null +++ b/errors.inc @@ -0,0 +1,113 @@ +; ================================================== +; MSX BASIC for Orion-128 computer +; +; Error messages and constants +; Disassembled by Romychs @ 2026-10-08 +; ================================================== + +; -------------------------------------------------- +; Error messages +; -------------------------------------------------- +MB_ERRTAB: + DB 0x00 +MSG_ERR_NWF: + DB "NEXT without FOR", 0 ; 0x01 + DB "Syntax error", 0 ; 0x02 + DB "RETURN without GOSUB", 0 ; 0x03 + DB "Out of DATA", 0 ; 0x04 + DB "Illegal function call", 0 ; 0x05 + DB "Overflow", 0 ; 0x06 + DB "Out of memory", 0 ; 0x07 + DB "Undefined line number", 0 ; 0x08 + DB "Subscript out of range", 0 ; 0x09 + DB "Redimensioned array", 0 ; 0x0A + DB "Division by zero", 0 ; 0x0B + DB "Illegal direct", 0 ; 0x0C + DB "Type mismatch", 0 ; 0x0D + DB "Out of string space", 0 ; 0x0E + DB "String too long", 0 ; 0x0F + DB "String formula too complex", 0 ; 0x10 + DB "Can't CONTINUE", 0 ; 0x11 + DB "Undefined user function", 0 ; 0x12 + DB "Device I/O error", 0 ; 0x13 + DB "Verify error", 0 ; 0x14 + DB "No RESUME", 0 ; 0x15 + DB "RESUME without error", 0 ; 0x16 + DB "Unprintable error", 0 ; 0x17 + DB "Missing operand", 0 ; 0x18 + DB "Line buffer overflow", 0 ; 0x19 + DB "FIELD overflow", 0 ; 0x32 + DB "Internal error", 0 ; 0x33 + DB "Bad file number", 0 ; 0x34 + DB "File not found", 0 ; 0x35 + DB "File already open", 0 ; 0x36 + DB "Input past end", 0 ; 0x37 + DB "Bad file name", 0 ; 0x38 + DB "Direct statement in file", 0 ; 0x39 + DB "Sequential I/O only", 0 ; 0x3A + DB "File not OPEN", 0 ; 0x3B + +; Orion specific errors + DB "Bad file mode", 0 ; 0x3C + DB "File still open", 0 ; 0x3D + DB "File already exists", 0 ; 0x3E + DB "Disk full", 0 ; 0x3F + DB "Disk write protected", 0 ; 0x40 + DB "Disk I/O error", 0 ; 0x41 + + +; -------------------------------------------------- +; Error codes +; -------------------------------------------------- +ERRNF EQU 0x01 ; 1 Next wo for +ERRSN EQU 0x02 ; 2 Syntax err +ERRRG EQU 0x03 ; 3 Ret wo gosub +ERROD EQU 0x04 ; 4 Out of data +ERRFC EQU 0x05 ; 5 Illegal function call +ERROV EQU 0x06 ; 6 Overflow +ERROM EQU 0x07 ; 7 Out of memory +ERRULN EQU 0x08 ; 8 Undefined line number +ERRBS EQU 0x09 ; 9 Subscr out of range +ERRDD EQU 0x0a ; 10 Redimensioned array +ERRDV0 EQU 0x0b ; 11 Division by zero +ERRID EQU 0x0c ; 12 Illegal direct +ERRTM EQU 0x0d ; 13 Type mismatch +ERRSO EQU 0x0e ; 14 Out of string space +ERRLS EQU 0x0f ; 15 String too long +ERRST EQU 0x10 ; 16 String formula too complex +ERRCN EQU 0x11 ; 17 Can't CONTINUE +ERRUF EQU 0x12 ; 18 Undefined user function +ERRDIO EQU 0x13 ; 19 Device IO error +ERRVE EQU 0x14 ; 20 Verify error +ERRNR EQU 0x15 ; 21 No resume +ERRRWE EQU 0x16 ; 22 Resume wo error +ERRUE EQU 0x17 ; 23 Unprintable error +ERRMO EQU 0x18 ; 24 Missing operand +ERRLBO EQU 0x19 ; 25 Line buff over + + +NONDSK EQU ERRLBO + 1 ; DSKERR - disk BASIC errors + +ERRFO EQU 0x32 ; 50 Field overflow +ERRIE EQU 0x33 ; 51 Internal error +ERRBFN EQU 0x34 ; 52 Bad File Number +ERRFNF EQU 0x35 ; 53 File Not Found +ERRFAO EQU 0x36 ; 54 File Already open +ERRIPE EQU 0x37 ; 55 Inp past end +ERRBN EQU 0x38 ; 56 Bad file Name +ERRDSF EQU 0x39 ; 57 Direct stmt in file +ERRSIO EQU 0x3A ; 58 Sequential I/O only +ERRFNO EQU 0x3B ; 59 File not open + +; Orion specific errors +ERRBFM EQU 0x3C ; 60 Bad file mode +ERRFSO EQU 0x3D ; 61 File still open +ERRFAE EQU 0x3E ; 62 File already exists +ERRDF EQU 0x3F ; 63 Disk full +ERRDWP EQU 0x40 ; 64 Disk write protected +ERRDIO EQU 0x41 ; 65 Disk I/O error + +; -------------------------------------------------- +LSTERR EQU ERRDIO + 1 diff --git a/ioports.inc b/ioports.inc new file mode 100644 index 0000000..95648b8 --- /dev/null +++ b/ioports.inc @@ -0,0 +1,94 @@ +; =================================================== +; Orion-128 computer +; System I/O ports +; +; Disassembled by Romychs @ 2026-10-08 +; =================================================== + + +; System port mapped to RAM address. +PORT_F400_KBD EQU 0xf400 + +; System port mapped to RAM address. +PORT_F401_KBD EQU 0xf401 + +; System port mapped to RAM address. +PORT_F402_KBD EQU 0xf402 + +; System port mapped to RAM address. +PORT_F500_USR1 EQU 0xf500 + +; System port mapped to RAM address. +PORT_F600_USR2 EQU 0xf600 + +; System port mapped to RAM address. +PORT_F601_USR2 EQU 0xf601 + +; System port mapped to RAM address. +PORT_F602_USR2 EQU 0xf602 + +; System port mapped to RAM address. +PORT_F603_USR2 EQU 0xf603 + +; System port mapped to RAM address. +; VG93 State/Command +FDC_F700_STATE EQU 0xf700 + +; System port mapped to RAM address. +; VG93 Track number +FDC_F701_TRACK EQU 0xf701 + +; System port mapped to RAM address. +; VG93 Sector number +FDC_F702_SECTOR EQU 0xf702 + +; System port mapped to RAM address. +; VG93 read/write data from floppy +FDC_F703_DATA EQU 0xf703 + +; System port mapped to RAM address. +FDC_F704_REQ EQU 0xf704 + +; System port mapped to RAM address. +; Select floppy disk side +FDC_F708_SIDE EQU 0xf708 + + +; Write only system port mapped to RAM address. +; Set video mode. +; bit 0 - palette 0-1, 1-2; +; bit 1 - color count 0 - 16 colors, 1 - 4 colors; +; bit 2 - 0-mono, 1-color; +PORT_SYS1 EQU 0xF800 + + +; Write only system port mapped to RAM address. +; Set active RAM page +; bits D[3:0] - page number +PORT_SYS2 EQU 0xf900 + +; Write only system port mapped to RAM address. +; Switch Screen +; bits D[1:0] - screen number; +; bit D6 - RAM Refresh; +; bit D7 - 12k/16k (384px/512px screen width) +PORT_SYS3 EQU 0xfa00 + +; Write only system port mapped to RAM address. +PORT_SYS4 EQU 0xfb00 + +; =================================================== +; I/O Ports +; =================================================== + +; Set active RAM page +; bits D[3:0] - page number +P_SW_MEM EQU 0xf9 + +; Switch screen RAM window +; D1 D0 +; 0 0 — screen 1 (0xС000—0xEFFF) +; 0 1 — screen 2 (0x8000—0xAFFF) +; 1 0 — screen 3 (0x4000—0x6FFF) +; 1 1 — screen 4 (0x0000—0x2FFF) +P_SW_SCR EQU 0xfa diff --git a/monitor.inc b/monitor.inc new file mode 100644 index 0000000..57183c2 --- /dev/null +++ b/monitor.inc @@ -0,0 +1,100 @@ +; =================================================== +; Orion-128 computer +; MONITOR Program symbols +; +; ram:f800-ram:ffff +; Disassembled by Romychs @ 2026-10-05 +; =================================================== + +; Keyboard read +; Out: A - key code +MON_KBRD EQU 0xf803 + + +; Read byte from tape +; Inp: A = 0xff - with search syncro byte, 0x00 - without +; Out: A = byte from tape +MON_TRD EQU 0xf806 + +; Character output to screen +; Inp: C - char code +MON_TV2 EQU 0xf809 + +; Tape write byte +; Inp: C - byte to write +MON_TWR EQU 0xf80c + +; Write char to screen +; Inp: A - char +MON_OUT EQU 0xf80f + +; Get keyboard status +; Out: A = 0xff - key pressed +; A = 0x00 - no key pressed +MON_STTS EQU 0xf812 + +; Out byte in HEX form to screen +; Inp: A - byte to print +MON_ASC EQU 0xf815 + +; Output string +; Inp: HL -> asciiz string +MON_MSG EQU 0xf818 + +; Input key wo wait +; Out: A = 0xff no key pressed +; A = 0xfe rus/lat key pressed +; else A = key code +MON_INKEY EQU 0xf81b + +; Read cursor position +; Out: H - Y +; L - X +MON_GETCUR EQU 0xf81e + +MON_USR_DRV EQU 0xf821 + +; Read file from tape +MON_TRDF EQU 0xf824 + +; Write file to tape +; Inp: HL - start addres of code +; DE - end address of code +MON_TWRF EQU 0xf827 + +; Calculate checksum +; Inp: HL - start addres of code +; DE - end address of code +; Out: BC - checksum +MON_CHKSUM EQU 0xf82a + +; Unpack internal character generator +MON_UNPAK EQU 0xf82d + +; Read last free RAM address +; Out: HL - address +MON_LASTADDR EQU 0xf830 + +MON_RESET EQU 0xf833 + +; Read byte from RAM page +; Inp: HL - Address +; A - page 0..3 +; Out: C - result +MON_RBDS EQU 0xf836 + +; Write byte to RAM page +; Inp: HL - Address +; A - page 0..3 +; C - byte to write to +MON_WBDS EQU 0x1e53 + +; Set cursor position +; Inp: H - row +; L - column +MON_SET_CUR EQU 0xf83c + +; Make beep sound +MON_SOUND EQU 0xf83f + + diff --git a/mzbas.asm b/mzbas.asm new file mode 100644 index 0000000..3576cd2 --- /dev/null +++ b/mzbas.asm @@ -0,0 +1,6 @@ +; ================================================== +; MSX BASIC for Orion-128 computer +; +; Main file +; Disassembled by Romychs @ 2026-10-08 +; ==================================================