xref: /OK3568_Linux_fs/u-boot/common/bedbug.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* $Id$ */
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun #include <common.h>
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #include <linux/ctype.h>
6*4882a593Smuzhiyun #include <bedbug/bedbug.h>
7*4882a593Smuzhiyun #include <bedbug/ppc.h>
8*4882a593Smuzhiyun #include <bedbug/regs.h>
9*4882a593Smuzhiyun #include <bedbug/tables.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #define Elf32_Word	unsigned long
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* USE_SOURCE_CODE enables some symbolic debugging functions of this
14*4882a593Smuzhiyun    code.  This is only useful if the program will have access to the
15*4882a593Smuzhiyun    source code for the binary being examined.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* #define USE_SOURCE_CODE 1 */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
21*4882a593Smuzhiyun extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
22*4882a593Smuzhiyun extern struct symreflist *symByAddr;
23*4882a593Smuzhiyun extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
24*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun int print_operands __P ((struct ppc_ctx *));
27*4882a593Smuzhiyun int get_operand_value __P ((struct opcode *, unsigned long,
28*4882a593Smuzhiyun 				enum OP_FIELD, unsigned long *));
29*4882a593Smuzhiyun struct opcode *find_opcode __P ((unsigned long));
30*4882a593Smuzhiyun struct opcode *find_opcode_by_name __P ((char *));
31*4882a593Smuzhiyun char *spr_name __P ((int));
32*4882a593Smuzhiyun int spr_value __P ((char *));
33*4882a593Smuzhiyun char *tbr_name __P ((int));
34*4882a593Smuzhiyun int tbr_value __P ((char *));
35*4882a593Smuzhiyun int parse_operand __P ((unsigned long, struct opcode *,
36*4882a593Smuzhiyun 			struct operand *, char *, int *));
37*4882a593Smuzhiyun int get_word __P ((char **, char *));
38*4882a593Smuzhiyun long read_number __P ((char *));
39*4882a593Smuzhiyun int downstring __P ((char *));
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /*======================================================================
43*4882a593Smuzhiyun  * Entry point for the PPC disassembler.
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * Arguments:
46*4882a593Smuzhiyun  *	memaddr		The address to start disassembling from.
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  *	virtual		If this value is non-zero, then this will be
49*4882a593Smuzhiyun  *			used as the base address for the output and
50*4882a593Smuzhiyun  *			symbol lookups.  If this value is zero then
51*4882a593Smuzhiyun  *			memaddr is used as the absolute address.
52*4882a593Smuzhiyun  *
53*4882a593Smuzhiyun  *	num_instr	The number of instructions to disassemble.  Since
54*4882a593Smuzhiyun  *			each instruction is 32 bits long, this can be
55*4882a593Smuzhiyun  *			computed if you know the total size of the region.
56*4882a593Smuzhiyun  *
57*4882a593Smuzhiyun  *	pfunc		The address of a function that is called to print
58*4882a593Smuzhiyun  *			each line of output.  The function should take a
59*4882a593Smuzhiyun  *			single character pointer as its parameters a la puts.
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  *	flags		Sets options for the output.  This is a
62*4882a593Smuzhiyun  *			bitwise-inclusive-OR of the following
63*4882a593Smuzhiyun  *			values.  Note that only one of the radix
64*4882a593Smuzhiyun  *			options may be set.
65*4882a593Smuzhiyun  *
66*4882a593Smuzhiyun  *			F_RADOCTAL	- output radix is unsigned base 8.
67*4882a593Smuzhiyun  *			F_RADUDECIMAL	- output radix is unsigned base 10.
68*4882a593Smuzhiyun  *			F_RADSDECIMAL	- output radix is signed base 10.
69*4882a593Smuzhiyun  *			F_RADHEX	- output radix is unsigned base 16.
70*4882a593Smuzhiyun  *			F_SIMPLE	- use simplified mnemonics.
71*4882a593Smuzhiyun  *			F_SYMBOL	- lookup symbols for addresses.
72*4882a593Smuzhiyun  *			F_INSTR		- output raw instruction.
73*4882a593Smuzhiyun  *			F_LINENO	- show line # info if available.
74*4882a593Smuzhiyun  *
75*4882a593Smuzhiyun  * Returns true if the area was successfully disassembled or false if
76*4882a593Smuzhiyun  * a problem was encountered with accessing the memory.
77*4882a593Smuzhiyun  */
78*4882a593Smuzhiyun 
disppc(unsigned char * memaddr,unsigned char * virtual,int num_instr,int (* pfunc)(const char *),unsigned long flags)79*4882a593Smuzhiyun int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr,
80*4882a593Smuzhiyun 			int (*pfunc) (const char *), unsigned long flags)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	int i;
83*4882a593Smuzhiyun 	struct ppc_ctx ctx;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
86*4882a593Smuzhiyun 	int line_no = 0;
87*4882a593Smuzhiyun 	int last_line_no = 0;
88*4882a593Smuzhiyun 	char funcname[128] = { 0 };
89*4882a593Smuzhiyun 	char filename[256] = { 0 };
90*4882a593Smuzhiyun 	char last_funcname[128] = { 0 };
91*4882a593Smuzhiyun 	int symoffset;
92*4882a593Smuzhiyun 	char *symname;
93*4882a593Smuzhiyun 	char *cursym = (char *) 0;
94*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
95*4882a593Smuzhiyun   /*------------------------------------------------------------*/
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	ctx.flags = flags;
98*4882a593Smuzhiyun 	ctx.virtual = virtual;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/* Figure out the output radix before we go any further */
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (ctx.flags & F_RADOCTAL) {
103*4882a593Smuzhiyun 		/* Unsigned octal output */
104*4882a593Smuzhiyun 		strcpy (ctx.radix_fmt, "O%o");
105*4882a593Smuzhiyun 	} else if (ctx.flags & F_RADUDECIMAL) {
106*4882a593Smuzhiyun 		/* Unsigned decimal output */
107*4882a593Smuzhiyun 		strcpy (ctx.radix_fmt, "%u");
108*4882a593Smuzhiyun 	} else if (ctx.flags & F_RADSDECIMAL) {
109*4882a593Smuzhiyun 		/* Signed decimal output */
110*4882a593Smuzhiyun 		strcpy (ctx.radix_fmt, "%d");
111*4882a593Smuzhiyun 	} else {
112*4882a593Smuzhiyun 		/* Unsigned hex output */
113*4882a593Smuzhiyun 		strcpy (ctx.radix_fmt, "0x%x");
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (ctx.virtual == 0) {
117*4882a593Smuzhiyun 		ctx.virtual = memaddr;
118*4882a593Smuzhiyun 	}
119*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
120*4882a593Smuzhiyun 	if (ctx.flags & F_SYMBOL) {
121*4882a593Smuzhiyun 		if (symByAddr == 0)		/* no symbols loaded */
122*4882a593Smuzhiyun 			ctx.flags &= ~F_SYMBOL;
123*4882a593Smuzhiyun 		else {
124*4882a593Smuzhiyun 			cursym = (char *) 0;
125*4882a593Smuzhiyun 			symoffset = 0;
126*4882a593Smuzhiyun 		}
127*4882a593Smuzhiyun 	}
128*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* format each line as "XXXXXXXX: <symbol> IIIIIIII  disassembly" where,
131*4882a593Smuzhiyun 	   XXXXXXXX is the memory address in hex,
132*4882a593Smuzhiyun 	   <symbol> is the symbolic location if F_SYMBOL is set.
133*4882a593Smuzhiyun 	   IIIIIIII is the raw machine code in hex if F_INSTR is set,
134*4882a593Smuzhiyun 	   and disassembly is the disassembled machine code with numbers
135*4882a593Smuzhiyun 	   formatted according to the 'radix' parameter */
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {
138*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
139*4882a593Smuzhiyun 		if (ctx.flags & F_LINENO) {
140*4882a593Smuzhiyun 			if ((line_info_from_addr ((Elf32_Word) ctx.virtual,
141*4882a593Smuzhiyun 				filename, funcname, &line_no) == true) &&
142*4882a593Smuzhiyun 				((line_no != last_line_no) ||
143*4882a593Smuzhiyun 				 (strcmp (last_funcname, funcname) != 0))) {
144*4882a593Smuzhiyun 				print_source_line (filename, funcname, line_no, pfunc);
145*4882a593Smuzhiyun 			}
146*4882a593Smuzhiyun 			last_line_no = line_no;
147*4882a593Smuzhiyun 			strcpy (last_funcname, funcname);
148*4882a593Smuzhiyun 		}
149*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual);
152*4882a593Smuzhiyun 		ctx.datalen = 10;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
155*4882a593Smuzhiyun 		if (ctx.flags & F_SYMBOL) {
156*4882a593Smuzhiyun 			if ((symname =
157*4882a593Smuzhiyun 				 symbol_name_from_addr((Elf32_Word) ctx.virtual,
158*4882a593Smuzhiyun 						true, 0)) != 0) {
159*4882a593Smuzhiyun 				cursym = symname;
160*4882a593Smuzhiyun 				symoffset = 0;
161*4882a593Smuzhiyun 			} else {
162*4882a593Smuzhiyun 				if ((cursym == 0) &&
163*4882a593Smuzhiyun 					((symname =
164*4882a593Smuzhiyun 					  symbol_name_from_addr((Elf32_Word) ctx.virtual,
165*4882a593Smuzhiyun 						false, &symoffset)) != 0)) {
166*4882a593Smuzhiyun 					cursym = symname;
167*4882a593Smuzhiyun 				} else {
168*4882a593Smuzhiyun 					symoffset += 4;
169*4882a593Smuzhiyun 				}
170*4882a593Smuzhiyun 			}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 			if (cursym != 0) {
173*4882a593Smuzhiyun 				sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
174*4882a593Smuzhiyun 				ctx.datalen = strlen (ctx.data);
175*4882a593Smuzhiyun 				sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
176*4882a593Smuzhiyun 				strcat (ctx.data, ">");
177*4882a593Smuzhiyun 				ctx.datalen = strlen (ctx.data);
178*4882a593Smuzhiyun 			}
179*4882a593Smuzhiyun 		}
180*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 		ctx.instr = INSTRUCTION (memaddr);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		if (ctx.flags & F_INSTR) {
185*4882a593Smuzhiyun 			/* Find the opcode structure for this opcode.  If one is not found
186*4882a593Smuzhiyun 			   then it must be an illegal instruction */
187*4882a593Smuzhiyun 			sprintf (&ctx.data[ctx.datalen],
188*4882a593Smuzhiyun 					 "   %02lx %02lx %02lx %02lx    ",
189*4882a593Smuzhiyun 					 ((ctx.instr >> 24) & 0xff),
190*4882a593Smuzhiyun 					 ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
191*4882a593Smuzhiyun 					 (ctx.instr & 0xff));
192*4882a593Smuzhiyun 			ctx.datalen += 18;
193*4882a593Smuzhiyun 		} else {
194*4882a593Smuzhiyun 			strcat (ctx.data, "   ");
195*4882a593Smuzhiyun 			ctx.datalen += 3;
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		if ((ctx.op = find_opcode (ctx.instr)) == 0) {
199*4882a593Smuzhiyun 			/* Illegal Opcode */
200*4882a593Smuzhiyun 			sprintf (&ctx.data[ctx.datalen], "        .long 0x%08lx",
201*4882a593Smuzhiyun 					 ctx.instr);
202*4882a593Smuzhiyun 			ctx.datalen += 24;
203*4882a593Smuzhiyun 			(*pfunc) (ctx.data);
204*4882a593Smuzhiyun 			continue;
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		if (((ctx.flags & F_SIMPLE) == 0) ||
208*4882a593Smuzhiyun 			(ctx.op->hfunc == 0) ||
209*4882a593Smuzhiyun 			((*ctx.op->hfunc) (&ctx) == false)) {
210*4882a593Smuzhiyun 			sprintf (&ctx.data[ctx.datalen], "%-7s ", ctx.op->name);
211*4882a593Smuzhiyun 			ctx.datalen += 8;
212*4882a593Smuzhiyun 			print_operands (&ctx);
213*4882a593Smuzhiyun 		}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		(*pfunc) (ctx.data);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return true;
219*4882a593Smuzhiyun }								/* disppc */
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun /*======================================================================
224*4882a593Smuzhiyun  * Called by the disassembler to print the operands for an instruction.
225*4882a593Smuzhiyun  *
226*4882a593Smuzhiyun  * Arguments:
227*4882a593Smuzhiyun  *	ctx		A pointer to the disassembler context record.
228*4882a593Smuzhiyun  *
229*4882a593Smuzhiyun  * always returns 0.
230*4882a593Smuzhiyun  */
231*4882a593Smuzhiyun 
print_operands(struct ppc_ctx * ctx)232*4882a593Smuzhiyun int print_operands (struct ppc_ctx *ctx)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	int open_parens = 0;
235*4882a593Smuzhiyun 	int field;
236*4882a593Smuzhiyun 	unsigned long operand;
237*4882a593Smuzhiyun 	struct operand *opr;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
240*4882a593Smuzhiyun 	char *symname;
241*4882a593Smuzhiyun 	int offset;
242*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
243*4882a593Smuzhiyun   /*------------------------------------------------------------*/
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* Walk through the operands and list each in order */
246*4882a593Smuzhiyun 	for (field = 0; ctx->op->fields[field] != 0; ++field) {
247*4882a593Smuzhiyun 		if (ctx->op->fields[field] > n_operands) {
248*4882a593Smuzhiyun 			continue;			/* bad operand ?! */
249*4882a593Smuzhiyun 		}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 		opr = &operands[ctx->op->fields[field] - 1];
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 		if (opr->hint & OH_SILENT) {
254*4882a593Smuzhiyun 			continue;
255*4882a593Smuzhiyun 		}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		if ((field > 0) && !open_parens) {
258*4882a593Smuzhiyun 			strcat (ctx->data, ",");
259*4882a593Smuzhiyun 			ctx->datalen++;
260*4882a593Smuzhiyun 		}
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		operand = (ctx->instr >> opr->shift) & ((1 << opr->bits) - 1);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 		if (opr->hint & OH_ADDR) {
265*4882a593Smuzhiyun 			if ((operand & (1 << (opr->bits - 1))) != 0) {
266*4882a593Smuzhiyun 				operand = operand - (1 << opr->bits);
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 			if (ctx->op->hint & H_RELATIVE)
270*4882a593Smuzhiyun 				operand = (operand << 2) + (unsigned long) ctx->virtual;
271*4882a593Smuzhiyun 			else
272*4882a593Smuzhiyun 				operand = (operand << 2);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 			sprintf (&ctx->data[ctx->datalen], "0x%lx", operand);
276*4882a593Smuzhiyun 			ctx->datalen = strlen (ctx->data);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
279*4882a593Smuzhiyun 			if ((ctx->flags & F_SYMBOL) &&
280*4882a593Smuzhiyun 				((symname =
281*4882a593Smuzhiyun 				  symbol_name_from_addr (operand, 0, &offset)) != 0)) {
282*4882a593Smuzhiyun 				sprintf (&ctx->data[ctx->datalen], " <%s", symname);
283*4882a593Smuzhiyun 				if (offset != 0) {
284*4882a593Smuzhiyun 					strcat (ctx->data, "+");
285*4882a593Smuzhiyun 					ctx->datalen = strlen (ctx->data);
286*4882a593Smuzhiyun 					sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
287*4882a593Smuzhiyun 							 offset);
288*4882a593Smuzhiyun 				}
289*4882a593Smuzhiyun 				strcat (ctx->data, ">");
290*4882a593Smuzhiyun 			}
291*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
292*4882a593Smuzhiyun 		}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 		else if (opr->hint & OH_REG) {
295*4882a593Smuzhiyun 			if ((operand == 0) &&
296*4882a593Smuzhiyun 				(opr->field == O_rA) && (ctx->op->hint & H_RA0_IS_0)) {
297*4882a593Smuzhiyun 				strcat (ctx->data, "0");
298*4882a593Smuzhiyun 			} else {
299*4882a593Smuzhiyun 				sprintf (&ctx->data[ctx->datalen], "r%d", (short) operand);
300*4882a593Smuzhiyun 			}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 			if (open_parens) {
303*4882a593Smuzhiyun 				strcat (ctx->data, ")");
304*4882a593Smuzhiyun 				open_parens--;
305*4882a593Smuzhiyun 			}
306*4882a593Smuzhiyun 		}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		else if (opr->hint & OH_SPR) {
309*4882a593Smuzhiyun 			strcat (ctx->data, spr_name (operand));
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		else if (opr->hint & OH_TBR) {
313*4882a593Smuzhiyun 			strcat (ctx->data, tbr_name (operand));
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		else if (opr->hint & OH_LITERAL) {
317*4882a593Smuzhiyun 			switch (opr->field) {
318*4882a593Smuzhiyun 			case O_cr2:
319*4882a593Smuzhiyun 				strcat (ctx->data, "cr2");
320*4882a593Smuzhiyun 				ctx->datalen += 3;
321*4882a593Smuzhiyun 				break;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 			default:
324*4882a593Smuzhiyun 				break;
325*4882a593Smuzhiyun 			}
326*4882a593Smuzhiyun 		}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 		else {
329*4882a593Smuzhiyun 			sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
330*4882a593Smuzhiyun 					 (unsigned short) operand);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 			if (open_parens) {
333*4882a593Smuzhiyun 				strcat (ctx->data, ")");
334*4882a593Smuzhiyun 				open_parens--;
335*4882a593Smuzhiyun 			}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 			else if (opr->hint & OH_OFFSET) {
338*4882a593Smuzhiyun 				strcat (ctx->data, "(");
339*4882a593Smuzhiyun 				open_parens++;
340*4882a593Smuzhiyun 			}
341*4882a593Smuzhiyun 		}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		ctx->datalen = strlen (ctx->data);
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	return 0;
347*4882a593Smuzhiyun }								/* print_operands */
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /*======================================================================
352*4882a593Smuzhiyun  * Called to get the value of an arbitrary operand with in an instruction.
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  * Arguments:
355*4882a593Smuzhiyun  *	op		The pointer to the opcode structure to which
356*4882a593Smuzhiyun  *			the operands belong.
357*4882a593Smuzhiyun  *
358*4882a593Smuzhiyun  *	instr		The instruction (32 bits) containing the opcode
359*4882a593Smuzhiyun  *			and the operands to print.  By the time that
360*4882a593Smuzhiyun  *			this routine is called the operand has already
361*4882a593Smuzhiyun  *			been added to the output.
362*4882a593Smuzhiyun  *
363*4882a593Smuzhiyun  *	field		The field (operand) to get the value of.
364*4882a593Smuzhiyun  *
365*4882a593Smuzhiyun  *	value		The address of an unsigned long to be filled in
366*4882a593Smuzhiyun  *			with the value of the operand if it is found.  This
367*4882a593Smuzhiyun  *			will only be filled in if the function returns
368*4882a593Smuzhiyun  *			true.  This may be passed as 0 if the value is
369*4882a593Smuzhiyun  *			not required.
370*4882a593Smuzhiyun  *
371*4882a593Smuzhiyun  * Returns true if the operand was found or false if it was not.
372*4882a593Smuzhiyun  */
373*4882a593Smuzhiyun 
get_operand_value(struct opcode * op,unsigned long instr,enum OP_FIELD field,unsigned long * value)374*4882a593Smuzhiyun int get_operand_value (struct opcode *op, unsigned long instr,
375*4882a593Smuzhiyun 					   enum OP_FIELD field, unsigned long *value)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	int i;
378*4882a593Smuzhiyun 	struct operand *opr;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun   /*------------------------------------------------------------*/
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (field > n_operands) {
383*4882a593Smuzhiyun 		return false;			/* bad operand ?! */
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	/* Walk through the operands and list each in order */
387*4882a593Smuzhiyun 	for (i = 0; op->fields[i] != 0; ++i) {
388*4882a593Smuzhiyun 		if (op->fields[i] != field) {
389*4882a593Smuzhiyun 			continue;
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 		opr = &operands[op->fields[i] - 1];
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		if (value) {
395*4882a593Smuzhiyun 			*value = (instr >> opr->shift) & ((1 << opr->bits) - 1);
396*4882a593Smuzhiyun 		}
397*4882a593Smuzhiyun 		return true;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	return false;
401*4882a593Smuzhiyun }								/* operand_value */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun /*======================================================================
406*4882a593Smuzhiyun  * Called by the disassembler to match an opcode value to an opcode structure.
407*4882a593Smuzhiyun  *
408*4882a593Smuzhiyun  * Arguments:
409*4882a593Smuzhiyun  *	instr		The instruction (32 bits) to match.  This value
410*4882a593Smuzhiyun  *			may contain operand values as well as the opcode
411*4882a593Smuzhiyun  *			since they will be masked out anyway for this
412*4882a593Smuzhiyun  *			search.
413*4882a593Smuzhiyun  *
414*4882a593Smuzhiyun  * Returns the address of an opcode struct (from the opcode table) if the
415*4882a593Smuzhiyun  * operand successfully matched an entry, or 0 if no match was found.
416*4882a593Smuzhiyun  */
417*4882a593Smuzhiyun 
find_opcode(unsigned long instr)418*4882a593Smuzhiyun struct opcode *find_opcode (unsigned long instr)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	struct opcode *ptr;
421*4882a593Smuzhiyun 	int top = 0;
422*4882a593Smuzhiyun 	int bottom = n_opcodes - 1;
423*4882a593Smuzhiyun 	int idx;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun   /*------------------------------------------------------------*/
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	while (top <= bottom) {
428*4882a593Smuzhiyun 		idx = (top + bottom) >> 1;
429*4882a593Smuzhiyun 		ptr = &opcodes[idx];
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 		if ((instr & ptr->mask) < ptr->opcode) {
432*4882a593Smuzhiyun 			bottom = idx - 1;
433*4882a593Smuzhiyun 		} else if ((instr & ptr->mask) > ptr->opcode) {
434*4882a593Smuzhiyun 			top = idx + 1;
435*4882a593Smuzhiyun 		} else {
436*4882a593Smuzhiyun 			return ptr;
437*4882a593Smuzhiyun 		}
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	return (struct opcode *) 0;
441*4882a593Smuzhiyun }								/* find_opcode */
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun /*======================================================================
446*4882a593Smuzhiyun  * Called by the assembler to match an opcode name to an opcode structure.
447*4882a593Smuzhiyun  *
448*4882a593Smuzhiyun  * Arguments:
449*4882a593Smuzhiyun  *	name		The text name of the opcode, e.g. "b", "mtspr", etc.
450*4882a593Smuzhiyun  *
451*4882a593Smuzhiyun  * The opcodes are sorted numerically by their instruction binary code
452*4882a593Smuzhiyun  * so a search for the name cannot use the binary search used by the
453*4882a593Smuzhiyun  * other find routine.
454*4882a593Smuzhiyun  *
455*4882a593Smuzhiyun  * Returns the address of an opcode struct (from the opcode table) if the
456*4882a593Smuzhiyun  * name successfully matched an entry, or 0 if no match was found.
457*4882a593Smuzhiyun  */
458*4882a593Smuzhiyun 
find_opcode_by_name(char * name)459*4882a593Smuzhiyun struct opcode *find_opcode_by_name (char *name)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	int idx;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun   /*------------------------------------------------------------*/
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	downstring (name);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	for (idx = 0; idx < n_opcodes; ++idx) {
468*4882a593Smuzhiyun 		if (!strcmp (name, opcodes[idx].name))
469*4882a593Smuzhiyun 			return &opcodes[idx];
470*4882a593Smuzhiyun 	}
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return (struct opcode *) 0;
473*4882a593Smuzhiyun }								/* find_opcode_by_name */
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun /*======================================================================
478*4882a593Smuzhiyun  * Convert the 'spr' operand from its numeric value to its symbolic name.
479*4882a593Smuzhiyun  *
480*4882a593Smuzhiyun  * Arguments:
481*4882a593Smuzhiyun  *	value		The value of the 'spr' operand.  This value should
482*4882a593Smuzhiyun  *			be unmodified from its encoding in the instruction.
483*4882a593Smuzhiyun  *			the split-field computations will be performed
484*4882a593Smuzhiyun  *			here before the switch.
485*4882a593Smuzhiyun  *
486*4882a593Smuzhiyun  * Returns the address of a character array containing the name of the
487*4882a593Smuzhiyun  * special purpose register defined by the 'value' parameter, or the
488*4882a593Smuzhiyun  * address of a character array containing "???" if no match was found.
489*4882a593Smuzhiyun  */
490*4882a593Smuzhiyun 
spr_name(int value)491*4882a593Smuzhiyun char *spr_name (int value)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	unsigned short spr;
494*4882a593Smuzhiyun 	static char other[10];
495*4882a593Smuzhiyun 	int i;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun   /*------------------------------------------------------------*/
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/* spr is a 10 bit field whose interpretation has the high and low
500*4882a593Smuzhiyun 	   five-bit fields reversed from their encoding in the operand */
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	spr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	for (i = 0; i < n_sprs; ++i) {
505*4882a593Smuzhiyun 		if (spr == spr_map[i].spr_val)
506*4882a593Smuzhiyun 			return spr_map[i].spr_name;
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	sprintf (other, "%d", spr);
510*4882a593Smuzhiyun 	return other;
511*4882a593Smuzhiyun }								/* spr_name */
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun /*======================================================================
516*4882a593Smuzhiyun  * Convert the 'spr' operand from its symbolic name to its numeric value
517*4882a593Smuzhiyun  *
518*4882a593Smuzhiyun  * Arguments:
519*4882a593Smuzhiyun  *	name		The symbolic name of the 'spr' operand.  The
520*4882a593Smuzhiyun  *			split-field encoding will be done by this routine.
521*4882a593Smuzhiyun  *			NOTE: name can be a number.
522*4882a593Smuzhiyun  *
523*4882a593Smuzhiyun  * Returns the numeric value for the spr appropriate for encoding a machine
524*4882a593Smuzhiyun  * instruction.  Returns 0 if unable to find the SPR.
525*4882a593Smuzhiyun  */
526*4882a593Smuzhiyun 
spr_value(char * name)527*4882a593Smuzhiyun int spr_value (char *name)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	struct spr_info *sprp;
530*4882a593Smuzhiyun 	int spr;
531*4882a593Smuzhiyun 	int i;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun   /*------------------------------------------------------------*/
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	if (!name || !*name)
536*4882a593Smuzhiyun 		return 0;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	if (isdigit ((int) name[0])) {
539*4882a593Smuzhiyun 		i = htonl (read_number (name));
540*4882a593Smuzhiyun 		spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
541*4882a593Smuzhiyun 		return spr;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	downstring (name);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	for (i = 0; i < n_sprs; ++i) {
547*4882a593Smuzhiyun 		sprp = &spr_map[i];
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		if (strcmp (name, sprp->spr_name) == 0) {
550*4882a593Smuzhiyun 			/* spr is a 10 bit field whose interpretation has the high and low
551*4882a593Smuzhiyun 			   five-bit fields reversed from their encoding in the operand */
552*4882a593Smuzhiyun 			i = htonl (sprp->spr_val);
553*4882a593Smuzhiyun 			spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 			return spr;
556*4882a593Smuzhiyun 		}
557*4882a593Smuzhiyun 	}
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	return 0;
560*4882a593Smuzhiyun }								/* spr_value */
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun /*======================================================================
565*4882a593Smuzhiyun  * Convert the 'tbr' operand from its numeric value to its symbolic name.
566*4882a593Smuzhiyun  *
567*4882a593Smuzhiyun  * Arguments:
568*4882a593Smuzhiyun  *	value		The value of the 'tbr' operand.  This value should
569*4882a593Smuzhiyun  *			be unmodified from its encoding in the instruction.
570*4882a593Smuzhiyun  *			the split-field computations will be performed
571*4882a593Smuzhiyun  *			here before the switch.
572*4882a593Smuzhiyun  *
573*4882a593Smuzhiyun  * Returns the address of a character array containing the name of the
574*4882a593Smuzhiyun  * time base register defined by the 'value' parameter, or the address
575*4882a593Smuzhiyun  * of a character array containing "???" if no match was found.
576*4882a593Smuzhiyun  */
577*4882a593Smuzhiyun 
tbr_name(int value)578*4882a593Smuzhiyun char *tbr_name (int value)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	unsigned short tbr;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun   /*------------------------------------------------------------*/
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	/* tbr is a 10 bit field whose interpretation has the high and low
585*4882a593Smuzhiyun 	   five-bit fields reversed from their encoding in the operand */
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	tbr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (tbr == 268)
590*4882a593Smuzhiyun 		return "TBL";
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	else if (tbr == 269)
593*4882a593Smuzhiyun 		return "TBU";
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	return "???";
597*4882a593Smuzhiyun }								/* tbr_name */
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun /*======================================================================
602*4882a593Smuzhiyun  * Convert the 'tbr' operand from its symbolic name to its numeric value.
603*4882a593Smuzhiyun  *
604*4882a593Smuzhiyun  * Arguments:
605*4882a593Smuzhiyun  *	name		The symbolic name of the 'tbr' operand.  The
606*4882a593Smuzhiyun  *			split-field encoding will be done by this routine.
607*4882a593Smuzhiyun  *
608*4882a593Smuzhiyun  * Returns the numeric value for the spr appropriate for encoding a machine
609*4882a593Smuzhiyun  * instruction.  Returns 0 if unable to find the TBR.
610*4882a593Smuzhiyun  */
611*4882a593Smuzhiyun 
tbr_value(char * name)612*4882a593Smuzhiyun int tbr_value (char *name)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun 	int tbr;
615*4882a593Smuzhiyun 	int val;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun   /*------------------------------------------------------------*/
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	if (!name || !*name)
620*4882a593Smuzhiyun 		return 0;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	downstring (name);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	if (isdigit ((int) name[0])) {
625*4882a593Smuzhiyun 		val = read_number (name);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 		if (val != 268 && val != 269)
628*4882a593Smuzhiyun 			return 0;
629*4882a593Smuzhiyun 	} else if (strcmp (name, "tbl") == 0)
630*4882a593Smuzhiyun 		val = 268;
631*4882a593Smuzhiyun 	else if (strcmp (name, "tbu") == 0)
632*4882a593Smuzhiyun 		val = 269;
633*4882a593Smuzhiyun 	else
634*4882a593Smuzhiyun 		return 0;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	/* tbr is a 10 bit field whose interpretation has the high and low
637*4882a593Smuzhiyun 	   five-bit fields reversed from their encoding in the operand */
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	val = htonl (val);
640*4882a593Smuzhiyun 	tbr = ((val >> 5) & 0x1f) | ((val & 0x1f) << 5);
641*4882a593Smuzhiyun 	return tbr;
642*4882a593Smuzhiyun }								/* tbr_name */
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun /*======================================================================
647*4882a593Smuzhiyun  * The next several functions (handle_xxx) are the routines that handle
648*4882a593Smuzhiyun  * disassembling the opcodes with simplified mnemonics.
649*4882a593Smuzhiyun  *
650*4882a593Smuzhiyun  * Arguments:
651*4882a593Smuzhiyun  *	ctx		A pointer to the disassembler context record.
652*4882a593Smuzhiyun  *
653*4882a593Smuzhiyun  * Returns true if the simpler form was printed or false if it was not.
654*4882a593Smuzhiyun  */
655*4882a593Smuzhiyun 
handle_bc(struct ppc_ctx * ctx)656*4882a593Smuzhiyun int handle_bc (struct ppc_ctx *ctx)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	unsigned long bo;
659*4882a593Smuzhiyun 	unsigned long bi;
660*4882a593Smuzhiyun 	static struct opcode blt = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
661*4882a593Smuzhiyun 	0, "blt", H_RELATIVE
662*4882a593Smuzhiyun 	};
663*4882a593Smuzhiyun 	static struct opcode bne =
664*4882a593Smuzhiyun 			{ B_OPCODE (16, 0, 0), B_MASK, {O_cr2, O_BD, 0},
665*4882a593Smuzhiyun 	0, "bne", H_RELATIVE
666*4882a593Smuzhiyun 	};
667*4882a593Smuzhiyun 	static struct opcode bdnz = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
668*4882a593Smuzhiyun 	0, "bdnz", H_RELATIVE
669*4882a593Smuzhiyun 	};
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun   /*------------------------------------------------------------*/
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	if (get_operand_value(ctx->op, ctx->instr, O_BO, &bo) == false)
674*4882a593Smuzhiyun 		return false;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (get_operand_value(ctx->op, ctx->instr, O_BI, &bi) == false)
677*4882a593Smuzhiyun 		return false;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	if ((bo == 12) && (bi == 0)) {
680*4882a593Smuzhiyun 		ctx->op = &blt;
681*4882a593Smuzhiyun 		sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
682*4882a593Smuzhiyun 		ctx->datalen += 8;
683*4882a593Smuzhiyun 		print_operands (ctx);
684*4882a593Smuzhiyun 		return true;
685*4882a593Smuzhiyun 	} else if ((bo == 4) && (bi == 10)) {
686*4882a593Smuzhiyun 		ctx->op = &bne;
687*4882a593Smuzhiyun 		sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
688*4882a593Smuzhiyun 		ctx->datalen += 8;
689*4882a593Smuzhiyun 		print_operands (ctx);
690*4882a593Smuzhiyun 		return true;
691*4882a593Smuzhiyun 	} else if ((bo == 16) && (bi == 0)) {
692*4882a593Smuzhiyun 		ctx->op = &bdnz;
693*4882a593Smuzhiyun 		sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
694*4882a593Smuzhiyun 		ctx->datalen += 8;
695*4882a593Smuzhiyun 		print_operands (ctx);
696*4882a593Smuzhiyun 		return true;
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	return false;
700*4882a593Smuzhiyun }								/* handle_blt */
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun /*======================================================================
705*4882a593Smuzhiyun  * Outputs source line information for the disassembler.  This should
706*4882a593Smuzhiyun  * be modified in the future to lookup the actual line of source code
707*4882a593Smuzhiyun  * from the file, but for now this will do.
708*4882a593Smuzhiyun  *
709*4882a593Smuzhiyun  * Arguments:
710*4882a593Smuzhiyun  *	filename	The address of a character array containing the
711*4882a593Smuzhiyun  *			absolute path and file name of the source file.
712*4882a593Smuzhiyun  *
713*4882a593Smuzhiyun  *	funcname	The address of a character array containing the
714*4882a593Smuzhiyun  *			name of the function (not C++ demangled (yet))
715*4882a593Smuzhiyun  *			to which this code belongs.
716*4882a593Smuzhiyun  *
717*4882a593Smuzhiyun  *	line_no		An integer specifying the source line number that
718*4882a593Smuzhiyun  *			generated this code.
719*4882a593Smuzhiyun  *
720*4882a593Smuzhiyun  *	pfunc		The address of a function to call to print the output.
721*4882a593Smuzhiyun  *
722*4882a593Smuzhiyun  *
723*4882a593Smuzhiyun  * Returns true if it was able to output the line info, or false if it was
724*4882a593Smuzhiyun  * not.
725*4882a593Smuzhiyun  */
726*4882a593Smuzhiyun 
print_source_line(char * filename,char * funcname,int line_no,int (* pfunc)(const char *))727*4882a593Smuzhiyun int print_source_line (char *filename, char *funcname,
728*4882a593Smuzhiyun 					   int line_no, int (*pfunc) (const char *))
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun 	char out_buf[256];
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun   /*------------------------------------------------------------*/
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	(*pfunc) ("");				/* output a newline */
735*4882a593Smuzhiyun 	sprintf (out_buf, "%s %s(): line %d", filename, funcname, line_no);
736*4882a593Smuzhiyun 	(*pfunc) (out_buf);
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	return true;
739*4882a593Smuzhiyun }								/* print_source_line */
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun /*======================================================================
744*4882a593Smuzhiyun  * Entry point for the PPC assembler.
745*4882a593Smuzhiyun  *
746*4882a593Smuzhiyun  * Arguments:
747*4882a593Smuzhiyun  *	asm_buf		An array of characters containing the assembly opcode
748*4882a593Smuzhiyun  *			and operands to convert to a POWERPC machine
749*4882a593Smuzhiyun  *			instruction.
750*4882a593Smuzhiyun  *
751*4882a593Smuzhiyun  * Returns the machine instruction or zero.
752*4882a593Smuzhiyun  */
753*4882a593Smuzhiyun 
asmppc(unsigned long memaddr,char * asm_buf,int * err)754*4882a593Smuzhiyun unsigned long asmppc (unsigned long memaddr, char *asm_buf, int *err)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun 	struct opcode *opc;
757*4882a593Smuzhiyun 	struct operand *oper[MAX_OPERANDS];
758*4882a593Smuzhiyun 	unsigned long instr;
759*4882a593Smuzhiyun 	unsigned long param;
760*4882a593Smuzhiyun 	char *ptr = asm_buf;
761*4882a593Smuzhiyun 	char scratch[20];
762*4882a593Smuzhiyun 	int i;
763*4882a593Smuzhiyun 	int w_operands = 0;			/* wanted # of operands */
764*4882a593Smuzhiyun 	int n_operands = 0;			/* # of operands read */
765*4882a593Smuzhiyun 	int asm_debug = 0;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun   /*------------------------------------------------------------*/
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	if (err)
770*4882a593Smuzhiyun 		*err = 0;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	if (get_word (&ptr, scratch) == 0)
773*4882a593Smuzhiyun 		return 0;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* Lookup the opcode structure based on the opcode name */
776*4882a593Smuzhiyun 	if ((opc = find_opcode_by_name (scratch)) == (struct opcode *) 0) {
777*4882a593Smuzhiyun 		if (err)
778*4882a593Smuzhiyun 			*err = E_ASM_BAD_OPCODE;
779*4882a593Smuzhiyun 		return 0;
780*4882a593Smuzhiyun 	}
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	if (asm_debug) {
783*4882a593Smuzhiyun 		printf ("asmppc: Opcode = \"%s\"\n", opc->name);
784*4882a593Smuzhiyun 	}
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	for (i = 0; i < 8; ++i) {
787*4882a593Smuzhiyun 		if (opc->fields[i] == 0)
788*4882a593Smuzhiyun 			break;
789*4882a593Smuzhiyun 		++w_operands;
790*4882a593Smuzhiyun 	}
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	if (asm_debug) {
793*4882a593Smuzhiyun 		printf ("asmppc: Expecting %d operands\n", w_operands);
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	instr = opc->opcode;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	/* read each operand */
799*4882a593Smuzhiyun 	while (n_operands < w_operands) {
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 		oper[n_operands] = &operands[opc->fields[n_operands] - 1];
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 		if (oper[n_operands]->hint & OH_SILENT) {
804*4882a593Smuzhiyun 			/* Skip silent operands, they are covered in opc->opcode */
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 			if (asm_debug) {
807*4882a593Smuzhiyun 				printf ("asmppc: Operand %d \"%s\" SILENT\n", n_operands,
808*4882a593Smuzhiyun 						oper[n_operands]->name);
809*4882a593Smuzhiyun 			}
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 			++n_operands;
812*4882a593Smuzhiyun 			continue;
813*4882a593Smuzhiyun 		}
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 		if (get_word (&ptr, scratch) == 0)
816*4882a593Smuzhiyun 			break;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 		if (asm_debug) {
819*4882a593Smuzhiyun 			printf ("asmppc: Operand %d \"%s\" : \"%s\"\n", n_operands,
820*4882a593Smuzhiyun 					oper[n_operands]->name, scratch);
821*4882a593Smuzhiyun 		}
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 		if ((param = parse_operand (memaddr, opc, oper[n_operands],
824*4882a593Smuzhiyun 									scratch, err)) == -1)
825*4882a593Smuzhiyun 			return 0;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 		instr |= param;
828*4882a593Smuzhiyun 		++n_operands;
829*4882a593Smuzhiyun 	}
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	if (n_operands < w_operands) {
832*4882a593Smuzhiyun 		if (err)
833*4882a593Smuzhiyun 			*err = E_ASM_NUM_OPERANDS;
834*4882a593Smuzhiyun 		return 0;
835*4882a593Smuzhiyun 	}
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	if (asm_debug) {
838*4882a593Smuzhiyun 		printf ("asmppc: Instruction = 0x%08lx\n", instr);
839*4882a593Smuzhiyun 	}
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	return instr;
842*4882a593Smuzhiyun }								/* asmppc */
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun /*======================================================================
847*4882a593Smuzhiyun  * Called by the assembler to interpret a single operand
848*4882a593Smuzhiyun  *
849*4882a593Smuzhiyun  * Arguments:
850*4882a593Smuzhiyun  *	ctx		A pointer to the disassembler context record.
851*4882a593Smuzhiyun  *
852*4882a593Smuzhiyun  * Returns 0 if the operand is ok, or -1 if it is bad.
853*4882a593Smuzhiyun  */
854*4882a593Smuzhiyun 
parse_operand(unsigned long memaddr,struct opcode * opc,struct operand * oper,char * txt,int * err)855*4882a593Smuzhiyun int parse_operand (unsigned long memaddr, struct opcode *opc,
856*4882a593Smuzhiyun 				   struct operand *oper, char *txt, int *err)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun 	long data;
859*4882a593Smuzhiyun 	long mask;
860*4882a593Smuzhiyun 	int is_neg = 0;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun   /*------------------------------------------------------------*/
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	mask = (1 << oper->bits) - 1;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	if (oper->hint & OH_ADDR) {
867*4882a593Smuzhiyun 		data = read_number (txt);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 		if (opc->hint & H_RELATIVE)
870*4882a593Smuzhiyun 			data = data - memaddr;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 		if (data < 0)
873*4882a593Smuzhiyun 			is_neg = 1;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		data >>= 2;
876*4882a593Smuzhiyun 		data &= (mask >> 1);
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 		if (is_neg)
879*4882a593Smuzhiyun 			data |= 1 << (oper->bits - 1);
880*4882a593Smuzhiyun 	}
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	else if (oper->hint & OH_REG) {
883*4882a593Smuzhiyun 		if (txt[0] == 'r' || txt[0] == 'R')
884*4882a593Smuzhiyun 			txt++;
885*4882a593Smuzhiyun 		else if (txt[0] == '%' && (txt[1] == 'r' || txt[1] == 'R'))
886*4882a593Smuzhiyun 			txt += 2;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 		data = read_number (txt);
889*4882a593Smuzhiyun 		if (data > 31) {
890*4882a593Smuzhiyun 			if (err)
891*4882a593Smuzhiyun 				*err = E_ASM_BAD_REGISTER;
892*4882a593Smuzhiyun 			return -1;
893*4882a593Smuzhiyun 		}
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 		data = htonl (data);
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	else if (oper->hint & OH_SPR) {
899*4882a593Smuzhiyun 		if ((data = spr_value (txt)) == 0) {
900*4882a593Smuzhiyun 			if (err)
901*4882a593Smuzhiyun 				*err = E_ASM_BAD_SPR;
902*4882a593Smuzhiyun 			return -1;
903*4882a593Smuzhiyun 		}
904*4882a593Smuzhiyun 	}
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	else if (oper->hint & OH_TBR) {
907*4882a593Smuzhiyun 		if ((data = tbr_value (txt)) == 0) {
908*4882a593Smuzhiyun 			if (err)
909*4882a593Smuzhiyun 				*err = E_ASM_BAD_TBR;
910*4882a593Smuzhiyun 			return -1;
911*4882a593Smuzhiyun 		}
912*4882a593Smuzhiyun 	}
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	else {
915*4882a593Smuzhiyun 		data = htonl (read_number (txt));
916*4882a593Smuzhiyun 	}
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	return (data & mask) << oper->shift;
919*4882a593Smuzhiyun }								/* parse_operand */
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 
asm_error_str(int err)922*4882a593Smuzhiyun char *asm_error_str (int err)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun 	switch (err) {
925*4882a593Smuzhiyun 	case E_ASM_BAD_OPCODE:
926*4882a593Smuzhiyun 		return "Bad opcode";
927*4882a593Smuzhiyun 	case E_ASM_NUM_OPERANDS:
928*4882a593Smuzhiyun 		return "Bad number of operands";
929*4882a593Smuzhiyun 	case E_ASM_BAD_REGISTER:
930*4882a593Smuzhiyun 		return "Bad register number";
931*4882a593Smuzhiyun 	case E_ASM_BAD_SPR:
932*4882a593Smuzhiyun 		return "Bad SPR name or number";
933*4882a593Smuzhiyun 	case E_ASM_BAD_TBR:
934*4882a593Smuzhiyun 		return "Bad TBR name or number";
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	return "";
938*4882a593Smuzhiyun }								/* asm_error_str */
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun /*======================================================================
943*4882a593Smuzhiyun  * Copy a word from one buffer to another, ignores leading white spaces.
944*4882a593Smuzhiyun  *
945*4882a593Smuzhiyun  * Arguments:
946*4882a593Smuzhiyun  *	src		The address of a character pointer to the
947*4882a593Smuzhiyun  *			source buffer.
948*4882a593Smuzhiyun  *	dest		A pointer to a character buffer to write the word
949*4882a593Smuzhiyun  *			into.
950*4882a593Smuzhiyun  *
951*4882a593Smuzhiyun  * Returns the number of non-white space characters copied, or zero.
952*4882a593Smuzhiyun  */
953*4882a593Smuzhiyun 
get_word(char ** src,char * dest)954*4882a593Smuzhiyun int get_word (char **src, char *dest)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun 	char *ptr = *src;
957*4882a593Smuzhiyun 	int nchars = 0;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun   /*------------------------------------------------------------*/
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	/* Eat white spaces */
962*4882a593Smuzhiyun 	while (*ptr && isblank (*ptr))
963*4882a593Smuzhiyun 		ptr++;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	if (*ptr == 0) {
966*4882a593Smuzhiyun 		*src = ptr;
967*4882a593Smuzhiyun 		return 0;
968*4882a593Smuzhiyun 	}
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	/* Find the text of the word */
971*4882a593Smuzhiyun 	while (*ptr && !isblank (*ptr) && (*ptr != ','))
972*4882a593Smuzhiyun 		dest[nchars++] = *ptr++;
973*4882a593Smuzhiyun 	ptr = (*ptr == ',') ? ptr + 1 : ptr;
974*4882a593Smuzhiyun 	dest[nchars] = 0;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	*src = ptr;
977*4882a593Smuzhiyun 	return nchars;
978*4882a593Smuzhiyun }								/* get_word */
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun /*======================================================================
983*4882a593Smuzhiyun  * Convert a numeric string to a number, be aware of base notations.
984*4882a593Smuzhiyun  *
985*4882a593Smuzhiyun  * Arguments:
986*4882a593Smuzhiyun  *	txt		The numeric string.
987*4882a593Smuzhiyun  *
988*4882a593Smuzhiyun  * Returns the converted numeric value.
989*4882a593Smuzhiyun  */
990*4882a593Smuzhiyun 
read_number(char * txt)991*4882a593Smuzhiyun long read_number (char *txt)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun 	long val;
994*4882a593Smuzhiyun 	int is_neg = 0;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun   /*------------------------------------------------------------*/
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	if (txt == 0 || *txt == 0)
999*4882a593Smuzhiyun 		return 0;
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	if (*txt == '-') {
1002*4882a593Smuzhiyun 		is_neg = 1;
1003*4882a593Smuzhiyun 		++txt;
1004*4882a593Smuzhiyun 	}
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	if (txt[0] == '0' && (txt[1] == 'x' || txt[1] == 'X'))	/* hex */
1007*4882a593Smuzhiyun 		val = simple_strtoul (&txt[2], NULL, 16);
1008*4882a593Smuzhiyun 	else						/* decimal */
1009*4882a593Smuzhiyun 		val = simple_strtoul (txt, NULL, 10);
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	if (is_neg)
1012*4882a593Smuzhiyun 		val = -val;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	return val;
1015*4882a593Smuzhiyun }								/* read_number */
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 
downstring(char * s)1018*4882a593Smuzhiyun int downstring (char *s)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun 	if (!s || !*s)
1021*4882a593Smuzhiyun 		return 0;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	while (*s) {
1024*4882a593Smuzhiyun 		if (isupper (*s))
1025*4882a593Smuzhiyun 			*s = tolower (*s);
1026*4882a593Smuzhiyun 		s++;
1027*4882a593Smuzhiyun 	}
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	return 0;
1030*4882a593Smuzhiyun }								/* downstring */
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun /*======================================================================
1035*4882a593Smuzhiyun  * Examines the instruction at the current address and determines the
1036*4882a593Smuzhiyun  * next address to be executed.  This will take into account branches
1037*4882a593Smuzhiyun  * of different types so that a "step" and "next" operations can be
1038*4882a593Smuzhiyun  * supported.
1039*4882a593Smuzhiyun  *
1040*4882a593Smuzhiyun  * Arguments:
1041*4882a593Smuzhiyun  *	nextaddr	The address (to be filled in) of the next
1042*4882a593Smuzhiyun  *			instruction to execute.  This will only be a valid
1043*4882a593Smuzhiyun  *			address if true is returned.
1044*4882a593Smuzhiyun  *
1045*4882a593Smuzhiyun  *	step_over	A flag indicating how to compute addresses for
1046*4882a593Smuzhiyun  *			branch statements:
1047*4882a593Smuzhiyun  *			 true  = Step over the branch (next)
1048*4882a593Smuzhiyun  *			 false = step into the branch (step)
1049*4882a593Smuzhiyun  *
1050*4882a593Smuzhiyun  * Returns true if it was able to compute the address.  Returns false if
1051*4882a593Smuzhiyun  * it has a problem reading the current instruction or one of the registers.
1052*4882a593Smuzhiyun  */
1053*4882a593Smuzhiyun 
find_next_address(unsigned char * nextaddr,int step_over,struct pt_regs * regs)1054*4882a593Smuzhiyun int find_next_address (unsigned char *nextaddr, int step_over,
1055*4882a593Smuzhiyun 					   struct pt_regs *regs)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun 	unsigned long pc;			/* SRR0 register from PPC */
1058*4882a593Smuzhiyun 	unsigned long ctr;			/* CTR register from PPC */
1059*4882a593Smuzhiyun 	unsigned long cr;			/* CR register from PPC */
1060*4882a593Smuzhiyun 	unsigned long lr;			/* LR register from PPC */
1061*4882a593Smuzhiyun 	unsigned long instr;		/* instruction at SRR0 */
1062*4882a593Smuzhiyun 	unsigned long next;			/* computed instruction for 'next' */
1063*4882a593Smuzhiyun 	unsigned long step;			/* computed instruction for 'step' */
1064*4882a593Smuzhiyun 	unsigned long addr = 0;		/* target address operand */
1065*4882a593Smuzhiyun 	unsigned long aa = 0;		/* AA operand */
1066*4882a593Smuzhiyun 	unsigned long lk = 0;		/* LK operand */
1067*4882a593Smuzhiyun 	unsigned long bo = 0;		/* BO operand */
1068*4882a593Smuzhiyun 	unsigned long bi = 0;		/* BI operand */
1069*4882a593Smuzhiyun 	struct opcode *op = 0;		/* opcode structure for 'instr' */
1070*4882a593Smuzhiyun 	int ctr_ok = 0;
1071*4882a593Smuzhiyun 	int cond_ok = 0;
1072*4882a593Smuzhiyun 	int conditional = 0;
1073*4882a593Smuzhiyun 	int branch = 0;
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun   /*------------------------------------------------------------*/
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	if (nextaddr == 0 || regs == 0) {
1078*4882a593Smuzhiyun 		printf ("find_next_address: bad args");
1079*4882a593Smuzhiyun 		return false;
1080*4882a593Smuzhiyun 	}
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	pc = regs->nip & 0xfffffffc;
1083*4882a593Smuzhiyun 	instr = INSTRUCTION (pc);
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if ((op = find_opcode (instr)) == (struct opcode *) 0) {
1086*4882a593Smuzhiyun 		printf ("find_next_address: can't parse opcode 0x%lx", instr);
1087*4882a593Smuzhiyun 		return false;
1088*4882a593Smuzhiyun 	}
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	ctr = regs->ctr;
1091*4882a593Smuzhiyun 	cr = regs->ccr;
1092*4882a593Smuzhiyun 	lr = regs->link;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	switch (op->opcode) {
1095*4882a593Smuzhiyun 	case B_OPCODE (16, 0, 0):	/* bc */
1096*4882a593Smuzhiyun 	case B_OPCODE (16, 0, 1):	/* bcl */
1097*4882a593Smuzhiyun 	case B_OPCODE (16, 1, 0):	/* bca */
1098*4882a593Smuzhiyun 	case B_OPCODE (16, 1, 1):	/* bcla */
1099*4882a593Smuzhiyun 		if (!get_operand_value (op, instr, O_BD, &addr) ||
1100*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_BO, &bo) ||
1101*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_BI, &bi) ||
1102*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_AA, &aa) ||
1103*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_LK, &lk))
1104*4882a593Smuzhiyun 			return false;
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 		if ((addr & (1 << 13)) != 0)
1107*4882a593Smuzhiyun 			addr = addr - (1 << 14);
1108*4882a593Smuzhiyun 		addr <<= 2;
1109*4882a593Smuzhiyun 		conditional = 1;
1110*4882a593Smuzhiyun 		branch = 1;
1111*4882a593Smuzhiyun 		break;
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun 	case I_OPCODE (18, 0, 0):	/* b */
1114*4882a593Smuzhiyun 	case I_OPCODE (18, 0, 1):	/* bl */
1115*4882a593Smuzhiyun 	case I_OPCODE (18, 1, 0):	/* ba */
1116*4882a593Smuzhiyun 	case I_OPCODE (18, 1, 1):	/* bla */
1117*4882a593Smuzhiyun 		if (!get_operand_value (op, instr, O_LI, &addr) ||
1118*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_AA, &aa) ||
1119*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_LK, &lk))
1120*4882a593Smuzhiyun 			return false;
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 		if ((addr & (1 << 23)) != 0)
1123*4882a593Smuzhiyun 			addr = addr - (1 << 24);
1124*4882a593Smuzhiyun 		addr <<= 2;
1125*4882a593Smuzhiyun 		conditional = 0;
1126*4882a593Smuzhiyun 		branch = 1;
1127*4882a593Smuzhiyun 		break;
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	case XL_OPCODE (19, 528, 0):	/* bcctr */
1130*4882a593Smuzhiyun 	case XL_OPCODE (19, 528, 1):	/* bcctrl */
1131*4882a593Smuzhiyun 		if (!get_operand_value (op, instr, O_BO, &bo) ||
1132*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_BI, &bi) ||
1133*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_LK, &lk))
1134*4882a593Smuzhiyun 			return false;
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 		addr = ctr;
1137*4882a593Smuzhiyun 		aa = 1;
1138*4882a593Smuzhiyun 		conditional = 1;
1139*4882a593Smuzhiyun 		branch = 1;
1140*4882a593Smuzhiyun 		break;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	case XL_OPCODE (19, 16, 0):	/* bclr */
1143*4882a593Smuzhiyun 	case XL_OPCODE (19, 16, 1):	/* bclrl */
1144*4882a593Smuzhiyun 		if (!get_operand_value (op, instr, O_BO, &bo) ||
1145*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_BI, &bi) ||
1146*4882a593Smuzhiyun 			!get_operand_value (op, instr, O_LK, &lk))
1147*4882a593Smuzhiyun 			return false;
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 		addr = lr;
1150*4882a593Smuzhiyun 		aa = 1;
1151*4882a593Smuzhiyun 		conditional = 1;
1152*4882a593Smuzhiyun 		branch = 1;
1153*4882a593Smuzhiyun 		break;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	default:
1156*4882a593Smuzhiyun 		conditional = 0;
1157*4882a593Smuzhiyun 		branch = 0;
1158*4882a593Smuzhiyun 		break;
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	if (conditional) {
1162*4882a593Smuzhiyun 		switch ((bo & 0x1e) >> 1) {
1163*4882a593Smuzhiyun 		case 0:				/* 0000y */
1164*4882a593Smuzhiyun 			if (--ctr != 0)
1165*4882a593Smuzhiyun 				ctr_ok = 1;
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 			cond_ok = !(cr & (1 << (31 - bi)));
1168*4882a593Smuzhiyun 			break;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 		case 1:				/* 0001y */
1171*4882a593Smuzhiyun 			if (--ctr == 0)
1172*4882a593Smuzhiyun 				ctr_ok = 1;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 			cond_ok = !(cr & (1 << (31 - bi)));
1175*4882a593Smuzhiyun 			break;
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 		case 2:				/* 001zy */
1178*4882a593Smuzhiyun 			ctr_ok = 1;
1179*4882a593Smuzhiyun 			cond_ok = !(cr & (1 << (31 - bi)));
1180*4882a593Smuzhiyun 			break;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 		case 4:				/* 0100y */
1183*4882a593Smuzhiyun 			if (--ctr != 0)
1184*4882a593Smuzhiyun 				ctr_ok = 1;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 			cond_ok = cr & (1 << (31 - bi));
1187*4882a593Smuzhiyun 			break;
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 		case 5:				/* 0101y */
1190*4882a593Smuzhiyun 			if (--ctr == 0)
1191*4882a593Smuzhiyun 				ctr_ok = 1;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 			cond_ok = cr & (1 << (31 - bi));
1194*4882a593Smuzhiyun 			break;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 		case 6:				/* 011zy */
1197*4882a593Smuzhiyun 			ctr_ok = 1;
1198*4882a593Smuzhiyun 			cond_ok = cr & (1 << (31 - bi));
1199*4882a593Smuzhiyun 			break;
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 		case 8:				/* 1z00y */
1202*4882a593Smuzhiyun 			if (--ctr != 0)
1203*4882a593Smuzhiyun 				ctr_ok = cond_ok = 1;
1204*4882a593Smuzhiyun 			break;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 		case 9:				/* 1z01y */
1207*4882a593Smuzhiyun 			if (--ctr == 0)
1208*4882a593Smuzhiyun 				ctr_ok = cond_ok = 1;
1209*4882a593Smuzhiyun 			break;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 		case 10:				/* 1z1zz */
1212*4882a593Smuzhiyun 			ctr_ok = cond_ok = 1;
1213*4882a593Smuzhiyun 			break;
1214*4882a593Smuzhiyun 		}
1215*4882a593Smuzhiyun 	}
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	if (branch && (!conditional || (ctr_ok && cond_ok))) {
1218*4882a593Smuzhiyun 		if (aa)
1219*4882a593Smuzhiyun 			step = addr;
1220*4882a593Smuzhiyun 		else
1221*4882a593Smuzhiyun 			step = addr + pc;
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 		if (lk)
1224*4882a593Smuzhiyun 			next = pc + 4;
1225*4882a593Smuzhiyun 		else
1226*4882a593Smuzhiyun 			next = step;
1227*4882a593Smuzhiyun 	} else {
1228*4882a593Smuzhiyun 		step = next = pc + 4;
1229*4882a593Smuzhiyun 	}
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	if (step_over == true)
1232*4882a593Smuzhiyun 		*(unsigned long *) nextaddr = next;
1233*4882a593Smuzhiyun 	else
1234*4882a593Smuzhiyun 		*(unsigned long *) nextaddr = step;
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	return true;
1237*4882a593Smuzhiyun }								/* find_next_address */
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun /*
1241*4882a593Smuzhiyun  * Copyright (c) 2000 William L. Pitts and W. Gerald Hicks
1242*4882a593Smuzhiyun  * All rights reserved.
1243*4882a593Smuzhiyun  *
1244*4882a593Smuzhiyun  * Redistribution and use in source and binary forms are freely
1245*4882a593Smuzhiyun  * permitted provided that the above copyright notice and this
1246*4882a593Smuzhiyun  * paragraph and the following disclaimer are duplicated in all
1247*4882a593Smuzhiyun  * such forms.
1248*4882a593Smuzhiyun  *
1249*4882a593Smuzhiyun  * This software is provided "AS IS" and without any express or
1250*4882a593Smuzhiyun  * implied warranties, including, without limitation, the implied
1251*4882a593Smuzhiyun  * warranties of merchantability and fitness for a particular
1252*4882a593Smuzhiyun  * purpose.
1253*4882a593Smuzhiyun  */
1254