1// Copyright 2014 The Go Authors.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ppc64asm
6
7import (
8	"encoding/binary"
9	"fmt"
10	"log"
11)
12
13const debugDecode = false
14
15const prefixOpcode = 1
16
17// instFormat is a decoding rule for one specific instruction form.
18// an instruction ins matches the rule if ins&Mask == Value
19// DontCare bits should be zero, but the machine might not reject
20// ones in those bits, they are mainly reserved for future expansion
21// of the instruction set.
22// The Args are stored in the same order as the instruction manual.
23//
24// Prefixed instructions are stored as:
25//
26//	prefix << 32 | suffix,
27//
28// Regular instructions are:
29//
30//	inst << 32
31type instFormat struct {
32	Op       Op
33	Mask     uint64
34	Value    uint64
35	DontCare uint64
36	Args     [6]*argField
37}
38
39// argField indicate how to decode an argument to an instruction.
40// First parse the value from the BitFields, shift it left by Shift
41// bits to get the actual numerical value.
42type argField struct {
43	Type  ArgType
44	Shift uint8
45	BitFields
46}
47
48// Parse parses the Arg out from the given binary instruction i.
49func (a argField) Parse(i [2]uint32) Arg {
50	switch a.Type {
51	default:
52		return nil
53	case TypeUnknown:
54		return nil
55	case TypeReg:
56		return R0 + Reg(a.BitFields.Parse(i))
57	case TypeCondRegBit:
58		return Cond0LT + CondReg(a.BitFields.Parse(i))
59	case TypeCondRegField:
60		return CR0 + CondReg(a.BitFields.Parse(i))
61	case TypeFPReg:
62		return F0 + Reg(a.BitFields.Parse(i))
63	case TypeVecReg:
64		return V0 + Reg(a.BitFields.Parse(i))
65	case TypeVecSReg:
66		return VS0 + Reg(a.BitFields.Parse(i))
67	case TypeVecSpReg:
68		return VS0 + Reg(a.BitFields.Parse(i))*2
69	case TypeMMAReg:
70		return A0 + Reg(a.BitFields.Parse(i))
71	case TypeSpReg:
72		return SpReg(a.BitFields.Parse(i))
73	case TypeImmSigned:
74		return Imm(a.BitFields.ParseSigned(i) << a.Shift)
75	case TypeImmUnsigned:
76		return Imm(a.BitFields.Parse(i) << a.Shift)
77	case TypePCRel:
78		return PCRel(a.BitFields.ParseSigned(i) << a.Shift)
79	case TypeLabel:
80		return Label(a.BitFields.ParseSigned(i) << a.Shift)
81	case TypeOffset:
82		return Offset(a.BitFields.ParseSigned(i) << a.Shift)
83	case TypeNegOffset:
84		// An oddball encoding of offset for hashchk and similar.
85		// e.g hashchk offset is 0b1111111000000000 | DX << 8 | D << 3
86		off := a.BitFields.ParseSigned(i) << a.Shift
87		neg := int64(-1) << (int(a.Shift) + a.BitFields.NumBits())
88		return Offset(neg | off)
89	}
90}
91
92type ArgType int8
93
94const (
95	TypeUnknown      ArgType = iota
96	TypePCRel                // PC-relative address
97	TypeLabel                // absolute address
98	TypeReg                  // integer register
99	TypeCondRegBit           // conditional register bit (0-31)
100	TypeCondRegField         // conditional register field (0-7)
101	TypeFPReg                // floating point register
102	TypeVecReg               // vector register
103	TypeVecSReg              // VSX register
104	TypeVecSpReg             // VSX register pair (even only encoding)
105	TypeMMAReg               // MMA register
106	TypeSpReg                // special register (depends on Op)
107	TypeImmSigned            // signed immediate
108	TypeImmUnsigned          // unsigned immediate/flag/mask, this is the catch-all type
109	TypeOffset               // signed offset in load/store
110	TypeNegOffset            // A negative 16 bit value 0b1111111xxxxx000 encoded as 0bxxxxx (e.g in the hashchk instruction)
111	TypeLast                 // must be the last one
112)
113
114func (t ArgType) String() string {
115	switch t {
116	default:
117		return fmt.Sprintf("ArgType(%d)", int(t))
118	case TypeUnknown:
119		return "Unknown"
120	case TypeReg:
121		return "Reg"
122	case TypeCondRegBit:
123		return "CondRegBit"
124	case TypeCondRegField:
125		return "CondRegField"
126	case TypeFPReg:
127		return "FPReg"
128	case TypeVecReg:
129		return "VecReg"
130	case TypeVecSReg:
131		return "VecSReg"
132	case TypeVecSpReg:
133		return "VecSpReg"
134	case TypeMMAReg:
135		return "MMAReg"
136	case TypeSpReg:
137		return "SpReg"
138	case TypeImmSigned:
139		return "ImmSigned"
140	case TypeImmUnsigned:
141		return "ImmUnsigned"
142	case TypePCRel:
143		return "PCRel"
144	case TypeLabel:
145		return "Label"
146	case TypeOffset:
147		return "Offset"
148	case TypeNegOffset:
149		return "NegOffset"
150	}
151}
152
153func (t ArgType) GoString() string {
154	s := t.String()
155	if t > 0 && t < TypeLast {
156		return "Type" + s
157	}
158	return s
159}
160
161var (
162	// Errors
163	errShort   = fmt.Errorf("truncated instruction")
164	errUnknown = fmt.Errorf("unknown instruction")
165)
166
167var decoderCover []bool
168
169// Decode decodes the leading bytes in src as a single instruction using
170// byte order ord.
171func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) {
172	if len(src) < 4 {
173		return inst, errShort
174	}
175	if decoderCover == nil {
176		decoderCover = make([]bool, len(instFormats))
177	}
178	inst.Len = 4
179	ui_extn := [2]uint32{ord.Uint32(src[:inst.Len]), 0}
180	ui := uint64(ui_extn[0]) << 32
181	inst.Enc = ui_extn[0]
182	opcode := inst.Enc >> 26
183	if opcode == prefixOpcode {
184		// This is a prefixed instruction
185		inst.Len = 8
186		if len(src) < 8 {
187			return inst, errShort
188		}
189		// Merge the suffixed word.
190		ui_extn[1] = ord.Uint32(src[4:inst.Len])
191		ui |= uint64(ui_extn[1])
192		inst.SuffixEnc = ui_extn[1]
193	}
194	for i, iform := range instFormats {
195		if ui&iform.Mask != iform.Value {
196			continue
197		}
198		if ui&iform.DontCare != 0 {
199			if debugDecode {
200				log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op)
201			}
202			// to match GNU objdump (libopcodes), we ignore don't care bits
203		}
204		for i, argfield := range iform.Args {
205			if argfield == nil {
206				break
207			}
208			inst.Args[i] = argfield.Parse(ui_extn)
209		}
210		inst.Op = iform.Op
211		if debugDecode {
212			log.Printf("%#x: search entry %d", ui, i)
213			continue
214		}
215		break
216	}
217	if inst.Op == 0 && inst.Enc != 0 {
218		return inst, errUnknown
219	}
220	return inst, nil
221}
222