sd:isa
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| sd:isa [2026/06/16 07:58] – appledog | sd:isa [2026/06/18 04:53] (current) – appledog | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| == ISA Overview | == ISA Overview | ||
| The SD-8516 instruction set is organized into four tiers. Numbering is canonical | The SD-8516 instruction set is organized into four tiers. Numbering is canonical | ||
| - | in decimal (as defined in '' | + | in decimal (as defined in '' |
| * **Tier 1 - Core** behaves like a RISC instruction set: small, orthogonal, and complete on its own. Target this first. Everything above it can be synthesized from the core if you have to. | * **Tier 1 - Core** behaves like a RISC instruction set: small, orthogonal, and complete on its own. Target this first. Everything above it can be synthesized from the core if you have to. | ||
| * **Tier 2 - Extended** are quality-of-life instructions for hand assemblers. '' | * **Tier 2 - Extended** are quality-of-life instructions for hand assemblers. '' | ||
| * **Tier 3 - CISC** are heavier, mostly VAX- and 680x0-flavored instructions: | * **Tier 3 - CISC** are heavier, mostly VAX- and 680x0-flavored instructions: | ||
| - | * **Tier 4 - Acceleration** are instructions added primarily to speed up a specific consumer: the LLVM backend ('' | + | * **Tier 4 - Acceleration** are instructions added primarily to speed up a specific consumer: the LLVM backend ('' |
| A handful of opcodes carry aliases (e.g. '' | A handful of opcodes carry aliases (e.g. '' | ||
| Line 27: | Line 27: | ||
| | 7 | $07 | [[# | | 7 | $07 | [[# | ||
| | 9 | $09 | [[# | | 9 | $09 | [[# | ||
| - | | 11 | $0B | PUSH | PUSH A | Push register onto stack | + | | 11 | $0B | [[#PUSH]] | PUSH A | Push register onto stack |
| - | | 12 | $0C | POP | POP Y | Pop stack into register | + | | 12 | $0C | [[#POP]] | POP Y | Pop stack into register |
| - | | 15 | $0F | PUSHF | PUSHF | Push flags | + | | 15 | $0F | [[#PUSHF]] | PUSHF | Push flags |
| - | | 16 | $10 | POPF | POPF | Pop flags | * | | + | | 16 | $10 | [[#POPF]] | POPF | Pop flags | * | |
| - | | 23 | $17 | INC | INC X | Increment register by 1 (any width) | + | | 23 | $17 | [[#INC]] | INC X | Increment register by 1 (any width) |
| - | | 24 | $18 | DEC | DEC Y | Decrement register by 1 (any width) | + | | 24 | $18 | [[#DEC]] | DEC Y | Decrement register by 1 (any width) |
| - | | 30 | $1E | ADD | ADD X, Y | X = X + Y | + | | 30 | $1E | [[#ADD]] | ADD X, Y | X = X + Y |
| - | | 31 | $1F | SUB | SUB X, Y | X = X - Y | + | | 31 | $1F | [[#SUB]] | SUB X, Y | X = X - Y |
| - | | 50 | $32 | AND | AND dst, src | Bitwise AND | | | + | | 50 | $32 | [[#AND]] | AND dst, src | Bitwise AND | | |
| - | | 51 | $33 | OR | OR dst, src | Bitwise OR | + | | 51 | $33 | [[#OR]] | OR dst, src | Bitwise OR |
| - | | 52 | $34 | XOR | XOR dst, src | Bitwise XOR | | | + | | 52 | $34 | [[#XOR]] | XOR dst, src | Bitwise XOR | | |
| - | | 53 | $35 | NOT | NOT reg | Bitwise NOT (invert all bits) | | | + | | 53 | $35 | [[#NOT]] | NOT reg | Bitwise NOT (invert all bits) | | |
| - | | 70 | $46 | SHL | SHL A | Shift left | Z N C | | + | | 70 | $46 | [[#SHL]] | SHL A | Shift left | Z N C | |
| - | | 71 | $47 | SHR | SHR A | Shift right | Z N C | | + | | 71 | $47 | [[#SHR]] | SHR A | Shift right | Z N C | |
| - | | 90 | $5A | CMP | CMP A, B | Compare (subtract, discard result) | + | | 90 | $5A | [[#CMP]] | CMP A, B | Compare (subtract, discard result) |
| - | | 91 | $5B | CMP_IMM | + | | 91 | $5B | [[#CMP_IMM]] | CMP A, $1 | Compare against immediate |
| - | | 100 | $64 | JMP | JMP @label | + | | 100 | $64 | [[#JMP]] | JMP @label |
| - | | 101 | $65 | JZ | JZ @label | + | | 101 | $65 | [[#JZ]] | JZ @label |
| - | | 102 | $66 | JNZ | JNZ @label | + | | 102 | $66 | [[#JNZ]] | JNZ @label |
| - | | 105 | $69 | JC | JC @label | + | | 105 | $69 | [[#JC]] | JC @label |
| - | | 106 | $6A | JNC | JNC @label | + | | 106 | $6A | [[#JNC]] | JNC @label |
| | 130 | $82 | [[# | | 130 | $82 | [[# | ||
| - | | 133 | $85 | RET | RET | Return from subroutine (pop IP) | | | + | | 133 | $85 | [[#RET]] | RET | Return from subroutine (pop IP) | | |
| - | | 134 | $86 | INT | INT $10 | Software interrupt | + | | 134 | $86 | [[#INT]] | INT $10 | Software interrupt |
| - | | 135 | $87 | RTI | RTI | Return from interrupt | + | | 135 | $87 | [[#RTI]] | RTI | Return from interrupt |
| - | | 182 | $B6 | SETF | SETF $80 | Set bits in the flags register | + | | 182 | $B6 | [[#SETF]] | SETF $80 | Set bits in the flags register |
| - | | 183 | $B7 | CLRF | CLRF $80 | Clear bits in the flags register | + | | 183 | $B7 | [[#CLRF]] | CLRF $80 | Clear bits in the flags register |
| - | | 184 | $B8 | TESTF | TESTF $80 | Non-destructive AND against flags | Z C | | + | | 184 | $B8 | [[#TESTF]] | TESTF $80 | Non-destructive AND against flags | Z C | |
| - | | 254 | $FE | NOP | NOP | No operation | + | | 254 | $FE | [[#NOP]] | NOP | No operation |
| - | | 255 | $FF | HALT | HALT | Halt CPU (sets HALT flag) | | | + | | 255 | $FF | [[#HALT]] | HALT | Halt CPU (sets HALT flag) | | |
| + | |||
| + | Although this is intended as a RISC core, there are some extras here, primarily LD-8bit hot path, which is done to speed up execution of 8 bit loads by about 30%. Additionally, | ||
| + | |||
| + | POPF however, is a strong canidate for removal. It would really only be needed for a kind of protected mode, interrupt mode or kernal mode, and we dont use it currently. | ||
| + | |||
| + | Finally, it may be interesting to fuse CMP and JZ. Imagine, any CMP and conditional jump could be a CJMP. ex. '' | ||
| + | |||
| + | Consider: | ||
| + | * No CMP exists in isolation | ||
| + | * No JZ exists without responding to a change in the Z flag. | ||
| + | * CJZ A, A can test for zero after a load if we really need one. | ||
| + | |||
| + | Further investigate: | ||
| + | * Does the cost of flag calculation outweight dispatch for how often a CMP occurrs? | ||
| === Tier 2: Extended (Quality of Life) | === Tier 2: Extended (Quality of Life) | ||
| Line 164: | Line 178: | ||
| === Tier 4: Acceleration (LLVM / Forth / Hardware) | === Tier 4: Acceleration (LLVM / Forth / Hardware) | ||
| - | Instructions added to remove work from a specific hot path rather than to add | + | Instructions added to remove work from a specific hot path rather than to add expressiveness. Each one has a primary consumer noted below. |
| - | expressiveness. Each one has a primary consumer noted below. | + | |
| + | Canidates for inclusion: LEA, fused CMP-Bcc and CMP-Jcc, conditional move, LD_IDX16 | ||
| | # | hex | Mnemonic | Example | | # | hex | Mnemonic | Example | ||
| Line 196: | Line 211: | ||
| from the tables above. | from the tables above. | ||
| - | <wrap #ld /> | + | <wrap #ld_imm |
| - | **'' | + | **'' |
| + | Load register with an immediate | ||
| + | |||
| + | <wrap #ld_mem /> | ||
| + | **''# | ||
| + | Load register from memory | ||
| + | |||
| + | <wrap #ld_reg /> | ||
| + | **''# | ||
| + | Load register from memory (register-indirect | ||
| + | |||
| + | <wrap #ld_imm8 /> | ||
| + | **'' | ||
| + | Load byte register with an immediate value. '' | ||
| + | |||
| + | <wrap #ld_mem8 /> | ||
| + | **''# | ||
| + | Load byte from memory (absolute). '' | ||
| + | |||
| + | <wrap #ld_reg8 /> | ||
| + | **''# | ||
| + | Load byte from memory (register-indirect). '' | ||
| + | |||
| + | <wrap #st_mem /> | ||
| + | **''# | ||
| + | Store register to memory (absolute). '' | ||
| + | |||
| + | < | ||
| + | **''# | ||
| + | Store register to memory (register-indirect). '' | ||
| <wrap #mov /> | <wrap #mov /> | ||
| **''# | **''# | ||
| - | Register-to-register copy. **MOV requires source and destination of equal width**; | + | Register-to-register copy ex. '' |
| - | this is enforced at assemble time. A move that changes width is not a MOV -- use | + | |
| - | [[# | + | |
| - | than guessing which bytes you meant. | + | |
| - | <wrap #call /> | + | <wrap #push /> |
| - | **''# | + | **''# |
| - | CALL pushes the return address (the instruction after the call) and jumps to the | + | Push register onto stack. '' |
| - | target. CALLR takes a register | + | |
| - | 8-bit registers combine with the current bank, 24-bit registers give a full | + | <wrap #pop /> |
| - | address, and a 32-bit pair (e.g. AB) is narrowed to 24 bits by discarding the high | + | **'' |
| - | byte. This makes 32-bit register pairs usable as function pointers. | + | Pop stack into register. '' |
| + | |||
| + | <wrap #pushf /> | ||
| + | **''# | ||
| + | Push flags register onto stack. | ||
| + | |||
| + | <wrap #popf /> | ||
| + | **''# | ||
| + | Pop stack into flags register. * | ||
| + | |||
| + | <wrap #inc /> | ||
| + | **''# | ||
| + | Increment register by 1 (any width). '' | ||
| + | |||
| + | <wrap #dec /> | ||
| + | **''# | ||
| + | Decrement register by 1 (any width). '' | ||
| <wrap #step /> | <wrap #step /> | ||
| Line 220: | Line 277: | ||
| pointer ('' | pointer ('' | ||
| pointer bookkeeping of a copy loop into the access itself. | pointer bookkeeping of a copy loop into the access itself. | ||
| + | |||
| + | <wrap #mov-x /> | ||
| + | **''# | ||
| + | Move with sign-extend (MOVSX) or zero-extend (MOVZX). The source is read at its own | ||
| + | width and written across the full destination, | ||
| + | source' | ||
| + | wider** than the source; this is checked at assemble time. Both fully define the | ||
| + | destination, | ||
| + | in-place overlapping case ('' | ||
| + | |||
| + | These exist to collapse the compiler' | ||
| + | sign-extend, | ||
| + | ('' | ||
| + | it in one. Integer promotion makes signed widening pervasive in C, so this is a | ||
| + | recurring code-size win. MOVZX similarly drops the masking immediate of an | ||
| + | '' | ||
| + | |||
| + | <wrap #add /> | ||
| + | **''# | ||
| + | Add registers. '' | ||
| + | |||
| + | <wrap #sub /> | ||
| + | **''# | ||
| + | Subtract registers. '' | ||
| + | |||
| + | <wrap #and /> | ||
| + | **''# | ||
| + | Bitwise AND. '' | ||
| + | |||
| + | <wrap #or /> | ||
| + | **''# | ||
| + | Bitwise OR. '' | ||
| + | |||
| + | <wrap #xor /> | ||
| + | **''# | ||
| + | Bitwise XOR. '' | ||
| + | |||
| + | <wrap #not /> | ||
| + | **''# | ||
| + | Bitwise NOT (invert all bits). '' | ||
| + | |||
| + | <wrap #shl /> | ||
| + | **''# | ||
| + | Shift left. '' | ||
| + | |||
| + | <wrap #shr /> | ||
| + | **''# | ||
| + | Shift right (logical). '' | ||
| <wrap #shx /> | <wrap #shx /> | ||
| Line 227: | Line 332: | ||
| the current emulator handler before relying on this entry.// | the current emulator handler before relying on this entry.// | ||
| - | <wrap #branch | + | <wrap #cmp /> |
| - | **''# | + | **''# |
| - | Two-byte relative branches with a signed 8-bit displacement | + | Compare registers |
| - | the instruction). They mirror the absolute jumps but encode shorter and stay | + | |
| - | position-independent, | + | |
| - | BNC/BNAE are aliases. For targets outside +/-127, use the absolute jumps. | + | |
| - | <wrap #setflag | + | <wrap #cmp_imm |
| - | **''# | + | **''# |
| - | Set the zero, negative, carry, and overflow flags respectively. Useful when you are | + | Compare register against immediate. '' |
| - | certain no intervening operation disturbs the flag -- for example, carry survives | + | |
| - | POP and MOV, so it is a common error/clear channel out of a routine ('' | + | |
| - | <wrap #see /> | + | <wrap #jmp /> |
| - | **''# | + | **''# |
| - | system to signal an error, but free for your own use otherwise. Think of it as an | + | Unconditional jump. '' |
| - | " | + | |
| - | <wrap #sef /> | + | <wrap #jz /> |
| - | **''# | + | **''# |
| - | otherwise safe for machine-language use. | + | Jump if zero. '' |
| - | <wrap #seb /> | + | <wrap #jnz /> |
| - | **''# | + | **''# |
| - | safe for machine-language use. | + | Jump if not zero. '' |
| - | <wrap #seu /> | + | <wrap #jc /> |
| - | **''# | + | **''# |
| - | programmer. | + | Jump if carry set (alias JAE for unsigned {{{> |
| - | <wrap #sed /> | + | <wrap #jnc /> |
| - | **''# | + | **''# |
| - | considerably. Trace output may be compiled out in some builds. | + | Jump if carry clear (alias JNAE for unsigned <). '' |
| - | <wrap #sei /> | + | <wrap #call /> |
| - | **''# | + | **''# |
| - | fire. | + | CALL pushes the return address (the instruction after the call) and jumps to the |
| + | target. CALLR takes a register operand and dispatches on its width: 16-bit and | ||
| + | 8-bit registers combine with the current bank, 24-bit registers give a full | ||
| + | address, and a 32-bit pair (e.g. AB) is narrowed to 24 bits by discarding the high | ||
| + | byte. This makes 32-bit register pairs usable as function pointers. | ||
| - | <wrap #ssi /> | + | <wrap #branch |
| - | **''# | + | **''# |
| - | semi-reserved | + | Two-byte relative branches with a signed 8-bit displacement (range -128..+127 from |
| + | the instruction). They mirror | ||
| + | position-independent, | ||
| + | BNC/BNAE are aliases. For targets outside +/-127, use the absolute jumps. | ||
| <wrap #memcopy /> | <wrap #memcopy /> | ||
| Line 283: | Line 389: | ||
| <wrap #cmpc /> | <wrap #cmpc /> | ||
| **''# | **''# | ||
| - | Non-zero byte compare, useful for strings. Compares up to C characters; C returns | + | Non-zero byte compare, useful for strings. Compares up to C characters; C returns either the index of the first mismatch or the matched length. Sets ZERO on a full match; otherwise CARRY distinguishes the -1 / +1 ordering. |
| - | either the index of the first mismatch or the matched length. Sets ZERO on a full | + | |
| - | match; otherwise CARRY distinguishes the -1 / +1 ordering. | + | |
| - | CMPC allows early termination when '' | + | CMPC allows early termination when '' |
| - | semantics. If both strings reach a terminator at the same position with all prior | + | |
| - | bytes equal, the loop exits matched (Z=1, C=1). Only '' | + | |
| - | that point '' | + | |
| - | '' | + | |
| - | null-terminated strcmp in one instruction. | + | |
| <wrap #skpc /> | <wrap #skpc /> | ||
| Line 324: | Line 423: | ||
| you write CRUD for a struct); the register form exists so generic kernel queue | you write CRUD for a struct); the register form exists so generic kernel queue | ||
| helpers can take "field offset" | helpers can take "field offset" | ||
| + | |||
| + | <wrap #setflag /> | ||
| + | **''# | ||
| + | Set the zero, negative, carry, and overflow flags respectively. Useful when you are | ||
| + | certain no intervening operation disturbs the flag -- for example, carry survives | ||
| + | POP and MOV, so it is a common error/clear channel out of a routine ('' | ||
| + | |||
| + | <wrap #see /> | ||
| + | **''# | ||
| + | system to signal an error, but free for your own use otherwise. Think of it as an | ||
| + | " | ||
| + | |||
| + | <wrap #sef /> | ||
| + | **''# | ||
| + | otherwise safe for machine-language use. | ||
| + | |||
| + | <wrap #seb /> | ||
| + | **''# | ||
| + | safe for machine-language use. | ||
| + | |||
| + | <wrap #seu /> | ||
| + | **''# | ||
| + | programmer. | ||
| + | |||
| + | <wrap #sed /> | ||
| + | **''# | ||
| + | considerably. Trace output may be compiled out in some builds. | ||
| + | |||
| + | <wrap #sei /> | ||
| + | **''# | ||
| + | fire. | ||
| + | |||
| + | <wrap #ssi /> | ||
| + | **''# | ||
| + | semi-reserved and may be removed. | ||
| <wrap #case /> | <wrap #case /> | ||
| Line 353: | Line 487: | ||
| <wrap #casetab /> | <wrap #casetab /> | ||
| **''# | **''# | ||
| - | Jump table held at a base address rather than inline. Indexes an address from the | + | Jump table held at a base address rather than inline. Indexes an address from the table at '' |
| - | table at '' | + | |
| - | //The precise indexing and out-of-bounds policy should be confirmed against the | + | |
| - | current emulator handler: the older CASE3 (computed table at base) and CASEB | + | |
| - | (scanned '' | + | |
| - | table-at-base form.// | + | |
| <wrap #cvtan /> | <wrap #cvtan /> | ||
| **''# | **''# | ||
| - | Convert ASCII to number. Maps ' | + | Convert ASCII to number. Maps ' |
| - | a decimal digit (0-9) and Carry if it is not a hex digit (0-15). Also a fast digit | + | |
| - | test: '' | + | |
| - | Designed for zoned decimal, and works for zoned hex. | + | |
| <wrap #cvtna /> | <wrap #cvtna /> | ||
| Line 371: | Line 497: | ||
| Convert number to ASCII, the inverse of CVTAN. Maps 0-35 to ' | Convert number to ASCII, the inverse of CVTAN. Maps 0-35 to ' | ||
| if outside 0-9 and Carry if outside 0-15. | if outside 0-9 and Carry if outside 0-15. | ||
| - | |||
| - | <wrap #movx /> | ||
| - | **''# | ||
| - | Move with sign-extend (MOVSX) or zero-extend (MOVZX). The source is read at its own | ||
| - | width and written across the full destination, | ||
| - | source' | ||
| - | wider** than the source; this is checked at assemble time. Both fully define the | ||
| - | destination, | ||
| - | in-place overlapping case ('' | ||
| - | |||
| - | These exist to collapse the compiler' | ||
| - | sign-extend, | ||
| - | ('' | ||
| - | it in one. Integer promotion makes signed widening pervasive in C, so this is a | ||
| - | recurring code-size win. MOVZX similarly drops the masking immediate of an | ||
| - | '' | ||
| <wrap #idx /> | <wrap #idx /> | ||
| - | **''# | + | **''# |
| - | Indexed load/store: a 24-bit pointer register plus a displacement. The '' | + | |
| - | take a signed byte immediate (-128..+127); | + | |
| - | These back the compiler' | + | |
| - | pointer base must be a 24-bit register; the effective address reads the base at its | + | |
| true width before applying the offset. | true width before applying the offset. | ||
| Line 411: | Line 517: | ||
| <codify armasm> | <codify armasm> | ||
| - | LDFLX $F000 ; loop start | + | LDFLX $F000 ; |
| - | LDA #1 | + | LDA #1 ; start at 1 |
| - | STA [FLX] | + | STA [FLX] ; write starting counter at first four bytes |
| - | LDA #1000 | + | LDA #1000 ; go until 1000 |
| - | STA [FLX+4] | + | STA [FLX+4] |
| loop: | loop: | ||
| - | LSTEPM | + | LSTEPM |
| JNZ @loop | JNZ @loop | ||
| </ | </ | ||
| - | Unlike a DEC loop it counts upward and supports an arbitrary start. | + | Unlike a DEC loop it counts upward and supports an arbitrary start. |
| - | for Forth and has been generalized by [[# | + | |
| - | LSTEPM | + | Only used by Forth. It is recommended to use LSTEP instead; this instruction |
| <wrap #ttos /> | <wrap #ttos /> | ||
sd/isa.1781596728.txt.gz · Last modified: by appledog
