diff --git a/asm/riscv_assemble.go b/asm/riscv_assemble.go index f95b3db..d073e68 100644 --- a/asm/riscv_assemble.go +++ b/asm/riscv_assemble.go @@ -1532,6 +1532,21 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv csrOp, srcOp = ops[1], ops[0] } rdOp = nil + // The toolchain picks the opcode form from the source's kind: + // CSRW $2, csr assembles as CSRRWI exactly as CSRWI does, and + // the register spellings stay on CSRRW. + if isImmOperand(srcOp) { + csrMnem = map[string]string{ + "CSRS": "CSRRSI", "CSRW": "CSRRWI", "CSRC": "CSRRCI", + "CSRSI": "CSRRSI", "CSRWI": "CSRRWI", "CSRCI": "CSRRCI", + }[mnem] + } else { + csrMnem = map[string]string{ + "CSRS": "CSRRS", "CSRW": "CSRRW", "CSRC": "CSRRC", + "CSRSI": "CSRRSI", "CSRWI": "CSRRWI", "CSRCI": "CSRRCI", + }[mnem] + } + csrEnc = riscvCsrTable[csrMnem] default: // Either src, csr, rd or csr, src, rd: a CSR *name* in the // second operand marks the toolchain's order. @@ -1541,6 +1556,17 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv csrOp, srcOp = ops[1], ops[0] } } + // An immediate source selects the immediate opcode (CSRRW $2, + // c, rd encodes CSRRWI, byte-identical to the explicit form), + // mirroring the toolchain's constant rewrite. + if isImmOperand(srcOp) { + csrMnem = map[string]string{ + "CSRRW": "CSRRWI", "CSRRS": "CSRRSI", "CSRRC": "CSRRCI", + }[csrMnem] + if csrMnem != "" { + csrEnc = riscvCsrTable[csrMnem] + } + } } csr, ok := riscvCSRAddress(csrOp) if !ok && csrFix == 0 {