github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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  // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
   125  // The difference between MRC and MCR is represented by a bit high in the word, not
   126  // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
   127  // we return the opcode for MRC so that asm doesn't need to import obj/arm.
   128  func ARMMRCOffset(op int, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 int16, ok bool) {
   129  	op1 := int64(0)
   130  	if op == arm.AMRC {
   131  		op1 = 1
   132  	}
   133  	bits, ok := ParseARMCondition(cond)
   134  	if !ok {
   135  		return
   136  	}
   137  	offset = (0xe << 24) | // opcode
   138  		(op1 << 20) | // MCR/MRC
   139  		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
   140  		((x0 & 15) << 8) | //coprocessor number
   141  		((x1 & 7) << 21) | // coprocessor operation
   142  		((x2 & 15) << 12) | // ARM register
   143  		((x3 & 15) << 16) | // Crn
   144  		((x4 & 15) << 0) | // Crm
   145  		((x5 & 7) << 5) | // coprocessor information
   146  		(1 << 4) /* must be set */
   147  	return offset, arm.AMRC, true
   148  }
   149  
   150  // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
   151  // MULA, MULAWT or MULAWB, the 4-operand instructions.
   152  func IsARMMULA(op int) bool {
   153  	switch op {
   154  	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
   155  		return true
   156  	}
   157  	return false
   158  }
   159  
   160  var bcode = []int{
   161  	arm.ABEQ,
   162  	arm.ABNE,
   163  	arm.ABCS,
   164  	arm.ABCC,
   165  	arm.ABMI,
   166  	arm.ABPL,
   167  	arm.ABVS,
   168  	arm.ABVC,
   169  	arm.ABHI,
   170  	arm.ABLS,
   171  	arm.ABGE,
   172  	arm.ABLT,
   173  	arm.ABGT,
   174  	arm.ABLE,
   175  	arm.AB,
   176  	obj.ANOP,
   177  }
   178  
   179  // ARMConditionCodes handles the special condition code situation for the ARM.
   180  // It returns a boolean to indicate success; failure means cond was unrecognized.
   181  func ARMConditionCodes(prog *obj.Prog, cond string) bool {
   182  	if cond == "" {
   183  		return true
   184  	}
   185  	bits, ok := ParseARMCondition(cond)
   186  	if !ok {
   187  		return false
   188  	}
   189  	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
   190  	if prog.As == arm.AB {
   191  		prog.As = int16(bcode[(bits^arm.C_SCOND_XOR)&0xf])
   192  		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
   193  	}
   194  	prog.Scond = bits
   195  	return true
   196  }
   197  
   198  // ParseARMCondition parses the conditions attached to an ARM instruction.
   199  // The input is a single string consisting of period-separated condition
   200  // codes, such as ".P.W". An initial period is ignored.
   201  func ParseARMCondition(cond string) (uint8, bool) {
   202  	return parseARMCondition(cond, armLS, armSCOND)
   203  }
   204  
   205  func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
   206  	if strings.HasPrefix(cond, ".") {
   207  		cond = cond[1:]
   208  	}
   209  	if cond == "" {
   210  		return arm.C_SCOND_NONE, true
   211  	}
   212  	names := strings.Split(cond, ".")
   213  	bits := uint8(0)
   214  	for _, name := range names {
   215  		if b, present := ls[name]; present {
   216  			bits |= b
   217  			continue
   218  		}
   219  		if b, present := scond[name]; present {
   220  			bits = (bits &^ arm.C_SCOND) | b
   221  			continue
   222  		}
   223  		return 0, false
   224  	}
   225  	return bits, true
   226  }
   227  
   228  func armRegisterNumber(name string, n int16) (int16, bool) {
   229  	if n < 0 || 15 < n {
   230  		return 0, false
   231  	}
   232  	switch name {
   233  	case "R":
   234  		return arm.REG_R0 + n, true
   235  	case "F":
   236  		return arm.REG_F0 + n, true
   237  	}
   238  	return 0, false
   239  }