mirror of
https://github.com/42wim/matterbridge.git
synced 2024-12-29 22:52:43 +01:00
439 lines
7.5 KiB
Go
439 lines
7.5 KiB
Go
|
// 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)
|
|||
|
}
|