Sixty four instructions becomes seventy

The six settled back on the twenty fourth, built now.

RCAL and RRET are a call that puts nothing back. CALL restores A, B and Data
Pointers 0 through 2, which costs ten bytes of Stack and is why a subroutine
here can only hand anything back through Q, DP3 or memory. RCAL costs two and
restores nothing, which is what a short leaf routine wants and is unsafe in
exactly the way the name says.

They are a pair because the frames are different sizes: returning from one
through the other walks the Stack to somewhere that was never a return address.
That was the user's correction to the original proposal, which had a raw call
and no raw return.

DPUA and DPDA offset a Data Pointer by A; DPUW and DPDW by A and B together,
most significant first. DPUP and DPDN take a byte written into the program, so
moving a pointer by something just worked out meant storing it and loading it
back. Down as well as up on symmetry grounds, which was also the user's call -
the argument against it came from counting uses in a corpus written under the
constraint.

The opcodes sit where they belong: 0x16 and 0x1E immediately below CALL and RET,
and 0x4E through 0x51 at the end of the Data Pointer family. All six fit shapes
that already existed, so instructiontable.py needed only set membership and both
machine side copies of the table regenerated from it unchanged.

Checked at every level it exists at: the emulator runs them, the host assembler
encodes them, the monitor disassembles all six with the right lengths, and the
assembler that runs on the machine builds a program using them byte for byte
identically to the host - and that program runs.

The recorded test measures what the two calls COST as well as what they put
back, because an RCAL that quietly did what CALL does would still return to the
right place. It does not survive that: returned through RRET, it hangs.

docs.sh can read a two word number now. The count of instructions taking a Data
Pointer went past twenty, and the pattern only allowed one word, so the check
would have reported that the manual had stopped saying it rather than that the
number was wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-08-25 17:29:43 -04:00
co-authored by Claude Opus 5
parent 00d896e3e7
commit af0360128b
11 changed files with 247 additions and 11 deletions
+9 -3
View File
@@ -53,7 +53,7 @@ A conditional branch reads the thing it names at the moment it runs. BRA looks a
## Naming a Data Pointer:
Seventeen instructions work through a Data Pointer. Each of them carries a selector byte immediately after its opcode, naming which Data Pointer it means. LDD and STD move a pointer through a pointer, so they carry two selectors, the first naming the pointer being moved and the second naming the pointer that addresses it.
Twenty one instructions work through a Data Pointer. Each of them carries a selector byte immediately after its opcode, naming which Data Pointer it means. LDD and STD move a pointer through a pointer, so they carry two selectors, the first naming the pointer being moved and the second naming the pointer that addresses it.
The selector is a full byte, but only enough of it is read to choose among the Data Pointers the machine has. A selector larger than the highest numbered pointer wraps around rather than being rejected, so it is the assembler's job to refuse to write one.
@@ -76,7 +76,7 @@ The Bytes column is the total length of the instruction, counting its opcode, an
| 07 | SHL | 1 | A and B form a circular shift register. Rotate this register left. |
| 08 | SHR | 1 | A and B form a circular shift register. Rotate this register right. |
### Branch and Subroutine Operations: 14 Instructions
### Branch and Subroutine Operations: 16 Instructions
| Hex Code | Mnemonic | Bytes | Description |
| -- | ---- | -- | -- |
| 10 | BRI | 3 | Branch Immediately. Loads the immediate next two bytes of Program Memory into the Program Counter, first the most significant byte, then the least. |
@@ -89,9 +89,11 @@ The Bytes column is the total length of the instruction, counting its opcode, an
| 1B | BNA | 3 | Branch if A is not zero. |
| 1C | BNB | 3 | Branch if B is not zero. |
| 1D | BNC | 3 | Branch if the Carry Flag is clear. |
| 16 | RCAL | 3 | Raw call. Pushes only the Program Counter, then performs an immediate branch. Two bytes of Stack, and nothing is put back. Must be returned from with RRET. |
| 17 | CALL | 3 | Call subroutine. Pushes the Program Counter, Data Pointers 0 through 2, B and A to the Stack, then performs an immediate branch. This costs ten bytes of Stack. |
| 18 | SWI | 2 | Software Interrupt. The next byte names a software vector. Pushes an interrupt frame and dispatches through it. Never masked. |
| 19 | RETI | 1 | Return from an interrupt. Restores everything the frame holds and carries on from where the interrupt arrived. |
| 1E | RRET | 1 | Return from a raw call. Takes back the Program Counter and nothing else. |
| 1F | RET | 1 | Return from subroutine. Restores A, B, and Data Pointers 0 through 2 from the Stack, then sets the Program Counter to the instruction after the CALL. Data Pointer 3 and Q are left as the subroutine leaves them. |
### Register Operations: 13 Instructions
@@ -124,7 +126,7 @@ Q is where every ALU result lands, and Q is not itself an ALU operand, so MVQA a
| 35 | POPB | 1 | Reads the location referenced by the Stack Pointer from Data Memory into B then increments the Stack Pointer. |
| 36 | POPD | 2 | Restores the named Data Pointer from the stack, increments the Stack Pointer by two. |
### Data Operations: 14 Instructions
### Data Operations: 18 Instructions
| Hex Code | Mnemonic | Bytes | Description |
| -- | ---- | -- | -- |
| 40 | INCD | 2 | Increments the named Data Pointer. |
@@ -141,6 +143,10 @@ Q is where every ALU result lands, and Q is not itself an ALU operand, so MVQA a
| 4B | STD | 3 | Stores the first named Data Pointer into the two bytes of Data Memory addressed by the second, most significant byte first. |
| 4C | MVSD | 2 | Copies the Stack Pointer into the named Data Pointer. The Stack Pointer itself is unchanged. |
| 4D | MVDS | 2 | Copies the named Data Pointer into the Stack Pointer, moving the Stack. Read The Stack Pointer, Set By Hand before using it. |
| 4E | DPUA | 2 | Offsets the named Data Pointer up by A. |
| 4F | DPDA | 2 | Offsets the named Data Pointer down by A. |
| 50 | DPUW | 2 | Offsets the named Data Pointer up by A and B together, A being the most significant. |
| 51 | DPDW | 2 | Offsets the named Data Pointer down by A and B together, A being the most significant. |
BRD is the only branch whose destination is not written into the program. Every other branch carries the address it goes to, fixed when the program was assembled; BRD takes it from a Data Pointer, which is what makes a table of addresses something a program can dispatch through rather than only read. Together with LDD it turns the Data Segment into somewhere a program can keep a list of places to go.