Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/caljer1/9900dis/llms.txt

Use this file to discover all available pages before exploring further.

9900dis decodes the complete TMS9900 instruction set, organized into encoding formats 3.5.1 through 3.5.13. Each format uses a different opcode bit-field arrangement within the 16-bit instruction word. The disassembler tries each format handler in sequence and emits the mnemonic and operands for the first handler that recognises the opcode.

Addressing modes

Formats 3.5.1 and 3.5.4 encode a two-bit type field (t) alongside a four-bit register field for each operand. The param351() function in rom.py maps these to the following four addressing modes.
ModeEncoding (t)SyntaxDescription
00b00r0r15Register direct — operand is the workspace register value
10b01*r0Register indirect — operand is the word at the address held in the register
20b10@>addr or @>addr(rN)Symbolic / indexed — a second word in the instruction stream holds the base address; if rN is non-zero it is added as an index
30b11*r0+Register indirect with autoincrement — same as mode 1, then the register is incremented by 1 (byte op) or 2 (word op)
Mode 2 consumes an extra word from the ROM stream, so symbolic instructions are four bytes wide rather than two.

Instruction reference

The TMS9900 instructions decoded by 9900dis are grouped below by function. Each accordion lists the mnemonic, a brief description, and a representative output line as emitted by 9900dis.
Instructions that copy, load, or store values without arithmetic side-effects.
MnemonicDescriptionExample output
MOVMove word from source to destinationMOV r1,r2
MOVBMove byte from source to destinationMOVB @>E000,r8
CLRClear operand to zeroCLR r0
SETOSet operand to >FFFF (all ones)SETO *r3
LILoad immediate word into registerLI r0,>1234
LWPILoad workspace pointer from immediateLWPI >8300
LIMILoad interrupt mask from immediateLIMI >0002
STSTStore status register into workspace registerSTST r12
STWPStore workspace pointer into workspace registerSTWP r13
SWPBSwap high and low bytes of operand in-placeSWPB r5
LI, LWPI, and LIMI consume a second word from the ROM stream as their immediate operand. LWPI and LIMI belong to format 3.5.10 and emit only the immediate value, not a register.
Instructions that perform integer arithmetic and update status bits accordingly.
MnemonicDescriptionExample output
AAdd word: dst = dst + srcA r1,r2
ABAdd byteAB @>028A,r2
SSubtract word: dst = dst - srcS r3,r4
SBSubtract byteSB r0,*r1
INCIncrement operand by 1INC r6
INCTIncrement operand by 2INCT r7
DECDecrement operand by 1DEC r6
DECTDecrement operand by 2DECT r7
NEGNegate (two’s complement)NEG r2
ABSAbsolute valueABS r2
AIAdd immediate word to registerAI r0,>FF00
MPYUnsigned multiply: 32-bit product in rD:rD+1MPY r3,r0
DIVUnsigned divide: quotient in rD, remainder in rD+1DIV r3,r0
A, AB, S, and SB are format 3.5.1 instructions (opcode in bits 15–13, byte flag in bit 12). INC through ABS are format 3.5.4 single-operand instructions. AI is format 3.5.9 and consumes an extra immediate word.
Bitwise and comparison instructions.
MnemonicDescriptionExample output
CCompare word: set status, no writeC r1,r2
CBCompare byteCB @>028A,r3
COCCompare ones corresponding: (src AND dst) == srcCOC r2,r4
CZCCompare zeros corresponding: (src AND dst) == 0CZC r3,r4
XORExclusive OR word: dst = dst XOR srcXOR r1,r2
SOCSet ones corresponding: dst = dst OR srcSOC r1,r2
SOCBSet ones corresponding byteSOCB @>028A,r2
SZCSet zeros corresponding: dst = dst AND NOT srcSZC r1,r2
SZCBSet zeros corresponding byteSZCB r0,*r1
ANDIAND immediate: rN = rN AND immANDI r2,>00FF
CICompare immediate: set status, no writeCI r0,>1000
ORIOR immediate: rN = rN OR immORI r3,>8000
INVInvert (bitwise NOT) operandINV r4
C, CB, SOC, SOCB, SZC, and SZCB are format 3.5.1. COC, CZC, and XOR are format 3.5.2 (opcode in bits 15–10) and use a destination register field in bits 9–6. ANDI, CI, and ORI are format 3.5.9 and consume an extra immediate word.
Shift instructions operate on a workspace register and a 4-bit count field. When the count field is zero the shift count is taken from the low four bits of r0 at runtime.
MnemonicDescriptionExample output
SLAShift left arithmeticSLA r2,4
SRAShift right arithmetic (sign-extended)SRA r2,1
SRCShift right circularSRC r1,3
SRLShift right logical (zero-filled)SRL r3,8
All four belong to format 3.5.8. The disassembler output is {:8}r{w},{c} — register index followed by shift count.
Instructions that alter the program counter.
MnemonicDescriptionExample output
BBranch to address (absolute)B @>6000
BLBranch and link — saves PC to r11BL @RESET
BLWPBranch and load workspace pointer — context switchBLWP @>0000
RTWPReturn with workspace pointer — restore contextRTWP
XExecute instruction at operand addressX *r11
JMPUnconditional jump (relative)JMP >6020
JEQJump if equal (EQ status bit set)JEQ >6010
JGTJump if greater than (AGT bit set)JGT >6030
JHJump if high (unsigned >)JH >6040
JHEJump if high or equal (unsigned >=)JHE >6050
JLJump if low (unsigned <)JL >6060
JLEJump if low or equal (unsigned <=)JLE >6070
JLTJump if less than (signed <)JLT >6080
JNCJump if no carryJNC >6090
JNEJump if not equalJNE >60A0
JNOJump if no overflowJNO >60B0
JOCJump if overflow carryJOC >60C0
JOPJump if odd parityJOP >60D0
B, BL, BLWP, X are format 3.5.4 single-operand. RTWP is format 3.5.12 (no operands). All jump instructions are format 3.5.7 — see Jump displacement calculation below.
Instructions that access the Communications Register Unit (CRU) bit-addressable I/O bus.
MnemonicDescriptionExample output
LDCRLoad CRU — transfer c bits from workspace register to CRULDCR r1,8
STCRStore CRU — read c bits from CRU into workspace registerSTCR r1,8
SBOSet CRU bit to oneSBO 12
SBZSet CRU bit to zeroSBZ 12
TBTest CRU bit — result in EQ status bitTB 12
LDCR and STCR are format 3.5.5. The second operand is a bit count encoded in bits 9–6 of the instruction word. SBO, SBZ, and TB are format 3.5.6; their operand is an 8-bit signed CRU offset in bits 7–0.
MnemonicDescriptionExample output
IDLEIdle until an interrupt occursIDLE
RSETReset — assert RESET to external hardwareRSET
CKOFClock off — stop the CPU clockCKOF
CKONClock on — restart the CPU clockCKON
LREXLoad ROM and executeLREX
XOPExtended operation — software trap to XOP routineXOP r1,2
IDLE, RSET, CKOF, CKON, and LREX are format 3.5.13 and carry no operands. They share the same deconstruct3512() decoder as format 3.5.12 (RTWP) but key against the mne3513 dictionary. XOP is format 3.5.3 and uses the same physical layout as format 3.5.2, with the destination field interpreted as an XOP vector number (0–15) rather than a register.

Jump displacement calculation

All 13 jump instructions (format 3.5.7) encode the branch target as a signed 8-bit displacement in the low byte of the instruction word. The handle357() function computes the absolute target address as follows:
target = current_pc + 2 × signedByte(displacement)
current_pc is the address of the next instruction — the program counter has already been advanced by 2 by the time handle357() is called (readword() increments self.pc on every read). The displacement is therefore relative to the instruction after the jump, consistent with the TMS9900 hardware specification. The signedByte() helper converts the raw unsigned byte value to a signed integer:
def signedByte(value):
    if value > 127:
        return (256 - value) * (-1)
    else:
        return value
For example, a JMP at address >6010 with displacement byte >FE (254 unsigned, −2 signed) targets >6010 + 2 + 2 × (−2) = >600E — one instruction back, forming an infinite loop. If a label exists in the hints file for the target address, handle357() substitutes the symbolic name via hex_or_label() instead of emitting the raw hex address.

Build docs developers (and LLMs) love