golang.org/x/arch@v0.17.0/ppc64/ppc64map/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 // ppc64map constructs the ppc64 opcode map from the instruction set CSV file. 6 // 7 // Usage: 8 // 9 // ppc64map [-fmt=format] ppc64.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 ppc64asm package 15 // encoder - generate a self-contained file which can be used to encode 16 // go obj.Progs into machine code 17 // asm - generate a gnu asm file which can be compiled by gcc containing 18 // all opcodes discovered in ppc64.csv using macro friendly arguments. 19 package main 20 21 import ( 22 "bytes" 23 "encoding/csv" 24 "flag" 25 "fmt" 26 gofmt "go/format" 27 "log" 28 "math/bits" 29 "os" 30 "regexp" 31 "sort" 32 "strconv" 33 "strings" 34 "text/template" 35 36 asm "golang.org/x/arch/ppc64/ppc64asm" 37 ) 38 39 var format = flag.String("fmt", "text", "output format: text, decoder, asm") 40 var debug = flag.Bool("debug", false, "enable debugging output") 41 42 var inputFile string 43 44 type isaversion uint32 45 46 const ( 47 // Sort as supersets of each other. Generally speaking, each newer ISA 48 // supports a superset of the previous instructions with a few exceptions 49 // throughout. 50 ISA_P1 isaversion = iota 51 ISA_P2 52 ISA_PPC 53 ISA_V200 54 ISA_V201 55 ISA_V202 56 ISA_V203 57 ISA_V205 58 ISA_V206 59 ISA_V207 60 ISA_V30 61 ISA_V30B 62 ISA_V30C 63 ISA_V31 64 ISA_V31B 65 ) 66 67 var isaToISA = map[string]isaversion{ 68 "P1": ISA_P1, 69 "P2": ISA_P2, 70 "PPC": ISA_PPC, 71 "v2.00": ISA_V200, 72 "v2.01": ISA_V201, 73 "v2.02": ISA_V202, 74 "v2.03": ISA_V203, 75 "v2.05": ISA_V205, 76 "v2.06": ISA_V206, 77 "v2.07": ISA_V207, 78 "v3.0": ISA_V30, 79 "v3.0B": ISA_V30B, 80 "v3.0C": ISA_V30C, 81 "v3.1": ISA_V31, 82 "v3.1B": ISA_V31B, 83 } 84 85 func usage() { 86 fmt.Fprintf(os.Stderr, "usage: ppc64map [-fmt=format] ppc64.csv\n") 87 os.Exit(2) 88 } 89 90 func main() { 91 log.SetFlags(0) 92 log.SetPrefix("ppc64map: ") 93 94 flag.Usage = usage 95 flag.Parse() 96 if flag.NArg() != 1 { 97 usage() 98 } 99 100 inputFile = flag.Arg(0) 101 102 var print func(*Prog) 103 switch *format { 104 default: 105 log.Fatalf("unknown output format %q", *format) 106 case "text": 107 print = printText 108 case "decoder": 109 print = printDecoder 110 case "asm": 111 print = printASM 112 case "encoder": 113 print = printEncoder 114 } 115 116 p, err := readCSV(flag.Arg(0)) 117 if err != nil { 118 log.Fatal(err) 119 } 120 log.Printf("Parsed %d instruction forms.", len(p.Insts)) 121 print(p) 122 } 123 124 // readCSV reads the CSV file and returns the corresponding Prog. 125 // It may print details about problems to standard error using the log package. 126 func readCSV(file string) (*Prog, error) { 127 // Read input. 128 // Skip leading blank and # comment lines. 129 f, err := os.Open(file) 130 if err != nil { 131 return nil, err 132 } 133 csvReader := csv.NewReader(f) 134 csvReader.Comment = '#' 135 table, err := csvReader.ReadAll() 136 if err != nil { 137 return nil, fmt.Errorf("parsing %s: %v", file, err) 138 } 139 if len(table) == 0 { 140 return nil, fmt.Errorf("empty csv input") 141 } 142 if len(table[0]) < 4 { 143 return nil, fmt.Errorf("csv too narrow: need at least four columns") 144 } 145 146 p := &Prog{} 147 for _, row := range table { 148 add(p, row[0], row[1], row[2], row[3]) 149 } 150 return p, nil 151 } 152 153 type Prog struct { 154 Insts []Inst 155 OpRanges map[string]string 156 nextOrder int // Next position value (used for Insts[x].order) 157 } 158 159 type Field struct { 160 Name string 161 BitFields asm.BitFields 162 BitFieldNames []string 163 Type asm.ArgType 164 Shift uint8 165 } 166 167 func (f Field) String() string { 168 return fmt.Sprintf("%v(%s%v)", f.Type, f.Name, f.BitFields) 169 } 170 171 type Inst struct { 172 Text string 173 Encoding string 174 Op string 175 Mask uint32 176 Value uint32 177 DontCare uint32 178 SMask uint32 // The opcode Mask of the suffix word 179 SValue uint32 // Likewise for the Value 180 SDontCare uint32 // Likewise for the DontCare bits 181 Fields []Field 182 Words int // Number of words instruction encodes to. 183 Isa isaversion 184 memOp bool // Is this a memory operation? 185 memOpX bool // Is this an x-form memory operation? 186 memOpSt bool // Is this a store memory operations? 187 order int // Position in pp64.csv. 188 } 189 190 func (i Inst) String() string { 191 return fmt.Sprintf("%s (%s) %08x/%08x[%08x] %v (%s)", i.Op, i.Encoding, i.Value, i.Mask, i.DontCare, i.Fields, i.Text) 192 } 193 194 type Arg struct { 195 Name string 196 Bits int8 197 Offs int8 198 // Instruction word position. 0 for single word instructions (all < ISA 3.1 insn) 199 // For prefixed instructions, 0 for the prefix word, 1 for the second insn word. 200 Word int8 201 } 202 203 func (a Arg) String() string { 204 return fmt.Sprintf("%s[%d:%d]", a.Name, a.Offs, a.Offs+a.Bits-1) 205 } 206 207 func (a Arg) Maximum() int { 208 return 1<<uint8(a.Bits) - 1 209 } 210 211 func (a Arg) BitMask() uint32 { 212 return uint32(a.Maximum()) << a.Shift() 213 } 214 215 func (a Arg) Shift() uint8 { 216 return uint8(32 - a.Offs - a.Bits) 217 } 218 219 type Args []Arg 220 221 func (as Args) String() string { 222 ss := make([]string, len(as)) 223 for i := range as { 224 ss[i] = as[i].String() 225 } 226 return strings.Join(ss, "|") 227 } 228 229 func (as Args) Find(name string) int { 230 for i := range as { 231 if as[i].Name == name { 232 return i 233 } 234 } 235 return -1 236 } 237 238 func (as *Args) Append(a Arg) { 239 *as = append(*as, a) 240 } 241 242 func (as *Args) Delete(i int) { 243 *as = append((*as)[:i], (*as)[i+1:]...) 244 } 245 246 func (as Args) Clone() Args { 247 return append(Args{}, as...) 248 } 249 250 func (a Arg) isDontCare() bool { 251 return a.Name[0] == '/' && a.Name == strings.Repeat("/", len(a.Name)) 252 } 253 254 type instArray []Inst 255 256 func (i instArray) Len() int { 257 return len(i) 258 } 259 260 func (i instArray) Swap(j, k int) { 261 i[j], i[k] = i[k], i[j] 262 } 263 264 // Sort by decreasing number of mask bits to ensure extended mnemonics 265 // are always found first when scanning the table. 266 func (i instArray) Less(j, k int) bool { 267 return bits.OnesCount32(i[j].Mask) > bits.OnesCount32(i[k].Mask) 268 } 269 270 // Split the string encoding into an Args. The encoding string loosely matches the regex 271 // (arg@bitpos|)+ 272 func parseFields(encoding, text string, word int8) Args { 273 var err error 274 var args Args 275 276 fields := strings.Split(encoding, "|") 277 278 for i, f := range fields { 279 name, off := "", -1 280 if f == "" { 281 off = 32 282 if i == 0 || i != len(fields)-1 { 283 fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f) 284 panic("Invalid encoding entry.") 285 } 286 } else { 287 j := strings.Index(f, "@") 288 if j < 0 { 289 fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f) 290 panic("Invalid encoding entry.") 291 } 292 k := strings.Index(f[j+1:], " ") 293 if k >= 0 { 294 if strings.HasSuffix(f[j+1:], " 31") { 295 f = f[:len(f)-3] 296 } 297 } 298 off, err = strconv.Atoi(f[j+1:]) 299 if err != nil { 300 fmt.Fprintf(os.Stderr, "err for: %s has: %s for %s\n", f[:j], err, f[j+1:]) 301 } 302 name = f[:j] 303 } 304 if len(args) > 0 { 305 args[len(args)-1].Bits += int8(off) 306 } 307 if name != "" { 308 arg := Arg{Name: name, Offs: int8(off), Bits: int8(-off), Word: word} 309 args.Append(arg) 310 } 311 } 312 313 return args 314 } 315 316 // Compute the Mask (usually Opcode + secondary Opcode bitfields), 317 // the Value (the expected value under the mask), and 318 // reserved bits (i.e the // fields which should be set to 0) 319 func computeMaskValueReserved(args Args, text string) (mask, value, reserved uint32) { 320 for i := 0; i < len(args); i++ { 321 arg := args[i] 322 v, err := strconv.Atoi(arg.Name) 323 switch { 324 case err == nil: // is a numbered field 325 if v < 0 || v > arg.Maximum() { 326 fmt.Fprintf(os.Stderr, "%s: field %s value (%d) is out of range (%d-bit)\n", text, arg, v, arg.Bits) 327 } 328 mask |= arg.BitMask() 329 value |= uint32(v) << arg.Shift() 330 args.Delete(i) 331 i-- 332 case arg.Name[0] == '/': // is don't care 333 if arg.Name != strings.Repeat("/", len(arg.Name)) { 334 log.Fatalf("%s: arg %v named like a don't care bit, but it's not", text, arg) 335 } 336 reserved |= arg.BitMask() 337 args.Delete(i) 338 i-- 339 default: 340 continue 341 } 342 } 343 344 // rename duplicated fields (e.g. 30@0|RS@6|RA@11|sh@16|mb@21|0@27|sh@30|Rc@31|) 345 // but only support two duplicated fields 346 for i := 1; i < len(args); i++ { 347 if args[:i].Find(args[i].Name) >= 0 { 348 args[i].Name += "2" 349 } 350 if args[:i].Find(args[i].Name) >= 0 { 351 log.Fatalf("%s: more than one duplicated fields: %s", text, args) 352 } 353 } 354 355 // sanity checks 356 if mask&reserved != 0 { 357 log.Fatalf("%s: mask (%08x) and don't care (%08x) collide", text, mask, reserved) 358 } 359 if value&^mask != 0 { 360 log.Fatalf("%s: value (%08x) out of range of mask (%08x)", text, value, mask) 361 } 362 363 var argMask uint32 364 for _, arg := range args { 365 if arg.Bits <= 0 || arg.Bits > 32 || arg.Offs > 31 || arg.Offs <= 0 { 366 log.Fatalf("%s: arg %v has wrong bit field spec", text, arg) 367 } 368 if mask&arg.BitMask() != 0 { 369 log.Fatalf("%s: mask (%08x) intersect with arg %v", text, mask, arg) 370 } 371 if argMask&arg.BitMask() != 0 { 372 log.Fatalf("%s: arg %v overlap with other args %v", text, arg, args) 373 } 374 argMask |= arg.BitMask() 375 } 376 if 1<<32-1 != mask|reserved|argMask { 377 log.Fatalf("%s: args %v fail to cover all 32 bits", text, args) 378 } 379 380 return 381 } 382 383 // Parse a row from the CSV describing the instructions, and place the 384 // detected instructions into p. One entry may generate multiple intruction 385 // entries as each extended mnemonic listed in text is treated like a unique 386 // instruction. 387 func add(p *Prog, text, mnemonics, encoding, isa string) { 388 // Parse encoding, building size and offset of each field. 389 // The first field in the encoding is the smallest offset. 390 // And note the MSB is bit 0, not bit 31. 391 // Example: "31@0|RS@6|RA@11|///@16|26@21|Rc@31|" 392 var args, pargs Args 393 var pmask, pvalue, presv, resv uint32 394 iword := int8(0) 395 ispfx := false 396 397 isaLevel, fnd := isaToISA[isa] 398 if !fnd { 399 log.Fatalf("%s: ISA level '%s' is unknown\n", text, isa) 400 return 401 } 402 403 // Is this a prefixed instruction? 404 if encoding[0] == ',' { 405 pfields := strings.Split(encoding, ",")[1:] 406 407 if len(pfields) != 2 { 408 log.Fatalf("%s: Prefixed instruction must be 2 words long.\n", text) 409 return 410 } 411 pargs = parseFields(pfields[0], text, iword) 412 pmask, pvalue, presv = computeMaskValueReserved(pargs, text) 413 // Move to next instruction word 414 iword++ 415 encoding = pfields[1] 416 ispfx = true 417 } 418 419 args = parseFields(encoding, text, iword) 420 mask, value, dontCare := computeMaskValueReserved(args, text) 421 422 if ispfx { 423 args = append(args, pargs...) 424 } 425 426 // split mnemonics into individual instructions 427 // example: "b target_addr (AA=0 LK=0)|ba target_addr (AA=1 LK=0)|bl target_addr (AA=0 LK=1)|bla target_addr (AA=1 LK=1)" 428 insts := strings.Split(categoryRe.ReplaceAllString(mnemonics, ""), "|") 429 foundInst := []Inst{} 430 for _, inst := range insts { 431 value, mask := value, mask 432 pvalue, pmask := pvalue, pmask 433 args := args.Clone() 434 if inst == "" { 435 continue 436 } 437 // amend mask and value 438 parts := instRe.FindStringSubmatch(inst) 439 if parts == nil { 440 log.Fatalf("%v couldn't match %s", instRe, inst) 441 } 442 conds := condRe.FindAllStringSubmatch(parts[2], -1) 443 isPCRel := true 444 for _, cond := range conds { 445 i := args.Find(cond[1]) 446 v, _ := strconv.ParseInt(cond[2], 16, 32) // the regular expression has checked the number format 447 if i < 0 { 448 log.Fatalf("%s: %s don't contain arg %s used in %s", text, args, cond[1], inst) 449 } 450 if cond[1] == "AA" && v == 1 { 451 isPCRel = false 452 } 453 mask |= args[i].BitMask() 454 value |= uint32(v) << args[i].Shift() 455 args.Delete(i) 456 } 457 inst := Inst{Text: text, Encoding: parts[1], Value: value, Mask: mask, DontCare: dontCare} 458 if ispfx { 459 inst = Inst{Text: text, Encoding: parts[1], Value: pvalue, Mask: pmask, DontCare: presv, SValue: value, SMask: mask, SDontCare: resv} 460 } 461 462 // order inst.Args according to mnemonics order 463 for i, opr := range operandRe.FindAllString(parts[1], -1) { 464 if i == 0 { // operation 465 inst.Op = opr 466 continue 467 } 468 field := Field{Name: opr} 469 typ := asm.TypeUnknown 470 var shift uint8 471 opr2 := "" 472 opr3 := "" 473 switch opr { 474 case "target_addr": 475 shift = 2 476 if isPCRel { 477 typ = asm.TypePCRel 478 } else { 479 typ = asm.TypeLabel 480 } 481 if args.Find("LI") >= 0 { 482 opr = "LI" 483 } else { 484 opr = "BD" 485 } 486 487 case "offset": 488 switch inst.Op { 489 // These encode a 6 bit displacement in the format of an X-form opcode. 490 // Allowable displaments are -8 to -8*64 in 8B increments. 491 case "hashchk", "hashchkp", "hashst", "hashstp": 492 typ = asm.TypeNegOffset 493 opr = "DX" 494 opr2 = "D" 495 shift = 3 496 497 } 498 499 case "XMSK", "YMSK", "PMSK", "IX", "BHRBE": 500 typ = asm.TypeImmUnsigned 501 502 case "IMM32": 503 typ = asm.TypeImmUnsigned 504 opr = "imm0" 505 opr2 = "imm1" 506 507 // Handle these cases specially. Note IMM is used on 508 // prefixed MMA instructions as a bitmask. Usually, it is a signed value. 509 case "R", "UIM", "IMM": 510 if ispfx { 511 typ = asm.TypeImmUnsigned 512 break 513 } 514 fallthrough 515 516 case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DGM", "RMC", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY", "SC", "PL", "MP", "N", "DRM", "RM": 517 typ = asm.TypeImmUnsigned 518 if i := args.Find(opr); i < 0 { 519 log.Printf("coerce to D: %s: couldn't find extended field %s in %s", text, opr, args) 520 opr = "D" 521 } 522 case "bm": 523 opr = "b0" 524 opr2 = "b1" 525 opr3 = "b2" 526 typ = asm.TypeImmUnsigned 527 528 case "SH": 529 typ = asm.TypeImmUnsigned 530 if args.Find("sh2") >= 0 { // sh2 || sh 531 opr = "sh2" 532 opr2 = "sh" 533 } 534 case "MB", "ME": 535 typ = asm.TypeImmUnsigned 536 if n := strings.ToLower(opr); args.Find(n) >= 0 { 537 opr = n // xx[5] || xx[0:4] 538 } 539 case "SI", "SIM", "TE": 540 if ispfx { 541 typ = asm.TypeImmSigned 542 opr = "si0" 543 opr2 = "si1" 544 break 545 } 546 typ = asm.TypeImmSigned 547 if i := args.Find(opr); i < 0 { 548 opr = "D" 549 } 550 case "DCMX": 551 typ = asm.TypeImmUnsigned 552 // Some instructions encode this consecutively. 553 if i := args.Find(opr); i >= 0 { 554 break 555 } 556 typ = asm.TypeImmUnsigned 557 opr = "dc" 558 opr2 = "dm" 559 opr3 = "dx" 560 case "DS": 561 typ = asm.TypeOffset 562 shift = 2 563 case "DQ": 564 typ = asm.TypeOffset 565 shift = 4 566 case "D": 567 if ispfx { 568 typ = asm.TypeOffset 569 opr = "d0" 570 opr2 = "d1" 571 break 572 } 573 if i := args.Find(opr); i >= 0 { 574 typ = asm.TypeOffset 575 break 576 } 577 if i := args.Find("UI"); i >= 0 { 578 typ = asm.TypeImmUnsigned 579 opr = "UI" 580 break 581 } 582 if i := args.Find("SI"); i >= 0 { 583 typ = asm.TypeImmSigned 584 opr = "SI" 585 break 586 } 587 if i := args.Find("d0"); i >= 0 { 588 typ = asm.TypeImmSigned 589 // DX-form 590 opr = "d0" 591 opr2 = "d1" 592 opr3 = "d2" 593 } 594 case "RA", "RB", "RC", "RS", "RSp", "RT", "RTp": 595 typ = asm.TypeReg 596 case "BT", "BA", "BB", "BC", "BI": 597 if strings.HasPrefix(inst.Op, "mtfs") { 598 // mtfsb[01] instructions use BT, but they specify fields in the fpscr. 599 typ = asm.TypeImmUnsigned 600 } else { 601 typ = asm.TypeCondRegBit 602 } 603 case "BF", "BFA": 604 if strings.HasPrefix(inst.Op, "mtfs") { 605 // mtfsfi[.] instructions use BF, but they specify fields in the fpscr. 606 typ = asm.TypeImmUnsigned 607 } else { 608 typ = asm.TypeCondRegField 609 } 610 case "FRA", "FRB", "FRBp", "FRC", "FRS", "FRSp", "FRT", "FRTp", "FRAp": 611 typ = asm.TypeFPReg 612 case "XA", "XB", "XC", "XS", "XT": // 5-bit, split field 613 typ = asm.TypeVecSReg 614 opr2 = opr[1:] 615 opr = opr[1:] + "X" 616 case "XTp", "XSp": // 5-bit, split field 617 //XTp encodes 5 bits, VSR is XT*32 + TP<<1 618 typ = asm.TypeVecSpReg 619 opr2 = opr[1:2] + "p" 620 opr = opr[1:2] + "X" 621 622 case "XAp": 623 // XAp in MMA encodes a regular VSR, but is only valid 624 // if it is even, and does not overlap the accumulator. 625 typ = asm.TypeVecSReg 626 opr2 = opr[1:2] + "p" 627 opr = opr[1:2] + "X" 628 629 case "AT", "AS": 630 typ = asm.TypeMMAReg 631 632 case "VRA", "VRB", "VRC", "VRS", "VRT": 633 typ = asm.TypeVecReg 634 635 case "SPR", "TBR": 636 typ = asm.TypeSpReg 637 if n := strings.ToLower(opr); n != opr && args.Find(n) >= 0 { 638 opr = n // spr[5:9] || spr[0:4] 639 } 640 } 641 if typ == asm.TypeUnknown { 642 log.Fatalf("%s %s unknown type for opr %s", text, inst, opr) 643 } 644 field.Type = typ 645 field.Shift = shift 646 var f1, f2, f3 asm.BitField 647 switch { 648 case opr3 != "": 649 b0 := args.Find(opr) 650 b1 := args.Find(opr2) 651 b2 := args.Find(opr3) 652 f1.Offs, f1.Bits, f1.Word = uint8(args[b0].Offs), uint8(args[b0].Bits), uint8(args[b0].Word) 653 f2.Offs, f2.Bits, f2.Word = uint8(args[b1].Offs), uint8(args[b1].Bits), uint8(args[b1].Word) 654 f3.Offs, f3.Bits, f3.Word = uint8(args[b2].Offs), uint8(args[b2].Bits), uint8(args[b2].Word) 655 656 case opr2 != "": 657 ext := args.Find(opr) 658 if ext < 0 { 659 log.Fatalf("%s: couldn't find extended field %s in %s", text, opr, args) 660 } 661 f1.Offs, f1.Bits, f1.Word = uint8(args[ext].Offs), uint8(args[ext].Bits), uint8(args[ext].Word) 662 base := args.Find(opr2) 663 if base < 0 { 664 log.Fatalf("%s: couldn't find base field %s in %s", text, opr2, args) 665 } 666 f2.Offs, f2.Bits, f2.Word = uint8(args[base].Offs), uint8(args[base].Bits), uint8(args[base].Word) 667 case opr == "mb", opr == "me": // xx[5] || xx[0:4] 668 i := args.Find(opr) 669 if i < 0 { 670 log.Fatalf("%s: couldn't find special 'm[be]' field for %s in %s", text, opr, args) 671 } 672 f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs+args[i].Bits)-1, 1, uint8(args[i].Word) 673 f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), uint8(args[i].Bits)-1, uint8(args[i].Word) 674 case opr == "spr", opr == "tbr", opr == "tmr", opr == "dcr": // spr[5:9] || spr[0:4] 675 i := args.Find(opr) 676 if i < 0 { 677 log.Fatalf("%s: couldn't find special 'spr' field for %s in %s", text, opr, args) 678 } 679 if args[i].Bits != 10 { 680 log.Fatalf("%s: special 'spr' field is not 10-bit: %s", text, args) 681 } 682 f1.Offs, f1.Bits, f2.Word = uint8(args[i].Offs)+5, 5, uint8(args[i].Word) 683 f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), 5, uint8(args[i].Word) 684 default: 685 i := args.Find(opr) 686 if i < 0 { 687 log.Fatalf("%s: couldn't find %s in %s", text, opr, args) 688 } 689 f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs), uint8(args[i].Bits), uint8(args[i].Word) 690 } 691 field.BitFields.Append(f1) 692 field.BitFieldNames = append(field.BitFieldNames, opr) 693 if f2.Bits > 0 { 694 field.BitFields.Append(f2) 695 field.BitFieldNames = append(field.BitFieldNames, opr2) 696 } 697 if f3.Bits > 0 { 698 field.BitFields.Append(f3) 699 field.BitFieldNames = append(field.BitFieldNames, opr3) 700 } 701 inst.Fields = append(inst.Fields, field) 702 } 703 if *debug { 704 fmt.Printf("%v\n", inst) 705 } 706 inst.Isa = isaLevel 707 inst.memOp = hasMemoryArg(&inst) 708 inst.memOpX = inst.memOp && inst.Op[len(inst.Op)-1] == 'x' 709 inst.memOpSt = inst.memOp && strings.Contains(inst.Text, "Store") 710 inst.Words = 1 711 inst.order = p.nextOrder 712 p.nextOrder++ 713 if ispfx { 714 inst.Words = 2 715 } 716 foundInst = append(foundInst, inst) 717 } 718 719 // Sort mnemonics by bitcount. This ensures more specific mnemonics are picked 720 // up before generic ones (e.g li vs addi, or cmpld/cmplw vs cmpl) 721 sort.Sort(instArray(foundInst)) 722 723 p.Insts = append(p.Insts, foundInst...) 724 } 725 726 // condRegexp is a regular expression that matches condition in mnemonics (e.g. "AA=1") 727 const condRegexp = `\s*([[:alpha:]]+)=([0-9a-f]+)\s*` 728 729 // condRe matches condition in mnemonics (e.g. "AA=1") 730 var condRe = regexp.MustCompile(condRegexp) 731 732 // instRe matches instruction with potentially multiple conditions in mnemonics 733 var instRe = regexp.MustCompile(`^(.*?)\s?(\((` + condRegexp + `)+\))?$`) 734 735 // categoryRe matches intruction category notices in mnemonics 736 var categoryRe = regexp.MustCompile(`(\s*\[Category:[^]]*\]\s*)|(\s*\[Co-requisite[^]]*\]\s*)|(\s*\(\s*0[Xx][[0-9A-Fa-f_]{9}\s*\)\s*)`) 737 738 // operandRe matches each operand (including opcode) in instruction mnemonics 739 var operandRe = regexp.MustCompile(`([[:alpha:]][[:alnum:]_]*\.?)`) 740 741 // printText implements the -fmt=text mode, which is not implemented (yet?). 742 func printText(p *Prog) { 743 log.Fatal("-fmt=text not implemented") 744 } 745 746 // Some ISA instructions look like memory ops, but are not. 747 var isNotMemopMap = map[string]bool{ 748 "lxvkq": true, 749 "lvsl": true, 750 "lvsr": true, 751 } 752 753 // Some ISA instructions are memops, but are not described like "Load ..." or "Store ..." 754 var isMemopMap = map[string]bool{ 755 "hashst": true, 756 "hashstp": true, 757 "hashchk": true, 758 "hashchkp": true, 759 } 760 761 // Does this instruction contain a memory argument (e.g x-form load or d-form store) 762 func hasMemoryArg(insn *Inst) bool { 763 return ((strings.HasPrefix(insn.Text, "Load") || strings.HasPrefix(insn.Text, "Store") || 764 strings.HasPrefix(insn.Text, "Prefixed Load") || strings.HasPrefix(insn.Text, "Prefixed Store")) && !isNotMemopMap[insn.Op]) || 765 isMemopMap[insn.Op] 766 } 767 768 // Generate a function which takes an obj.Proj and convert it into 769 // machine code in the supplied buffer. These functions are used 770 // by asm9.go. 771 func insnEncFuncStr(insn *Inst, firstName [2]string) string { 772 buf := new(bytes.Buffer) 773 // Argument packing order. 774 // Note, if a2 is not a register type, it is skipped. 775 argOrder := []string{ 776 "p.To", // a6 777 "p.From", // a1 778 "p", // a2 779 "p.RestArgs[0].Addr", // a3 780 "p.RestArgs[1].Addr", // a4 781 "p.RestArgs[2].Addr", // a5 782 } 783 if len(insn.Fields) > len(argOrder) { 784 log.Fatalf("cannot handle %v. Only %d args supported.", insn, len(argOrder)) 785 } 786 787 // Does this field require an obj.Addr.Offset? 788 isImmediate := func(t asm.ArgType) bool { 789 return t == asm.TypeImmUnsigned || t == asm.TypeSpReg || t == asm.TypeImmSigned || t == asm.TypeOffset || t == asm.TypeNegOffset 790 } 791 792 if insn.memOp { 793 // Swap to/from arguments if we are generating 794 // for a store operation. 795 if insn.memOpSt { 796 // Otherwise, order first three args as: p.From, p.To, p.To 797 argOrder[0], argOrder[1] = argOrder[1], argOrder[0] 798 } 799 argOrder[2] = argOrder[1] // p.Reg is either an Index or Offset (X or D-form) 800 } else if len(insn.Fields) > 2 && isImmediate(insn.Fields[2].Type) { 801 // Delete the a2 argument if it is not a register type. 802 argOrder = append(argOrder[0:2], argOrder[3:]...) 803 } 804 805 fmt.Fprintf(buf, "// %s\n", insn.Encoding) 806 fmt.Fprintf(buf, "func type_%s(c *ctxt9, p *obj.Prog, t *Optab, out *[5]uint32) {\n", insn.Op) 807 if insn.Words > 1 { 808 fmt.Fprintf(buf, "o0 := GenPfxOpcodes[p.As - A%s]\n", firstName[1]) 809 } 810 fmt.Fprintf(buf, "o%d := GenOpcodes[p.As - A%s]\n", insn.Words-1, firstName[0]) 811 812 errCheck := "" 813 for j, atype := range insn.Fields { 814 itype := ".Reg" 815 if isImmediate(atype.Type) { 816 itype = ".Offset" 817 } else if insn.memOpX && atype.Name == "RA" { 818 // X-form memory operations encode RA as the index register of memory type arg. 819 itype = ".Index" 820 } 821 822 bitPos := uint64(0) 823 // VecSpReg is encoded as an even numbered VSR. It is implicitly shifted by 1. 824 if atype.Type == asm.TypeVecSpReg { 825 bitPos += 1 826 } 827 // Count the total number of bits to work backwards when shifting 828 for _, f := range atype.BitFields { 829 bitPos += uint64(f.Bits) 830 } 831 // Adjust for any shifting (e.g DQ/DS shifted instructions) 832 bitPos += uint64(atype.Shift) 833 bits := bitPos 834 835 // Generate code to twirl the respective bits into the correct position, and mask off extras. 836 for i, f := range atype.BitFields { 837 bitPos -= uint64(f.Bits) 838 argStr := argOrder[j] + itype 839 if bitPos != 0 { 840 argStr = fmt.Sprintf("(%s>>%d)", argStr, bitPos) 841 } 842 mask := (1 << uint64(f.Bits)) - 1 843 shift := 32 - uint64(f.Offs) - uint64(f.Bits) 844 fmt.Fprintf(buf, "o%d |= uint32(%s&0x%x)<<%d // %s\n", f.Word, argStr, mask, shift, atype.BitFieldNames[i]) 845 } 846 847 // Generate a check to verify shifted inputs satisfy their constraints. 848 // For historical reasons this is not needed for 16 bit values shifted by 16. (i.e SI/UI constants in addis/xoris) 849 if atype.Type != asm.TypeNegOffset && atype.Shift != 0 && atype.Shift != 16 && bits != 32 { 850 arg := argOrder[j] + itype 851 mod := (1 << atype.Shift) - 1 852 errCheck += fmt.Sprintf("if %s & 0x%x != 0 {\n", arg, mod) 853 errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant 0x%%x (%%d) is not a multiple of %d\\n%%v\",%s,%s,p)\n", mod+1, arg, arg) 854 errCheck += fmt.Sprintf("}\n") 855 } 856 // NegOffset requires a stronger offset check 857 if atype.Type == asm.TypeNegOffset { 858 arg := argOrder[j] + itype 859 mask := -1 << (atype.BitFields.NumBits() + int(atype.Shift)) 860 maskl := mask // Sign bits are implied in this type. 861 mask |= (1 << atype.Shift) - 1 862 min := maskl 863 max := maskl | (^mask) 864 step := 1 << atype.Shift 865 errCheck += fmt.Sprintf("if %s & 0x%x != 0x%x {\n", arg, uint32(mask), uint32(maskl)) 866 errCheck += fmt.Sprintf("c.ctxt.Diag(\"Constant(%%d) must within the range of [%d,%d] in steps of %d\\n%%v\",%s,p)\n", min, max, step, arg) 867 errCheck += fmt.Sprintf("}\n") 868 } 869 j++ 870 } 871 buf.WriteString(errCheck) 872 if insn.Words > 1 { 873 fmt.Fprintf(buf, "out[1] = o1\n") 874 } 875 fmt.Fprintf(buf, "out[0] = o0\n") 876 fmt.Fprintf(buf, "}\n") 877 return buf.String() 878 } 879 880 // Generate a stringed name representing the type of arguments ISA 881 // instruction needs to be encoded into a usable machine instruction 882 func insnTypeStr(insn *Inst, uniqueRegTypes bool) string { 883 if len(insn.Fields) == 0 { 884 return "type_none" 885 } 886 887 ret := "type_" 888 889 // Tag store opcodes to give special treatment when generating 890 // assembler function. They encode similarly to their load analogues. 891 if insn.memOp { 892 if insn.memOpSt { 893 ret += "st_" 894 } else { 895 ret += "ld_" 896 } 897 } 898 899 // TODO: this is only sufficient for ISA3.1. 900 for _, atype := range insn.Fields { 901 switch atype.Type { 902 // Simple, register like 5 bit field (CR bit, FPR, GPR, VR) 903 case asm.TypeReg, asm.TypeFPReg, asm.TypeVecReg, asm.TypeCondRegBit: 904 if uniqueRegTypes { 905 ret += map[asm.ArgType]string{asm.TypeReg: "R", asm.TypeFPReg: "F", asm.TypeVecReg: "V", asm.TypeCondRegBit: "C"}[atype.Type] 906 // Handle even/odd pairs in FPR/GPR args. They encode as 5 bits too, but odd values are invalid. 907 if atype.Name[len(atype.Name)-1] == 'p' { 908 ret += "p" 909 } 910 } else { 911 ret += "R" 912 } 913 case asm.TypeMMAReg, asm.TypeCondRegField: // 3 bit register fields (MMA or CR field) 914 ret += "M" 915 case asm.TypeSpReg: 916 ret += "P" 917 case asm.TypeVecSReg: // VSX register (6 bits, usually split into 2 fields) 918 ret += "X" 919 case asm.TypeVecSpReg: // VSX register pair (5 bits, maybe split fields) 920 ret += "Y" 921 case asm.TypeImmSigned, asm.TypeOffset, asm.TypeImmUnsigned: 922 if atype.Type == asm.TypeImmUnsigned { 923 ret += "I" 924 } else { 925 ret += "S" 926 } 927 if atype.Shift != 0 { 928 ret += fmt.Sprintf("%d", atype.Shift) 929 } 930 case asm.TypeNegOffset: // e.g offset in hashst rb, offset(ra) 931 ret += "N" 932 default: 933 log.Fatalf("Unhandled type in insnTypeStr: %v\n", atype) 934 } 935 936 // And add bit packing info 937 for _, bf := range atype.BitFields { 938 ret += fmt.Sprintf("_%d_%d", bf.Word*32+bf.Offs, bf.Bits) 939 } 940 } 941 return ret 942 } 943 944 type AggInfo struct { 945 Insns []*Inst // List of instructions sharing this type 946 Typef string // The generated function name matching this 947 } 948 949 // Generate an Optab entry for a set of instructions with identical argument types 950 // and write it to buf. 951 func genOptabEntry(ta *AggInfo, typeMap map[string]*Inst) string { 952 buf := new(bytes.Buffer) 953 fitArg := func(f *Field, i *Inst) string { 954 argToRegType := map[asm.ArgType]string{ 955 // TODO: only complete for ISA 3.1 956 asm.TypeReg: "C_REG", 957 asm.TypeCondRegField: "C_CREG", 958 asm.TypeCondRegBit: "C_CRBIT", 959 asm.TypeFPReg: "C_FREG", 960 asm.TypeVecReg: "C_VREG", 961 asm.TypeVecSReg: "C_VSREG", 962 asm.TypeVecSpReg: "C_VSREG", 963 asm.TypeMMAReg: "C_AREG", 964 asm.TypeSpReg: "C_SPR", 965 } 966 if t, fnd := argToRegType[f.Type]; fnd { 967 if f.Name[len(f.Name)-1] == 'p' { 968 return t + "P" 969 } 970 return t 971 } 972 bits := f.Shift 973 for _, sf := range f.BitFields { 974 bits += sf.Bits 975 } 976 shift := "" 977 if f.Shift != 0 { 978 shift = fmt.Sprintf("S%d", f.Shift) 979 } 980 sign := "U" 981 if f.Type == asm.TypeImmSigned || f.Type == asm.TypeOffset { 982 sign = "S" 983 // DS/DQ offsets should explicitly test their offsets to ensure 984 // they are aligned correctly. This makes tracking down bad offset 985 // passed to the compiler more straightfoward. 986 if f.Type == asm.TypeOffset { 987 shift = "" 988 } 989 } 990 if f.Type == asm.TypeNegOffset { 991 // This is a hack, but allows hashchk and like to correctly 992 // merge there argument into a C_SOREG memory location type 993 // argument a little later. 994 sign = "S" 995 bits = 16 996 shift = "" 997 } 998 return fmt.Sprintf("C_%s%d%sCON", sign, bits, shift) 999 } 1000 insn := ta.Insns[0] 1001 args := [6]string{} 1002 // Note, a2 is skipped if the second input argument does not map to a reg. 1003 argOrder := []int{ 1004 5, 1005 0, 1006 1, 1007 2, 1008 3, 1009 4} 1010 1011 i := 0 1012 for _, j := range insn.Fields { 1013 // skip a2 if it isn't a reg type. 1014 at := fitArg(&j, insn) 1015 if argOrder[i] == 1 && !strings.HasSuffix(at, "REG") { 1016 i++ 1017 } 1018 args[argOrder[i]] = at 1019 i++ 1020 } 1021 1022 // Likewise, fixup memory operations. Combine imm + reg, reg + reg 1023 // operations into memory type arguments. 1024 if insn.memOp { 1025 switch args[0] + " " + args[1] { 1026 case "C_REG C_REG": 1027 args[0] = "C_XOREG" 1028 case "C_S16CON C_REG": 1029 args[0] = "C_SOREG" 1030 case "C_S34CON C_REG": 1031 args[0] = "C_LOREG" 1032 } 1033 args[1] = "" 1034 // Finally, fixup store operand ordering to match golang 1035 if insn.memOpSt { 1036 args[0], args[5] = args[5], args[0] 1037 } 1038 1039 } 1040 fmt.Fprintf(buf, "{as: A%s,", opName(insn.Op)) 1041 for i, s := range args { 1042 if len(s) <= 0 { 1043 continue 1044 } 1045 fmt.Fprintf(buf, "a%d: %s, ", i+1, s) 1046 } 1047 typef := typeMap[ta.Typef].Op 1048 1049 pfx := "" 1050 if insn.Words > 1 { 1051 pfx = " ispfx: true," 1052 } 1053 fmt.Fprintf(buf, "asmout: type_%s,%s size: %d},\n", typef, pfx, insn.Words*4) 1054 return buf.String() 1055 } 1056 1057 // printEncoder implements the -fmt=encoder mode. This generates a go file named 1058 // asm9_gtables.go.new. It is self-contained and is called into by the PPC64 1059 // assembler routines. 1060 // 1061 // For now it is restricted to generating code for ISA 3.1 and newer, but it could 1062 // support older ISA versions with some work, and integration effort. 1063 func printEncoder(p *Prog) { 1064 const minISA = ISA_V31 1065 1066 // The type map separates based on obj.Addr to a bit field. Register types 1067 // for GPR, FPR, VR pack identically, but are classified differently. 1068 typeMap := map[string]*Inst{} 1069 typeAggMap := map[string]*AggInfo{} 1070 var oplistBuf bytes.Buffer 1071 var opnameBuf bytes.Buffer 1072 1073 // The first opcode of 32 or 64 bits to appear in the opcode tables. 1074 firstInsn := [2]string{} 1075 1076 // Sort the instructions by word size, then by ISA version, oldest to newest. 1077 sort.Slice(p.Insts, func(i, j int) bool { 1078 if p.Insts[i].Words != p.Insts[j].Words { 1079 return p.Insts[i].Words < p.Insts[j].Words 1080 } 1081 return p.Insts[i].order > p.Insts[j].order 1082 }) 1083 1084 // Classify each opcode and it's arguments, and generate opcode name/enum values. 1085 for i, insn := range p.Insts { 1086 if insn.Isa < minISA { 1087 continue 1088 } 1089 extra := "" 1090 if firstInsn[insn.Words-1] == "" { 1091 firstInsn[insn.Words-1] = opName(insn.Op) 1092 if insn.Words == 1 { 1093 extra = " = ALASTAOUT + iota" 1094 } 1095 } 1096 opType := insnTypeStr(&insn, false) 1097 opTypeOptab := insnTypeStr(&insn, true) 1098 fmt.Fprintf(&oplistBuf, "A%s%s\n", opName(insn.Op), extra) 1099 fmt.Fprintf(&opnameBuf, "\"%s\",\n", opName(insn.Op)) 1100 // Use the oldest instruction to name the encoder function. Some names 1101 // may change if minISA is lowered. 1102 if _, fnd := typeMap[opType]; !fnd { 1103 typeMap[opType] = &p.Insts[i] 1104 } 1105 at, fnd := typeAggMap[opTypeOptab] 1106 if !fnd { 1107 typeAggMap[opTypeOptab] = &AggInfo{[]*Inst{&p.Insts[i]}, opType} 1108 } else { 1109 at.Insns = append(at.Insns, &p.Insts[i]) 1110 } 1111 } 1112 fmt.Fprintf(&oplistBuf, "ALASTGEN\n") 1113 fmt.Fprintf(&oplistBuf, "AFIRSTGEN = A%s\n", firstInsn[0]) 1114 1115 // Sort type information before outputing to ensure stable ordering 1116 targ := struct { 1117 InputFile string 1118 Insts []Inst 1119 MinISA isaversion 1120 TypeAggList []*AggInfo 1121 TypeList []*Inst 1122 FirstInsn [2]string 1123 TypeMap map[string]*Inst 1124 Oplist string 1125 Opnames string 1126 }{InputFile: inputFile, Insts: p.Insts, MinISA: minISA, FirstInsn: firstInsn, TypeMap: typeMap, Oplist: oplistBuf.String(), Opnames: opnameBuf.String()} 1127 for _, v := range typeAggMap { 1128 targ.TypeAggList = append(targ.TypeAggList, v) 1129 } 1130 for _, v := range typeMap { 1131 targ.TypeList = append(targ.TypeList, v) 1132 } 1133 sort.Slice(targ.TypeAggList, func(i, j int) bool { 1134 // Sort based on the first entry, it is the last to appear in Appendix F. 1135 return targ.TypeAggList[i].Insns[0].Op < targ.TypeAggList[j].Insns[0].Op 1136 }) 1137 sort.Slice(targ.TypeList, func(i, j int) bool { 1138 return targ.TypeList[i].Op < targ.TypeList[j].Op 1139 }) 1140 1141 // Generate asm9_gtable.go from the following template. 1142 asm9_gtable_go := ` 1143 // DO NOT EDIT 1144 // generated by: ppc64map -fmt=encoder {{.InputFile}} 1145 1146 package ppc64 1147 1148 import ( 1149 "cmd/internal/obj" 1150 ) 1151 1152 const ( 1153 {{print $.Oplist -}} 1154 ) 1155 1156 var GenAnames = []string { 1157 {{print $.Opnames -}} 1158 } 1159 1160 var GenOpcodes = [...]uint32 { 1161 {{range $v := .Insts}}{{if ge $v.Isa $.MinISA -}} 1162 {{if (eq $v.Words 1)}}{{printf "0x%08x, // A%s" $v.Value (opname $v.Op)}} 1163 {{else}} {{printf "0x%08x, // A%s" $v.SValue (opname $v.Op)}} 1164 {{end}}{{end}}{{end -}} 1165 } 1166 1167 var GenPfxOpcodes = [...]uint32 { 1168 {{range $v := .Insts}}{{if and (ge $v.Isa $.MinISA) (eq $v.Words 2) -}} 1169 {{printf "0x%08x, // A%s" $v.Value (opname $v.Op)}} 1170 {{end}}{{end -}} 1171 } 1172 1173 var optabGen = []Optab { 1174 {{range $v := .TypeAggList -}} 1175 {{genoptabentry $v $.TypeMap -}} 1176 {{end -}} 1177 } 1178 1179 {{range $v := .TypeList}} 1180 {{genencoderfunc $v $.FirstInsn}} 1181 {{end}} 1182 1183 func opsetGen(from obj.As) bool { 1184 r0 := from & obj.AMask 1185 switch from { 1186 {{range $v := .TypeAggList -}} 1187 case A{{opname (index $v.Insns 0).Op}}: 1188 {{range $w := (slice $v.Insns 1) -}} 1189 opset(A{{opname $w.Op}},r0) 1190 {{end -}} 1191 {{end -}} 1192 default: 1193 return false 1194 } 1195 return true 1196 } 1197 ` 1198 tmpl := template.New("asm9_gtable.go") 1199 tmpl.Funcs(template.FuncMap{ 1200 "opname": opName, 1201 "genencoderfunc": insnEncFuncStr, 1202 "genoptabentry": genOptabEntry, 1203 }) 1204 tmpl.Parse(asm9_gtable_go) 1205 1206 // Write and gofmt the new file. 1207 var tbuf bytes.Buffer 1208 if err := tmpl.Execute(&tbuf, targ); err != nil { 1209 log.Fatal(err) 1210 } 1211 tout, err := gofmt.Source(tbuf.Bytes()) 1212 if err != nil { 1213 fmt.Printf("%s", tbuf.Bytes()) 1214 log.Fatalf("gofmt error: %v", err) 1215 } 1216 if err := os.WriteFile("asm9_gtables.go.new", tout, 0666); err != nil { 1217 log.Fatalf("Failed to create asm9_gtables.new: %v", err) 1218 } 1219 } 1220 1221 // printASM implements the -fmt=asm mode. This prints out a gnu assembler file 1222 // which can be used to used to generate test output to verify the golang 1223 // disassembler's gnu output matches gnu binutils. This is used as an input to 1224 // ppc64util to generate the decode_generated.txt test case. 1225 func printASM(p *Prog) { 1226 fmt.Printf("#include \"hack.h\"\n") 1227 fmt.Printf(".text\n") 1228 for _, inst := range p.Insts { 1229 // Prefixed load/stores have extra restrictions with D(RA) and R. Rename them 1230 // To simplify generation. 1231 str := inst.Encoding 1232 if str[0] == 'p' && str[len(str)-1] == 'R' { 1233 str = strings.Replace(str, "D(RA),R", "Dpfx(RApfx),Rpfx", 1) 1234 str = strings.Replace(str, "RA,SI,R", "RApfx,SIpfx,Rpfx", 1) 1235 } 1236 fmt.Printf("\t%s\n", str) 1237 } 1238 } 1239 1240 // opName translate an opcode to a valid Go identifier all-cap op name. 1241 func opName(op string) string { 1242 return strings.ToUpper(strings.Replace(op, ".", "CC", 1)) 1243 } 1244 1245 // argFieldName constructs a name for the argField 1246 func argFieldName(f Field) string { 1247 ns := []string{"ap", f.Type.String()} 1248 for _, b := range f.BitFields { 1249 ns = append(ns, fmt.Sprintf("%d_%d", b.Word*32+b.Offs, b.Word*32+b.Offs+b.Bits-1)) 1250 } 1251 if f.Shift > 0 { 1252 ns = append(ns, fmt.Sprintf("shift%d", f.Shift)) 1253 } 1254 return strings.Join(ns, "_") 1255 } 1256 1257 var funcBodyTmpl = template.Must(template.New("funcBody").Parse(``)) 1258 1259 // printDecoder implements the -fmt=decoder mode. 1260 // It emits the tables.go for package armasm's decoder. 1261 func printDecoder(p *Prog) { 1262 var buf bytes.Buffer 1263 1264 fmt.Fprintf(&buf, "// Code generated by ppc64map -fmt=decoder %s DO NOT EDIT.\n", inputFile) 1265 fmt.Fprintf(&buf, "\n") 1266 1267 fmt.Fprintf(&buf, "package ppc64asm\n\n") 1268 1269 // Build list of opcodes, using the csv order (which corresponds to ISA docs order) 1270 m := map[string]bool{} 1271 fmt.Fprintf(&buf, "const (\n\t_ Op = iota\n") 1272 for _, inst := range p.Insts { 1273 name := opName(inst.Op) 1274 if ok := m[name]; ok { 1275 continue 1276 } 1277 m[name] = true 1278 fmt.Fprintf(&buf, "\t%s\n", name) 1279 } 1280 fmt.Fprint(&buf, ")\n\n\n") 1281 1282 // Emit slice mapping opcode number to name string. 1283 m = map[string]bool{} 1284 fmt.Fprintf(&buf, "var opstr = [...]string{\n") 1285 for _, inst := range p.Insts { 1286 name := opName(inst.Op) 1287 if ok := m[name]; ok { 1288 continue 1289 } 1290 m[name] = true 1291 fmt.Fprintf(&buf, "\t%s: %q,\n", opName(inst.Op), inst.Op) 1292 } 1293 fmt.Fprint(&buf, "}\n\n\n") 1294 1295 // print out argFields 1296 fmt.Fprintf(&buf, "var (\n") 1297 m = map[string]bool{} 1298 for _, inst := range p.Insts { 1299 for _, f := range inst.Fields { 1300 name := argFieldName(f) 1301 if ok := m[name]; ok { 1302 continue 1303 } 1304 m[name] = true 1305 fmt.Fprintf(&buf, "\t%s = &argField{Type: %#v, Shift: %d, BitFields: BitFields{", name, f.Type, f.Shift) 1306 for _, b := range f.BitFields { 1307 fmt.Fprintf(&buf, "{%d, %d, %d},", b.Offs, b.Bits, b.Word) 1308 } 1309 fmt.Fprintf(&buf, "}}\n") 1310 } 1311 } 1312 fmt.Fprint(&buf, ")\n\n\n") 1313 1314 // Emit decoding table. 1315 fmt.Fprintf(&buf, "var instFormats = [...]instFormat{\n") 1316 for _, inst := range p.Insts { 1317 m, v, dc := uint64(inst.Mask)<<32, uint64(inst.Value)<<32, uint64(inst.DontCare)<<32 1318 m, v, dc = uint64(inst.SMask)|m, uint64(inst.SValue)|v, uint64(inst.SDontCare)|dc 1319 fmt.Fprintf(&buf, "\t{ %s, %#x, %#x, %#x,", opName(inst.Op), m, v, dc) 1320 fmt.Fprintf(&buf, " // %s (%s)\n\t\t[6]*argField{", inst.Text, inst.Encoding) 1321 for _, f := range inst.Fields { 1322 fmt.Fprintf(&buf, "%s, ", argFieldName(f)) 1323 } 1324 fmt.Fprintf(&buf, "}},\n") 1325 } 1326 fmt.Fprint(&buf, "}\n\n") 1327 1328 out, err := gofmt.Source(buf.Bytes()) 1329 if err != nil { 1330 log.Fatalf("gofmt error: %v", err) 1331 fmt.Printf("%s", buf.Bytes()) 1332 } else { 1333 fmt.Printf("%s", out) 1334 } 1335 }