Kind Pure package
Name v0
Namespace moul / x / vm / riscv
Exported functions n/a — not supported for pure packages by the node (vm/qfuncs)
Module gno.land/p/moul/x/vm/riscv/v0
gno 0.9 decode.gno gno
⧉
1 package riscv 2 3 // RV32 instruction decode: bit fields, not a parser. 4 // 5 // Every instruction is exactly 32 bits and the opcode is the low 7. The rest is 6 // slicing: which fields exist depends on the format, and there are six formats. 7 // This file is only the slicing; exec.gno decides what the fields mean. 8 not supported for pure packages by the node (vm/qfuncs)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
9 // Instruction formats. Named as the spec names them.
10 const (
11 opLUI = 0x37
12 opAUIPC = 0x17
13 opJAL = 0x6F
14 opJALR = 0x67
15 opBranch = 0x63
16 opLoad = 0x03
17 opStore = 0x23
18 opImm = 0x13
19 opReg = 0x33
20 opSystem = 0x73
21 opFence = 0x0F
22 )
23
24 // opcode returns the low 7 bits.
25 func opcode(inst uint32 ) uint32 { return inst & 0x7F }
26
27 // rd, rs1 and rs2 are register selectors, 5 bits each, always in the same place
28 // when the format has them.
29 func rd(inst uint32 ) uint32 { return (inst >> 7 ) & 0x1F }
30 func rs1(inst uint32 ) uint32 { return (inst >> 15 ) & 0x1F }
31 func rs2(inst uint32 ) uint32 { return (inst >> 20 ) & 0x1F }
32
33 // funct3 and funct7 narrow an opcode to an operation.
34 func funct3(inst uint32 ) uint32 { return (inst >> 12 ) & 0x7 }
35 func funct7(inst uint32 ) uint32 { return inst >> 25 }
36
37 // The immediates. Each format scatters the bits differently, and every one of
38 // them is SIGN EXTENDED from its top bit: RISC-V has no zero-extended immediate
39 // in the base set, and getting that wrong is the classic decoder bug because
40 // small positive programs still work.
41 //
42 // The shift-right-on-int32 idiom is the sign extension: Go defines >> on a
43 // signed type as arithmetic.
44
45 // immI is the 12-bit immediate of I-type (loads, ALU-immediate, JALR, ECALL).
46 func immI(inst uint32 ) uint32 { return uint32 ( int32 (inst) >> 20 ) }
47
48 // immS is S-type (stores), split across two fields.
49 func immS(inst uint32 ) uint32 {
50 return uint32 ( int32 (inst)>> 25 << 5 ) | ((inst >> 7 ) & 0x1F )
51 }
52
53 // immB is B-type (branches): S-type with the bits rotated, and bit 0 always
54 // zero because a branch target is 2-byte aligned.
55 func immB(inst uint32 ) uint32 {
56 imm := uint32 ( int32 (inst)>> 31 ) << 12 // sign, bit 12
57 imm |= ((inst >> 7 ) & 0x1 ) << 11 // bit 11
58 imm |= ((inst >> 25 ) & 0x3F ) << 5 // bits 10:5
59 imm |= ((inst >> 8 ) & 0xF ) << 1 // bits 4:1
60 return imm
61 }
62
63 // immU is U-type (LUI, AUIPC): the top 20 bits, already in place.
64 func immU(inst uint32 ) uint32 { return inst & 0xFFFFF000 }
65
66 // immJ is J-type (JAL), the most scattered of the six.
67 func immJ(inst uint32 ) uint32 {
68 imm := uint32 ( int32 (inst)>> 31 ) << 20 // sign, bit 20
69 imm |= ((inst >> 12 ) & 0xFF ) << 12 // bits 19:12
70 imm |= ((inst >> 20 ) & 0x1 ) << 11 // bit 11
71 imm |= ((inst >> 21 ) & 0x3FF ) << 1 // bits 10:1
72 return imm
73 }
74