forked from lug/matterbridge
		
	
		
			
				
	
	
		
			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)
 | ||
| }
 | 
