ppc64asm,ppc64map: update for ISA 3.1
Likewise, add all missing ISA 3.0 instructions. This table is generated in a two-step process. 1. Parse ISA 3.1 Appendix F. 2. Scan ISA for descriptions 3. Sort to match old ISA (and check for bugs) and append new insn to bottom A second patch will reformat these instructions into a sorting order of the ISA 3.1 appendix F, that is by version then alphabetically. This intermediate patch ensures we don't regress, and helped catch quite a few ISA 3.1 typos. The tooling is left in another repo, and is loosely based on the spec.go tooling for ppc64. Notably, transaction memory instructions are effectively removed in ISA 3.1, and some shuffling of descriptions has result in cmp*/li/lis becoming extended mnemonics instead, thus they go away. VLE/SPE/embedded instructions are also removed. They were never used, and have been removed since ISA 3.0. Similarly, the new ISA introduces prefixed instructions using opcode 1. They are encoded like two instruction words. However, it should be noted prefixes cannot be applied to any instruction, only those specifically enumerated in the documentation. Likewise, what would be the primary opcode of the suffixed instruction is not always identical to it's non-prefixed counterpart. A number of small changes have been made to the parser to accomodate new instructions and minor changes to existing ones. Note, DCBI was a book iii-e instruction in ISA 2.07, and only emulated on P8, and the opcode is reserved in newer ISAs. Note, isel BI decoding is slightly different than gnu. It is much more readable to decode like other condition register BI fields. Similarly, paste. and mtfsf* like instruction decoding is improved to match the newer ISA. Note, book ii extended mnemonics are mostly ignored. These are inconsistently described in the documentation, and most should never appear in golang compiled code. We do handle the exceptional cases for some, such as the hwsync/lwsync and the l*arx instructions. Change-Id: I41711807a5fbdbdd22a2bde4159a09dad5382691 Reviewed-on: https://go-review.googlesource.com/c/arch/+/298793 Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com> Reviewed-by: Carlos Eduardo Seo <carlos.seo@linaro.org> Trust: Carlos Eduardo Seo <carlos.seo@linaro.org>
This commit is contained in:
Родитель
ea130f1b0a
Коммит
d48d9c4a19
1946
ppc64/pp64.csv
1946
ppc64/pp64.csv
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -54,6 +54,10 @@ func (a argField) Parse(i uint32) Arg {
|
|||
return V0 + Reg(a.BitFields.Parse(i))
|
||||
case TypeVecSReg:
|
||||
return VS0 + Reg(a.BitFields.Parse(i))
|
||||
case TypeVecSpReg:
|
||||
return VS0 + Reg(a.BitFields.Parse(i))*2
|
||||
case TypeMMAReg:
|
||||
return A0 + Reg(a.BitFields.Parse(i))
|
||||
case TypeSpReg:
|
||||
return SpReg(a.BitFields.Parse(i))
|
||||
case TypeImmSigned:
|
||||
|
@ -81,6 +85,8 @@ const (
|
|||
TypeFPReg // floating point register
|
||||
TypeVecReg // vector register
|
||||
TypeVecSReg // VSX register
|
||||
TypeVecSpReg // VSX register pair (even only encoding)
|
||||
TypeMMAReg // MMA register
|
||||
TypeSpReg // special register (depends on Op)
|
||||
TypeImmSigned // signed immediate
|
||||
TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type
|
||||
|
@ -106,6 +112,10 @@ func (t ArgType) String() string {
|
|||
return "VecReg"
|
||||
case TypeVecSReg:
|
||||
return "VecSReg"
|
||||
case TypeVecSpReg:
|
||||
return "VecSpReg"
|
||||
case TypeMMAReg:
|
||||
return "MMAReg"
|
||||
case TypeSpReg:
|
||||
return "SpReg"
|
||||
case TypeImmSigned:
|
||||
|
|
|
@ -34,6 +34,8 @@ func GNUSyntax(inst Inst, pc uint64) string {
|
|||
startArg := 0
|
||||
sep := " "
|
||||
opName := inst.Op.String()
|
||||
argList := inst.Args[:]
|
||||
|
||||
switch opName {
|
||||
case "bc", "bcl", "bca", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
|
||||
sfx := inst.Op.String()[2:]
|
||||
|
@ -223,23 +225,68 @@ func GNUSyntax(inst Inst, pc uint64) string {
|
|||
buf.WriteString("spr")
|
||||
}
|
||||
|
||||
case "sync":
|
||||
switch arg := inst.Args[0].(type) {
|
||||
case Imm:
|
||||
switch arg {
|
||||
case 0:
|
||||
buf.WriteString("hwsync")
|
||||
case 1:
|
||||
buf.WriteString("lwsync")
|
||||
case 2:
|
||||
buf.WriteString("ptesync")
|
||||
}
|
||||
case "mtfsfi", "mtfsfi.":
|
||||
buf.WriteString(opName)
|
||||
l := inst.Args[2].(Imm)
|
||||
if l == 0 {
|
||||
// L == 0 is an extended mnemonic for the same.
|
||||
asm := fmt.Sprintf(" %s,%s",
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
gnuArg(&inst, 1, inst.Args[1], PC))
|
||||
buf.WriteString(asm)
|
||||
startArg = 3
|
||||
}
|
||||
startArg = 2
|
||||
|
||||
case "paste.":
|
||||
buf.WriteString(opName)
|
||||
l := inst.Args[2].(Imm)
|
||||
if l == 1 {
|
||||
// L == 1 is an extended mnemonic for the same.
|
||||
asm := fmt.Sprintf(" %s,%s",
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
gnuArg(&inst, 1, inst.Args[1], PC))
|
||||
buf.WriteString(asm)
|
||||
startArg = 3
|
||||
}
|
||||
|
||||
case "mtfsf", "mtfsf.":
|
||||
buf.WriteString(opName)
|
||||
l := inst.Args[3].(Imm)
|
||||
if l == 0 {
|
||||
// L == 0 is an extended mnemonic for the same.
|
||||
asm := fmt.Sprintf(" %s,%s,%s",
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
gnuArg(&inst, 1, inst.Args[1], PC),
|
||||
gnuArg(&inst, 2, inst.Args[2], PC))
|
||||
buf.WriteString(asm)
|
||||
startArg = 4
|
||||
}
|
||||
|
||||
case "sync":
|
||||
lsc := inst.Args[0].(Imm)<<4 | inst.Args[1].(Imm)
|
||||
switch lsc {
|
||||
case 0x00:
|
||||
buf.WriteString("hwsync")
|
||||
startArg = 2
|
||||
case 0x10:
|
||||
buf.WriteString("lwsync")
|
||||
startArg = 2
|
||||
default:
|
||||
buf.WriteString(opName)
|
||||
}
|
||||
|
||||
case "lbarx", "lharx", "lwarx", "ldarx":
|
||||
// If EH == 0, omit printing EH.
|
||||
eh := inst.Args[3].(Imm)
|
||||
if eh == 0 {
|
||||
argList = inst.Args[:3]
|
||||
}
|
||||
buf.WriteString(inst.Op.String())
|
||||
|
||||
default:
|
||||
buf.WriteString(inst.Op.String())
|
||||
}
|
||||
for i, arg := range inst.Args[:] {
|
||||
for i, arg := range argList {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -220,6 +220,14 @@ const (
|
|||
VS61
|
||||
VS62
|
||||
VS63
|
||||
A0 // MMA registers. These are effectively shadow registers of four adjacent VSR's [An*4,An*4+3]
|
||||
A1
|
||||
A2
|
||||
A3
|
||||
A4
|
||||
A5
|
||||
A6
|
||||
A7
|
||||
)
|
||||
|
||||
func (Reg) IsArg() {}
|
||||
|
@ -233,6 +241,8 @@ func (r Reg) String() string {
|
|||
return fmt.Sprintf("v%d", int(r-V0))
|
||||
case VS0 <= r && r <= VS63:
|
||||
return fmt.Sprintf("vs%d", int(r-VS0))
|
||||
case A0 <= r && r <= A7:
|
||||
return fmt.Sprintf("a%d", int(r-A0))
|
||||
default:
|
||||
return fmt.Sprintf("Reg(%d)", int(r))
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool
|
|||
return true
|
||||
case MTVSRWA, MTVSRWZ, MFVSRWZ, MFVSRD, MTVSRD: // We don't support extended mnemonics using VRs or FPRs
|
||||
return true
|
||||
case ISEL: // We decode the BI similar to conditional branch insn, objdump doesn't.
|
||||
return true
|
||||
case SYNC, WAIT, RFEBB: // ISA 3.1 adds more bits and extended mnemonics for these book ii instructions.
|
||||
return true
|
||||
}
|
||||
|
||||
if len(dec.enc) >= 4 {
|
||||
|
|
|
@ -76,6 +76,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
|
|||
}
|
||||
args = append(args, args[0])
|
||||
return op + " " + strings.Join(args[1:], ",")
|
||||
case PASTECC:
|
||||
// paste. has two input registers, and an L field, unlike other 3 operand instructions.
|
||||
return op + " " + args[0] + "," + args[1] + "," + args[2]
|
||||
case SYNC:
|
||||
if args[0] == "$1" {
|
||||
return "LWSYNC"
|
||||
|
@ -136,7 +139,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
|
|||
case LXVL, LXVLL:
|
||||
return op + " " + args[1] + "," + args[2] + "," + args[0]
|
||||
|
||||
case DCBT, DCBTST, DCBZ, DCBST, DCBI, ICBI:
|
||||
case DCBT, DCBTST, DCBZ, DCBST, ICBI:
|
||||
if args[0] == "0" || args[0] == "R0" {
|
||||
return op + " (" + args[1] + ")"
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -184,7 +184,7 @@ b4830002| plan9 MOVHU R4,2(R3)
|
|||
7c6400f4| plan9 POPCNTB R3,R4
|
||||
7c6402f4| plan9 POPCNTW R3,R4
|
||||
7c6403f4| plan9 POPCNTD R3,R4
|
||||
7c23270d| plan9 PASTECC R3,R4
|
||||
7c23270d| plan9 PASTECC R3,R4,$1
|
||||
7c23260c| plan9 COPY R3,R4
|
||||
7ca01868| plan9 LBAR (R3),R5
|
||||
7ca018e8| plan9 LHAR (R3),R5
|
||||
|
@ -196,7 +196,6 @@ b4830002| plan9 MOVHU R4,2(R3)
|
|||
7c0004ac| plan9 HWSYNC
|
||||
4c00012c| plan9 ISYNC
|
||||
7c2004ac| plan9 LWSYNC
|
||||
7c041bac| plan9 DCBI (R3)(R4)
|
||||
7c04186c| plan9 DCBST (R3)(R4)
|
||||
7c041fec| plan9 DCBZ (R3)(R4)
|
||||
7c041a2c| plan9 DCBT (R3)(R4)
|
||||
|
@ -585,7 +584,6 @@ b4830002| gnu sthu r4,2(r3)
|
|||
4c00012c| gnu isync
|
||||
7c0004ac| gnu hwsync
|
||||
7c2004ac| gnu lwsync
|
||||
7c041bac| gnu dcbi r4,r3
|
||||
7c04186c| gnu dcbst r4,r3
|
||||
7c041fec| gnu dcbz r4,r3
|
||||
7c041a2c| gnu dcbt r4,r3,0
|
||||
|
@ -846,3 +844,13 @@ f0400fe0| gnu xvcvsxddp vs2,vs1
|
|||
7c6802a6| gnu mflr r3
|
||||
7c6902a6| gnu mfctr r3
|
||||
4c8c0000| gnu mcrf cr1,cr3
|
||||
7c2101a7| gnu mtvsrwa vs33,r1
|
||||
7c2101e7| gnu mtvsrwz vs33,r1
|
||||
7ce10067| gnu mfvsrd r1,vs39
|
||||
7ce100e7| gnu mfvsrwz r1,vs39
|
||||
7c210167| gnu mtvsrd vs33,r1
|
||||
7c8112de| gnu isel r4,r1,r2,4*cr2+so
|
||||
7c2104ac| gnu sync 1,1
|
||||
7c2110ac| gnu dcbf r1,r2,1
|
||||
7c20003c| gnu wait 1,0
|
||||
4c000924| gnu rfebb 1
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -14,15 +14,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"flag"
|
||||
"fmt"
|
||||
gofmt "go/format"
|
||||
"log"
|
||||
"math/bits"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
@ -30,7 +31,7 @@ import (
|
|||
asm "golang.org/x/arch/ppc64/ppc64asm"
|
||||
)
|
||||
|
||||
var format = flag.String("fmt", "text", "output format: text, decoder")
|
||||
var format = flag.String("fmt", "text", "output format: text, decoder, asm")
|
||||
var debug = flag.Bool("debug", false, "enable debugging output")
|
||||
|
||||
var inputFile string
|
||||
|
@ -60,13 +61,15 @@ func main() {
|
|||
print = printText
|
||||
case "decoder":
|
||||
print = printDecoder
|
||||
case "asm":
|
||||
print = printASM
|
||||
}
|
||||
|
||||
p, err := readCSV(flag.Arg(0))
|
||||
log.Printf("Parsed %d instruction forms.", len(p.Insts))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Printf("Parsed %d instruction forms.", len(p.Insts))
|
||||
print(p)
|
||||
}
|
||||
|
||||
|
@ -79,23 +82,9 @@ func readCSV(file string) (*Prog, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := bufio.NewReader(f)
|
||||
for {
|
||||
c, err := b.ReadByte()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if c == '\n' {
|
||||
continue
|
||||
}
|
||||
if c == '#' {
|
||||
b.ReadBytes('\n')
|
||||
continue
|
||||
}
|
||||
b.UnreadByte()
|
||||
break
|
||||
}
|
||||
table, err := csv.NewReader(b).ReadAll()
|
||||
csvReader := csv.NewReader(f)
|
||||
csvReader.Comment = '#'
|
||||
table, err := csvReader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s: %v", file, err)
|
||||
}
|
||||
|
@ -108,6 +97,10 @@ func readCSV(file string) (*Prog, error) {
|
|||
|
||||
p := &Prog{}
|
||||
for _, row := range table {
|
||||
// TODO: add support for prefixed instructions. Ignore for now.
|
||||
if row[2][0] == ',' {
|
||||
continue
|
||||
}
|
||||
add(p, row[0], row[1], row[2], row[3])
|
||||
}
|
||||
return p, nil
|
||||
|
@ -200,14 +193,25 @@ func (a Arg) isDontCare() bool {
|
|||
return a.Name[0] == '/' && a.Name == strings.Repeat("/", len(a.Name))
|
||||
}
|
||||
|
||||
type instArray []Inst
|
||||
|
||||
func (i instArray) Len() int {
|
||||
return len(i)
|
||||
}
|
||||
|
||||
func (i instArray) Swap(j, k int) {
|
||||
i[j], i[k] = i[k], i[j]
|
||||
}
|
||||
|
||||
// Sort by decreasing number of mask bits to ensure extended mnemonics
|
||||
// are always found first when scanning the table.
|
||||
func (i instArray) Less(j, k int) bool {
|
||||
return bits.OnesCount32(i[j].Mask) > bits.OnesCount32(i[k].Mask)
|
||||
}
|
||||
|
||||
// add adds the entry from the CSV described by text, mnemonics, encoding, and tags
|
||||
// to the program p.
|
||||
func add(p *Prog, text, mnemonics, encoding, tags string) {
|
||||
if strings.HasPrefix(mnemonics, "e_") || strings.HasPrefix(mnemonics, "se_") {
|
||||
// TODO(minux): VLE instructions are ignored.
|
||||
return
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -313,6 +317,7 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
// 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
|
||||
args := args.Clone()
|
||||
|
@ -351,6 +356,7 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
typ := asm.TypeUnknown
|
||||
var shift uint8
|
||||
opr2 := ""
|
||||
opr3 := ""
|
||||
switch opr {
|
||||
case "target_addr":
|
||||
shift = 2
|
||||
|
@ -364,11 +370,17 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
} else {
|
||||
opr = "BD"
|
||||
}
|
||||
case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "UIM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DCMX", "DGM", "RMC", "R", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY":
|
||||
case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "UIM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DGM", "RMC", "R", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY", "SC", "PL", "MP", "N", "IMM", "DRM", "RM":
|
||||
typ = asm.TypeImmUnsigned
|
||||
if i := args.Find(opr); i < 0 {
|
||||
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
|
||||
|
@ -385,6 +397,16 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
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
|
||||
|
@ -406,6 +428,13 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
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":
|
||||
|
@ -428,6 +457,22 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
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
|
||||
|
@ -445,8 +490,16 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
}
|
||||
field.Type = typ
|
||||
field.Shift = shift
|
||||
var f1, f2 asm.BitField
|
||||
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 = uint8(args[b0].Offs), uint8(args[b0].Bits)
|
||||
f2.Offs, f2.Bits = uint8(args[b1].Offs), uint8(args[b1].Bits)
|
||||
f3.Offs, f3.Bits = uint8(args[b2].Offs), uint8(args[b2].Bits)
|
||||
|
||||
case opr2 != "":
|
||||
ext := args.Find(opr)
|
||||
if ext < 0 {
|
||||
|
@ -486,14 +539,22 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
|
|||
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)
|
||||
}
|
||||
|
||||
p.Insts = append(p.Insts, 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...)
|
||||
}
|
||||
|
||||
// condRegexp is a regular expression that matches condition in mnemonics (e.g. "AA=1")
|
||||
|
@ -516,6 +577,18 @@ func printText(p *Prog) {
|
|||
log.Fatal("-fmt=text not implemented")
|
||||
}
|
||||
|
||||
// printASM implements the -fmt=asm mode. This prints out a gnu assembler file
|
||||
// which can be used to used to generate test output to verify the golang
|
||||
// disassembler's gnu output matches gnu binutils. This is used as an input to
|
||||
// ppc64util to generate the decode_generated.txt test case.
|
||||
func printASM(p *Prog) {
|
||||
fmt.Printf("#include \"hack.h\"\n")
|
||||
fmt.Printf(".text\n")
|
||||
for _, inst := range p.Insts {
|
||||
fmt.Printf("\t%s\n", inst.Encoding)
|
||||
}
|
||||
}
|
||||
|
||||
// opName translate an opcode to a valid Go identifier all-cap op name.
|
||||
func opName(op string) string {
|
||||
return strings.ToUpper(strings.Replace(op, ".", "CC", 1))
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// This file requires gcc and binutils with -mcpu=power10 support.
|
||||
// ppc64util runs a series of commands like:
|
||||
// go run map.go -fmt=asm ../pp64.csv > asm.S
|
||||
// powerpc64le-linux-gnu-gcc -c asm.S -mcpu=power10 -mbig
|
||||
// powerpc64le-linux-gnu-objdump -d asm.o
|
||||
// to create the file decode_generated.txt used to verify the disassembler.
|
||||
//
|
||||
// Note, the golang disassembler is not expected to support every extended
|
||||
// mnemonic, but it should support those which frequently show up in object
|
||||
// files compiled by the golang toolchain.
|
||||
|
||||
#define RA 1
|
||||
#define RB 2
|
||||
#define RS 3
|
||||
#define RT 4
|
||||
#define RC 5
|
||||
#define RSp 6
|
||||
#define RTp 8
|
||||
|
||||
#define MB 1
|
||||
#define ME 7
|
||||
#define NB 2
|
||||
#define CY 1
|
||||
|
||||
#define LEV 1
|
||||
|
||||
#define FRBp 2
|
||||
#define FRAp 4
|
||||
#define FRTp 6
|
||||
#define FRSp 8
|
||||
#define FRT 3
|
||||
#define FRA 5
|
||||
#define FRB 7
|
||||
#define FRC 9
|
||||
#define FRS 11
|
||||
#define FLM 8
|
||||
#define U 3
|
||||
#define W 0
|
||||
#define TE 15
|
||||
#define SP 1
|
||||
#define S 1
|
||||
#define DRM 0x7
|
||||
#define RM 0x3
|
||||
|
||||
#define BF 3
|
||||
#define SH 7
|
||||
|
||||
#define XT 33
|
||||
#define XA 35
|
||||
#define XB 37
|
||||
#define XS 39
|
||||
#define XC 41
|
||||
#define XAp 36
|
||||
#define XTp 38
|
||||
#define XSp 40
|
||||
#define DM 1
|
||||
#define SHW 2
|
||||
|
||||
#define VRA 1
|
||||
#define VRB 2
|
||||
#define VRC 3
|
||||
#define VRT 4
|
||||
#define VRS 5
|
||||
#define SHB 3
|
||||
#define SIX 1
|
||||
#define ST 1
|
||||
#define PS 0
|
||||
#define MP 1
|
||||
#define bm 0x45FF
|
||||
#define N 3
|
||||
|
||||
#define AT 7
|
||||
#define AS 6
|
||||
|
||||
#define RMC 3
|
||||
|
||||
#define UIM 1
|
||||
#define DCMX 0x23
|
||||
#define DCM 0x11
|
||||
#define DGM 0x11
|
||||
#define R 1
|
||||
|
||||
#define BA 1
|
||||
#define BB 2
|
||||
#define BT 3
|
||||
#define BO 4
|
||||
#define BI 6
|
||||
#define BH 0
|
||||
#define BFA 7
|
||||
#define FXM 8
|
||||
#define BC 11
|
||||
|
||||
#define L 1
|
||||
#define EH 1
|
||||
|
||||
#define SPR 69
|
||||
#define BHRBE 69
|
||||
#define TO 0x11
|
||||
#define TBR 268
|
||||
#define CT 2
|
||||
#define FC 2
|
||||
#define TH 3
|
||||
#define WC 1
|
||||
#define PL 0
|
||||
#define IH 4
|
||||
#define RIC 1
|
||||
#define PRS 1
|
||||
|
||||
#define SIM 6
|
||||
#define IMM 13
|
||||
#define IMM8 14
|
||||
#define D 0x80
|
||||
#define SC 1
|
||||
|
||||
#define target_addr 0x690
|
||||
|
||||
#define XMSK 0x9
|
||||
#define YMSK 0x3
|
||||
#define PMSK 0x2
|
||||
|
||||
#define IX 1
|
||||
#define IMM32 0x1234567
|
||||
#define Dpfx 0x160032
|
||||
#define RApfx 0x0
|
||||
#define Rpfx 1
|
||||
#define SIpfx 0xFFFFFFFE00010007
|
||||
|
||||
// These decode as m.fpr* or m.vr*. This is a matter of preference. We
|
||||
// don't support these mnemonics, and I don't think they improve reading
|
||||
// disassembled code in most cases. so ignore.
|
||||
//
|
||||
// Likewise, if you add to this list, add tests to decode.txt to ensure we
|
||||
// still test these, while ignoring the extended mnemonics which get
|
||||
// generated.
|
||||
#define mfvsrd xsrsp
|
||||
#define mfvsrwz xsrsp
|
||||
#define mtvsrd xsrsp
|
||||
#define mtvsrwz xsrsp
|
||||
#define mtvsrwa xsrsp
|
||||
|
||||
// isel BC bit is not decoded like other BC fields.
|
||||
// A special test case is added to decode.txt to verify this.
|
||||
// We decode it like other BC fields.
|
||||
#define isel rldicl
|
||||
|
||||
|
||||
// Likewise, these are obscure book ii instructions with extended mnemonics
|
||||
// which are almost guaranteed never to show up in go code
|
||||
#define dcbf add
|
||||
#define sync xsrsp
|
||||
#define wait xsrsp
|
||||
#define rfebb sc
|
||||
|
||||
// sync 1,1 is the stncisync extended mnemonic. Similar to the above, but
|
||||
// the lwsync/hwsync extended mnemonics are tested in decode.txt
|
||||
#define sync xsrsp
|
|
@ -2,7 +2,9 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
// Generate interesting test cases from ppc64 objdump via
|
||||
// go run util.go
|
||||
//
|
||||
|
@ -20,6 +22,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -79,11 +82,13 @@ func emitBranches(out io.Writer) {
|
|||
}
|
||||
}
|
||||
|
||||
// Emit a test file using the generator called name.txt
|
||||
// Emit a test file using the generator called name.txt. This requires
|
||||
// a GCC toolchain which supports -mcpu=power10.
|
||||
func genOutput(name, tcPfx string, generator func(io.Writer)) {
|
||||
// Generate object code from gcc
|
||||
cmd := exec.Command(tcPfx+"gcc", "-c", "-mbig", "-mcpu=power9", "-x", "assembler-with-cpp", "-o", name+".o", "-")
|
||||
cmd := exec.Command(tcPfx+"gcc", "-c", "-mbig", "-mcpu=power10", "-x", "assembler-with-cpp", "-o", name+".o", "-")
|
||||
input, _ := cmd.StdinPipe()
|
||||
cmd.Stderr = os.Stderr
|
||||
go func() {
|
||||
defer input.Close()
|
||||
generator(input.(io.Writer))
|
||||
|
@ -107,20 +112,39 @@ func genOutput(name, tcPfx string, generator func(io.Writer)) {
|
|||
return
|
||||
}
|
||||
|
||||
pfx := ""
|
||||
dec := ""
|
||||
for scanner.Scan() {
|
||||
ln := spacere.Split(scanner.Text(), -1)
|
||||
if len(ln) >= 7 {
|
||||
opc := strings.Join(ln[2:6], "")
|
||||
dec := strings.Join(ln[6:], " ")
|
||||
fmt.Fprintf(outf, "%s|\tgnu\t%s\n", opc, dec)
|
||||
if len(pfx) == 0 {
|
||||
dec = strings.Join(ln[6:], " ")
|
||||
}
|
||||
if v, _ := strconv.ParseInt(ln[2], 16, 16); v&0xFC == 0x04 {
|
||||
pfx = opc
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(outf, "%s%s|\tgnu\t%s\n", pfx, opc, dec)
|
||||
pfx = ""
|
||||
}
|
||||
|
||||
}
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
// Generate representative instructions for all[1] instructions in pp64.csv.
|
||||
//
|
||||
// [1] See hack.h for a few minor, exceptional workarounds.
|
||||
func emitGenerated(out io.Writer) {
|
||||
cmd := exec.Command("go", "run", "../ppc64map/map.go", "-fmt=asm", "../pp64.csv")
|
||||
cmdout, _ := cmd.Output()
|
||||
out.Write(cmdout)
|
||||
}
|
||||
|
||||
// Produce generated test outputs. This should be run every so often with
|
||||
// new versions of objdump to ensure we stay up to date.
|
||||
func main() {
|
||||
genOutput("decode_branch", "powerpc64le-linux-gnu-", emitBranches)
|
||||
genOutput("decode_generated", "powerpc64le-linux-gnu-", emitGenerated)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче