This is an old revision of the document!
Table of Contents
Appendix 4 Instruction Set Architecture
ISA Overview
The SD-8516 has core, extended, and CISC instructions.
- CORE operates like a RISC instruction set. It is designed to be completely sufficient while remaining small. This is what you should target first.
- EXTENDED are quality of life instructions. A great example is ADD register immediate. You do not need this instruction; you can load values into registers and add them. But we provide ADD register, immediate for quality of life. Technically, MUL is a QOL as well since you can loop with ADD.
- CISC instructions are special instructions, usually VAX-isms, designed to be quality of life for assembly language programmers.
Core instruction set
27 RISC-style instructions. A small core.
| 01 | LD_MEM | LDA [$5] | Load register from memory location | |
| 00 | LD_IMM | LDA $5 | Load register with immediate value | |
| 02 | LD_REG | LDA [X] | load register from memory location | |
| 05 | ST_MEM | STA [$10] | Store register in memory location | |
| 06 | ST_REG | STA [X] | Store A in memory location using register as pointer | |
| 09 | MOV | MOV Y, A | Copy A up on Y | |
| 0B | PUSH | PUSH A | Push A onto stack – ye scurvy dog! | |
| 0C | POP | POP Y | Pull stack value an' hand it over to register | |
| 0F | PUSHF | PUSHF | Push flags | |
| 10 | POPF | POPF | Pop flags back | |
| 15 | INC | INC X | Increment register by 1 (any size: byte/word/etc.) | |
| 16 | DEC | DEC Y | Decrement register by 1 (any size) | |
| 1E | ADD | ADD X, Y | Add X = X + Y | |
| 1F | SUB | SUB X, Y | Subtract X = X - Y | |
| 32 | AND | AND dst, src | Bitwise AND (compare two integers bit by bit) | |
| 33 | OR | OR dst, src | Bitwise OR (same) | |
| 34 | XOR | OR dst, src | Bitwise XOR | |
| 35 | NOT | NOT reg | Invert all bits in an integer word | |
| 46 | SHL | SHL A | Shift left | Z, N, C |
| 47 | SHR | SHR A | Shift right | Z, N, C |
| 5A | CMP | CMP A, B | Compare (subtract, discard result) | Z, N, C, V |
| 5B | CMP_IMM | CMP A, 0x0001 | Compare (subtract, discard result) | Z, N, C, V |
| 64 | JMP | JMP @label | Unconditional jump | None |
| 65 | JZ | JZ @label | Jump if zero | None |
| 66 | JNZ | JNZ @label | Jump if not zero | None |
| 67 | JC | JC @label | Jump if carry set | None |
| 68 | JNC | JNC @label | Jump if carry clear | None |
| 84 | CALL | CALL @label | Call subroutine (push IP, jump) | |
| 85 | RET | Return from subroutine (pop IP) | ||
| B6 | SETF | SETF 0x80 | Set bits in flags | * |
| B7 | CLRF | CLRF 0x80 | Clear bits in flags | * |
| B8 | TESTF | TESTF 0x80 | Non-destructive AND | Z C |
Core-2 instructions
10 instructions. Some instructions are not strictly RISC but still considered core.
| 20 | MUL | MUL X, Y | Multiply X = X * Y | |
| 21 | DIV | DIV X, Y | Divide X = X / Y | |
| 22 | MOD | MOD X, Y | Modulo X = X % Y | |
| 86 | INT | INT 0x10 | Software interrupt | |
| 87 | RTI | RTI | Return from Interrupt |
Extended instruction set
53 instructions. Some of these are more extended than others. For example, load from a memory location is, in fact
| 03 | LD_REG24 | LDA [X:Y] | Load register from memory location using [low_byte:word] | |
| 04 | LD_IMM24 | LDA [$1:$C000] | Load byte from memory location [bank:addr] | |
| 07 | ST_REG24 | STA [X:Y] | Store A in memory using [low_byte:word] registers. | |
| 08 | ST_IMM24 | STA [$0:$A0] | Store register in memory location [bank:addr] | |
| 0A | XCHG | XCHG X, Y | Swap dem two – X an Y trade place, quick quick | |
| 0D | PUSHA | PUSHA | Save all registers in ye treasure chest | |
| 0E | POPA | POPA | Get the registers back |
ST_PD 25 // pre-dec store. STA [-, BLX] LD_FS 26 // load+forward step. LDA [BLX, +] ST_FS 27 // store+forward step. STA [BLX, +]
| 23 | ADD_REG_IMM | ADD X, $1234 | Add immediate word value; X = X + immediate | |
| 24 | SUB_REG_IMM | SUB X, $ABCD | Subtract immediate; X = X - immediate | |
| 25 | MUL_REG_IMM | MUL X, $100 | Multiply by immediate; X:Y = X * immediate | |
| 26 | DIV_REG_IMM | DIV X, $10 | Divide by immediate; X = quotient, Y = remainder | |
| 27 | MOD_REG_IMM | MOD X, $FF | Modulo by immediate; X = X % immediate | |
| 28 | ADDC | ADDC X, Y | Add with carry; X = X + Y + carry flag | |
| 29 | SUBC | SUBC X, Y | Subtract with borrow; X = X - Y - borrow | |
| 30 | ADDC_REG_IMM | ADDC X, $5 | Add imm w/carry; X = X + imm + carry | |
| 31 | SUBC_REG_IMM | SUBC X, $1 | Subtract w/carry X = X - imm - borrow | |
| 36 | TEST | TEST dst, src | Non-destructive AND | |
| 37 | AND_IMM | AND dst, imm | Bitwise AND with immediate | |
| 38 | OR_IMM | OR dst, imm | Bitwise OR with immediate | |
| 48 | SHLC | SHLC A | Shift left | Z, N, C |
| 49 | SHRC | SHRC A | Shift right | Z, N, C |
| 4A | ROL | ROL A | Rotate left | Z, N, C |
| 4B | ROR | ROR A | Rotate right | Z, N, C |
| 4C | ROLC | ROLC A | Rotate left | Z, N, C |
| 4D | RORC | RORC A | Rotate right | Z, N, C |
| A0 | SEZ | SEZ | Set zero flag | Z |
| A1 | SEN | SEN | Set negative flag | N |
| A2 | SEC | SEC | Set carry flag | C |
| A3 | SEV | SEV | Set overflow flag | V |
| A4 | SEE | SEE | Set Extra Flag (User flag) | E |
| A5 | SEF | SEF | Set Free Flag (User flag) | F |
| A6 | SEB | SEB | Set Bonus Flag (User flag) | B |
| A7 | SEU | Set User Flag (User flag) | U | |
| A8 | SED | Set Debug Flag | D | |
| A9 | SEI | Set Enable Interrupt | I | |
| AA | SSI | Enable Sound System Interrupts | S | |
| AB | CLZ | Clear zero flag | Z | |
| AC | CLN | Clear negative flag | N | |
| AD | CLC | Clear carry flag | C | |
| AE | CLV | Clear overflow flag | V | |
| AF | CLE | CLE | Clear E | E |
| B0 | CLF | CLF | Clear F Flag (user flag) | F |
| B1 | CLB | B | ||
| B2 | CLU | U | ||
| B3 | CLD | D | ||
| B4 | CLI | CLI | Clear Interrupt Flag | I |
| B5 | CSI | CSI | Clear Sound Interrupt | S |
LD_IDXI 210 // indexed immediate: LDreg, [ptr + imm] signed byte immediate, -128 to +127 LD_IDXR 211 // indexed register: LDreg, [ptr + reg] register offset ST_IDXI 212 // ST [ptr + imm], reg ST_IDXR 213 // ST [ptr + reg], reg
| FB | BASIC | Reserved | |
| FC | YIELD | Yield thread priority | Y |
| FD | BREAK | Reserved | |
| FE | NOP | No operation | |
| FF | HALT | Halt CPU (sets HALT flag) | H |
CISC instruction set
7 instructions. CISC style, usually inspired by VAX, 680×0, or other CISC-leaning processors.
| 8C | MEMCOPY | MEMCOPY src, dst, n | Copy memory from ptr to ptr. | |
| 8D | SCAN | SCAN src, reg | Scan ptr src for needle reg | |
| 8E | CMPC3 | CMPC3 ELM, FLD, C | Compare Characters | Z C |
| 8F | SKPC | SKPC ELM, AL | Skip characters | |
| 90 | SKPC_IMM | SKPC ELM, $20 | Skip characters (immediate) | |
| 98 | PAB | PAB | Pack low 4 bytes of A and low 4 bytes of B into AL | |
| 99 | UAB | UAB | Unpack AL into low 4 bytes of AL and low 4 bytes of BL |
| C8 | CASE | CASE AL | Jumptable instruction. Will CALL the address in IP+(reg*3) |
| C9 | CASE3 | CASE3 ELM, AL, AH | VAX-style case. takes base, selector, limit. |
| CA | CASEB | CASEB ELM, AL, AH | case-on-byte. takes base, selector, numrec. |
| CB | CVTAN | CVTAN AL | Zone converter ASCII 0-Z to Number) |
| CC | CVTNA | CVNAT AL | Zone converter 0-35 to ASCII '0' to 'Z' |
Dictionary
here you will find information about each opcode.
$A0 SEZ
$A1 SEN
$A2 SEC
$A3 SEV
Sets the main CPU flags zero flag, negative flag, carry flag and overflow flag. If you are absolutely sure no intervening operations set these flags you can use them. For example, carry is unaffected by POP and MOV so it is used to return error or clear from some interrupts and routines. EX. JC @error.
$A4 SEE
Sets Exception flag. The execption flag is sometimes used by interrupts or the system to indicate an error, but in the absence of anything weird you can use it yourself. Consider it an 'Extra' flag.
$A5 SEF
Sets F flag. The “Flag” flag. It's flag. The 'free' flag? Used for 'First-statement' in BASIC. Considered safe for machine language programmer use.
$A6 SEB
Sets B flag. The alternate flag. 'bonus' flag? Used for BREAK in BASIC. Considered safe for machine language programmer use.
$A7 SEU
Sets USER flag. User-facing flag, not used by the system. Considered reserved for programmer use.
$A8 SED
Sets debug. Prints trace messages when on. Slows system down a lot. Trace messages may be removed in some versions.
$A9 SEI
Enables or turns off interrupts. If off, INT won't fire. Probably useless.
$AA SSI
Sets the Sound Interrupt flag. Currently managed by the KERNAL, not really important for users. Probably useless and might be removed later. Considered 'semi-reserved'.
#140 $8C MEMCOPY src, dst, reg
Copies bytes in reg from src to dst. Handles over-writes. Very fast MMU operation. Useful for copying strings if you know the length; int12_strcpy is a tight LDA/STA/JNZ loop, but this is just one opcode.
#141 $8D SCAN ELM, reg
Scan the bytes starting at ELM for the bytes in register reg. If register is 8-bit it will search for a byte. If it's a word, it will search for the word. Can be used to find targets for further keyword matching, as it can very quickly find a sequence of 1, 2, 3 or 4 bytes in memory. Can be used to calculate string length; scan for zero and compare pointer to string start.
#142 $8E CMPC3 ELM, FLD, C
Non-zero byte compare. Useful for comparing strings. Scan up to C characters. The total number of characters scanned will be returned in C. So, C will point to either the first matching character, or will contain the string length. Sets ZERO on a match. If zero is not set, they don't match and Carry indicates if the STRCMP is -1 (not set) or +1 (set).
#143 $8F SKPC ELM, reg
Anti-scan. Scans until the character/word/etc. is not found. If a word width or wider register is used, will skip by needle width. Ends with ELM pointing to the first non-matching character. Most of the time this is used to skip spaces: SKPC ELM, $20 ; skip spaces, ELM points after last space.
#153 $99 PAB
Pack the low 4 bits of AL and BL into AL. This is useful for BCD and 4bpp video mode.
Start: [ AL ][ BL ]
[....llll][....hhhh]
End: [ AL ][ BL ]
[hhhhllll][....hhhh]
#153 $99 UAB
Unpack the 8 bits in AL into AL and BL and zeroes the four high bits of AL and BL. This is useful for BCD and 4bpp video mode.
Start: [ AL ][ BL ]
[hhhhllll][........]
End: [ AL ][ BL ]
[0000llll][0000hhhh]
#200 $C8 CASE selector, #limit
switch-case. Index an address from selector and CALL to it. Limit is an immediate value (0-255) that represents the length of the table. If selector > limit it will silently fall-through (not CALL). If you need to detect whether or not the CALL occurred it is suggested that the handlers produce an error code (the 'default' of which is that no handler was called). Table format: [addr][addr][addr]…
#201 $C9 CASE3 base, selector, limit
switch-case. Index an address from the table at base and CALL to it. Otherwise works like CASE, falling through whether or not the CALL occurred. Table format: [addr][addr][addr]…
#202 $CA CASEB base, selector, limit
switch-case-on-byte. Index an address from the table at base and jump to it. Works like CASE3 except that limit is not checked and the records are scanned instead of computed. This means you do not need to have a complete set of indexes to the table. Table format: [selector][addr][selector][addr][selector][addr]…
#203 $CB CVTAN reg8
Convert ASCII to number. Will convert ASCII characters in the range '0-Z' into the numbers 0-35. Overflow is set if it is not a digit (0-9), and carry will be set if it is not a hexidecimal digit (0-15). This is also a fast way to test if something is a number; MOV reg8, AL and CVTAN reg8 can test for digits with JO/JNO (JV/JNV). This instruction is designed to work with zoned decimal but can also work with zoned hexidecimal (this essentially means numbers in strings).
#204 $CC CVTNA reg8
Convert number to ASCII. Will convert the number 0 to 35 in a register to the ASCII characters '0' to 'Z'. Overflow is set if it is not a digit (0-9) and Carry is set if it is not a hexidecimal (0-F). This is the inverse of CVTAN. This instruction is designed to work with zoned decimal but can also work with zoned hexidecimal (this essentially means numbers in strings).
