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 }