mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/asm, cmd/internal/obj: add riscv64 generic CSR ops
Support is added for the generic RISC-V CSR operations; CSRRC, CSRRCI, CSRRS, CSRRSI, CSRRW, CSRRWI. These instructions require special handling as their second operand is a symbolic CSR register name and not an immediate value or a register. CSR names are implemented as special operands. RISC-V CSRs are not currently saved and restored when a go routine is asynchronously pre-empted so it is only safe to use these instructions in hand written assembler. Note that CSRRS was already partially supported by the assembler so this restriction predates this commit. We mention it here as this commit makes CSRRS much easier to use. Change-Id: I9ff8d804328b418a879d463e7d9cc31f489c7a00 Reviewed-on: https://go-review.googlesource.com/c/go/+/630519 Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: Joel Sing <joel@sing.id.au> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
f37d75472d
commit
dd8276657f
8 changed files with 165 additions and 13 deletions
|
|
@ -11,6 +11,7 @@ package arch
|
||||||
import (
|
import (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/internal/obj/riscv"
|
"cmd/internal/obj/riscv"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsRISCV64AMO reports whether op is an AMO instruction that requires
|
// IsRISCV64AMO reports whether op is an AMO instruction that requires
|
||||||
|
|
@ -32,6 +33,20 @@ func IsRISCV64VTypeI(op obj.As) bool {
|
||||||
return op == riscv.AVSETVLI || op == riscv.AVSETIVLI
|
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
|
var riscv64SpecialOperand map[string]riscv.SpecialOperand
|
||||||
|
|
||||||
// RISCV64SpecialOperand returns the internal representation of a special operand.
|
// RISCV64SpecialOperand returns the internal representation of a special operand.
|
||||||
|
|
@ -39,9 +54,21 @@ func RISCV64SpecialOperand(name string) riscv.SpecialOperand {
|
||||||
if riscv64SpecialOperand == nil {
|
if riscv64SpecialOperand == nil {
|
||||||
// Generate mapping when function is first called.
|
// Generate mapping when function is first called.
|
||||||
riscv64SpecialOperand = map[string]riscv.SpecialOperand{}
|
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
|
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 {
|
if opd, ok := riscv64SpecialOperand[name]; ok {
|
||||||
return opd
|
return opd
|
||||||
|
|
|
||||||
|
|
@ -782,6 +782,21 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
prog.RegTo2 = a[2].Reg
|
prog.RegTo2 = a[2].Reg
|
||||||
break
|
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.From = a[0]
|
||||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||||
prog.To = a[2]
|
prog.To = a[2]
|
||||||
|
|
|
||||||
18
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
18
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
|
|
@ -172,6 +172,24 @@ start:
|
||||||
SD X5, (X6) // 23305300
|
SD X5, (X6) // 23305300
|
||||||
SD X5, 4(X6) // 23325300
|
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)
|
// 8.1: Base Counters and Timers (Zicntr)
|
||||||
RDCYCLE X5 // f32200c0
|
RDCYCLE X5 // f32200c0
|
||||||
RDTIME X5 // f32210c0
|
RDTIME X5 // f32210c0
|
||||||
|
|
|
||||||
21
src/cmd/asm/internal/asm/testdata/riscv64error.s
vendored
21
src/cmd/asm/internal/asm/testdata/riscv64error.s
vendored
|
|
@ -3,6 +3,27 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
TEXT errors(SB),$0
|
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 $errors(SB), (X5) // ERROR "address load must target register"
|
||||||
MOV $8(SP), (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"
|
MOVB $8(SP), X5 // ERROR "unsupported address load"
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ import (
|
||||||
//
|
//
|
||||||
// <symbolic constant name>
|
// <symbolic constant name>
|
||||||
// Special symbolic constants for ARM64 (such as conditional flags, tlbi_op and so on)
|
// 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:
|
// Encoding:
|
||||||
// type = TYPE_SPECIAL
|
// type = TYPE_SPECIAL
|
||||||
// offset = The constant value corresponding to this symbol
|
// offset = The constant value corresponding to this symbol
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ import (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var CSRs map[uint16]string = csrs
|
||||||
|
|
||||||
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
|
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -1315,9 +1317,10 @@ type SpecialOperand int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SPOP_BEGIN SpecialOperand = obj.SpecialOperandRISCVBase
|
SPOP_BEGIN SpecialOperand = obj.SpecialOperandRISCVBase
|
||||||
|
SPOP_RVV_BEGIN
|
||||||
|
|
||||||
// Vector mask policy.
|
// Vector mask policy.
|
||||||
SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 1
|
SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 2
|
||||||
SPOP_MU
|
SPOP_MU
|
||||||
|
|
||||||
// Vector tail policy.
|
// Vector tail policy.
|
||||||
|
|
@ -1338,8 +1341,13 @@ const (
|
||||||
SPOP_E16
|
SPOP_E16
|
||||||
SPOP_E32
|
SPOP_E32
|
||||||
SPOP_E64
|
SPOP_E64
|
||||||
|
SPOP_RVV_END
|
||||||
|
|
||||||
SPOP_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_CSR_END + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
var specialOperands = map[SpecialOperand]struct {
|
var specialOperands = map[SpecialOperand]struct {
|
||||||
|
|
@ -1367,17 +1375,33 @@ var specialOperands = map[SpecialOperand]struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (so SpecialOperand) encode() uint32 {
|
func (so SpecialOperand) encode() uint32 {
|
||||||
op, ok := specialOperands[so]
|
switch {
|
||||||
if ok {
|
case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
|
||||||
return op.encoding
|
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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String returns the textual representation of a SpecialOperand.
|
||||||
func (so SpecialOperand) String() string {
|
func (so SpecialOperand) String() string {
|
||||||
op, ok := specialOperands[so]
|
switch {
|
||||||
if ok {
|
case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
|
||||||
return op.name
|
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 ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,14 @@ func opSuffixString(s uint8) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func specialOperandConv(a int64) string {
|
func specialOperandConv(a int64) string {
|
||||||
|
var s string
|
||||||
|
|
||||||
spc := SpecialOperand(a)
|
spc := SpecialOperand(a)
|
||||||
if spc >= SPOP_BEGIN && spc < SPOP_END {
|
if spc >= SPOP_BEGIN && spc < SPOP_END {
|
||||||
return spc.String()
|
s = spc.String()
|
||||||
}
|
}
|
||||||
return "SPC_??"
|
if s == "" {
|
||||||
|
return "SPC_??"
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1920,7 +1920,12 @@ var instructions = [ALAST & obj.AMask]instructionData{
|
||||||
ASD & obj.AMask: {enc: sIEncoding},
|
ASD & obj.AMask: {enc: sIEncoding},
|
||||||
|
|
||||||
// 7.1: CSR Instructions
|
// 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
|
// 13.1: Multiplication Operations
|
||||||
AMUL & obj.AMask: {enc: rIIIEncoding, ternary: true},
|
AMUL & obj.AMask: {enc: rIIIEncoding, ternary: true},
|
||||||
|
|
@ -3327,6 +3332,43 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
||||||
ins.imm = -1022
|
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:
|
case AFENCE:
|
||||||
ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
|
ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
|
||||||
ins.imm = 0x0ff
|
ins.imm = 0x0ff
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue