The Þog of 2023-03-07 — Another Fantasy ISA
This is another yet-unnamed fantasy CPU instruction set inspired by RISC-V, MIPS, and Professor Bruce Jacob's RiSC-16. It has fixed-length 16 bit instructions, 7 general purpose registers, and a zero register.
Instruction Encoding
The eight registers directly available contain 16 bit, two's-compliment integers. The zero register always returns 0, and all writes to it are ignored. Whether an instruction's immediate value is interpreted as signed or unsigned depends on the opcode.
A fault will be triggered if the program counter or a SW/LW is not word-aligned.
RRR Encoding
F E D C B A 9 8 7 6 5 4 3 2 1 0 Bit
├───┼───────────┼───────────┼───────────┼───────────────────┤
│ 0 │ rs2 │ rs1 │ rd │ opcode │ RRR Type
└───┴───────────┴───────────┴───────────┴───────────────────┘
RRI Encoding
F E D C B A 9 8 7 6 5 4 3 2 1 0 Bit
├───────────────┼───────────┼───────────┼───────────────────┤
│ imm5 │ rs1 │ rd │ opcode │ RRI Type
└───────────────┴───────────┴───────────┴───────────────────┘
RI Encoding
F E D C B A 9 8 7 6 5 4 3 2 1 0 Bit
├───────────────────────────┼───────────┼───────────────────┤
│ imm8 │ rd │ opcode │ RI Type
└───────────────────────────┴───────────┴───────────────────┘
Opcodes
Arithmetic operations
┌─────┬──┬───┬─────┐
│00000│00│RRR│ ADD│ rd := rs1 + rs2
├─────┼──┼───┼─────┤
│00001│01│RRR│ SUB│ rd := rs1 - rs2
├─────┼──┼───┼─────┤
│00010│02│RRR│ SLL│ rd := rs1 << rs2
├─────┼──┼───┼─────┤
│00011│03│RRR│ SRL│ rd := rs1 >>> rs2
├─────┼──┼───┼─────┤
│00100│04│RRR│ SRA│ rd := rs1 >> rs2
├─────┼──┼───┼─────┤
│00101│05│RRI│ ADI│ rd := rs1 + (signed)imm5
├─────┼──┼───┼─────┤
│00110│06│RI │ LUI│ rd := imm8 << 8
├─────┼──┼───┼─────┤
│00111│07│RI │ LLI│ rd := (rd & 0xFF00) | imm8
└─────┴──┴───┴─────┘
Memory operations
┌─────┬──┬───┬─────┐
│01000│08│RRI│ SW│ *(u16)(rd + imm5) := rs1
├─────┼──┼───┼─────┤
│01001│09│RRI│ LW│ rd := *(u16)(rs1 + imm5)
├─────┼──┼───┼─────┤
│01010│0A│RRI│ SB│ *(u8)(rd + imm5) := rs1 & 0xFF
├─────┼──┼───┼─────┤
│01011│0B│RRI│ LB│ rd := *(i8)(rs1 + imm5)
├─────┼──┼───┼─────┤
│01100│0C│RRI│ LBU│ rd := *(u8)(rs1 + imm5)
├─────┼──┼───┼─────┤
│01101│0D│ │ │
│01110│0E│ │ │ Reserved
│01111│0F│ │ │
└─────┴──┴───┴─────┘
Bit operations
┌─────┬──┬───┬─────┐
│10000│10│RRR│ AND│ rd := rs1 & rs2
├─────┼──┼───┼─────┤
│10001│11│RRR│ OR│ rd := rs1 | rs2
├─────┼──┼───┼─────┤
│10010│12│RRR│ XOR│ rd := rs1 ^ rs2
└─────┴──┴───┴─────┘
Comparison operations
┌─────┬──┬───┬─────┐
│10011│13│RRR│ EQ│ rd := rs1 == rs2
├─────┼──┼───┼─────┤
│10100│14│RRR│ GT│ rd := (signed)rs1 > (signed)rs2
├─────┼──┼───┼─────┤
│10101│15│RRR│ GE│ rd := (signed)rs1 >= (signed)rs2
├─────┼──┼───┼─────┤
│10110│16│RRR│ GTU│ rd := (unsigned)rs1 > (unsigned)rs2
├─────┼──┼───┼─────┤
│10111│17│RRR│ GEU│ rd := (unsigned)rs1 >= (unsigned)rs2
└─────┴──┴───┴─────┘
Jump operations
┌─────┬──┬───┬─────┐
│11000│18│RRR│ JLR│ rd := pc + 2; pc := rs1 + (signed)rs2
├─────┼──┼───┼─────┤
│11001│19│RI │ BNS│ if rd == 0 then pc := pc + (signed)(imm8 * 2)
├─────┼──┼───┼─────┤
│11010│1A│RI │ BS│ if rd != 0 then pc := pc + (signed)(imm8 * 2)
├─────┼──┼───┼─────┤
│11011│1B│ │ │ Reserved
└─────┴──┴───┴─────┘
Special operations
┌─────┬──┬───┬─────┐
│11100│1C│RI │ SF│ csr[imm8] := rd
├─────┼──┼───┼─────┤
│11101│1D│RI │ LF│ rd := csr[imm8]
├─────┼──┼───┼─────┤
│11110│1E│RI │ SYC│ System call
├─────┼──┼───┼─────┤
│11111│1F│RI │ BRK│ Break to debugger/environment
└─────┴──┴───┴─────┘
Assembler Syntax
Example assembler program
; routine that prints 'hello, world\n' to an imaginary uart
.org $0100
Start:
li r1, Hello
add r2, r0, 13
add r3, r0, 4 ; the imaginary uart's address
@Loop:
lbu r4, r1, 0
sb r1, r4, 0
adi r1, r1, 1
adi r2, r2, -1
eq r4, r2, r0
bns r4, @Loop
brk $00
.org $0200
Hello:
.ascii "hello, world"
.byte $0a
Pseudo-ops and their expansions
┌───┬───────────────────┐
│nop│ add r0, r0, r0│
├───┼───────────────────┤
│not│ sub A, B, r0│
├───┼───────────────────┤
│li │lui A, IMM & 0xFF00│
│ │lli A, IMM & 0x00FF│
└───┴───────────────────┘