s390x: add s390x disassembler support, GNU syntax
Change-Id: Idd91cc89510ce117e49db541fd68b0fa113b92fa Reviewed-on: https://go-review.googlesource.com/c/arch/+/575675 Auto-Submit: Cherry Mui <cherryyz@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Bill O'Farrell <billotosyr@gmail.com> Reviewed-by: Srinivas Pokala <Pokala.Srinivas@ibm.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Родитель
b863392466
Коммит
9d90945922
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,2 @@
|
||||||
|
tables.go: ../s390xmap/map.go ../s390x.csv
|
||||||
|
go run ../s390xmap/map.go -fmt=decoder ../s390x.csv >_tables.go && gofmt _tables.go >tables.go && rm _tables.go
|
|
@ -0,0 +1,241 @@
|
||||||
|
// Copyright 2024 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 s390xasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// instFormat is a decoding rule for one specific instruction form.
|
||||||
|
// An instruction ins matches the rule if ins&Mask == Value.
|
||||||
|
// DontCare bits are mainly used for finding the same instruction
|
||||||
|
// name differing with the number of argument fields.
|
||||||
|
// The Args are stored in the same order as the instruction manual.
|
||||||
|
type instFormat struct {
|
||||||
|
Op Op
|
||||||
|
Mask uint64
|
||||||
|
Value uint64
|
||||||
|
DontCare uint64
|
||||||
|
Args [8]*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
|
||||||
|
flags uint16
|
||||||
|
BitField
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the Arg out from the given binary instruction i.
|
||||||
|
func (a argField) Parse(i uint64) Arg {
|
||||||
|
switch a.Type {
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
case TypeUnknown:
|
||||||
|
return nil
|
||||||
|
case TypeReg:
|
||||||
|
return R0 + Reg(a.BitField.Parse(i))
|
||||||
|
case TypeFPReg:
|
||||||
|
return F0 + Reg(a.BitField.Parse(i))
|
||||||
|
case TypeCReg:
|
||||||
|
return C0 + Reg(a.BitField.Parse(i))
|
||||||
|
case TypeACReg:
|
||||||
|
return A0 + Reg(a.BitField.Parse(i))
|
||||||
|
case TypeBaseReg:
|
||||||
|
return B0 + Base(a.BitField.Parse(i))
|
||||||
|
case TypeIndexReg:
|
||||||
|
return X0 + Index(a.BitField.Parse(i))
|
||||||
|
case TypeDispUnsigned:
|
||||||
|
return Disp12(a.BitField.Parse(i))
|
||||||
|
case TypeDispSigned20:
|
||||||
|
return Disp20(a.BitField.ParseSigned(i))
|
||||||
|
case TypeVecReg:
|
||||||
|
m := i >> 24 // Handling RXB field(bits 36 to 39)
|
||||||
|
if ((m>>3)&0x1 == 1) && (a.BitField.Offs == 8) {
|
||||||
|
return V0 + VReg(a.BitField.Parse(i)) + VReg(16)
|
||||||
|
} else if ((m>>2)&0x1 == 1) && (a.BitField.Offs == 12) {
|
||||||
|
return V0 + VReg(a.BitField.Parse(i)) + VReg(16)
|
||||||
|
} else if ((m>>1)&0x1 == 1) && (a.BitField.Offs == 16) {
|
||||||
|
return V0 + VReg(a.BitField.Parse(i)) + VReg(16)
|
||||||
|
} else if ((m)&0x1 == 1) && (a.BitField.Offs == 32) {
|
||||||
|
return V0 + VReg(a.BitField.Parse(i)) + VReg(16)
|
||||||
|
} else {
|
||||||
|
return V0 + VReg(a.BitField.Parse(i))
|
||||||
|
}
|
||||||
|
case TypeImmSigned8:
|
||||||
|
return Sign8(a.BitField.ParseSigned(i))
|
||||||
|
case TypeImmSigned16:
|
||||||
|
return Sign16(a.BitField.ParseSigned(i))
|
||||||
|
case TypeImmSigned32:
|
||||||
|
return Sign32(a.BitField.ParseSigned(i))
|
||||||
|
case TypeImmUnsigned:
|
||||||
|
return Imm(a.BitField.Parse(i))
|
||||||
|
case TypeRegImSigned12:
|
||||||
|
return RegIm12(a.BitField.ParseSigned(i))
|
||||||
|
case TypeRegImSigned16:
|
||||||
|
return RegIm16(a.BitField.ParseSigned(i))
|
||||||
|
case TypeRegImSigned24:
|
||||||
|
return RegIm24(a.BitField.ParseSigned(i))
|
||||||
|
case TypeRegImSigned32:
|
||||||
|
return RegIm32(a.BitField.ParseSigned(i))
|
||||||
|
case TypeMask:
|
||||||
|
return Mask(a.BitField.Parse(i))
|
||||||
|
case TypeLen:
|
||||||
|
return Len(a.BitField.Parse(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArgType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeUnknown ArgType = iota
|
||||||
|
TypeReg // integer register
|
||||||
|
TypeFPReg // floating point register
|
||||||
|
TypeACReg // access register
|
||||||
|
TypeCReg // control register
|
||||||
|
TypeVecReg // vector register
|
||||||
|
TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type
|
||||||
|
TypeImmSigned8 // Signed 8-bit Immdediate
|
||||||
|
TypeImmSigned16 // Signed 16-bit Immdediate
|
||||||
|
TypeImmSigned32 // Signed 32-bit Immdediate
|
||||||
|
TypeBaseReg // Base Register for accessing memory
|
||||||
|
TypeIndexReg // Index Register
|
||||||
|
TypeDispUnsigned // Displacement 12-bit unsigned for memory address
|
||||||
|
TypeDispSigned20 // Displacement 20-bit signed for memory address
|
||||||
|
TypeRegImSigned12 // RegisterImmediate 12-bit signed data
|
||||||
|
TypeRegImSigned16 // RegisterImmediate 16-bit signed data
|
||||||
|
TypeRegImSigned24 // RegisterImmediate 24-bit signed data
|
||||||
|
TypeRegImSigned32 // RegisterImmediate 32-bit signed data
|
||||||
|
TypeMask // 4-bit Mask
|
||||||
|
TypeLen // Length of Memory Operand
|
||||||
|
TypeLast
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t ArgType) String() string {
|
||||||
|
switch t {
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("ArgType(%d)", int(t))
|
||||||
|
case TypeUnknown:
|
||||||
|
return "Unknown"
|
||||||
|
case TypeReg:
|
||||||
|
return "Reg"
|
||||||
|
case TypeFPReg:
|
||||||
|
return "FPReg"
|
||||||
|
case TypeACReg:
|
||||||
|
return "ACReg"
|
||||||
|
case TypeCReg:
|
||||||
|
return "CReg"
|
||||||
|
case TypeDispUnsigned:
|
||||||
|
return "DispUnsigned"
|
||||||
|
case TypeDispSigned20:
|
||||||
|
return "DispSigned20"
|
||||||
|
case TypeBaseReg:
|
||||||
|
return "BaseReg"
|
||||||
|
case TypeIndexReg:
|
||||||
|
return "IndexReg"
|
||||||
|
case TypeVecReg:
|
||||||
|
return "VecReg"
|
||||||
|
case TypeImmSigned8:
|
||||||
|
return "ImmSigned8"
|
||||||
|
case TypeImmSigned16:
|
||||||
|
return "ImmSigned16"
|
||||||
|
case TypeImmSigned32:
|
||||||
|
return "ImmSigned32"
|
||||||
|
case TypeImmUnsigned:
|
||||||
|
return "ImmUnsigned"
|
||||||
|
case TypeRegImSigned12:
|
||||||
|
return "RegImSigned12"
|
||||||
|
case TypeRegImSigned16:
|
||||||
|
return "RegImSigned16"
|
||||||
|
case TypeRegImSigned24:
|
||||||
|
return "RegImSigned24"
|
||||||
|
case TypeRegImSigned32:
|
||||||
|
return "RegImSigned32"
|
||||||
|
case TypeMask:
|
||||||
|
return "Mask"
|
||||||
|
case TypeLen:
|
||||||
|
return "Len"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) (inst Inst, err error) {
|
||||||
|
if len(src) < 2 {
|
||||||
|
return inst, errShort
|
||||||
|
}
|
||||||
|
if decoderCover == nil {
|
||||||
|
decoderCover = make([]bool, len(instFormats))
|
||||||
|
}
|
||||||
|
bit_check := binary.BigEndian.Uint16(src[:2])
|
||||||
|
bit_check = bit_check >> 14
|
||||||
|
l := int(0)
|
||||||
|
if (bit_check & 0x03) == 0 {
|
||||||
|
l = 2
|
||||||
|
} else if bit_check&0x03 == 3 {
|
||||||
|
l = 6
|
||||||
|
} else if (bit_check&0x01 == 1) || (bit_check&0x02 == 2) {
|
||||||
|
l = 4
|
||||||
|
}
|
||||||
|
inst.Len = l
|
||||||
|
ui_extn := uint64(0)
|
||||||
|
switch l {
|
||||||
|
case 2:
|
||||||
|
ui_extn = uint64(binary.BigEndian.Uint16(src[:inst.Len]))
|
||||||
|
inst.Enc = ui_extn
|
||||||
|
ui_extn = ui_extn << 48
|
||||||
|
case 4:
|
||||||
|
ui_extn = uint64(binary.BigEndian.Uint32(src[:inst.Len]))
|
||||||
|
inst.Enc = ui_extn
|
||||||
|
ui_extn = ui_extn << 32
|
||||||
|
case 6:
|
||||||
|
u1 := binary.BigEndian.Uint32(src[:(inst.Len - 2)])
|
||||||
|
u2 := binary.BigEndian.Uint16(src[(inst.Len - 2):inst.Len])
|
||||||
|
ui_extn = uint64(u1)<<16 | uint64(u2)
|
||||||
|
ui_extn = ui_extn << 16
|
||||||
|
inst.Enc = ui_extn
|
||||||
|
default:
|
||||||
|
return inst, errShort
|
||||||
|
}
|
||||||
|
for _, iform := range instFormats {
|
||||||
|
if ui_extn&iform.Mask != iform.Value {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (iform.DontCare & ^(ui_extn)) != iform.DontCare {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j, argfield := range iform.Args {
|
||||||
|
if argfield == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
inst.Args[j] = argfield.Parse(ui_extn)
|
||||||
|
}
|
||||||
|
inst.Op = iform.Op
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if inst.Op == 0 && inst.Enc != 0 {
|
||||||
|
return inst, errUnknown
|
||||||
|
}
|
||||||
|
return inst, nil
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright 2024 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 s390xasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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)
|
||||||
|
var out string
|
||||||
|
if err != nil {
|
||||||
|
out = "error: " + err.Error()
|
||||||
|
} else {
|
||||||
|
switch syntax {
|
||||||
|
case "gnu":
|
||||||
|
out = GNUSyntax(inst, pc)
|
||||||
|
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,98 @@
|
||||||
|
// Copyright 2024 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 s390xasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A BitField is a bit-field in a 64-bit double word.
|
||||||
|
// Bits are counted from 0 from the MSB to 63 as the LSB.
|
||||||
|
type BitField struct {
|
||||||
|
Offs uint8 // the offset of the left-most bit.
|
||||||
|
Bits uint8 // length in bits.
|
||||||
|
}
|
||||||
|
|
||||||
|
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 uint64) uint64 {
|
||||||
|
if b.Bits > 64 || b.Bits == 0 || b.Offs > 63 || b.Offs+b.Bits > 64 {
|
||||||
|
panic(fmt.Sprintf("invalid bitfiled %v", b))
|
||||||
|
}
|
||||||
|
if b.Bits == 20 {
|
||||||
|
return ((((i >> (64 - b.Offs - b.Bits)) & ((1 << 8) - 1)) << 12) | ((i >> (64 - b.Offs - b.Bits + 8)) & 0xFFF))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return (i >> (64 - 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 uint64) int64 {
|
||||||
|
u := int64(b.Parse(i))
|
||||||
|
return u << (64 - b.Bits) >> (64 - 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 uint64) (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 uint64) 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 uint64) 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,399 @@
|
||||||
|
// Copyright 2024 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 s390xasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Inst struct {
|
||||||
|
Op Op // Opcode mnemonic
|
||||||
|
Enc uint64 // Raw encoding bits (if Len == 8, this is the prefix word)
|
||||||
|
Len int // Length of encoding in bytes.
|
||||||
|
Args Args // Instruction arguments, in Power ISA manual order.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Inst) String(pc uint64) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var rxb_check bool
|
||||||
|
m := i.Op.String()
|
||||||
|
if strings.HasPrefix(m, "v") || strings.Contains(m, "wfc") || strings.Contains(m, "wfk") {
|
||||||
|
rxb_check = true
|
||||||
|
}
|
||||||
|
mnemonic := HandleExtndMnemonic(&i)
|
||||||
|
buf.WriteString(fmt.Sprintf("%s", mnemonic))
|
||||||
|
for j, arg := range i.Args {
|
||||||
|
if arg == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if j == 0 {
|
||||||
|
buf.WriteString(" ")
|
||||||
|
} else {
|
||||||
|
switch arg.(type) {
|
||||||
|
case VReg, Reg:
|
||||||
|
if _, ok := i.Args[j-1].(Disp12); ok {
|
||||||
|
buf.WriteString("")
|
||||||
|
} else if _, ok := i.Args[j-1].(Disp20); ok {
|
||||||
|
buf.WriteString("")
|
||||||
|
} else {
|
||||||
|
buf.WriteString(",")
|
||||||
|
}
|
||||||
|
case Base:
|
||||||
|
if _, ok := i.Args[j-1].(VReg); ok {
|
||||||
|
buf.WriteString(",")
|
||||||
|
} else if _, ok := i.Args[j-1].(Reg); ok {
|
||||||
|
buf.WriteString(",")
|
||||||
|
}
|
||||||
|
case Index, Len:
|
||||||
|
default:
|
||||||
|
buf.WriteString(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString(arg.String(pc))
|
||||||
|
if rxb_check && i.Args[j+2] == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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, Base, Index, Disp20, Disp12, Len, Mask, Sign8, Sign16, Sign32, RegIm12, RegIm16, RegIm24, RegIm32.
|
||||||
|
type Arg interface {
|
||||||
|
IsArg()
|
||||||
|
String(pc uint64) 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 [8]Arg
|
||||||
|
|
||||||
|
// Base represents an 4-bit Base Register field
|
||||||
|
type Base uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
B0 Base = iota
|
||||||
|
B1
|
||||||
|
B2
|
||||||
|
B3
|
||||||
|
B4
|
||||||
|
B5
|
||||||
|
B6
|
||||||
|
B7
|
||||||
|
B8
|
||||||
|
B9
|
||||||
|
B10
|
||||||
|
B11
|
||||||
|
B12
|
||||||
|
B13
|
||||||
|
B14
|
||||||
|
B15
|
||||||
|
)
|
||||||
|
|
||||||
|
func (Base) IsArg() {}
|
||||||
|
func (r Base) String(pc uint64) string {
|
||||||
|
switch {
|
||||||
|
case B1 <= r && r <= B15:
|
||||||
|
s := "%"
|
||||||
|
return fmt.Sprintf("%sr%d)", s, int(r-B0))
|
||||||
|
case B0 == r:
|
||||||
|
return fmt.Sprintf("")
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Base(%d)", int(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Index represents an 4-bit Index Register field
|
||||||
|
type Index uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
X0 Index = iota
|
||||||
|
X1
|
||||||
|
X2
|
||||||
|
X3
|
||||||
|
X4
|
||||||
|
X5
|
||||||
|
X6
|
||||||
|
X7
|
||||||
|
X8
|
||||||
|
X9
|
||||||
|
X10
|
||||||
|
X11
|
||||||
|
X12
|
||||||
|
X13
|
||||||
|
X14
|
||||||
|
X15
|
||||||
|
)
|
||||||
|
|
||||||
|
func (Index) IsArg() {}
|
||||||
|
func (r Index) String(pc uint64) string {
|
||||||
|
switch {
|
||||||
|
case X1 <= r && r <= X15:
|
||||||
|
s := "%"
|
||||||
|
return fmt.Sprintf("%sr%d,", s, int(r-X0))
|
||||||
|
case X0 == r:
|
||||||
|
return fmt.Sprintf("")
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Base(%d)", int(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disp20 represents an 20-bit Unsigned Displacement
|
||||||
|
type Disp20 uint32
|
||||||
|
|
||||||
|
func (Disp20) IsArg() {}
|
||||||
|
func (r Disp20) String(pc uint64) string {
|
||||||
|
if (r>>19)&0x01 == 1 {
|
||||||
|
return fmt.Sprintf("%d(", int32(r|0xfff<<20))
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%d(", int32(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disp12 represents an 12-bit Unsigned Displacement
|
||||||
|
type Disp12 uint16
|
||||||
|
|
||||||
|
func (Disp12) IsArg() {}
|
||||||
|
func (r Disp12) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d(", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegIm12 represents an 12-bit Register immediate number.
|
||||||
|
type RegIm12 uint16
|
||||||
|
|
||||||
|
func (RegIm12) IsArg() {}
|
||||||
|
func (r RegIm12) String(pc uint64) string {
|
||||||
|
if (r>>11)&0x01 == 1 {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int16(r|0xf<<12))))
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int16(r))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegIm16 represents an 16-bit Register immediate number.
|
||||||
|
type RegIm16 uint16
|
||||||
|
|
||||||
|
func (RegIm16) IsArg() {}
|
||||||
|
func (r RegIm16) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int16(r))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegIm24 represents an 24-bit Register immediate number.
|
||||||
|
type RegIm24 uint32
|
||||||
|
|
||||||
|
func (RegIm24) IsArg() {}
|
||||||
|
func (r RegIm24) String(pc uint64) string {
|
||||||
|
if (r>>23)&0x01 == 1 {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int32(r|0xff<<24))))
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int32(r))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegIm32 represents an 32-bit Register immediate number.
|
||||||
|
type RegIm32 uint32
|
||||||
|
|
||||||
|
func (RegIm32) IsArg() {}
|
||||||
|
func (r RegIm32) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%#x", pc+(2*uint64(int32(r))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
R0 Reg = iota
|
||||||
|
R1
|
||||||
|
R2
|
||||||
|
R3
|
||||||
|
R4
|
||||||
|
R5
|
||||||
|
R6
|
||||||
|
R7
|
||||||
|
R8
|
||||||
|
R9
|
||||||
|
R10
|
||||||
|
R11
|
||||||
|
R12
|
||||||
|
R13
|
||||||
|
R14
|
||||||
|
R15
|
||||||
|
F0
|
||||||
|
F1
|
||||||
|
F2
|
||||||
|
F3
|
||||||
|
F4
|
||||||
|
F5
|
||||||
|
F6
|
||||||
|
F7
|
||||||
|
F8
|
||||||
|
F9
|
||||||
|
F10
|
||||||
|
F11
|
||||||
|
F12
|
||||||
|
F13
|
||||||
|
F14
|
||||||
|
F15
|
||||||
|
A0
|
||||||
|
A1
|
||||||
|
A2
|
||||||
|
A3
|
||||||
|
A4
|
||||||
|
A5
|
||||||
|
A6
|
||||||
|
A7
|
||||||
|
A8
|
||||||
|
A9
|
||||||
|
A10
|
||||||
|
A11
|
||||||
|
A12
|
||||||
|
A13
|
||||||
|
A14
|
||||||
|
A15
|
||||||
|
C0
|
||||||
|
C1
|
||||||
|
C2
|
||||||
|
C3
|
||||||
|
C4
|
||||||
|
C5
|
||||||
|
C6
|
||||||
|
C7
|
||||||
|
C8
|
||||||
|
C9
|
||||||
|
C10
|
||||||
|
C11
|
||||||
|
C12
|
||||||
|
C13
|
||||||
|
C14
|
||||||
|
C15
|
||||||
|
)
|
||||||
|
|
||||||
|
func (Reg) IsArg() {}
|
||||||
|
func (r Reg) String(pc uint64) string {
|
||||||
|
s := "%"
|
||||||
|
switch {
|
||||||
|
case R0 <= r && r <= R15:
|
||||||
|
return fmt.Sprintf("%sr%d", s, int(r-R0))
|
||||||
|
case F0 <= r && r <= F15:
|
||||||
|
return fmt.Sprintf("%sf%d", s, int(r-F0))
|
||||||
|
case A0 <= r && r <= A15:
|
||||||
|
return fmt.Sprintf("%sa%d", s, int(r-A0))
|
||||||
|
case C0 <= r && r <= C15:
|
||||||
|
return fmt.Sprintf("%sc%d", s, int(r-C0))
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Reg(%d)", int(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VReg is a vector register. The zero value means V0, not the absence of a register.
|
||||||
|
|
||||||
|
type VReg uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
V0 VReg = iota
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
func (VReg) IsArg() {}
|
||||||
|
func (r VReg) String(pc uint64) string {
|
||||||
|
s := "%"
|
||||||
|
if V0 <= r && r <= V31 {
|
||||||
|
return fmt.Sprintf("%sv%d", s, int(r-V0))
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("VReg(%d)", int(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imm represents an immediate number.
|
||||||
|
type Imm uint32
|
||||||
|
|
||||||
|
func (Imm) IsArg() {}
|
||||||
|
func (i Imm) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d", uint32(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign8 represents an 8-bit signed immediate number.
|
||||||
|
type Sign8 int8
|
||||||
|
|
||||||
|
func (Sign8) IsArg() {}
|
||||||
|
func (i Sign8) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign16 represents an 16-bit signed immediate number.
|
||||||
|
type Sign16 int16
|
||||||
|
|
||||||
|
func (Sign16) IsArg() {}
|
||||||
|
func (i Sign16) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign32 represents an 32-bit signed immediate number.
|
||||||
|
type Sign32 int32
|
||||||
|
|
||||||
|
func (Sign32) IsArg() {}
|
||||||
|
func (i Sign32) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask represents an 4-bit mask value
|
||||||
|
type Mask uint8
|
||||||
|
|
||||||
|
func (Mask) IsArg() {}
|
||||||
|
func (i Mask) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len represents an 8-bit type holds 4/8-bit Len argument
|
||||||
|
type Len uint8
|
||||||
|
|
||||||
|
func (Len) IsArg() {}
|
||||||
|
func (i Len) String(pc uint64) string {
|
||||||
|
return fmt.Sprintf("%d,", uint16(i)+1)
|
||||||
|
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,636 @@
|
||||||
|
// Copyright 2024 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.
|
||||||
|
|
||||||
|
// s390xmap constructs the s390x opcode map from the instruction set CSV file.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// s390map [-fmt=format] s390x.csv
|
||||||
|
//
|
||||||
|
// The known output formats are:
|
||||||
|
//
|
||||||
|
// text (default) - print decoding tree in text form
|
||||||
|
// decoder - print decoding tables for the s390xasm package
|
||||||
|
// encoder - generate a self-contained file which can be used to encode
|
||||||
|
// go obj.Progs into machine code
|
||||||
|
// asm - generate a GNU asm file which can be compiled by gcc containing
|
||||||
|
// all opcodes discovered in s390x.csv using macro friendly arguments.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
gofmt "go/format"
|
||||||
|
asm "golang.org/x/arch/s390x/s390xasm"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var format = flag.String("fmt", "text", "output format: text, decoder, asm")
|
||||||
|
var debug = flag.Bool("debug", false, "enable debugging output")
|
||||||
|
|
||||||
|
var inputFile string
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage: s390xmap [-fmt=format] s390x.csv\n")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("s390xmap: ")
|
||||||
|
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
if flag.NArg() != 1 {
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
inputFile = flag.Arg(0)
|
||||||
|
|
||||||
|
var printTyp func(*Prog)
|
||||||
|
switch *format {
|
||||||
|
default:
|
||||||
|
log.Fatalf("unknown output format %q", *format)
|
||||||
|
case "text":
|
||||||
|
printTyp = printText
|
||||||
|
case "decoder":
|
||||||
|
printTyp = printDecoder
|
||||||
|
case "asm":
|
||||||
|
printTyp = printASM
|
||||||
|
case "encoder":
|
||||||
|
printTyp = printEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := readCSV(flag.Arg(0))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Printf("Parsed %d instruction forms.", len(p.Insts))
|
||||||
|
printTyp(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readCSV reads the CSV file and returns the corresponding Prog.
|
||||||
|
// It may print details about problems to standard error using the log package.
|
||||||
|
func readCSV(file string) (*Prog, error) {
|
||||||
|
// Read input.
|
||||||
|
// Skip leading blank and # comment lines.
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
csvReader := csv.NewReader(f)
|
||||||
|
csvReader.Comment = '#'
|
||||||
|
table, err := csvReader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing %s: %v", file, err)
|
||||||
|
}
|
||||||
|
if len(table) == 0 {
|
||||||
|
return nil, fmt.Errorf("empty csv input")
|
||||||
|
}
|
||||||
|
if len(table[0]) < 3 {
|
||||||
|
return nil, fmt.Errorf("csv too narrow: need at least four columns")
|
||||||
|
}
|
||||||
|
|
||||||
|
p := &Prog{}
|
||||||
|
for _, row := range table {
|
||||||
|
add(p, row[0], row[1], row[2], row[3])
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Prog struct {
|
||||||
|
Insts []Inst
|
||||||
|
OpRanges map[string]string
|
||||||
|
nextOrder int // Next position value (used for Insts[x].order)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
Name string
|
||||||
|
BitField asm.BitField
|
||||||
|
Type asm.ArgType
|
||||||
|
flags uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Field) String() string {
|
||||||
|
return fmt.Sprintf("%v(%s%v)", f.Type, f.Name, f.BitField)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Inst struct {
|
||||||
|
Text string
|
||||||
|
Encoding string
|
||||||
|
Op string
|
||||||
|
Mask uint64
|
||||||
|
Value uint64
|
||||||
|
DontCare uint64
|
||||||
|
Len uint16
|
||||||
|
Fields []Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Inst) String() string {
|
||||||
|
return fmt.Sprintf("%s (%s) %08x/%08x %v (%s)", i.Op, i.Encoding, i.Value, i.Mask, i.Fields, i.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Arg struct {
|
||||||
|
Name string
|
||||||
|
Bits int8
|
||||||
|
Offs int8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arg) String() string {
|
||||||
|
return fmt.Sprintf("%s[%d:%d]", a.Name, a.Offs, a.Offs+a.Bits-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arg) Maximum() int {
|
||||||
|
return 1<<uint8(a.Bits) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arg) BitMask() uint64 {
|
||||||
|
return uint64(a.Maximum()) << a.Shift()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arg) Shift() uint8 {
|
||||||
|
return uint8(64 - a.Offs - a.Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Args []Arg
|
||||||
|
|
||||||
|
func (as Args) String() string {
|
||||||
|
ss := make([]string, len(as))
|
||||||
|
for i := range as {
|
||||||
|
ss[i] = as[i].String()
|
||||||
|
}
|
||||||
|
return strings.Join(ss, "|")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as Args) Find(name string) int {
|
||||||
|
for i := range as {
|
||||||
|
if as[i].Name == name {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *Args) Append(a Arg) {
|
||||||
|
*as = append(*as, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *Args) Delete(i int) {
|
||||||
|
*as = append((*as)[:i], (*as)[i+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as Args) Clone() Args {
|
||||||
|
return append(Args{}, as...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Arg) isDontCare() bool {
|
||||||
|
return a.Name[0] == '/' && a.Name == strings.Repeat("/", len(a.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the string encoding into an Args. The encoding string loosely matches the regex
|
||||||
|
// (arg@bitpos|)+
|
||||||
|
func parseFields(encoding, text string) Args {
|
||||||
|
var err error
|
||||||
|
var args Args
|
||||||
|
|
||||||
|
fields := strings.Split(encoding, "|")
|
||||||
|
|
||||||
|
for i, f := range fields {
|
||||||
|
name, off := "", -1
|
||||||
|
if f == "" {
|
||||||
|
off = 64
|
||||||
|
if i == 0 || i != len(fields)-1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f)
|
||||||
|
panic("Invalid encoding entry.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
j := strings.Index(f, "@")
|
||||||
|
if j < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: wrong %d-th encoding field: %q\n", text, i, f)
|
||||||
|
panic("Invalid encoding entry.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
off, err = strconv.Atoi(f[j+1:])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "err for: %s has: %s for %s\n", f[:j], err, f[j+1:])
|
||||||
|
}
|
||||||
|
name = f[:j]
|
||||||
|
}
|
||||||
|
if len(args) > 0 {
|
||||||
|
args[len(args)-1].Bits += int8(off)
|
||||||
|
}
|
||||||
|
if name != "" && name != "??" {
|
||||||
|
arg := Arg{Name: name, Offs: int8(off), Bits: int8(-off)}
|
||||||
|
args.Append(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the Mask (usually Opcode + secondary Opcode bitfields),
|
||||||
|
// the Value (the expected value under the mask), and
|
||||||
|
// reserved bits (i.e the // fields which should be set to 0)
|
||||||
|
func computeMaskValueReserved(args Args, text string) (mask, value, reserved uint64) {
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
arg := args[i]
|
||||||
|
v, err := strconv.Atoi(arg.Name)
|
||||||
|
switch {
|
||||||
|
case err == nil && v >= 0: // is a numbered field
|
||||||
|
if v < 0 || v > arg.Maximum() {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: field %s value (%d) is out of range (%d-bit)\n", text, arg, v, arg.Bits)
|
||||||
|
}
|
||||||
|
mask |= arg.BitMask()
|
||||||
|
value |= uint64(v) << arg.Shift()
|
||||||
|
args.Delete(i)
|
||||||
|
i--
|
||||||
|
case arg.Name[0] == '/': // don't care
|
||||||
|
if arg.Name != strings.Repeat("/", len(arg.Name)) {
|
||||||
|
log.Fatalf("%s: arg %v named like a don't care bit, but it's not", text, arg)
|
||||||
|
}
|
||||||
|
reserved |= arg.BitMask()
|
||||||
|
args.Delete(i)
|
||||||
|
i--
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sanity checks
|
||||||
|
if mask&reserved != 0 {
|
||||||
|
log.Fatalf("%s: mask (%08x) and don't care (%08x) collide", text, mask, reserved)
|
||||||
|
}
|
||||||
|
if value&^mask != 0 {
|
||||||
|
log.Fatalf("%s: value (%08x) out of range of mask (%08x)", text, value, mask)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Imm_signed_8bit_check(op string) bool {
|
||||||
|
imm_8 := []string{"ASI", "AGSI", "ALSI", "ALGSI", "CIB", "CGIB", "CIJ", "CGIJ"}
|
||||||
|
var ret bool
|
||||||
|
ret = false
|
||||||
|
for _, str := range imm_8 {
|
||||||
|
if strings.Compare(op, str) == 0 {
|
||||||
|
ret = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func Imm_signed_16bit_check(op string) bool {
|
||||||
|
imm_16 := []string{"AHI", "AGHI", "ALHSIK", "ALGHSIK", "AHIK", "AGHIK", "LHI", "LGHI", "MVGHI", "CIT", "CGIT", "CGHI", "CGHSI", "CHHSI", "CHI", "CHSI", "CRJ", "CGRJ"}
|
||||||
|
var ret bool
|
||||||
|
ret = false
|
||||||
|
for _, str := range imm_16 {
|
||||||
|
if strings.Compare(op, str) == 0 {
|
||||||
|
ret = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func Imm_signed_32bit_check(op string) bool {
|
||||||
|
imm_32 := []string{"AFI", "AGFI", "AIH", "CIH", "CFI", "CGFI", "CRL", "STRL", "STGRL"}
|
||||||
|
var ret bool
|
||||||
|
ret = false
|
||||||
|
for _, str := range imm_32 {
|
||||||
|
if strings.Compare(op, str) == 0 {
|
||||||
|
ret = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func check_flags(flags string) bool {
|
||||||
|
if strings.Contains(flags, "Da") {
|
||||||
|
return true
|
||||||
|
} else if strings.Contains(flags, "Db") {
|
||||||
|
return true
|
||||||
|
} else if strings.Contains(flags, "Dt") {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a row from the CSV describing the instructions, and place the
|
||||||
|
// detected instructions into p. One entry may generate multiple intruction
|
||||||
|
// entries as each extended mnemonic listed in text is treated like a unique
|
||||||
|
// instruction.
|
||||||
|
// func add(p *Prog, text, mnemonics, encoding, format string) {
|
||||||
|
func add(p *Prog, text, mnemonics, encoding, flags string) {
|
||||||
|
// Parse encoding, building size and offset of each field.
|
||||||
|
// The first field in the encoding is the smallest offset.
|
||||||
|
// And note the MSB is bit 0, not bit 31.
|
||||||
|
// Example: "31@0|RS@6|RA@11|///@16|26@21|Rc@31|"
|
||||||
|
var args Args
|
||||||
|
|
||||||
|
args = parseFields(encoding, text)
|
||||||
|
mask, value, dontCare := computeMaskValueReserved(args, text)
|
||||||
|
|
||||||
|
// split mnemonics into individual instructions
|
||||||
|
// example: "b target_addr (AA=0 LK=0)|ba target_addr (AA=1 LK=0)|bl target_addr (AA=0 LK=1)|bla target_addr (AA=1 LK=1)"
|
||||||
|
inst := Inst{Text: text, Encoding: mnemonics, Value: value, Mask: mask, DontCare: dontCare}
|
||||||
|
|
||||||
|
// order inst.Args according to mnemonics order
|
||||||
|
for i, opr := range operandRe.FindAllString(mnemonics, -1) {
|
||||||
|
if i == 0 { // operation
|
||||||
|
inst.Op = opr
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
field := Field{Name: opr}
|
||||||
|
typ := asm.TypeUnknown
|
||||||
|
flag := uint16(0)
|
||||||
|
switch opr {
|
||||||
|
case "R1", "R2", "R3":
|
||||||
|
s := strings.Split(mnemonics, " ")
|
||||||
|
switch opr {
|
||||||
|
case "R1":
|
||||||
|
switch s[0] {
|
||||||
|
case "CPDT", "CPXT", "CDXT", "CZXT", "CZDT":
|
||||||
|
typ = asm.TypeFPReg
|
||||||
|
flag = 0x2
|
||||||
|
case "CUXTR", "EEXTR", "EEDTR", "EFPC", "ESXTR", "ESDTR", "LGDR", "SFPC", "SFASR":
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
case "CPYA", "LAM", "LAMY", "STAM", "STAMY", "SAR", "TAR":
|
||||||
|
typ = asm.TypeACReg
|
||||||
|
flag = 0x3
|
||||||
|
case "LCTL", "LCTLG", "STCTL", "STCTG":
|
||||||
|
typ = asm.TypeCReg
|
||||||
|
flag = 0x4
|
||||||
|
default:
|
||||||
|
if check_flags(flags) {
|
||||||
|
if strings.Contains(text, "CONVERT TO") {
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeFPReg
|
||||||
|
flag = 0x2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "R2":
|
||||||
|
switch s[0] {
|
||||||
|
case "IEXTR", "IEDTR", "LDGR", "RRXTR", "RRDTR":
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
case "CPYA", "EAR":
|
||||||
|
typ = asm.TypeACReg
|
||||||
|
flag = 0x3
|
||||||
|
default:
|
||||||
|
if check_flags(flags) {
|
||||||
|
if strings.Contains(text, "CONVERT FROM") {
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeFPReg
|
||||||
|
flag = 0x2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "R3":
|
||||||
|
switch s[0] {
|
||||||
|
case "LAM", "LAMY", "STAM", "STAMY":
|
||||||
|
typ = asm.TypeACReg
|
||||||
|
flag = 0x3
|
||||||
|
case "LCTL", "LCTLG", "STCTL", "STCTG":
|
||||||
|
typ = asm.TypeCReg
|
||||||
|
flag = 0x4
|
||||||
|
default:
|
||||||
|
if check_flags(flags) {
|
||||||
|
typ = asm.TypeFPReg
|
||||||
|
flag = 0x2
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeReg
|
||||||
|
flag = 0x1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "I", "I1", "I2", "I3", "I4", "I5":
|
||||||
|
flag = 0x0
|
||||||
|
switch opr {
|
||||||
|
case "I", "I1":
|
||||||
|
typ = asm.TypeImmUnsigned
|
||||||
|
|
||||||
|
case "I2":
|
||||||
|
if Imm_signed_8bit_check(inst.Op) {
|
||||||
|
typ = asm.TypeImmSigned8
|
||||||
|
break
|
||||||
|
} else if Imm_signed_16bit_check(inst.Op) { // "ASI", "AGSI", "ALSI", "ALGSI"
|
||||||
|
typ = asm.TypeImmSigned16
|
||||||
|
break
|
||||||
|
} else if Imm_signed_32bit_check(inst.Op) { // "AHI", "AGHI", "AHIK", "AGHIK", "LHI", "LGHI"
|
||||||
|
typ = asm.TypeImmSigned32
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeImmUnsigned
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "I3", "I4", "I5":
|
||||||
|
typ = asm.TypeImmUnsigned
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case "RI2", "RI3", "RI4":
|
||||||
|
flag = 0x80
|
||||||
|
i := args.Find(opr)
|
||||||
|
count := uint8(args[i].Bits)
|
||||||
|
if count == 12 {
|
||||||
|
typ = asm.TypeRegImSigned12
|
||||||
|
break
|
||||||
|
} else if count == 16 {
|
||||||
|
typ = asm.TypeRegImSigned16
|
||||||
|
break
|
||||||
|
} else if count == 24 {
|
||||||
|
typ = asm.TypeRegImSigned24
|
||||||
|
break
|
||||||
|
} else if count == 32 {
|
||||||
|
typ = asm.TypeRegImSigned32
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "M1", "M3", "M4", "M5", "M6":
|
||||||
|
flag = 0x800
|
||||||
|
typ = asm.TypeMask
|
||||||
|
|
||||||
|
case "B1", "B2", "B3", "B4":
|
||||||
|
typ = asm.TypeBaseReg
|
||||||
|
flag = 0x20 | 0x01
|
||||||
|
|
||||||
|
case "X2":
|
||||||
|
typ = asm.TypeIndexReg
|
||||||
|
flag = 0x40 | 0x01
|
||||||
|
|
||||||
|
case "D1", "D2", "D3", "D4":
|
||||||
|
flag = 0x10
|
||||||
|
i := args.Find(opr)
|
||||||
|
if uint8(args[i].Bits) == 20 {
|
||||||
|
typ = asm.TypeDispSigned20
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
typ = asm.TypeDispUnsigned
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case "L1", "L2":
|
||||||
|
typ = asm.TypeLen
|
||||||
|
flag = 0x10
|
||||||
|
case "V1", "V2", "V3", "V4", "V5", "V6":
|
||||||
|
typ = asm.TypeVecReg
|
||||||
|
flag = 0x08
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ == asm.TypeUnknown {
|
||||||
|
log.Fatalf("%s %s unknown type for opr %s", text, inst, opr)
|
||||||
|
}
|
||||||
|
field.Type = typ
|
||||||
|
field.flags = flag
|
||||||
|
var f1 asm.BitField
|
||||||
|
i := args.Find(opr)
|
||||||
|
if i < 0 {
|
||||||
|
log.Fatalf("%s: couldn't find %s in %s", text, opr, args)
|
||||||
|
}
|
||||||
|
f1.Offs, f1.Bits = uint8(args[i].Offs), uint8(args[i].Bits)
|
||||||
|
field.BitField = f1
|
||||||
|
inst.Fields = append(inst.Fields, field)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(inst.Op, "V") || strings.Contains(inst.Op, "WFC") || strings.Contains(inst.Op, "WFK") { //Check Vector Instructions
|
||||||
|
Bits := asm.BitField{Offs: 36, Bits: 4}
|
||||||
|
field := Field{Name: "RXB", BitField: Bits, Type: asm.TypeImmUnsigned, flags: 0xC00}
|
||||||
|
inst.Fields = append(inst.Fields, field)
|
||||||
|
}
|
||||||
|
if *debug {
|
||||||
|
fmt.Printf("%v\n", inst)
|
||||||
|
}
|
||||||
|
p.Insts = append(p.Insts, inst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// operandRe matches each operand (including opcode) in instruction mnemonics
|
||||||
|
var operandRe = regexp.MustCompile(`([[:alpha:]][[:alnum:]_]*\.?)`)
|
||||||
|
|
||||||
|
// printText implements the -fmt=text mode, which is not implemented (yet?).
|
||||||
|
func printText(p *Prog) {
|
||||||
|
log.Fatal("-fmt=text not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// printEncoder implements the -fmt=encoder mode. which is not implemented (yet?).
|
||||||
|
func printEncoder(p *Prog) {
|
||||||
|
log.Fatal("-fmt=encoder not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func printASM(p *Prog) {
|
||||||
|
fmt.Printf("#include \"hack.h\"\n")
|
||||||
|
fmt.Printf(".text\n")
|
||||||
|
for _, inst := range p.Insts {
|
||||||
|
fmt.Printf("\t%s\n", inst.Encoding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// argFieldName constructs a name for the argField
|
||||||
|
func argFieldName(f Field) string {
|
||||||
|
ns := []string{"ap", f.Type.String()}
|
||||||
|
b := f.BitField
|
||||||
|
ns = append(ns, fmt.Sprintf("%d_%d", b.Offs, b.Offs+b.Bits-1))
|
||||||
|
return strings.Join(ns, "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
// printDecoder implements the -fmt=decoder mode.
|
||||||
|
// It emits the tables.go for package armasm's decoder.
|
||||||
|
func printDecoder(p *Prog) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
fmt.Fprintf(&buf, "// Code generated by s390xmap -fmt=decoder %s DO NOT EDIT.\n", inputFile)
|
||||||
|
fmt.Fprintf(&buf, "\n")
|
||||||
|
|
||||||
|
fmt.Fprintf(&buf, "package s390xasm\n\n")
|
||||||
|
|
||||||
|
// Build list of opcodes, using the csv order (which corresponds to ISA docs order)
|
||||||
|
m := map[string]bool{}
|
||||||
|
fmt.Fprintf(&buf, "const (\n\t_ Op = iota\n")
|
||||||
|
for i := 0; i < len(p.Insts); i++ {
|
||||||
|
name := p.Insts[i].Op
|
||||||
|
switch name {
|
||||||
|
case "CUUTF", "CUTFU", "PPNO":
|
||||||
|
m[name] = false
|
||||||
|
p.Insts = append(p.Insts[:i], p.Insts[i+1:]...)
|
||||||
|
i--
|
||||||
|
default:
|
||||||
|
m[name] = true
|
||||||
|
}
|
||||||
|
if ok := m[name]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "\t%s\n", name)
|
||||||
|
}
|
||||||
|
fmt.Fprint(&buf, ")\n\n\n")
|
||||||
|
|
||||||
|
// Emit slice mapping opcode number to name string.
|
||||||
|
m = map[string]bool{}
|
||||||
|
fmt.Fprintf(&buf, "var opstr = [...]string{\n")
|
||||||
|
for _, inst := range p.Insts {
|
||||||
|
name := inst.Op
|
||||||
|
if ok := m[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[name] = true
|
||||||
|
fmt.Fprintf(&buf, "\t%s: %q,\n", inst.Op, strings.ToLower(inst.Op))
|
||||||
|
}
|
||||||
|
fmt.Fprint(&buf, "}\n\n\n")
|
||||||
|
|
||||||
|
// print out argFields
|
||||||
|
fmt.Fprintf(&buf, "var (\n")
|
||||||
|
m = map[string]bool{}
|
||||||
|
for _, inst := range p.Insts {
|
||||||
|
for _, f := range inst.Fields {
|
||||||
|
name := argFieldName(f)
|
||||||
|
if ok := m[name]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[name] = true
|
||||||
|
fmt.Fprintf(&buf, "\t%s = &argField{Type: %#v, flags: %#x, BitField: BitField", name, f.Type, f.flags)
|
||||||
|
b := f.BitField
|
||||||
|
fmt.Fprintf(&buf, "{%d, %d }", b.Offs, b.Bits)
|
||||||
|
fmt.Fprintf(&buf, "}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprint(&buf, ")\n\n\n")
|
||||||
|
|
||||||
|
// Emit decoding table.
|
||||||
|
fmt.Fprintf(&buf, "var instFormats = [...]instFormat{\n")
|
||||||
|
for _, inst := range p.Insts {
|
||||||
|
m, v, dc := inst.Mask, inst.Value, inst.DontCare
|
||||||
|
fmt.Fprintf(&buf, "\t{ %s, %#x, %#x, %#x,", inst.Op, m, v, dc)
|
||||||
|
fmt.Fprintf(&buf, " // %s (%s)\n\t\t[8]*argField{", inst.Text, inst.Encoding)
|
||||||
|
for _, f := range inst.Fields {
|
||||||
|
fmt.Fprintf(&buf, "%s, ", argFieldName(f))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "}},\n")
|
||||||
|
}
|
||||||
|
fmt.Fprint(&buf, "}\n\n")
|
||||||
|
|
||||||
|
out, err := gofmt.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("gofmt error: %v", err)
|
||||||
|
fmt.Printf("%s", buf.Bytes())
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s", out)
|
||||||
|
}
|
||||||
|
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2024 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 -march=z16 support.
|
||||||
|
// s390xutil runs a series of commands like:
|
||||||
|
// go run map.go -fmt=asm ../s390x.csv > asm.S
|
||||||
|
// /usr/bin/gcc -c asm.S -march=z16
|
||||||
|
// /usr/bin/objdump -d asm.o
|
||||||
|
// to create the file decode_generated.txt used to verify the disassembler.
|
||||||
|
//
|
||||||
|
// Note, the Go disassembler is not expected to support every extended
|
||||||
|
// mnemonic, but it should support those which frequently show up in object
|
||||||
|
// files compiled by the Go toolchain.
|
||||||
|
|
||||||
|
|
||||||
|
#define R1 8
|
||||||
|
#define R2 0
|
||||||
|
#define R3 0
|
||||||
|
|
||||||
|
#define X2 2
|
||||||
|
|
||||||
|
#define L1 4
|
||||||
|
#define L2 4
|
||||||
|
|
||||||
|
#define B1 2
|
||||||
|
#define B2 1
|
||||||
|
#define B3 6
|
||||||
|
#define B4 8
|
||||||
|
|
||||||
|
#define D1 6
|
||||||
|
#define D2 11
|
||||||
|
#define D3 182
|
||||||
|
#define D4 205
|
||||||
|
|
||||||
|
#define V1 18
|
||||||
|
#define V2 3
|
||||||
|
#define V3 5
|
||||||
|
#define V4 8
|
||||||
|
|
||||||
|
#define I 124
|
||||||
|
#define I1 12
|
||||||
|
#define I2 8
|
||||||
|
#define I3 9
|
||||||
|
#define I4 105
|
||||||
|
#define I5 18
|
||||||
|
|
||||||
|
#define RI2 0
|
||||||
|
#define RI3 294
|
||||||
|
#define RI4 -168
|
||||||
|
|
||||||
|
#define M1 7
|
||||||
|
#define M3 3
|
||||||
|
#define M4 1
|
||||||
|
#define M5 9
|
||||||
|
#define M6 11
|
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright 2024 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 s390x objdump via
|
||||||
|
// go run util.go
|
||||||
|
//
|
||||||
|
// This requires "/usr/bin/gcc" and "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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Emit a test file using the generator called name.txt. This requires
|
||||||
|
// a GCC toolchain which supports -march=z16.
|
||||||
|
func genOutput(name, tcPfx string, generator func(io.Writer)) {
|
||||||
|
// Generate object code from gcc
|
||||||
|
cmd := exec.Command(tcPfx+"gcc", "-c", "-march=z16", "-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
|
||||||
|
}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
ln := spacere.Split(scanner.Text(), -1)
|
||||||
|
var cnt int16
|
||||||
|
if len(ln) >= 5 {
|
||||||
|
v, _ := strconv.ParseInt(ln[2], 16, 16)
|
||||||
|
if (v >> 6 & 0x3) == 0 {
|
||||||
|
cnt = 2
|
||||||
|
} else if v>>6&0x3 == 1 || v>>6&0x3 == 2 {
|
||||||
|
cnt = 4
|
||||||
|
} else {
|
||||||
|
cnt = 6
|
||||||
|
}
|
||||||
|
opc := strings.Join(ln[2:cnt+2], "")
|
||||||
|
dec := strings.Join(ln[cnt+2:], " ")
|
||||||
|
fmt.Fprintf(outf, "%12s|\tgnu\t%-18s\n", opc, dec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate representative instructions for all[1] instructions in s390x.csv.
|
||||||
|
//
|
||||||
|
// [1] See hack.h for a few minor, exceptional workarounds.
|
||||||
|
func emitGenerated(out io.Writer) {
|
||||||
|
cmd := exec.Command("go", "run", "../s390xmap/map.go", "-fmt=asm", "../s390x.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_generated", "/usr/bin/", emitGenerated)
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче