Files
SplitBit-Emulator/Programs/CosmOS/Assembler/table.asm
T
AnachronautandClaude Opus 5 dcb331c151 SplitBit assembles SplitBit: M1, a single file with no includes
Programs/CosmOS/Assembler/ is an assembler written in SplitBit assembly. It
runs under CosmOS, reads source off a SplitBit disk, and writes a binary back
to it with no host involved anywhere:

    > run Asm.sbx hello.asm
    wrote hello.bin: program 17, data 14, labels 2

THE ACCEPTANCE TEST IS THE BYTES. Tests/native.sh assembles Programs/hello.asm
both ways and compares the two files byte for byte, then runs the one the
machine built. "It ran" and "the sizes look right" both pass for a binary with
a label one byte out, which is a program that jumps into the middle of an
instruction - so the only honest test is the one SplitDisk and sbfs.asm
already work under: two implementations of one written specification, each
checking the other. The files are identical and the result prints Hello,
World! in 70 cycles.

hello.asm is the target because it is the oldest program in the repository.
The first thing this machine ever ran is now the first thing it assembles for
itself.

TWO PASSES OVER STREAMED SOURCE. The C assembler reads every token of every
file into one array; that cannot port, because cosmos.asm alone is 56,047
bytes against 64K of Data Memory. The native one streams through a 256 byte
window, twice, and keeps only the label table between the passes. Two passes
suffice because every length is known without resolving anything - an
instruction's from its shape, a value's is one, a string's is its characters
and a zero - so the first pass fixes every address and the second never needs
a fixup list. A forward reference stops being a special case and becomes the
reason there are two passes at all.

The parts, each checked before anything was built on it:
  source.asm    characters out of a file of any size, with a line number
  token.asm     tokens out of characters, one character of lookahead
  classify.asm  what a token is, in the C assembler's order, which IS the
                language: keyword, instruction, value, string, label
  labels.asm    names packed in an arena, four bytes of index each
  numbers.asm   sixteen bit arithmetic, since sbfs.asm's cannot be reached
  table.asm     the instruction set, generated by the same script the
                monitor's copy is, and now BOTH are checked by docs.sh

readTest.asm and tokenTest.asm check the reader and the tokenizer on their
own, recorded as cosmosSource and cosmosTokens. A wrong classification does
not produce a wrong byte somewhere obvious; it produces a right looking
program of the wrong length, so it is worth catching where it happens.

WHAT IT REFUSES: #Include, #Base, #Align, #Reserve and #Vectors are refused
by name rather than ignored. Skipping a directive would produce a file that
looked right and was the wrong length, which is the worst thing an assembler
can do.

Two traps worth recording, both already known to this project and both hit
again: CALL restores A, B and DP0-DP2, so three routines returning an answer
in A had it undone by their own return; and numStep works on DP0, so three
sites that set DP1 left a pointer that never advanced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
2026-08-20 22:13:15 -04:00

107 lines
3.1 KiB
NASM

; The instruction set, as the assembler needs to see it.
;
; A SECOND COPY, and it is worth saying why rather than hoping nobody notices. The monitor
; has one of these in cosmos.asm, and the assembler cannot use it: the monitor's copy lives
; in the system's data at an address that moves every time CosmOS is rebuilt, and there is
; no linker to reach it by name. So the assembler carries its own 448 bytes. That is the
; cost of having no libraries, paid where it is cheapest to pay.
;
; Both copies are generated by Tests/instructiontable.py from the C assembler's own list,
; and Tests/docs.sh checks both against it. Neither can drift without the suite saying so.
;
; Seven bytes an entry: the opcode, the shape, and four characters of name with the zero
; the assembler puts after a string. Every mnemonic is four characters or fewer, so a name
; padded to four is an exact match rather than a prefix.
;
; It goes in the DATA Segment, because the assembler has to read it and an instruction can
; only read Data Memory. A table in Program Memory could not be reached by the program
; holding it, except through the memory controller.
#Data
; How many bytes an instruction of each shape runs to, the opcode included. The assembler
; does not use this to size a token - the operand that follows is a token of its own and
; carries its own length - but it is what says an instruction is well formed.
AsmShapeLength:
0d1 0d3 0d2 0d2 0d3 0d4 0d3
; How many Data Pointer selectors an instruction of each shape names. This is what the
; assembler needs: a selector is part of the mnemonic rather than a token after it, so it
; is the one thing about an instruction's length that is not settled by the opcode alone.
;
; 0 no operand 4 a selector and a byte
; 1 an address 5 a selector and an address, which is SETD
; 2 a byte 6 two selectors, which is LDD and STD
; 3 a selector
AsmShapeSelectors:
0d0 0d0 0d0 0d1 0d1 0d1 0d2
AsmInstructionCount:
0d64
AsmInstructions:
0x00 0d0 "ADD "
0x01 0d0 "SUB "
0x02 0d0 "AND "
0x03 0d0 "OR "
0x04 0d0 "XOR "
0x05 0d0 "NOTA"
0x06 0d0 "NOTB"
0x07 0d0 "SHL "
0x08 0d0 "SHR "
0x10 0d1 "BRI "
0x11 0d1 "BRQ "
0x12 0d1 "BRA "
0x13 0d1 "BRB "
0x14 0d1 "BRC "
0x15 0d3 "BRD "
0x1A 0d1 "BNQ "
0x1B 0d1 "BNA "
0x1C 0d1 "BNB "
0x1D 0d1 "BNC "
0x17 0d1 "CALL"
0x18 0d2 "SWI "
0x19 0d0 "RETI"
0x1F 0d0 "RET "
0x20 0d0 "RSTA"
0x21 0d0 "RSTB"
0x22 0d0 "INCA"
0x23 0d0 "INCB"
0x24 0d0 "DECA"
0x25 0d0 "DECB"
0x26 0d2 "INIA"
0x27 0d2 "INIB"
0x28 0d0 "CCF "
0x29 0d0 "MVQA"
0x2A 0d0 "MVQB"
0x2B 0d0 "SIF "
0x2C 0d0 "CIF "
0x30 0d0 "PSHQ"
0x31 0d0 "PSHA"
0x32 0d0 "PSHB"
0x33 0d3 "PSHD"
0x34 0d0 "POPA"
0x35 0d0 "POPB"
0x36 0d3 "POPD"
0x40 0d3 "INCD"
0x41 0d3 "DECD"
0x42 0d3 "LDA "
0x43 0d3 "LDB "
0x44 0d3 "STQ "
0x45 0d3 "STA "
0x46 0d3 "STB "
0x47 0d5 "SETD"
0x48 0d4 "DPUP"
0x49 0d4 "DPDN"
0x4A 0d6 "LDD "
0x4B 0d6 "STD "
0x4C 0d3 "MVSD"
0x4D 0d3 "MVDS"
0xD0 0d2 "OUTQ"
0xD1 0d2 "OUTA"
0xD2 0d2 "OUTB"
0xE0 0d2 "INA "
0xE1 0d2 "INB "
0xF0 0d0 "NOP "
0xFF 0d0 "HALT"