github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/cmd/asm/internal/arch/arm.go (about)

     1  // Copyright 2015 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  // This file encapsulates some of the odd characteristics of the ARM
     6  // instruction set, to minimize its interaction with the core of the
     7  // assembler.
     8  
     9  package arch
    10  
    11  import (
    12  	"strings"
    13  
    14  	"cmd/internal/obj"
    15  	"cmd/internal/obj/arm"
    16  )
    17  
    18  var armLS = map[string]uint8{
    19  	"U":  arm.C_UBIT,
    20  	"S":  arm.C_SBIT,
    21  	"W":  arm.C_WBIT,
    22  	"P":  arm.C_PBIT,
    23  	"PW": arm.C_WBIT | arm.C_PBIT,
    24  	"WP": arm.C_WBIT | arm.C_PBIT,
    25  }
    26  
    27  var armSCOND = map[string]uint8{
    28  	"EQ":  arm.C_SCOND_EQ,
    29  	"NE":  arm.C_SCOND_NE,
    30  	"CS":  arm.C_SCOND_HS,
    31  	"HS":  arm.C_SCOND_HS,
    32  	"CC":  arm.C_SCOND_LO,
    33  	"LO":  arm.C_SCOND_LO,
    34  	"MI":  arm.C_SCOND_MI,
    35  	"PL":  arm.C_SCOND_PL,
    36  	"VS":  arm.C_SCOND_VS,
    37  	"VC":  arm.C_SCOND_VC,
    38  	"HI":  arm.C_SCOND_HI,
    39  	"LS":  arm.C_SCOND_LS,
    40  	"GE":  arm.C_SCOND_GE,
    41  	"LT":  arm.C_SCOND_LT,
    42  	"GT":  arm.C_SCOND_GT,
    43  	"LE":  arm.C_SCOND_LE,
    44  	"AL":  arm.C_SCOND_NONE,
    45  	"U":   arm.C_UBIT,
    46  	"S":   arm.C_SBIT,
    47  	"W":   arm.C_WBIT,
    48  	"P":   arm.C_PBIT,
    49  	"PW":  arm.C_WBIT | arm.C_PBIT,
    50  	"WP":  arm.C_WBIT | arm.C_PBIT,
    51  	"F":   arm.C_FBIT,
    52  	"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
    53  	"IAW": arm.C_WBIT | arm.C_UBIT,
    54  	"DBW": arm.C_WBIT | arm.C_PBIT,
    55  	"DAW": arm.C_WBIT,
    56  	"IB":  arm.C_PBIT | arm.C_UBIT,
    57  	"IA":  arm.C_UBIT,
    58  	"DB":  arm.C_PBIT,
    59  	"DA":  0,
    60  }
    61  
    62  var armJump = map[string]bool{
    63  	"B":    true,
    64  	"BL":   true,
    65  	"BEQ":  true,
    66  	"BNE":  true,
    67  	"BCS":  true,
    68  	"BHS":  true,
    69  	"BCC":  true,
    70  	"BLO":  true,
    71  	"BMI":  true,
    72  	"BPL":  true,
    73  	"BVS":  true,
    74  	"BVC":  true,
    75  	"BHI":  true,
    76  	"BLS":  true,
    77  	"BGE":  true,
    78  	"BLT":  true,
    79  	"BGT":  true,
    80  	"BLE":  true,
    81  	"CALL": true,
    82  	"JMP":  true,
    83  }
    84  
    85  func jumpArm(word string) bool {
    86  	return armJump[word]
    87  }
    88  
    89  // IsARMCMP reports whether the op (as defined by an arm.A* constant) is
    90  // one of the comparison instructions that require special handling.
    91  func IsARMCMP(op int) bool {
    92  	switch op {
    93  	case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
    94  		return true
    95  	}
    96  	return false
    97  }
    98  
    99  // IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
   100  // one of the STREX-like instructions that require special handling.
   101  func IsARMSTREX(op int) bool {
   102  	switch op {
   103  	case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
   104  		return true
   105  	}
   106  	return false
   107  }
   108  
   109  // MCR is not defined by the obj/arm; instead we define it privately here.
   110  // It is encoded as an MRC with a bit inside the instruction word,
   111  // passed to arch.ARMMRCOffset.
   112  const aMCR = arm.ALAST + 1
   113  
   114  // IsARMMRC reports whether the op (as defined by an arm.A* constant) is
   115  // MRC or MCR
   116  func IsARMMRC(op int) bool {
   117  	switch op {
   118  	case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
   119  		return true
   120  	}
   121  	return false
   122  }
   123  
   124  // IsARMFloatCmp reports whether the op is a floating comparison instruction.
   125  func IsARMFloatCmp(op int) bool {
   126  	switch op {
   127  	case arm.ACMPF, arm.ACMPD:
   128  		return true
   129  	}
   130  	return false
   131  }
   132  
   133  // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   134  // The difference between MRC and MCR is represented by a bit high in the word, not
   135  // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   136  // we return the opcode for MRC so that asm doesn't need to import obj/arm.
   137  func ARMMRCOffset(op int, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 int16, ok bool) {
   138  	op1 := int64(0)
   139  	if op == arm.AMRC {
   140  		op1 = 1
   141  	}
   142  	bits, ok := ParseARMCondition(cond)
   143  	if !ok {
   144  		return
   145  	}
   146  	offset = (0xe << 24) | // opcode
   147  		(op1 << 20) | // MCR/MRC
   148  		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   149  		((x0 & 15) << 8) | //coprocessor number
   150  		((x1 & 7) << 21) | // coprocessor operation
   151  		((x2 & 15) << 12) | // ARM register
   152  		((x3 & 15) << 16) | // Crn
   153  		((x4 & 15) << 0) | // Crm
   154  		((x5 & 7) << 5) | // coprocessor information
   155  		(1 << 4) /* must be set */
   156  	return offset, arm.AMRC, true
   157  }
   158  
   159  // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   160  // MULA, MULAWT or MULAWB, the 4-operand instructions.
   161  func IsARMMULA(op int) bool {
   162  	switch op {
   163  	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
   164  		return true
   165  	}
   166  	return false
   167  }
   168  
   169  var bcode = []int{
   170  	arm.ABEQ,
   171  	arm.ABNE,
   172  	arm.ABCS,
   173  	arm.ABCC,
   174  	arm.ABMI,
   175  	arm.ABPL,
   176  	arm.ABVS,
   177  	arm.ABVC,
   178  	arm.ABHI,
   179  	arm.ABLS,
   180  	arm.ABGE,
   181  	arm.ABLT,
   182  	arm.ABGT,
   183  	arm.ABLE,
   184  	arm.AB,
   185  	obj.ANOP,
   186  }
   187  
   188  // ARMConditionCodes handles the special condition code situation for the ARM.
   189  // It returns a boolean to indicate success; failure means cond was unrecognized.
   190  func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   191  	if cond == "" {
   192  		return true
   193  	}
   194  	bits, ok := ParseARMCondition(cond)
   195  	if !ok {
   196  		return false
   197  	}
   198  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   199  	if prog.As == arm.AB {
   200  		prog.As = int16(bcode[(bits^arm.C_SCOND_XOR)&0xf])
   201  		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   202  	}
   203  	prog.Scond = bits
   204  	return true
   205  }
   206  
   207  // ParseARMCondition parses the conditions attached to an ARM instruction.
   208  // The input is a single string consisting of period-separated condition
   209  // codes, such as ".P.W". An initial period is ignored.
   210  func ParseARMCondition(cond string) (uint8, bool) {
   211  	return parseARMCondition(cond, armLS, armSCOND)
   212  }
   213  
   214  func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   215  	if strings.HasPrefix(cond, ".") {
   216  		cond = cond[1:]
   217  	}
   218  	if cond == "" {
   219  		return arm.C_SCOND_NONE, true
   220  	}
   221  	names := strings.Split(cond, ".")
   222  	bits := uint8(0)
   223  	for _, name := range names {
   224  		if b, present := ls[name]; present {
   225  			bits |= b
   226  			continue
   227  		}
   228  		if b, present := scond[name]; present {
   229  			bits = (bits &^ arm.C_SCOND) | b
   230  			continue
   231  		}
   232  		return 0, false
   233  	}
   234  	return bits, true
   235  }
   236  
   237  func armRegisterNumber(name string, n int16) (int16, bool) {
   238  	if n < 0 || 15 < n {
   239  		return 0, false
   240  	}
   241  	switch name {
   242  	case "R":
   243  		return arm.REG_R0 + n, true
   244  	case "F":
   245  		return arm.REG_F0 + n, true
   246  	}
   247  	return 0, false
   248  }