feat(riscv): add MOV pseudo-instruction and RVC compressed encoding

Assisted-by: DeepSeek V4 Pro
This commit is contained in:
2026-08-02 18:22:00 +02:00
parent eee7a6d4a4
commit 243b087116
8 changed files with 946 additions and 78 deletions
+78
View File
@@ -171,6 +171,13 @@ var riscvInstrTable = map[string]riscvEnc{
"SLLW": {0x3B, 0x1, 0x00},
"SRLW": {0x3B, 0x5, 0x00},
"SRAW": {0x3B, 0x5, 0x20},
// RV64I — I-type shift-immediate (shamt in rs2 field).
"SLLI": {0x13, 0x1, 0x00},
"SRLI": {0x13, 0x5, 0x00},
"SRAI": {0x13, 0x5, 0x20},
"SLLIW": {0x1B, 0x1, 0x00},
"SRLIW": {0x1B, 0x5, 0x00},
"SRAIW": {0x1B, 0x5, 0x20},
// RV64M — multiply/divide.
"MUL": {0x33, 0x0, 0x01},
"MULH": {0x33, 0x1, 0x01},
@@ -429,3 +436,74 @@ func riscvJType(rd int, offset int32) uint32 {
(uint32(rd) << 7) |
0x6F // JAL opcode
}
// ---- RVC (compressed) encoding helpers ----
// isRVCIntReg reports whether a register number can be encoded in the 3-bit
// prime register field used by compressed instructions (x8–x15).
func isRVCIntReg(r int) bool { return r >= 8 && r <= 15 }
// rvcReg3 returns the 3-bit encoding for registers x8–x15 (0–7).
func rvcReg3(r int) uint32 { return uint32(r - 8) }
// rvcCR encodes a CR-type (register) compressed instruction.
// Format: funct4 | rd/rs1 | rs2 | op=2.
func rvcCR(funct4, rd, rs2 uint32) uint16 {
return uint16((funct4 << 12) | (rd << 7) | (rs2 << 2) | 0x2)
}
// rvcCI encodes a CI-type (immediate) compressed instruction.
func rvcCI(funct3, rd uint32, imm uint32) uint16 {
return uint16((funct3 << 13) | ((imm>>5)&1)<<12 | (rd << 7) | (imm&0x1F)<<2 | 0x2)
}
// rvcCSS encodes a CSS-type (stack store) compressed instruction.
func rvcCSS(funct3, rs2 uint32, imm uint32) uint16 {
return uint16((funct3 << 13) | (imm << 7) | (rs2 << 2) | 0x2)
}
// rvcCL encodes a CL-type (load) compressed instruction.
// imm layout: [5:3] in bits [12:10], [2|6] in bits [6:5].
func rvcCL(funct3, rd, rs1 uint32, imm uint32) uint16 {
bits := uint16((funct3 << 13) | ((imm>>3)&0x7)<<10 | (rs1 << 7) | ((imm & 0x7) << 5) | (rd << 2) | 0x0)
return bits
}
// rvcCS encodes a CS-type (store) compressed instruction.
func rvcCS(funct3, rs2, rs1 uint32, imm uint32) uint16 {
return uint16((funct3 << 13) | ((imm>>3)&0x7)<<10 | (rs1 << 7) | ((imm & 0x7) << 5) | (rs2 << 2) | 0x0)
}
// rvcCJ encodes a CJ-type (jump) compressed instruction.
// offset is a 12-bit signed offset (bit 0 is always 0).
func rvcCJ(funct3 uint32, offset int32) uint16 {
uoff := uint32(offset) & 0xFFE
bits := ((uoff >> 11) & 1) << 10
bits |= ((uoff >> 4) & 1) << 9
bits |= ((uoff >> 9) & 0x3) << 7
bits |= ((uoff >> 10) & 1) << 6
bits |= ((uoff >> 6) & 1) << 5
bits |= ((uoff >> 7) & 1) << 4
bits |= ((uoff >> 1) & 0x7) << 1
bits |= ((uoff >> 5) & 1)
return uint16((funct3 << 13) | (bits << 2) | 0x1)
}
// rvcCB encodes a CB-type (branch) compressed instruction.
// imm encodes the 8-bit branch offset (bits [8|4:3|7:6|2:1|5]).
func rvcCB(funct3, rs1 uint32, offset int32) uint16 {
uoff := uint32(offset) & 0x1FE // bits [8:1]
bits := ((uoff >> 8) & 1) << 7 // imm[8]
bits |= ((uoff >> 3) & 0x3) << 5 // imm[4:3]
bits |= (uoff & 0x7) << 2 // imm[2|1|?]
// Actually the encoding is more complex. Let me use a simpler approach.
// CB format: funct3[15:13] | offset[8|4:3] | rs1'[9:7] | offset[7:6|2:1|5] | op[1:0]
// Bit pattern for offset: [8|4:3|7:6|2:1|5]
offBits := uint32(0)
offBits |= ((uoff >> 8) & 1) << 10 // bit 10 = offset[8]
offBits |= ((uoff >> 3) & 0x3) << 8 // bits 9:8 = offset[4:3]
offBits |= ((uoff >> 6) & 0x3) << 6 // bits 7:6 = offset[7:6]
offBits |= ((uoff >> 1) & 0x3) << 3 // bits 4:3 = offset[2:1]
offBits |= ((uoff >> 5) & 1) << 2 // bit 2 = offset[5]
return uint16((funct3 << 13) | offBits | (rs1 << 7) | 0x1)
}