Instructions - Nakazoto/CenturionComputer GitHub Wiki
Instructions
This is a list of the available registers, OpCodes / Instructions, and what they mean. These were all reverse engineered by just looking at existing code and recognizing patterns. As such, this list may be incomplete or full of errors. Any resemblance to the mnemonics or syntax used by other processors, such as the 8086, is simply a coincidence as this ISA has its roots in the Eldorado Electrodata Corporation EE200 which hails from approximately 1971. Documentation on the EE200 can be found here. Most of this information is specifically for the CPU6, the CPU5 and CPU4 all have their own quirks that must be accounted for when writing assembly.
Note, the previous page that was here is outdated, but if you're still looking for something that was on that page, it is available here.
P.ASM
Everything here is designed to be able to allow you to write assembly that can be assembled using the built-in Centurion assembler. This assembler will also output direct Hexadecimal that can be copied when using the PRT0 option.
Registers
There are eight registers available, though care should be taken with some registers, particularly the X, S, C and P registers, as these are used for specific functions during some OpCodes. For more information, refer to this page on the Registers.
Suffixes and Building the OpCode
Suffixes are a major key to using Centurion assembly. Each assembly statement consists of:
- A Base mnemonic (eg.
LDA
for LoaD A register)- Refer to the OpCode List below for more information.
- A size suffix (eg.
LDAB
for LoaD A register Byte)- No suffix means to perform the operation on the entire register. The suffix 'B' means to use the low-order byte of the register: AL, BL, XL, YL, ZL, SL, CL, PL. The high-order byte of the register (AU, BU, XU, YU, ZU, SU, CU, PU) is unaffected.
- An addressing mode (eg.
LDAB/
for LoaD A register Byte with direct value)- Used for instructions that access memory. The suffixes and their usage can be quite complex. Refer to the following section for more information.
Addressing Modes
Addressing modes are a type of suffix added to the base mnemonic+size suffix and used for instructions that access memory. The suffixes are as follows:
Suffix | Usage | Notes |
---|---|---|
= | Literal | The byte or word argument to the instruction is used as the value. |
/ | Direct | The word argument to the instruction is used as the address in memory to get the value from. |
$ | Indirect | The word argument to the instruction is used as the address of a word in memory which is used as the address to get the value from. |
Relative | (This a space character, not a blank) The argument to the instruction is taken as a displacement from PC, or if it is a label, the displacement is calculated. The displacement must be in the range [-128,127] and is relative to the start of the next instruction. The displaced address is used as the address in memory to get the value from. | |
* | Relative Indirect | The argument to the instruction is taken as a displacement from PC, or if it is a label, the displacement is calculated. The displacement must be in the range [-128,127] and is relative to the start of the next instruction. The displaced address is used as the address of a word in memory which is used as the address to get the value from. |
+ | Indexed Addressing | See below. |
- | Indexed Addressing | See below. |
Indexed Addressing
Either '+' or '-' suffix works. There are 12 sub-modes of this mode, controlled by suffixing the argument to the instruction:
- ' ': use the register as an address.
- '+': use the register as an address, then increment the register by 1 (if 'B' suffix on the mnemonic) or 2 (if no 'B' suffix).
- '-': decrement the register by 1 (if 'B' suffix on the mnemonic) or 2 (if no 'B' suffix), then use the register as an address.
- ',nnn': use the register plus the displacement nnn as an address.
- '+,nnn': use the register plus the displacement nnn as an address, then increment the register by 1 (if 'B' suffix on the mnemonic) or 2 (if no 'B' suffix).
- '-,nnn': decrement the register by 1 (if 'B' suffix on the mnemonic) or 2 (if no 'B' suffix), then use the register plus the displacement nnn as an address.
- '*': use the register as an address of a word in memory to use as the address. Can be combined with any of the 6 suffix patterns above to form the other six sub-modes.
- The indexed addressing suffixes are also used for implicit indexing, which is just a shorter way to encode some operations that don't require post-increment or pre-decrement. When the low nibble of a memory opcode is 8-F, it is implicit indexing and allows for a single-byte encoding instead of a two-byte encoding to accomplish the same thing.
BIGNUM and MemBlock
There are of course exceptions to the addressing modes shown above, notably the BIGNUM and MemBlock instructions. Refer to each individual Operation in the full list below for more information.
OpCode List
Each instruction (in each addressing mode if applicable) has an example snippet. The special instructions may not do anything sensible, so run at your own risk. The snippets do not necessarily show a meaningful normal way to use the instruction, though most attempt to. Some (especially the extended addressing modes in BIGNUM and MEMBLOCK) make almost no sense at all, like literal->literal, but the ISA allows it, and it is classic Centurion style with self-modifying code.
Notation in comments uses * instead of () to dereference to avoid confusion with parentheses used for grouping. This notation is also somewhat used in the assembly for indirect addressing. So "*WORD3" means the value found at the address labeled "WORD3". "B" means the value found at the address held in the B register. "(B+3)" means the value found at three plus the address held in the B register. "**B" means the value found at the address found at the address held in the B register. And so on - there are a lot of modes.
Note that the term "string" in any comments does not mean ASCII strings that are human readable unless noted. It generally means any array of bytes.
The CPU6-only instructions are noted when you see "CPU5 illegal start" and "CPU5 illegal end". Removing the instructions between those pairs will allow assembly with P.ASM5 (or S.ASM on a CPU5). In some cases the "CPU5 illegal start" includes a "JMP/ TESTILL", in which case the lines between the start/end should be replaced with that instruction instead for proper operation. All of the support code before and after the instruction snippets is CPU5-compatible. Thus, it is not necessarily the best way to do the same functionality on a CPU6 and should not be used as such.
You will generally need to read the test code and then review the output after running the test to see what is happening as the output is generally terse - usually just the flags, registers, and/or memory after the operation. Note that the display of the P register is missing for most tests because it takes extra work to capture it. Wherever its value is important, it is being printed properly. On CPU5 it is not possible to capture it without changing flags, so it is not done there at all. See PRINTREGS for details.
Instruction count notes:
- Encodings that differ only in arguments beyond the opcode itself are not counted as separate instructions. Most Centurion instructions are almost perfectly orthogonal, so any register can be used with them, so it does not make sense to count each one as a separate instruction.
- Each addressing mode is counted as a separate instruction. This is in line with ARM.
- A CPU6 extension that does not add an addressing mode does not count as a separate instruction. E.g., INRB added the ability to increment by 1-16 instead of just by 1. That is a single functionality still.
- Conversely, adding addressing modes does count as separate instructions. E.g., XFR added three addressing modes to the previous functionality of register-to-register transfers, so it counts as four instructions.
- Encodings that the assembler will never generate are still counted as separate instructions. E.g., the indirect addressing mode with no offset will always be encoded using the implicit register opcode, which is shorter, instead of the indexed direct encoding.
- Instruction encodings that assemble but do not actually work are noted in comments but are not counted.
0x00 ~ 0x0F
HLT, NOP, SF, RF, EI, DI, SL, RL, CL, RSR, RI, SYN, PCX, DLY, RSV
HLT = Halt
NOP = No operation
SF = Set fault
RF = Reset fault
EI = Enable interrupt
DI = Disable interrupt
SL = Set link/carry
RL = Reset link/carry
CL = Complement/invert link/carry
RSR = Return from subroutine
RI = Return from interrupt
SYN = Flash the abort light
PCX = Transfer PC to X
DLY = 4.55 ms delay
RSV = Return from SVC
0x10 ~ 0x1F
BL, BNL, BF, BNF, BZ, BNZ, BM, BP, BGZ, BLE, BS1, BS2, BS3, BS4, BI, BCK
BL = Branch if link/carry set
BNL = Branch if link/carry not set
BF = Branch if fault set
BNF = Branch if fault not set
BZ = Branch if zero
BNZ = Branch if not zero
BM = Branch if minus set
BP = Branch on positive
BGZ = Branch if greater than zero
BLE = Branch if less than or equal to zero
BS1 = Branch if sense switch 1 is set
BS2 = Branch if sense switch 2 is set
BS3 = Branch if sense switch 3 is set
BS4 = Branch if sense switch 4 is set
BI = Branch if interrupts enabled
BCK = Branch if clock enabled
0x20 ~ 0x2F
INRB, DCRB, CLRB, IVRB, SRRB, SLRB, RRRB, RLRB, INAB, DCAB, CLAB, IVAB, SRAB, SLAB, PageTable, DMA
INRB = Increment byte
DCRB = Decrement byte
CLRB = Clear byte
IVRB = Invert byte
SRRB = Arithmetic shift byte right
SLRB = Arithmetic shift byte left
RRRB = Rotate byte right (wraps through carry)
RLRB= Rotate byte left (wraps through carry)
INAB = Increment A register byte
DCAB = Decrement A register byte
CLAB = Clear A register byte
IVAB = Invert A register byte
SRAB = Shift A register byte right
SLAB = Shift A register byte left
PageTable =
DMA =
0x30 ~ 0x3F
INR/INC = Increment word
DCR/DEC = Decrement word
CLR/CAD = Clear (or set) word
IVR/IAD = Invert word
SRR/SHR = Shift word register right
RRR/RTR = Rotate word register right
INA = Increment A register word
DCA = Decrement A register word
CLA = Clear A register word
IVA = Invert A register word
SRA = Shift A register word right
SLA = Shift A register word Left
INX = Increment X register word
DCX = Decrement X register word
0x40 ~ 0x4F
ADDB, SUBB, ANDB, ORIB, OREB, XFRB, BIGNUM, MemBlock, AABB, SABB, NABB, XAXB, XAYB, XABB, XAZB, XASB
ADDB = Add two byte registers
SUBB = Subtract two byte registers
ANDB = AND two byte registers
ORIB = OR two byte registers
OREB = XOR two byte registers
XFRB = Transfer byte register into byte register
BIGNUM = Variable-length integer operations
MemBlock = Memory block operations
AABB = Add A register low byte and B register low byte
SABB = Subtract A register low byte and B register low byte
NABB = AND A register low byte and B register low byte
XAXB = Transfer A register low byte into X register low byte
XAYB = Transfer A register low byte into Y register low byte
XABB = Transfer A register low byte into B register low byte
XAZB = Transfer A register low byte into Z register low byte
XASB = Transfer A register low byte into S register low byte
0x50 ~ 0x5F
ADD, SUB, AND, ORI, ORE, XFR, EAO, DAO, AAB, SAB, NAB, XAX, XAY, XAB, XAZ, XAS
ADD = Add two word registers
SUB = Subtract two word registers
AND = AND two word registers
ORI = OR two word registers
ORE = XOR two word registers
XFR = Transfer word register into word register
EAO = Enable abort on overflow
DAO = Disable abort on overflow
AAB = Add A register word and B register word
SAB = Subtract A register word and B register word
NAB = AND A register word and B register word
XAX = Transfer A register word into X register word
XAY = Transfer A register word into Y register word
XAB = Transfer A register word into B register word
XAZ = Transfer A register word into Z register word
XAS = Transfer A register word into S register word
0x60 ~ 0x6F
LDX = Load X register word
SVC = Service call
MemBlock = Memory block operations
STX = Store X register word
LST = Load status
SST = Store status
0x70 ~ 0x7F
JMP, EPE, MUL, DIV, JSR, STK, POP
JMP = Jump
EPE = Enable Parity Error
MUL = Multiply word register and word register
DIV = Divider word register and word register
JSR = Jump to subroutine
STK = Push to stack
POP = Pop from stack
0x80 ~ 0x8F
LDAB = Load A register byte
DPE = Disable Parity Error
0x90 ~ 0x9F
LDA = Load A register word
SOP = Set Odd Parity
0xA0 ~ 0xAF
STAB = Store A register byte
SEP = Set Even Parity
0xB0 ~ 0xBF
STA = Store A register word
ECK = Enable Clock
0xC0 ~ 0xCF
LDBB = Load B register byte
DCK = Disable Clock
0xD0 ~ 0xDF
LDB = Load B register word
STR = Store register
SAR = Store A register
0xE0 ~ 0xEF
STBB = Store B register byte
LAR = Load A register
0xF0 ~ 0xFF
STB = Store B register word
LIO/SIO = Load IO/Store IO
MVL = Move long