Monitor: a line assembler

a <address>, then instructions until a line that is just a dot.

The syntax is the assembler's own: a selector rides on the mnemonic as LDA.0
or LDD.0.1, and leaving one off means Data Pointer 0 exactly as it does in a
source file, so nothing learned at the monitor has to be unlearned when
writing a program. Case is folded, since the assembler does not care either.

Numbers are hexadecimal and bare. A source file writes 0x2000 or 0d16 because
it has both and must say which; a monitor has one and says so once, in the
manual, rather than on every line.

It reads the same table the disassembler does, searched the other way round,
which is the point of it being a table rather than two lists: what a writes,
d reads back, and neither can drift from the other or from the assembler both
were generated from. Instruction lengths come from the shared shape table
too, so the cursor cannot get out of step with what was written.

THE WHOLE LINE IS UNDERSTOOD BEFORE ANYTHING IS WRITTEN. Emitting the opcode
first and discovering a missing operand afterwards leaves half an instruction
in memory, which the next line usually covers up and the last line of a
session does not. Written that way first and fixed.

What cannot be written is a label, and that is the whole difference between
this and the assembler proper: a label is a promise to fill an address in
later, and later is what a line at a time does not have.

The recorded test now types in a complete program - a string poked into Data
Memory, instructions assembled into Program Memory, and the result run - and
includes a lower case mnemonic, both selector forms, an instruction that does
not exist and one missing its value, so the refusals sit beside the successes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Anachronaut
2026-08-19 22:29:50 -04:00
co-authored by Claude Opus 5
parent c23adb2836
commit 3b800a69e8
8 changed files with 475 additions and 6 deletions
+22
View File
@@ -719,10 +719,32 @@ bank 01
| --- | --- |
| `x [addr]` | Sixty-four bytes, as hex and as characters |
| `d [addr]` | Eight instructions, disassembled |
| `a addr` | Assemble instructions, until a line that is just a dot |
| `s addr b b …` | Put those bytes there |
| `b program\|data\|n` | Which bank to look at |
| `g addr` | Go there |
`a` writes the assembler's own syntax: a selector rides on the mnemonic as `LDA.0` or `LDD.0.1`, and leaving one off means Data Pointer 0 exactly as it does in a source file, so nothing learned at the monitor has to be unlearned when writing a program. Case does not matter, and the whole line is refused before anything is written, so a mistyped instruction leaves no half of itself behind.
```
* b data
* s 8100 68 65 6C 6C 6F 2C 20 74 79 70 65 64 0A 00
* b program
* a 8200
8200: SETD.0 8100
8204: SWI 10
8206: SWI 12
8208: .
* g 8200
hello, typed
```
A program and its data, both entered by hand, calling a system service and returning to the prompt they were written at. Note the two banks: instructions go into Program Memory and the string into Data Memory, because that is what a Harvard machine means and the monitor will not guess for you.
**Numbers here are hexadecimal and bare.** A source file writes `0x2000` or `0d16` because it has both and must say which; the monitor has one and says so once.
**What cannot be written is a label**, and that is the whole difference between this and the assembler proper. A label is a promise to fill an address in later, and later is what a line at a time does not have. It is also why the same instruction table serves both directions here: what `a` writes, `d` reads back, and neither can drift from the other or from the assembler they were generated from.
`x` and `d` share one cursor and each leaves it past what it showed, so without an address either carries on — reading through memory is one letter at a time, and you can switch between bytes and instructions without retyping where you are. `s` deliberately does not move it.
Everything else here does something; the monitor looks at what the others did. It shows memory as hex and as characters, disassembles it, writes bytes into it, and jumps to an address — all through the memory controller, which is the only thing that can reach Program Memory.