func add()

in ppc64/ppc64map/map.go [332:642]


func add(p *Prog, text, mnemonics, encoding, tags string) {
	// Parse encoding, building size and offset of each field.
	// The first field in the encoding is the smallest offset.
	// And note the MSB is bit 0, not bit 31.
	// Example: "31@0|RS@6|RA@11|///@16|26@21|Rc@31|"
	var args, pargs Args
	var pmask, pvalue, presv, resv uint32
	iword := int8(0)
	ispfx := false

	// Is this a prefixed instruction?
	if encoding[0] == ',' {
		pfields := strings.Split(encoding, ",")[1:]

		if len(pfields) != 2 {
			fmt.Fprintf(os.Stderr, "%s: Prefixed instruction must be 2 words long.\n", text)
			return
		}
		pargs = parseFields(pfields[0], text, iword)
		pmask, pvalue, presv = computeMaskValueReserved(pargs, text)
		// Move to next instruction word
		iword++
		encoding = pfields[1]
		ispfx = true
	}

	args = parseFields(encoding, text, iword)
	mask, value, dontCare := computeMaskValueReserved(args, text)

	if ispfx {
		args = append(args, pargs...)
	}

	// split mnemonics into individual instructions
	// 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)"
	insts := strings.Split(categoryRe.ReplaceAllString(mnemonics, ""), "|")
	foundInst := []Inst{}
	for _, inst := range insts {
		value, mask := value, mask
		pvalue, pmask := pvalue, pmask
		args := args.Clone()
		if inst == "" {
			continue
		}
		// amend mask and value
		parts := instRe.FindStringSubmatch(inst)
		if parts == nil {
			log.Fatalf("%v couldn't match %s", instRe, inst)
		}
		conds := condRe.FindAllStringSubmatch(parts[2], -1)
		isPCRel := true
		for _, cond := range conds {
			i := args.Find(cond[1])
			v, _ := strconv.ParseInt(cond[2], 16, 32) // the regular expression has checked the number format
			if i < 0 {
				log.Fatalf("%s: %s don't contain arg %s used in %s", text, args, cond[1], inst)
			}
			if cond[1] == "AA" && v == 1 {
				isPCRel = false
			}
			mask |= args[i].BitMask()
			value |= uint32(v) << args[i].Shift()
			args.Delete(i)
		}
		inst := Inst{Text: text, Encoding: parts[1], Value: value, Mask: mask, DontCare: dontCare}
		if ispfx {
			inst = Inst{Text: text, Encoding: parts[1], Value: pvalue, Mask: pmask, DontCare: presv, SValue: value, SMask: mask, SDontCare: resv}
		}

		// order inst.Args according to mnemonics order
		for i, opr := range operandRe.FindAllString(parts[1], -1) {
			if i == 0 { // operation
				inst.Op = opr
				continue
			}
			field := Field{Name: opr}
			typ := asm.TypeUnknown
			var shift uint8
			opr2 := ""
			opr3 := ""
			switch opr {
			case "target_addr":
				shift = 2
				if isPCRel {
					typ = asm.TypePCRel
				} else {
					typ = asm.TypeLabel
				}
				if args.Find("LI") >= 0 {
					opr = "LI"
				} else {
					opr = "BD"
				}

			case "XMSK", "YMSK", "PMSK", "IX":
				typ = asm.TypeImmUnsigned

			case "IMM32":
				typ = asm.TypeImmUnsigned
				opr = "imm0"
				opr2 = "imm1"

			// Handle these cases specially. Note IMM is used on
			// prefixed MMA instructions as a bitmask. Usually, it is a signed value.
			case "R", "UIM", "IMM":
				if ispfx {
					typ = asm.TypeImmUnsigned
					break
				}
				fallthrough

			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":
				typ = asm.TypeImmUnsigned
				if i := args.Find(opr); i < 0 {
					log.Printf("coerce to D: %s: couldn't find extended field %s in %s", text, opr, args)
					opr = "D"
				}
			case "bm":
				opr = "b0"
				opr2 = "b1"
				opr3 = "b2"
				typ = asm.TypeImmUnsigned

			case "SH":
				typ = asm.TypeImmUnsigned
				if args.Find("sh2") >= 0 { // sh2 || sh
					opr = "sh2"
					opr2 = "sh"
				}
			case "MB", "ME":
				typ = asm.TypeImmUnsigned
				if n := strings.ToLower(opr); args.Find(n) >= 0 {
					opr = n // xx[5] || xx[0:4]
				}
			case "SI", "SIM", "TE":
				if ispfx {
					typ = asm.TypeImmSigned
					opr = "si0"
					opr2 = "si1"
					break
				}
				typ = asm.TypeImmSigned
				if i := args.Find(opr); i < 0 {
					opr = "D"
				}
			case "DCMX":
				typ = asm.TypeImmUnsigned
				// Some instructions encode this consecutively.
				if i := args.Find(opr); i >= 0 {
					break
				}
				typ = asm.TypeImmUnsigned
				opr = "dc"
				opr2 = "dm"
				opr3 = "dx"
			case "DS":
				typ = asm.TypeOffset
				shift = 2
			case "DQ":
				typ = asm.TypeOffset
				shift = 4
			case "D":
				if ispfx {
					typ = asm.TypeOffset
					opr = "d0"
					opr2 = "d1"
					break
				}
				if i := args.Find(opr); i >= 0 {
					typ = asm.TypeOffset
					break
				}
				if i := args.Find("UI"); i >= 0 {
					typ = asm.TypeImmUnsigned
					opr = "UI"
					break
				}
				if i := args.Find("SI"); i >= 0 {
					typ = asm.TypeImmSigned
					opr = "SI"
					break
				}
				if i := args.Find("d0"); i >= 0 {
					typ = asm.TypeImmSigned
					// DX-form
					opr = "d0"
					opr2 = "d1"
					opr3 = "d2"
				}
			case "RA", "RB", "RC", "RS", "RSp", "RT", "RTp":
				typ = asm.TypeReg
			case "BT", "BA", "BB", "BC", "BI":
				if strings.HasPrefix(inst.Op, "mtfs") {
					// mtfsb[01] instructions use BT, but they specify fields in the fpscr.
					typ = asm.TypeImmUnsigned
				} else {
					typ = asm.TypeCondRegBit
				}
			case "BF", "BFA":
				if strings.HasPrefix(inst.Op, "mtfs") {
					// mtfsfi[.] instructions use BF, but they specify fields in the fpscr.
					typ = asm.TypeImmUnsigned
				} else {
					typ = asm.TypeCondRegField
				}
			case "FRA", "FRB", "FRBp", "FRC", "FRS", "FRSp", "FRT", "FRTp", "FRAp":
				typ = asm.TypeFPReg
			case "XA", "XB", "XC", "XS", "XT": // 5-bit, split field
				typ = asm.TypeVecSReg
				opr2 = opr[1:]
				opr = opr[1:] + "X"
			case "XTp", "XSp": // 5-bit, split field
				//XTp encodes 5 bits, VSR is XT*32 + TP<<1
				typ = asm.TypeVecSpReg
				opr2 = opr[1:2] + "p"
				opr = opr[1:2] + "X"

			case "XAp":
				// XAp in MMA encodes a regular VSR, but is only valid
				// if it is even, and does not overlap the accumulator.
				typ = asm.TypeVecSReg
				opr2 = opr[1:2] + "p"
				opr = opr[1:2] + "X"

			case "AT", "AS":
				typ = asm.TypeMMAReg

			case "VRA", "VRB", "VRC", "VRS", "VRT":
				typ = asm.TypeVecReg

			case "SPR", "DCRN", "BHRBE", "TBR", "SR", "TMR", "PMRN": // Note: if you add to this list and the register field needs special handling, add it to switch statement below
				typ = asm.TypeSpReg
				switch opr {
				case "DCRN":
					opr = "DCR"
				}
				if n := strings.ToLower(opr); n != opr && args.Find(n) >= 0 {
					opr = n // spr[5:9] || spr[0:4]
				}
			}
			if typ == asm.TypeUnknown {
				log.Fatalf("%s %s unknown type for opr %s", text, inst, opr)
			}
			field.Type = typ
			field.Shift = shift
			var f1, f2, f3 asm.BitField
			switch {
			case opr3 != "":
				b0 := args.Find(opr)
				b1 := args.Find(opr2)
				b2 := args.Find(opr3)
				f1.Offs, f1.Bits, f1.Word = uint8(args[b0].Offs), uint8(args[b0].Bits), uint8(args[b0].Word)
				f2.Offs, f2.Bits, f2.Word = uint8(args[b1].Offs), uint8(args[b1].Bits), uint8(args[b1].Word)
				f3.Offs, f3.Bits, f3.Word = uint8(args[b2].Offs), uint8(args[b2].Bits), uint8(args[b2].Word)

			case opr2 != "":
				ext := args.Find(opr)
				if ext < 0 {
					log.Fatalf("%s: couldn't find extended field %s in %s", text, opr, args)
				}
				f1.Offs, f1.Bits, f1.Word = uint8(args[ext].Offs), uint8(args[ext].Bits), uint8(args[ext].Word)
				base := args.Find(opr2)
				if base < 0 {
					log.Fatalf("%s: couldn't find base field %s in %s", text, opr2, args)
				}
				f2.Offs, f2.Bits, f2.Word = uint8(args[base].Offs), uint8(args[base].Bits), uint8(args[base].Word)
			case opr == "mb", opr == "me": // xx[5] || xx[0:4]
				i := args.Find(opr)
				if i < 0 {
					log.Fatalf("%s: couldn't find special 'm[be]' field for %s in %s", text, opr, args)
				}
				f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs+args[i].Bits)-1, 1, uint8(args[i].Word)
				f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), uint8(args[i].Bits)-1, uint8(args[i].Word)
			case opr == "spr", opr == "tbr", opr == "tmr", opr == "dcr": // spr[5:9] || spr[0:4]
				i := args.Find(opr)
				if i < 0 {
					log.Fatalf("%s: couldn't find special 'spr' field for %s in %s", text, opr, args)
				}
				if args[i].Bits != 10 {
					log.Fatalf("%s: special 'spr' field is not 10-bit: %s", text, args)
				}
				f1.Offs, f1.Bits, f2.Word = uint8(args[i].Offs)+5, 5, uint8(args[i].Word)
				f2.Offs, f2.Bits, f2.Word = uint8(args[i].Offs), 5, uint8(args[i].Word)
			default:
				i := args.Find(opr)
				if i < 0 {
					log.Fatalf("%s: couldn't find %s in %s", text, opr, args)
				}
				f1.Offs, f1.Bits, f1.Word = uint8(args[i].Offs), uint8(args[i].Bits), uint8(args[i].Word)
			}
			field.BitFields.Append(f1)
			if f2.Bits > 0 {
				field.BitFields.Append(f2)
			}
			if f3.Bits > 0 {
				field.BitFields.Append(f3)
			}
			inst.Fields = append(inst.Fields, field)
		}
		if *debug {
			fmt.Printf("%v\n", inst)
		}
		foundInst = append(foundInst, inst)
	}

	// Sort mnemonics by bitcount.  This ensures more specific mnemonics are picked
	// up before generic ones (e.g li vs addi, or cmpld/cmplw vs cmpl)
	sort.Sort(instArray(foundInst))

	p.Insts = append(p.Insts, foundInst...)
}