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