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...)
}