golang.org/x/arch@v0.17.0/arm/armmap/map.go (about) 1 // Copyright 2014 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 // Armmap constructs the ARM opcode map from the instruction set CSV file. 6 // 7 // Usage: 8 // 9 // armmap [-fmt=format] arm.csv 10 // 11 // The known output formats are: 12 // 13 // text (default) - print decoding tree in text form 14 // decoder - print decoding tables for the armasm package 15 package main 16 17 import ( 18 "bufio" 19 "encoding/csv" 20 "flag" 21 "fmt" 22 "log" 23 "os" 24 "sort" 25 "strconv" 26 "strings" 27 ) 28 29 var format = flag.String("fmt", "text", "output format: text, decoder") 30 31 var inputFile string 32 33 func usage() { 34 fmt.Fprintf(os.Stderr, "usage: armmap [-fmt=format] x86.csv\n") 35 os.Exit(2) 36 } 37 38 func main() { 39 log.SetFlags(0) 40 log.SetPrefix("armmap: ") 41 42 flag.Usage = usage 43 flag.Parse() 44 if flag.NArg() != 1 { 45 usage() 46 } 47 48 inputFile = flag.Arg(0) 49 50 var print func(*Prog) 51 switch *format { 52 default: 53 log.Fatalf("unknown output format %q", *format) 54 case "text": 55 print = printText 56 case "decoder": 57 print = printDecoder 58 } 59 60 p, err := readCSV(flag.Arg(0)) 61 if err != nil { 62 log.Fatal(err) 63 } 64 65 print(p) 66 } 67 68 // readCSV reads the CSV file and returns the corresponding Prog. 69 // It may print details about problems to standard error using the log package. 70 func readCSV(file string) (*Prog, error) { 71 // Read input. 72 // Skip leading blank and # comment lines. 73 f, err := os.Open(file) 74 if err != nil { 75 return nil, err 76 } 77 b := bufio.NewReader(f) 78 for { 79 c, err := b.ReadByte() 80 if err != nil { 81 break 82 } 83 if c == '\n' { 84 continue 85 } 86 if c == '#' { 87 b.ReadBytes('\n') 88 continue 89 } 90 b.UnreadByte() 91 break 92 } 93 table, err := csv.NewReader(b).ReadAll() 94 if err != nil { 95 return nil, fmt.Errorf("parsing %s: %v", file, err) 96 } 97 if len(table) == 0 { 98 return nil, fmt.Errorf("empty csv input") 99 } 100 if len(table[0]) < 5 { 101 return nil, fmt.Errorf("csv too narrow: need at least five columns") 102 } 103 104 p := &Prog{} 105 for _, row := range table { 106 add(p, row[0], row[1], row[2], row[3], row[4]) 107 } 108 return p, nil 109 } 110 111 type Prog struct { 112 Inst []Inst 113 OpRanges map[string]string 114 } 115 116 type Inst struct { 117 Text string 118 Encoding string 119 Mask uint32 120 Value uint32 121 Priority int 122 OpBase string 123 OpBits uint64 124 Args []string 125 } 126 127 type Arg struct { 128 Name string 129 Bits uint64 130 } 131 132 // add adds the entry from the CSV described by maskstr, valuestr, text, encoding, tags 133 // to the program p. 134 func add(p *Prog, maskstr, valuestr, text, encoding, tags string) { 135 if strings.Contains(tags, "pseudo") { 136 return 137 } 138 139 // For now, ignore the VFP floating point instructions. 140 if strings.HasPrefix(text, "V") && !strings.Contains(tags, "vfp") { 141 // TODO 142 return 143 } 144 145 mask, err := strconv.ParseUint(maskstr, 0, 32) 146 if err != nil { 147 log.Printf("invalid mask %q", maskstr) 148 return 149 } 150 value, err := strconv.ParseUint(valuestr, 0, 32) 151 if err != nil { 152 log.Printf("invalid value %q", valuestr) 153 return 154 } 155 156 // Parse encoding, building size and offset of each field. 157 // The first field in the encoding is the largest offset. 158 fuzzy := uint32(0) // mask of 'should be' bits 159 fieldOffset := map[string]int{} 160 fieldWidth := map[string]int{} 161 off := 32 162 for _, f := range strings.Split(encoding, "|") { 163 n := 1 164 if i := strings.Index(f, ":"); i >= 0 { 165 n, _ = strconv.Atoi(f[i+1:]) 166 } 167 off -= n 168 fieldOffset[f] = off 169 fieldWidth[f] = n 170 if f == "(0)" || f == "(1)" { 171 fuzzy |= 1 << uint(off) 172 } 173 } 174 if off != 0 { 175 fmt.Fprintf(os.Stderr, "%s: counted %d bits in %s\n", text, 32-off, encoding) 176 } 177 178 // Track which encoding fields we found uses for. 179 // If we do not find a use for a field, that's an error in the input tables. 180 fieldUsed := map[string]bool{} 181 182 // Split text into opcode and arguments. 183 var op, argstr string 184 if i := strings.Index(text, " "); i >= 0 { 185 op = text[:i] 186 argstr = text[i:] 187 } else { 188 op = text 189 } 190 op = strings.TrimSpace(op) 191 argstr = strings.TrimSpace(argstr) 192 193 // Parse opcode suffixes. 194 i := strings.Index(op, "<") 195 if i < 0 { 196 i = len(op) 197 } 198 if j := strings.Index(op, "{"); j >= 0 && j < i { 199 i = j 200 } 201 op, suffix := op[:i], op[i:] 202 if suffix != "" && opSuffix[suffix] == "" { 203 fmt.Fprintf(os.Stderr, "%s: invalid op suffix %q in %s\n", text, suffix, op+suffix) 204 } 205 206 // Make sure fields needed by opcode suffix are available. 207 for _, f := range strings.Split(opSuffix[suffix], ",") { 208 if f != "" && fieldWidth[f] == 0 { 209 fmt.Fprintf(os.Stderr, "%s: opsuffix %s missing %s in encoding %s\n", text, suffix, f, encoding) 210 } 211 fieldUsed[f] = true 212 } 213 214 // Build list of opcodes that can be generated by this suffix. 215 // For example, the opcodes generated by ADD<c> are ADD.EQ, ADD.NE, etc. 216 // To simplify the decoding of instruction opcodes, we arrange that this 217 // sequence aligns with the encoding, so that decoding amounts to extracting 218 // the right bits, concatenating them, and adding them to the first opcode in 219 // the sequence. If the condition code is present, we always place it in the 220 // low order bits, so that x&^15 == FOO_EQ tests whether x is any of the 221 // conditional FOO instructions. 222 ops := []string{op} 223 opBits := uint64(0) // record of bits to extract and add to opcode base 224 opFields := strings.Split(opSuffix[suffix], ",") 225 // First the optional elements, like {S} meaning "" or ".S". 226 for strings.HasPrefix(suffix, "{") { 227 i := strings.Index(suffix, "}") 228 var f, option string 229 option, suffix = suffix[1:i], suffix[i+1:] 230 f, opFields = opFields[0], opFields[1:] 231 if option == "W" { 232 // The {W} option on PLD{W} uses the R bit which is !W. 233 ops = cross(ops, "."+option, "") 234 } else { 235 ops = cross(ops, "", "."+option) 236 } 237 if fieldWidth[f] != 1 { 238 fmt.Fprintf(os.Stderr, "%s: have %d bits for {%s}\n", text, fieldWidth[f], option) 239 } 240 // opBits is a sequence of 16-bit chunks describing contiguous bit sections. 241 // Each chunk is 8-bit offset followed by 8-bit size. 242 opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | 1 243 } 244 // Then the true field substitutions. 245 haveCond := false 246 for strings.Contains(suffix, "<") { 247 var f, literal, x string 248 if len(opFields) == 0 { 249 fmt.Fprintf(os.Stderr, "%s: ran out of suffix fields for <%s>\n", text, x) 250 break 251 } 252 f, opFields = opFields[0], opFields[1:] 253 i := strings.Index(suffix, "<") 254 j := strings.Index(suffix, ">") 255 literal, x, suffix = suffix[:i], suffix[i+1:j], suffix[j+1:] 256 257 // Add leading literal text to all opcodes. 258 ops = cross(ops, literal) 259 260 // The <c> condition can happen anywhere in the opcode text 261 // but we want to generate the actual variation in the low bits 262 // of the list index. Remember when and where we've seen <c> and apply 263 // it after the loop has finished. 264 if x == "c" && f == "cond:4" { 265 haveCond = true 266 ops = cross(ops, "_COND_") 267 continue 268 } 269 270 // Otherwise, choices[x] lists the possible expansions of <x>. 271 // If <x> is of the form <A,B,C> the choices are A, B, and C. 272 expand := choices[x] 273 if expand == nil && strings.Contains(x, ",") { 274 expand = strings.Split(x, ",") 275 } 276 if expand == nil { 277 fmt.Fprintf(os.Stderr, "%s: unknown choices for <%s>\n", text, x) 278 expand = []string{x} 279 } else if len(expand) != 1<<uint(fieldWidth[f]) { 280 fmt.Fprintf(os.Stderr, "%s: have %d choices for <%s> but %d bits\n", text, len(expand), x, fieldWidth[f]) 281 } 282 opBits = opBits<<16 | uint64(fieldOffset[f])<<8 | uint64(fieldWidth[f]) 283 ops = cross(ops, expand...) 284 } 285 if haveCond { 286 // Apply condtional suffix last. 287 opBits = opBits<<16 | 28<<8 | 4 288 ops = crossCond(ops) 289 } 290 ops = cross(ops, suffix) 291 292 // Now ops is a list of opcodes generated by this opcode pattern. 293 // We want to make sure that we can arrange for those opcodes to 294 // happen consecutively in the final opcode numbering. 295 // Record in p.OpRanges[op] the required consecutive sequence of 296 // opcode that includes op. To make searches easier, we record 297 // the sequence as a comma-separated list of strings with commas 298 // on both ends: [A, B] encodes as ",A,B,". 299 if p.OpRanges == nil { 300 p.OpRanges = make(map[string]string) 301 } 302 opstr := "," + strings.Join(ops, ",") + "," 303 for _, op := range ops { 304 if old := p.OpRanges[op]; old != "" && old != opstr { 305 if strings.Contains(old, opstr) { 306 opstr = old 307 } else if strings.Contains(opstr, old) { 308 // great, do nothing 309 } else { 310 // It would also be okay if there is some subsequence s such that 311 // old = x+s and opstr = s+y (or vice versa), in which case we should 312 // record opstr = x+s+y. However, this has not come up in practice. 313 // Failing that, we can't satisfy the sequencing requirements. 314 fmt.Fprintf(os.Stderr, "%s: %s appears in both %s and %s\n", text, op, old, opstr) 315 } 316 } 317 } 318 for _, op := range strings.Split(opstr, ",") { 319 if op != "" { 320 p.OpRanges[op] = opstr 321 } 322 } 323 324 // Process the arguments, building a list of argument descriptions. 325 // Each argument description has the form <argument>|field@off|field@off... 326 // where the |field@off suffixes give the name and location of the fields 327 // needed by the argument. Each such string maps to a different decoding 328 // type in the generated table, according to the argOps map. 329 var args []string 330 for argstr != "" { 331 // Find longest match among argSuffixes pieces. 332 best := 0 333 for a := range argSuffixes { 334 if argstr == a || strings.HasPrefix(argstr, a+",") { 335 if best < len(a) { 336 best = len(a) 337 } 338 } 339 } 340 if best == 0 { 341 fmt.Fprintf(os.Stderr, "%s: unknown arg %s\n", text, argstr) 342 break 343 } 344 345 var arg, desc string 346 arg, argstr = argstr[:best], strings.TrimSpace(strings.TrimLeft(argstr[best:], ",")) 347 desc = arg 348 for _, f := range strings.Split(argSuffixes[desc], ",") { 349 if f == "" { 350 continue 351 } 352 if fieldWidth[f] == 0 { 353 fmt.Fprintf(os.Stderr, "%s: arg %s missing %s in encoding %s\n", text, arg, f, encoding) 354 } 355 fieldUsed[f] = true 356 desc += fmt.Sprintf("|%s@%d", f, fieldOffset[f]) 357 } 358 args = append(args, desc) 359 } 360 361 // Check that all encoding fields were used by suffix or argument decoding. 362 for f := range fieldWidth { 363 switch f { 364 case "0", "1", "(0)", "(1)": 365 // ok 366 default: 367 if !fieldUsed[f] { 368 fmt.Fprintf(os.Stderr, "%s: encoding field %s not used in %s\n", text, f, encoding) 369 } 370 } 371 } 372 373 // Determine decoding priority. Instructions that say 'SEE X' in the tag 374 // are considered lower priority than ones that don't. In theory the 375 // structure described by the SEE tags might be richer than that, but 376 // in practice it only has those two levels. 377 // We leave space for two more priorities according to whether the 378 // fuzzy bits are set correctly. The full set of priorities then is: 379 // 380 // 4 - no SEE tag, fuzzy bits all match 381 // 3 - no SEE tag, some fuzzy bits don't match 382 // 2 - SEE tag, fuzzy bits all match 383 // 1 - SEE tag, some fuzzy bits don't match 384 // 385 // You could argue for swapping the middle two levels but so far 386 // it has not been an issue. 387 pri := 4 388 if strings.Contains(tags, "SEE") { 389 pri = 2 390 } 391 392 inst := Inst{ 393 Text: text, 394 Encoding: encoding, 395 Mask: uint32(mask), 396 Value: uint32(value), 397 Priority: pri, 398 OpBase: ops[0], 399 OpBits: opBits, 400 Args: args, 401 } 402 p.Inst = append(p.Inst, inst) 403 404 if fuzzy != 0 { 405 inst.Mask &^= fuzzy 406 inst.Priority-- 407 p.Inst = append(p.Inst, inst) 408 } 409 } 410 411 // opSuffix describes the encoding fields used to resolve a given opcode suffix. 412 var opSuffix = map[string]string{ 413 "<ADD,SUB>": "op", 414 "<BIF,BIT,BSL>": "op:2", 415 "<MLA,MLS><c>.F<32,64>": "op,cond:4,sz", 416 "<MLS,MLA><c>.F<32,64>": "op,cond:4,sz", 417 "<BT,TB><c>": "tb,cond:4", 418 "<TBL,TBX>.8": "op", 419 "<c>": "cond:4", 420 "<c>.32": "cond:4", 421 "<c>.F<32,64>": "cond:4,sz", 422 "<x><y><c>": "N,M,cond:4", 423 "<y><c>": "M,cond:4", 424 "{B}<c>": "B,cond:4", 425 "{E}<c>.F<32,64>": "E,cond:4,sz", 426 "{R}<c>": "R,cond:4", 427 "<c>.F<32,64>.<U,S>32": "cond:4,sz,op", 428 "<R,><c>.<U,S>32.F<32,64>": "op,cond:4,signed,sz", 429 "{S}<c>": "S,cond:4", 430 "{W}": "R", 431 "{X}<c>": "M,cond:4", 432 "<B,T><c>.<F32.F16,F16.F32>": "T,cond:4,op", 433 "<c>.<F64.F32,F32.F64>": "cond:4,sz", 434 "<c>.FX<S,U><16,32>.F<32,64>": "cond:4,U,sx,sz", 435 "<c>.F<32,64>.FX<S,U><16,32>": "cond:4,sz,U,sx", 436 } 437 438 // choices[x] describes the choices for filling in "<"+x+">" in an opcode suffix. 439 // Opcodes that end up containing ZZ take up a numeric sequence value but are 440 // not exported in the package API. 441 var choices = map[string][]string{ 442 "c": {".EQ", ".NE", ".CS", ".CC", ".MI", ".PL", ".VS", ".VC", ".HI", ".LS", ".GE", ".LT", ".GT", ".LE", "", ".ZZ"}, 443 "x": {"B", "T"}, 444 "y": {"B", "T"}, 445 } 446 447 // argOps maps from argument descriptions to internal decoder name. 448 var argOps = map[string]string{ 449 // 4-bit register encodings 450 "<Rm>|Rm:4@0": "arg_R_0", 451 "<Rn>|Rn:4@0": "arg_R_0", 452 "<Rt>|Rt:4@0": "arg_R_0", 453 "<Rm>|Rm:4@8": "arg_R_8", 454 "<Ra>|Ra:4@12": "arg_R_12", 455 "<Rd>|Rd:4@12": "arg_R_12", 456 "<RdLo>|RdLo:4@12": "arg_R_12", 457 "<Rt>|Rt:4@12": "arg_R_12", 458 "<Rt_nzcv>|Rt:4@12": "arg_R_12_nzcv", 459 "<Rd>|Rd:4@16": "arg_R_16", 460 "<RdHi>|RdHi:4@16": "arg_R_16", 461 "<Rn>|Rn:4@16": "arg_R_16", 462 463 // first and second of consecutive register pair 464 "<Rt1>|Rt:4@0": "arg_R1_0", 465 "<Rt1>|Rt:4@12": "arg_R1_12", 466 "<Rt2>|Rt:4@0": "arg_R2_0", 467 "<Rt2>|Rt:4@12": "arg_R2_12", 468 469 // register arithmetic 470 "<Rm>,<type> <Rs>|Rm:4@0|Rs:4@8|type:2@5": "arg_R_shift_R", 471 "<Rm>{,<shift>}|Rm:4@0|imm5:5@7|type:2@5": "arg_R_shift_imm", 472 "<Rn>{,<shift>}|Rn:4@0|imm5:5@7|sh@6": "arg_R_shift_imm", 473 "<Rm>{,LSL #<imm5>}|Rm:4@0|imm5:5@7": "arg_R_shift_imm", 474 "<Rm>{,<rotation>}|Rm:4@0|rotate:2@10": "arg_R_rotate", 475 476 // memory references 477 "<Rn>{!}|Rn:4@16|W@21": "arg_R_16_WB", 478 "[<Rn>]|Rn:4@16": "arg_mem_R", 479 "[<Rn>,+/-<Rm>{, <shift>}]{!}|Rn:4@16|U@23|Rm:4@0|type:2@5|imm5:5@7|P@24|W@21": "arg_mem_R_pm_R_shift_imm_W", 480 "[<Rn>{,#+/-<imm8>}]{!}|Rn:4@16|P@24|U@23|W@21|imm4H:4@8|imm4L:4@0": "arg_mem_R_pm_imm8_W", 481 "[<Rn>] {,#+/-<imm8>}|Rn:4@16|U@23|imm4H:4@8|imm4L:4@0": "arg_mem_R_pm_imm8_postindex", 482 "[<Rn>{,#+/-<imm12>}]{!}|Rn:4@16|P@24|U@23|W@21|imm12:12@0": "arg_mem_R_pm_imm12_W", 483 "[<Rn>],#+/-<imm12>|Rn:4@16|imm12:12@0|U@23": "arg_mem_R_pm_imm12_postindex", 484 "[<Rn>,#+/-<imm12>]|Rn:4@16|U@23|imm12:12@0": "arg_mem_R_pm_imm12_offset", 485 "[<Rn>] {,#+/-<imm12>}|Rn:4@16|U@23|imm12:12@0": "arg_mem_R_pm_imm12_postindex", 486 "[<Rn>], +/-<Rm>|Rn:4@16|U@23|Rm:4@0": "arg_mem_R_pm_R_postindex", 487 "[<Rn>,+/-<Rm>]{!}|Rn:4@16|U@23|Rm:4@0|P@24|W@21": "arg_mem_R_pm_R_W", 488 "[<Rn>],+/-<Rm>{, <shift>}|Rn:4@16|Rm:4@0|imm5:5@7|type:2@5|U@23": "arg_mem_R_pm_R_shift_imm_postindex", 489 "[<Rn>,+/-<Rm>{, <shift>}]|Rn:4@16|U@23|Rm:4@0|type:2@5|imm5:5@7": "arg_mem_R_pm_R_shift_imm_offset", 490 "[<Rn>{,#+/-<imm8>}]|Rn:4@16|U@23|imm8:8@0": "arg_mem_R_pm_imm8at0_offset", 491 492 // pc-relative constants 493 "<label+12>|imm12:12@0": "arg_label_p_12", 494 "<label-12>|imm12:12@0": "arg_label_m_12", 495 "<label+/-12>|imm12:12@0|U@23": "arg_label_pm_12", 496 "<label+/-4+4>|imm4H:4@8|imm4L:4@0|U@23": "arg_label_pm_4_4", 497 498 // constants 499 "#<const>|imm12:12@0": "arg_const", 500 "#<imm5>|imm5:5@7": "arg_imm5", 501 "#<imm5_nz>|imm5:5@7": "arg_imm5_nz", 502 "#<imm5_32>|imm5:5@7": "arg_imm5_32", 503 "<label24>|imm24:24@0": "arg_label24", 504 "#<lsb>|lsb:5@7": "arg_imm5", 505 "#<width>|lsb:5@7|msb:5@16": "arg_lsb_width", 506 "#<imm12+4>|imm12:12@8|imm4:4@0": "arg_imm_12at8_4at0", 507 "#<imm12+4>|imm12:12@0|imm4:4@16": "arg_imm_4at16_12at0", 508 "<label24H>|imm24:24@0|H@24": "arg_label24H", 509 "#<option>|option:4@0": "arg_option", 510 "#<widthm1>|widthm1:5@16": "arg_widthm1", 511 "#<sat_imm4>|sat_imm:4@16": "arg_satimm4", 512 "#<sat_imm5>|sat_imm:5@16": "arg_satimm5", 513 "#<sat_imm4m1>|sat_imm:4@16": "arg_satimm4m1", 514 "#<sat_imm5m1>|sat_imm:5@16": "arg_satimm5m1", 515 "#<imm24>|imm24:24@0": "arg_imm24", 516 517 // special 518 "<registers>|register_list:16@0": "arg_registers", 519 "<registers2>|register_list:16@0": "arg_registers2", 520 "<registers1>|Rt:4@12": "arg_registers1", 521 "<endian_specifier>|E@9": "arg_endian", 522 523 "SP": "arg_SP", 524 "APSR": "arg_APSR", 525 "FPSCR": "arg_FPSCR", 526 527 // VFP floating point registers 528 "<Sd>|Vd:4@12|D@22": "arg_Sd", 529 "<Sd,Dd>|Vd:4@12|D@22|sz@8": "arg_Sd_Dd", 530 "<Dd,Sd>|Vd:4@12|D@22|sz@8": "arg_Dd_Sd", 531 "<Sn>|Vn:4@16|N@7": "arg_Sn", 532 "<Sn,Dn>|Vn:4@16|N@7|sz@8": "arg_Sn_Dn", 533 "<Sm>|Vm:4@0|M@5": "arg_Sm", 534 "<Sm,Dm>|Vm:4@0|M@5|sz@8": "arg_Sm_Dm", 535 "#0.0": "arg_fp_0", 536 "#<imm_vfp>|imm4H:4@16|imm4L:4@0|sz@8": "arg_imm_vfp", 537 "#<fbits>|sx@7|imm4:4@0|i@5": "arg_fbits", 538 "<Dn[x]>|N@7|Vn:4@16|opc1@21": "arg_Dn_half", 539 "<Dd[x]>|D@7|Vd:4@16|opc1@21": "arg_Dn_half", 540 } 541 542 // argSuffixes describes the encoding fields needed for a particular suffix. 543 // The set of keys in argSuffixes also drives the identification of suffix pieces. 544 // For example, <Rm> and <Rm>{, <type> <Rs>} are both keys in the map 545 // and matching is done 'longest first', so "<Rm>, <Rm>{, <type> <Rs>}" is 546 // parsed as just two arguments despite the extra ", ". 547 // The field order in the map values must match the order expected in 548 // the argument descriptions in argOps. 549 var argSuffixes = map[string]string{ 550 "#0": "", 551 "#0.0": "", 552 "#<const>": "imm12:12", 553 "#<fbits>": "sx,imm4:4,i", 554 "#<imm12+4>": "imm12:12,imm4:4", 555 "#<imm24>": "imm24:24", 556 "#<imm3>": "imm3:3", 557 "#<imm4>": "imm4:4", 558 "#<imm5>": "imm5:5", 559 "#<imm5_nz>": "imm5:5", 560 "#<imm5_32>": "imm5:5", 561 "#<imm6>": "imm6:6", 562 "#<immsize>": "size:2", 563 "#<imm_vfp>": "imm4H:4,imm4L:4,sz", 564 "#<sat_imm4>": "sat_imm:4", 565 "#<sat_imm5>": "sat_imm:5", 566 "#<sat_imm4m1>": "sat_imm:4", 567 "#<sat_imm5m1>": "sat_imm:5", 568 "#<lsb>": "lsb:5", 569 "#<option>": "option:4", 570 "#<width>": "lsb:5,msb:5", 571 "#<widthm1>": "widthm1:5", 572 "+/-<Rm>": "Rm:4,U", 573 "<Dd>": "D,Vd:4", 574 "<Dd[x]>": "D,Vd:4,opc1", 575 "<Dm>": "M,Vm:4", 576 "<Dm[x]>": "M,Vm:4,size:2", 577 "<Dn>": "N,Vn:4", 578 "<Dn[x]>": "N,Vn:4,opc1", 579 "<Dm[size_x]>": "imm4:4", 580 "<Qd>": "D,Vd:4", 581 "<Qm>": "M,Vm:4", 582 "<Qn>": "N,Vn:4", 583 "<Ra>": "Ra:4", 584 "<Rd>": "Rd:4", 585 "<RdHi>": "RdHi:4", 586 "<RdLo>": "RdLo:4", 587 "<Rm>": "Rm:4", 588 "<Rm>{,<rotation>}": "Rm:4,rotate:2", 589 "<Rm>{,<shift>}": "Rm:4,imm5:5,type:2", 590 "<Rm>{,LSL #<imm5>}": "Rm:4,imm5:5", 591 "<Rn>": "Rn:4", 592 "<Rn>{!}": "Rn:4,W", 593 "<Rn>{,<shift>}": "Rn:4,imm5:5,sh", 594 "<Rs>": "Rs:4", 595 "<Rt1>": "Rt:4", 596 "<Rt2>": "Rt:4", 597 "<Rt>": "Rt:4", 598 "<Rt_nzcv>": "Rt:4", 599 "<Sd>": "Vd:4,D", 600 "<Sm1>": "Vm:4,M", 601 "<Sm>": "Vm:4,M", 602 "<Sn>": "Vn:4,N", 603 "<Sd,Dd>": "Vd:4,D,sz", 604 "<Dd,Sd>": "Vd:4,D,sz", 605 "<Sn,Dn>": "Vn:4,N,sz", 606 "<Sm,Dm>": "Vm:4,M,sz", 607 "<endian_specifier>": "E", 608 "<label+/-12>": "imm12:12,U", 609 "<label+12>": "imm12:12", 610 "<label-12>": "imm12:12", 611 "<label24>": "imm24:24", 612 "<label24H>": "imm24:24,H", 613 "<label+/-4+4>": "imm4H:4,imm4L:4,U", 614 "<list4>": "D,Vd:4,type:4", 615 "<list3>": "D,Vd:4,index_align:4", 616 "<list3t>": "D,Vd:4,T", 617 "<list1>": "D,Vd:4", 618 "<list_len>": "N,Vn:4,len:2", 619 "<vlist32>": "D,Vd:4,imm8:8", 620 "<vlist64>": "D,Vd:4,imm8:8", 621 "<registers>": "register_list:16", 622 "<registers2>": "register_list:16", 623 "<registers1>": "Rt:4", 624 "APSR": "", 625 "<Rm>,<type> <Rs>": "Rm:4,Rs:4,type:2", 626 "FPSCR": "", 627 "SP": "", 628 "[<Rn>,#+/-<imm12>]": "Rn:4,U,imm12:12", 629 "[<Rn>,+/-<Rm>]{!}": "Rn:4,U,Rm:4,P,W", 630 "[<Rn>,+/-<Rm>{, <shift>}]": "Rn:4,U,Rm:4,type:2,imm5:5", 631 "[<Rn>,+/-<Rm>{, <shift>}]{!}": "Rn:4,U,Rm:4,type:2,imm5:5,P,W", 632 "[<Rn>] {,#+/-<imm12>}": "Rn:4,U,imm12:12", 633 "[<Rn>] {,#+/-<imm8>}": "Rn:4,U,imm4H:4,imm4L:4", 634 "[<Rn>]": "Rn:4", 635 "[<Rn>],#+/-<imm12>": "Rn:4,imm12:12,U", 636 "[<Rn>],+/-<Rm>{, <shift>}": "Rn:4,Rm:4,imm5:5,type:2,U", 637 "[<Rn>]{!}": "Rn:4,Rm:4", 638 "[<Rn>{@<align>}]{!}": "XXX", 639 "[<Rn>{,#+/-<imm12>}]{!}": "Rn:4,P,U,W,imm12:12", 640 "[<Rn>{,#+/-<imm8>}]{!}": "Rn:4,P,U,W,imm4H:4,imm4L:4", 641 "[<Rn>{,#+/-<imm8>}]": "Rn:4,U,imm8:8", 642 "[<Rn>], +/-<Rm>": "Rn:4,U,Rm:4", 643 "#<imm_simd1>": "i,imm3:3,imm4:4,cmode:4", 644 "#<imm_simd>": "op,i,imm3:3,imm4:4,cmode:4", 645 "#<imm_vs>": "L,imm6:6", 646 "#<imm_vsn>": "imm6:6", 647 } 648 649 // cross returns the string concatenation cross product of xs and ys. 650 func cross(xs []string, ys ...string) []string { 651 var xys []string 652 653 for _, x := range xs { 654 for _, y := range ys { 655 xys = append(xys, x+y) 656 } 657 } 658 return xys 659 } 660 661 // crossCond returns the cross product of xs with all the possible 662 // conditional execution suffixes. It is assumed that each string x in xs 663 // contains a substring _COND_ marking where the conditional suffix 664 // should be placed. 665 func crossCond(xs []string) []string { 666 ys := choices["c"] 667 var xys []string 668 669 for _, x := range xs { 670 i := strings.Index(x, "_COND_") 671 pre, post := x[:i], x[i+6:] 672 for _, y := range ys { 673 xys = append(xys, pre+y+post) 674 } 675 } 676 return xys 677 } 678 679 // printText implements the -fmt=text mode, which is not implemented (yet?). 680 func printText(p *Prog) { 681 log.Fatal("-fmt=text not implemented") 682 } 683 684 // printDecoder implements the -fmt=decoder mode. 685 // It emits the tables.go for package armasm's decoder. 686 func printDecoder(p *Prog) { 687 fmt.Printf("package armasm\n\n") 688 689 // Build list of opcodes sorted by name 690 // but preserving the sequential ranges needed for opcode decoding. 691 haveRange := make(map[string]string) 692 for _, r := range p.OpRanges { 693 haveRange[r] = r 694 } 695 var ranges []string 696 for _, r := range haveRange { 697 ranges = append(ranges, r) 698 } 699 sort.Strings(ranges) 700 701 // Emit const definitions for opcodes. 702 fmt.Printf("const (\n") 703 iota := 0 704 fmt.Printf("\t_ Op = iota\n") 705 iota++ 706 for _, r := range ranges { 707 for _, op := range strings.Split(r, ",") { 708 if op == "" { 709 continue 710 } 711 // Assume if opcode says .EQ it is the start of a 16-wide 712 // iteration through the conditional suffixes. If so, emit 713 // blank names until the assigned value is 16-aligned. 714 if strings.Contains(op, ".EQ") { 715 for iota&15 != 0 { 716 fmt.Printf("\t_\n") 717 iota++ 718 } 719 } 720 fmt.Printf("\t%s\n", strings.Replace(op, ".", "_", -1)) 721 iota++ 722 } 723 } 724 fmt.Printf(")\n") 725 726 // Emit slice mapping opcode number to name string. 727 fmt.Printf("\nvar opstr = [...]string{\n") 728 for _, r := range ranges { 729 for _, op := range strings.Split(r, ",") { 730 if op == "" { 731 continue 732 } 733 fmt.Printf("\t%s: %q,\n", strings.Replace(op, ".", "_", -1), op) 734 } 735 } 736 fmt.Printf("}\n") 737 738 // Emit decoding table. 739 unknown := map[string]bool{} 740 fmt.Printf("\nvar instFormats = [...]instFormat{\n") 741 for _, inst := range p.Inst { 742 fmt.Printf("\t{%#08x, %#08x, %d, %s, %#x, instArgs{", inst.Mask, inst.Value, inst.Priority, strings.Replace(inst.OpBase, ".", "_", -1), inst.OpBits) 743 for i, a := range inst.Args { 744 if i > 0 { 745 fmt.Printf(", ") 746 } 747 str := argOps[a] 748 if str == "" && !unknown[a] { 749 fmt.Fprintf(os.Stderr, "%s: unknown arg %s\n", inst.Text, a) 750 unknown[a] = true 751 } 752 fmt.Printf("%s", str) 753 } 754 fmt.Printf("}}, // %s %s\n", inst.Text, inst.Encoding) 755 } 756 fmt.Printf("}\n") 757 }