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 }