1131 строка
22 KiB
Go
1131 строка
22 KiB
Go
// Copyright 2017 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package arm64asm
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// An Op is an ARM64 opcode.
|
|
type Op uint16
|
|
|
|
// NOTE: The actual Op values are defined in tables.go.
|
|
// They are chosen to simplify instruction decoding and
|
|
// are not a dense packing from 0 to N, although the
|
|
// density is high, probably at least 90%.
|
|
|
|
func (op Op) String() string {
|
|
if op >= Op(len(opstr)) || opstr[op] == "" {
|
|
return fmt.Sprintf("Op(%d)", int(op))
|
|
}
|
|
return opstr[op]
|
|
}
|
|
|
|
// An Inst is a single instruction.
|
|
type Inst struct {
|
|
Op Op // Opcode mnemonic
|
|
Enc uint32 // Raw encoding bits.
|
|
Args Args // Instruction arguments, in ARM manual order.
|
|
}
|
|
|
|
func (i Inst) String() string {
|
|
var args []string
|
|
for _, arg := range i.Args {
|
|
if arg == nil {
|
|
break
|
|
}
|
|
args = append(args, arg.String())
|
|
}
|
|
return i.Op.String() + " " + strings.Join(args, ", ")
|
|
}
|
|
|
|
// An Args holds the instruction arguments.
|
|
// If an instruction has fewer than 5 arguments,
|
|
// the final elements in the array are nil.
|
|
type Args [5]Arg
|
|
|
|
// An Arg is a single instruction argument, one of these types:
|
|
// Reg, RegSP, ImmShift, RegExtshiftAmount, PCRel, MemImmediate,
|
|
// MemExtend, Imm, Imm64, Imm_hint, Imm_clrex, Imm_dcps, Cond,
|
|
// Imm_c, Imm_option, Imm_prfop, Pstatefield, Systemreg, Imm_fp
|
|
// RegisterWithArrangement, RegisterWithArrangementAndIndex.
|
|
type Arg interface {
|
|
isArg()
|
|
String() string
|
|
}
|
|
|
|
// A Reg is a single register.
|
|
// The zero value denotes W0, not the absence of a register.
|
|
type Reg uint16
|
|
|
|
const (
|
|
W0 Reg = iota
|
|
W1
|
|
W2
|
|
W3
|
|
W4
|
|
W5
|
|
W6
|
|
W7
|
|
W8
|
|
W9
|
|
W10
|
|
W11
|
|
W12
|
|
W13
|
|
W14
|
|
W15
|
|
W16
|
|
W17
|
|
W18
|
|
W19
|
|
W20
|
|
W21
|
|
W22
|
|
W23
|
|
W24
|
|
W25
|
|
W26
|
|
W27
|
|
W28
|
|
W29
|
|
W30
|
|
WZR
|
|
|
|
X0
|
|
X1
|
|
X2
|
|
X3
|
|
X4
|
|
X5
|
|
X6
|
|
X7
|
|
X8
|
|
X9
|
|
X10
|
|
X11
|
|
X12
|
|
X13
|
|
X14
|
|
X15
|
|
X16
|
|
X17
|
|
X18
|
|
X19
|
|
X20
|
|
X21
|
|
X22
|
|
X23
|
|
X24
|
|
X25
|
|
X26
|
|
X27
|
|
X28
|
|
X29
|
|
X30
|
|
XZR
|
|
|
|
B0
|
|
B1
|
|
B2
|
|
B3
|
|
B4
|
|
B5
|
|
B6
|
|
B7
|
|
B8
|
|
B9
|
|
B10
|
|
B11
|
|
B12
|
|
B13
|
|
B14
|
|
B15
|
|
B16
|
|
B17
|
|
B18
|
|
B19
|
|
B20
|
|
B21
|
|
B22
|
|
B23
|
|
B24
|
|
B25
|
|
B26
|
|
B27
|
|
B28
|
|
B29
|
|
B30
|
|
B31
|
|
|
|
H0
|
|
H1
|
|
H2
|
|
H3
|
|
H4
|
|
H5
|
|
H6
|
|
H7
|
|
H8
|
|
H9
|
|
H10
|
|
H11
|
|
H12
|
|
H13
|
|
H14
|
|
H15
|
|
H16
|
|
H17
|
|
H18
|
|
H19
|
|
H20
|
|
H21
|
|
H22
|
|
H23
|
|
H24
|
|
H25
|
|
H26
|
|
H27
|
|
H28
|
|
H29
|
|
H30
|
|
H31
|
|
|
|
S0
|
|
S1
|
|
S2
|
|
S3
|
|
S4
|
|
S5
|
|
S6
|
|
S7
|
|
S8
|
|
S9
|
|
S10
|
|
S11
|
|
S12
|
|
S13
|
|
S14
|
|
S15
|
|
S16
|
|
S17
|
|
S18
|
|
S19
|
|
S20
|
|
S21
|
|
S22
|
|
S23
|
|
S24
|
|
S25
|
|
S26
|
|
S27
|
|
S28
|
|
S29
|
|
S30
|
|
S31
|
|
|
|
D0
|
|
D1
|
|
D2
|
|
D3
|
|
D4
|
|
D5
|
|
D6
|
|
D7
|
|
D8
|
|
D9
|
|
D10
|
|
D11
|
|
D12
|
|
D13
|
|
D14
|
|
D15
|
|
D16
|
|
D17
|
|
D18
|
|
D19
|
|
D20
|
|
D21
|
|
D22
|
|
D23
|
|
D24
|
|
D25
|
|
D26
|
|
D27
|
|
D28
|
|
D29
|
|
D30
|
|
D31
|
|
|
|
Q0
|
|
Q1
|
|
Q2
|
|
Q3
|
|
Q4
|
|
Q5
|
|
Q6
|
|
Q7
|
|
Q8
|
|
Q9
|
|
Q10
|
|
Q11
|
|
Q12
|
|
Q13
|
|
Q14
|
|
Q15
|
|
Q16
|
|
Q17
|
|
Q18
|
|
Q19
|
|
Q20
|
|
Q21
|
|
Q22
|
|
Q23
|
|
Q24
|
|
Q25
|
|
Q26
|
|
Q27
|
|
Q28
|
|
Q29
|
|
Q30
|
|
Q31
|
|
|
|
V0
|
|
V1
|
|
V2
|
|
V3
|
|
V4
|
|
V5
|
|
V6
|
|
V7
|
|
V8
|
|
V9
|
|
V10
|
|
V11
|
|
V12
|
|
V13
|
|
V14
|
|
V15
|
|
V16
|
|
V17
|
|
V18
|
|
V19
|
|
V20
|
|
V21
|
|
V22
|
|
V23
|
|
V24
|
|
V25
|
|
V26
|
|
V27
|
|
V28
|
|
V29
|
|
V30
|
|
V31
|
|
|
|
WSP = WZR // These are different registers with the same encoding.
|
|
SP = XZR // These are different registers with the same encoding.
|
|
)
|
|
|
|
func (Reg) isArg() {}
|
|
|
|
func (r Reg) String() string {
|
|
switch {
|
|
case r == WZR:
|
|
return "WZR"
|
|
case r == XZR:
|
|
return "XZR"
|
|
case W0 <= r && r <= W30:
|
|
return fmt.Sprintf("W%d", int(r-W0))
|
|
case X0 <= r && r <= X30:
|
|
return fmt.Sprintf("X%d", int(r-X0))
|
|
|
|
case B0 <= r && r <= B31:
|
|
return fmt.Sprintf("B%d", int(r-B0))
|
|
case H0 <= r && r <= H31:
|
|
return fmt.Sprintf("H%d", int(r-H0))
|
|
case S0 <= r && r <= S31:
|
|
return fmt.Sprintf("S%d", int(r-S0))
|
|
case D0 <= r && r <= D31:
|
|
return fmt.Sprintf("D%d", int(r-D0))
|
|
case Q0 <= r && r <= Q31:
|
|
return fmt.Sprintf("Q%d", int(r-Q0))
|
|
|
|
case V0 <= r && r <= V31:
|
|
return fmt.Sprintf("V%d", int(r-V0))
|
|
default:
|
|
return fmt.Sprintf("Reg(%d)", int(r))
|
|
}
|
|
}
|
|
|
|
// A RegSP represent a register and X31/W31 is regarded as SP/WSP.
|
|
type RegSP Reg
|
|
|
|
func (RegSP) isArg() {}
|
|
|
|
func (r RegSP) String() string {
|
|
switch Reg(r) {
|
|
case WSP:
|
|
return "WSP"
|
|
case SP:
|
|
return "SP"
|
|
default:
|
|
return Reg(r).String()
|
|
}
|
|
}
|
|
|
|
type ImmShift struct {
|
|
imm uint16
|
|
shift uint8
|
|
}
|
|
|
|
func (ImmShift) isArg() {}
|
|
|
|
func (is ImmShift) String() string {
|
|
if is.shift == 0 {
|
|
return fmt.Sprintf("#%#x", is.imm)
|
|
}
|
|
if is.shift < 128 {
|
|
return fmt.Sprintf("#%#x, LSL #%d", is.imm, is.shift)
|
|
}
|
|
return fmt.Sprintf("#%#x, MSL #%d", is.imm, is.shift-128)
|
|
}
|
|
|
|
type ExtShift uint8
|
|
|
|
const (
|
|
_ ExtShift = iota
|
|
uxtb
|
|
uxth
|
|
uxtw
|
|
uxtx
|
|
sxtb
|
|
sxth
|
|
sxtw
|
|
sxtx
|
|
lsl
|
|
lsr
|
|
asr
|
|
ror
|
|
)
|
|
|
|
func (extShift ExtShift) String() string {
|
|
switch extShift {
|
|
case uxtb:
|
|
return "UXTB"
|
|
|
|
case uxth:
|
|
return "UXTH"
|
|
|
|
case uxtw:
|
|
return "UXTW"
|
|
|
|
case uxtx:
|
|
return "UXTX"
|
|
|
|
case sxtb:
|
|
return "SXTB"
|
|
|
|
case sxth:
|
|
return "SXTH"
|
|
|
|
case sxtw:
|
|
return "SXTW"
|
|
|
|
case sxtx:
|
|
return "SXTX"
|
|
|
|
case lsl:
|
|
return "LSL"
|
|
|
|
case lsr:
|
|
return "LSR"
|
|
|
|
case asr:
|
|
return "ASR"
|
|
|
|
case ror:
|
|
return "ROR"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
type RegExtshiftAmount struct {
|
|
reg Reg
|
|
extShift ExtShift
|
|
amount uint8
|
|
show_zero bool
|
|
}
|
|
|
|
func (RegExtshiftAmount) isArg() {}
|
|
|
|
func (rea RegExtshiftAmount) String() string {
|
|
buf := rea.reg.String()
|
|
if rea.extShift != ExtShift(0) {
|
|
buf += ", " + rea.extShift.String()
|
|
if rea.amount != 0 {
|
|
buf += fmt.Sprintf(" #%d", rea.amount)
|
|
} else {
|
|
if rea.show_zero == true {
|
|
buf += fmt.Sprintf(" #%d", rea.amount)
|
|
}
|
|
}
|
|
}
|
|
return buf
|
|
}
|
|
|
|
// A PCRel describes a memory address (usually a code label)
|
|
// as a distance relative to the program counter.
|
|
type PCRel int64
|
|
|
|
func (PCRel) isArg() {}
|
|
|
|
func (r PCRel) String() string {
|
|
return fmt.Sprintf(".%+#x", uint64(r))
|
|
}
|
|
|
|
// An AddrMode is an ARM addressing mode.
|
|
type AddrMode uint8
|
|
|
|
const (
|
|
_ AddrMode = iota
|
|
AddrPostIndex // [R], X - use address R, set R = R + X
|
|
AddrPreIndex // [R, X]! - use address R + X, set R = R + X
|
|
AddrOffset // [R, X] - use address R + X
|
|
AddrPostReg // [Rn], Rm - - use address Rn, set Rn = Rn + Rm
|
|
)
|
|
|
|
// A MemImmediate is a memory reference made up of a base R and immediate X.
|
|
// The effective memory address is R or R+X depending on AddrMode.
|
|
type MemImmediate struct {
|
|
Base RegSP
|
|
Mode AddrMode
|
|
imm int32
|
|
}
|
|
|
|
func (MemImmediate) isArg() {}
|
|
|
|
func (m MemImmediate) String() string {
|
|
R := m.Base.String()
|
|
X := fmt.Sprintf("#%d", m.imm)
|
|
|
|
switch m.Mode {
|
|
case AddrOffset:
|
|
if X == "#0" {
|
|
return fmt.Sprintf("[%s]", R)
|
|
}
|
|
return fmt.Sprintf("[%s,%s]", R, X)
|
|
case AddrPreIndex:
|
|
return fmt.Sprintf("[%s,%s]!", R, X)
|
|
case AddrPostIndex:
|
|
return fmt.Sprintf("[%s],%s", R, X)
|
|
case AddrPostReg:
|
|
post := Reg(X0) + Reg(m.imm)
|
|
postR := post.String()
|
|
return fmt.Sprintf("[%s], %s", R, postR)
|
|
}
|
|
return fmt.Sprintf("unimplemented!")
|
|
}
|
|
|
|
// A MemExtend is a memory reference made up of a base R and index expression X.
|
|
// The effective memory address is R or R+X depending on Index, Extend and Amount.
|
|
type MemExtend struct {
|
|
Base RegSP
|
|
Index Reg
|
|
Extend ExtShift
|
|
// Amount indicates the index shift amount (but also see ShiftMustBeZero field below).
|
|
Amount uint8
|
|
// Refer to ARM reference manual, for byte load/store(register), the index
|
|
// shift amount must be 0, encoded in "S" as 0 if omitted, or as 1 if present.
|
|
// a.ShiftMustBeZero is set true indicates the index shift amount must be 0.
|
|
// In GNU syntax, a #0 shift amount is printed if Amount is 1 but ShiftMustBeZero
|
|
// is true; #0 is not printed if Amount is 0 and ShiftMustBeZero is true.
|
|
// Both cases represent shift by 0 bit.
|
|
ShiftMustBeZero bool
|
|
}
|
|
|
|
func (MemExtend) isArg() {}
|
|
|
|
func (m MemExtend) String() string {
|
|
Rbase := m.Base.String()
|
|
RIndex := m.Index.String()
|
|
if m.ShiftMustBeZero {
|
|
if m.Amount != 0 {
|
|
return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String())
|
|
} else {
|
|
if m.Extend != lsl {
|
|
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
|
|
} else {
|
|
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
|
|
}
|
|
}
|
|
} else {
|
|
if m.Amount != 0 {
|
|
return fmt.Sprintf("[%s,%s,%s #%d]", Rbase, RIndex, m.Extend.String(), m.Amount)
|
|
} else {
|
|
if m.Extend != lsl {
|
|
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
|
|
} else {
|
|
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// An Imm is an integer constant.
|
|
type Imm struct {
|
|
Imm uint32
|
|
Decimal bool
|
|
}
|
|
|
|
func (Imm) isArg() {}
|
|
|
|
func (i Imm) String() string {
|
|
if !i.Decimal {
|
|
return fmt.Sprintf("#%#x", i.Imm)
|
|
} else {
|
|
return fmt.Sprintf("#%d", i.Imm)
|
|
}
|
|
}
|
|
|
|
type Imm64 struct {
|
|
Imm uint64
|
|
Decimal bool
|
|
}
|
|
|
|
func (Imm64) isArg() {}
|
|
|
|
func (i Imm64) String() string {
|
|
if !i.Decimal {
|
|
return fmt.Sprintf("#%#x", i.Imm)
|
|
} else {
|
|
return fmt.Sprintf("#%d", i.Imm)
|
|
}
|
|
}
|
|
|
|
// An Imm_hint is an integer constant for HINT instruction.
|
|
type Imm_hint uint8
|
|
|
|
func (Imm_hint) isArg() {}
|
|
|
|
func (i Imm_hint) String() string {
|
|
return fmt.Sprintf("#%#x", uint32(i))
|
|
}
|
|
|
|
// An Imm_clrex is an integer constant for CLREX instruction.
|
|
type Imm_clrex uint8
|
|
|
|
func (Imm_clrex) isArg() {}
|
|
|
|
func (i Imm_clrex) String() string {
|
|
if i == 15 {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("#%#x", uint32(i))
|
|
}
|
|
|
|
// An Imm_dcps is an integer constant for DCPS[123] instruction.
|
|
type Imm_dcps uint16
|
|
|
|
func (Imm_dcps) isArg() {}
|
|
|
|
func (i Imm_dcps) String() string {
|
|
if i == 0 {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("#%#x", uint32(i))
|
|
}
|
|
|
|
// Standard conditions.
|
|
type Cond struct {
|
|
Value uint8
|
|
Invert bool
|
|
}
|
|
|
|
func (Cond) isArg() {}
|
|
|
|
func (c Cond) String() string {
|
|
cond31 := c.Value >> 1
|
|
invert := bool((c.Value & 1) == 1)
|
|
invert = (invert != c.Invert)
|
|
switch cond31 {
|
|
case 0:
|
|
if invert {
|
|
return "NE"
|
|
} else {
|
|
return "EQ"
|
|
}
|
|
case 1:
|
|
if invert {
|
|
return "CC"
|
|
} else {
|
|
return "CS"
|
|
}
|
|
case 2:
|
|
if invert {
|
|
return "PL"
|
|
} else {
|
|
return "MI"
|
|
}
|
|
case 3:
|
|
if invert {
|
|
return "VC"
|
|
} else {
|
|
return "VS"
|
|
}
|
|
case 4:
|
|
if invert {
|
|
return "LS"
|
|
} else {
|
|
return "HI"
|
|
}
|
|
case 5:
|
|
if invert {
|
|
return "LT"
|
|
} else {
|
|
return "GE"
|
|
}
|
|
case 6:
|
|
if invert {
|
|
return "LE"
|
|
} else {
|
|
return "GT"
|
|
}
|
|
case 7:
|
|
return "AL"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// An Imm_c is an integer constant for SYS/SYSL/TLBI instruction.
|
|
type Imm_c uint8
|
|
|
|
func (Imm_c) isArg() {}
|
|
|
|
func (i Imm_c) String() string {
|
|
return fmt.Sprintf("C%d", uint8(i))
|
|
}
|
|
|
|
// An Imm_option is an integer constant for DMB/DSB/ISB instruction.
|
|
type Imm_option uint8
|
|
|
|
func (Imm_option) isArg() {}
|
|
|
|
func (i Imm_option) String() string {
|
|
switch uint8(i) {
|
|
case 15:
|
|
return "SY"
|
|
case 14:
|
|
return "ST"
|
|
case 13:
|
|
return "LD"
|
|
case 11:
|
|
return "ISH"
|
|
case 10:
|
|
return "ISHST"
|
|
case 9:
|
|
return "ISHLD"
|
|
case 7:
|
|
return "NSH"
|
|
case 6:
|
|
return "NSHST"
|
|
case 5:
|
|
return "NSHLD"
|
|
case 3:
|
|
return "OSH"
|
|
case 2:
|
|
return "OSHST"
|
|
case 1:
|
|
return "OSHLD"
|
|
}
|
|
return fmt.Sprintf("#%#02x", uint8(i))
|
|
}
|
|
|
|
// An Imm_prfop is an integer constant for PRFM instruction.
|
|
type Imm_prfop uint8
|
|
|
|
func (Imm_prfop) isArg() {}
|
|
|
|
func (i Imm_prfop) String() string {
|
|
prf_type := (i >> 3) & (1<<2 - 1)
|
|
prf_target := (i >> 1) & (1<<2 - 1)
|
|
prf_policy := i & 1
|
|
var result string
|
|
|
|
switch prf_type {
|
|
case 0:
|
|
result = "PLD"
|
|
case 1:
|
|
result = "PLI"
|
|
case 2:
|
|
result = "PST"
|
|
case 3:
|
|
return fmt.Sprintf("#%#02x", uint8(i))
|
|
}
|
|
switch prf_target {
|
|
case 0:
|
|
result += "L1"
|
|
case 1:
|
|
result += "L2"
|
|
case 2:
|
|
result += "L3"
|
|
case 3:
|
|
return fmt.Sprintf("#%#02x", uint8(i))
|
|
}
|
|
if prf_policy == 0 {
|
|
result += "KEEP"
|
|
} else {
|
|
result += "STRM"
|
|
}
|
|
return result
|
|
}
|
|
|
|
type Pstatefield uint8
|
|
|
|
const (
|
|
SPSel Pstatefield = iota
|
|
DAIFSet
|
|
DAIFClr
|
|
)
|
|
|
|
func (Pstatefield) isArg() {}
|
|
|
|
func (p Pstatefield) String() string {
|
|
switch p {
|
|
case SPSel:
|
|
return "SPSel"
|
|
case DAIFSet:
|
|
return "DAIFSet"
|
|
case DAIFClr:
|
|
return "DAIFClr"
|
|
default:
|
|
return "unimplemented"
|
|
}
|
|
}
|
|
|
|
type Systemreg struct {
|
|
op0 uint8
|
|
op1 uint8
|
|
cn uint8
|
|
cm uint8
|
|
op2 uint8
|
|
}
|
|
|
|
func (Systemreg) isArg() {}
|
|
|
|
func (s Systemreg) String() string {
|
|
return fmt.Sprintf("S%d_%d_C%d_C%d_%d",
|
|
s.op0, s.op1, s.cn, s.cm, s.op2)
|
|
}
|
|
|
|
// An Imm_fp is a signed floating-point constant.
|
|
type Imm_fp struct {
|
|
s uint8
|
|
exp int8
|
|
pre uint8
|
|
}
|
|
|
|
func (Imm_fp) isArg() {}
|
|
|
|
func (i Imm_fp) String() string {
|
|
var s, pre, numerator, denominator int16
|
|
var result float64
|
|
if i.s == 0 {
|
|
s = 1
|
|
} else {
|
|
s = -1
|
|
}
|
|
pre = s * int16(16+i.pre)
|
|
if i.exp > 0 {
|
|
numerator = (pre << uint8(i.exp))
|
|
denominator = 16
|
|
} else {
|
|
numerator = pre
|
|
denominator = (16 << uint8(-1*i.exp))
|
|
}
|
|
result = float64(numerator) / float64(denominator)
|
|
return fmt.Sprintf("#%.18e", result)
|
|
}
|
|
|
|
type Arrangement uint8
|
|
|
|
const (
|
|
_ Arrangement = iota
|
|
ArrangementB
|
|
Arrangement8B
|
|
Arrangement16B
|
|
ArrangementH
|
|
Arrangement4H
|
|
Arrangement8H
|
|
ArrangementS
|
|
Arrangement2S
|
|
Arrangement4S
|
|
ArrangementD
|
|
Arrangement1D
|
|
Arrangement2D
|
|
Arrangement1Q
|
|
)
|
|
|
|
func (a Arrangement) String() (result string) {
|
|
switch a {
|
|
case ArrangementB:
|
|
result = ".B"
|
|
case Arrangement8B:
|
|
result = ".8B"
|
|
case Arrangement16B:
|
|
result = ".16B"
|
|
case ArrangementH:
|
|
result = ".H"
|
|
case Arrangement4H:
|
|
result = ".4H"
|
|
case Arrangement8H:
|
|
result = ".8H"
|
|
case ArrangementS:
|
|
result = ".S"
|
|
case Arrangement2S:
|
|
result = ".2S"
|
|
case Arrangement4S:
|
|
result = ".4S"
|
|
case ArrangementD:
|
|
result = ".D"
|
|
case Arrangement1D:
|
|
result = ".1D"
|
|
case Arrangement2D:
|
|
result = ".2D"
|
|
case Arrangement1Q:
|
|
result = ".1Q"
|
|
}
|
|
return
|
|
}
|
|
|
|
// Register with arrangement: <Vd>.<T>, { <Vt>.8B, <Vt2>.8B},
|
|
type RegisterWithArrangement struct {
|
|
r Reg
|
|
a Arrangement
|
|
cnt uint8
|
|
}
|
|
|
|
func (RegisterWithArrangement) isArg() {}
|
|
|
|
func (r RegisterWithArrangement) String() string {
|
|
result := r.r.String()
|
|
result += r.a.String()
|
|
if r.cnt > 0 {
|
|
result = "{" + result
|
|
if r.cnt == 2 {
|
|
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
|
|
result += ", " + r1.String() + r.a.String()
|
|
} else if r.cnt > 2 {
|
|
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
|
|
for i := 1; i < int(r.cnt); i++ {
|
|
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
|
|
result += ", " + cur.String() + r.a.String()
|
|
}
|
|
} else {
|
|
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
|
|
result += "-" + r1.String() + r.a.String()
|
|
}
|
|
}
|
|
result += "}"
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Register with arrangement and index:
|
|
//
|
|
// <Vm>.<Ts>[<index>],
|
|
// { <Vt>.B, <Vt2>.B }[<index>].
|
|
type RegisterWithArrangementAndIndex struct {
|
|
r Reg
|
|
a Arrangement
|
|
index uint8
|
|
cnt uint8
|
|
}
|
|
|
|
func (RegisterWithArrangementAndIndex) isArg() {}
|
|
|
|
func (r RegisterWithArrangementAndIndex) String() string {
|
|
result := r.r.String()
|
|
result += r.a.String()
|
|
if r.cnt > 0 {
|
|
result = "{" + result
|
|
if r.cnt == 2 {
|
|
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
|
|
result += ", " + r1.String() + r.a.String()
|
|
} else if r.cnt > 2 {
|
|
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
|
|
for i := 1; i < int(r.cnt); i++ {
|
|
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
|
|
result += ", " + cur.String() + r.a.String()
|
|
}
|
|
} else {
|
|
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
|
|
result += "-" + r1.String() + r.a.String()
|
|
}
|
|
}
|
|
result += "}"
|
|
}
|
|
return fmt.Sprintf("%s[%d]", result, r.index)
|
|
}
|
|
|
|
type sysOp struct {
|
|
op sysInstFields
|
|
r Reg
|
|
hasOperand2 bool
|
|
}
|
|
|
|
func (s sysOp) isArg() {}
|
|
|
|
func (s sysOp) String() string {
|
|
result := s.op.String()
|
|
// If s.hasOperand2 is false, the value in the register
|
|
// specified by s.r is ignored.
|
|
if s.hasOperand2 {
|
|
result += ", " + s.r.String()
|
|
}
|
|
return result
|
|
}
|
|
|
|
type sysInstFields struct {
|
|
op1 uint8
|
|
cn uint8
|
|
cm uint8
|
|
op2 uint8
|
|
}
|
|
|
|
type sysInstAttrs struct {
|
|
typ sys
|
|
name string
|
|
hasOperand2 bool
|
|
}
|
|
|
|
func (s sysInstFields) isArg() {}
|
|
|
|
func (s sysInstFields) getAttrs() sysInstAttrs {
|
|
attrs, ok := sysInstsAttrs[sysInstFields{s.op1, s.cn, s.cm, s.op2}]
|
|
if !ok {
|
|
return sysInstAttrs{typ: sys_SYS}
|
|
}
|
|
return attrs
|
|
}
|
|
|
|
func (s sysInstFields) String() string {
|
|
return s.getAttrs().name
|
|
}
|
|
|
|
func (s sysInstFields) getType() sys {
|
|
return s.getAttrs().typ
|
|
}
|
|
|
|
var sysInstsAttrs = map[sysInstFields]sysInstAttrs{
|
|
sysInstFields{0, 8, 3, 0}: {sys_TLBI, "VMALLE1IS", false},
|
|
sysInstFields{0, 8, 3, 1}: {sys_TLBI, "VAE1IS", true},
|
|
sysInstFields{0, 8, 3, 2}: {sys_TLBI, "ASIDE1IS", true},
|
|
sysInstFields{0, 8, 3, 3}: {sys_TLBI, "VAAE1IS", true},
|
|
sysInstFields{0, 8, 3, 5}: {sys_TLBI, "VALE1IS", true},
|
|
sysInstFields{0, 8, 3, 7}: {sys_TLBI, "VAALE1IS", true},
|
|
sysInstFields{0, 8, 7, 0}: {sys_TLBI, "VMALLE1", false},
|
|
sysInstFields{0, 8, 7, 1}: {sys_TLBI, "VAE1", true},
|
|
sysInstFields{0, 8, 7, 2}: {sys_TLBI, "ASIDE1", true},
|
|
sysInstFields{0, 8, 7, 3}: {sys_TLBI, "VAAE1", true},
|
|
sysInstFields{0, 8, 7, 5}: {sys_TLBI, "VALE1", true},
|
|
sysInstFields{0, 8, 7, 7}: {sys_TLBI, "VAALE1", true},
|
|
sysInstFields{4, 8, 0, 1}: {sys_TLBI, "IPAS2E1IS", true},
|
|
sysInstFields{4, 8, 0, 5}: {sys_TLBI, "IPAS2LE1IS", true},
|
|
sysInstFields{4, 8, 3, 0}: {sys_TLBI, "ALLE2IS", false},
|
|
sysInstFields{4, 8, 3, 1}: {sys_TLBI, "VAE2IS", true},
|
|
sysInstFields{4, 8, 3, 4}: {sys_TLBI, "ALLE1IS", false},
|
|
sysInstFields{4, 8, 3, 5}: {sys_TLBI, "VALE2IS", true},
|
|
sysInstFields{4, 8, 3, 6}: {sys_TLBI, "VMALLS12E1IS", false},
|
|
sysInstFields{4, 8, 4, 1}: {sys_TLBI, "IPAS2E1", true},
|
|
sysInstFields{4, 8, 4, 5}: {sys_TLBI, "IPAS2LE1", true},
|
|
sysInstFields{4, 8, 7, 0}: {sys_TLBI, "ALLE2", false},
|
|
sysInstFields{4, 8, 7, 1}: {sys_TLBI, "VAE2", true},
|
|
sysInstFields{4, 8, 7, 4}: {sys_TLBI, "ALLE1", false},
|
|
sysInstFields{4, 8, 7, 5}: {sys_TLBI, "VALE2", true},
|
|
sysInstFields{4, 8, 7, 6}: {sys_TLBI, "VMALLS12E1", false},
|
|
sysInstFields{6, 8, 3, 0}: {sys_TLBI, "ALLE3IS", false},
|
|
sysInstFields{6, 8, 3, 1}: {sys_TLBI, "VAE3IS", true},
|
|
sysInstFields{6, 8, 3, 5}: {sys_TLBI, "VALE3IS", true},
|
|
sysInstFields{6, 8, 7, 0}: {sys_TLBI, "ALLE3", false},
|
|
sysInstFields{6, 8, 7, 1}: {sys_TLBI, "VAE3", true},
|
|
sysInstFields{6, 8, 7, 5}: {sys_TLBI, "VALE3", true},
|
|
sysInstFields{0, 8, 1, 0}: {sys_TLBI, "VMALLE1OS", false},
|
|
sysInstFields{0, 8, 1, 1}: {sys_TLBI, "VAE1OS", true},
|
|
sysInstFields{0, 8, 1, 2}: {sys_TLBI, "ASIDE1OS", true},
|
|
sysInstFields{0, 8, 1, 3}: {sys_TLBI, "VAAE1OS", true},
|
|
sysInstFields{0, 8, 1, 5}: {sys_TLBI, "VALE1OS", true},
|
|
sysInstFields{0, 8, 1, 7}: {sys_TLBI, "VAALE1OS", true},
|
|
sysInstFields{0, 8, 2, 1}: {sys_TLBI, "RVAE1IS", true},
|
|
sysInstFields{0, 8, 2, 3}: {sys_TLBI, "RVAAE1IS", true},
|
|
sysInstFields{0, 8, 2, 5}: {sys_TLBI, "RVALE1IS", true},
|
|
sysInstFields{0, 8, 2, 7}: {sys_TLBI, "RVAALE1IS", true},
|
|
sysInstFields{0, 8, 5, 1}: {sys_TLBI, "RVAE1OS", true},
|
|
sysInstFields{0, 8, 5, 3}: {sys_TLBI, "RVAAE1OS", true},
|
|
sysInstFields{0, 8, 5, 5}: {sys_TLBI, "RVALE1OS", true},
|
|
sysInstFields{0, 8, 5, 7}: {sys_TLBI, "RVAALE1OS", true},
|
|
sysInstFields{0, 8, 6, 1}: {sys_TLBI, "RVAE1", true},
|
|
sysInstFields{0, 8, 6, 3}: {sys_TLBI, "RVAAE1", true},
|
|
sysInstFields{0, 8, 6, 5}: {sys_TLBI, "RVALE1", true},
|
|
sysInstFields{0, 8, 6, 7}: {sys_TLBI, "RVAALE1", true},
|
|
sysInstFields{4, 8, 0, 2}: {sys_TLBI, "RIPAS2E1IS", true},
|
|
sysInstFields{4, 8, 0, 6}: {sys_TLBI, "RIPAS2LE1IS", true},
|
|
sysInstFields{4, 8, 1, 0}: {sys_TLBI, "ALLE2OS", false},
|
|
sysInstFields{4, 8, 1, 1}: {sys_TLBI, "VAE2OS", true},
|
|
sysInstFields{4, 8, 1, 4}: {sys_TLBI, "ALLE1OS", false},
|
|
sysInstFields{4, 8, 1, 5}: {sys_TLBI, "VALE2OS", true},
|
|
sysInstFields{4, 8, 1, 6}: {sys_TLBI, "VMALLS12E1OS", false},
|
|
sysInstFields{4, 8, 2, 1}: {sys_TLBI, "RVAE2IS", true},
|
|
sysInstFields{4, 8, 2, 5}: {sys_TLBI, "RVALE2IS", true},
|
|
sysInstFields{4, 8, 4, 0}: {sys_TLBI, "IPAS2E1OS", true},
|
|
sysInstFields{4, 8, 4, 2}: {sys_TLBI, "RIPAS2E1", true},
|
|
sysInstFields{4, 8, 4, 3}: {sys_TLBI, "RIPAS2E1OS", true},
|
|
sysInstFields{4, 8, 4, 4}: {sys_TLBI, "IPAS2LE1OS", true},
|
|
sysInstFields{4, 8, 4, 6}: {sys_TLBI, "RIPAS2LE1", true},
|
|
sysInstFields{4, 8, 4, 7}: {sys_TLBI, "RIPAS2LE1OS", true},
|
|
sysInstFields{4, 8, 5, 1}: {sys_TLBI, "RVAE2OS", true},
|
|
sysInstFields{4, 8, 5, 5}: {sys_TLBI, "RVALE2OS", true},
|
|
sysInstFields{4, 8, 6, 1}: {sys_TLBI, "RVAE2", true},
|
|
sysInstFields{4, 8, 6, 5}: {sys_TLBI, "RVALE2", true},
|
|
sysInstFields{6, 8, 1, 0}: {sys_TLBI, "ALLE3OS", false},
|
|
sysInstFields{6, 8, 1, 1}: {sys_TLBI, "VAE3OS", true},
|
|
sysInstFields{6, 8, 1, 5}: {sys_TLBI, "VALE3OS", true},
|
|
sysInstFields{6, 8, 2, 1}: {sys_TLBI, "RVAE3IS", true},
|
|
sysInstFields{6, 8, 2, 5}: {sys_TLBI, "RVALE3IS", true},
|
|
sysInstFields{6, 8, 5, 1}: {sys_TLBI, "RVAE3OS", true},
|
|
sysInstFields{6, 8, 5, 5}: {sys_TLBI, "RVALE3OS", true},
|
|
sysInstFields{6, 8, 6, 1}: {sys_TLBI, "RVAE3", true},
|
|
sysInstFields{6, 8, 6, 5}: {sys_TLBI, "RVALE3", true},
|
|
sysInstFields{0, 7, 6, 1}: {sys_DC, "IVAC", true},
|
|
sysInstFields{0, 7, 6, 2}: {sys_DC, "ISW", true},
|
|
sysInstFields{0, 7, 10, 2}: {sys_DC, "CSW", true},
|
|
sysInstFields{0, 7, 14, 2}: {sys_DC, "CISW", true},
|
|
sysInstFields{3, 7, 4, 1}: {sys_DC, "ZVA", true},
|
|
sysInstFields{3, 7, 10, 1}: {sys_DC, "CVAC", true},
|
|
sysInstFields{3, 7, 11, 1}: {sys_DC, "CVAU", true},
|
|
sysInstFields{3, 7, 14, 1}: {sys_DC, "CIVAC", true},
|
|
sysInstFields{0, 7, 6, 3}: {sys_DC, "IGVAC", true},
|
|
sysInstFields{0, 7, 6, 4}: {sys_DC, "IGSW", true},
|
|
sysInstFields{0, 7, 6, 5}: {sys_DC, "IGDVAC", true},
|
|
sysInstFields{0, 7, 6, 6}: {sys_DC, "IGDSW", true},
|
|
sysInstFields{0, 7, 10, 4}: {sys_DC, "CGSW", true},
|
|
sysInstFields{0, 7, 10, 6}: {sys_DC, "CGDSW", true},
|
|
sysInstFields{0, 7, 14, 4}: {sys_DC, "CIGSW", true},
|
|
sysInstFields{0, 7, 14, 6}: {sys_DC, "CIGDSW", true},
|
|
sysInstFields{3, 7, 4, 3}: {sys_DC, "GVA", true},
|
|
sysInstFields{3, 7, 4, 4}: {sys_DC, "GZVA", true},
|
|
sysInstFields{3, 7, 10, 3}: {sys_DC, "CGVAC", true},
|
|
sysInstFields{3, 7, 10, 5}: {sys_DC, "CGDVAC", true},
|
|
sysInstFields{3, 7, 12, 3}: {sys_DC, "CGVAP", true},
|
|
sysInstFields{3, 7, 12, 5}: {sys_DC, "CGDVAP", true},
|
|
sysInstFields{3, 7, 13, 3}: {sys_DC, "CGVADP", true},
|
|
sysInstFields{3, 7, 13, 5}: {sys_DC, "CGDVADP", true},
|
|
sysInstFields{3, 7, 14, 3}: {sys_DC, "CIGVAC", true},
|
|
sysInstFields{3, 7, 14, 5}: {sys_DC, "CIGDVAC", true},
|
|
sysInstFields{3, 7, 12, 1}: {sys_DC, "CVAP", true},
|
|
sysInstFields{3, 7, 13, 1}: {sys_DC, "CVADP", true},
|
|
}
|