forked from jshiffer/matterbridge
180 lines
4.4 KiB
Go
180 lines
4.4 KiB
Go
|
// 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
|
||
|
|
||
|
// instFormat is a decoding rule for one specific instruction form.
|
||
|
// a uint32 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.
|
||
|
type instFormat struct {
|
||
|
Op Op
|
||
|
Mask uint32
|
||
|
Value uint32
|
||
|
DontCare uint32
|
||
|
Args [5]*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 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 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)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
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
|
||
|
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 TypeSpReg:
|
||
|
return "SpReg"
|
||
|
case TypeImmSigned:
|
||
|
return "ImmSigned"
|
||
|
case TypeImmUnsigned:
|
||
|
return "ImmUnsigned"
|
||
|
case TypePCRel:
|
||
|
return "PCRel"
|
||
|
case TypeLabel:
|
||
|
return "Label"
|
||
|
case TypeOffset:
|
||
|
return "Offset"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 // only 4-byte instructions are supported
|
||
|
ui := ord.Uint32(src[:inst.Len])
|
||
|
inst.Enc = ui
|
||
|
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)
|
||
|
}
|
||
|
inst.Op = iform.Op
|
||
|
if debugDecode {
|
||
|
log.Printf("%#x: search entry %d", ui, i)
|
||
|
continue
|
||
|
}
|
||
|
break
|
||
|
}
|
||
|
if inst.Op == 0 {
|
||
|
return inst, errUnknown
|
||
|
}
|
||
|
return inst, nil
|
||
|
}
|