// 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)) } // An 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<