summaryrefslogtreecommitdiff
path: root/src/cmd/internal/rsc.io/arm/armasm/inst.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/rsc.io/arm/armasm/inst.go')
-rw-r--r--src/cmd/internal/rsc.io/arm/armasm/inst.go438
1 files changed, 438 insertions, 0 deletions
diff --git a/src/cmd/internal/rsc.io/arm/armasm/inst.go b/src/cmd/internal/rsc.io/arm/armasm/inst.go
new file mode 100644
index 000000000..60d633bdb
--- /dev/null
+++ b/src/cmd/internal/rsc.io/arm/armasm/inst.go
@@ -0,0 +1,438 @@
+// Copyright 2014 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 armasm
+
+import (
+ "bytes"
+ "fmt"
+)
+
+// A Mode is an instruction execution mode.
+type Mode int
+
+const (
+ _ Mode = iota
+ ModeARM
+ ModeThumb
+)
+
+func (m Mode) String() string {
+ switch m {
+ case ModeARM:
+ return "ARM"
+ case ModeThumb:
+ return "Thumb"
+ }
+ return fmt.Sprintf("Mode(%d)", int(m))
+}
+
+// An Op is an ARM 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.
+ Len int // Length of encoding in bytes.
+ Args Args // Instruction arguments, in ARM manual order.
+}
+
+func (i Inst) String() string {
+ var buf bytes.Buffer
+ buf.WriteString(i.Op.String())
+ for j, arg := range i.Args {
+ if arg == nil {
+ break
+ }
+ if j == 0 {
+ buf.WriteString(" ")
+ } else {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(arg.String())
+ }
+ return buf.String()
+}
+
+// An Args holds the instruction arguments.
+// If an instruction has fewer than 4 arguments,
+// the final elements in the array are nil.
+type Args [4]Arg
+
+// An Arg is a single instruction argument, one of these types:
+// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg.
+type Arg interface {
+ IsArg()
+ String() string
+}
+
+type Float32Imm float32
+
+func (Float32Imm) IsArg() {}
+
+func (f Float32Imm) String() string {
+ return fmt.Sprintf("#%v", float32(f))
+}
+
+type Float64Imm float32
+
+func (Float64Imm) IsArg() {}
+
+func (f Float64Imm) String() string {
+ return fmt.Sprintf("#%v", float64(f))
+}
+
+// An Imm is an integer constant.
+type Imm uint32
+
+func (Imm) IsArg() {}
+
+func (i Imm) String() string {
+ return fmt.Sprintf("#%#x", uint32(i))
+}
+
+// A ImmAlt is an alternate encoding of an integer constant.
+type ImmAlt struct {
+ Val uint8
+ Rot uint8
+}
+
+func (ImmAlt) IsArg() {}
+
+func (i ImmAlt) Imm() Imm {
+ v := uint32(i.Val)
+ r := uint(i.Rot)
+ return Imm(v>>r | v<<(32-r))
+}
+
+func (i ImmAlt) String() string {
+ return fmt.Sprintf("#%#x, %d", i.Val, i.Rot)
+}
+
+// A Label is a text (code) address.
+type Label uint32
+
+func (Label) IsArg() {}
+
+func (i Label) String() string {
+ return fmt.Sprintf("%#x", uint32(i))
+}
+
+// A Reg is a single register.
+// The zero value denotes R0, not the absence of a register.
+type Reg uint8
+
+const (
+ R0 Reg = iota
+ R1
+ R2
+ R3
+ R4
+ R5
+ R6
+ R7
+ R8
+ R9
+ R10
+ R11
+ R12
+ R13
+ R14
+ R15
+
+ 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
+
+ APSR
+ APSR_nzcv
+ FPSCR
+
+ SP = R13
+ LR = R14
+ PC = R15
+)
+
+func (Reg) IsArg() {}
+
+func (r Reg) String() string {
+ switch r {
+ case APSR:
+ return "APSR"
+ case APSR_nzcv:
+ return "APSR_nzcv"
+ case FPSCR:
+ return "FPSCR"
+ case SP:
+ return "SP"
+ case PC:
+ return "PC"
+ case LR:
+ return "LR"
+ }
+ if R0 <= r && r <= R15 {
+ return fmt.Sprintf("R%d", int(r-R0))
+ }
+ if S0 <= r && r <= S31 {
+ return fmt.Sprintf("S%d", int(r-S0))
+ }
+ if D0 <= r && r <= D31 {
+ return fmt.Sprintf("D%d", int(r-D0))
+ }
+ return fmt.Sprintf("Reg(%d)", int(r))
+}
+
+// A RegX represents a fraction of a multi-value register.
+// The Index field specifies the index number,
+// but the size of the fraction is not specified.
+// It must be inferred from the instruction and the register type.
+// For example, in a VMOV instruction, RegX{D5, 1} represents
+// the top 32 bits of the 64-bit D5 register.
+type RegX struct {
+ Reg Reg
+ Index int
+}
+
+func (RegX) IsArg() {}
+
+func (r RegX) String() string {
+ return fmt.Sprintf("%s[%d]", r.Reg, r.Index)
+}
+
+// A RegList is a register list.
+// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list.
+type RegList uint16
+
+func (RegList) IsArg() {}
+
+func (r RegList) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "{")
+ sep := ""
+ for i := 0; i < 16; i++ {
+ if r&(1<<uint(i)) != 0 {
+ fmt.Fprintf(&buf, "%s%s", sep, Reg(i).String())
+ sep = ","
+ }
+ }
+ fmt.Fprintf(&buf, "}")
+ return buf.String()
+}
+
+// An Endian is the argument to the SETEND instruction.
+type Endian uint8
+
+const (
+ LittleEndian Endian = 0
+ BigEndian Endian = 1
+)
+
+func (Endian) IsArg() {}
+
+func (e Endian) String() string {
+ if e != 0 {
+ return "BE"
+ }
+ return "LE"
+}
+
+// A Shift describes an ARM shift operation.
+type Shift uint8
+
+const (
+ ShiftLeft Shift = 0 // left shift
+ ShiftRight Shift = 1 // logical (unsigned) right shift
+ ShiftRightSigned Shift = 2 // arithmetic (signed) right shift
+ RotateRight Shift = 3 // right rotate
+ RotateRightExt Shift = 4 // right rotate through carry (Count will always be 1)
+)
+
+var shiftName = [...]string{
+ "LSL", "LSR", "ASR", "ROR", "RRX",
+}
+
+func (s Shift) String() string {
+ if s < 5 {
+ return shiftName[s]
+ }
+ return fmt.Sprintf("Shift(%d)", int(s))
+}
+
+// A RegShift is a register shifted by a constant.
+type RegShift struct {
+ Reg Reg
+ Shift Shift
+ Count uint8
+}
+
+func (RegShift) IsArg() {}
+
+func (r RegShift) String() string {
+ return fmt.Sprintf("%s %s #%d", r.Reg, r.Shift, r.Count)
+}
+
+// A RegShiftReg is a register shifted by a register.
+type RegShiftReg struct {
+ Reg Reg
+ Shift Shift
+ RegCount Reg
+}
+
+func (RegShiftReg) IsArg() {}
+
+func (r RegShiftReg) String() string {
+ return fmt.Sprintf("%s %s %s", r.Reg, r.Shift, r.RegCount)
+}
+
+// A PCRel describes a memory address (usually a code label)
+// as a distance relative to the program counter.
+// TODO(rsc): Define which program counter (PC+4? PC+8? PC?).
+type PCRel int32
+
+func (PCRel) IsArg() {}
+
+func (r PCRel) String() string {
+ return fmt.Sprintf("PC%+#x", int32(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
+ AddrLDM // R – [R] but formats as R, for LDM/STM only
+ AddrLDM_WB // R! - [R], X where X is instruction-specific amount, for LDM/STM only
+)
+
+// A Mem 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 AddrMode.
+// The index expression is X = Sign*(Index Shift Count) + Offset,
+// but in any instruction either Sign = 0 or Offset = 0.
+type Mem struct {
+ Base Reg
+ Mode AddrMode
+ Sign int8
+ Index Reg
+ Shift Shift
+ Count uint8
+ Offset int16
+}
+
+func (Mem) IsArg() {}
+
+func (m Mem) String() string {
+ R := m.Base.String()
+ X := ""
+ if m.Sign != 0 {
+ X = "+"
+ if m.Sign < 0 {
+ X = "-"
+ }
+ X += m.Index.String()
+ if m.Shift != ShiftLeft || m.Count != 0 {
+ X += fmt.Sprintf(", %s #%d", m.Shift, m.Count)
+ }
+ } else {
+ X = fmt.Sprintf("#%d", m.Offset)
+ }
+
+ 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 AddrLDM:
+ if X == "#0" {
+ return R
+ }
+ case AddrLDM_WB:
+ if X == "#0" {
+ return R + "!"
+ }
+ }
+ return fmt.Sprintf("[%s Mode(%d) %s]", R, int(m.Mode), X)
+}