rsc.io/go@v0.0.0-20150416155037-e040fd465409/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  }
    83  
    84  func jumpArm(word string) bool {
    85  	return armJump[word]
    86  }
    87  
    88  // IsARMCMP reports whether the op (as defined by an arm.A* constant) is
    89  // one of the comparison instructions that require special handling.
    90  func IsARMCMP(op int) bool {
    91  	switch op {
    92  	case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
    93  		return true
    94  	}
    95  	return false
    96  }
    97  
    98  // IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
    99  // one of the STREX-like instructions that require special handling.
   100  func IsARMSTREX(op int) bool {
   101  	switch op {
   102  	case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
   103  		return true
   104  	}
   105  	return false
   106  }
   107  
   108  // MCR is not defined by the obj/arm; instead we define it privately here.
   109  // It is encoded as an MRC with a bit inside the instruction word,
   110  // passed to arch.ARMMRCOffset.
   111  const aMCR = arm.ALAST + 1
   112  
   113  // IsARMMRC reports whether the op (as defined by an arm.A* constant) is
   114  // MRC or MCR
   115  func IsARMMRC(op int) bool {
   116  	switch op {
   117  	case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
   118  		return true
   119  	}
   120  	return false
   121  }
   122  
   123  // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   124  // The difference between MRC and MCR is represented by a bit high in the word, not
   125  // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   126  // we return the opcode for MRC so that asm doesn't need to import obj/arm.
   127  func ARMMRCOffset(op int, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 int16, ok bool) {
   128  	op1 := int64(0)
   129  	if op == arm.AMRC {
   130  		op1 = 1
   131  	}
   132  	bits, ok := ParseARMCondition(cond)
   133  	if !ok {
   134  		return
   135  	}
   136  	offset = (0xe << 24) | // opcode
   137  		(op1 << 20) | // MCR/MRC
   138  		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   139  		((x0 & 15) << 8) | //coprocessor number
   140  		((x1 & 7) << 21) | // coprocessor operation
   141  		((x2 & 15) << 12) | // ARM register
   142  		((x3 & 15) << 16) | // Crn
   143  		((x4 & 15) << 0) | // Crm
   144  		((x5 & 7) << 5) | // coprocessor information
   145  		(1 << 4) /* must be set */
   146  	return offset, arm.AMRC, true
   147  }
   148  
   149  // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   150  // MULA, MULAWT or MULAWB, the 4-operand instructions.
   151  func IsARMMULA(op int) bool {
   152  	switch op {
   153  	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
   154  		return true
   155  	}
   156  	return false
   157  }
   158  
   159  var bcode = []int{
   160  	arm.ABEQ,
   161  	arm.ABNE,
   162  	arm.ABCS,
   163  	arm.ABCC,
   164  	arm.ABMI,
   165  	arm.ABPL,
   166  	arm.ABVS,
   167  	arm.ABVC,
   168  	arm.ABHI,
   169  	arm.ABLS,
   170  	arm.ABGE,
   171  	arm.ABLT,
   172  	arm.ABGT,
   173  	arm.ABLE,
   174  	arm.AB,
   175  	obj.ANOP,
   176  }
   177  
   178  // ARMConditionCodes handles the special condition code situation for the ARM.
   179  // It returns a boolean to indicate success; failure means cond was unrecognized.
   180  func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   181  	if cond == "" {
   182  		return true
   183  	}
   184  	bits, ok := ParseARMCondition(cond)
   185  	if !ok {
   186  		return false
   187  	}
   188  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   189  	if prog.As == arm.AB {
   190  		prog.As = int16(bcode[(bits^arm.C_SCOND_XOR)&0xf])
   191  		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   192  	}
   193  	prog.Scond = bits
   194  	return true
   195  }
   196  
   197  // ParseARMCondition parses the conditions attached to an ARM instruction.
   198  // The input is a single string consisting of period-separated condition
   199  // codes, such as ".P.W". An initial period is ignored.
   200  func ParseARMCondition(cond string) (uint8, bool) {
   201  	return parseARMCondition(cond, armLS, armSCOND)
   202  }
   203  
   204  func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   205  	if strings.HasPrefix(cond, ".") {
   206  		cond = cond[1:]
   207  	}
   208  	if cond == "" {
   209  		return arm.C_SCOND_NONE, true
   210  	}
   211  	names := strings.Split(cond, ".")
   212  	bits := uint8(0)
   213  	for _, name := range names {
   214  		if b, present := ls[name]; present {
   215  			bits |= b
   216  			continue
   217  		}
   218  		if b, present := scond[name]; present {
   219  			bits = (bits &^ arm.C_SCOND) | b
   220  			continue
   221  		}
   222  		return 0, false
   223  	}
   224  	return bits, true
   225  }
   226  
   227  func armRegisterNumber(name string, n int16) (int16, bool) {
   228  	if n < 0 || 15 < n {
   229  		return 0, false
   230  	}
   231  	switch name {
   232  	case "R":
   233  		return arm.REG_R0 + n, true
   234  	case "F":
   235  		return arm.REG_F0 + n, true
   236  	}
   237  	return 0, false
   238  }