As of 2023-07-05, this document is unfinished!
Support for unaligned loads and stores is implementation-defined.
The byte order is little-endian for the file format, instructions, and data values.
Instruction and data memory are in separate spaces. Only the data memory is read-write accessible to the ISA. Instruction space pointers are only word-addressable, data space is octet-addressable.
struct HeaderSymbol { offset: uint32, // the instruction word this symbol // points to, must not be zero name: [uint8; 60], // zero-padded string } struct Header { magic: [uint8; 4] = "Plg\x00", data_len: uint32, // must be a multiple of 16 bss_len: uint32, // ditto, bss space is appended to the end // of data space but is not stored in the file text_count: uint32, // length in 32 bit words, not bytes sym_count: uint32, // what pc will be set to at startup for in-vm initialization // if zero, the 0th instruction word must be 'eret' reset_vector: uint32, // 40 free bytes for implementations to use userdata: [uint8; 40], // symbols for the host to call plugin functions syms: [HeaderSymbol; sym_count], // these two sections are separate in the ISA, // data being general purpose read-write space, // and text being host-read-only instruction memory data: [uint8; data_len], text: [uint32; text_count], }
There are 32 general purpose 32-bit integer registers. Writes to the zero register are ignored, and reading from it always returns zero.
Floating-point operations share the 32 integer registers.
All instructions are a fixed 32 bits in length, with 128 available opcodes.
Immediate fields must be zero if an instruction does not use them.
31 22 17 12 07 04 00 Bit ├───────┼─────┼─────┼─────┼───────┼───────┤ │ imm10 │ rs2 │ rs1 │ rd │ opc │ opf │ └───────┴─────┴─────┴─────┴───────┴───────┘
31 17 12 07 04 00 Bit ├─────────────┼─────┼─────┼───────┼───────┤ │ imm15 │ rs1 │ rd │ opc │ opf │ └─────────────┴─────┴─────┴───────┴───────┘
31 12 07 03 00 Bit ├───────────────────┼─────┼───────┼───────┤ │ imm20 │ rd │ opc │ opf │ └───────────────────┴─────┴───────┴───────┘
Instructions either listed as 'reserved' or not listed at all should cause an invalid instruction exception.
An instruction field must be zero if the instruction does not use it.
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 00 │ 00 │ break │ Debugger breakpoint │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 00 │ 01 │ eret │ Halt execution and return to host │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 00 │ 02 │ ecall │ Call host function (imm15) │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 00 │ │ Reserved │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 01 │ sw │ Store 32b word (rd) to (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 02 │ sh │ Store 16b short (rd) to (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 03 │ sb │ Store 8b byte (rd) to (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 04 │ │ Reserved │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 05 │ lw │ Load s-ext 32b word (rd) from (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 06 │ lh │ Load s-ext 16b short (rd) from (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 07 │ lb │ Load s-ext 8b byte (rd) from (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 08 │ │ Reserved │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 09 │ lhu │ Load z-ext 16b short (rd) from (rs1 + imm15) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 01 │ 0A │ lbu │ Load z-ext 8b byte (rd) from (rs1 + imm15) │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 00 │ addi │ rd := rs1 + (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 01 │ subi │ rd := rs1 - (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 02 │ andi │ rd := rs1 & (imm15 s-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 03 │ xori │ rd := rs1 ^ (imm15 s-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 04 │ ori │ rd := rs1 | (imm15 s-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 05 │ slli │ rd := rs1 << (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 06 │ srli │ rd := rs1 z-ext>> (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 07 │ srai │ rd := rs1 s-ext>> (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 08 │ muli │ rd := rs1 * (imm15 s-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 09 │ divi │ rd := rs1 /trunc (imm15 s-ext) (0 illegal) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0A │ remi │ rd := rs1 %trunc (imm15 s-ext) (0 illegal) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0B │ icf │ rd := (float)rs1 truncated to int32 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0C │ fci │ rd := rs1 converted to float │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0D │roundf │ rd := round((float)rs1) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0E │ ceilf │ rd := ceil((float)rs1) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 02 │ 0F │floorf │ rd := floor((float)rs1) │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 00 │ add │ rd := rs1 + rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 01 │ sub │ rd := rs1 - rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 02 │ and │ rd := rs1 & rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 03 │ xor │ rd := rs1 ^ rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 04 │ or │ rd := rs1 | rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 05 │ sll │ rd := rs1 << rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 06 │ srl │ rd := rs1 z-ext>> rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 07 │ sra │ rd := rs1 s-ext>> rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 08 │ mul │ rd := rs1 * rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 09 │ div │ rd := rs1 /trunc rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0A │ rem │ rd := rs1 %trunc rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0B │ addf │ rd := (float)rs1 + (float)rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0C │ subf │ rd := (float)rs1 - (float)rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0D │ mulf │ rd := (float)rs1 * (float)rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0E │ divf │ rd := (float)rs1 / (float)rs2 │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 03 │ 0F │ sqrtf │ rd := sqrt((float)rs1) │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 00 │ jalr │ rd := pc + 1; pc := rs1 + (imm15 z-ext) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 01 │ beq │ if rs1 == rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 02 │ bne │ if rs1 != rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 03 │ blt │ if rs1 <s rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 04 │ bge │ if rs1 >=s rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 05 │ bltu │ if rs1 <u rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 06 │ bgeu │ if rs1 >=u rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 07 │ bltf │ if rs1 <f rs2 { pc += (imm15 s-ext) } │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 04 │ 08 │ bgef │ if rs1 >=f rs2 { pc += (imm15 s-ext) } │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌────┬────┬───────┬──────────────────────────────────────────────┐ │ opc│ opf│ Name│ Description│ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 05 │ 00 │ lui │ rd := (imm20 << 12) │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 05 │ 01 │ lif │ rd := (imm20 s-ext) converted to float │ ├────┼────┼───────┼──────────────────────────────────────────────┤ │ 05 │ 02 │ jal │ rd := pc + 1; pc = (imm20 z-ext) │ └────┴────┴───────┴──────────────────────────────────────────────┘
┌─────────────────┬──────────────────────────────────────────────┐ │ Example│ Description│ ├─────────────────┼──────────────────────────────────────────────┤ │ nop │ addi zero zero 0 │ ├─────────────────┼──────────────────────────────────────────────┤ │ mv rd rs1 │ addi rd rs1 0 │ ├─────────────────┼──────────────────────────────────────────────┤ │ not rd rs1 │ xori rd rs1 -1 │ ├─────────────────┼──────────────────────────────────────────────┤ │ TODO │ │ └─────────────────┴──────────────────────────────────────────────┘
This ABI is used both for function calls inside the VM and for host-VM syscalls.
┌────┬────┬──────────────────────────────────┬────────┐ │ Rn│Name│ Description│ Saver│ ├────┼────┼──────────────────────────────────┼────────┤ │ 00 │zero│ Always zero │ ---- │ ├────┼────┼──────────────────────────────────┼────────┤ │ 01 │ ra │ Return address │ Caller │ ├────┼────┼──────────────────────────────────┼────────┤ │ 02 │ sp │ Stack pointer │ Callee │ ├────┼────┼──────────────────────────────────┼────────┤ │ 03 │ fp │ Frame pointer │ Callee │ ├────┼────┼──────────────────────────────────┼────────┤ │ 04 │ a0 │ Function arguments/Return values │ Caller │ │ 05 │ a1 │ │ │ │ 06 │ a2 │ │ │ │ 07 │ a3 │ │ │ │ 08 │ a4 │ │ │ │ 09 │ a5 │ │ │ │ 0A │ a6 │ │ │ │ 0B │ a7 │ │ │ ├────┼────┼──────────────────────────────────┼────────┤ │ 0C │ t0 │ Temporary registers │ Caller │ │ 0D │ t1 │ │ │ │ 0E │ t2 │ │ │ │ 0F │ t3 │ │ │ │ 10 │ t4 │ │ │ │ 11 │ t5 │ │ │ │ 12 │ t6 │ │ │ │ 13 │ t7 │ │ │ │ 14 │ t8 │ │ │ │ 15 │ t9 │ │ │ ├────┼────┼──────────────────────────────────┼────────┤ │ 16 │ s0 │ Saved registers │ Callee │ │ 17 │ s1 │ │ │ │ 18 │ s2 │ │ │ │ 19 │ s3 │ │ │ │ 1A │ s4 │ │ │ │ 1B │ s5 │ │ │ │ 1C │ s6 │ │ │ │ 1D │ s7 │ │ │ │ 1E │ s8 │ │ │ │ 1F │ s9 │ │ │ └────┴────┴──────────────────────────────────┴────────┘
┌─────────────┬───────┐ │ C Type Name │ Bytes │ ├─────────────┼───────┤ │ char │ 1 │ ├─────────────┼───────┤ │ short │ 2 │ ├─────────────┼───────┤ │ int │ 4 │ ├─────────────┼───────┤ │ long │ 4 │ ├─────────────┼───────┤ │ long long │ 8 │ ├─────────────┼───────┤ │ void * │ 4 │ ├─────────────┼───────┤ │ float │ 4 │ ├─────────────┼───────┤ │ double │ --- │ The semantics of 'double' and ├─────────────┼───────┤ 'long double' are undefined by this spec. │ long double │ --- │ └─────────────┴───────┘