1/*	$OpenBSD: db_disasm.c,v 1.4 2024/05/22 05:51:49 jsg Exp $	*/
2/*
3 * Copyright (c) 1996, 2001, 2003 Dale Rahn. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/param.h>
27#include <sys/proc.h>
28#include <sys/systm.h>
29
30#include <machine/db_machdep.h>
31
32#include <ddb/db_access.h>
33#include <ddb/db_sym.h>
34#include <ddb/db_variables.h>
35#include <ddb/db_interface.h>
36#include <ddb/db_output.h>
37
38enum opf {
39	Opf_INVALID,
40	Opf_A,
41	Opf_A0,
42	Opf_B,
43	Opf_BI,
44	Opf_BI1,
45	Opf_BO,
46	Opf_CRM,
47	Opf_D,
48	Opf_S,
49	Opf_FM,
50	Opf_LK,
51	Opf_RC,
52	Opf_AA,
53	Opf_LI,
54	Opf_OE,
55	Opf_SR,
56	Opf_TO,
57	Opf_SIMM,
58	Opf_UIMM,
59	Opf_crbA,
60	Opf_crbB,
61	Opf_crbD,
62	Opf_crfD,
63	Opf_crfS,
64	Opf_d,
65	Opf_ds,
66	Opf_spr,
67	Opf_tbr,
68
69	Opf_BD,
70	Opf_C,
71
72	Opf_NB,
73
74	Opf_sh,
75	Opf_SH,
76	Opf_mb,
77	Opf_MB,
78	Opf_ME,
79};
80
81
82struct db_field {
83	char *name;
84	enum opf opf;
85} db_fields[] = {
86	{ "A",		Opf_A },
87	{ "A0",		Opf_A0 },
88	{ "B",		Opf_B },
89	{ "D",		Opf_D },
90	{ "S",		Opf_S },
91	{ "AA",		Opf_AA },
92	{ "LI",		Opf_LI },
93	{ "BD",		Opf_BD },
94	{ "BI",		Opf_BI },
95	{ "BI1",	Opf_BI1 },
96	{ "BO",		Opf_BO },
97	{ "CRM",	Opf_CRM },
98	{ "FM",		Opf_FM },
99	{ "LK",		Opf_LK },
100	{ "MB",		Opf_MB },
101	{ "ME",		Opf_ME },
102	{ "NB",		Opf_NB },
103	{ "OE",		Opf_OE },
104	{ "RC",		Opf_RC },
105	{ "SH",		Opf_SH },
106	{ "SR",		Opf_SR },
107	{ "TO",		Opf_TO },
108	{ "SIMM",	Opf_SIMM },
109	{ "UIMM",	Opf_UIMM },
110	{ "crbA",	Opf_crbA },
111	{ "crbB",	Opf_crbB },
112	{ "crbD",	Opf_crbD },
113	{ "crfD",	Opf_crfD },
114	{ "crfS",	Opf_crfS },
115	{ "d",		Opf_d },
116	{ "ds",		Opf_ds },
117	{ "mb",		Opf_mb },
118	{ "sh",		Opf_sh },
119	{ "spr",	Opf_spr },
120	{ "tbr",	Opf_tbr },
121	{ NULL,		0 }
122};
123
124struct opcode {
125	char *name;
126	u_int32_t mask;
127	u_int32_t code;
128	char *decode_str;
129};
130
131typedef u_int32_t instr_t;
132typedef void (op_class_func) (u_int32_t addr, instr_t instr);
133
134u_int32_t extract_field(u_int32_t value, u_int32_t base, u_int32_t width);
135void disasm_fields(u_int32_t addr, const struct opcode *popcode, instr_t instr,
136    char *disasm_str, size_t bufsize);
137void disasm_process_field(u_int32_t addr, instr_t instr, char **ppfmt,
138    char *ppoutput, size_t bufsize);
139void dis_ppc(u_int32_t addr, const struct opcode *opcodeset, instr_t instr);
140
141
142op_class_func op_ill, op_base;
143op_class_func op_cl_x13, op_cl_x1e, op_cl_x1f;
144op_class_func op_cl_x3a, op_cl_x3b;
145op_class_func op_cl_x3e, op_cl_x3f;
146
147op_class_func *opcodes_base[] = {
148/*x00*/	op_ill,		op_ill,		op_base,	op_ill,
149/*x04*/	op_ill,		op_ill,		op_ill,		op_base,
150/*x08*/	op_base,	op_base,	op_base,	op_base,
151/*x0C*/	op_base,	op_base,	op_base/*XXX*/,	op_base/*XXX*/,
152/*x10*/	op_base,	op_base,	op_base,	op_cl_x13,
153/*x14*/	op_base,	op_base,	op_ill,		op_base,
154/*x18*/	op_base,	op_base,	op_base,	op_base,
155/*x1C*/	op_base,	op_base,	op_cl_x1e,	op_cl_x1f,
156/*x20*/	op_base,	op_base,	op_base,	op_base,
157/*x24*/	op_base,	op_base,	op_base,	op_base,
158/*x28*/	op_base,	op_base,	op_base,	op_base,
159/*x2C*/	op_base,	op_base,	op_base,	op_base,
160/*x30*/	op_base,	op_base,	op_base,	op_base,
161/*x34*/	op_base,	op_base,	op_base,	op_base,
162/*x38*/	op_ill,		op_ill,		op_cl_x3a,	op_cl_x3b,
163/*x3C*/	op_ill,		op_ill,		op_cl_x3e,	op_cl_x3f
164};
165
166
167/* This table could be modified to make significant the "reserved" fields
168 * of the opcodes, But I didn't feel like it when typing in the table,
169 * I would recommend that this table be looked over for errors,
170 * This was derived from the table in Appendix A.2 of (Mot part # MPCFPE/AD)
171 * PowerPC Microprocessor Family: The Programming Environments
172 */
173
174const struct opcode opcodes[] = {
175	{ "tdi",	0xfc000000, 0x08000000, " %{TO},%{A},%{SIMM}" },
176	{ "twi",	0xfc000000, 0x0c000000, " %{TO},%{A},%{SIMM}" },
177
178	{ "mulli",	0xfc000000, 0x1c000000, " %{D},%{A},%{SIMM}" },
179	{ "subfic",	0xfc000000, 0x20000000, " %{D},%{A},%{SIMM}" },
180	{ "cmpli",	0xff800000, 0x28000000, " %{A},%{UIMM}" },
181	{ "cmpli",	0xfc400000, 0x28000000, " %{crfD}%{A}, %{UIMM}" },
182	{ "cmpi",	0xff800000, 0x2c000000, " %{A},%{SIMM}"},
183	{ "cmpi",	0xfc400000, 0x2c000000, " %{crfD}%{A},%{SIMM}" },
184	{ "addic",	0xfc000000, 0x30000000, " %{D},%{A},%{SIMM}" },
185	{ "addic.",	0xfc000000, 0x34000000, " %{D},%{A},%{SIMM}" },
186	{ "addi",	0xfc000000, 0x38000000, " %{D},%{A0}%{SIMM}" },
187	{ "addis",	0xfc000000, 0x3c000000, " %{D},%{A0}%{SIMM}" },
188	{ "sc",		0xffffffff, 0x44000002, "" },
189	{ "b",		0xfc000000, 0x40000000, "%{BO}%{LK}%{AA} %{BI}%{BD}" },
190	{ "b",		0xfc000000, 0x48000000, "%{LK}%{AA} %{LI}" },
191
192	{ "rlwimi",	0xfc000000, 0x50000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
193	{ "rlwinm",	0xfc000000, 0x54000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
194	{ "rlwnm",	0xfc000000, 0x5c000000, "%{RC} %{A},%{S},%{SH},%{MB},%{ME}" },
195
196	{ "ori",	0xfc000000, 0x60000000, " %{A},%{S},%{UIMM}" },
197	{ "oris",	0xfc000000, 0x64000000, " %{A},%{S},%{UIMM}" },
198	{ "xori",	0xfc000000, 0x68000000, " %{A},%{S},%{UIMM}" },
199	{ "xoris",	0xfc000000, 0x6c000000, " %{A},%{S},%{UIMM}" },
200
201	{ "andi.",	0xfc000000, 0x70000000, " %{A},%{S},%{UIMM}" },
202	{ "andis.",	0xfc000000, 0x74000000, " %{A},%{S},%{UIMM}" },
203
204	{ "lwz",	0xfc000000, 0x80000000, " %{D},%{d}(%{A})" },
205	{ "lwzu",	0xfc000000, 0x84000000, " %{D},%{d}(%{A})" },
206	{ "lbz",	0xfc000000, 0x88000000, " %{D},%{d}(%{A})" },
207	{ "lbzu",	0xfc000000, 0x8c000000, " %{D},%{d}(%{A})" },
208	{ "stw",	0xfc000000, 0x90000000, " %{S},%{d}(%{A})" },
209	{ "stwu",	0xfc000000, 0x94000000, " %{S},%{d}(%{A})" },
210	{ "stb",	0xfc000000, 0x98000000, " %{S},%{d}(%{A})" },
211	{ "stbu",	0xfc000000, 0x9c000000, " %{S},%{d}(%{A})" },
212
213	{ "lhz",	0xfc000000, 0xa0000000, " %{D},%{d}(%{A})" },
214	{ "lhzu",	0xfc000000, 0xa4000000, " %{D},%{d}(%{A})" },
215	{ "lha",	0xfc000000, 0xa8000000, " %{D},%{d}(%{A})" },
216	{ "lhau",	0xfc000000, 0xac000000, " %{D},%{d}(%{A})" },
217	{ "sth",	0xfc000000, 0xb0000000, " %{S},%{d}(%{A})" },
218	{ "sthu",	0xfc000000, 0xb4000000, " %{S},%{d}(%{A})" },
219	{ "lmw",	0xfc000000, 0xb8000000, " %{D},%{d}(%{A})" },
220	{ "stmw",	0xfc000000, 0xbc000000, " %{S},%{d}(%{A})" },
221
222	{ "lfs",	0xfc000000, 0xc0000000, " %{D},%{d}(%{A})" },
223	{ "lfsu",	0xfc000000, 0xc4000000, " %{D},%{d}(%{A})" },
224	{ "lfd",	0xfc000000, 0xc8000000, " %{D},%{d}(%{A})" },
225	{ "lfdu",	0xfc000000, 0xcc000000, " %{D},%{d}(%{A})" },
226
227	{ "stfs",	0xfc000000, 0xd0000000, " %{S},%{d}(%{A})" },
228	{ "stfsu",	0xfc000000, 0xd4000000, " %{S},%{d}(%{A})" },
229	{ "stfd",	0xfc000000, 0xd8000000, " %{S},%{d}(%{A})" },
230	{ "stfdu",	0xfc000000, 0xdc000000, " %{S},%{d}(%{A})" },
231	{ "",		0x0,		0x0, "" }
232
233};
234
235/* 13 * 4 = 4c */
236const struct opcode opcodes_13[] = {
237/* 0x13 << 2 */
238	{ "mcrf",	0xfc0007fe, 0x4c000000, " %{crfD},%{crfS}" },
239	{ "b",/*bclr*/	0xfc0007fe, 0x4c000020, "%{BO}lr%{LK} %{BI1}" },
240	{ "crnor",	0xfc0007fe, 0x4c000042, " %{crbD},%{crbA},%{crbB}" },
241	{ "rfi",	0xfc0007fe, 0x4c000064, "" },
242	{ "crandc",	0xfc0007fe, 0x4c000102, " %{crbD},%{crbA},%{crbB}" },
243	{ "isync",	0xfc0007fe, 0x4c00012c, "" },
244	{ "crxor",	0xfc0007fe, 0x4c000182, " %{crbD},%{crbA},%{crbB}" },
245	{ "crnand",	0xfc0007fe, 0x4c0001c2, " %{crbD},%{crbA},%{crbB}" },
246	{ "crand",	0xfc0007fe, 0x4c000202, " %{crbD},%{crbA},%{crbB}" },
247	{ "creqv",	0xfc0007fe, 0x4c000242, " %{crbD},%{crbA},%{crbB}" },
248	{ "crorc",	0xfc0007fe, 0x4c000342, " %{crbD},%{crbA},%{crbB}" },
249	{ "cror",	0xfc0007fe, 0x4c000382, " %{crbD},%{crbA},%{crbB}" },
250	{ "b"/*bcctr*/,	0xfc0007fe, 0x4c000420, "%{BO}ctr%{LK} %{BI1}" },
251	{ "",		0x0,		0x0, "" }
252};
253
254/* 1e * 4 = 78 */
255const struct opcode opcodes_1e[] = {
256	{ "rldicl",	0xfc00001c, 0x78000000, " %{A},%{S},%{sh},%{mb}" },
257	{ "rldicr",	0xfc00001c, 0x78000004, " %{A},%{S},%{sh},%{mb}" },
258	{ "rldic",	0xfc00001c, 0x78000008, " %{A},%{S},%{sh},%{mb}" },
259	{ "rldimi",	0xfc00001c, 0x7800000c, " %{A},%{S},%{sh},%{mb}" },
260	{ "rldcl",	0xfc00003e, 0x78000010, " %{A},%{S},%{B},%{mb}" },
261	{ "rldcr",	0xfc00003e, 0x78000012, " %{A},%{S},%{B},%{mb}" },
262	{ "",		0x0,		0x0, "" }
263};
264
265/* 1f * 4 = 7c */
266const struct opcode opcodes_1f[] = {
267/* 1f << 2 */
268	{ "cmpd",	0xfc2007fe, 0x7c200000, " %{crfD}%{A},%{B}" },
269	{ "cmpw",	0xfc2007fe, 0x7c000000, " %{crfD}%{A},%{B}" },
270	{ "tw",		0xfc0007fe, 0x7c000008, " %{TO},%{A},%{B}" },
271	{ "subfc",	0xfc0003fe, 0x7c000010, "%{OE}%{RC} %{D},%{A},%{B}" },
272	{ "mulhdu",	0xfc0007fe, 0x7c000012, "%{RC} %{D},%{A},%{B}" },
273	{ "addc",	0xfc0003fe, 0x7c000014, "%{OE}%{RC} %{D},%{A},%{B}" },
274	{ "mulhwu",	0xfc0007fe, 0x7c000016, "%{RC} %{D},%{A},%{B}" },
275
276	{ "mfcr",	0xfc0007fe, 0x7c000026, " %{D}" },
277	{ "lwarx",	0xfc0007fe, 0x7c000028, " %{D},%{A0}%{B}" },
278	{ "ldx",	0xfc0007fe, 0x7c00002a, " %{D},%{A0}%{B}" },
279	{ "lwzx",	0xfc0007fe, 0x7c00002e, " %{D},%{A0}%{B}" },
280	{ "slw",	0xfc0007fe, 0x7c000030, "%{RC} %{A},%{S},%{B}" },
281	{ "cntlzw",	0xfc0007fe, 0x7c000034, "%{RC} %{A},%{S}" },
282	{ "sld",	0xfc0007fe, 0x7c000036, "%{RC} %{A},%{S},%{B}" },
283	{ "and",	0xfc0007fe, 0x7c000038, "%{RC} %{A},%{S},%{B}" },
284	{ "cmpld",	0xfc2007fe, 0x7c200040, " %{crfD}%{A},%{B}" },
285	{ "cmplw",	0xfc2007fe, 0x7c000040, " %{crfD}%{A},%{B}" },
286	{ "subf",	0xfc0003fe, 0x7c000050, "%{OE}%{RC} %{D},%{A},%{B}" },
287	{ "ldux",	0xfc0007fe, 0x7c00006a, " %{D},%{A},%{B}" },
288	{ "dcbst",	0xfc0007fe, 0x7c00006c, " %{A0}%{B}" },
289	{ "lwzux",	0xfc0007fe, 0x7c00006e, " %{D},%{A},%{B}" },
290	{ "cntlzd",	0xfc0007fe, 0x7c000074, "%{RC} %{A},%{S}" },
291	{ "andc",	0xfc0007fe, 0x7c000078, "%{RC} %{A},%{S},%{B}" },
292	{ "td",		0xfc0007fe, 0x7c000088, " %{TO},%{A},%{B}" },
293	{ "mulhd",	0xfc0007fe, 0x7c000092, "%{RC} %{D},%{A},%{B}" },
294	{ "mulhw",	0xfc0007fe, 0x7c000096, "%{RC} %{D},%{A},%{B}" },
295	{ "mfmsr",	0xfc0007fe, 0x7c0000a6, " %{D}" },
296	{ "ldarx",	0xfc0007fe, 0x7c0000a8, " %{D},%{A0}%{B}" },
297	{ "dcbf",	0xfc0007fe, 0x7c0000ac, " %{A0}%{B}" },
298	{ "lbzx",	0xfc0007fe, 0x7c0000ae, " %{D},%{A0}%{B}" },
299	{ "neg",	0xfc0003fe, 0x7c0000d0, "%{OE}%{RC} %{D},%{A}" },
300	{ "lbzux",	0xfc0007fe, 0x7c0000ee, " %{D},%{A},%{B}" },
301	{ "nor",	0xfc0007fe, 0x7c0000f8, "%{RC} %{A},%{S}" },
302	{ "subfe",	0xfc0003fe, 0x7c000110, "%{OE}%{RC} %{D},%{A}" },
303	{ "adde",	0xfc0003fe, 0x7c000114, "%{OE}%{RC} %{D},%{A}" },
304	{ "mtcrf",	0xfc0007fe, 0x7c000120, " %{S},%{CRM}" },
305	{ "mtmsr",	0xfc0007fe, 0x7c000124, " %{S}" },
306	{ "stdx",	0xfc0007fe, 0x7c00012a, " %{S},%{A0}%{B}" },
307	{ "stwcx.",	0xfc0007ff, 0x7c00012d, " %{S},%{A},%{B}" },
308	{ "stwx",	0xfc0007fe, 0x7c00012e, " %{S},%{A},%{B}" },
309	{ "stdux",	0xfc0007fe, 0x7c00016a, " %{S},%{A},%{B}" },
310	{ "stwux",	0xfc0007fe, 0x7c00016e, " %{S},%{A},%{B}" },
311	{ "subfze",	0xfc0003fe, 0x7c000190, "%{OE}%{RC} %{D},%{A}" },
312	{ "addze",	0xfc0003fe, 0x7c000194, "%{OE}%{RC} %{D},%{A}" },
313	{ "mtsr",	0xfc0007fe, 0x7c0001a4, " %{SR},%{S}" },
314	{ "stdcx.",	0xfc0007ff, 0x7c0001ad, " %{S},%{A0}%{B}" },
315	{ "stbx",	0xfc0007fe, 0x7c0001ae, " %{S},%{A0}%{B}" },
316	{ "subfme",	0xfc0003fe, 0x7c0001d0, "%{OE}%{RC} %{D},%{A}" },
317	{ "mulld",	0xfc0003fe, 0x7c0001d2, "%{OE}%{RC} %{D},%{A},%{B}" },
318	{ "addme",	0xfc0003fe, 0x7c0001d4, "%{OE}%{RC} %{D},%{A}" },
319	{ "mullw",	0xfc0003fe, 0x7c0001d6, "%{OE}%{RC} %{D},%{A},%{B}" },
320	{ "mtsrin",	0xfc0007fe, 0x7c0001e4, " %{S},%{B}" },
321	{ "dcbtst",	0xfc0007fe, 0x7c0001ec, " %{A0}%{B}" },
322	{ "stbux",	0xfc0007fe, 0x7c0001ee, " %{S},%{A},%{B}" },
323	{ "add",	0xfc0003fe, 0x7c000214, "" },
324	{ "dcbt",	0xfc0007fe, 0x7c00022c, " %{A0}%{B}" },
325	{ "lhzx",	0xfc0007ff, 0x7c00022e, " %{D},%{A0}%{B}" },
326	{ "eqv",	0xfc0007fe, 0x7c000238, "%{RC} %{A},%{S},%{B}" },
327	{ "tlbie",	0xfc0007fe, 0x7c000264, " %{B}" },
328	{ "eciwx",	0xfc0007fe, 0x7c00026c, " %{D},%{A0}%{B}" },
329	{ "lhzux",	0xfc0007fe, 0x7c00026e, " %{D},%{A},%{B}" },
330	{ "xor",	0xfc0007fe, 0x7c000278, "%{RC} %{A},%{S},%{B}" },
331	{ "mfspr",	0xfc0007fe, 0x7c0002a6, " %{D},%{spr}" },
332	{ "lwax",	0xfc0007fe, 0x7c0002aa, " %{D},%{A0}%{B}" },
333	{ "lhax",	0xfc0007fe, 0x7c0002ae, " %{D},%{A},%{B}" },
334	{ "tlbia",	0xfc0007fe, 0x7c0002e4, "" },
335	{ "mftb",	0xfc0007fe, 0x7c0002e6, " %{D},%{tbr}" },
336	{ "lwaux",	0xfc0007fe, 0x7c0002ea, " %{D},%{A},%{B}" },
337	{ "lhaux",	0xfc0007fe, 0x7c0002ee, " %{D},%{A},%{B}" },
338	{ "sthx",	0xfc0007fe, 0x7c00032e, " %{S},%{A0}%{B}" },
339	{ "orc",	0xfc0007fe, 0x7c000338, "%{RC} %{A},%{S},%{B}" },
340	{ "ecowx",	0xfc0007fe, 0x7c00036c, "%{RC} %{S},%{A0}%{B}" },
341	{ "slbie",	0xfc0007fc, 0x7c000364, " %{B}" },
342	{ "sthux",	0xfc0007fe, 0x7c00036e, " %{S},%{A0}%{B}" },
343	{ "or",		0xfc0007fe, 0x7c000378, "%{RC} %{A},%{S},%{B}" },
344	{ "divdu",	0xfc0003fe, 0x7c000392, "%{OE}%{RC} %{S},%{A},%{B}" },
345	{ "divwu",	0xfc0003fe, 0x7c000396, "%{OE}%{RC} %{S},%{A},%{B}" },
346	{ "mtspr",	0xfc0007fe, 0x7c0003a6, " %{spr},%{S}" },
347	{ "dcbi",	0xfc0007fe, 0x7c0003ac, " %{A0}%{B}" },
348	{ "nand",	0xfc0007fe, 0x7c0003b8, "%{RC} %{A},%{S},%{B}" },
349	{ "divd",	0xfc0003fe, 0x7c0003d2, "%{OE}%{RC} %{S},%{A},%{B}" },
350	{ "divw",	0xfc0003fe, 0x7c0003d6, "%{OE}%{RC} %{S},%{A},%{B}" },
351	{ "slbia",	0xfc0003fe, 0x7c0003e4, "%{OE}%{RC} %{S},%{A},%{B}" },
352	{ "mcrxr",	0xfc0007fe, 0x7c000400, "crfD1" },
353	{ "lswx",	0xfc0007fe, 0x7c00042a, " %{D},%{A0}%{B}" },
354	{ "lwbrx",	0xfc0007fe, 0x7c00042c, " %{D},%{A0}%{B}" },
355	{ "lfsx",	0xfc0007fe, 0x7c00042e, " %{D},%{A},%{B}" },
356	{ "srw",	0xfc0007fe, 0x7c000430, "%{RC} %{A},%{S},%{B}" },
357	{ "srd",	0xfc0007fe, 0x7c000436, "%{RC} %{A},%{S},%{B}" },
358	{ "tlbsync",	0xffffffff, 0x7c00046c, "" },
359	{ "lfsux",	0xfc0007fe, 0x7c00046e, " %{D},%{A},%{B}" },
360	{ "mfsr",	0xfc0007fe, 0x7c0004a6, " %{D},%{SR}" },
361	{ "lswi",	0xfc0007fe, 0x7c0004aa, " %{D},%{A},%{NB}" },
362	{ "sync",	0xfc0007fe, 0x7c0004ac, "" },
363	{ "lfdx",	0xfc0007fe, 0x7c0004ae, " %{D},%{A},%{B}" },
364	{ "lfdux",	0xfc0007fe, 0x7c0004ee, " %{D},%{A},%{B}" },
365	{ "mfsrin",	0xfc0007fe, 0x7c000526, "" },
366	{ "stswx",	0xfc0007fe, 0x7c00052a, " %{S},%{A0}%{B}" },
367	{ "stwbrx",	0xfc0007fe, 0x7c00052c, " %{S},%{A0}%{B}" },
368	{ "stfsx",	0xfc0007fe, 0x7c00052e, " %{S},%{A0}%{B}" },
369	{ "stfsux",	0xfc0007fe, 0x7c00056e, " %{S},%{A},%{B}" },
370	{ "stswi",	0xfc0007fe, 0x7c0005aa, "%{S},%{A0}%{NB}" },
371	{ "stfdx",	0xfc0007fe, 0x7c0005ae, " %{S},%{A0}%{B}" },
372	{ "stfdux",	0xfc0007fe, 0x7c0005ee, " %{S},%{A},%{B}" },
373	{ "lhbrx",	0xfc0007fe, 0x7c00062c, " %{D},%{A0}%{B}" },
374	{ "sraw",	0xfc0007fe, 0x7c000630, " %{A},%{S},%{B}" },
375	{ "srad",	0xfc0007fe, 0x7c000634, "%{RC} %{A},%{S},%{B}" },
376	{ "srawi",	0xfc0007fe, 0x7c000670, "%{RC} %{A},%{SH}" },
377	{ "sradi",	0xfc0007fc, 0x7c000674, " %{A},%{S},%{sh}" },
378	{ "eieio",	0xfc0007fe, 0x7c0006ac, "" }, /* MASK? */
379	{ "sthbrx",	0xfc0007fe, 0x7c00072c, " %{S},%{A0}%{B}" },
380	{ "extsh",	0xfc0007fe, 0x7c000734, "%{RC} %{A},%{S}" },
381	{ "extsb",	0xfc0007fe, 0x7c000774, "%{RC} %{A},%{S}" },
382	{ "icbi",	0xfc0007fe, 0x7c0007ac, " %{A0}%{B}" },
383
384	{ "stfiwx",	0xfc0007fe, 0x7c0007ae, " %{S},%{A0}%{B}" },
385	{ "extsw",	0xfc0007fe, 0x7c0007b4, "%{RC} %{A},%{S}" },
386	{ "dcbz",	0xfc0007fe, 0x7c0007ec, " %{A0}%{B}" },
387	{ "",		0x0,		0x0, 0, }
388};
389
390/* 3a * 4 = e8 */
391const struct opcode opcodes_3a[] = {
392	{ "ld",		0xfc000003, 0xe8000000, " %{D},%{ds}(%{A})" },
393	{ "ldu",	0xfc000003, 0xe8000001, " %{D},%{ds}(%{A})" },
394	{ "lwa",	0xfc000003, 0xe8000002, " %{D},%{ds}(%{A})" },
395	{ "",		0x0,		0x0, "" }
396};
397
398/* 3b * 4 = ec */
399const struct opcode opcodes_3b[] = {
400	{ "fdivs",	0xfc00003e, 0xec000024, "%{RC} f%{D},f%{A},f%{B}" },
401	{ "fsubs",	0xfc00003e, 0xec000028, "%{RC} f%{D},f%{A},f%{B}" },
402
403	{ "fadds",	0xfc00003e, 0xec00002a, "%{RC} f%{D},f%{A},f%{B}" },
404	{ "fsqrts",	0xfc00003e, 0xec00002c, "" },
405	{ "fres",	0xfc00003e, 0xec000030, "" },
406	{ "fmuls",	0xfc00003e, 0xec000032, "%{RC} f%{D},f%{A},f%{C}" },
407	{ "fmsubs",	0xfc00003e, 0xec000038, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
408	{ "fmadds",	0xfc00003e, 0xec00003a, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
409	{ "fnmsubs",	0xfc00003e, 0xec00003c, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
410	{ "fnmadds",	0xfc00003e, 0xec00003e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
411	{ "",		0x0,		0x0, "" }
412};
413
414/* 3e * 4 = f8 */
415const struct opcode opcodes_3e[] = {
416	{ "std",	0xfc000003, 0xf8000000, " %{D},%{ds}(%{A})" },
417	{ "stdu",	0xfc000003, 0xf8000001, " %{D},%{ds}(%{A})" },
418	{ "",		0x0,		0x0, "" }
419};
420
421/* 3f * 4 = fc */
422const struct opcode opcodes_3f[] = {
423	{ "fcmpu",	0xfc0007fe, 0xfc000000, " %{crfD},f%{A},f%{B}" },
424	{ "frsp",	0xfc0007fe, 0xfc000018, "%{RC} f%{D},f%{B}" },
425	{ "fctiw",	0xfc0007fe, 0xfc00001c, "%{RC} f%{D},f%{B}" },
426	{ "fctiwz",	0xfc0007fe, 0xfc00001e, "%{RC} f%{D},f%{B}" },
427
428	{ "fdiv",	0xfc00003e, 0xfc000024, "%{RC} f%{D},f%{A},f%{B}" },
429	{ "fsub",	0xfc00003e, 0xfc000028, "%{RC} f%{D},f%{A},f%{B}" },
430	{ "fadd",	0xfc00003e, 0xfc00002a, "%{RC} f%{D},f%{A},f%{B}" },
431	{ "fsqrt",	0xfc00003e, 0xfc00002c, "%{RC} f%{D},f%{B}" },
432	{ "fsel",	0xfc00003e, 0xfc00002e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
433	{ "fmul",	0xfc00003e, 0xfc000032, "%{RC} f%{D},f%{A},f%{C}" },
434	{ "frsqrte",	0xfc00003e, 0xfc000034, "%{RC} f%{D},f%{B}" },
435	{ "fmsub",	0xfc00003e, 0xfc000038, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
436	{ "fmadd",	0xfc00003e, 0xfc00003a, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
437	{ "fnmsub",	0xfc00003e, 0xfc00003c, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
438	{ "fnmadd",	0xfc00003e, 0xfc00003e, "%{RC} f%{D},f%{A},f%{C},f%{B}" },
439
440	{ "fcmpo",	0xfc0007fe, 0xfc000040, "%{RC} f%{D},f%{A},f%{C}" },
441	{ "mtfsb1",	0xfc0007fe, 0xfc00004c, "%{RC} f%{D},f%{A},f%{C}" },
442	{ "fneg",	0xfc0007fe, 0xfc000050, "%{RC} f%{D},f%{A},f%{C}" },
443	{ "mcrfs",	0xfc0007fe, 0xfc000080, "%{RC} f%{D},f%{A},f%{C}" },
444	{ "mtfsb0",	0xfc0007fe, 0xfc00008c, "%{RC} %{crfD},f%{C}" },
445	{ "fmr",	0xfc0007fe, 0xfc000090, "%{RC} f%{D},f%{B}" },
446	{ "mtfsfi",	0xfc0007fe, 0xfc00010c, "%{RC} %{crfD},f%{C},%{IMM}" },
447
448	{ "fnabs",	0xfc0007fe, 0xfc000110, "%{RC} f%{D},f%{B}" },
449	{ "fabs",	0xfc0007fe, 0xfc000210, "%{RC} f%{D},f%{B}" },
450	{ "mffs",	0xfc0007fe, 0xfc00048e, "%{RC} f%{D},f%{B}" },
451	{ "mtfsf",	0xfc0007fe, 0xfc00058e, "%{RC} %{FM},f%{B}" },
452	{ "fctid",	0xfc0007fe, 0xfc00065c, "%{RC} f%{D},f%{B}" },
453	{ "fctidz",	0xfc0007fe, 0xfc00065e, "%{RC} f%{D},f%{B}" },
454	{ "fcfid",	0xfc0007fe, 0xfc00069c, "%{RC} f%{D},f%{B}" },
455	{ "",		0x0,		0x0, "" }
456};
457
458void
459op_ill(u_int32_t addr, instr_t instr)
460{
461	db_printf("illegal instruction %x\n", instr);
462}
463
464/*
465 * Extracts bits out of an instruction opcode, base indicates the lsb
466 * to keep.
467 * Note that this uses the PowerPC bit number for base, MSb == 0
468 * because all of the documentation is written that way.
469 */
470u_int32_t
471extract_field(u_int32_t value, u_int32_t base, u_int32_t width)
472{
473	u_int32_t mask = (1 << width) - 1;
474	return ((value >> (31 - base)) & mask);
475}
476
477char *db_BOBI_cond[] = {
478	"ge",
479	"le",
480	"ne",
481	"ns",
482	"lt",
483	"gt",
484	"eq",
485	"so"
486};
487/* what about prediction directions? */
488char *db_BO_op[] = {
489	"dnzf",
490	"dnzf-",
491	"dzf",
492	"dzf-",
493	"",
494	"",
495	"",
496	"",
497	"dnzt",
498	"dnzt-",
499	"dzt",
500	"dzt-",
501	"",
502	"",
503	"",
504	"",
505	"dnz",
506	"dnz",
507	"dz",
508	"dz",
509	"",
510	"",
511	"",
512	"",
513	"dnz",
514	"dnz",
515	"dz",
516	"dz",
517	"",
518	"",
519	"",
520	""
521};
522
523char *BItbl[] = {
524	"", "gt", "eq", "so"
525};
526
527char BO_uses_tbl[32] = {
528	/* 0 */ 1,
529	/* 1 */ 1,
530	/* 2 */ 1,
531	/* 3 */ 1,
532	/* 4 */ 0,
533	/* 5 */ 0,
534	/* 6 */ 0, /* invalid */
535	/* 7 */ 0, /* invalid */
536	/* 8 */ 1,
537	/* 9 */ 1,
538	/* a */ 1,
539	/* b */ 1,
540	/* c */ 0,
541	/* d */ 0,
542	/* e */ 0, /* invalid */
543	/* f */ 1,
544	/* 10 */        1,
545	/* 11 */        1,
546	/* 12 */        1,
547	/* 13 */        1,
548	/* 14 */        1,
549	/* 15 */        0, /* invalid */
550	/* 16 */        0, /* invalid */
551	/* 17 */        0, /* invalid */
552	/* 18 */        0, /* invalid */
553	/* 19 */        0, /* invalid */
554	/* 1a */        0, /* invalid */
555	/* 1b */        0, /* invalid */
556	/* 1c */        0, /* invalid */
557	/* 1d */        0, /* invalid */
558	/* 1e */        0, /* invalid */
559	/* 1f */        0, /* invalid */
560};
561
562void
563disasm_process_field(u_int32_t addr, instr_t instr, char **ppfmt,
564    char *disasm_buf, size_t bufsize)
565{
566	char field [8];
567	char lbuf[50];
568	int i;
569	char *pfmt = *ppfmt;
570	enum opf opf;
571	char *name;
572	db_expr_t offset;
573
574	/* find field */
575	if (pfmt[0] != '%' || pfmt[1] != '{') {
576		printf("error in disasm fmt [%s]\n", pfmt);
577	}
578	pfmt = &pfmt[2];
579	for (i = 0;
580	    pfmt[i] != '\0' && pfmt[i] != '}' && i < sizeof(field);
581	    i++) {
582		field[i] = pfmt[i];
583	}
584	if (i == sizeof(field)) {
585		printf("error in disasm fmt [%s]\n", pfmt);
586		return;
587	}
588	field[i] = 0;
589	if (pfmt[i] == '\0') {
590		/* match following close paren { */
591		printf("disasm_process_field: missing } in [%s]\n", pfmt);
592	}
593	*ppfmt = &pfmt[i+1];
594	opf = Opf_INVALID;
595	for (i = 0; db_fields[i].name != NULL; i++) {
596		if (strcmp(db_fields[i].name, field) == 0) {
597			opf = db_fields[i].opf;
598			break;
599		}
600	}
601	switch (opf) {
602	case Opf_INVALID:
603		{
604			printf("unable to find variable [%s]\n", field);
605		}
606	case Opf_A:
607		{
608			u_int A;
609			A = extract_field(instr, 15, 5);
610			snprintf(lbuf, sizeof (lbuf), "r%d", A);
611			strlcat (disasm_buf, lbuf, bufsize);
612		}
613		break;
614	case Opf_A0:
615		{
616			u_int A;
617			A = extract_field(instr, 15, 5);
618			if (A != 0) {
619				snprintf(lbuf, sizeof (lbuf), "r%d,", A);
620				strlcat (disasm_buf, lbuf, bufsize);
621			}
622		}
623		break;
624	case Opf_AA:
625		if (instr & 0x2) {
626			strlcat (disasm_buf, "a", bufsize);
627		}
628		break;
629	case Opf_LI:
630		{
631			u_int LI;
632			LI = extract_field(instr, 29, 24);
633			LI = LI << 2;
634			if (LI & 0x02000000) {
635				LI |= ~0x03ffffff;
636			}
637			if ((instr & (1 << 1)) == 0) {
638				/* CHECK AA bit */
639				LI = addr + LI;
640			}
641			db_find_sym_and_offset(LI, &name, &offset);
642			if (name) {
643				if (offset == 0) {
644					snprintf(lbuf, sizeof (lbuf),
645					    "0x%x (%s)", LI, name);
646					strlcat (disasm_buf, lbuf, bufsize);
647				} else {
648					snprintf(lbuf, sizeof (lbuf),
649					    "0x%x (%s+0x%lx)", LI, name,
650					    offset);
651					strlcat (disasm_buf, lbuf, bufsize);
652				}
653			} else {
654				snprintf(lbuf, sizeof (lbuf), "0x%x", LI);
655				strlcat (disasm_buf, lbuf, bufsize);
656			}
657		}
658		break;
659	case Opf_B:
660		{
661			u_int B;
662			B = extract_field(instr, 20, 5);
663			snprintf(lbuf, sizeof (lbuf), "r%d", B);
664			strlcat (disasm_buf, lbuf, bufsize);
665		}
666		break;
667	case Opf_BD:
668		{
669			int BD;
670			BD = extract_field(instr, 29, 14);
671			BD = BD << 2;
672			if (BD & 0x00008000) {
673				BD |= ~0x00007fff;
674			}
675			if ((instr & (1 << 1)) == 0) {
676				/* CHECK AA bit */
677				BD = addr + BD;
678			}
679			db_find_sym_and_offset(BD, &name, &offset);
680			if (name) {
681				if (offset == 0) {
682					snprintf(lbuf, sizeof (lbuf),
683					    "0x%x (%s)", BD, name);
684					strlcat (disasm_buf, lbuf, bufsize);
685				} else {
686					snprintf(lbuf, sizeof (lbuf),
687					    "0x%x (%s+0x%lx)", BD, name, offset);
688					strlcat (disasm_buf, lbuf, bufsize);
689				}
690			} else {
691				snprintf(lbuf, sizeof (lbuf), "0x%x", BD);
692				strlcat (disasm_buf, lbuf, bufsize);
693			}
694		}
695		break;
696	case Opf_BI1:
697	case Opf_BI:
698		{
699			int BO, BI, cr, printcomma = 0;
700			BO = extract_field(instr, 10, 5);
701			BI = extract_field(instr, 15, 5);
702			cr =  (BI >> 2) & 7;
703			if (cr != 0) {
704				snprintf(lbuf, sizeof (lbuf), "cr%d", cr);
705				strlcat (disasm_buf, lbuf, bufsize);
706				printcomma = 1;
707			}
708			if (BO_uses_tbl[BO]) {
709				if ((cr != 0) && ((BI & 3) != 0) &&
710				    BO_uses_tbl[BO] != 0)
711					strlcat (disasm_buf, "+", bufsize);
712
713				snprintf(lbuf, sizeof (lbuf), "%s",
714				    BItbl[BI & 3]);
715				strlcat (disasm_buf, lbuf, bufsize);
716				printcomma = 1;
717			}
718			if ((opf == Opf_BI) && printcomma)
719				strlcat (disasm_buf, ",", bufsize);
720		}
721		break;
722	case Opf_BO:
723		{
724			int BO, BI;
725			BO = extract_field(instr, 10, 5);
726			strlcat (disasm_buf, db_BO_op[BO], bufsize);
727			if ((BO & 4) != 0) {
728				BI = extract_field(instr, 15, 5);
729				strlcat (disasm_buf,
730				    db_BOBI_cond[(BI & 0x3)| (((BO & 8) >> 1))],
731				    bufsize);
732
733				if (BO & 1)
734					strlcat (disasm_buf, "-", bufsize);
735			}
736		}
737		break;
738	case Opf_C:
739		{
740			u_int C;
741			C = extract_field(instr, 25, 5);
742			snprintf(lbuf, sizeof (lbuf), "r%d, ", C);
743			strlcat (disasm_buf, lbuf, bufsize);
744		}
745		break;
746	case Opf_CRM:
747		{
748			u_int CRM;
749			CRM = extract_field(instr, 19, 8);
750			snprintf(lbuf, sizeof (lbuf), "0x%x", CRM);
751			strlcat (disasm_buf, lbuf, bufsize);
752		}
753		break;
754	case Opf_FM:
755		{
756			u_int FM;
757			FM = extract_field(instr, 10, 8);
758			snprintf(lbuf, sizeof (lbuf), "%d", FM);
759			strlcat (disasm_buf, lbuf, bufsize);
760		}
761		break;
762	case Opf_LK:
763		if (instr & 0x1) {
764			strlcat (disasm_buf, "l", bufsize);
765		}
766		break;
767	case Opf_MB:
768		{
769			u_int MB;
770			MB = extract_field(instr, 20, 5);
771			snprintf(lbuf, sizeof (lbuf), "%d", MB);
772			strlcat (disasm_buf, lbuf, bufsize);
773		}
774		break;
775	case Opf_ME:
776		{
777			u_int ME;
778			ME = extract_field(instr, 25, 5);
779			snprintf(lbuf, sizeof (lbuf), "%d", ME);
780			strlcat (disasm_buf, lbuf, bufsize);
781		}
782		break;
783	case Opf_NB:
784		{
785			u_int NB;
786			NB = extract_field(instr, 20, 5);
787			if (NB == 0 ) {
788				NB=32;
789			}
790			snprintf(lbuf, sizeof (lbuf), "%d", NB);
791			strlcat (disasm_buf, lbuf, bufsize);
792		}
793		break;
794	case Opf_OE:
795		if (instr & (1 << (31-21))) {
796			strlcat (disasm_buf, "o", bufsize);
797		}
798		break;
799	case Opf_RC:
800		if (instr & 0x1) {
801			strlcat (disasm_buf, ".", bufsize);
802		}
803		break;
804	case Opf_S:
805	case Opf_D:
806		{
807			u_int D;
808			/* S and D are the same */
809			D = extract_field(instr, 10, 5);
810			snprintf(lbuf, sizeof (lbuf), "r%d", D);
811			strlcat (disasm_buf, lbuf, bufsize);
812		}
813		break;
814	case Opf_SH:
815		{
816			u_int SH;
817			SH = extract_field(instr, 20, 5);
818			snprintf(lbuf, sizeof (lbuf), "%d", SH);
819			strlcat (disasm_buf, lbuf, bufsize);
820		}
821		break;
822	case Opf_SIMM:
823	case Opf_d:
824		{
825			int IMM;
826			IMM = extract_field(instr, 31, 16);
827			if (IMM & 0x8000)
828				IMM |= ~0x7fff;
829			snprintf(lbuf, sizeof (lbuf), "%d", IMM);
830			strlcat (disasm_buf, lbuf, bufsize);
831		}
832		break;
833	case Opf_UIMM:
834		{
835			u_int IMM;
836			IMM = extract_field(instr, 31, 16);
837			snprintf(lbuf, sizeof (lbuf), "0x%x", IMM);
838			strlcat (disasm_buf, lbuf, bufsize);
839		}
840		break;
841	case Opf_SR:
842		{
843			u_int SR;
844			SR = extract_field(instr, 15, 3);
845			snprintf(lbuf, sizeof (lbuf), "sr%d", SR);
846			strlcat (disasm_buf, lbuf, bufsize);
847		}
848		break;
849	case Opf_TO:
850		{
851			u_int TO;
852			TO = extract_field(instr, 10, 1);
853			snprintf(lbuf, sizeof (lbuf), "%d", TO);
854			strlcat (disasm_buf, lbuf, bufsize);
855		}
856		break;
857	case Opf_crbA:
858		{
859			u_int crbA;
860			crbA = extract_field(instr, 15, 5);
861			snprintf(lbuf, sizeof (lbuf), "%d", crbA);
862			strlcat (disasm_buf, lbuf, bufsize);
863		}
864		break;
865	case Opf_crbB:
866		{
867			u_int crbB;
868			crbB = extract_field(instr, 20, 5);
869			snprintf(lbuf, sizeof (lbuf), "%d", crbB);
870			strlcat (disasm_buf, lbuf, bufsize);
871		}
872		break;
873	case Opf_crbD:
874		{
875			u_int crfD;
876			crfD = extract_field(instr, 8, 3);
877			snprintf(lbuf, sizeof (lbuf), "crf%d", crfD);
878			strlcat (disasm_buf, lbuf, bufsize);
879		}
880		break;
881	case Opf_crfD:
882		{
883			u_int crfD;
884			crfD = extract_field(instr, 8, 3);
885			snprintf(lbuf, sizeof (lbuf), "crf%d", crfD);
886			strlcat (disasm_buf, lbuf, bufsize);
887		}
888		break;
889	case Opf_crfS:
890		{
891			u_int crfS;
892			crfS = extract_field(instr, 13, 3);
893			snprintf(lbuf, sizeof (lbuf), "%d", crfS);
894			strlcat (disasm_buf, lbuf, bufsize);
895		}
896		break;
897	case Opf_ds:
898		{
899			int ds;
900			ds = extract_field(instr, 29, 14);
901			ds = ds << 2;
902			if (ds & 0x8000)
903				ds |= ~0x7fff;
904			snprintf(lbuf, sizeof (lbuf), "%d", ds);
905			strlcat (disasm_buf, lbuf, bufsize);
906		}
907		break;
908	case Opf_mb:
909		{
910			u_int mb, mbl, mbh;
911			mbl = extract_field(instr, 25, 4);
912			mbh = extract_field(instr, 26, 1);
913			mb = mbh << 4 | mbl;
914			snprintf(lbuf, sizeof (lbuf), ", %d", mb);
915			strlcat (disasm_buf, lbuf, bufsize);
916		}
917		break;
918	case Opf_sh:
919		{
920			u_int sh, shl, shh;
921			shl = extract_field(instr, 19, 4);
922			shh = extract_field(instr, 20, 1);
923			sh = shh << 4 | shl;
924			snprintf(lbuf, sizeof (lbuf), ", %d", sh);
925			strlcat (disasm_buf, lbuf, bufsize);
926		}
927		break;
928	case Opf_spr:
929		{
930			u_int spr;
931			u_int sprl;
932			u_int sprh;
933			char *reg;
934			sprl = extract_field(instr, 15, 5);
935			sprh = extract_field(instr, 20, 5);
936			spr = sprh << 5 | sprl;
937
938			/* this table could be written better */
939			switch (spr) {
940			case	1:
941				reg = "xer";
942				break;
943			case	8:
944				reg = "lr";
945				break;
946			case	9:
947				reg = "ctr";
948				break;
949			case	18:
950				reg = "dsisr";
951				break;
952			case	19:
953				reg = "dar";
954				break;
955			case	22:
956				reg = "dec";
957				break;
958			case	25:
959				reg = "sdr1";
960				break;
961			case	26:
962				reg = "srr0";
963				break;
964			case	27:
965				reg = "srr1";
966				break;
967			case	272:
968				reg = "SPRG0";
969				break;
970			case	273:
971				reg = "SPRG1";
972				break;
973			case	274:
974				reg = "SPRG3";
975				break;
976			case	275:
977				reg = "SPRG3";
978				break;
979			case	280:
980				reg = "asr";
981				break;
982			case	282:
983				reg = "aer";
984				break;
985			case	287:
986				reg = "pvr";
987				break;
988			case	528:
989				reg = "ibat0u";
990				break;
991			case	529:
992				reg = "ibat0l";
993				break;
994			case	530:
995				reg = "ibat1u";
996				break;
997			case	531:
998				reg = "ibat1l";
999				break;
1000			case	532:
1001				reg = "ibat2u";
1002				break;
1003			case	533:
1004				reg = "ibat2l";
1005				break;
1006			case	534:
1007				reg = "ibat3u";
1008				break;
1009			case	535:
1010				reg = "ibat3l";
1011				break;
1012			case	536:
1013				reg = "dbat0u";
1014				break;
1015			case	537:
1016				reg = "dbat0l";
1017				break;
1018			case	538:
1019				reg = "dbat1u";
1020				break;
1021			case	539:
1022				reg = "dbat1l";
1023				break;
1024			case	540:
1025				reg = "dbat2u";
1026				break;
1027			case	541:
1028				reg = "dbat2l";
1029				break;
1030			case	542:
1031				reg = "dbat3u";
1032				break;
1033			case	543:
1034				reg = "dbat3l";
1035				break;
1036			case	1013:
1037				reg = "dabr";
1038				break;
1039			default:
1040				reg = 0;
1041			}
1042			if (reg == 0) {
1043				snprintf(lbuf, sizeof (lbuf), "spr%d", spr);
1044				strlcat (disasm_buf, lbuf, bufsize);
1045			} else {
1046				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1047				strlcat (disasm_buf, lbuf, bufsize);
1048			}
1049		}
1050		break;
1051	case Opf_tbr:
1052		{
1053			u_int tbr;
1054			u_int tbrl;
1055			u_int tbrh;
1056			char *reg = NULL;
1057			tbrl = extract_field(instr, 15, 5);
1058			tbrh = extract_field(instr, 20, 5);
1059			tbr = tbrh << 5 | tbrl;
1060
1061			switch (tbr) {
1062			case 268:
1063				reg = "tbl";
1064				break;
1065			case 269:
1066				reg = "tbu";
1067				break;
1068			default:
1069				reg = 0;
1070			}
1071			if (reg == NULL) {
1072				snprintf(lbuf, sizeof (lbuf), "tbr%d", tbr);
1073				strlcat (disasm_buf, lbuf, bufsize);
1074			} else {
1075				snprintf(lbuf, sizeof (lbuf), "%s", reg);
1076				strlcat (disasm_buf, lbuf, bufsize);
1077			}
1078		}
1079		break;
1080	}
1081}
1082
1083void
1084disasm_fields(u_int32_t addr, const struct opcode *popcode, instr_t instr,
1085    char *disasm_str, size_t bufsize)
1086{
1087	char *pfmt;
1088	char cbuf[2];
1089	if (popcode->decode_str == NULL || popcode->decode_str[0] == '0') {
1090		return;
1091	}
1092	pfmt = popcode->decode_str;
1093	disasm_str[0] = '\0';
1094
1095	while (*pfmt != '\0')  {
1096		if (*pfmt == '%') {
1097			disasm_process_field(addr, instr, &pfmt, disasm_str,
1098			    bufsize);
1099		} else {
1100			cbuf[0] = *pfmt;
1101			cbuf[1] = '\0';
1102			strlcat(disasm_str, cbuf, bufsize);
1103			pfmt++;
1104		}
1105	}
1106}
1107
1108void
1109op_base(u_int32_t addr, instr_t instr)
1110{
1111	dis_ppc(addr, opcodes, instr);
1112}
1113
1114void
1115op_cl_x13(u_int32_t addr, instr_t instr)
1116{
1117	dis_ppc(addr, opcodes_13, instr);
1118}
1119
1120void
1121op_cl_x1e(u_int32_t addr, instr_t instr)
1122{
1123	dis_ppc(addr, opcodes_1e, instr);
1124}
1125
1126void
1127op_cl_x1f(u_int32_t addr, instr_t instr)
1128{
1129	dis_ppc(addr, opcodes_1f, instr);
1130}
1131
1132void
1133op_cl_x3a(u_int32_t addr, instr_t instr)
1134{
1135	dis_ppc(addr, opcodes_3a, instr);
1136}
1137
1138void
1139op_cl_x3b(u_int32_t addr, instr_t instr)
1140{
1141	dis_ppc(addr, opcodes_3b, instr);
1142}
1143
1144void
1145op_cl_x3e(u_int32_t addr, instr_t instr)
1146{
1147	dis_ppc(addr, opcodes_3e, instr);
1148}
1149
1150void
1151op_cl_x3f(u_int32_t addr, instr_t instr)
1152{
1153	dis_ppc(addr, opcodes_3f, instr);
1154}
1155
1156void
1157dis_ppc(u_int32_t addr, const struct opcode *opcodeset, instr_t instr)
1158{
1159	const struct opcode *op;
1160	int i;
1161	char disasm_str[80];
1162
1163	for (i=0; opcodeset[i].mask != 0; i++) {
1164		op = &opcodeset[i];
1165		if ((instr & op->mask) == op->code) {
1166			disasm_fields(addr, op, instr, disasm_str,
1167			    sizeof disasm_str);
1168			db_printf("%s%s\n", op->name, disasm_str);
1169			return;
1170		}
1171	}
1172	op_ill(addr, instr);
1173}
1174
1175vaddr_t
1176db_disasm(vaddr_t loc, int extended)
1177{
1178	int class;
1179	instr_t opcode;
1180	opcode = *(instr_t *)(loc);
1181	class = opcode >> 26;
1182	(opcodes_base[class])(loc, opcode);
1183
1184	return loc + 4;
1185}
1186