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 }