Home | History | Annotate | Download | only in armasm
      1 // Copyright 2014 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package armasm
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 )
     11 
     12 // A Mode is an instruction execution mode.
     13 type Mode int
     14 
     15 const (
     16 	_ Mode = iota
     17 	ModeARM
     18 	ModeThumb
     19 )
     20 
     21 func (m Mode) String() string {
     22 	switch m {
     23 	case ModeARM:
     24 		return "ARM"
     25 	case ModeThumb:
     26 		return "Thumb"
     27 	}
     28 	return fmt.Sprintf("Mode(%d)", int(m))
     29 }
     30 
     31 // An Op is an ARM opcode.
     32 type Op uint16
     33 
     34 // NOTE: The actual Op values are defined in tables.go.
     35 // They are chosen to simplify instruction decoding and
     36 // are not a dense packing from 0 to N, although the
     37 // density is high, probably at least 90%.
     38 
     39 func (op Op) String() string {
     40 	if op >= Op(len(opstr)) || opstr[op] == "" {
     41 		return fmt.Sprintf("Op(%d)", int(op))
     42 	}
     43 	return opstr[op]
     44 }
     45 
     46 // An Inst is a single instruction.
     47 type Inst struct {
     48 	Op   Op     // Opcode mnemonic
     49 	Enc  uint32 // Raw encoding bits.
     50 	Len  int    // Length of encoding in bytes.
     51 	Args Args   // Instruction arguments, in ARM manual order.
     52 }
     53 
     54 func (i Inst) String() string {
     55 	var buf bytes.Buffer
     56 	buf.WriteString(i.Op.String())
     57 	for j, arg := range i.Args {
     58 		if arg == nil {
     59 			break
     60 		}
     61 		if j == 0 {
     62 			buf.WriteString(" ")
     63 		} else {
     64 			buf.WriteString(", ")
     65 		}
     66 		buf.WriteString(arg.String())
     67 	}
     68 	return buf.String()
     69 }
     70 
     71 // An Args holds the instruction arguments.
     72 // If an instruction has fewer than 4 arguments,
     73 // the final elements in the array are nil.
     74 type Args [4]Arg
     75 
     76 // An Arg is a single instruction argument, one of these types:
     77 // Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg.
     78 type Arg interface {
     79 	IsArg()
     80 	String() string
     81 }
     82 
     83 type Float32Imm float32
     84 
     85 func (Float32Imm) IsArg() {}
     86 
     87 func (f Float32Imm) String() string {
     88 	return fmt.Sprintf("#%v", float32(f))
     89 }
     90 
     91 type Float64Imm float32
     92 
     93 func (Float64Imm) IsArg() {}
     94 
     95 func (f Float64Imm) String() string {
     96 	return fmt.Sprintf("#%v", float64(f))
     97 }
     98 
     99 // An Imm is an integer constant.
    100 type Imm uint32
    101 
    102 func (Imm) IsArg() {}
    103 
    104 func (i Imm) String() string {
    105 	return fmt.Sprintf("#%#x", uint32(i))
    106 }
    107 
    108 // A ImmAlt is an alternate encoding of an integer constant.
    109 type ImmAlt struct {
    110 	Val uint8
    111 	Rot uint8
    112 }
    113 
    114 func (ImmAlt) IsArg() {}
    115 
    116 func (i ImmAlt) Imm() Imm {
    117 	v := uint32(i.Val)
    118 	r := uint(i.Rot)
    119 	return Imm(v>>r | v<<(32-r))
    120 }
    121 
    122 func (i ImmAlt) String() string {
    123 	return fmt.Sprintf("#%#x, %d", i.Val, i.Rot)
    124 }
    125 
    126 // A Label is a text (code) address.
    127 type Label uint32
    128 
    129 func (Label) IsArg() {}
    130 
    131 func (i Label) String() string {
    132 	return fmt.Sprintf("%#x", uint32(i))
    133 }
    134 
    135 // A Reg is a single register.
    136 // The zero value denotes R0, not the absence of a register.
    137 type Reg uint8
    138 
    139 const (
    140 	R0 Reg = iota
    141 	R1
    142 	R2
    143 	R3
    144 	R4
    145 	R5
    146 	R6
    147 	R7
    148 	R8
    149 	R9
    150 	R10
    151 	R11
    152 	R12
    153 	R13
    154 	R14
    155 	R15
    156 
    157 	S0
    158 	S1
    159 	S2
    160 	S3
    161 	S4
    162 	S5
    163 	S6
    164 	S7
    165 	S8
    166 	S9
    167 	S10
    168 	S11
    169 	S12
    170 	S13
    171 	S14
    172 	S15
    173 	S16
    174 	S17
    175 	S18
    176 	S19
    177 	S20
    178 	S21
    179 	S22
    180 	S23
    181 	S24
    182 	S25
    183 	S26
    184 	S27
    185 	S28
    186 	S29
    187 	S30
    188 	S31
    189 
    190 	D0
    191 	D1
    192 	D2
    193 	D3
    194 	D4
    195 	D5
    196 	D6
    197 	D7
    198 	D8
    199 	D9
    200 	D10
    201 	D11
    202 	D12
    203 	D13
    204 	D14
    205 	D15
    206 	D16
    207 	D17
    208 	D18
    209 	D19
    210 	D20
    211 	D21
    212 	D22
    213 	D23
    214 	D24
    215 	D25
    216 	D26
    217 	D27
    218 	D28
    219 	D29
    220 	D30
    221 	D31
    222 
    223 	APSR
    224 	APSR_nzcv
    225 	FPSCR
    226 
    227 	SP = R13
    228 	LR = R14
    229 	PC = R15
    230 )
    231 
    232 func (Reg) IsArg() {}
    233 
    234 func (r Reg) String() string {
    235 	switch r {
    236 	case APSR:
    237 		return "APSR"
    238 	case APSR_nzcv:
    239 		return "APSR_nzcv"
    240 	case FPSCR:
    241 		return "FPSCR"
    242 	case SP:
    243 		return "SP"
    244 	case PC:
    245 		return "PC"
    246 	case LR:
    247 		return "LR"
    248 	}
    249 	if R0 <= r && r <= R15 {
    250 		return fmt.Sprintf("R%d", int(r-R0))
    251 	}
    252 	if S0 <= r && r <= S31 {
    253 		return fmt.Sprintf("S%d", int(r-S0))
    254 	}
    255 	if D0 <= r && r <= D31 {
    256 		return fmt.Sprintf("D%d", int(r-D0))
    257 	}
    258 	return fmt.Sprintf("Reg(%d)", int(r))
    259 }
    260 
    261 // A RegX represents a fraction of a multi-value register.
    262 // The Index field specifies the index number,
    263 // but the size of the fraction is not specified.
    264 // It must be inferred from the instruction and the register type.
    265 // For example, in a VMOV instruction, RegX{D5, 1} represents
    266 // the top 32 bits of the 64-bit D5 register.
    267 type RegX struct {
    268 	Reg   Reg
    269 	Index int
    270 }
    271 
    272 func (RegX) IsArg() {}
    273 
    274 func (r RegX) String() string {
    275 	return fmt.Sprintf("%s[%d]", r.Reg, r.Index)
    276 }
    277 
    278 // A RegList is a register list.
    279 // Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list.
    280 type RegList uint16
    281 
    282 func (RegList) IsArg() {}
    283 
    284 func (r RegList) String() string {
    285 	var buf bytes.Buffer
    286 	fmt.Fprintf(&buf, "{")
    287 	sep := ""
    288 	for i := 0; i < 16; i++ {
    289 		if r&(1<<uint(i)) != 0 {
    290 			fmt.Fprintf(&buf, "%s%s", sep, Reg(i).String())
    291 			sep = ","
    292 		}
    293 	}
    294 	fmt.Fprintf(&buf, "}")
    295 	return buf.String()
    296 }
    297 
    298 // An Endian is the argument to the SETEND instruction.
    299 type Endian uint8
    300 
    301 const (
    302 	LittleEndian Endian = 0
    303 	BigEndian    Endian = 1
    304 )
    305 
    306 func (Endian) IsArg() {}
    307 
    308 func (e Endian) String() string {
    309 	if e != 0 {
    310 		return "BE"
    311 	}
    312 	return "LE"
    313 }
    314 
    315 // A Shift describes an ARM shift operation.
    316 type Shift uint8
    317 
    318 const (
    319 	ShiftLeft        Shift = 0 // left shift
    320 	ShiftRight       Shift = 1 // logical (unsigned) right shift
    321 	ShiftRightSigned Shift = 2 // arithmetic (signed) right shift
    322 	RotateRight      Shift = 3 // right rotate
    323 	RotateRightExt   Shift = 4 // right rotate through carry (Count will always be 1)
    324 )
    325 
    326 var shiftName = [...]string{
    327 	"LSL", "LSR", "ASR", "ROR", "RRX",
    328 }
    329 
    330 func (s Shift) String() string {
    331 	if s < 5 {
    332 		return shiftName[s]
    333 	}
    334 	return fmt.Sprintf("Shift(%d)", int(s))
    335 }
    336 
    337 // A RegShift is a register shifted by a constant.
    338 type RegShift struct {
    339 	Reg   Reg
    340 	Shift Shift
    341 	Count uint8
    342 }
    343 
    344 func (RegShift) IsArg() {}
    345 
    346 func (r RegShift) String() string {
    347 	return fmt.Sprintf("%s %s #%d", r.Reg, r.Shift, r.Count)
    348 }
    349 
    350 // A RegShiftReg is a register shifted by a register.
    351 type RegShiftReg struct {
    352 	Reg      Reg
    353 	Shift    Shift
    354 	RegCount Reg
    355 }
    356 
    357 func (RegShiftReg) IsArg() {}
    358 
    359 func (r RegShiftReg) String() string {
    360 	return fmt.Sprintf("%s %s %s", r.Reg, r.Shift, r.RegCount)
    361 }
    362 
    363 // A PCRel describes a memory address (usually a code label)
    364 // as a distance relative to the program counter.
    365 // TODO(rsc): Define which program counter (PC+4? PC+8? PC?).
    366 type PCRel int32
    367 
    368 func (PCRel) IsArg() {}
    369 
    370 func (r PCRel) String() string {
    371 	return fmt.Sprintf("PC%+#x", int32(r))
    372 }
    373 
    374 // An AddrMode is an ARM addressing mode.
    375 type AddrMode uint8
    376 
    377 const (
    378 	_             AddrMode = iota
    379 	AddrPostIndex          // [R], X  use address R, set R = R + X
    380 	AddrPreIndex           // [R, X]!  use address R + X, set R = R + X
    381 	AddrOffset             // [R, X]  use address R + X
    382 	AddrLDM                // R  [R] but formats as R, for LDM/STM only
    383 	AddrLDM_WB             // R! - [R], X where X is instruction-specific amount, for LDM/STM only
    384 )
    385 
    386 // A Mem is a memory reference made up of a base R and index expression X.
    387 // The effective memory address is R or R+X depending on AddrMode.
    388 // The index expression is X = Sign*(Index Shift Count) + Offset,
    389 // but in any instruction either Sign = 0 or Offset = 0.
    390 type Mem struct {
    391 	Base   Reg
    392 	Mode   AddrMode
    393 	Sign   int8
    394 	Index  Reg
    395 	Shift  Shift
    396 	Count  uint8
    397 	Offset int16
    398 }
    399 
    400 func (Mem) IsArg() {}
    401 
    402 func (m Mem) String() string {
    403 	R := m.Base.String()
    404 	X := ""
    405 	if m.Sign != 0 {
    406 		X = "+"
    407 		if m.Sign < 0 {
    408 			X = "-"
    409 		}
    410 		X += m.Index.String()
    411 		if m.Shift != ShiftLeft || m.Count != 0 {
    412 			X += fmt.Sprintf(", %s #%d", m.Shift, m.Count)
    413 		}
    414 	} else {
    415 		X = fmt.Sprintf("#%d", m.Offset)
    416 	}
    417 
    418 	switch m.Mode {
    419 	case AddrOffset:
    420 		if X == "#0" {
    421 			return fmt.Sprintf("[%s]", R)
    422 		}
    423 		return fmt.Sprintf("[%s, %s]", R, X)
    424 	case AddrPreIndex:
    425 		return fmt.Sprintf("[%s, %s]!", R, X)
    426 	case AddrPostIndex:
    427 		return fmt.Sprintf("[%s], %s", R, X)
    428 	case AddrLDM:
    429 		if X == "#0" {
    430 			return R
    431 		}
    432 	case AddrLDM_WB:
    433 		if X == "#0" {
    434 			return R + "!"
    435 		}
    436 	}
    437 	return fmt.Sprintf("[%s Mode(%d) %s]", R, int(m.Mode), X)
    438 }
    439