import (
"cmd/internal/obj"
"cmd/internal/obj/riscv"
+ "fmt"
)
// IsRISCV64AMO reports whether op is an AMO instruction that requires
return op == riscv.AVSETVLI || op == riscv.AVSETIVLI
}
+// IsRISCV64CSRO reports whether the op is an instruction that uses
+// CSR symbolic names and whether that instruction expects a register
+// or an immediate source operand.
+func IsRISCV64CSRO(op obj.As) (imm bool, ok bool) {
+ switch op {
+ case riscv.ACSRRCI, riscv.ACSRRSI, riscv.ACSRRWI:
+ imm = true
+ fallthrough
+ case riscv.ACSRRC, riscv.ACSRRS, riscv.ACSRRW:
+ ok = true
+ }
+ return
+}
+
var riscv64SpecialOperand map[string]riscv.SpecialOperand
// RISCV64SpecialOperand returns the internal representation of a special operand.
if riscv64SpecialOperand == nil {
// Generate mapping when function is first called.
riscv64SpecialOperand = map[string]riscv.SpecialOperand{}
- for opd := riscv.SPOP_BEGIN; opd < riscv.SPOP_END; opd++ {
+ for opd := riscv.SPOP_RVV_BEGIN; opd < riscv.SPOP_RVV_END; opd++ {
riscv64SpecialOperand[opd.String()] = opd
}
+ // Add the CSRs
+ for csrCode, csrName := range riscv.CSRs {
+ // The set of RVV special operand names and the set of CSR special operands
+ // names are disjoint and so can safely share a single namespace. However,
+ // it's possible that a future update to the CSRs in inst.go could introduce
+ // a conflict. This check ensures that such a conflict does not go
+ // unnoticed.
+ if _, ok := riscv64SpecialOperand[csrName]; ok {
+ panic(fmt.Sprintf("riscv64 special operand %q redefined", csrName))
+ }
+ riscv64SpecialOperand[csrName] = riscv.SpecialOperand(int(csrCode) + int(riscv.SPOP_CSR_BEGIN))
+ }
}
if opd, ok := riscv64SpecialOperand[name]; ok {
return opd
prog.RegTo2 = a[2].Reg
break
}
+ // RISCV64 instructions that reference CSRs with symbolic names.
+ if isImm, ok := arch.IsRISCV64CSRO(op); ok {
+ if a[0].Type != obj.TYPE_CONST && isImm {
+ p.errorf("invalid value for first operand to %s instruction, must be a 5 bit unsigned immediate", op)
+ return
+ }
+ if a[1].Type != obj.TYPE_SPECIAL {
+ p.errorf("invalid value for second operand to %s instruction, must be a CSR name", op)
+ return
+ }
+ prog.AddRestSourceArgs([]obj.Addr{a[1]})
+ prog.From = a[0]
+ prog.To = a[2]
+ break
+ }
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
SD X5, (X6) // 23305300
SD X5, 4(X6) // 23325300
+ // 7.1: CSR Instructions
+ CSRRC X0, CYCLE, X5 // f33200c0
+ CSRRC X0, CYCLE, X0 // 733000c0
+ CSRRC X10, CYCLE, X5 // f33205c0
+ CSRRC $2, TIME, X5 // f37211c0
+ CSRRCI $2, TIME, X5 // f37211c0
+ CSRRS X0, CYCLE, X5 // f32200c0
+ CSRRS X0, CYCLE, X0 // 732000c0
+ CSRRS X10, CYCLE, X5 // f32205c0
+ CSRRS $2, TIME, X5 // f36211c0
+ CSRRS X0, VLENB, X5 // f32220c2
+ CSRRSI $2, TIME, X5 // f36211c0
+ CSRRW X0, CYCLE, X5 // f31200c0
+ CSRRW X0, CYCLE, X0 // 731000c0
+ CSRRW X10, CYCLE, X5 // f31205c0
+ CSRRW $2, TIME, X5 // f35211c0
+ CSRRWI $2, TIME, X5 // f35211c0
+
// 8.1: Base Counters and Timers (Zicntr)
RDCYCLE X5 // f32200c0
RDTIME X5 // f32210c0
// license that can be found in the LICENSE file.
TEXT errors(SB),$0
+ CSRRC (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
+ CSRRC X0, TU, X5 // ERROR "unknown CSR"
+ CSRRC X0, CYCLE // ERROR "missing CSR name"
+ CSRRC X0, CYCLE, (X10) // ERROR "needs an integer register output"
+ CSRRC $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRCI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRCI $1, TIME, (X15) // ERROR "needs an integer register output"
+ CSRRS (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
+ CSRRS X0, CYCLE, (X10) // ERROR "needs an integer register output"
+ CSRRS X0, TU, X5 // ERROR "unknown CSR"
+ CSRRS X0, CYCLE // ERROR "missing CSR name"
+ CSRRS $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRSI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRSI $1, TIME, (X15) // ERROR "needs an integer register output"
+ CSRRW (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
+ CSRRW X0, TU, X5 // ERROR "unknown CSR"
+ CSRRW X0, CYCLE // ERROR "missing CSR name"
+ CSRRW X0, CYCLE, (X5) // ERROR "needs an integer register output"
+ CSRRW $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRWI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
+ CSRRWI $1, TIME, (X15) // ERROR "needs an integer register output"
MOV $errors(SB), (X5) // ERROR "address load must target register"
MOV $8(SP), (X5) // ERROR "address load must target register"
MOVB $8(SP), X5 // ERROR "unsupported address load"
//
// <symbolic constant name>
// Special symbolic constants for ARM64 (such as conditional flags, tlbi_op and so on)
-// and RISCV64 (such as names for vector configuration instruction arguments).
+// and RISCV64 (such as names for vector configuration instruction arguments and CSRs).
// Encoding:
// type = TYPE_SPECIAL
// offset = The constant value corresponding to this symbol
"cmd/internal/obj"
)
+var CSRs map[uint16]string = csrs
+
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
const (
const (
SPOP_BEGIN SpecialOperand = obj.SpecialOperandRISCVBase
+ SPOP_RVV_BEGIN
// Vector mask policy.
- SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 1
+ SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 2
SPOP_MU
// Vector tail policy.
SPOP_E16
SPOP_E32
SPOP_E64
+ SPOP_RVV_END
+
+ // CSR names. 4096 special operands are reserved for RISC-V CSR names.
+ SPOP_CSR_BEGIN = SPOP_RVV_END
+ SPOP_CSR_END = SPOP_CSR_BEGIN + 4096
- SPOP_END
+ SPOP_END = SPOP_CSR_END + 1
)
var specialOperands = map[SpecialOperand]struct {
}
func (so SpecialOperand) encode() uint32 {
- op, ok := specialOperands[so]
- if ok {
- return op.encoding
+ switch {
+ case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
+ op, ok := specialOperands[so]
+ if ok {
+ return op.encoding
+ }
+ case so >= SPOP_CSR_BEGIN && so < SPOP_CSR_END:
+ csrNum := uint16(so - SPOP_CSR_BEGIN)
+ if _, ok := csrs[csrNum]; ok {
+ return uint32(csrNum)
+ }
}
return 0
}
+// String returns the textual representation of a SpecialOperand.
func (so SpecialOperand) String() string {
- op, ok := specialOperands[so]
- if ok {
- return op.name
+ switch {
+ case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
+ op, ok := specialOperands[so]
+ if ok {
+ return op.name
+ }
+ case so >= SPOP_CSR_BEGIN && so < SPOP_CSR_END:
+ if csrName, ok := csrs[uint16(so-SPOP_CSR_BEGIN)]; ok {
+ return csrName
+ }
}
return ""
}
}
func specialOperandConv(a int64) string {
+ var s string
+
spc := SpecialOperand(a)
if spc >= SPOP_BEGIN && spc < SPOP_END {
- return spc.String()
+ s = spc.String()
+ }
+ if s == "" {
+ return "SPC_??"
}
- return "SPC_??"
+ return s
}
ASD & obj.AMask: {enc: sIEncoding},
// 7.1: CSR Instructions
- ACSRRS & obj.AMask: {enc: iIIEncoding},
+ ACSRRC & obj.AMask: {enc: iIIEncoding, immForm: ACSRRCI},
+ ACSRRCI & obj.AMask: {enc: iIIEncoding},
+ ACSRRS & obj.AMask: {enc: iIIEncoding, immForm: ACSRRSI},
+ ACSRRSI & obj.AMask: {enc: iIIEncoding},
+ ACSRRW & obj.AMask: {enc: iIIEncoding, immForm: ACSRRWI},
+ ACSRRWI & obj.AMask: {enc: iIIEncoding},
// 13.1: Multiplication Operations
AMUL & obj.AMask: {enc: rIIIEncoding, ternary: true},
ins.imm = -1022
}
+ case ACSRRC, ACSRRCI, ACSRRS, ACSRRSI, ACSRRW, ACSRRWI:
+ if len(p.RestArgs) == 0 || p.RestArgs[0].Type != obj.TYPE_SPECIAL {
+ p.Ctxt.Diag("%v: missing CSR name", p)
+ return nil
+ }
+ if p.From.Type == obj.TYPE_CONST {
+ imm := p.From.Offset
+ if imm < 0 || imm >= 32 {
+ p.Ctxt.Diag("%v: immediate out of range 0 to 31", p)
+ return nil
+ }
+ ins.rs1 = uint32(imm) + REG_ZERO
+ } else if p.From.Type == obj.TYPE_REG {
+ ins.rs1 = uint32(p.From.Reg)
+ } else {
+ p.Ctxt.Diag("%v: integer register or immediate expected for 1st operand", p)
+ return nil
+ }
+ if p.To.Type != obj.TYPE_REG {
+ p.Ctxt.Diag("%v: needs an integer register output", p)
+ return nil
+ }
+ csrNum := SpecialOperand(p.RestArgs[0].Offset).encode()
+ if csrNum >= 1<<12 {
+ p.Ctxt.Diag("%v: unknown CSR", p)
+ return nil
+ }
+ if _, ok := CSRs[uint16(csrNum)]; !ok {
+ p.Ctxt.Diag("%v: unknown CSR", p)
+ return nil
+ }
+ ins.imm = int64(csrNum)
+ if ins.imm > 2047 {
+ ins.imm -= 4096
+ }
+ ins.rs2 = obj.REG_NONE
+
case AFENCE:
ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
ins.imm = 0x0ff