whatcanGOwrong
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
const debugDecode = false
|
||||
|
||||
const prefixOpcode = 1
|
||||
|
||||
// instFormat is a decoding rule for one specific instruction form.
|
||||
// an instruction ins matches the rule if ins&Mask == Value
|
||||
// DontCare bits should be zero, but the machine might not reject
|
||||
// ones in those bits, they are mainly reserved for future expansion
|
||||
// of the instruction set.
|
||||
// The Args are stored in the same order as the instruction manual.
|
||||
//
|
||||
// Prefixed instructions are stored as:
|
||||
//
|
||||
// prefix << 32 | suffix,
|
||||
//
|
||||
// Regular instructions are:
|
||||
//
|
||||
// inst << 32
|
||||
type instFormat struct {
|
||||
Op Op
|
||||
Mask uint64
|
||||
Value uint64
|
||||
DontCare uint64
|
||||
Args [6]*argField
|
||||
}
|
||||
|
||||
// argField indicate how to decode an argument to an instruction.
|
||||
// First parse the value from the BitFields, shift it left by Shift
|
||||
// bits to get the actual numerical value.
|
||||
type argField struct {
|
||||
Type ArgType
|
||||
Shift uint8
|
||||
BitFields
|
||||
}
|
||||
|
||||
// Parse parses the Arg out from the given binary instruction i.
|
||||
func (a argField) Parse(i [2]uint32) Arg {
|
||||
switch a.Type {
|
||||
default:
|
||||
return nil
|
||||
case TypeUnknown:
|
||||
return nil
|
||||
case TypeReg:
|
||||
return R0 + Reg(a.BitFields.Parse(i))
|
||||
case TypeCondRegBit:
|
||||
return Cond0LT + CondReg(a.BitFields.Parse(i))
|
||||
case TypeCondRegField:
|
||||
return CR0 + CondReg(a.BitFields.Parse(i))
|
||||
case TypeFPReg:
|
||||
return F0 + Reg(a.BitFields.Parse(i))
|
||||
case TypeVecReg:
|
||||
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:
|
||||
return Imm(a.BitFields.ParseSigned(i) << a.Shift)
|
||||
case TypeImmUnsigned:
|
||||
return Imm(a.BitFields.Parse(i) << a.Shift)
|
||||
case TypePCRel:
|
||||
return PCRel(a.BitFields.ParseSigned(i) << a.Shift)
|
||||
case TypeLabel:
|
||||
return Label(a.BitFields.ParseSigned(i) << a.Shift)
|
||||
case TypeOffset:
|
||||
return Offset(a.BitFields.ParseSigned(i) << a.Shift)
|
||||
case TypeNegOffset:
|
||||
// An oddball encoding of offset for hashchk and similar.
|
||||
// e.g hashchk offset is 0b1111111000000000 | DX << 8 | D << 3
|
||||
off := a.BitFields.ParseSigned(i) << a.Shift
|
||||
neg := int64(-1) << (int(a.Shift) + a.BitFields.NumBits())
|
||||
return Offset(neg | off)
|
||||
}
|
||||
}
|
||||
|
||||
type ArgType int8
|
||||
|
||||
const (
|
||||
TypeUnknown ArgType = iota
|
||||
TypePCRel // PC-relative address
|
||||
TypeLabel // absolute address
|
||||
TypeReg // integer register
|
||||
TypeCondRegBit // conditional register bit (0-31)
|
||||
TypeCondRegField // conditional register field (0-7)
|
||||
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
|
||||
TypeOffset // signed offset in load/store
|
||||
TypeNegOffset // A negative 16 bit value 0b1111111xxxxx000 encoded as 0bxxxxx (e.g in the hashchk instruction)
|
||||
TypeLast // must be the last one
|
||||
)
|
||||
|
||||
func (t ArgType) String() string {
|
||||
switch t {
|
||||
default:
|
||||
return fmt.Sprintf("ArgType(%d)", int(t))
|
||||
case TypeUnknown:
|
||||
return "Unknown"
|
||||
case TypeReg:
|
||||
return "Reg"
|
||||
case TypeCondRegBit:
|
||||
return "CondRegBit"
|
||||
case TypeCondRegField:
|
||||
return "CondRegField"
|
||||
case TypeFPReg:
|
||||
return "FPReg"
|
||||
case TypeVecReg:
|
||||
return "VecReg"
|
||||
case TypeVecSReg:
|
||||
return "VecSReg"
|
||||
case TypeVecSpReg:
|
||||
return "VecSpReg"
|
||||
case TypeMMAReg:
|
||||
return "MMAReg"
|
||||
case TypeSpReg:
|
||||
return "SpReg"
|
||||
case TypeImmSigned:
|
||||
return "ImmSigned"
|
||||
case TypeImmUnsigned:
|
||||
return "ImmUnsigned"
|
||||
case TypePCRel:
|
||||
return "PCRel"
|
||||
case TypeLabel:
|
||||
return "Label"
|
||||
case TypeOffset:
|
||||
return "Offset"
|
||||
case TypeNegOffset:
|
||||
return "NegOffset"
|
||||
}
|
||||
}
|
||||
|
||||
func (t ArgType) GoString() string {
|
||||
s := t.String()
|
||||
if t > 0 && t < TypeLast {
|
||||
return "Type" + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var (
|
||||
// Errors
|
||||
errShort = fmt.Errorf("truncated instruction")
|
||||
errUnknown = fmt.Errorf("unknown instruction")
|
||||
)
|
||||
|
||||
var decoderCover []bool
|
||||
|
||||
// Decode decodes the leading bytes in src as a single instruction using
|
||||
// byte order ord.
|
||||
func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) {
|
||||
if len(src) < 4 {
|
||||
return inst, errShort
|
||||
}
|
||||
if decoderCover == nil {
|
||||
decoderCover = make([]bool, len(instFormats))
|
||||
}
|
||||
inst.Len = 4
|
||||
ui_extn := [2]uint32{ord.Uint32(src[:inst.Len]), 0}
|
||||
ui := uint64(ui_extn[0]) << 32
|
||||
inst.Enc = ui_extn[0]
|
||||
opcode := inst.Enc >> 26
|
||||
if opcode == prefixOpcode {
|
||||
// This is a prefixed instruction
|
||||
inst.Len = 8
|
||||
if len(src) < 8 {
|
||||
return inst, errShort
|
||||
}
|
||||
// Merge the suffixed word.
|
||||
ui_extn[1] = ord.Uint32(src[4:inst.Len])
|
||||
ui |= uint64(ui_extn[1])
|
||||
inst.SuffixEnc = ui_extn[1]
|
||||
}
|
||||
for i, iform := range instFormats {
|
||||
if ui&iform.Mask != iform.Value {
|
||||
continue
|
||||
}
|
||||
if ui&iform.DontCare != 0 {
|
||||
if debugDecode {
|
||||
log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op)
|
||||
}
|
||||
// to match GNU objdump (libopcodes), we ignore don't care bits
|
||||
}
|
||||
for i, argfield := range iform.Args {
|
||||
if argfield == nil {
|
||||
break
|
||||
}
|
||||
inst.Args[i] = argfield.Parse(ui_extn)
|
||||
}
|
||||
inst.Op = iform.Op
|
||||
if debugDecode {
|
||||
log.Printf("%#x: search entry %d", ui, i)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if inst.Op == 0 && inst.Enc != 0 {
|
||||
return inst, errUnknown
|
||||
}
|
||||
return inst, nil
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
files, err := ioutil.ReadDir("testdata")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if !strings.HasPrefix(f.Name(), "decode") {
|
||||
continue
|
||||
}
|
||||
filename := path.Join("testdata", f.Name())
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decode(data, t, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a fake symbol to verify PCrel argument decoding.
|
||||
func symlookup(pc uint64) (string, uint64) {
|
||||
foopc := uint64(0x100000)
|
||||
if pc >= foopc && pc < foopc+0x10 {
|
||||
return "foo", foopc
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
|
||||
func decode(data []byte, t *testing.T, filename string) {
|
||||
all := string(data)
|
||||
// Simulate PC based on number of instructions found in the test file.
|
||||
pc := uint64(0)
|
||||
for strings.Contains(all, "\t\t") {
|
||||
all = strings.Replace(all, "\t\t", "\t", -1)
|
||||
}
|
||||
for _, line := range strings.Split(all, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
f := strings.SplitN(line, "\t", 3)
|
||||
i := strings.Index(f[0], "|")
|
||||
if i < 0 {
|
||||
t.Errorf("%s: parsing %q: missing | separator", filename, f[0])
|
||||
continue
|
||||
}
|
||||
if i%2 != 0 {
|
||||
t.Errorf("%s: parsing %q: misaligned | separator", filename, f[0])
|
||||
}
|
||||
size := i / 2
|
||||
code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
|
||||
if err != nil {
|
||||
t.Errorf("%s: parsing %q: %v", filename, f[0], err)
|
||||
continue
|
||||
}
|
||||
syntax, asm := f[1], f[2]
|
||||
inst, err := Decode(code, binary.BigEndian)
|
||||
var out string
|
||||
if err != nil {
|
||||
out = "error: " + err.Error()
|
||||
} else {
|
||||
switch syntax {
|
||||
case "gnu":
|
||||
out = GNUSyntax(inst, pc)
|
||||
case "plan9":
|
||||
pc := pc
|
||||
// Hack: Setting PC to 0 effectively transforms the PC relative address
|
||||
// of CALL (bl) into an absolute address when decoding in GoSyntax. This
|
||||
// simplifies the testing of symbol lookups via symlookup above.
|
||||
if inst.Op == BL {
|
||||
pc = 0
|
||||
}
|
||||
out = GoSyntax(inst, pc, symlookup)
|
||||
default:
|
||||
t.Errorf("unknown syntax %q", syntax)
|
||||
continue
|
||||
}
|
||||
}
|
||||
pc += uint64(size)
|
||||
if out != asm || inst.Len != size {
|
||||
t.Errorf("%s: Decode(%s) [%s] = %s want %s", filename, f[0], syntax, out, asm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// Package ppc64asm implements decoding of 64-bit PowerPC machine code.
|
||||
package ppc64asm
|
||||
@@ -0,0 +1,541 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// Support for testing against external disassembler program.
|
||||
// Copied and simplified from rsc.io/arm/armasm/ext_test.go.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths")
|
||||
dumpTest = flag.Bool("dump", false, "dump all encodings")
|
||||
mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
|
||||
longTest = flag.Bool("long", false, "long test")
|
||||
keep = flag.Bool("keep", false, "keep object files around")
|
||||
debug = false
|
||||
)
|
||||
|
||||
// An ExtInst represents a single decoded instruction parsed
|
||||
// from an external disassembler's output.
|
||||
type ExtInst struct {
|
||||
addr uint32
|
||||
enc [8]byte
|
||||
nenc int
|
||||
text string
|
||||
}
|
||||
|
||||
func (r ExtInst) String() string {
|
||||
return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
|
||||
}
|
||||
|
||||
// An ExtDis is a connection between an external disassembler and a test.
|
||||
type ExtDis struct {
|
||||
Dec chan ExtInst
|
||||
File *os.File
|
||||
Size int
|
||||
KeepFile bool
|
||||
Cmd *exec.Cmd
|
||||
}
|
||||
|
||||
// Run runs the given command - the external disassembler - and returns
|
||||
// a buffered reader of its standard output.
|
||||
func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
|
||||
if *keep {
|
||||
log.Printf("%s\n", strings.Join(cmd, " "))
|
||||
}
|
||||
ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
|
||||
out, err := ext.Cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stdoutpipe: %v", err)
|
||||
}
|
||||
if err := ext.Cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("exec: %v", err)
|
||||
}
|
||||
|
||||
b := bufio.NewReaderSize(out, 1<<20)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Wait waits for the command started with Run to exit.
|
||||
func (ext *ExtDis) Wait() error {
|
||||
return ext.Cmd.Wait()
|
||||
}
|
||||
|
||||
// testExtDis tests a set of byte sequences against an external disassembler.
|
||||
// The disassembler is expected to produce the given syntax and be run
|
||||
// in the given architecture mode (16, 32, or 64-bit).
|
||||
// The extdis function must start the external disassembler
|
||||
// and then parse its output, sending the parsed instructions on ext.Dec.
|
||||
// The generate function calls its argument f once for each byte sequence
|
||||
// to be tested. The generate function itself will be called twice, and it must
|
||||
// make the same sequence of calls to f each time.
|
||||
// When a disassembly does not match the internal decoding,
|
||||
// allowedMismatch determines whether this mismatch should be
|
||||
// allowed, or else considered an error.
|
||||
func testExtDis(
|
||||
t *testing.T,
|
||||
syntax string,
|
||||
extdis func(ext *ExtDis) error,
|
||||
generate func(f func([]byte)),
|
||||
allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool,
|
||||
) {
|
||||
start := time.Now()
|
||||
ext := &ExtDis{
|
||||
Dec: make(chan ExtInst),
|
||||
}
|
||||
errc := make(chan error)
|
||||
|
||||
// First pass: write instructions to input file for external disassembler.
|
||||
file, f, size, err := writeInst(generate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ext.Size = size
|
||||
ext.File = f
|
||||
defer func() {
|
||||
f.Close()
|
||||
if !*keep {
|
||||
os.Remove(file)
|
||||
}
|
||||
}()
|
||||
|
||||
// Second pass: compare disassembly against our decodings.
|
||||
var (
|
||||
totalTests = 0
|
||||
totalSkips = 0
|
||||
totalErrors = 0
|
||||
|
||||
errors = make([]string, 0, 100) // sampled errors, at most cap
|
||||
)
|
||||
go func() {
|
||||
errc <- extdis(ext)
|
||||
}()
|
||||
generate(func(enc []byte) {
|
||||
dec, ok := <-ext.Dec
|
||||
if !ok {
|
||||
t.Errorf("decoding stream ended early")
|
||||
return
|
||||
}
|
||||
inst, text := disasm(syntax, pad(enc))
|
||||
totalTests++
|
||||
if *dumpTest {
|
||||
fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
|
||||
}
|
||||
if text != dec.text || inst.Len != dec.nenc {
|
||||
suffix := ""
|
||||
if allowedMismatch(text, size, &inst, dec) {
|
||||
totalSkips++
|
||||
if !*mismatch {
|
||||
return
|
||||
}
|
||||
suffix += " (allowed mismatch)"
|
||||
}
|
||||
totalErrors++
|
||||
if len(errors) >= cap(errors) {
|
||||
j := rand.Intn(totalErrors)
|
||||
if j >= cap(errors) {
|
||||
return
|
||||
}
|
||||
errors = append(errors[:j], errors[j+1:]...)
|
||||
}
|
||||
errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix))
|
||||
}
|
||||
})
|
||||
|
||||
if *mismatch {
|
||||
totalErrors -= totalSkips
|
||||
}
|
||||
|
||||
for _, b := range errors {
|
||||
t.Log(b)
|
||||
}
|
||||
|
||||
if totalErrors > 0 {
|
||||
t.Fail()
|
||||
}
|
||||
t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
|
||||
|
||||
if err := <-errc; err != nil {
|
||||
t.Fatalf("external disassembler: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const start = 0x8000 // start address of text
|
||||
|
||||
// writeInst writes the generated byte sequences to a new file
|
||||
// starting at offset start. That file is intended to be the input to
|
||||
// the external disassembler.
|
||||
func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
|
||||
f, err = ioutil.TempFile("", "ppc64asm")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
file = f.Name()
|
||||
|
||||
f.Seek(start, io.SeekStart)
|
||||
w := bufio.NewWriter(f)
|
||||
defer w.Flush()
|
||||
size = 0
|
||||
generate(func(x []byte) {
|
||||
if len(x) != 4 && len(x) != 8 {
|
||||
panic(fmt.Sprintf("Unexpected instruction %v\n", x))
|
||||
}
|
||||
izeros := zeros
|
||||
if len(x) == 4 {
|
||||
// Only pad to 4 bytes for a 4 byte instruction word.
|
||||
izeros = izeros[4:]
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("%#x: %x%x\n", start+size, x, izeros[len(x):])
|
||||
}
|
||||
w.Write(x)
|
||||
w.Write(izeros[len(x):])
|
||||
size += len(izeros)
|
||||
})
|
||||
return file, f, size, nil
|
||||
}
|
||||
|
||||
var zeros = []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
// pad pads the code sequence with pops.
|
||||
func pad(enc []byte) []byte {
|
||||
if len(enc) < 4 {
|
||||
enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
||||
// disasm returns the decoded instruction and text
|
||||
// for the given source bytes, using the given syntax and mode.
|
||||
func disasm(syntax string, src []byte) (inst Inst, text string) {
|
||||
// If printTests is set, we record the coverage value
|
||||
// before and after, and we write out the inputs for which
|
||||
// coverage went up, in the format expected in testdata/decode.text.
|
||||
// This produces a fairly small set of test cases that exercise nearly
|
||||
// all the code.
|
||||
var cover float64
|
||||
if *printTests {
|
||||
cover -= coverage()
|
||||
}
|
||||
|
||||
inst, err := Decode(src, binary.BigEndian)
|
||||
if err != nil {
|
||||
text = "error: " + err.Error()
|
||||
} else {
|
||||
text = inst.String()
|
||||
switch syntax {
|
||||
//case "arm":
|
||||
// text = ARMSyntax(inst)
|
||||
case "gnu":
|
||||
text = GNUSyntax(inst, 0)
|
||||
//case "plan9":
|
||||
// text = GoSyntax(inst, 0, nil)
|
||||
default:
|
||||
text = "error: unknown syntax " + syntax
|
||||
}
|
||||
}
|
||||
|
||||
if *printTests {
|
||||
cover += coverage()
|
||||
if cover > 0 {
|
||||
max := len(src)
|
||||
if max > 4 && inst.Len <= 4 {
|
||||
max = 4
|
||||
}
|
||||
fmt.Printf("%x|%x\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], syntax, text)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// coverage returns a floating point number denoting the
|
||||
// test coverage until now. The number increases when new code paths are exercised,
|
||||
// both in the Go program and in the decoder byte code.
|
||||
func coverage() float64 {
|
||||
var f float64
|
||||
f += testing.Coverage()
|
||||
f += decodeCoverage()
|
||||
return f
|
||||
}
|
||||
|
||||
func decodeCoverage() float64 {
|
||||
n := 0
|
||||
for _, t := range decoderCover {
|
||||
if t {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return float64(1+n) / float64(1+len(decoderCover))
|
||||
}
|
||||
|
||||
// Helpers for writing disassembler output parsers.
|
||||
|
||||
// hasPrefix reports whether any of the space-separated words in the text s
|
||||
// begins with any of the given prefixes.
|
||||
func hasPrefix(s string, prefixes ...string) bool {
|
||||
for _, prefix := range prefixes {
|
||||
for s := s; s != ""; {
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
return true
|
||||
}
|
||||
i := strings.Index(s, " ")
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
s = s[i+1:]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// contains reports whether the text s contains any of the given substrings.
|
||||
func contains(s string, substrings ...string) bool {
|
||||
for _, sub := range substrings {
|
||||
if strings.Contains(s, sub) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isHex reports whether b is a hexadecimal character (0-9A-Fa-f).
|
||||
func isHex(b byte) bool { return b == '0' || unhex[b] > 0 }
|
||||
|
||||
// parseHex parses the hexadecimal byte dump in hex,
|
||||
// appending the parsed bytes to raw and returning the updated slice.
|
||||
// The returned bool signals whether any invalid hex was found.
|
||||
// Spaces and tabs between bytes are okay but any other non-hex is not.
|
||||
func parseHex(hex []byte, raw []byte) ([]byte, bool) {
|
||||
hex = trimSpace(hex)
|
||||
for j := 0; j < len(hex); {
|
||||
for hex[j] == ' ' || hex[j] == '\t' {
|
||||
j++
|
||||
}
|
||||
if j >= len(hex) {
|
||||
break
|
||||
}
|
||||
if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
|
||||
return nil, false
|
||||
}
|
||||
raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]])
|
||||
j += 2
|
||||
}
|
||||
return raw, true
|
||||
}
|
||||
|
||||
var unhex = [256]byte{
|
||||
'0': 0,
|
||||
'1': 1,
|
||||
'2': 2,
|
||||
'3': 3,
|
||||
'4': 4,
|
||||
'5': 5,
|
||||
'6': 6,
|
||||
'7': 7,
|
||||
'8': 8,
|
||||
'9': 9,
|
||||
'A': 10,
|
||||
'B': 11,
|
||||
'C': 12,
|
||||
'D': 13,
|
||||
'E': 14,
|
||||
'F': 15,
|
||||
'a': 10,
|
||||
'b': 11,
|
||||
'c': 12,
|
||||
'd': 13,
|
||||
'e': 14,
|
||||
'f': 15,
|
||||
}
|
||||
|
||||
// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
|
||||
func index(s []byte, t string) int {
|
||||
i := 0
|
||||
for {
|
||||
j := bytes.IndexByte(s[i:], t[0])
|
||||
if j < 0 {
|
||||
return -1
|
||||
}
|
||||
i = i + j
|
||||
if i+len(t) > len(s) {
|
||||
return -1
|
||||
}
|
||||
for k := 1; k < len(t); k++ {
|
||||
if s[i+k] != t[k] {
|
||||
goto nomatch
|
||||
}
|
||||
}
|
||||
return i
|
||||
nomatch:
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
|
||||
// If s must be rewritten, it is rewritten in place.
|
||||
func fixSpace(s []byte) []byte {
|
||||
s = trimSpace(s)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
|
||||
goto Fix
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
||||
Fix:
|
||||
b := s
|
||||
w := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '\t' || c == '\n' {
|
||||
c = ' '
|
||||
}
|
||||
if c == ' ' && w > 0 && b[w-1] == ' ' {
|
||||
continue
|
||||
}
|
||||
b[w] = c
|
||||
w++
|
||||
}
|
||||
if w > 0 && b[w-1] == ' ' {
|
||||
w--
|
||||
}
|
||||
return b[:w]
|
||||
}
|
||||
|
||||
// trimSpace trims leading and trailing space from s, returning a subslice of s.
|
||||
func trimSpace(s []byte) []byte {
|
||||
j := len(s)
|
||||
for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') {
|
||||
j--
|
||||
}
|
||||
i := 0
|
||||
for i < j && (s[i] == ' ' || s[i] == '\t') {
|
||||
i++
|
||||
}
|
||||
return s[i:j]
|
||||
}
|
||||
|
||||
// pcrel matches instructions using relative addressing mode.
|
||||
var (
|
||||
pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bc)[^ac ]* (?:(?:[0-9]{1,2},)|(?:[0-7]\*)|\+|lt|gt|eq|so|cr[0-7]|,)*)0x([0-9a-f]+)$`)
|
||||
)
|
||||
|
||||
// Generators.
|
||||
//
|
||||
// The test cases are described as functions that invoke a callback repeatedly,
|
||||
// with a new input sequence each time. These helpers make writing those
|
||||
// a little easier.
|
||||
|
||||
// randomCases generates random instructions.
|
||||
func randomCases(t *testing.T) func(func([]byte)) {
|
||||
return func(try func([]byte)) {
|
||||
// All the strides are relatively prime to 2 and therefore to 2²⁸,
|
||||
// so we will not repeat any instructions until we have tried all 2²⁸.
|
||||
// Using a stride other than 1 is meant to visit the instructions in a
|
||||
// pseudorandom order, which gives better variety in the set of
|
||||
// test cases chosen by -printtests.
|
||||
stride := uint32(10007)
|
||||
n := 1 << 28 / 7
|
||||
if testing.Short() {
|
||||
stride = 100003
|
||||
n = 1 << 28 / 1001
|
||||
} else if *longTest {
|
||||
stride = 2000033
|
||||
n = 1 << 29
|
||||
}
|
||||
x := uint32(0)
|
||||
for i := 0; i < n; i++ {
|
||||
enc := (x%15)<<28 | x&(1<<28-1)
|
||||
try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)})
|
||||
x += stride
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hexCases generates the cases written in hexadecimal in the encoded string.
|
||||
// Spaces in 'encoded' separate entire test cases, not individual bytes.
|
||||
func hexCases(t *testing.T, encoded string) func(func([]byte)) {
|
||||
return func(try func([]byte)) {
|
||||
for _, x := range strings.Fields(encoded) {
|
||||
src, err := hex.DecodeString(x)
|
||||
if err != nil {
|
||||
t.Errorf("parsing %q: %v", x, err)
|
||||
}
|
||||
try(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testdataCases generates the test cases recorded in testdata/decode.txt.
|
||||
// It only uses the inputs; it ignores the answers recorded in that file.
|
||||
func testdataCases(t *testing.T) func(func([]byte)) {
|
||||
var codes [][]byte
|
||||
data, err := ioutil.ReadFile("testdata/decode.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
f := strings.Fields(line)[0]
|
||||
i := strings.Index(f, "|")
|
||||
if i < 0 {
|
||||
t.Errorf("parsing %q: missing | separator", f)
|
||||
continue
|
||||
}
|
||||
if i%2 != 0 {
|
||||
t.Errorf("parsing %q: misaligned | separator", f)
|
||||
}
|
||||
code, err := hex.DecodeString(f[:i] + f[i+1:])
|
||||
if err != nil {
|
||||
t.Errorf("parsing %q: %v", f, err)
|
||||
continue
|
||||
}
|
||||
codes = append(codes, code)
|
||||
}
|
||||
|
||||
return func(try func([]byte)) {
|
||||
for _, code := range codes {
|
||||
try(code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func caller(skip int) string {
|
||||
pc, _, _, _ := runtime.Caller(skip)
|
||||
f := runtime.FuncForPC(pc)
|
||||
name := "?"
|
||||
if f != nil {
|
||||
name = f.Name()
|
||||
if i := strings.LastIndex(name, "."); i >= 0 {
|
||||
name = name[i+1:]
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A BitField is a bit-field in a 32-bit word.
|
||||
// Bits are counted from 0 from the MSB to 31 as the LSB.
|
||||
type BitField struct {
|
||||
Offs uint8 // the offset of the left-most bit.
|
||||
Bits uint8 // length in bits.
|
||||
// This instruction word holding this field.
|
||||
// It is always 0 for ISA < 3.1 instructions. It is
|
||||
// in decoding order. (0 == prefix, 1 == suffix on ISA 3.1)
|
||||
Word uint8
|
||||
}
|
||||
|
||||
func (b BitField) String() string {
|
||||
if b.Bits > 1 {
|
||||
return fmt.Sprintf("[%d:%d]", b.Offs, int(b.Offs+b.Bits)-1)
|
||||
} else if b.Bits == 1 {
|
||||
return fmt.Sprintf("[%d]", b.Offs)
|
||||
} else {
|
||||
return fmt.Sprintf("[%d, len=0]", b.Offs)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse extracts the bitfield b from i, and return it as an unsigned integer.
|
||||
// Parse will panic if b is invalid.
|
||||
func (b BitField) Parse(i [2]uint32) uint32 {
|
||||
if b.Bits > 32 || b.Bits == 0 || b.Offs > 31 || b.Offs+b.Bits > 32 {
|
||||
panic(fmt.Sprintf("invalid bitfiled %v", b))
|
||||
}
|
||||
return (i[b.Word] >> (32 - b.Offs - b.Bits)) & ((1 << b.Bits) - 1)
|
||||
}
|
||||
|
||||
// ParseSigned extracts the bitfield b from i, and return it as a signed integer.
|
||||
// ParseSigned will panic if b is invalid.
|
||||
func (b BitField) ParseSigned(i [2]uint32) int32 {
|
||||
u := int32(b.Parse(i))
|
||||
return u << (32 - b.Bits) >> (32 - b.Bits)
|
||||
}
|
||||
|
||||
// BitFields is a series of BitFields representing a single number.
|
||||
type BitFields []BitField
|
||||
|
||||
func (bs BitFields) String() string {
|
||||
ss := make([]string, len(bs))
|
||||
for i, bf := range bs {
|
||||
ss[i] = bf.String()
|
||||
}
|
||||
return fmt.Sprintf("<%s>", strings.Join(ss, "|"))
|
||||
}
|
||||
|
||||
func (bs *BitFields) Append(b BitField) {
|
||||
*bs = append(*bs, b)
|
||||
}
|
||||
|
||||
// parse extracts the bitfields from i, concatenate them and return the result
|
||||
// as an unsigned integer and the total length of all the bitfields.
|
||||
// parse will panic if any bitfield in b is invalid, but it doesn't check if
|
||||
// the sequence of bitfields is reasonable.
|
||||
func (bs BitFields) parse(i [2]uint32) (u uint64, Bits uint8) {
|
||||
for _, b := range bs {
|
||||
u = (u << b.Bits) | uint64(b.Parse(i))
|
||||
Bits += b.Bits
|
||||
}
|
||||
return u, Bits
|
||||
}
|
||||
|
||||
// Parse extracts the bitfields from i, concatenate them and return the result
|
||||
// as an unsigned integer. Parse will panic if any bitfield in b is invalid.
|
||||
func (bs BitFields) Parse(i [2]uint32) uint64 {
|
||||
u, _ := bs.parse(i)
|
||||
return u
|
||||
}
|
||||
|
||||
// ParseSigned extracts the bitfields from i, concatenate them and return the result
|
||||
// as a signed integer. Parse will panic if any bitfield in b is invalid.
|
||||
func (bs BitFields) ParseSigned(i [2]uint32) int64 {
|
||||
u, l := bs.parse(i)
|
||||
return int64(u) << (64 - l) >> (64 - l)
|
||||
}
|
||||
|
||||
// Count the number of bits in the aggregate BitFields
|
||||
func (bs BitFields) NumBits() int {
|
||||
num := 0
|
||||
for _, b := range bs {
|
||||
num += int(b.Bits)
|
||||
}
|
||||
return num
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func panicOrNot(f func()) (panicked bool) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
panicked = true
|
||||
}
|
||||
}()
|
||||
f()
|
||||
return false
|
||||
}
|
||||
|
||||
func TestBitField(t *testing.T) {
|
||||
var tests = []struct {
|
||||
b BitField
|
||||
i uint32 // input
|
||||
u uint32 // unsigned output
|
||||
s int32 // signed output
|
||||
fail bool // if the check should panic
|
||||
}{
|
||||
{BitField{0, 0, 0}, 0, 0, 0, true},
|
||||
{BitField{31, 2, 0}, 0, 0, 0, true},
|
||||
{BitField{31, 1, 0}, 1, 1, -1, false},
|
||||
{BitField{29, 2, 0}, 0 << 1, 0, 0, false},
|
||||
{BitField{29, 2, 0}, 1 << 1, 1, 1, false},
|
||||
{BitField{29, 2, 0}, 2 << 1, 2, -2, false},
|
||||
{BitField{29, 2, 0}, 3 << 1, 3, -1, false},
|
||||
{BitField{0, 32, 0}, 1<<32 - 1, 1<<32 - 1, -1, false},
|
||||
{BitField{16, 3, 0}, 1 << 15, 4, -4, false},
|
||||
}
|
||||
for i, tst := range tests {
|
||||
var (
|
||||
ou uint32
|
||||
os int32
|
||||
)
|
||||
failed := panicOrNot(func() {
|
||||
ou = tst.b.Parse([2]uint32{tst.i})
|
||||
os = tst.b.ParseSigned([2]uint32{tst.i})
|
||||
})
|
||||
if failed != tst.fail {
|
||||
t.Errorf("case %d: %v: fail test failed, got %v, expected %v", i, tst.b, failed, tst.fail)
|
||||
continue
|
||||
}
|
||||
if ou != tst.u {
|
||||
t.Errorf("case %d: %v.Parse(%d) returned %d, expected %d", i, tst.b, tst.i, ou, tst.u)
|
||||
continue
|
||||
}
|
||||
if os != tst.s {
|
||||
t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitFields(t *testing.T) {
|
||||
var tests = []struct {
|
||||
b BitFields
|
||||
i [2]uint32 // input
|
||||
u uint64 // unsigned output
|
||||
s int64 // signed output
|
||||
nb int // Total number of bits in BitField
|
||||
fail bool // if the check should panic
|
||||
}{
|
||||
{BitFields{{0, 0, 1}}, [2]uint32{0, 0}, 0, 0, 0, true},
|
||||
{BitFields{{31, 2, 1}}, [2]uint32{0, 0}, 0, 0, 2, true},
|
||||
{BitFields{{31, 1, 1}}, [2]uint32{0, 1}, 1, -1, 1, false},
|
||||
{BitFields{{29, 2, 1}}, [2]uint32{0, 0 << 1}, 0, 0, 2, false},
|
||||
{BitFields{{29, 2, 1}}, [2]uint32{0, 1 << 1}, 1, 1, 2, false},
|
||||
{BitFields{{29, 2, 1}}, [2]uint32{0, 2 << 1}, 2, -2, 2, false},
|
||||
{BitFields{{29, 2, 1}}, [2]uint32{0, 3 << 1}, 3, -1, 2, false},
|
||||
{BitFields{{0, 32, 1}}, [2]uint32{0, 1<<32 - 1}, 1<<32 - 1, -1, 32, false},
|
||||
{BitFields{{16, 3, 1}}, [2]uint32{0, 1 << 15}, 4, -4, 3, false},
|
||||
{BitFields{{16, 16, 0}, {16, 16, 1}}, [2]uint32{0x8016, 0x32}, 0x80160032, -0x7FE9FFCE, 32, false},
|
||||
{BitFields{{14, 18, 0}, {16, 16, 1}}, [2]uint32{0x38016, 0x32}, 0x380160032, -0x07FE9FFCE, 34, false},
|
||||
}
|
||||
for i, tst := range tests {
|
||||
var (
|
||||
ou uint64
|
||||
os int64
|
||||
onb int
|
||||
)
|
||||
failed := panicOrNot(func() {
|
||||
onb = tst.b.NumBits()
|
||||
ou = tst.b.Parse(tst.i)
|
||||
os = tst.b.ParseSigned(tst.i)
|
||||
})
|
||||
if failed != tst.fail {
|
||||
t.Errorf("case %d: %v: fail test failed, got %v, expected %v", i, tst.b, failed, tst.fail)
|
||||
continue
|
||||
}
|
||||
if ou != tst.u {
|
||||
t.Errorf("case %d: %v.Parse(%d) returned %d, expected %d", i, tst.b, tst.i, ou, tst.u)
|
||||
continue
|
||||
}
|
||||
if os != tst.s {
|
||||
t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
|
||||
}
|
||||
if onb != tst.nb {
|
||||
t.Errorf("case %d: %v.NumBits() returned %d, expected %d", i, tst.b, onb, tst.nb)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// bit 3 of index is a negated check.
|
||||
condBit = [8]string{
|
||||
"lt", "gt", "eq", "so",
|
||||
"ge", "le", "ne", "ns"}
|
||||
)
|
||||
|
||||
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
|
||||
// This form typically matches the syntax defined in the Power ISA Reference Manual.
|
||||
func GNUSyntax(inst Inst, pc uint64) string {
|
||||
var buf bytes.Buffer
|
||||
// When there are all 0s, identify them as the disassembler
|
||||
// in binutils would.
|
||||
if inst.Enc == 0 {
|
||||
return ".long 0x0"
|
||||
} else if inst.Op == 0 {
|
||||
return "error: unknown instruction"
|
||||
}
|
||||
|
||||
PC := pc
|
||||
// Special handling for some ops
|
||||
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:]
|
||||
bo := int(inst.Args[0].(Imm))
|
||||
bi := inst.Args[1].(CondReg)
|
||||
atsfx := [4]string{"", "?", "-", "+"}
|
||||
decsfx := [2]string{"dnz", "dz"}
|
||||
|
||||
//BO field is... complicated (z == ignored bit, at == prediction hint)
|
||||
//Paraphrased from ISA 3.1 Book I Section 2.4:
|
||||
//
|
||||
//0000z -> decrement ctr, b if ctr != 0 and CRbi == 0
|
||||
//0001z -> decrement ctr, b if ctr == 0 and CRbi == 0
|
||||
//001at -> b if CRbi == 0
|
||||
//0100z -> decrement ctr, b if ctr != 0 and CRbi == 1
|
||||
//0101z -> decrement ctr, b if ctr == 0 and CRbi == 1
|
||||
//011at -> b if CRbi == 1
|
||||
//1a00t -> decrement ctr, b if ctr != 0
|
||||
//1a01t -> decrement ctr, b if ctr == 0
|
||||
//1z1zz -> b always
|
||||
|
||||
// Decoding (in this order) we get
|
||||
// BO & 0b00100 == 0b00000 -> dz if BO[1], else dnz (not simplified for bcctrl forms)
|
||||
// BO & 0b10000 == 0b10000 -> (bc and bca forms not simplified), at = B[4]B[0] if B[2] != 0, done
|
||||
// BO & 0b10000 == 0b00000 -> t if BO[3], else f
|
||||
// BO & 0b10100 == 0b00100 -> at = B[0:1]
|
||||
|
||||
// BI fields rename as follows:
|
||||
// less than : lt BI%4==0 && test == t
|
||||
// less than or equal : le BI%4==1 && test == f
|
||||
// equal : eq BI%4==2 && test == t
|
||||
// greater than or equal: ge BI%4==0 && test == f
|
||||
// greater than : gt BI%4==1 && test == t
|
||||
// not less than : nl BI%4==0 && test == f
|
||||
// not equal : ne BI%4==2 && test == f
|
||||
// not greater than : ng BI%4==1 && test == f
|
||||
// summary overflow : so BI%4==3 && test == t
|
||||
// not summary overflow : ns BI%4==3 && test == f
|
||||
// unordered : un BI%4==3 && test == t
|
||||
// not unordered : nu BI%4==3 && test == f
|
||||
//
|
||||
// Note, there are only 8 possible tests, but quite a few more
|
||||
// ways to name fields. For simplicity, we choose those in condBit.
|
||||
|
||||
at := 0 // 0 == no hint, 1 == reserved, 2 == not likely, 3 == likely
|
||||
form := 1 // 1 == n/a, 0 == cr bit not set, 4 == cr bit set
|
||||
cr := (bi - Cond0LT) / 4
|
||||
bh := -1 // Only for lr/tar/ctr variants.
|
||||
switch opName {
|
||||
case "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
|
||||
bh = int(inst.Args[2].(Imm))
|
||||
}
|
||||
|
||||
if bo&0x14 == 0x14 {
|
||||
if bo == 0x14 && bi == Cond0LT { // preferred form of unconditional branch
|
||||
// Likewise, avoid printing fake b/ba/bl/bla
|
||||
if opName != "bc" && opName != "bca" && opName != "bcl" && opName != "bcla" {
|
||||
startArg = 2
|
||||
}
|
||||
}
|
||||
} else if bo&0x04 == 0 { // ctr is decremented
|
||||
if opName != "bcctr" && opName != "bcctrl" {
|
||||
startArg = 1
|
||||
tf := ""
|
||||
if bo&0x10 == 0x00 {
|
||||
tf = "f"
|
||||
if bo&0x08 == 0x08 {
|
||||
tf = "t"
|
||||
}
|
||||
}
|
||||
sfx = decsfx[(bo>>1)&1] + tf + sfx
|
||||
}
|
||||
if bo&0x10 == 0x10 {
|
||||
if opName != "bcctr" && opName != "bcctrl" {
|
||||
startArg = 2
|
||||
}
|
||||
if bi != Cond0LT {
|
||||
// A non-zero BI bit was encoded, but ignored by BO
|
||||
startArg = 0
|
||||
}
|
||||
at = ((bo & 0x8) >> 2) | (bo & 0x1)
|
||||
} else if bo&0x4 == 0x4 {
|
||||
at = bo & 0x3
|
||||
}
|
||||
} else if bo&0x10 == 0x10 { // BI field is not used
|
||||
if opName != "bca" && opName != "bc" {
|
||||
at = ((bo & 0x8) >> 2) | (bo & 0x1)
|
||||
startArg = 2
|
||||
}
|
||||
// If BI is encoded as a bit other than 0, no mnemonic.
|
||||
if bo&0x14 == 0x14 {
|
||||
startArg = 0
|
||||
}
|
||||
} else {
|
||||
form = (bo & 0x8) >> 1
|
||||
startArg = 2
|
||||
if bo&0x14 == 0x04 {
|
||||
at = bo & 0x3
|
||||
}
|
||||
}
|
||||
sfx += atsfx[at]
|
||||
|
||||
if form != 1 {
|
||||
bit := int((bi-Cond0LT)%4) | (^form)&0x4
|
||||
sfx = condBit[bit] + sfx
|
||||
}
|
||||
|
||||
if at != 1 && startArg > 0 && bh <= 0 {
|
||||
str := fmt.Sprintf("b%s", sfx)
|
||||
if startArg > 1 && (cr != 0 || bh > 0) {
|
||||
str += fmt.Sprintf(" cr%d", cr)
|
||||
sep = ","
|
||||
}
|
||||
buf.WriteString(str)
|
||||
if startArg < 2 && bh == 0 {
|
||||
str := fmt.Sprintf(" %s",
|
||||
gnuArg(&inst, 1, inst.Args[1], PC))
|
||||
buf.WriteString(str)
|
||||
startArg = 3
|
||||
} else if bh == 0 {
|
||||
startArg = 3
|
||||
}
|
||||
} else {
|
||||
if startArg == 0 || bh > 0 || at == 1 {
|
||||
buf.WriteString(inst.Op.String())
|
||||
buf.WriteString(atsfx[at])
|
||||
startArg = 0
|
||||
} else {
|
||||
buf.WriteString("b" + sfx)
|
||||
}
|
||||
if bh == 0 {
|
||||
str := fmt.Sprintf(" %d,%s", bo, gnuArg(&inst, 1, inst.Args[1], PC))
|
||||
buf.WriteString(str)
|
||||
startArg = 3
|
||||
}
|
||||
}
|
||||
|
||||
case "mtspr":
|
||||
opcode := inst.Op.String()
|
||||
buf.WriteString(opcode[0:2])
|
||||
switch spr := inst.Args[0].(type) {
|
||||
case SpReg:
|
||||
switch spr {
|
||||
case 1:
|
||||
buf.WriteString("xer")
|
||||
startArg = 1
|
||||
case 8:
|
||||
buf.WriteString("lr")
|
||||
startArg = 1
|
||||
case 9:
|
||||
buf.WriteString("ctr")
|
||||
startArg = 1
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
|
||||
case "mfspr":
|
||||
opcode := inst.Op.String()
|
||||
buf.WriteString(opcode[0:2])
|
||||
arg := inst.Args[0]
|
||||
switch spr := inst.Args[1].(type) {
|
||||
case SpReg:
|
||||
switch spr {
|
||||
case 1:
|
||||
buf.WriteString("xer ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 8:
|
||||
buf.WriteString("lr ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 9:
|
||||
buf.WriteString("ctr ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
case 268:
|
||||
buf.WriteString("tb ")
|
||||
buf.WriteString(gnuArg(&inst, 0, arg, PC))
|
||||
startArg = 2
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
default:
|
||||
buf.WriteString("spr")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
case "paddi":
|
||||
// There are several extended mnemonics. Notably, "pla" is
|
||||
// the only valid mnemonic for paddi (R=1), In this case, RA must
|
||||
// always be 0. Otherwise it is invalid.
|
||||
r := inst.Args[3].(Imm)
|
||||
ra := inst.Args[1].(Reg)
|
||||
str := opName
|
||||
if ra == R0 {
|
||||
name := []string{"pli", "pla"}
|
||||
str = fmt.Sprintf("%s %s,%s",
|
||||
name[r&1],
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
gnuArg(&inst, 2, inst.Args[2], PC))
|
||||
startArg = 4
|
||||
} else {
|
||||
str = fmt.Sprintf("%s %s,%s,%s", opName,
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
gnuArg(&inst, 1, inst.Args[1], PC),
|
||||
gnuArg(&inst, 2, inst.Args[2], PC))
|
||||
startArg = 4
|
||||
if r == 1 {
|
||||
// This is an illegal encoding (ra != 0 && r == 1) on ISA 3.1.
|
||||
v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
|
||||
return fmt.Sprintf(".quad 0x%x", v)
|
||||
}
|
||||
}
|
||||
buf.WriteString(str)
|
||||
|
||||
default:
|
||||
// Prefixed load/stores do not print the displacement register when R==1 (they are PCrel).
|
||||
// This also implies RA should be 0. Likewise, when R==0, printing of R can be omitted.
|
||||
if strings.HasPrefix(opName, "pl") || strings.HasPrefix(opName, "pst") {
|
||||
r := inst.Args[3].(Imm)
|
||||
ra := inst.Args[2].(Reg)
|
||||
d := inst.Args[1].(Offset)
|
||||
if r == 1 && ra == R0 {
|
||||
str := fmt.Sprintf("%s %s,%d", opName, gnuArg(&inst, 0, inst.Args[0], PC), d)
|
||||
buf.WriteString(str)
|
||||
startArg = 4
|
||||
} else {
|
||||
str := fmt.Sprintf("%s %s,%d(%s)", opName,
|
||||
gnuArg(&inst, 0, inst.Args[0], PC),
|
||||
d,
|
||||
gnuArg(&inst, 2, inst.Args[2], PC))
|
||||
if r == 1 {
|
||||
// This is an invalid encoding (ra != 0 && r == 1) on ISA 3.1.
|
||||
v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
|
||||
return fmt.Sprintf(".quad 0x%x", v)
|
||||
}
|
||||
buf.WriteString(str)
|
||||
startArg = 4
|
||||
}
|
||||
} else {
|
||||
buf.WriteString(opName)
|
||||
}
|
||||
}
|
||||
for i, arg := range argList {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
if i < startArg {
|
||||
continue
|
||||
}
|
||||
text := gnuArg(&inst, i, arg, PC)
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
buf.WriteString(sep)
|
||||
sep = ","
|
||||
buf.WriteString(text)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules.
|
||||
// NOTE: because GNUSyntax is the only caller of this func, and it receives a copy
|
||||
// of inst, it's ok to modify inst.Args here.
|
||||
func gnuArg(inst *Inst, argIndex int, arg Arg, pc uint64) string {
|
||||
// special cases for load/store instructions
|
||||
if _, ok := arg.(Offset); ok {
|
||||
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
|
||||
panic(fmt.Errorf("wrong table: offset not followed by register"))
|
||||
}
|
||||
}
|
||||
switch arg := arg.(type) {
|
||||
case Reg:
|
||||
if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
|
||||
return "0"
|
||||
}
|
||||
return arg.String()
|
||||
case CondReg:
|
||||
// The CondReg can either be found in a CMP, where the
|
||||
// condition register field is being set, or in an instruction
|
||||
// like a branch or isel that is testing a bit in a condition
|
||||
// register field.
|
||||
if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
|
||||
return "" // don't show cr0 for cmp instructions
|
||||
} else if arg >= CR0 {
|
||||
return fmt.Sprintf("cr%d", int(arg-CR0))
|
||||
}
|
||||
bit := condBit[(arg-Cond0LT)%4]
|
||||
if arg <= Cond0SO {
|
||||
return bit
|
||||
}
|
||||
return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
|
||||
case Imm:
|
||||
return fmt.Sprintf("%d", arg)
|
||||
case SpReg:
|
||||
switch int(arg) {
|
||||
case 1:
|
||||
return "xer"
|
||||
case 8:
|
||||
return "lr"
|
||||
case 9:
|
||||
return "ctr"
|
||||
case 268:
|
||||
return "tb"
|
||||
default:
|
||||
return fmt.Sprintf("%d", int(arg))
|
||||
}
|
||||
case PCRel:
|
||||
// If the arg is 0, use the relative address format.
|
||||
// Otherwise the pc is meaningful, use absolute address.
|
||||
if int(arg) == 0 {
|
||||
return fmt.Sprintf(".%+#x", int(arg))
|
||||
}
|
||||
addr := pc + uint64(int64(arg))
|
||||
return fmt.Sprintf("%#x", addr)
|
||||
case Label:
|
||||
return fmt.Sprintf("%#x", uint32(arg))
|
||||
case Offset:
|
||||
reg := inst.Args[argIndex+1].(Reg)
|
||||
removeArg(inst, argIndex+1)
|
||||
if reg == R0 {
|
||||
return fmt.Sprintf("%d(0)", int(arg))
|
||||
}
|
||||
return fmt.Sprintf("%d(r%d)", int(arg), reg-R0)
|
||||
}
|
||||
return fmt.Sprintf("???(%v)", arg)
|
||||
}
|
||||
|
||||
// removeArg removes the arg in inst.Args[index].
|
||||
func removeArg(inst *Inst, index int) {
|
||||
for i := index; i < len(inst.Args); i++ {
|
||||
if i+1 < len(inst.Args) {
|
||||
inst.Args[i] = inst.Args[i+1]
|
||||
} else {
|
||||
inst.Args[i] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isLoadStoreOp returns true if op is a load or store instruction
|
||||
func isLoadStoreOp(op Op) bool {
|
||||
switch op {
|
||||
case LBZ, LBZU, LBZX, LBZUX:
|
||||
return true
|
||||
case LHZ, LHZU, LHZX, LHZUX:
|
||||
return true
|
||||
case LHA, LHAU, LHAX, LHAUX:
|
||||
return true
|
||||
case LWZ, LWZU, LWZX, LWZUX:
|
||||
return true
|
||||
case LWA, LWAX, LWAUX:
|
||||
return true
|
||||
case LD, LDU, LDX, LDUX:
|
||||
return true
|
||||
case LQ:
|
||||
return true
|
||||
case STB, STBU, STBX, STBUX:
|
||||
return true
|
||||
case STH, STHU, STHX, STHUX:
|
||||
return true
|
||||
case STW, STWU, STWX, STWUX:
|
||||
return true
|
||||
case STD, STDU, STDX, STDUX:
|
||||
return true
|
||||
case STQ:
|
||||
return true
|
||||
case LHBRX, LWBRX, STHBRX, STWBRX:
|
||||
return true
|
||||
case LBARX, LWARX, LHARX, LDARX:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Inst struct {
|
||||
Op Op // Opcode mnemonic
|
||||
Enc uint32 // Raw encoding bits (if Len == 8, this is the prefix word)
|
||||
Len int // Length of encoding in bytes.
|
||||
SuffixEnc uint32 // Raw encoding bits of second word (if Len == 8)
|
||||
Args Args // Instruction arguments, in Power ISA manual order.
|
||||
}
|
||||
|
||||
func (i Inst) String() string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(i.Op.String())
|
||||
for j, arg := range i.Args {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
if j == 0 {
|
||||
buf.WriteString(" ")
|
||||
} else {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(arg.String())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// An Op is an instruction operation.
|
||||
type Op uint16
|
||||
|
||||
func (o Op) String() string {
|
||||
if int(o) >= len(opstr) || opstr[o] == "" {
|
||||
return fmt.Sprintf("Op(%d)", int(o))
|
||||
}
|
||||
return opstr[o]
|
||||
}
|
||||
|
||||
// An Arg is a single instruction argument, one of these types: Reg, CondReg, SpReg, Imm, PCRel, Label, or Offset.
|
||||
type Arg interface {
|
||||
IsArg()
|
||||
String() string
|
||||
}
|
||||
|
||||
// An Args holds the instruction arguments.
|
||||
// If an instruction has fewer than 6 arguments,
|
||||
// the final elements in the array are nil.
|
||||
type Args [6]Arg
|
||||
|
||||
// A Reg is a single register. The zero value means R0, not the absence of a register.
|
||||
// It also includes special registers.
|
||||
type Reg uint16
|
||||
|
||||
const (
|
||||
_ Reg = iota
|
||||
R0
|
||||
R1
|
||||
R2
|
||||
R3
|
||||
R4
|
||||
R5
|
||||
R6
|
||||
R7
|
||||
R8
|
||||
R9
|
||||
R10
|
||||
R11
|
||||
R12
|
||||
R13
|
||||
R14
|
||||
R15
|
||||
R16
|
||||
R17
|
||||
R18
|
||||
R19
|
||||
R20
|
||||
R21
|
||||
R22
|
||||
R23
|
||||
R24
|
||||
R25
|
||||
R26
|
||||
R27
|
||||
R28
|
||||
R29
|
||||
R30
|
||||
R31
|
||||
F0
|
||||
F1
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
F13
|
||||
F14
|
||||
F15
|
||||
F16
|
||||
F17
|
||||
F18
|
||||
F19
|
||||
F20
|
||||
F21
|
||||
F22
|
||||
F23
|
||||
F24
|
||||
F25
|
||||
F26
|
||||
F27
|
||||
F28
|
||||
F29
|
||||
F30
|
||||
F31
|
||||
V0 // VSX extension, F0 is V0[0:63].
|
||||
V1
|
||||
V2
|
||||
V3
|
||||
V4
|
||||
V5
|
||||
V6
|
||||
V7
|
||||
V8
|
||||
V9
|
||||
V10
|
||||
V11
|
||||
V12
|
||||
V13
|
||||
V14
|
||||
V15
|
||||
V16
|
||||
V17
|
||||
V18
|
||||
V19
|
||||
V20
|
||||
V21
|
||||
V22
|
||||
V23
|
||||
V24
|
||||
V25
|
||||
V26
|
||||
V27
|
||||
V28
|
||||
V29
|
||||
V30
|
||||
V31
|
||||
VS0
|
||||
VS1
|
||||
VS2
|
||||
VS3
|
||||
VS4
|
||||
VS5
|
||||
VS6
|
||||
VS7
|
||||
VS8
|
||||
VS9
|
||||
VS10
|
||||
VS11
|
||||
VS12
|
||||
VS13
|
||||
VS14
|
||||
VS15
|
||||
VS16
|
||||
VS17
|
||||
VS18
|
||||
VS19
|
||||
VS20
|
||||
VS21
|
||||
VS22
|
||||
VS23
|
||||
VS24
|
||||
VS25
|
||||
VS26
|
||||
VS27
|
||||
VS28
|
||||
VS29
|
||||
VS30
|
||||
VS31
|
||||
VS32
|
||||
VS33
|
||||
VS34
|
||||
VS35
|
||||
VS36
|
||||
VS37
|
||||
VS38
|
||||
VS39
|
||||
VS40
|
||||
VS41
|
||||
VS42
|
||||
VS43
|
||||
VS44
|
||||
VS45
|
||||
VS46
|
||||
VS47
|
||||
VS48
|
||||
VS49
|
||||
VS50
|
||||
VS51
|
||||
VS52
|
||||
VS53
|
||||
VS54
|
||||
VS55
|
||||
VS56
|
||||
VS57
|
||||
VS58
|
||||
VS59
|
||||
VS60
|
||||
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() {}
|
||||
func (r Reg) String() string {
|
||||
switch {
|
||||
case R0 <= r && r <= R31:
|
||||
return fmt.Sprintf("r%d", int(r-R0))
|
||||
case F0 <= r && r <= F31:
|
||||
return fmt.Sprintf("f%d", int(r-F0))
|
||||
case V0 <= r && r <= V31:
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// CondReg is a bit or field in the condition register.
|
||||
type CondReg int8
|
||||
|
||||
const (
|
||||
_ CondReg = iota
|
||||
// Condition Regster bits
|
||||
Cond0LT
|
||||
Cond0GT
|
||||
Cond0EQ
|
||||
Cond0SO
|
||||
Cond1LT
|
||||
Cond1GT
|
||||
Cond1EQ
|
||||
Cond1SO
|
||||
Cond2LT
|
||||
Cond2GT
|
||||
Cond2EQ
|
||||
Cond2SO
|
||||
Cond3LT
|
||||
Cond3GT
|
||||
Cond3EQ
|
||||
Cond3SO
|
||||
Cond4LT
|
||||
Cond4GT
|
||||
Cond4EQ
|
||||
Cond4SO
|
||||
Cond5LT
|
||||
Cond5GT
|
||||
Cond5EQ
|
||||
Cond5SO
|
||||
Cond6LT
|
||||
Cond6GT
|
||||
Cond6EQ
|
||||
Cond6SO
|
||||
Cond7LT
|
||||
Cond7GT
|
||||
Cond7EQ
|
||||
Cond7SO
|
||||
// Condition Register Fields
|
||||
CR0
|
||||
CR1
|
||||
CR2
|
||||
CR3
|
||||
CR4
|
||||
CR5
|
||||
CR6
|
||||
CR7
|
||||
)
|
||||
|
||||
func (CondReg) IsArg() {}
|
||||
func (c CondReg) String() string {
|
||||
switch {
|
||||
default:
|
||||
return fmt.Sprintf("CondReg(%d)", int(c))
|
||||
case c >= CR0:
|
||||
return fmt.Sprintf("CR%d", int(c-CR0))
|
||||
case c >= Cond0LT && c < CR0:
|
||||
return fmt.Sprintf("Cond%d%s", int((c-Cond0LT)/4), [4]string{"LT", "GT", "EQ", "SO"}[(c-Cond0LT)%4])
|
||||
}
|
||||
}
|
||||
|
||||
// SpReg is a special register, its meaning depends on Op.
|
||||
type SpReg uint16
|
||||
|
||||
const (
|
||||
SpRegZero SpReg = 0
|
||||
)
|
||||
|
||||
func (SpReg) IsArg() {}
|
||||
func (s SpReg) String() string {
|
||||
return fmt.Sprintf("SpReg(%d)", int(s))
|
||||
}
|
||||
|
||||
// PCRel is a PC-relative offset, used only in branch instructions.
|
||||
type PCRel int32
|
||||
|
||||
func (PCRel) IsArg() {}
|
||||
func (r PCRel) String() string {
|
||||
return fmt.Sprintf("PC%+#x", int32(r))
|
||||
}
|
||||
|
||||
// A Label is a code (text) address, used only in absolute branch instructions.
|
||||
type Label uint32
|
||||
|
||||
func (Label) IsArg() {}
|
||||
func (l Label) String() string {
|
||||
return fmt.Sprintf("%#x", uint32(l))
|
||||
}
|
||||
|
||||
// Imm represents an immediate number.
|
||||
type Imm int64
|
||||
|
||||
func (Imm) IsArg() {}
|
||||
func (i Imm) String() string {
|
||||
return fmt.Sprintf("%d", int32(i))
|
||||
}
|
||||
|
||||
// Offset represents a memory offset immediate.
|
||||
type Offset int64
|
||||
|
||||
func (Offset) IsArg() {}
|
||||
func (o Offset) String() string {
|
||||
return fmt.Sprintf("%+d", int32(o))
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestObjdumpPowerTestdata(t *testing.T) { testObjdump(t, testdataCases(t)) }
|
||||
func TestObjdumpPowerManual(t *testing.T) { testObjdump(t, hexCases(t, objdumpManualTests)) }
|
||||
|
||||
// Disable this for now since generating all possible bit combinations within a word
|
||||
// generates lots of ppc64x instructions not possible with golang so not worth supporting..
|
||||
//func TestObjdumpPowerRandom(t *testing.T) { testObjdump(t, randomCases(t)) }
|
||||
|
||||
// objdumpManualTests holds test cases that will be run by TestObjdumpPowerManual.
|
||||
// If you are debugging a few cases that turned up in a longer run, it can be useful
|
||||
// to list them here and then use -run=Manual, particularly with tracing enabled.
|
||||
// Note that these are byte sequences, so they must be reversed from the usual
|
||||
// word presentation.
|
||||
var objdumpManualTests = `
|
||||
6d746162
|
||||
4c040000
|
||||
88000017
|
||||
`
|
||||
|
||||
// allowedMismatchObjdump reports whether the mismatch between text and dec
|
||||
// should be allowed by the test.
|
||||
func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool {
|
||||
// we support more instructions than binutils
|
||||
if strings.Contains(dec.text, ".long") {
|
||||
return true
|
||||
}
|
||||
|
||||
switch inst.Op {
|
||||
case BC: // We don't print PC relative branches the same way.
|
||||
return true
|
||||
case DCBF, DCBT: // We only support extended mnemonics, and may not print 0 where R0 == 0.
|
||||
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
|
||||
case BL:
|
||||
// TODO: Ignore these for now. The output format from gnu objdump is dependent on more than the
|
||||
// instruction itself e.g: decode(48100009) = "bl 0x100008", 4, want "bl .+0x100008", 4
|
||||
return true
|
||||
}
|
||||
|
||||
if len(dec.enc) >= 4 {
|
||||
_ = binary.BigEndian.Uint32(dec.enc[:4])
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// Copied and simplified from rsc.io/arm/armasm/objdumpext_test.go.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var objdumpPath = "objdump"
|
||||
|
||||
var objdumpCrossNames = [...]string{"powerpc64-linux-gnu-objdump", "powerpc64le-linux-gnu-objdump"}
|
||||
|
||||
func testObjdump(t *testing.T, generate func(func([]byte))) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping objdump test in short mode")
|
||||
}
|
||||
if runtime.GOARCH != "ppc64le" && runtime.GOARCH != "ppc64" {
|
||||
found := false
|
||||
for _, c := range objdumpCrossNames {
|
||||
if _, err := exec.LookPath(c); err == nil {
|
||||
objdumpPath = c
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Skip("skipping; test requires host tool objdump for ppc64 or ppc64le")
|
||||
}
|
||||
} else if _, err := exec.LookPath(objdumpPath); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
|
||||
testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump)
|
||||
}
|
||||
|
||||
func objdump(ext *ExtDis) error {
|
||||
// File already written with instructions; add ELF header.
|
||||
if err := writeELF64(ext.File, ext.Size); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
nmatch int
|
||||
reading bool
|
||||
next uint32 = start
|
||||
addr uint32
|
||||
encbuf [8]byte
|
||||
enc []byte
|
||||
text string
|
||||
)
|
||||
flush := func() {
|
||||
if addr == next {
|
||||
if m := pcrel.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s.%+#x", m[1], int32(uint32(targ)-addr))
|
||||
}
|
||||
if strings.HasPrefix(text, "stmia") {
|
||||
text = "stm" + text[5:]
|
||||
}
|
||||
if strings.HasPrefix(text, "stmfd") {
|
||||
text = "stmdb" + text[5:]
|
||||
}
|
||||
if strings.HasPrefix(text, "ldmfd") {
|
||||
text = "ldm" + text[5:]
|
||||
}
|
||||
text = strings.Replace(text, "#0.0", "#0", -1)
|
||||
if text == "undefined" && len(enc) == 4 {
|
||||
text = "error: unknown instruction"
|
||||
enc = nil
|
||||
}
|
||||
// Prefixed instructions may not decode as expected if
|
||||
// they are an invalid form. Some are tested in decode.txt.
|
||||
// objdump treats these like two instructions.
|
||||
//
|
||||
// Look for primary opcode 1 and advance an exta 4 bytes if
|
||||
// this failed to decode.
|
||||
if strings.HasPrefix(text, ".long") && enc[0]>>2 == 1 {
|
||||
next += 4
|
||||
}
|
||||
ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
|
||||
encbuf = [8]byte{}
|
||||
next += uint32(len(enc))
|
||||
enc = nil
|
||||
}
|
||||
}
|
||||
var textangle = []byte("<.text>:")
|
||||
for {
|
||||
line, err := b.ReadSlice('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("reading objdump output: %v", err)
|
||||
}
|
||||
if bytes.Contains(line, textangle) {
|
||||
reading = true
|
||||
continue
|
||||
}
|
||||
if !reading {
|
||||
continue
|
||||
}
|
||||
if debug {
|
||||
os.Stdout.Write(line)
|
||||
}
|
||||
if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
|
||||
enc = enc1
|
||||
continue
|
||||
}
|
||||
flush()
|
||||
nmatch++
|
||||
addr, enc, text = parseLine(line, encbuf[:0])
|
||||
if addr > next {
|
||||
return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
|
||||
}
|
||||
}
|
||||
flush()
|
||||
if next != start+uint32(ext.Size) {
|
||||
return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
|
||||
}
|
||||
if err := ext.Wait(); err != nil {
|
||||
return fmt.Errorf("exec: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
undefined = []byte("<UNDEFINED>")
|
||||
unpredictable = []byte("<UNPREDICTABLE>")
|
||||
illegalShifter = []byte("<illegal shifter operand>")
|
||||
)
|
||||
|
||||
func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) {
|
||||
oline := line
|
||||
i := index(line, ":\t")
|
||||
if i < 0 {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
addr = uint32(x)
|
||||
line = line[i+2:]
|
||||
i = bytes.IndexByte(line, '\t')
|
||||
if i < 0 {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
enc, ok := parseHex(line[:i], encstart)
|
||||
if !ok {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
line = trimSpace(line[i:])
|
||||
if bytes.Contains(line, undefined) {
|
||||
text = "undefined"
|
||||
return
|
||||
}
|
||||
if bytes.Contains(line, illegalShifter) {
|
||||
text = "undefined"
|
||||
return
|
||||
}
|
||||
if false && bytes.Contains(line, unpredictable) {
|
||||
text = "unpredictable"
|
||||
return
|
||||
}
|
||||
if i := bytes.IndexByte(line, ';'); i >= 0 {
|
||||
line = trimSpace(line[:i])
|
||||
}
|
||||
text = string(fixSpace(line))
|
||||
return
|
||||
}
|
||||
|
||||
func parseContinuation(line []byte, enc []byte) []byte {
|
||||
i := index(line, ":\t")
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
line = line[i+1:]
|
||||
enc, _ = parseHex(line, enc)
|
||||
return enc
|
||||
}
|
||||
|
||||
// writeELF64 writes an ELF64 header to the file,
|
||||
// describing a text segment that starts at start
|
||||
// and extends for size bytes.
|
||||
func writeELF64(f *os.File, size int) error {
|
||||
f.Seek(0, io.SeekStart)
|
||||
var hdr elf.Header64
|
||||
var prog elf.Prog64
|
||||
var sect elf.Section64
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.BigEndian, &hdr)
|
||||
off1 := buf.Len()
|
||||
binary.Write(&buf, binary.BigEndian, &prog)
|
||||
off2 := buf.Len()
|
||||
binary.Write(&buf, binary.BigEndian, §)
|
||||
off3 := buf.Len()
|
||||
buf.Reset()
|
||||
data := byte(elf.ELFDATA2MSB)
|
||||
hdr = elf.Header64{
|
||||
Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
|
||||
Type: 2,
|
||||
Machine: uint16(elf.EM_PPC64),
|
||||
Version: 1,
|
||||
Entry: start,
|
||||
Phoff: uint64(off1),
|
||||
Shoff: uint64(off2),
|
||||
Flags: 0x05000002,
|
||||
Ehsize: uint16(off1),
|
||||
Phentsize: uint16(off2 - off1),
|
||||
Phnum: 1,
|
||||
Shentsize: uint16(off3 - off2),
|
||||
Shnum: 3,
|
||||
Shstrndx: 2,
|
||||
}
|
||||
binary.Write(&buf, binary.BigEndian, &hdr)
|
||||
prog = elf.Prog64{
|
||||
Type: 1,
|
||||
Off: start,
|
||||
Vaddr: start,
|
||||
Paddr: start,
|
||||
Filesz: uint64(size),
|
||||
Memsz: uint64(size),
|
||||
Flags: 5,
|
||||
Align: start,
|
||||
}
|
||||
binary.Write(&buf, binary.BigEndian, &prog)
|
||||
binary.Write(&buf, binary.BigEndian, §) // NULL section
|
||||
sect = elf.Section64{
|
||||
Name: 1,
|
||||
Type: uint32(elf.SHT_PROGBITS),
|
||||
Addr: start,
|
||||
Off: start,
|
||||
Size: uint64(size),
|
||||
Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
|
||||
Addralign: 4,
|
||||
}
|
||||
binary.Write(&buf, binary.BigEndian, §) // .text
|
||||
sect = elf.Section64{
|
||||
Name: uint32(len("\x00.text\x00")),
|
||||
Type: uint32(elf.SHT_STRTAB),
|
||||
Addr: 0,
|
||||
Off: uint64(off2 + (off3-off2)*3),
|
||||
Size: uint64(len("\x00.text\x00.shstrtab\x00")),
|
||||
Addralign: 1,
|
||||
}
|
||||
binary.Write(&buf, binary.BigEndian, §)
|
||||
buf.WriteString("\x00.text\x00.shstrtab\x00")
|
||||
f.Write(buf.Bytes())
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
package ppc64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GoSyntax returns the Go assembler syntax for the instruction.
|
||||
// The pc is the program counter of the first instruction, used for expanding
|
||||
// PC-relative addresses into absolute ones.
|
||||
// The symname function queries the symbol table for the program
|
||||
// being disassembled. It returns the name and base address of the symbol
|
||||
// containing the target, if any; otherwise it returns "", 0.
|
||||
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
|
||||
if symname == nil {
|
||||
symname = func(uint64) (string, uint64) { return "", 0 }
|
||||
}
|
||||
if inst.Op == 0 && inst.Enc == 0 {
|
||||
return "WORD $0"
|
||||
} else if inst.Op == 0 {
|
||||
return "?"
|
||||
}
|
||||
var args []string
|
||||
for i, a := range inst.Args[:] {
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
|
||||
args = append(args, s)
|
||||
}
|
||||
}
|
||||
var op string
|
||||
op = plan9OpMap[inst.Op]
|
||||
if op == "" {
|
||||
op = strings.ToUpper(inst.Op.String())
|
||||
if op[len(op)-1] == '.' {
|
||||
op = op[:len(op)-1] + "CC"
|
||||
}
|
||||
}
|
||||
// laid out the instruction
|
||||
switch inst.Op {
|
||||
default: // dst, sA, sB, ...
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return op
|
||||
case 1:
|
||||
return fmt.Sprintf("%s %s", op, args[0])
|
||||
case 2:
|
||||
if inst.Op == COPY || inst.Op == PASTECC {
|
||||
return op + " " + args[0] + "," + args[1]
|
||||
}
|
||||
return op + " " + args[1] + "," + args[0]
|
||||
case 3:
|
||||
if reverseOperandOrder(inst.Op) {
|
||||
return op + " " + args[2] + "," + args[1] + "," + args[0]
|
||||
}
|
||||
case 4:
|
||||
if reverseMiddleOps(inst.Op) {
|
||||
return op + " " + args[1] + "," + args[3] + "," + args[2] + "," + args[0]
|
||||
}
|
||||
}
|
||||
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"
|
||||
}
|
||||
return "HWSYNC"
|
||||
|
||||
case ISEL:
|
||||
return "ISEL " + args[3] + "," + args[1] + "," + args[2] + "," + args[0]
|
||||
|
||||
// store instructions always have the memory operand at the end, no need to reorder
|
||||
// indexed stores handled separately
|
||||
case STB, STBU,
|
||||
STH, STHU,
|
||||
STW, STWU,
|
||||
STD, STDU,
|
||||
STFD, STFDU,
|
||||
STFS, STFSU,
|
||||
STQ, HASHST, HASHSTP:
|
||||
return op + " " + strings.Join(args, ",")
|
||||
|
||||
case FCMPU, FCMPO, CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
|
||||
crf := int(inst.Args[0].(CondReg) - CR0)
|
||||
cmpstr := op + " " + args[1] + "," + args[2]
|
||||
if crf != 0 { // print CRx as the final operand if not implied (i.e BF != 0)
|
||||
cmpstr += "," + args[0]
|
||||
}
|
||||
return cmpstr
|
||||
|
||||
case LIS:
|
||||
return "ADDIS $0," + args[1] + "," + args[0]
|
||||
// store instructions with index registers
|
||||
case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
|
||||
STHBRX, STWBRX, STDBRX, STSWX, STFIWX:
|
||||
return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
|
||||
|
||||
case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
|
||||
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
|
||||
|
||||
case STXVX, STXVD2X, STXVW4X, STXVH8X, STXVB16X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
|
||||
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
|
||||
|
||||
case STXV:
|
||||
return op + " " + args[0] + "," + args[1]
|
||||
|
||||
case STXVL, STXVLL:
|
||||
return op + " " + args[0] + "," + args[1] + "," + args[2]
|
||||
|
||||
case LWAX, LWAUX, LWZX, LHZX, LBZX, LDX, LHAX, LHAUX, LDARX, LWARX, LHARX, LBARX, LFDX, LFDUX, LFSX, LFSUX, LDBRX, LWBRX, LHBRX, LDUX, LWZUX, LHZUX, LBZUX:
|
||||
if args[1] == "0" {
|
||||
return op + " (" + args[2] + ")," + args[0]
|
||||
}
|
||||
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
|
||||
|
||||
case LXVX, LXVD2X, LXVW4X, LXVH8X, LXVB16X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
|
||||
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
|
||||
|
||||
case LXV:
|
||||
return op + " " + args[1] + "," + args[0]
|
||||
|
||||
case LXVL, LXVLL:
|
||||
return op + " " + args[1] + "," + args[2] + "," + args[0]
|
||||
|
||||
case DCBT, DCBTST, DCBZ, DCBST, ICBI:
|
||||
if args[0] == "0" || args[0] == "R0" {
|
||||
return op + " (" + args[1] + ")"
|
||||
}
|
||||
return op + " (" + args[1] + ")(" + args[0] + ")"
|
||||
|
||||
// branch instructions needs additional handling
|
||||
case BCLR:
|
||||
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
|
||||
return "RET"
|
||||
}
|
||||
return op + " " + strings.Join(args, ", ")
|
||||
case BC:
|
||||
bo := int(inst.Args[0].(Imm))
|
||||
bi := int(inst.Args[1].(CondReg) - Cond0LT)
|
||||
bcname := condName[((bo&0x8)>>1)|(bi&0x3)]
|
||||
if bo&0x17 == 4 { // jump only a CR bit set/unset, no hints (at bits) set.
|
||||
if bi >= 4 {
|
||||
return fmt.Sprintf("B%s CR%d,%s", bcname, bi>>2, args[2])
|
||||
} else {
|
||||
return fmt.Sprintf("B%s %s", bcname, args[2])
|
||||
}
|
||||
}
|
||||
return op + " " + strings.Join(args, ",")
|
||||
case BCCTR:
|
||||
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
|
||||
return "BR (CTR)"
|
||||
}
|
||||
return op + " " + strings.Join(args, ", ")
|
||||
case BCCTRL:
|
||||
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
|
||||
return "BL (CTR)"
|
||||
}
|
||||
return op + " " + strings.Join(args, ",")
|
||||
case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
|
||||
return op + " " + strings.Join(args, ",")
|
||||
}
|
||||
}
|
||||
|
||||
// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
|
||||
//
|
||||
// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
|
||||
// of inst, it's ok to modify inst.Args here.
|
||||
func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
|
||||
// special cases for load/store instructions
|
||||
if _, ok := arg.(Offset); ok {
|
||||
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
|
||||
panic(fmt.Errorf("wrong table: offset not followed by register"))
|
||||
}
|
||||
}
|
||||
switch arg := arg.(type) {
|
||||
case Reg:
|
||||
if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
|
||||
return "0"
|
||||
}
|
||||
if arg == R30 {
|
||||
return "g"
|
||||
}
|
||||
return strings.ToUpper(arg.String())
|
||||
case CondReg:
|
||||
// This op is left as its numerical value, not mapped onto CR + condition
|
||||
if inst.Op == ISEL {
|
||||
return fmt.Sprintf("$%d", (arg - Cond0LT))
|
||||
}
|
||||
bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
|
||||
if arg <= Cond0SO {
|
||||
return bit
|
||||
} else if arg > Cond0SO && arg <= Cond7SO {
|
||||
return fmt.Sprintf("CR%d%s", int(arg-Cond0LT)/4, bit)
|
||||
} else {
|
||||
return fmt.Sprintf("CR%d", int(arg-CR0))
|
||||
}
|
||||
case Imm:
|
||||
return fmt.Sprintf("$%d", arg)
|
||||
case SpReg:
|
||||
switch arg {
|
||||
case 8:
|
||||
return "LR"
|
||||
case 9:
|
||||
return "CTR"
|
||||
}
|
||||
return fmt.Sprintf("SPR(%d)", int(arg))
|
||||
case PCRel:
|
||||
addr := pc + uint64(int64(arg))
|
||||
s, base := symname(addr)
|
||||
if s != "" && addr == base {
|
||||
return fmt.Sprintf("%s(SB)", s)
|
||||
}
|
||||
if inst.Op == BL && s != "" && (addr-base) == 8 {
|
||||
// When decoding an object built for PIE, a CALL targeting
|
||||
// a global entry point will be adjusted to the local entry
|
||||
// if any. For now, assume any symname+8 PC is a local call.
|
||||
return fmt.Sprintf("%s+%d(SB)", s, addr-base)
|
||||
}
|
||||
return fmt.Sprintf("%#x", addr)
|
||||
case Label:
|
||||
return fmt.Sprintf("%#x", int(arg))
|
||||
case Offset:
|
||||
reg := inst.Args[argIndex+1].(Reg)
|
||||
removeArg(inst, argIndex+1)
|
||||
if reg == R0 {
|
||||
return fmt.Sprintf("%d(0)", int(arg))
|
||||
}
|
||||
return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
|
||||
}
|
||||
return fmt.Sprintf("???(%v)", arg)
|
||||
}
|
||||
|
||||
func reverseMiddleOps(op Op) bool {
|
||||
switch op {
|
||||
case FMADD, FMADDCC, FMADDS, FMADDSCC, FMSUB, FMSUBCC, FMSUBS, FMSUBSCC, FNMADD, FNMADDCC, FNMADDS, FNMADDSCC, FNMSUB, FNMSUBCC, FNMSUBS, FNMSUBSCC, FSEL, FSELCC:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func reverseOperandOrder(op Op) bool {
|
||||
switch op {
|
||||
// Special case for SUBF, SUBFC: not reversed
|
||||
case ADD, ADDC, ADDE, ADDCC, ADDCCC:
|
||||
return true
|
||||
case MULLW, MULLWCC, MULHW, MULHWCC, MULLD, MULLDCC, MULHD, MULHDCC, MULLWO, MULLWOCC, MULHWU, MULHWUCC, MULLDO, MULLDOCC:
|
||||
return true
|
||||
case DIVD, DIVDCC, DIVDU, DIVDUCC, DIVDE, DIVDECC, DIVDEU, DIVDEUCC, DIVDO, DIVDOCC, DIVDUO, DIVDUOCC:
|
||||
return true
|
||||
case MODUD, MODSD, MODUW, MODSW:
|
||||
return true
|
||||
case FADD, FADDS, FSUB, FSUBS, FMUL, FMULS, FDIV, FDIVS, FMADD, FMADDS, FMSUB, FMSUBS, FNMADD, FNMADDS, FNMSUB, FNMSUBS, FMULSCC:
|
||||
return true
|
||||
case FADDCC, FADDSCC, FSUBCC, FMULCC, FDIVCC, FDIVSCC:
|
||||
return true
|
||||
case OR, ORCC, ORC, ORCCC, AND, ANDCC, ANDC, ANDCCC, XOR, XORCC, NAND, NANDCC, EQV, EQVCC, NOR, NORCC:
|
||||
return true
|
||||
case SLW, SLWCC, SLD, SLDCC, SRW, SRAW, SRWCC, SRAWCC, SRD, SRDCC, SRAD, SRADCC:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// revCondMap maps a conditional register bit to its inverse, if possible.
|
||||
var revCondMap = map[string]string{
|
||||
"LT": "GE", "GT": "LE", "EQ": "NE",
|
||||
}
|
||||
|
||||
// Lookup table to map BI[0:1] and BO[3] to an extended mnemonic for CR ops.
|
||||
// Bits 0-1 map to a bit with a CR field, and bit 2 selects the inverted (0)
|
||||
// or regular (1) extended mnemonic.
|
||||
var condName = []string{
|
||||
"GE",
|
||||
"LE",
|
||||
"NE",
|
||||
"NSO",
|
||||
"LT",
|
||||
"GT",
|
||||
"EQ",
|
||||
"SO",
|
||||
}
|
||||
|
||||
// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
|
||||
var plan9OpMap = map[Op]string{
|
||||
LWARX: "LWAR",
|
||||
LDARX: "LDAR",
|
||||
LHARX: "LHAR",
|
||||
LBARX: "LBAR",
|
||||
LWAX: "MOVW",
|
||||
LHAX: "MOVH",
|
||||
LWAUX: "MOVWU",
|
||||
LHAU: "MOVHU",
|
||||
LHAUX: "MOVHU",
|
||||
LDX: "MOVD",
|
||||
LDUX: "MOVDU",
|
||||
LWZX: "MOVWZ",
|
||||
LWZUX: "MOVWZU",
|
||||
LHZX: "MOVHZ",
|
||||
LHZUX: "MOVHZU",
|
||||
LBZX: "MOVBZ",
|
||||
LBZUX: "MOVBZU",
|
||||
LDBRX: "MOVDBR",
|
||||
LWBRX: "MOVWBR",
|
||||
LHBRX: "MOVHBR",
|
||||
MCRF: "MOVFL",
|
||||
XORI: "XOR",
|
||||
ORI: "OR",
|
||||
ANDICC: "ANDCC",
|
||||
ANDC: "ANDN",
|
||||
ANDCCC: "ANDNCC",
|
||||
ADDEO: "ADDEV",
|
||||
ADDEOCC: "ADDEVCC",
|
||||
ADDO: "ADDV",
|
||||
ADDOCC: "ADDVCC",
|
||||
ADDMEO: "ADDMEV",
|
||||
ADDMEOCC: "ADDMEVCC",
|
||||
ADDCO: "ADDCV",
|
||||
ADDCOCC: "ADDCVCC",
|
||||
ADDZEO: "ADDZEV",
|
||||
ADDZEOCC: "ADDZEVCC",
|
||||
SUBFME: "SUBME",
|
||||
SUBFMECC: "SUBMECC",
|
||||
SUBFZE: "SUBZE",
|
||||
SUBFZECC: "SUBZECC",
|
||||
SUBFZEO: "SUBZEV",
|
||||
SUBFZEOCC: "SUBZEVCC",
|
||||
SUBF: "SUB",
|
||||
SUBFC: "SUBC",
|
||||
SUBFCC: "SUBCC",
|
||||
SUBFCCC: "SUBCCC",
|
||||
ORC: "ORN",
|
||||
ORCCC: "ORNCC",
|
||||
MULLWO: "MULLWV",
|
||||
MULLWOCC: "MULLWVCC",
|
||||
MULLDO: "MULLDV",
|
||||
MULLDOCC: "MULLDVCC",
|
||||
DIVDO: "DIVDV",
|
||||
DIVDOCC: "DIVDVCC",
|
||||
DIVDUO: "DIVDUV",
|
||||
DIVDUOCC: "DIVDUVCC",
|
||||
ADDI: "ADD",
|
||||
MULLI: "MULLD",
|
||||
SRADI: "SRAD",
|
||||
STBCXCC: "STBCCC",
|
||||
STWCXCC: "STWCCC",
|
||||
STDCXCC: "STDCCC",
|
||||
LI: "MOVD",
|
||||
LBZ: "MOVBZ", STB: "MOVB",
|
||||
LBZU: "MOVBZU", STBU: "MOVBU",
|
||||
LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
|
||||
LHZU: "MOVHZU", STHU: "MOVHU",
|
||||
LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
|
||||
LWZU: "MOVWZU", STWU: "MOVWU",
|
||||
LD: "MOVD", STD: "MOVD",
|
||||
LDU: "MOVDU", STDU: "MOVDU",
|
||||
LFD: "FMOVD", STFD: "FMOVD",
|
||||
LFS: "FMOVS", STFS: "FMOVS",
|
||||
LFDX: "FMOVD", STFDX: "FMOVD",
|
||||
LFDU: "FMOVDU", STFDU: "FMOVDU",
|
||||
LFDUX: "FMOVDU", STFDUX: "FMOVDU",
|
||||
LFSX: "FMOVS", STFSX: "FMOVS",
|
||||
LFSU: "FMOVSU", STFSU: "FMOVSU",
|
||||
LFSUX: "FMOVSU", STFSUX: "FMOVSU",
|
||||
CMPD: "CMP", CMPDI: "CMP",
|
||||
CMPW: "CMPW", CMPWI: "CMPW",
|
||||
CMPLD: "CMPU", CMPLDI: "CMPU",
|
||||
CMPLW: "CMPWU", CMPLWI: "CMPWU",
|
||||
MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
|
||||
B: "BR",
|
||||
BL: "CALL",
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,885 @@
|
||||
6d746162| gnu xoris r20,r11,24930
|
||||
6d746162| plan9 XORIS R11,$24930,R20
|
||||
4c040000| gnu mcrf cr0,cr1
|
||||
88a70002| gnu lbz r5,2(r7)
|
||||
88a70002| plan9 MOVBZ 2(R7),R5
|
||||
00000000| plan9 WORD $0
|
||||
00010000| plan9 error: unknown instruction
|
||||
00000000| gnu .long 0x0
|
||||
00002000| gnu error: unknown instruction
|
||||
a1841e80| gnu lhz r12,7808(r4)
|
||||
a1841e80| plan9 MOVHZ 7808(R4),R12
|
||||
42000004| gnu bdnz 0x30
|
||||
e38d5b90| gnu lq r28,23440(r13)
|
||||
84127a20| gnu lwzu r0,31264(r18)
|
||||
84127a20| plan9 MOVWZU 31264(R18),R0
|
||||
a8630000| gnu lha r3,0(r3)
|
||||
a8630000| plan9 MOVH 0(R3),R3
|
||||
ebb24fd1| gnu ldu r29,20432(r18)
|
||||
ebb24fd1| plan9 MOVDU 20432(R18),R29
|
||||
b1ce0612| gnu sth r14,1554(r14)
|
||||
b1ce0612| plan9 MOVH R14,1554(R14)
|
||||
945c62a2| gnu stwu r2,25250(r28)
|
||||
f91b9c7a| gnu stq r8,-25480(r27)
|
||||
2c030001| gnu cmpwi r3,1
|
||||
2c030001| plan9 CMPW R3,$1
|
||||
e8610032| gnu lwa r3,48(r1)
|
||||
e8610032| plan9 MOVW 48(R1),R3
|
||||
4320336b| gnu bdnzla+ 0x3368
|
||||
7e40092e| gnu stwx r18,0,r1
|
||||
7e40092e| plan9 MOVW R18,(R1)(0)
|
||||
7c103c2c| gnu lwbrx r0,r16,r7
|
||||
7c103c2c| plan9 MOVWBR (R7)(R16),R0
|
||||
7c441d28| gnu stdbrx r2,r4,r3
|
||||
7c441d28| plan9 MOVDBR R2,(R3)(R4)
|
||||
3d220001| gnu addis r9,r2,1
|
||||
3d220001| plan9 ADDIS R2,$1,R9
|
||||
7ce628ae| gnu lbzx r7,r6,r5
|
||||
7ce628ae| plan9 MOVBZ (R5)(R6),R7
|
||||
7c0e1e99| gnu lxvd2x vs32,r14,r3
|
||||
7c0e1e99| plan9 LXVD2X (R3)(R14),VS32
|
||||
7c00422c| gnu dcbt r0,r8,0
|
||||
7c00422c| plan9 DCBT (R8)
|
||||
7fab3040| gnu cmpld cr7,r11,r6
|
||||
7fab3040| plan9 CMPU R11,R6,CR7
|
||||
2c030001| gnu cmpwi r3,1
|
||||
2c030001| plan9 CMPW R3,$1
|
||||
7c2b4840| gnu cmpld r11,r9
|
||||
7c2b4840| plan9 CMPU R11,R9
|
||||
7c6521ad| gnu stdcx. r3,r5,r4
|
||||
7c6521ad| plan9 STDCCC R3,(R4)(R5)
|
||||
fbe1ffd1| gnu stdu r31,-48(r1)
|
||||
fbe1ffd1| plan9 MOVDU R31,-48(R1)
|
||||
7c941f19| gnu stxvw4x vs36,r20,r3
|
||||
7c941f19| plan9 STXVW4X VS36,(R3)(R20)
|
||||
7c941f59| gnu stxvh8x vs36,r20,r3
|
||||
7c941f59| plan9 STXVH8X VS36,(R3)(R20)
|
||||
7c941fd9| gnu stxvb16x vs36,r20,r3
|
||||
7c941fd9| plan9 STXVB16X VS36,(R3)(R20)
|
||||
7c6520a8| gnu ldarx r3,r5,r4
|
||||
7c6520a8| plan9 LDAR (R4)(R5),R3
|
||||
7c6803a6| plan9 MOVD R3,LR
|
||||
7c6802a6| plan9 MOVD LR,R3
|
||||
7c6803a6| gnu mtlr r3
|
||||
7c6802a6| gnu mflr r3
|
||||
7c6903a6| plan9 MOVD R3,CTR
|
||||
7c6902a6| plan9 MOVD CTR,R3
|
||||
7c6903a6| gnu mtctr r3
|
||||
7c6902a6| gnu mfctr r3
|
||||
7c6c42a6| gnu mftb r3
|
||||
7c6c42a6| plan9 MOVD SPR(268),R3
|
||||
7c8202a6| plan9 MOVD SPR(2),R4
|
||||
7c8202a6| gnu mfspr r4,2
|
||||
41820010| plan9 BEQ 0x130
|
||||
41820010| gnu beq 0x134
|
||||
4086000c| plan9 BNE CR1,0x134
|
||||
4086000c| gnu bne cr1,0x138
|
||||
41880008| plan9 BLT CR2,0x138
|
||||
41880008| gnu blt cr2,0x13c
|
||||
418d0004| plan9 BGT CR3,0x13c
|
||||
418d0004| gnu bgt cr3,0x140
|
||||
e8830008| plan9 MOVD 8(R3),R4
|
||||
7ca4182a| plan9 MOVD (R3)(R4),R5
|
||||
e8830006| plan9 MOVW 4(R3),R4
|
||||
7ca41aaa| plan9 MOVW (R3)(R4),R5
|
||||
80830004| plan9 MOVWZ 4(R3),R4
|
||||
7ca4182e| plan9 MOVWZ (R3)(R4),R5
|
||||
a8830004| plan9 MOVH 4(R3),R4
|
||||
7ca41aae| plan9 MOVH (R3)(R4),R5
|
||||
a0830002| plan9 MOVHZ 2(R3),R4
|
||||
7ca41a2e| plan9 MOVHZ (R3)(R4),R5
|
||||
7ca418ae| plan9 MOVBZ (R3)(R4),R5
|
||||
7ca41c28| plan9 MOVDBR (R3)(R4),R5
|
||||
7ca41c2c| plan9 MOVWBR (R3)(R4),R5
|
||||
7ca41e2c| plan9 MOVHBR (R3)(R4),R5
|
||||
e8830009| plan9 MOVDU 8(R3),R4
|
||||
7ca4186a| plan9 MOVDU (R3)(R4),R5
|
||||
7ca41aea| plan9 MOVWU (R3)(R4),R5
|
||||
84830004| plan9 MOVWZU 4(R3),R4
|
||||
7ca4186e| plan9 MOVWZU (R3)(R4),R5
|
||||
ac830002| plan9 MOVHU 2(R3),R4
|
||||
7ca41aee| plan9 MOVHU (R3)(R4),R5
|
||||
a4830002| plan9 MOVHZU 2(R3),R4
|
||||
7ca41a6e| plan9 MOVHZU (R3)(R4),R5
|
||||
8c830001| plan9 MOVBZU 1(R3),R4
|
||||
7ca418ee| plan9 MOVBZU (R3)(R4),R5
|
||||
f8830008| plan9 MOVD R4,8(R3)
|
||||
7ca4192a| plan9 MOVD R5,(R3)(R4)
|
||||
90830004| plan9 MOVW R4,4(R3)
|
||||
7ca4192e| plan9 MOVW R5,(R3)(R4)
|
||||
b0830002| plan9 MOVH R4,2(R3)
|
||||
7ca41b2e| plan9 MOVH R5,(R3)(R4)
|
||||
98830001| plan9 MOVB R4,1(R3)
|
||||
7ca419ae| plan9 MOVB R5,(R3)(R4)
|
||||
7ca41d28| plan9 MOVDBR R5,(R3)(R4)
|
||||
7ca41d2c| plan9 MOVWBR R5,(R3)(R4)
|
||||
7ca41f2c| plan9 MOVHBR R5,(R3)(R4)
|
||||
f8830009| plan9 MOVDU R4,8(R3)
|
||||
7ca4196a| plan9 MOVDU R5,(R3)(R4)
|
||||
94830004| plan9 MOVWU R4,4(R3)
|
||||
7ca4196e| plan9 MOVWU R5,(R3)(R4)
|
||||
b4830002| plan9 MOVHU R4,2(R3)
|
||||
7ca41b6e| plan9 MOVHU R5,(R3)(R4)
|
||||
9c830001| plan9 MOVBU R4,1(R3)
|
||||
7ca419ee| plan9 MOVBU R5,(R3)(R4)
|
||||
7c232040| plan9 CMPU R3,R4
|
||||
7c032000| plan9 CMPW R3,R4
|
||||
7c032040| plan9 CMPWU R3,R4
|
||||
7ca41a14| plan9 ADD R3,R4,R5
|
||||
7ca41a15| plan9 ADDCC R3,R4,R5
|
||||
7ca41814| plan9 ADDC R3,R4,R5
|
||||
7ca41815| plan9 ADDCCC R3,R4,R5
|
||||
7c851838| plan9 AND R3,R4,R5
|
||||
7c851839| plan9 ANDCC R3,R4,R5
|
||||
7c851878| plan9 ANDN R3,R4,R5
|
||||
7c851879| plan9 ANDNCC R3,R4,R5
|
||||
7c851b78| plan9 OR R3,R4,R5
|
||||
7c851b79| plan9 ORCC R3,R4,R5
|
||||
7c851b38| plan9 ORN R3,R4,R5
|
||||
7c851b39| plan9 ORNCC R3,R4,R5
|
||||
7c851a78| plan9 XOR R3,R4,R5
|
||||
7c851a79| plan9 XORCC R3,R4,R5
|
||||
7c851bb8| plan9 NAND R3,R4,R5
|
||||
7c851bb9| plan9 NANDCC R3,R4,R5
|
||||
7c851a38| plan9 EQV R3,R4,R5
|
||||
7c851a39| plan9 EQVCC R3,R4,R5
|
||||
7c8300d0| plan9 NEG R3,R4
|
||||
7c8300d1| plan9 NEGCC R3,R4
|
||||
7c8518f8| plan9 NOR R3,R4,R5
|
||||
7c8518f9| plan9 NORCC R3,R4,R5
|
||||
7ca32050| plan9 SUB R3,R4,R5
|
||||
7ca32051| plan9 SUBCC R3,R4,R5
|
||||
7ca32010| plan9 SUBC R3,R4,R5
|
||||
7ca32011| plan9 SUBCCC R3,R4,R5
|
||||
7ca419d6| plan9 MULLW R3,R4,R5
|
||||
7ca419d7| plan9 MULLWCC R3,R4,R5
|
||||
7ca41896| plan9 MULHW R3,R4,R5
|
||||
7ca41816| plan9 MULHWU R3,R4,R5
|
||||
7ca421d2| plan9 MULLD R4,R4,R5
|
||||
1c63000a| plan9 MULLD R3,$10,R3
|
||||
7ca419d3| plan9 MULLDCC R3,R4,R5
|
||||
7ca41892| plan9 MULHD R3,R4,R5
|
||||
7ca41893| plan9 MULHDCC R3,R4,R5
|
||||
7ca41dd6| plan9 MULLWV R3,R4,R5
|
||||
7ca41dd7| plan9 MULLWVCC R3,R4,R5
|
||||
7ca41817| plan9 MULHWUCC R3,R4,R5
|
||||
7ca41dd2| plan9 MULLDV R3,R4,R5
|
||||
7ca41dd3| plan9 MULLDVCC R3,R4,R5
|
||||
7ca41bd2| plan9 DIVD R3,R4,R5
|
||||
7ca41bd3| plan9 DIVDCC R3,R4,R5
|
||||
7ca41b92| plan9 DIVDU R3,R4,R5
|
||||
7ca41fd2| plan9 DIVDV R3,R4,R5
|
||||
7ca41b93| plan9 DIVDUCC R3,R4,R5
|
||||
7ca41fd3| plan9 DIVDVCC R3,R4,R5
|
||||
7ca41f92| plan9 DIVDUV R3,R4,R5
|
||||
7ca41f93| plan9 DIVDUVCC R3,R4,R5
|
||||
7ca41b52| plan9 DIVDE R3,R4,R5
|
||||
7ca41b53| plan9 DIVDECC R3,R4,R5
|
||||
7ca41b12| plan9 DIVDEU R3,R4,R5
|
||||
7ca41b13| plan9 DIVDEUCC R3,R4,R5
|
||||
7ca41a12| plan9 MODUD R3,R4,R5
|
||||
7ca41a16| plan9 MODUW R3,R4,R5
|
||||
7ca41e12| plan9 MODSD R3,R4,R5
|
||||
7ca41e16| plan9 MODSW R3,R4,R5
|
||||
7c851830| plan9 SLW R3,R4,R5
|
||||
7c851836| plan9 SLD R3,R4,R5
|
||||
7c851c30| plan9 SRW R3,R4,R5
|
||||
7c851e30| plan9 SRAW R3,R4,R5
|
||||
7c851c36| plan9 SRD R3,R4,R5
|
||||
7c851e34| plan9 SRAD R3,R4,R5
|
||||
7c631ef4| plan9 EXTSWSLI R3,$3,R3
|
||||
7c6400f4| plan9 POPCNTB R3,R4
|
||||
7c6402f4| plan9 POPCNTW R3,R4
|
||||
7c6403f4| plan9 POPCNTD R3,R4
|
||||
7c23270d| plan9 PASTECC R3,R4,$1
|
||||
7c23260c| plan9 COPY R3,R4
|
||||
7ca01868| plan9 LBAR (R3),R5
|
||||
7ca018e8| plan9 LHAR (R3),R5
|
||||
7ca01828| plan9 LWAR (R3),R5
|
||||
7ca018a8| plan9 LDAR (R3),R5
|
||||
7c65256d| plan9 STBCCC R3,(R4)(R5)
|
||||
7c65212d| plan9 STWCCC R3,(R4)(R5)
|
||||
7c6521ad| plan9 STDCCC R3,(R4)(R5)
|
||||
7c0004ac| plan9 HWSYNC
|
||||
4c00012c| plan9 ISYNC
|
||||
7c2004ac| plan9 LWSYNC
|
||||
7c04186c| plan9 DCBST (R3)(R4)
|
||||
7c041fec| plan9 DCBZ (R3)(R4)
|
||||
7c041a2c| plan9 DCBT (R3)(R4)
|
||||
7c041fac| plan9 ICBI (R3)(R4)
|
||||
c8230008| plan9 FMOVD 8(R3),F1
|
||||
7c241cae| plan9 FMOVD (R3)(R4),F1
|
||||
cc230008| plan9 FMOVDU 8(R3),F1
|
||||
7c241cee| plan9 FMOVDU (R3)(R4),F1
|
||||
c0230004| plan9 FMOVS 4(R3),F1
|
||||
7c241c2e| plan9 FMOVS (R3)(R4),F1
|
||||
c4230004| plan9 FMOVSU 4(R3),F1
|
||||
7c241c6e| plan9 FMOVSU (R3)(R4),F1
|
||||
d8230008| plan9 FMOVD F1,8(R3)
|
||||
7c241dae| plan9 FMOVD F1,(R3)(R4)
|
||||
dc230008| plan9 FMOVDU F1,8(R3)
|
||||
7c241dee| plan9 FMOVDU F1,(R3)(R4)
|
||||
d0230004| plan9 FMOVS F1,4(R3)
|
||||
7c241d2e| plan9 FMOVS F1,(R3)(R4)
|
||||
d4230004| plan9 FMOVSU F1,4(R3)
|
||||
7c241d6e| plan9 FMOVSU F1,(R3)(R4)
|
||||
fc62082a| plan9 FADD F1,F2,F3
|
||||
fc62082b| plan9 FADDCC F1,F2,F3
|
||||
ec62082a| plan9 FADDS F1,F2,F3
|
||||
ec62082b| plan9 FADDSCC F1,F2,F3
|
||||
fc620828| plan9 FSUB F1,F2,F3
|
||||
fc620829| plan9 FSUBCC F1,F2,F3
|
||||
ec620828| plan9 FSUBS F1,F2,F3
|
||||
fc620829| plan9 FSUBCC F1,F2,F3
|
||||
fc620072| plan9 FMUL F1,F2,F3
|
||||
fc620073| plan9 FMULCC F1,F2,F3
|
||||
ec620072| plan9 FMULS F1,F2,F3
|
||||
ec620073| plan9 FMULSCC F1,F2,F3
|
||||
fc620824| plan9 FDIV F1,F2,F3
|
||||
fc620825| plan9 FDIVCC F1,F2,F3
|
||||
ec620824| plan9 FDIVS F1,F2,F3
|
||||
ec620825| plan9 FDIVSCC F1,F2,F3
|
||||
fc8110fa| plan9 FMADD F1,F2,F3,F4
|
||||
fc8110fb| plan9 FMADDCC F1,F2,F3,F4
|
||||
ec8110fa| plan9 FMADDS F1,F2,F3,F4
|
||||
ec8110fb| plan9 FMADDSCC F1,F2,F3,F4
|
||||
fc8110f8| plan9 FMSUB F1,F2,F3,F4
|
||||
fc8110f9| plan9 FMSUBCC F1,F2,F3,F4
|
||||
ec8110f8| plan9 FMSUBS F1,F2,F3,F4
|
||||
ec8110f9| plan9 FMSUBSCC F1,F2,F3,F4
|
||||
fc8110fe| plan9 FNMADD F1,F2,F3,F4
|
||||
fc8110ff| plan9 FNMADDCC F1,F2,F3,F4
|
||||
ec8110fe| plan9 FNMADDS F1,F2,F3,F4
|
||||
ec8110ff| plan9 FNMADDSCC F1,F2,F3,F4
|
||||
fc8110fc| plan9 FNMSUB F1,F2,F3,F4
|
||||
fc8110fd| plan9 FNMSUBCC F1,F2,F3,F4
|
||||
ec8110fc| plan9 FNMSUBS F1,F2,F3,F4
|
||||
ec8110fd| plan9 FNMSUBSCC F1,F2,F3,F4
|
||||
fc8110ee| plan9 FSEL F1,F2,F3,F4
|
||||
fc8110ef| plan9 FSELCC F1,F2,F3,F4
|
||||
fc400a10| plan9 FABS F1,F2
|
||||
fc400a11| plan9 FABSCC F1,F2
|
||||
fc400850| plan9 FNEG F1,F2
|
||||
fc400a11| plan9 FABSCC F1,F2
|
||||
fc400818| plan9 FRSP F1,F2
|
||||
fc400819| plan9 FRSPCC F1,F2
|
||||
fc40081c| plan9 FCTIW F1,F2
|
||||
fc40081d| plan9 FCTIWCC F1,F2
|
||||
fc40081e| plan9 FCTIWZ F1,F2
|
||||
fc40081f| plan9 FCTIWZCC F1,F2
|
||||
fc400e5c| plan9 FCTID F1,F2
|
||||
fc400e5d| plan9 FCTIDCC F1,F2
|
||||
fc400e5e| plan9 FCTIDZ F1,F2
|
||||
fc400e5f| plan9 FCTIDZCC F1,F2
|
||||
fc400e9c| plan9 FCFID F1,F2
|
||||
fc400e9d| plan9 FCFIDCC F1,F2
|
||||
fc400f9c| plan9 FCFIDU F1,F2
|
||||
fc400f9d| plan9 FCFIDUCC F1,F2
|
||||
ec400e9c| plan9 FCFIDS F1,F2
|
||||
ec400e9d| plan9 FCFIDSCC F1,F2
|
||||
ec400830| plan9 FRES F1,F2
|
||||
ec400831| plan9 FRESCC F1,F2
|
||||
fc400bd0| plan9 FRIM F1,F2
|
||||
fc400bd1| plan9 FRIMCC F1,F2
|
||||
fc400b90| plan9 FRIP F1,F2
|
||||
fc400b91| plan9 FRIPCC F1,F2
|
||||
fc400b50| plan9 FRIZ F1,F2
|
||||
fc400b51| plan9 FRIZCC F1,F2
|
||||
fc400b10| plan9 FRIN F1,F2
|
||||
fc400b11| plan9 FRINCC F1,F2
|
||||
fc400834| plan9 FRSQRTE F1,F2
|
||||
fc400835| plan9 FRSQRTECC F1,F2
|
||||
fc40082c| plan9 FSQRT F1,F2
|
||||
fc40082d| plan9 FSQRTCC F1,F2
|
||||
ec40082c| plan9 FSQRTS F1,F2
|
||||
ec40082d| plan9 FSQRTSCC F1,F2
|
||||
fc011040| plan9 FCMPO F1,F2
|
||||
fc011000| plan9 FCMPU F1,F2
|
||||
7c2418ce| plan9 LVX (R3)(R4),V1
|
||||
7c241ace| plan9 LVXL (R3)(R4),V1
|
||||
7c24180c| plan9 LVSL (R3)(R4),V1
|
||||
7c24184c| plan9 LVSR (R3)(R4),V1
|
||||
7c24180e| plan9 LVEBX (R3)(R4),V1
|
||||
7c24184e| plan9 LVEHX (R3)(R4),V1
|
||||
7c24188e| plan9 LVEWX (R3)(R4),V1
|
||||
7c2419ce| plan9 STVX V1,(R3)(R4)
|
||||
7c241bce| plan9 STVXL V1,(R3)(R4)
|
||||
7c24190e| plan9 STVEBX V1,(R3)(R4)
|
||||
7c24194e| plan9 STVEHX V1,(R3)(R4)
|
||||
7c24198e| plan9 STVEWX V1,(R3)(R4)
|
||||
10611404| plan9 VAND V1,V2,V3
|
||||
10611444| plan9 VANDC V1,V2,V3
|
||||
10611584| plan9 VNAND V1,V2,V3
|
||||
10611484| plan9 VOR V1,V2,V3
|
||||
10611544| plan9 VORC V1,V2,V3
|
||||
106114c4| plan9 VXOR V1,V2,V3
|
||||
10611504| plan9 VNOR V1,V2,V3
|
||||
10611684| plan9 VEQV V1,V2,V3
|
||||
10611000| plan9 VADDUBM V1,V2,V3
|
||||
10611040| plan9 VADDUHM V1,V2,V3
|
||||
10611080| plan9 VADDUWM V1,V2,V3
|
||||
106110c0| plan9 VADDUDM V1,V2,V3
|
||||
10611100| plan9 VADDUQM V1,V2,V3
|
||||
10611140| plan9 VADDCUQ V1,V2,V3
|
||||
10611180| plan9 VADDCUW V1,V2,V3
|
||||
10611200| plan9 VADDUBS V1,V2,V3
|
||||
10611240| plan9 VADDUHS V1,V2,V3
|
||||
10611280| plan9 VADDUWS V1,V2,V3
|
||||
10611400| plan9 VSUBUBM V1,V2,V3
|
||||
10611440| plan9 VSUBUHM V1,V2,V3
|
||||
10611480| plan9 VSUBUWM V1,V2,V3
|
||||
106114c0| plan9 VSUBUDM V1,V2,V3
|
||||
10611500| plan9 VSUBUQM V1,V2,V3
|
||||
10611540| plan9 VSUBCUQ V1,V2,V3
|
||||
10611580| plan9 VSUBCUW V1,V2,V3
|
||||
10611600| plan9 VSUBUBS V1,V2,V3
|
||||
10611640| plan9 VSUBUHS V1,V2,V3
|
||||
10611680| plan9 VSUBUWS V1,V2,V3
|
||||
10611700| plan9 VSUBSBS V1,V2,V3
|
||||
10611740| plan9 VSUBSHS V1,V2,V3
|
||||
10611780| plan9 VSUBSWS V1,V2,V3
|
||||
108110fe| plan9 VSUBEUQM V1,V2,V3,V4
|
||||
108110ff| plan9 VSUBECUQ V1,V2,V3,V4
|
||||
10611308| plan9 VMULESB V1,V2,V3
|
||||
10611108| plan9 VMULOSB V1,V2,V3
|
||||
10611208| plan9 VMULEUB V1,V2,V3
|
||||
10611008| plan9 VMULOUB V1,V2,V3
|
||||
10611348| plan9 VMULESH V1,V2,V3
|
||||
10611148| plan9 VMULOSH V1,V2,V3
|
||||
10611248| plan9 VMULEUH V1,V2,V3
|
||||
10611048| plan9 VMULOUH V1,V2,V3
|
||||
10611348| plan9 VMULESH V1,V2,V3
|
||||
10611188| plan9 VMULOSW V1,V2,V3
|
||||
10611288| plan9 VMULEUW V1,V2,V3
|
||||
10611088| plan9 VMULOUW V1,V2,V3
|
||||
10611089| plan9 VMULUWM V1,V2,V3
|
||||
10611408| plan9 VPMSUMB V1,V2,V3
|
||||
10611448| plan9 VPMSUMH V1,V2,V3
|
||||
10611488| plan9 VPMSUMW V1,V2,V3
|
||||
106114c8| plan9 VPMSUMD V1,V2,V3
|
||||
108110e3| plan9 VMSUMUDM V1,V2,V3,V4
|
||||
10611004| plan9 VRLB V1,V2,V3
|
||||
10611044| plan9 VRLH V1,V2,V3
|
||||
10611084| plan9 VRLW V1,V2,V3
|
||||
106110c4| plan9 VRLD V1,V2,V3
|
||||
10611104| plan9 VSLB V1,V2,V3
|
||||
10611144| plan9 VSLH V1,V2,V3
|
||||
10611184| plan9 VSLW V1,V2,V3
|
||||
106111c4| plan9 VSL V1,V2,V3
|
||||
1061140c| plan9 VSLO V1,V2,V3
|
||||
10611204| plan9 VSRB V1,V2,V3
|
||||
10611244| plan9 VSRH V1,V2,V3
|
||||
10611284| plan9 VSRW V1,V2,V3
|
||||
106112c4| plan9 VSR V1,V2,V3
|
||||
1061144c| plan9 VSRO V1,V2,V3
|
||||
106115c4| plan9 VSLD V1,V2,V3
|
||||
10611304| plan9 VSRAB V1,V2,V3
|
||||
10611344| plan9 VSRAH V1,V2,V3
|
||||
10611384| plan9 VSRAW V1,V2,V3
|
||||
106113c4| plan9 VSRAD V1,V2,V3
|
||||
10400f02| plan9 VCLZB V1,V2
|
||||
10400f42| plan9 VCLZH V1,V2
|
||||
10400f82| plan9 VCLZW V1,V2
|
||||
10400fc2| plan9 VCLZD V1,V2
|
||||
10400f03| plan9 VPOPCNTB V1,V2
|
||||
10400f43| plan9 VPOPCNTH V1,V2
|
||||
10400f83| plan9 VPOPCNTW V1,V2
|
||||
10400fc3| plan9 VPOPCNTD V1,V2
|
||||
10611006| plan9 VCMPEQUB V1,V2,V3
|
||||
10611406| plan9 VCMPEQUBCC V1,V2,V3
|
||||
10611046| plan9 VCMPEQUH V1,V2,V3
|
||||
10611446| plan9 VCMPEQUHCC V1,V2,V3
|
||||
10611086| plan9 VCMPEQUW V1,V2,V3
|
||||
10611486| plan9 VCMPEQUWCC V1,V2,V3
|
||||
106110c7| plan9 VCMPEQUD V1,V2,V3
|
||||
106114c7| plan9 VCMPEQUDCC V1,V2,V3
|
||||
10611206| plan9 VCMPGTUB V1,V2,V3
|
||||
10611606| plan9 VCMPGTUBCC V1,V2,V3
|
||||
10611246| plan9 VCMPGTUH V1,V2,V3
|
||||
10611646| plan9 VCMPGTUHCC V1,V2,V3
|
||||
10611286| plan9 VCMPGTUW V1,V2,V3
|
||||
10611686| plan9 VCMPGTUWCC V1,V2,V3
|
||||
106112c7| plan9 VCMPGTUD V1,V2,V3
|
||||
106116c7| plan9 VCMPGTUDCC V1,V2,V3
|
||||
10611306| plan9 VCMPGTSB V1,V2,V3
|
||||
10611706| plan9 VCMPGTSBCC V1,V2,V3
|
||||
10611346| plan9 VCMPGTSH V1,V2,V3
|
||||
10611746| plan9 VCMPGTSHCC V1,V2,V3
|
||||
10611386| plan9 VCMPGTSW V1,V2,V3
|
||||
10611786| plan9 VCMPGTSWCC V1,V2,V3
|
||||
106113c7| plan9 VCMPGTSD V1,V2,V3
|
||||
106117c7| plan9 VCMPGTSDCC V1,V2,V3
|
||||
10611107| plan9 VCMPNEZB V1,V2,V3
|
||||
10611507| plan9 VCMPNEZBCC V1,V2,V3
|
||||
10611007| plan9 VCMPNEB V1,V2,V3
|
||||
10611407| plan9 VCMPNEBCC V1,V2,V3
|
||||
10611047| plan9 VCMPNEH V1,V2,V3
|
||||
10611447| plan9 VCMPNEHCC V1,V2,V3
|
||||
10611087| plan9 VCMPNEW V1,V2,V3
|
||||
10611487| plan9 VCMPNEWCC V1,V2,V3
|
||||
108110eb| plan9 VPERM V1,V2,V3,V4
|
||||
108110fb| plan9 VPERMR V1,V2,V3,V4
|
||||
108110ed| plan9 VPERMXOR V1,V2,V3,V4
|
||||
1061154c| plan9 VBPERMQ V1,V2,V3
|
||||
106115cc| plan9 VBPERMD V1,V2,V3
|
||||
108110ea| plan9 VSEL V1,V2,V3,V4
|
||||
10611508| plan9 VCIPHER V1,V2,V3
|
||||
10611509| plan9 VCIPHERLAST V1,V2,V3
|
||||
10611548| plan9 VNCIPHER V1,V2,V3
|
||||
10611549| plan9 VNCIPHERLAST V1,V2,V3
|
||||
104105c8| plan9 VSBOX V1,V2
|
||||
7c241e98| plan9 LXVD2X (R3)(R4),VS1
|
||||
7c241e18| plan9 LXVW4X (R3)(R4),VS1
|
||||
7c241e58| plan9 LXVH8X (R3)(R4),VS1
|
||||
7c241ed8| plan9 LXVB16X (R3)(R4),VS1
|
||||
f4230011| plan9 LXV 16(R3),VS1
|
||||
7c23221a| plan9 LXVL R3,R4,VS1
|
||||
7c23225a| plan9 LXVLL R3,R4,VS1
|
||||
7c241a18| plan9 LXVX (R3)(R4),VS1
|
||||
7c241c98| plan9 LXSDX (R3)(R4),VS1
|
||||
7c241f98| plan9 STXVD2X VS1,(R3)(R4)
|
||||
f4230015| plan9 STXV VS1,16(R3)
|
||||
7c23231a| plan9 STXVL VS1,R3,R4
|
||||
7c23235a| plan9 STXVLL VS1,R3,R4
|
||||
7c241b18| plan9 STXVX VS1,(R3)(R4)
|
||||
7c241d98| plan9 STXSDX VS1,(R3)(R4)
|
||||
7c241898| plan9 LXSIWAX (R3)(R4),VS1
|
||||
7c241918| plan9 STXSIWX VS1,(R3)(R4)
|
||||
7c230066| plan9 MFVSRD VS1,R3
|
||||
7c230166| plan9 MTVSRD R3,VS1
|
||||
f0611410| plan9 XXLAND VS1,VS2,VS3
|
||||
f0611490| plan9 XXLOR VS1,VS2,VS3
|
||||
f0611550| plan9 XXLORC VS1,VS2,VS3
|
||||
f06114d0| plan9 XXLXOR VS1,VS2,VS3
|
||||
f08110f0| plan9 XXSEL VS1,VS2,VS3,VS4
|
||||
f0570f6c| plan9 XXBRD VS1,VS2
|
||||
f04f0f6c| plan9 XXBRW VS1,VS2
|
||||
f0470f6c| plan9 XXBRH VS1,VS2
|
||||
f0611090| plan9 XXMRGHW VS1,VS2,VS3
|
||||
f0410a90| plan9 XXSPLTW VS1,$1,VS2
|
||||
f06110d0| plan9 XXPERM VS1,VS2,VS3
|
||||
f0611110| plan9 XXSLDWI VS1,VS2,$1,VS3
|
||||
f0400c24| plan9 XSCVDPSP VS1,VS2
|
||||
f0400e24| plan9 XVCVDPSP VS1,VS2
|
||||
f0400de0| plan9 XSCVSXDDP VS1,VS2
|
||||
f0400f60| plan9 XVCVDPSXDS VS1,VS2
|
||||
f0400fe0| plan9 XVCVSXDDP VS1,VS2
|
||||
7c6803a6| plan9 MOVD R3,LR
|
||||
7c6903a6| plan9 MOVD R3,CTR
|
||||
7c6802a6| plan9 MOVD LR,R3
|
||||
7c6902a6| plan9 MOVD CTR,R3
|
||||
4c8c0000| plan9 MOVFL CR3,CR1
|
||||
48100001| plan9 CALL foo(SB)
|
||||
48100009| plan9 CALL foo+8(SB)
|
||||
4810000d| plan9 CALL 0x10000c
|
||||
7c6803a6| gnu mtlr r3
|
||||
7c6802a6| gnu mflr r3
|
||||
7c6903a6| gnu mtctr r3
|
||||
7c6902a6| gnu mfctr r3
|
||||
7c6c42a6| gnu mftb r3
|
||||
7c8202a6| gnu mfspr r4,2
|
||||
e8830008| gnu ld r4,8(r3)
|
||||
7ca4182a| gnu ldx r5,r4,r3
|
||||
e8830006| gnu lwa r4,4(r3)
|
||||
7ca41aaa| gnu lwax r5,r4,r3
|
||||
80830004| gnu lwz r4,4(r3)
|
||||
7ca4182e| gnu lwzx r5,r4,r3
|
||||
a8830004| gnu lha r4,4(r3)
|
||||
7ca41aae| gnu lhax r5,r4,r3
|
||||
a0830002| gnu lhz r4,2(r3)
|
||||
7ca41a2e| gnu lhzx r5,r4,r3
|
||||
7ca418ae| gnu lbzx r5,r4,r3
|
||||
7ca41c28| gnu ldbrx r5,r4,r3
|
||||
7ca41c2c| gnu lwbrx r5,r4,r3
|
||||
7ca41e2c| gnu lhbrx r5,r4,r3
|
||||
e8830009| gnu ldu r4,8(r3)
|
||||
7ca4186a| gnu ldux r5,r4,r3
|
||||
7ca41aea| gnu lwaux r5,r4,r3
|
||||
84830004| gnu lwzu r4,4(r3)
|
||||
7ca4186e| gnu lwzux r5,r4,r3
|
||||
ac830002| gnu lhau r4,2(r3)
|
||||
7ca41aee| gnu lhaux r5,r4,r3
|
||||
a4830002| gnu lhzu r4,2(r3)
|
||||
7ca41a6e| gnu lhzux r5,r4,r3
|
||||
8c830001| gnu lbzu r4,1(r3)
|
||||
7ca418ee| gnu lbzux r5,r4,r3
|
||||
f8830008| gnu std r4,8(r3)
|
||||
7ca4192a| gnu stdx r5,r4,r3
|
||||
90830004| gnu stw r4,4(r3)
|
||||
7ca4192e| gnu stwx r5,r4,r3
|
||||
b0830002| gnu sth r4,2(r3)
|
||||
7ca41b2e| gnu sthx r5,r4,r3
|
||||
98830001| gnu stb r4,1(r3)
|
||||
7ca419ae| gnu stbx r5,r4,r3
|
||||
7ca41d28| gnu stdbrx r5,r4,r3
|
||||
7ca41d2c| gnu stwbrx r5,r4,r3
|
||||
7ca41f2c| gnu sthbrx r5,r4,r3
|
||||
f8830009| gnu stdu r4,8(r3)
|
||||
7ca4196a| gnu stdux r5,r4,r3
|
||||
94830004| gnu stwu r4,4(r3)
|
||||
7ca4196e| gnu stwux r5,r4,r3
|
||||
b4830002| gnu sthu r4,2(r3)
|
||||
7ca41b6e| gnu sthux r5,r4,r3
|
||||
9c830001| gnu stbu r4,1(r3)
|
||||
7ca419ee| gnu stbux r5,r4,r3
|
||||
7c232040| gnu cmpld r3,r4
|
||||
7c032000| gnu cmpw r3,r4
|
||||
7c032040| gnu cmplw r3,r4
|
||||
7ca41a14| gnu add r5,r4,r3
|
||||
7ca41814| gnu addc r5,r4,r3
|
||||
7ca41815| gnu addc. r5,r4,r3
|
||||
7c851838| gnu and r5,r4,r3
|
||||
7c851878| gnu andc r5,r4,r3
|
||||
7c851839| gnu and. r5,r4,r3
|
||||
7c851b78| gnu or r5,r4,r3
|
||||
7c851b38| gnu orc r5,r4,r3
|
||||
7c851b79| gnu or. r5,r4,r3
|
||||
7c851a78| gnu xor r5,r4,r3
|
||||
7c851a79| gnu xor. r5,r4,r3
|
||||
7c851bb8| gnu nand r5,r4,r3
|
||||
7c851bb9| gnu nand. r5,r4,r3
|
||||
7c851a38| gnu eqv r5,r4,r3
|
||||
7c851a39| gnu eqv. r5,r4,r3
|
||||
7c8518f8| gnu nor r5,r4,r3
|
||||
7c8518f9| gnu nor. r5,r4,r3
|
||||
7ca32050| gnu subf r5,r3,r4
|
||||
7ca32010| gnu subfc r5,r3,r4
|
||||
7ca419d6| gnu mullw r5,r4,r3
|
||||
7ca419d7| gnu mullw. r5,r4,r3
|
||||
7ca41896| gnu mulhw r5,r4,r3
|
||||
7ca41816| gnu mulhwu r5,r4,r3
|
||||
7ca421d2| gnu mulld r5,r4,r4
|
||||
7ca419d3| gnu mulld. r5,r4,r3
|
||||
7ca41892| gnu mulhd r5,r4,r3
|
||||
7ca41893| gnu mulhd. r5,r4,r3
|
||||
7ca41dd6| gnu mullwo r5,r4,r3
|
||||
7ca41dd7| gnu mullwo. r5,r4,r3
|
||||
7ca41817| gnu mulhwu. r5,r4,r3
|
||||
7ca41dd2| gnu mulldo r5,r4,r3
|
||||
7ca41dd3| gnu mulldo. r5,r4,r3
|
||||
7ca41bd2| gnu divd r5,r4,r3
|
||||
7ca41bd3| gnu divd. r5,r4,r3
|
||||
7ca41b92| gnu divdu r5,r4,r3
|
||||
7ca41fd2| gnu divdo r5,r4,r3
|
||||
7ca41b93| gnu divdu. r5,r4,r3
|
||||
7ca41fd3| gnu divdo. r5,r4,r3
|
||||
7ca41f92| gnu divduo r5,r4,r3
|
||||
7ca41f93| gnu divduo. r5,r4,r3
|
||||
7ca41b52| gnu divde r5,r4,r3
|
||||
7ca41b53| gnu divde. r5,r4,r3
|
||||
7ca41b12| gnu divdeu r5,r4,r3
|
||||
7ca41b13| gnu divdeu. r5,r4,r3
|
||||
7ca41a12| gnu modud r5,r4,r3
|
||||
7ca41a16| gnu moduw r5,r4,r3
|
||||
7ca41e12| gnu modsd r5,r4,r3
|
||||
7ca41e16| gnu modsw r5,r4,r3
|
||||
7c851830| gnu slw r5,r4,r3
|
||||
7c851836| gnu sld r5,r4,r3
|
||||
7c851c30| gnu srw r5,r4,r3
|
||||
7c851e30| gnu sraw r5,r4,r3
|
||||
7c851c36| gnu srd r5,r4,r3
|
||||
7c851e34| gnu srad r5,r4,r3
|
||||
7c6400f4| gnu popcntb r4,r3
|
||||
7c6402f4| gnu popcntw r4,r3
|
||||
7c6403f4| gnu popcntd r4,r3
|
||||
7c23270d| gnu paste. r3,r4
|
||||
7c23260c| gnu copy r3,r4
|
||||
7ca01868| gnu lbarx r5,0,r3
|
||||
7ca018e8| gnu lharx r5,0,r3
|
||||
7ca01828| gnu lwarx r5,0,r3
|
||||
7ca018a8| gnu ldarx r5,0,r3
|
||||
7c65256d| gnu stbcx. r3,r5,r4
|
||||
7c65212d| gnu stwcx. r3,r5,r4
|
||||
7c6521ad| gnu stdcx. r3,r5,r4
|
||||
4c00012c| gnu isync
|
||||
7c0004ac| gnu hwsync
|
||||
7c2004ac| gnu lwsync
|
||||
7c04186c| gnu dcbst r4,r3
|
||||
7c041fec| gnu dcbz r4,r3
|
||||
7c041a2c| gnu dcbt r4,r3,0
|
||||
7c041fac| gnu icbi r4,r3
|
||||
c8230008| gnu lfd f1,8(r3)
|
||||
7c241cae| gnu lfdx f1,r4,r3
|
||||
cc230008| gnu lfdu f1,8(r3)
|
||||
7c241cee| gnu lfdux f1,r4,r3
|
||||
c0230004| gnu lfs f1,4(r3)
|
||||
7c241c2e| gnu lfsx f1,r4,r3
|
||||
c4230004| gnu lfsu f1,4(r3)
|
||||
7c241c6e| gnu lfsux f1,r4,r3
|
||||
d8230008| gnu stfd f1,8(r3)
|
||||
7c241dae| gnu stfdx f1,r4,r3
|
||||
dc230008| gnu stfdu f1,8(r3)
|
||||
7c241dee| gnu stfdux f1,r4,r3
|
||||
d0230004| gnu stfs f1,4(r3)
|
||||
7c241d2e| gnu stfsx f1,r4,r3
|
||||
d4230004| gnu stfsu f1,4(r3)
|
||||
7c241d6e| gnu stfsux f1,r4,r3
|
||||
fc62082a| gnu fadd f3,f2,f1
|
||||
fc62082b| gnu fadd. f3,f2,f1
|
||||
ec62082a| gnu fadds f3,f2,f1
|
||||
ec62082b| gnu fadds. f3,f2,f1
|
||||
fc620828| gnu fsub f3,f2,f1
|
||||
fc620829| gnu fsub. f3,f2,f1
|
||||
ec620828| gnu fsubs f3,f2,f1
|
||||
fc620829| gnu fsub. f3,f2,f1
|
||||
fc620072| gnu fmul f3,f2,f1
|
||||
fc620073| gnu fmul. f3,f2,f1
|
||||
ec620072| gnu fmuls f3,f2,f1
|
||||
ec620073| gnu fmuls. f3,f2,f1
|
||||
fc620824| gnu fdiv f3,f2,f1
|
||||
fc620825| gnu fdiv. f3,f2,f1
|
||||
ec620824| gnu fdivs f3,f2,f1
|
||||
ec620825| gnu fdivs. f3,f2,f1
|
||||
fc8110fa| gnu fmadd f4,f1,f3,f2
|
||||
fc8110fb| gnu fmadd. f4,f1,f3,f2
|
||||
ec8110fa| gnu fmadds f4,f1,f3,f2
|
||||
ec8110fb| gnu fmadds. f4,f1,f3,f2
|
||||
fc8110f8| gnu fmsub f4,f1,f3,f2
|
||||
fc8110f9| gnu fmsub. f4,f1,f3,f2
|
||||
ec8110f8| gnu fmsubs f4,f1,f3,f2
|
||||
ec8110f9| gnu fmsubs. f4,f1,f3,f2
|
||||
fc8110fe| gnu fnmadd f4,f1,f3,f2
|
||||
fc8110ff| gnu fnmadd. f4,f1,f3,f2
|
||||
ec8110fe| gnu fnmadds f4,f1,f3,f2
|
||||
ec8110ff| gnu fnmadds. f4,f1,f3,f2
|
||||
fc8110fc| gnu fnmsub f4,f1,f3,f2
|
||||
fc8110fd| gnu fnmsub. f4,f1,f3,f2
|
||||
ec8110fc| gnu fnmsubs f4,f1,f3,f2
|
||||
ec8110fd| gnu fnmsubs. f4,f1,f3,f2
|
||||
fc8110ee| gnu fsel f4,f1,f3,f2
|
||||
fc8110ef| gnu fsel. f4,f1,f3,f2
|
||||
fc400a10| gnu fabs f2,f1
|
||||
fc400a11| gnu fabs. f2,f1
|
||||
fc400850| gnu fneg f2,f1
|
||||
fc400a11| gnu fabs. f2,f1
|
||||
fc400818| gnu frsp f2,f1
|
||||
fc400819| gnu frsp. f2,f1
|
||||
fc40081c| gnu fctiw f2,f1
|
||||
fc40081d| gnu fctiw. f2,f1
|
||||
fc40081e| gnu fctiwz f2,f1
|
||||
fc40081f| gnu fctiwz. f2,f1
|
||||
fc400e5c| gnu fctid f2,f1
|
||||
fc400e5d| gnu fctid. f2,f1
|
||||
fc400e5e| gnu fctidz f2,f1
|
||||
fc400e5f| gnu fctidz. f2,f1
|
||||
fc400e9c| gnu fcfid f2,f1
|
||||
fc400e9d| gnu fcfid. f2,f1
|
||||
fc400f9c| gnu fcfidu f2,f1
|
||||
fc400f9d| gnu fcfidu. f2,f1
|
||||
ec400e9c| gnu fcfids f2,f1
|
||||
ec400e9d| gnu fcfids. f2,f1
|
||||
ec400830| gnu fres f2,f1
|
||||
ec400831| gnu fres. f2,f1
|
||||
fc400bd0| gnu frim f2,f1
|
||||
fc400bd1| gnu frim. f2,f1
|
||||
fc400b90| gnu frip f2,f1
|
||||
fc400b91| gnu frip. f2,f1
|
||||
fc400b50| gnu friz f2,f1
|
||||
fc400b51| gnu friz. f2,f1
|
||||
fc400b10| gnu frin f2,f1
|
||||
fc400b11| gnu frin. f2,f1
|
||||
fc400834| gnu frsqrte f2,f1
|
||||
fc400835| gnu frsqrte. f2,f1
|
||||
fc40082c| gnu fsqrt f2,f1
|
||||
fc40082d| gnu fsqrt. f2,f1
|
||||
ec40082c| gnu fsqrts f2,f1
|
||||
ec40082d| gnu fsqrts. f2,f1
|
||||
fc011040| gnu fcmpo cr0,f1,f2
|
||||
fc011000| gnu fcmpu cr0,f1,f2
|
||||
7c2418ce| gnu lvx v1,r4,r3
|
||||
7c241ace| gnu lvxl v1,r4,r3
|
||||
7c24180c| gnu lvsl v1,r4,r3
|
||||
7c24184c| gnu lvsr v1,r4,r3
|
||||
7c24180e| gnu lvebx v1,r4,r3
|
||||
7c24184e| gnu lvehx v1,r4,r3
|
||||
7c24188e| gnu lvewx v1,r4,r3
|
||||
7c2419ce| gnu stvx v1,r4,r3
|
||||
7c241bce| gnu stvxl v1,r4,r3
|
||||
7c24190e| gnu stvebx v1,r4,r3
|
||||
7c24194e| gnu stvehx v1,r4,r3
|
||||
7c24198e| gnu stvewx v1,r4,r3
|
||||
10611404| gnu vand v3,v1,v2
|
||||
10611444| gnu vandc v3,v1,v2
|
||||
10611584| gnu vnand v3,v1,v2
|
||||
10611484| gnu vor v3,v1,v2
|
||||
10611544| gnu vorc v3,v1,v2
|
||||
106114c4| gnu vxor v3,v1,v2
|
||||
10611504| gnu vnor v3,v1,v2
|
||||
10611684| gnu veqv v3,v1,v2
|
||||
10611000| gnu vaddubm v3,v1,v2
|
||||
10611040| gnu vadduhm v3,v1,v2
|
||||
10611080| gnu vadduwm v3,v1,v2
|
||||
106110c0| gnu vaddudm v3,v1,v2
|
||||
10611100| gnu vadduqm v3,v1,v2
|
||||
10611140| gnu vaddcuq v3,v1,v2
|
||||
10611180| gnu vaddcuw v3,v1,v2
|
||||
10611200| gnu vaddubs v3,v1,v2
|
||||
10611240| gnu vadduhs v3,v1,v2
|
||||
10611280| gnu vadduws v3,v1,v2
|
||||
10611400| gnu vsububm v3,v1,v2
|
||||
10611440| gnu vsubuhm v3,v1,v2
|
||||
10611480| gnu vsubuwm v3,v1,v2
|
||||
106114c0| gnu vsubudm v3,v1,v2
|
||||
10611500| gnu vsubuqm v3,v1,v2
|
||||
10611540| gnu vsubcuq v3,v1,v2
|
||||
10611580| gnu vsubcuw v3,v1,v2
|
||||
10611600| gnu vsububs v3,v1,v2
|
||||
10611640| gnu vsubuhs v3,v1,v2
|
||||
10611680| gnu vsubuws v3,v1,v2
|
||||
10611700| gnu vsubsbs v3,v1,v2
|
||||
10611740| gnu vsubshs v3,v1,v2
|
||||
10611780| gnu vsubsws v3,v1,v2
|
||||
108110fe| gnu vsubeuqm v4,v1,v2,v3
|
||||
108110ff| gnu vsubecuq v4,v1,v2,v3
|
||||
10611308| gnu vmulesb v3,v1,v2
|
||||
10611108| gnu vmulosb v3,v1,v2
|
||||
10611208| gnu vmuleub v3,v1,v2
|
||||
10611008| gnu vmuloub v3,v1,v2
|
||||
10611348| gnu vmulesh v3,v1,v2
|
||||
10611148| gnu vmulosh v3,v1,v2
|
||||
10611248| gnu vmuleuh v3,v1,v2
|
||||
10611048| gnu vmulouh v3,v1,v2
|
||||
10611348| gnu vmulesh v3,v1,v2
|
||||
10611188| gnu vmulosw v3,v1,v2
|
||||
10611288| gnu vmuleuw v3,v1,v2
|
||||
10611088| gnu vmulouw v3,v1,v2
|
||||
10611089| gnu vmuluwm v3,v1,v2
|
||||
10611408| gnu vpmsumb v3,v1,v2
|
||||
10611448| gnu vpmsumh v3,v1,v2
|
||||
10611488| gnu vpmsumw v3,v1,v2
|
||||
106114c8| gnu vpmsumd v3,v1,v2
|
||||
108110e3| gnu vmsumudm v4,v1,v2,v3
|
||||
10611004| gnu vrlb v3,v1,v2
|
||||
10611044| gnu vrlh v3,v1,v2
|
||||
10611084| gnu vrlw v3,v1,v2
|
||||
106110c4| gnu vrld v3,v1,v2
|
||||
10611104| gnu vslb v3,v1,v2
|
||||
10611144| gnu vslh v3,v1,v2
|
||||
10611184| gnu vslw v3,v1,v2
|
||||
106111c4| gnu vsl v3,v1,v2
|
||||
1061140c| gnu vslo v3,v1,v2
|
||||
10611204| gnu vsrb v3,v1,v2
|
||||
10611244| gnu vsrh v3,v1,v2
|
||||
10611284| gnu vsrw v3,v1,v2
|
||||
106112c4| gnu vsr v3,v1,v2
|
||||
1061144c| gnu vsro v3,v1,v2
|
||||
106115c4| gnu vsld v3,v1,v2
|
||||
10611304| gnu vsrab v3,v1,v2
|
||||
10611344| gnu vsrah v3,v1,v2
|
||||
10611384| gnu vsraw v3,v1,v2
|
||||
106113c4| gnu vsrad v3,v1,v2
|
||||
10400f02| gnu vclzb v2,v1
|
||||
10400f42| gnu vclzh v2,v1
|
||||
10400f82| gnu vclzw v2,v1
|
||||
10400fc2| gnu vclzd v2,v1
|
||||
10400f03| gnu vpopcntb v2,v1
|
||||
10400f43| gnu vpopcnth v2,v1
|
||||
10400f83| gnu vpopcntw v2,v1
|
||||
10400fc3| gnu vpopcntd v2,v1
|
||||
10611006| gnu vcmpequb v3,v1,v2
|
||||
10611406| gnu vcmpequb. v3,v1,v2
|
||||
10611046| gnu vcmpequh v3,v1,v2
|
||||
10611446| gnu vcmpequh. v3,v1,v2
|
||||
10611086| gnu vcmpequw v3,v1,v2
|
||||
10611486| gnu vcmpequw. v3,v1,v2
|
||||
106110c7| gnu vcmpequd v3,v1,v2
|
||||
106114c7| gnu vcmpequd. v3,v1,v2
|
||||
10611206| gnu vcmpgtub v3,v1,v2
|
||||
10611606| gnu vcmpgtub. v3,v1,v2
|
||||
10611246| gnu vcmpgtuh v3,v1,v2
|
||||
10611646| gnu vcmpgtuh. v3,v1,v2
|
||||
10611286| gnu vcmpgtuw v3,v1,v2
|
||||
10611686| gnu vcmpgtuw. v3,v1,v2
|
||||
106112c7| gnu vcmpgtud v3,v1,v2
|
||||
106116c7| gnu vcmpgtud. v3,v1,v2
|
||||
10611306| gnu vcmpgtsb v3,v1,v2
|
||||
10611706| gnu vcmpgtsb. v3,v1,v2
|
||||
10611346| gnu vcmpgtsh v3,v1,v2
|
||||
10611746| gnu vcmpgtsh. v3,v1,v2
|
||||
10611386| gnu vcmpgtsw v3,v1,v2
|
||||
10611786| gnu vcmpgtsw. v3,v1,v2
|
||||
106113c7| gnu vcmpgtsd v3,v1,v2
|
||||
106117c7| gnu vcmpgtsd. v3,v1,v2
|
||||
10611107| gnu vcmpnezb v3,v1,v2
|
||||
10611507| gnu vcmpnezb. v3,v1,v2
|
||||
10611007| gnu vcmpneb v3,v1,v2
|
||||
10611407| gnu vcmpneb. v3,v1,v2
|
||||
10611047| gnu vcmpneh v3,v1,v2
|
||||
10611447| gnu vcmpneh. v3,v1,v2
|
||||
10611087| gnu vcmpnew v3,v1,v2
|
||||
10611487| gnu vcmpnew. v3,v1,v2
|
||||
108110eb| gnu vperm v4,v1,v2,v3
|
||||
108110fb| gnu vpermr v4,v1,v2,v3
|
||||
108110ed| gnu vpermxor v4,v1,v2,v3
|
||||
1061154c| gnu vbpermq v3,v1,v2
|
||||
106115cc| gnu vbpermd v3,v1,v2
|
||||
108110ea| gnu vsel v4,v1,v2,v3
|
||||
10611508| gnu vcipher v3,v1,v2
|
||||
10611509| gnu vcipherlast v3,v1,v2
|
||||
10611548| gnu vncipher v3,v1,v2
|
||||
10611549| gnu vncipherlast v3,v1,v2
|
||||
104105c8| gnu vsbox v2,v1
|
||||
7c241e98| gnu lxvd2x vs1,r4,r3
|
||||
f4230011| gnu lxv vs1,16(r3)
|
||||
7c23221a| gnu lxvl vs1,r3,r4
|
||||
7c23225a| gnu lxvll vs1,r3,r4
|
||||
7c241c98| gnu lxsdx vs1,r4,r3
|
||||
7c241a18| gnu lxvx vs1,r4,r3
|
||||
7c241b18| gnu stxvx vs1,r4,r3
|
||||
7c241f98| gnu stxvd2x vs1,r4,r3
|
||||
f4230015| gnu stxv vs1,16(r3)
|
||||
7c23231a| gnu stxvl vs1,r3,r4
|
||||
7c23235a| gnu stxvll vs1,r3,r4
|
||||
7c241d98| gnu stxsdx vs1,r4,r3
|
||||
7c241898| gnu lxsiwax vs1,r4,r3
|
||||
7c241918| gnu stxsiwx vs1,r4,r3
|
||||
7c230066| gnu mfvsrd r3,vs1
|
||||
7c230166| gnu mtvsrd vs1,r3
|
||||
f0611410| gnu xxland vs3,vs1,vs2
|
||||
f0611490| gnu xxlor vs3,vs1,vs2
|
||||
f0611550| gnu xxlorc vs3,vs1,vs2
|
||||
f06114d0| gnu xxlxor vs3,vs1,vs2
|
||||
f08110f0| gnu xxsel vs4,vs1,vs2,vs3
|
||||
f0611090| gnu xxmrghw vs3,vs1,vs2
|
||||
f0410a90| gnu xxspltw vs2,vs1,1
|
||||
f06110d0| gnu xxperm vs3,vs1,vs2
|
||||
f0611110| gnu xxsldwi vs3,vs1,vs2,1
|
||||
f0400c24| gnu xscvdpsp vs2,vs1
|
||||
f0400e24| gnu xvcvdpsp vs2,vs1
|
||||
f0400de0| gnu xscvsxddp vs2,vs1
|
||||
f0400f60| gnu xvcvdpsxds vs2,vs1
|
||||
f0400fe0| gnu xvcvsxddp vs2,vs1
|
||||
7c6803a6| gnu mtlr r3
|
||||
7c6903a6| gnu mtctr r3
|
||||
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
|
||||
0602000138800007| gnu pli r4,-8589869049
|
||||
7c5b03c0| plan9 SETNBCR CR6SO,R2
|
||||
fc811000| plan9 FCMPU F1,F2,CR1
|
||||
7c220176| plan9 BRD R1,R2
|
||||
7c2201b6| plan9 BRH R1,R2
|
||||
7c220136| plan9 BRW R1,R2
|
||||
7c2311b8| plan9 CFUGED R1,R2,R3
|
||||
04100016e4820032| gnu .quad 0x4100016e4820032
|
||||
0612000138820007| gnu .quad 0x612000138820007
|
||||
7fe20de5| plan9 HASHCHK -8(R2),R1
|
||||
7fe20da5| plan9 HASHST R1,-8(R2)
|
||||
7c020de4| plan9 HASHCHK -512(R2),R1
|
||||
7c020da4| plan9 HASHST R1,-512(R2)
|
||||
7c020de5| plan9 HASHCHK -256(R2),R1
|
||||
7c020da5| plan9 HASHST R1,-256(R2)
|
||||
7fe115a5| plan9 HASHST R2,-8(R1)
|
||||
7fe11525| plan9 HASHSTP R2,-8(R1)
|
||||
7fe115e5| plan9 HASHCHK -8(R1),R2
|
||||
7fe11565| plan9 HASHCHKP -8(R1),R2
|
||||
+2816
File diff suppressed because it is too large
Load Diff
+1418
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,503 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// Power64spec reads the “Power ISA V2.07” Manual
|
||||
// to collect instruction encoding details and writes those details to standard output
|
||||
// in CSV format.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// ppc64spec PowerISA_V2.07_PUBLIC.pdf >ppc64.csv
|
||||
//
|
||||
// Each CSV line contains four fields:
|
||||
//
|
||||
// instruction
|
||||
// The instruction heading, such as "AAD imm8".
|
||||
// mnemonic
|
||||
// The instruction mnemonics, separated by | symbols.
|
||||
// encoding
|
||||
// The instruction encoding, a sequence of name@startbit| describing each bit field in turn.
|
||||
// tags
|
||||
// For now, empty.
|
||||
//
|
||||
// For more on the exact meaning of these fields, see the Power manual.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"rsc.io/pdf"
|
||||
)
|
||||
|
||||
type Inst struct {
|
||||
Name string
|
||||
Text string
|
||||
Enc string
|
||||
}
|
||||
|
||||
const debugPage = 0
|
||||
|
||||
var stdout *bufio.Writer
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("ppc64spec: ")
|
||||
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "usage: ppc64spec file.pdf\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
f, err := pdf.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Find instruction set reference in outline, to build instruction list.
|
||||
instList := instHeadings(f.Outline())
|
||||
if len(instList) < 200 {
|
||||
log.Fatalf("only found %d instructions in table of contents", len(instList))
|
||||
}
|
||||
|
||||
var all = []Inst{
|
||||
// Split across multiple columns and pages!
|
||||
{"Count Leading Zeros Word X-form", "cntlzw RA, RS (Rc=0)\ncntlzw. RA, RS (Rc=1)", "31@0|RS@6|RA@11|///@16|26@21|Rc@31|"},
|
||||
}
|
||||
|
||||
for j, headline := range instList {
|
||||
for _, inst := range all {
|
||||
if headline == inst.Name {
|
||||
instList[j] = ""
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan document looking for instructions.
|
||||
// Must find exactly the ones in the outline.
|
||||
n := f.NumPage()
|
||||
for pageNum := 1; pageNum <= n; pageNum++ {
|
||||
if debugPage > 0 && pageNum != debugPage {
|
||||
continue
|
||||
}
|
||||
p := f.Page(pageNum)
|
||||
table := parsePage(pageNum, p)
|
||||
if len(table) == 0 {
|
||||
continue
|
||||
}
|
||||
InstLoop:
|
||||
for _, inst := range table {
|
||||
for j, headline := range instList {
|
||||
if inst.Name == headline {
|
||||
instList[j] = ""
|
||||
continue InstLoop
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "page %d: unexpected instruction %q\n", pageNum, inst.Name)
|
||||
}
|
||||
all = append(all, table...)
|
||||
}
|
||||
|
||||
if debugPage == 0 {
|
||||
for _, headline := range instList {
|
||||
if headline != "" {
|
||||
switch headline {
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "missing instruction %q\n", headline)
|
||||
case "CHKA": // ThumbEE
|
||||
case "CPS": // system instruction
|
||||
case "CPY": // synonym for MOV
|
||||
case "ENTERX": // ThumbEE
|
||||
case "F* (former VFP instruction mnemonics)": // synonyms
|
||||
case "HB, HBL, HBLP, HBP": // ThumbEE
|
||||
case "LEAVEX": // ThumbEE
|
||||
case "MOV (shifted register)": // pseudo instruction for ASR, LSL, LSR, ROR, and RRX
|
||||
case "NEG": // synonym for RSB
|
||||
case "RFE": // system instruction
|
||||
case "SMC (previously SMI)": // system instruction
|
||||
case "SRS": // system instruction
|
||||
case "SUBS PC, LR and related instructions": // system instruction
|
||||
case "VAND (immediate)": // pseudo instruction
|
||||
case "VCLE (register)": // pseudo instruction
|
||||
case "VCLT (register)": // pseudo instruction
|
||||
case "VORN (immediate)": // pseudo instruction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stdout = bufio.NewWriter(os.Stdout)
|
||||
for _, inst := range all {
|
||||
fmt.Fprintf(stdout, "%q,%q,%q,%q\n", inst.Name, strings.Replace(inst.Text, "\n", "|", -1), inst.Enc, "")
|
||||
}
|
||||
stdout.Flush()
|
||||
|
||||
}
|
||||
|
||||
func instHeadings(outline pdf.Outline) []string {
|
||||
return appendInstHeadings(outline, nil)
|
||||
}
|
||||
|
||||
var instRE = regexp.MustCompile(` ([A-Z0-9]+-form|Byte|Word|Doubleword|Halfword)($| \[)`)
|
||||
var sectionRE = regexp.MustCompile(`^[0-9A-Z]+\.[0-9]`)
|
||||
|
||||
func appendInstHeadings(outline pdf.Outline, list []string) []string {
|
||||
if strings.Contains(outline.Title, "Variable Length Encoding (VLE) Encoding") {
|
||||
for _, child := range outline.Child {
|
||||
vle = appendInstHeadings(child, vle)
|
||||
}
|
||||
return list
|
||||
}
|
||||
if instRE.MatchString(outline.Title) && !sectionRE.MatchString(outline.Title) {
|
||||
list = append(list, outline.Title)
|
||||
}
|
||||
if outline.Title == "Transaction Abort Word Conditional" {
|
||||
list = append(list, outline.Title+" X-form")
|
||||
}
|
||||
for _, child := range outline.Child {
|
||||
list = appendInstHeadings(child, list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
const inch = 72.0
|
||||
|
||||
func parsePage(num int, p pdf.Page) []Inst {
|
||||
content := p.Content()
|
||||
|
||||
var text []pdf.Text
|
||||
for _, t := range content.Text {
|
||||
text = append(text, t)
|
||||
}
|
||||
|
||||
text = findWords(text)
|
||||
|
||||
if debugPage > 0 {
|
||||
for _, t := range text {
|
||||
fmt.Println(t)
|
||||
}
|
||||
for _, r := range content.Rect {
|
||||
fmt.Println(r)
|
||||
}
|
||||
}
|
||||
|
||||
// Look for instruction encodings.
|
||||
// Some begin with a Helvetica-BoldOblique size 11 headline like "AND X-Form",
|
||||
// is followed by Helvetica 9 mnemonic, and then a bit box with
|
||||
// Helvetica 9 fields and Helvetica 7 bit offsets.
|
||||
// Others use Arial,BoldItalic 11 for the headline,
|
||||
// Arial 8 for the mnemonic, and Arial 4.2 for the bit offsets.
|
||||
|
||||
var insts []Inst
|
||||
for {
|
||||
// Heading
|
||||
for len(text) > 0 && !match(text[0], "Helvetica-BoldOblique", 11, "") && !match(text[0], "Arial,BoldItalic", 11, "") && !match(text[0], "Arial,BoldItalic", 10, "") {
|
||||
text = text[1:]
|
||||
}
|
||||
if len(text) == 0 {
|
||||
break
|
||||
}
|
||||
heading := text[0].S
|
||||
text = text[1:]
|
||||
for len(text) > 0 && (match(text[0], "Helvetica-BoldOblique", 11, "") || match(text[0], "Arial,BoldItalic", 11, "") || match(text[0], "Arial,BoldItalic", 10, "")) {
|
||||
heading += " " + text[0].S
|
||||
text = text[1:]
|
||||
}
|
||||
heading = strings.Replace(heading, "]", "] ", -1)
|
||||
heading = strings.Replace(heading, " ", " ", -1)
|
||||
heading = strings.Replace(heading, "rEVX-form", "r EVX-form", -1)
|
||||
heading = strings.Replace(heading, "eX-form", "e X-form", -1)
|
||||
heading = strings.Replace(heading, "mSD4-form", "m SD4-form", -1)
|
||||
heading = strings.Replace(heading, "eSCI8-form", "e SCI8-form", -1)
|
||||
heading = strings.TrimSpace(heading)
|
||||
if isVLE(heading) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Mnemonic
|
||||
if len(text) == 0 || (!match(text[0], "Helvetica", 9, "") && !match(text[0], "Helvetica-BoldOblique", 9, "") && !match(text[0], "Arial", 9, "") && !match(text[0], "Arial", 10, "")) {
|
||||
continue
|
||||
}
|
||||
mnemonic := ""
|
||||
y := text[0].Y
|
||||
x0 := text[0].X
|
||||
for len(text) > 0 && (match(text[0], "Helvetica", 9, "") || match(text[0], "Helvetica-BoldOblique", 9, "") || match(text[0], "Arial", 9, "") || match(text[0], "Courier", 8, "") || match(text[0], "LucidaConsole", 7.17, "") || text[0].Y == y) {
|
||||
if text[0].Y != y {
|
||||
if math.Abs(text[0].X-x0) > 4 {
|
||||
break
|
||||
}
|
||||
mnemonic += "\n"
|
||||
y = text[0].Y
|
||||
} else if mnemonic != "" {
|
||||
mnemonic += " "
|
||||
}
|
||||
mnemonic += text[0].S
|
||||
text = text[1:]
|
||||
}
|
||||
|
||||
// Encoding
|
||||
bits, i := readBitBox(heading, content, text, num)
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
insts = append(insts, Inst{heading, mnemonic, bits})
|
||||
}
|
||||
return insts
|
||||
}
|
||||
|
||||
var vle = []string{
|
||||
"System Call C-form,ESC-form",
|
||||
}
|
||||
|
||||
func isVLE(s string) bool {
|
||||
for _, v := range vle {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func readBitBox(headline string, content pdf.Content, text []pdf.Text, pageNum int) (string, int) {
|
||||
// fields
|
||||
i := 0
|
||||
if len(text) == 0 || (!match(text[i], "Helvetica", 9, "") && !match(text[i], "Helvetica", 7.26, "") && !match(text[i], "Arial", 9, "") && !match(text[i], "Arial", 7.98, "") && !match(text[i], "Arial", 7.2, "")) {
|
||||
fmt.Fprintf(os.Stderr, "page %d: no bit fields for %q\n", pageNum, headline)
|
||||
if len(text) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "\tlast text: %v\n", text[0])
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
sz := text[i].FontSize
|
||||
y2 := text[i].Y
|
||||
x2 := 0.0
|
||||
for i < len(text) && text[i].Y == y2 {
|
||||
if x2 < text[i].X+text[i].W {
|
||||
x2 = text[i].X + text[i].W
|
||||
}
|
||||
i++
|
||||
}
|
||||
y2 += sz / 2
|
||||
|
||||
// bit numbers
|
||||
if i >= len(text) || text[i].S != "0" {
|
||||
if headline == "Transaction Abort Doubleword Conditional X-form" {
|
||||
// Split across the next page.
|
||||
return "31@0|TO@6|RA@11|RB@16|814@21|1@31|", i
|
||||
}
|
||||
if headline == "Add Scaled Immediate SCI8-form" {
|
||||
// Very strange fonts.
|
||||
return "06@0|RT@6|RA@11|8@16|Rc@20|F@21|SCL@22|UI8@24|", i
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "page %d: no bit numbers for %s\n", pageNum, headline)
|
||||
if i < len(text) {
|
||||
fmt.Fprintf(os.Stderr, "\tlast text: %v\n", text[i])
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
sz = text[i].FontSize
|
||||
y1 := text[i].Y
|
||||
x1 := text[i].X
|
||||
for i < len(text) && text[i].Y == y1 {
|
||||
if x2 < text[i].X+text[i].W {
|
||||
x2 = text[i].X + text[i].W
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
if debugPage > 0 {
|
||||
fmt.Println("encoding box", x1, y1, x2, y2, i, text[0], text[i])
|
||||
}
|
||||
|
||||
// Find lines (thin rectangles) separating bit fields.
|
||||
var bottom, top pdf.Rect
|
||||
const (
|
||||
yMargin = 0.25 * 72
|
||||
xMargin = 1 * 72
|
||||
)
|
||||
for _, r := range content.Rect {
|
||||
// Only consider lines in the same column.
|
||||
if (x1 < 306) != (r.Max.X < 306) {
|
||||
continue
|
||||
}
|
||||
if r.Max.Y-r.Min.Y < 2 && x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
|
||||
if y1-yMargin < r.Min.Y && r.Min.Y < y1 {
|
||||
bottom = r
|
||||
}
|
||||
if y2 < r.Min.Y && r.Min.Y < y2+8 {
|
||||
top = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bottom.Min.X == 0 {
|
||||
// maybe bit numbers are outside box; see doze, nap, sleep, rvwinkle.
|
||||
for _, r := range content.Rect {
|
||||
// Only consider lines in the same column.
|
||||
if (x1 < 306) != (r.Max.X < 306) {
|
||||
continue
|
||||
}
|
||||
if r.Max.Y-r.Min.Y < 2 && x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
|
||||
if y1+sz/2 < r.Min.Y && r.Min.Y < y2 {
|
||||
bottom = r
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if debugPage > 0 {
|
||||
fmt.Println("top", top, "bottom", bottom)
|
||||
}
|
||||
|
||||
const ε = 0.1 * 72
|
||||
var bars []pdf.Rect
|
||||
for _, r := range content.Rect {
|
||||
if r.Max.X-r.Min.X < 2 && math.Abs(r.Min.Y-bottom.Min.Y) < ε && math.Abs(r.Max.Y-top.Min.Y) < ε && (bottom.Min.X < 306) == (r.Max.X < 306) {
|
||||
bars = append(bars, r)
|
||||
}
|
||||
}
|
||||
sort.Sort(RectHorizontal(bars))
|
||||
|
||||
out := ""
|
||||
for i := 0; i < len(bars)-1; i++ {
|
||||
var sub []pdf.Text
|
||||
x1, x2 := bars[i].Min.X, bars[i+1].Min.X
|
||||
for _, t := range content.Text {
|
||||
tx := t.X + t.W/2
|
||||
ty := t.Y + t.FontSize/4
|
||||
if x1 < tx && tx < x2 && y1 < ty && ty < y2 {
|
||||
sub = append(sub, t)
|
||||
}
|
||||
}
|
||||
var str []string
|
||||
for _, t := range findWords(sub) {
|
||||
str = append(str, t.S)
|
||||
}
|
||||
s := strings.Join(str, "@")
|
||||
out += s + "|"
|
||||
}
|
||||
|
||||
if out == "" {
|
||||
fmt.Fprintf(os.Stderr, "page %d: no bit encodings for %s\n", pageNum, headline)
|
||||
}
|
||||
return out, i
|
||||
}
|
||||
|
||||
type RectHorizontal []pdf.Rect
|
||||
|
||||
func (x RectHorizontal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
func (x RectHorizontal) Less(i, j int) bool { return x[i].Min.X < x[j].Min.X }
|
||||
func (x RectHorizontal) Len() int { return len(x) }
|
||||
|
||||
func checkNoEncodings(num int, text []pdf.Text) {
|
||||
for _, t := range text {
|
||||
if match(t, "Helvetica-Bold", 9, "Encoding") {
|
||||
fmt.Fprintf(os.Stderr, "page %d: unexpected encoding: %s\n", num, t.S)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func match(t pdf.Text, font string, size float64, substr string) bool {
|
||||
return t.Font == font && (size == 0 || math.Abs(t.FontSize-size) < 0.1) && strings.Contains(t.S, substr)
|
||||
}
|
||||
|
||||
func findWords(chars []pdf.Text) (words []pdf.Text) {
|
||||
// Sort by Y coordinate and normalize.
|
||||
const nudge = 1.5
|
||||
sort.Sort(pdf.TextVertical(chars))
|
||||
old := -100000.0
|
||||
for i, c := range chars {
|
||||
if c.Y != old && math.Abs(old-c.Y) < nudge {
|
||||
chars[i].Y = old
|
||||
} else {
|
||||
old = c.Y
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by Y coordinate, breaking ties with X.
|
||||
// This will bring letters in a single word together.
|
||||
sort.Sort(pdf.TextVertical(chars))
|
||||
|
||||
// Loop over chars.
|
||||
for i := 0; i < len(chars); {
|
||||
// Find all chars on line.
|
||||
j := i + 1
|
||||
for j < len(chars) && chars[j].Y == chars[i].Y {
|
||||
j++
|
||||
}
|
||||
var end float64
|
||||
// Split line into words (really, phrases).
|
||||
for k := i; k < j; {
|
||||
ck := &chars[k]
|
||||
s := ck.S
|
||||
end = ck.X + ck.W
|
||||
charSpace := ck.FontSize / 6
|
||||
wordSpace := ck.FontSize * 2 / 3
|
||||
l := k + 1
|
||||
for l < j {
|
||||
// Grow word.
|
||||
cl := &chars[l]
|
||||
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace {
|
||||
s += cl.S
|
||||
end = cl.X + cl.W
|
||||
l++
|
||||
continue
|
||||
}
|
||||
// Add space to phrase before next word.
|
||||
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace {
|
||||
s += " " + cl.S
|
||||
end = cl.X + cl.W
|
||||
l++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
f := ck.Font
|
||||
f = strings.TrimSuffix(f, ",Italic")
|
||||
f = strings.TrimSuffix(f, "-Italic")
|
||||
words = append(words, pdf.Text{f, ck.FontSize, ck.X, ck.Y, end - ck.X, s})
|
||||
k = l
|
||||
}
|
||||
i = j
|
||||
}
|
||||
|
||||
// Split into two columns.
|
||||
var col1, col2 []pdf.Text
|
||||
for _, w := range words {
|
||||
if w.X > 306 {
|
||||
col2 = append(col2, w)
|
||||
} else {
|
||||
col1 = append(col1, w)
|
||||
}
|
||||
}
|
||||
return append(col1, col2...)
|
||||
}
|
||||
|
||||
func sameFont(f1, f2 string) bool {
|
||||
f1 = strings.TrimSuffix(f1, ",Italic")
|
||||
f1 = strings.TrimSuffix(f1, "-Italic")
|
||||
f2 = strings.TrimSuffix(f1, ",Italic")
|
||||
f2 = strings.TrimSuffix(f1, "-Italic")
|
||||
return strings.TrimSuffix(f1, ",Italic") == strings.TrimSuffix(f2, ",Italic") || f1 == "Symbol" || f2 == "Symbol" || f1 == "TimesNewRoman" || f2 == "TimesNewRoman"
|
||||
}
|
||||
|
||||
var jsFix = strings.NewReplacer(
|
||||
// `\u003c`, `<`,
|
||||
// `\u003e`, `>`,
|
||||
// `\u0026`, `&`,
|
||||
// `\u0009`, `\t`,
|
||||
)
|
||||
|
||||
func printTable(name string, table []Inst) {
|
||||
_ = strconv.Atoi
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// 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
|
||||
|
||||
// A valid displacement value for the hash check and hash store instructions.
|
||||
#define offset -128
|
||||
|
||||
// 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
|
||||
@@ -0,0 +1,149 @@
|
||||
// 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.
|
||||
|
||||
//go:build ignore
|
||||
|
||||
// Generate interesting test cases from ppc64 objdump via
|
||||
// go run util.go
|
||||
//
|
||||
// This requires powerpc64le-linux-gnu-gcc and powerpc64le-linux-gnu-objdump be in
|
||||
// the PATH this command is run.
|
||||
//
|
||||
// These tools can be acquired from the IBM advance toolchain for amd64 hosts too.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Generator for branch on spr (bclr, bctar, bcctr)
|
||||
func emitBSpr(bo, bi, l uint32, out io.Writer) {
|
||||
var insn [3]uint32 = [3]uint32{19<<26 | 16<<1, 19<<26 | 528<<1, 19<<26 | 560<<1}
|
||||
for bh := uint32(0); bh < 3; bh++ {
|
||||
for _, m := range insn {
|
||||
m |= bo << 21
|
||||
m |= bi << 16
|
||||
m |= bh << 11
|
||||
m |= l << 0
|
||||
fmt.Fprintf(out, "\t.long 0x%08x\n", m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generator for bc
|
||||
func emitBc(bo, bi, l uint32, out io.Writer) {
|
||||
for aa := uint32(0); aa < 2; aa++ {
|
||||
m := uint32(16 << 26)
|
||||
m |= bo << 21
|
||||
m |= bi << 16
|
||||
m |= l << 0
|
||||
m |= aa << 1
|
||||
m |= 128
|
||||
fmt.Fprintf(out, "\t.long 0x%08x\n", m)
|
||||
}
|
||||
}
|
||||
|
||||
// Generator all interesting conditional branch type instructions
|
||||
func emitBranches(out io.Writer) {
|
||||
fmt.Fprintf(out, ".text\n")
|
||||
for bo := 0; bo < 0x20; bo++ {
|
||||
// objdump behaves strangely on some cases when a z bit is set.
|
||||
// Ignore these, they should never show up in correct code.
|
||||
if bo&0x15 == 0x1 {
|
||||
// skip 0b0.0.z cases where z != 0
|
||||
continue
|
||||
}
|
||||
if bo&0x14 == 0x14 && bo != 14 {
|
||||
// skip 0b1z1zz cases where z != 0
|
||||
continue
|
||||
}
|
||||
// skip at == 1 cases. objdump doesn't handle these well either.
|
||||
reserved_at := map[int]bool{5: true, 13: true, 17: true, 19: true}
|
||||
if reserved_at[bo] {
|
||||
continue
|
||||
}
|
||||
// only test cr0/cr1 bits. cr2-cr7 cases are basically identical to cr1.
|
||||
for bi := 0; bi < 0x8; bi++ {
|
||||
for l := 0; l < 2; l++ {
|
||||
emitBSpr(uint32(bo), uint32(bi), uint32(l), out)
|
||||
emitBc(uint32(bo), uint32(bi), uint32(l), out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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=power10", "-x", "assembler-with-cpp", "-o", name+".o", "-")
|
||||
input, _ := cmd.StdinPipe()
|
||||
cmd.Stderr = os.Stderr
|
||||
go func() {
|
||||
defer input.Close()
|
||||
generator(input.(io.Writer))
|
||||
}()
|
||||
if cmd.Run() != nil {
|
||||
fmt.Printf("Failed running gcc for: %s\n", name)
|
||||
return
|
||||
}
|
||||
defer os.Remove(name + ".o")
|
||||
cmd = exec.Command(tcPfx+"objdump", "-d", name+".o")
|
||||
|
||||
// Run objdump and parse output into test format
|
||||
output, _ := cmd.StdoutPipe()
|
||||
defer output.Close()
|
||||
scanner := bufio.NewScanner(output)
|
||||
spacere := regexp.MustCompile("[[:space:]]+")
|
||||
outf, _ := os.Create(name + ".txt")
|
||||
defer outf.Close()
|
||||
if cmd.Start() != nil {
|
||||
fmt.Printf("Failed running objdump for: %s\n", name)
|
||||
return
|
||||
}
|
||||
|
||||
pfx := ""
|
||||
dec := ""
|
||||
for scanner.Scan() {
|
||||
ln := spacere.Split(scanner.Text(), -1)
|
||||
if len(ln) >= 7 {
|
||||
opc := strings.Join(ln[2:6], "")
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user