MSI-88
Information
The MSI-88 (MSI/88e) handheld data terminal (CDP1802ACE, 8K system ROM at 0x0000–0x1FFF) runs a stack-based threaded bytecode interpreter that executes the firmware's operator/monitor logic, which is stored as a token stream starting at 0x1E2B. For general hardware information, see the General Information section.
The fetch loop is at 0x0011. Register RD is the bytecode program counter. Each single-byte token dispatches through one of two 2-byte tables: the target address parity selects the execution mode.
Register Usage
| R2 | Return / hardware stack (start 0x809C, grows down); holds CALL return addresses |
| R3 | Dispatch target; routine jumped to via SEP R3 |
| R6 | Scratch (0x8100) |
| R7 | Dispatch table 0x0B00 for low tokens (0x00–0x7F) |
| R8 | Dispatch table 0x0A00 for high tokens (0x80–0xFF) |
| RD | Bytecode program counter (token pointer, advanced by LDA RD) |
| RE | Data stack pointer (0x80Fx, grows down; 16-bit words big-endian) |
| RF | Interpreter core (0x0011); SEP RF returns to the fetch loop |
Architecture
| CPU | CDP1802ACE @ 2.0 MHz |
| System ROM | 8K at 0x0000–0x1FFF |
| Interpreter loop | ROM at 0x0011 (LDA RD fetch) |
| Dispatch tables | 0x0A00 (high tokens) and 0x0B00 (low tokens), 2 bytes each |
| Data stack | 0x80F0–0x8100 (RE pointer, 16-bit values, grows down) |
| Return stack | R2 hardware stack (CALL / RET) |
| Boot program | Token stream at 0x1E2B; data subroutines ≈ 0x074B |
Each table entry is a 2-byte address. An even target is a GOTO to native 1802 micro-op (SEP R3); an odd target is a CALL to a data-subroutine (push RD on the R2 return stack, set RD to the odd target, and re-enter the interpreter on that nested token stream). Opcode 0x8C (RET) pops RD from R2 to return.
Definitions
| bb | 8-bit operand byte appended to the opcode field (e.g. 90bb, 9Ebb); zero-extended for PUSH, used as the relative offset for JP / JZ / LOOP |
| aaaa | 16-bit immediate operand or branch target (2 inline bytes, big-endian) |
| TOS / NOS / 3OS | Top / next / third 16-bit value on the data stack |
| TOS.0 / NOS.0 | Low byte of the corresponding stack value (8-bit operand) |
| [ ] | Address value: the 16-bit value at the memory address held in the stack position (dereference), e.g. [TOS], [NOS], [3OS] |
| EFx | CDP1802 EF flag inputs (x = 1, 2, or 3); PUSH EFx pushes 0x0001 if set, else 0x0000 |
| SW | Mode-switch input (INP 2, low 2 bits); PUSH SW pushes 0x0001 if clear, else 0x0000 |
| R | Return stack; the value at the top of the R2 return/control stack (PUSH R, peek, non-destructive) |
| Rx | CPU register (x = 2, C, or E); R2 is the return/control stack pointer (PUSH R2), RC is added to the inline operand (PUSH aaaa, RC), RE is the data-stack pointer (PUSH RE) |
Syntax
Instructions (except CALL and PUSH 16 bit constant)
| Opcode | Mnemonic | Parameter | Forth | Handler | Description |
|---|---|---|---|---|---|
| 01 | IDLE | IDLE | 03DB | Power down — replaces CALL 03DB (the data-subroutine at 0x03DB is IDLE followed by RET). The boot path's deliberate power-down halt; the trace shows IDLE for both this CALL-form entry and the native EC opcode | |
| 03 | PULSE | 2, 08 | PULSE2 8 | 0683 | Pulse port-2 bit 3 (0x08): set it then immediately clear it; replaces CALL 0683. A short handshake/strobe pulse with no delay |
| 04 | SEQ | Q ON | 068A | Set Q output (=1) | |
| 05 | REQ | Q OFF | 068C | Reset Q output (=0) | |
| 07 | HASH | TOS | CHECKSUM | 06FE | Composite memory-range walk (provisional, needs more traces): pop 16-bit counter TOS (R4), seed address R5 from the 0x81D1/0x81D3 pointer table, loop R4 times accumulating R5 = R5 + M(R5), push final 16-bit result. Likely a checksum/hash or address-generator - not a stack primitive |
| 0C | LDVAL | TOS | LDVAL | 0753 | Clear the display, load the standard message into the text buffer at 0x810B, and write the low byte of the popped value as a character at buffer offset 4 (0x810F); pops 1 word (the value) |
| 0D | TIN | TOS | RX | 075C | Serial byte receive into memory - tape or terminal input (provisional, source unconfirmed): pop count (TOS) and address (NOS); for each byte sample the EF2 input 8 times MSB-first, one sample per Q-clock pulse (REQ/SEQ), with an EF3/OUT 2/INP 1 device handshake when EF3 = 0; store the byte to M[RA] and read-back verify; on failure save the failing address to M(0x8143/44) and push 0x0001, on success push 0x0000 |
| 14 | SUB | [TOS], NOS | -! | 07B4 | M[TOS] = M[TOS] - NOS (16-bit memory subtract, big-endian word at [TOS], borrow across bytes). Pops both operands |
| 15 | SUB | [TOS], NOS.0 | C-! | 07C4 | M[TOS] = M[TOS] - NOS.0 (byte memory subtract; only the low byte of NOS is used). Pops both operands |
| 1D | CKRAM | TOS | PROBE | 09C8 | RAM probe on TOS: write-verify 0 and FF at each byte from addr; stop/re-push addr at first non-writable byte |
| 23 | PUSH | EF3 | EF3? | 0820 | Push 0x0001 if EF3 = 1, else 0x0000 |
| 24 | PUSH | EF1 | EF1? | 082C | Push 0x0001 if EF1 = 1, else 0x0000 |
| 25 | PUSH | EF2 | EF2? | 0830 | Push 0x0001 if EF2 = 1, else 0x0000 |
| 3B | TOUT | TOS | TX | 0D4C | Serial byte transmit from memory - tape or terminal output (provisional, source unconfirmed, paired with TIN 0x0D): pop count (TOS) and address (NOS); wait for EF2 = 1 (device ready, with a DEC R9 time-out that pushes 0x0001 on timeout); then bit-bang each source byte out on Q (FSK: SHRC + SEQ/REQ + SMI 01 timing); push 0x0000 on completion |
| 3F | RSTOR | RESTORE | 0F20 | Restore the saved program state (program counter and both stacks) and continue execution | |
| 47 | PUSH | RE | SP@ | 0F8A | Push the 16-bit data-stack pointer (RE) as a word |
| 48 | HASH | TOS, NOS | CHECKSUM | 0F94 | Memory-range walk with explicit base: pop base address (TOS) and count (NOS); loop count times adding each byte to the address (R5 = R5 + M(R5), then advance); push the final address |
| 49 | FILL | TOS.0, NOS.0, [3OS] | FILL | 0FB2 | Fill memory: fill NOS.0 bytes at the address in 3OS with the byte TOS.0 |
| 4B | PUSH | R2 | RSP@ | 0FDA | Push the 16-bit return-stack pointer (R2) as a word |
| 4C | XOR | TOS, NOS | XOR | 0FE2 | TOS = NOS XOR TOS (16-bit bitwise XOR) |
| 4D | SHL | NOS, TOS.0 | LSHIFT | 0FEC | TOS = NOS << TOS.0 (16-bit left shift by the low byte of TOS; result becomes the top of stack) |
| 50 | PUSH | SW | SW? | 1E80 | Push 1 if the mode switches are clear (INP 2, low 2 bits), else 0 |
| 6F | SWAPB | TOS | SWAB | 123A | Swap the high and low bytes of the top stack word (16-bit byte-swap) |
| 80 | NOOP | NOOP | 004E | No operation | |
| 8C | RET | EXIT | 005E | Return; pop return address from return stack | |
| 8D | RET | DROP, 4 | EXIT4 | 0064 | Return, discarding 4 bytes (2 words) from the return stack first |
| 8E | RET | DROP, 8 | EXIT8 | 006A | Return, discarding 8 bytes (4 words) from the return stack first |
| 8F | PUSH | aaaa | LIT | 0070 | Push 16-bit immediate (2 inline bytes) |
| 91 | PUSH | aaaa, RC | LIT RC | 007A | Push 16-bit immediate + RC (2 inline bytes, big-endian); equals PUSH aaaa when RC = 0 |
| 9C | DISPA | TOS, NOS.0 | DISPATCH | 00F6 | Dispatch (indirect): use the base word (TOS) and the low byte of NOS (doubled) to read a record, switch the dispatch page and execute the computed token |
| 9D | DISPA | TOS | EXECUTE | 010A | Dispatch: switch the dispatch-table page (high byte of TOS) and execute the computed token (low byte of TOS) |
| A0 | PUSHR | TOS, NOS | 2>R | 012A | Pop TOS and NOS from the data stack and push both onto the R2 return/control stack (NOS goes deeper, TOS on top) |
| A1 | PUSHR | 0 | >R 0 >R | 012E | Pop TOS from the data stack; push TOS and a zero word onto the R2 return stack |
| A2 | PUSHR | >R | 013E | Pop TOS from the data stack and push it onto the R2 return/control stack | |
| A3 | POPR | R> | 0148 | Pop a 16-bit value from the R2 return/control stack and push it onto the data stack | |
| A4 | PUSH | R | R@ | 0152 | Push the control/return-stack top value onto the data stack (peek, non-destructive) |
| A5 | PUSH | R2, 4 | RSP+4 @ | 0158 | Push the 16-bit word 4 bytes above the R2 return-stack top onto the data stack (peek, non-destructive, two words below the top word; R2 unchanged) |
| A6 | DUPR | R@ >R | 0166 | Duplicate the R2 return-stack top word one slot higher (M(R2+2):M(R2+3) = M(R2):M(R2+1); R2 unchanged) | |
| A7 | DROP | DROP | 0172 | Drop TOS (discard top of stack) | |
| A8 | DUP | DUP | 0176 | Duplicate TOS (push copy of top value) | |
| A9 | SWAP | SWAP | 0180 | Exchange TOS and NOS on data stack (swap top two 16-bit values) | |
| AA | OVER | OVER | 0190 | Copy NOS to TOS (push copy of second stack value on top) | |
| AB | LD | TOS, [TOS] | @ | 019A | Load the 16-bit value from the memory address in TOS (dereference); TOS = M[TOS] |
| AC | LD | TOS.0, [TOS] | C@ | 01A6 | Load byte M[TOS] into TOS.0 and zero-extend the result |
| AD | LD | [TOS], NOS | ! | 01B0 | Store NOS into M[TOS] (16-bit) |
| AE | LD | [TOS], NOS.0 | C! | 01BE | Store the low byte of NOS into M[TOS] (byte store) |
| AF | ADD | [TOS], NOS | +! | 01C6 | 16-bit memory add: M[TOS] += NOS (big-endian word at [TOS], carry across bytes) |
| B0 | AND | TOS, NOS | AND | 01D6 | TOS = NOS AND TOS (16-bit bitwise AND, pops both, pushes result) |
| B1 | OR | TOS, NOS | OR | 01E2 | TOS = NOS OR TOS (16-bit bitwise OR, pops both, pushes result) |
| B2 | SUB | TOS, NOS | - | 01EE | TOS = NOS - TOS (16-bit sub) |
| B3 | ADD | TOS, NOS | + | 01FA | TOS = NOS + TOS (16-bit add) |
| B4 | SUB | TOS, 0 | 0- | 0206 | Negate TOS: TOS = 0 - TOS (16-bit two’s-complement) |
| B5 | ISZ | TOS | 0= | 0210 | Zero test: push 0x0001 if TOS = 0, else 0x0000 |
| B6 | ISNEG | TOS | 0< | 021E | Sign test on TOS: push 0x0001 if TOS < 0 (bit 15 set), else 0x0000 |
| B7 | ISGT | NOS, TOS | > | 0226 | Push 1 if NOS > TOS else 0 (signed 16-bit compare) |
| B8 | ISLT | NOS, TOS | < | 023A | Signed 16-bit less-than: push 1 if NOS < TOS, else 0 |
| B9 | ISEQ | TOS, NOS | = | 0246 | Push 1 if TOS = NOS else 0 |
| BA | MCPY | [NOS], [3OS] | CMOVE | 025E | Copy TOS bytes from the memory address in 3OS to the memory address in NOS (pops count, dest, src) |
| BB | MUL | TOS.0, NOS.0 | C* | 026C | 8-bit x 8-bit multiply: TOS = TOS.0 x NOS.0 (16-bit result, shift-and-add) |
| BC | DIV | NOS, TOS.0 | /MOD | 028A | Divide: NOS = NOS / TOS.0 (low byte of TOS is the divisor); quotient goes to NOS, remainder to TOS (in place) |
| C6 | PUSH | 810B | LIT | 02D4 | Push the 16-bit constant 0x810B (text/edit buffer base); also sets flag M(0x8002)=1 (buffer active) |
| CE | PUSH | [810A] | C@ 810A | 0317 | Push the byte at M[0x810A] zero-extended to 16 bits |
| CF | PUSH | 810B+[810A] | C@ 810A 810B + | 031B | Push 0x810B plus the byte at M[0x810A] |
| D0 | LD | TOS.0, 810B+[810A] | C@ 810A 810B + C@ | 031F | Load byte M[0x810B + M[0x810A]] into TOS.0 and zero-extend the result (buffer character at the cursor) |
| D1 | LD | 810B+[810A], NOS.0 | C! 810A 810B + | 0323 | Store the low byte of NOS at M[0x810B + M[0x810A]] (byte store at the buffer cursor) |
| D2 | PUSH | [8107] | C@ 8107 | 0327 | Push the byte at M[0x8107] zero-extended to 16 bits |
| D3 | PUSHB | 0 | CLIT 0 | 014E | Push a single zero byte (0x00) onto the data stack |
| D4 | SHL | TOS | 2* | 032A | TOS = TOS << 1 (16-bit left shift / double, in place) |
| D7 | DIVR | NOS, TOS.0 | /MOD SWAP | 0345 | 16-bit division: divide NOS by TOS.0; TOS = quotient, NOS = remainder (result-order complement of DIV BC) |
| D8 | MOD | NOS, TOS.0 | MOD | 0355 | Remainder of NOS / TOS.0 (16-bit division; quotient dropped) |
| D9 | CLS | CLS | 035A | Clear the display: write 0x20 (space) to 34 display-buffer bytes via STXD at the R6 display pointer, set M(0x8002)=1 (buffer active), then return (LBR J02DB) | |
| DA | SVM | SAVEMSG | 036B | Copy 32 bytes from the display buffer (0x810B) to the message table (0x81DB) | |
| DB | LDM | LOADMSG | 0371 | Copy 32 bytes from the message table (0x81DB) into the display buffer (0x810B) | |
| DC | LDMSG | TOS | LDMSG | 0377 | Clear the display and load a length-prefixed message into the text buffer at 0x810B: pop TOS = table address, copy M[TOS] bytes from M[TOS+1..] to M(0x810B) |
| DD | LD | [TOS], 0 | 0 C! | 0382 | Byte store of constant 0: M[TOS] = 0x00 (alternate entry of DE at 0x0382, skipping the LDI 01) |
| DE | LD | [TOS], 1 | 1 C! | 0380 | Byte store of constant 1: M[TOS] = 0x01 |
| E0 | LD | [TOS], 0001 | 1 ! | 1E00 | Word store of constant 1: M[TOS]:M[TOS+1] = 0x0001 |
| E1 | OUT | 2, TOS.0 | OUT2 | 0394 | Set the bits given by TOS.0 in the port 2 output |
| E2 | OUTM | 2, TOS.0 | OUTM2 | 039E | Clear the bits given by TOS.0 in the port 2 output |
| E3 | INP1 | TOS, TOS.0 | INP1 | 03A8 | Push 0x0001 if (INP 1 AND TOS.0) ≠ 0, else 0x0000 (TOS.0 is a mask) |
| E4 | INP1 | 08 | INP1 8 | 03B3 | Push 0x0001 if (INP 1 AND 0x08) ≠ 0, else 0x0000 — fixed mask 0x08 (INP1 bit 3 = battery/voltage flag); replaces CALL 03B3 |
| E5 | INP1 | 20 | INP1 20 | 03B7 | Push 0x0001 if (INP 1 AND 0x20) ≠ 0, else 0x0000 — fixed mask 0x20 (bit 5 function unconfirmed); replaces CALL 03B7 |
| E6 | SCAN | SCAN | 03BA | Display refresh and keyboard scan: save context and disable interrupts, strobe the display (OUT 1/2/4), then check the 0x5A5B program-loaded flag at 8103/8104 — run the loaded program (vector 8203/8204) if present, else restart the interpreter at the idle program 03DB (IDLE) that halts the terminal | |
| E7 | ROT | ROT | 1E0E | Rotate the top three stack words: TOS=A, NOS=B, 3OS=C → TOS=C, NOS=A, 3OS=B | |
| E8 | OUT | 2, 40 | OUT2 40 | 1E23 | Output the 8-bit value 0x40 to port 2 |
| E9 | OUTM | 2, 40 | OUTM2 40 | 1E27 | Clear bit 6 (0x40) in the port 2 output |
| EA | OUT | 2, 20 | OUT2 20 | 03C1 | Set port-2 bit 5 (0x20) and hold it for a fixed 500-iteration delay; replaces CALL 03C1. The bit-5 set companion of EB (OUTM 2, 20); the EA/EB pair mirrors the E8/E9 bit-6 pair |
| EB | OUTM | 2, 20 | OUTM2 20 | 03CB | Clear port-2 bit 5 (0x20); replaces CALL 03CB. The bit-clear companion of EA (OUT 2, 20) |
| EC | IDLE | IDLE | 03D0 | Terminal halt / power-down: blank the display (OUT 2 0x00/0x80), disable interrupts, zero R0, and halt in IDL. Reached deliberately at the end of the boot self-test when no program is loaded (the 0x5A5B program-loaded flag at 8103/8104 is absent). No key poll and no INT wake — with no interrupt/DMA source this is a permanent halt until power-cycle. Renamed from KEYWAIT | |
| ED | INC | [TOS] | 1+! | 03DE | 16-bit memory increment: M[TOS] += 1 (big-endian word with carry) |
| EE | DEC | [TOS] | 1-! | 03E0 | 16-bit memory decrement: M[TOS] -= 1 (big-endian word with borrow) |
| EF | SEND | SEND | 05AC | Send the text buffer M(0x810B): 10 characters to the MAN2815 display and the whole string to a parallel-connected device. The external send happens only while the buffer-active flag M(0x8002) is set (set by CLS); the flag is cleared when the send completes, so the whole string is transmitted once while the display keeps refreshing | |
| FB | INCB | [TOS] | C1+! | 0646 | Byte memory increment: M[TOS] += 1 |
| FC | DECB | [TOS] | C1-! | 0648 | Byte memory decrement: M[TOS] -= 1 |
| FD | ADD | [TOS], NOS.0 | C+! | 0654 | Byte memory add: M[TOS] += NOS.0 (low byte of NOS) |
PUSH 16 bit constant
| Opcode | Mnemonic | Parameter | Forth | Handler | Description |
|---|---|---|---|---|---|
| 06 | PUSH | 0693 | LIT | 068F | Push the 16-bit constant 0x0693 |
| 09 | PUSH | 81FB | LIT | 0747 | Push the 16-bit constant 0x81FB |
| 0A | PUSH | 81D7 | LIT | 074B | Push the 16-bit constant 0x81D7 |
| 0B | PUSH | 81D9 | LIT | 074F | Push the 16-bit constant 0x81D9 |
| 0E | PUSH | 8131 | LIT | 079B | Push the 16-bit constant 0x8131 |
| 0F | PUSH | 8133 | LIT | 079F | Push the 16-bit constant 0x8133 |
| 10 | PUSH | 8135 | LIT | 07A3 | Push the 16-bit constant 0x8135 |
| 11 | PUSH | 8140 | LIT | 07A7 | Push the 16-bit constant 0x8140 |
| 12 | PUSH | 8142 | LIT | 07AB | Push the 16-bit constant 0x8142 |
| 13 | PUSH | 8143 | LIT | 07AF | Push the 16-bit constant 0x8143 |
| 38 | PUSH | 81FD | LIT | 0D1B | Push the 16-bit constant 0x81FD |
| 39 | PUSH | 0D23 | LIT | 0D1F | Push the 16-bit constant 0x0D23 |
| 45 | PUSH | 8026 | LIT | 0F71 | Push the 16-bit constant 0x8026 |
| 4E | PUSH | 810B | LIT | 1003 | Push the 16-bit constant 0x810B |
| 51 | PUSH | 1043 | LIT | 103F | Push the 16-bit constant 0x1043 |
| 52 | PUSH | 1095 | LIT | 1091 | Push the 16-bit constant 0x1095 |
| 53 | PUSH | 10B7 | LIT | 10B3 | Push the 16-bit constant 0x10B7 |
| 54 | PUSH | 10BF | LIT | 10BB | Push the 16-bit constant 0x10BF |
| 55 | PUSH | 10C7 | LIT | 10C3 | Push the 16-bit constant 0x10C7 |
| 56 | PUSH | 10CD | LIT | 10C9 | Push the 16-bit constant 0x10CD |
| 57 | PUSH | 10D3 | LIT | 10CF | Push the 16-bit constant 0x10D3 |
| 58 | PUSH | 10D9 | LIT | 10D5 | Push the 16-bit constant 0x10D9 |
| 59 | PUSH | 81FD | LIT | 10DF | Push the 16-bit constant 0x81FD |
| 5A | PUSH | 81FE | LIT | 10E3 | Push the 16-bit constant 0x81FE |
| 5B | PUSH | 81FF | LIT | 10E7 | Push the 16-bit constant 0x81FF |
| 5C | PUSH | 80A0 | LIT | 10EB | Push the 16-bit constant 0x80A0 |
| 5D | PUSH | 80A2 | LIT | 10EF | Push the 16-bit constant 0x80A2 |
| 5F | PUSH | 80A4 | LIT | 10FB | Push the 16-bit constant 0x80A4 |
| 60 | PUSH | 80A6 | LIT | 10FF | Push the 16-bit constant 0x80A6 |
| 61 | PUSH | 80A8 | LIT | 1103 | Push the 16-bit constant 0x80A8 |
| 62 | PUSH | 80AA | LIT | 1107 | Push the 16-bit constant 0x80AA |
| 63 | PUSH | 80AC | LIT | 110B | Push the 16-bit constant 0x80AC |
| 64 | PUSH | 8027 | LIT | 110F | Push the 16-bit constant 0x8027 |
| 65 | PUSH | 8028 | LIT | 1113 | Push the 16-bit constant 0x8028 |
| 66 | PUSH | 802A | LIT | 1117 | Push the 16-bit constant 0x802A |
| 6C | PUSH | 81D5 | LIT | 11DB | Push the 16-bit constant 0x81D5 |
| 96 | PUSH | 0000 | LIT | 00DC | Push the 16-bit constant 0x0000 |
| 97 | PUSH | 0001 | LIT | 00E2 | Push the 16-bit constant 0x0001 |
| 98 | PUSH | 0002 | LIT | 00E6 | Push the 16-bit constant 0x0002 |
| 99 | PUSH | 0010 | LIT | 00EA | Push the 16-bit constant 0x0010 |
| 9A | PUSH | 0020 | LIT | 00EE | Push the 16-bit constant 0x0020 |
| 9B | PUSH | 0040 | LIT | 00F2 | Push the 16-bit constant 0x0040 |
| BD | PUSH | 8100 | LIT | 02AF | Push the 16-bit constant 0x8100 |
| BE | PUSH | 8101 | LIT | 02B3 | Push the 16-bit constant 0x8101 |
| BF | PUSH | 8102 | LIT | 02B7 | Push the 16-bit constant 0x8102 |
| C0 | PUSH | 8103 | LIT | 02BB | Push the 16-bit constant 0x8103 |
| C1 | PUSH | 8105 | LIT | 02BF | Push the 16-bit constant 0x8105 |
| C2 | PUSH | 8107 | LIT | 02C3 | Push the 16-bit constant 0x8107 |
| C3 | PUSH | 8108 | LIT | 02C7 | Push the 16-bit constant 0x8108 |
| C4 | PUSH | 8109 | LIT | 02CB | Push the 16-bit constant 0x8109 |
| C5 | PUSH | 810A | LIT | 02CF | Push the 16-bit constant 0x810A |
| C7 | PUSH | 81DB | LIT | 02E5 | Push the 16-bit constant 0x81DB |
| CC | PUSH | 812D | LIT | 030F | Push the 16-bit constant 0x812D |
| CD | PUSH | 812F | LIT | 0313 | Push the 16-bit constant 0x812F |
CALL
| Opcode | Mnemonic | Parameter | Forth | Handler | Description |
|---|---|---|---|---|---|
| 00 | CALL | 0675 | CALL 0675 | 0675 | Call the data-subroutine at 0x0675 |
| 02 | CALL | 067D | CALL 067D | 067D | Call the data-subroutine at 0x067D |
| 16 | CALL | 07CF | CALL 07CF | 07CF | Call the data-subroutine at 0x07CF |
| 17 | CALL | 07D5 | CALL 07D5 | 07D5 | Call the data-subroutine at 0x07D5 |
| 18 | CALL | 07DB | CALL 07DB | 07DB | Call the data-subroutine at 0x07DB |
| 19 | CALL | 07FB | CALL 07FB | 07FB | Call the data-subroutine at 0x07FB |
| 1A | CALL | 1DF7 | CALL 1DF7 | 1DF7 | Call the data-subroutine at 0x1DF7 |
| 1B | CALL | 0805 | CALL 0805 | 0805 | Call the data-subroutine at 0x0805 |
| 1C | CALL | 094B | CALL 094B | 094B | Call the data-subroutine at 0x094B |
| 1F | CALL | 1E2B | CALL 1E2B | 1E2B | Call the data-subroutine at 0x1E2B |
| 21 | CALL | 08F1 | CALL 08F1 | 08F1 | Call the data-subroutine at 0x08F1 |
| 26 | CALL | 0835 | CALL 0835 | 0835 | Call the data-subroutine at 0x0835 |
| 27 | CALL | 083D | CALL 083D | 083D | Call the data-subroutine at 0x083D |
| 28 | CALL | 0841 | CALL 0841 | 0841 | Call the data-subroutine at 0x0841 |
| 29 | CALL | 084D | CALL 084D | 084D | Call the data-subroutine at 0x084D |
| 2A | CALL | 0853 | CALL 0853 | 0853 | Call the data-subroutine at 0x0853 |
| 2C | CALL | 0CEF | CALL 0CEF | 0CEF | Call the data-subroutine at 0x0CEF |
| 2D | CALL | 0CF7 | CALL 0CF7 | 0CF7 | Call the data-subroutine at 0x0CF7 |
| 2E | CALL | 1E91 | CALL 1E91 | 1E91 | Call the data-subroutine at 0x1E91 |
| 2F | CALL | 1E99 | CALL 1E99 | 1E99 | Call the data-subroutine at 0x1E99 |
| 30 | CALL | 1ECF | CALL 1ECF | 1ECF | Call the data-subroutine at 0x1ECF |
| 31 | CALL | 1EED | CALL 1EED | 1EED | Call the data-subroutine at 0x1EED |
| 32 | CALL | 1EEF | CALL 1EEF | 1EEF | Call the data-subroutine at 0x1EEF |
| 35 | CALL | 1F45 | CALL 1F45 | 1F45 | Call the data-subroutine at 0x1F45 |
| 36 | CALL | 1D71 | CALL 1D71 | 1D71 | Call the data-subroutine at 0x1D71 |
| 37 | CALL | 0D0B | CALL 0D0B | 0D0B | Call the data-subroutine at 0x0D0B |
| 3A | CALL | 0D41 | CALL 0D41 | 0D41 | Call the data-subroutine at 0x0D41 |
| 40 | CALL | 0F35 | CALL 0F35 | 0F35 | Call the data-subroutine at 0x0F35 |
| 41 | CALL | 0F37 | CALL 0F37 | 0F37 | Call the data-subroutine at 0x0F37 |
| 4F | CALL | 1007 | CALL 1007 | 1007 | Call the data-subroutine at 0x1007 |
| 5E | CALL | 10F3 | CALL 10F3 | 10F3 | Call the data-subroutine at 0x10F3 |
| 67 | CALL | 111B | CALL 111B | 111B | Call the data-subroutine at 0x111B |
| 6A | CALL | 11AD | CALL 11AD | 11AD | Call the data-subroutine at 0x11AD |
| 6B | CALL | 11B1 | CALL 11B1 | 11B1 | Call the data-subroutine at 0x11B1 |
| 6D | CALL | 11DF | CALL 11DF | 11DF | Call the data-subroutine at 0x11DF |
| 6E | CALL | 11E5 | CALL 11E5 | 11E5 | Call the data-subroutine at 0x11E5 |
| 70 | CALL | 1245 | CALL 1245 | 1245 | Call the data-subroutine at 0x1245 |
| 71 | CALL | 124B | CALL 124B | 124B | Call the data-subroutine at 0x124B |
| 72 | CALL | 1253 | CALL 1253 | 1253 | Call the data-subroutine at 0x1253 |
| 73 | CALL | 1279 | CALL 1279 | 1279 | Call the data-subroutine at 0x1279 |
| 74 | CALL | 128B | CALL 128B | 128B | Call the data-subroutine at 0x128B |
| 75 | CALL | 1295 | CALL 1295 | 1295 | Call the data-subroutine at 0x1295 |
| 76 | CALL | 129D | CALL 129D | 129D | Call the data-subroutine at 0x129D |
| 77 | CALL | 12A1 | CALL 12A1 | 12A1 | Call the data-subroutine at 0x12A1 |
| 78 | CALL | 12C5 | CALL 12C5 | 12C5 | Call the data-subroutine at 0x12C5 |
| 79 | CALL | 1C65 | CALL 1C65 | 1C65 | Call the data-subroutine at 0x1C65 |
| 7A | CALL | 1339 | CALL 1339 | 1339 | Call the data-subroutine at 0x1339 |
| 7B | CALL | 136B | CALL 136B | 136B | Call the data-subroutine at 0x136B |
| D5 | CALL | 0333 | CALL 0333 | 0333 | Call the data-subroutine at 0x0333 |
| D6 | CALL | 0341 | CALL 0341 | 0341 | Call the data-subroutine at 0x0341 |
| F0 | CALL | 05ED | CALL 05ED | 05ED | Call the data-subroutine at 0x05ED |
| F1 | CALL | 05F3 | CALL 05F3 | 05F3 | Call the data-subroutine at 0x05F3 |
| F2 | CALL | 05F7 | CALL 05F7 | 05F7 | Call the data-subroutine at 0x05F7 |
| F3 | CALL | 0605 | CALL 0605 | 0605 | Call the data-subroutine at 0x0605 |
| F4 | CALL | 060D | CALL 060D | 060D | Call the data-subroutine at 0x060D |
| F5 | CALL | 0617 | CALL 0617 | 0617 | Call the data-subroutine at 0x0617 |
| F6 | CALL | 061B | CALL 061B | 061B | Call the data-subroutine at 0x061B |
| F7 | CALL | 061F | CALL 061F | 061F | Call the data-subroutine at 0x061F |
| F8 | CALL | 062B | CALL 062B | 062B | Call the data-subroutine at 0x062B |
| F9 | CALL | 062F | CALL 062F | 062F | Call the data-subroutine at 0x062F |
| FA | CALL | 0643 | CALL 0643 | 0643 | Call the data-subroutine at 0x0643 |
| FE | CALL | 065F | CALL 065F | 065F | Call the data-subroutine at 0x065F |
| FF | CALL | 0671 | CALL 0671 | 0671 | Call the data-subroutine at 0x0671 |
SYS
| Opcode | Mnemonic | Parameter | Forth | Handler | Description |
|---|---|---|---|---|---|
| 08 | SYS | 072C | SYS 072C | 072C | Feed a byte block to the serial/tape interface (count and address from the stack) |
| 1E | SYS | 08BC | SYS 08BC | 08BC | Display strobe: OUT 1/2/4 with an IDL wait |
| 20 | SYS | 1DC0 | SYS 1DC0 | 1DC0 | Poll input port 1 until bit 7 is set |
| 22 | SYS | 090C | SYS 090C | 090C | Wait for EF1 |
| 2B | SYS | 0C00 | SYS 0C00 | 0C00 | Keyboard input: read a key, set up the input state, and rewind the program counter |
| 33 | SYS | 1F0E | SYS 1F0E | 1F0E | Wait for EF1, then push 0x00F2 |
| 34 | SYS | 1F34 | SYS 1F34 | 1F34 | Wait for EF1, then push a variable value (intent unclear) |
| 3C | SYS | 0E40 | SYS 0E40 | 0E40 | Invalid/broken handler; likely data executed as code, probably not a real opcode |
| 3D | SYS | 0E92 | SYS 0E92 | 0E92 | Save context, then wait in IDL |
| 3E | SYS | 0F0E | SYS 0F0E | 0F0E | Unexamined; kept as a placeholder |
| 42 and 43 | SYS | 0F3A | SYS 0F3A | 0F3A | Interrupt-protected status write: write the status code, clear a flag, restore interrupts |
| 44 | SYS | 0F3C | SYS 0F3C | 0F3C | Interrupt-protected status write with status code 0x35 (same handler as 42/43) |
| 46 | SYS | 0F76 | SYS 0F76 | 0F76 | Unexamined; kept as a placeholder |
| 4A | SYS | 0FC6 | SYS 0FC6 | 0FC6 | Table lookup / vector dispatch: replace TOS with a 2-byte table entry indexed by its doubled low byte |
| 68 | SYS | 0D4A | SYS 0D4A | 0D4A | Serial/tape byte transmit (TOUT variant with a timing delay) |
| 69 | SYS | 11A2 | SYS 11A2 | 11A2 | Feed a single byte through the bit-serial routine |
| 81 | SYS | 0040 | SYS 0040 | 0040 | Reset the low dispatch-table page to the default (0x0B) |
| 82 to 8A | SYS | 0044 | SYS 0044 | 0044 | Set the low dispatch-table page (per-token table entry) |
| 8B | SYS | 0050 | SYS 0050 | 0050 | Save context (return-stack pointer and dispatch-page into a temp area) |
| DF | SYS | 1E02 | SYS 1E02 | 1E02 | Unexamined; kept as a placeholder |
Note: The SYS table above lists native 1802 micro-ops whose exact function is still under verification (serial block feed, keyboard input, EF1-wait helpers, display strobes, and a few high-table entries). They are defined in the SYS block of the syntax file using the handler’s dispatch-table address as the constant, e.g. const=0040 stack code=81.
The tape/terminal byte I/O pair TIN (0x0D) and TOUT (0x3B), and the status-message transmit SEND (0xEF), are provisional pending confirmation of the EF2/EF3 wiring and the cassette/acoustic/remote interface.
SCAN (0xE6) is the display-refresh / restart entry; IDLE (0xEC, renamed from KEYWAIT) is the terminal power-down halt at the end of the boot self-test when no program is loaded. The MSI/88 uses no interrupts, so IDL waits in it forever until power-cycle.