xref: /plan9/sys/src/libmach/kdb.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 /*
7  * Sparc-specific debugger interface
8  */
9 
10 static	char	*sparcexcep(Map*, Rgetter);
11 static	int	sparcfoll(Map*, ulong, Rgetter, ulong*);
12 static	int	sparcinst(Map*, ulong, char, char*, int);
13 static	int	sparcdas(Map*, ulong, char*, int);
14 static	int	sparcinstlen(Map*, ulong);
15 
16 Machdata sparcmach =
17 {
18 	{0x91, 0xd0, 0x20, 0x01},	/* breakpoint: TA $1 */
19 	4,			/* break point size */
20 
21 	beswab,			/* convert short to local byte order */
22 	beswal,			/* convert long to local byte order */
23 	risctrace,		/* C traceback */
24 	riscframe,		/* frame finder */
25 	0,			/* ublock fixup */
26 	sparcexcep,		/* print exception */
27 	0,			/* breakpoint fixup */
28 	beieeesftos,		/* single precision float printer */
29 	beieeedftos,		/* double precision float printer */
30 	sparcfoll,		/* following addresses */
31 	sparcinst,		/* print instruction */
32 	sparcdas,		/* dissembler */
33 	sparcinstlen,		/* instruction size */
34 };
35 
36 static char *trapname[] =
37 {
38 	"reset",
39 	"instruction access exception",
40 	"illegal instruction",
41 	"privileged instruction",
42 	"fp disabled",
43 	"window overflow",
44 	"window underflow",
45 	"unaligned address",
46 	"fp exception",
47 	"data access exception",
48 	"tag overflow",
49 };
50 
51 static char*
52 excname(ulong tbr)
53 {
54 	static char buf[32];
55 
56 	if(tbr < sizeof trapname/sizeof(char*))
57 		return trapname[tbr];
58 	if(tbr >= 130)
59 		sprint(buf, "trap instruction %d", tbr-128);
60 	else if(17<=tbr && tbr<=31)
61 		sprint(buf, "interrupt level %d", tbr-16);
62 	else switch(tbr){
63 	case 36:
64 		return "cp disabled";
65 	case 40:
66 		return "cp exception";
67 	case 128:
68 		return "syscall";
69 	case 129:
70 		return "breakpoint";
71 	default:
72 		sprint(buf, "unknown trap %d", tbr);
73 	}
74     Return:
75 	return buf;
76 }
77 
78 static char*
79 sparcexcep(Map *map, Rgetter rget)
80 {
81 	long tbr;
82 
83 	tbr = (*rget)(map, "TBR");
84 	tbr = (tbr&0xFFF)>>4;
85 	return excname(tbr);
86 }
87 
88 	/* Sparc disassembler and related functions */
89 
90 struct opcode {
91 	char	*mnemonic;
92 	void	(*f)(struct instr*, char*);
93 	int	flag;
94 };
95 
96 static	char FRAMENAME[] = ".frame";
97 
98 typedef struct instr Instr;
99 
100 struct instr {
101 	uchar	op;		/* bits 31-30 */
102 	uchar	rd;		/* bits 29-25 */
103 	uchar	op2;		/* bits 24-22 */
104 	uchar	a;		/* bit  29    */
105 	uchar	cond;		/* bits 28-25 */
106 	uchar	op3;		/* bits 24-19 */
107 	uchar	rs1;		/* bits 18-14 */
108 	uchar	i;		/* bit  13    */
109 	uchar	asi;		/* bits 12-05 */
110 	uchar	rs2;		/* bits 04-00 */
111 	short	simm13;		/* bits 12-00, signed */
112 	ushort	opf;		/* bits 13-05 */
113 	ulong	immdisp22;	/* bits 21-00 */
114 	ulong	simmdisp22;	/* bits 21-00, signed */
115 	ulong	disp30;		/* bits 30-00 */
116 	ulong	imm32;		/* SETHI+ADD constant */
117 	int	target;		/* SETHI+ADD dest reg */
118 	long	w0;
119 	long	w1;
120 	ulong	addr;		/* pc of instruction */
121 	char	*curr;		/* current fill level in output buffer */
122 	char	*end;		/* end of buffer */
123 	int 	size;		/* number of longs in instr */
124 	char	*err;		/* errmsg */
125 };
126 
127 static	Map	*mymap;		/* disassembler context */
128 static	int	dascase;
129 
130 static int	mkinstr(ulong, Instr*);
131 static void	bra1(Instr*, char*, char*[]);
132 static void	bra(Instr*, char*);
133 static void	fbra(Instr*, char*);
134 static void	cbra(Instr*, char*);
135 static void	unimp(Instr*, char*);
136 static void	fpop(Instr*, char*);
137 static void	shift(Instr*, char*);
138 static void	sethi(Instr*, char*);
139 static void	load(Instr*, char*);
140 static void	loada(Instr*, char*);
141 static void	store(Instr*, char*);
142 static void	storea(Instr*, char*);
143 static void	add(Instr*, char*);
144 static void	cmp(Instr*, char*);
145 static void	wr(Instr*, char*);
146 static void	jmpl(Instr*, char*);
147 static void	rd(Instr*, char*);
148 static void	loadf(Instr*, char*);
149 static void	storef(Instr*, char*);
150 static void	loadc(Instr*, char*);
151 static void	loadcsr(Instr*, char*);
152 static void	trap(Instr*, char*);
153 
154 static struct opcode sparcop0[8] = {
155 	[0]	"UNIMP",	unimp,	0,	/* page 137 */
156 	[2]	"B",		bra,	0,	/* page 119 */
157 	[4]	"SETHI",	sethi,	0,	/* page 104 */
158 	[6]	"FB",		fbra,	0,	/* page 121 */
159 	[7]	"CB",		cbra,	0,	/* page 123 */
160 };
161 
162 static struct opcode sparcop2[64] = {
163 	[0x00]	"ADD",		add,	0,	/* page 108 */
164 	[0x10]	"ADDCC",	add,	0,
165 	[0x08]	"ADDX",		add,	0,
166 	[0x18]	"ADDXCC",	add,	0,
167 
168 	[0x20]	"TADD",		add,	0,	/* page 109 */
169 	[0x22]	"TADDCCTV",	add,	0,
170 
171 	[0x04]	"SUB",		add,	0,	/* page 110 */
172 	[0x14]	"SUBCC",	cmp,	0,
173 	[0x0C]	"SUBX",		add,	0,
174 	[0x1C]	"SUBXCC",	add,	0,
175 
176 	[0x21]	"TSUB",		add,	0,	/* page 111 */
177 	[0x23]	"TSUBCCTV",	add,	0,
178 
179 	[0x24]	"MULSCC",	add,	0,	/* page 112 */
180 
181 	[0x0A]	"UMUL",		add,	0,	/* page 113 */
182 	[0x0B]	"SMUL",		add,	0,
183 	[0x1A]	"UMULCC",	add,	0,
184 	[0x1B]	"SMULCC",	add,	0,
185 
186 	[0x0E]	"UDIV",		add,	0,	/* page 115 */
187 	[0x0F]	"SDIV",		add,	0,
188 	[0x1E]	"UDIVCC",	add,	0,
189 	[0x1F]	"SDIVCC",	add,	0,
190 
191 	[0x01]	"AND",		add,	0,	/* page 106 */
192 	[0x11]	"ANDCC",	add,	0,
193 	[0x05]	"ANDN",		add,	0,
194 	[0x15]	"ANDNCC",	add,	0,
195 	[0x02]	"OR",		add,	0,
196 	[0x12]	"ORCC",		add,	0,
197 	[0x06]	"ORN",		add,	0,
198 	[0x16]	"ORNCC",	add,	0,
199 	[0x03]	"XOR",		add,	0,
200 	[0x13]	"XORCC",	add,	0,
201 	[0x07]	"XORN",		add,	0,
202 	[0x17]	"XORNCC",	add,	0,
203 
204 	[0x25]	"SLL",		shift,	0,	/* page 107 */
205 	[0x26]	"SRL",		shift,	0,
206 	[0x27]	"SRA",		shift,	0,
207 
208 	[0x3C]	"SAVE",		add,	0,	/* page 117 */
209 	[0x3D]	"RESTORE",	add,	0,
210 
211 	[0x38]	"JMPL",		jmpl,	0,	/* page 126 */
212 
213 	[0x39]	"RETT",		add,	0,	/* page 127 */
214 
215 	[0x3A]	"T",		trap,	0,	/* page 129 */
216 
217 	[0x28]	"rdy",		rd,	0,	/* page 131 */
218 	[0x29]	"rdpsr",	rd,	0,
219 	[0x2A]	"rdwim",	rd,	0,
220 	[0x2B]	"rdtbr",	rd,	0,
221 
222 	[0x30]	"wry",		wr,	0,	/* page 133 */
223 	[0x31]	"wrpsr",	wr,	0,
224 	[0x32]	"wrwim",	wr,	0,
225 	[0x33]	"wrtbr",	wr,	0,
226 
227 	[0x3B]	"flush",	add,	0,	/* page 138 */
228 
229 	[0x34]	"FPOP",		fpop,	0,	/* page 140 */
230 	[0x35]	"FPOP",		fpop,	0,
231 };
232 
233 static struct opcode sparcop3[64]={
234 	[0x09]	"ldsb",		load,	0,	/* page 90 */
235 	[0x19]	"ldsba",	loada,	0,
236 	[0x0A]	"ldsh",		load,	0,
237 	[0x1A]	"ldsha",	loada,	0,
238 	[0x01]	"ldub",		load,	0,
239 	[0x11]	"lduba",	loada,	0,
240 	[0x02]	"lduh",		load,	0,
241 	[0x12]	"lduha",	loada,	0,
242 	[0x00]	"ld",		load,	0,
243 	[0x10]	"lda",		loada,	0,
244 	[0x03]	"ldd",		load,	0,
245 	[0x13]	"ldda",		loada,	0,
246 
247 	[0x20]	"ldf",		loadf,	0,	/* page 92 */
248 	[0x23]	"lddf",		loadf,	0,
249 	[0x21]	"ldfsr",	loadf,0,
250 
251 	[0x30]	"ldc",		loadc,	0,	/* page 94 */
252 	[0x33]	"lddc",		loadc,	0,
253 	[0x31]	"ldcsr",	loadcsr,0,
254 
255 	[0x05]	"stb",		store,	0,	/* page 95 */
256 	[0x15]	"stba",		storea,	0,
257 	[0x06]	"sth",		store,	0,
258 	[0x16]	"stha",		storea,	0,
259 	[0x04]	"st",		store,	0,
260 	[0x14]	"sta",		storea,	0,
261 	[0x07]	"std",		store,	0,
262 	[0x17]	"stda",		storea,	0,
263 
264 	[0x24]	"stf",		storef,	0,	/* page 97 */
265 	[0x27]	"stdf",		storef,	0,
266 	[0x25]	"stfsr",	storef,0,
267 	[0x26]	"stdfq",	storef,0,
268 
269 	[0x34]	"stc",		loadc,	0,	/* page 99 */
270 	[0x37]	"stdc",		loadc,	0,
271 	[0x35]	"stcsr",	loadcsr,0,
272 	[0x36]	"stdcq",	loadcsr,0,
273 
274 	[0x0D]	"ldstub",	store,	0,	/* page 101 */
275 	[0x1D]	"ldstuba",	storea,	0,
276 
277 	[0x0F]	"swap",		load,	0,	/* page 102 */
278 	[0x1F]	"swapa",	loada,	0,
279 };
280 
281 static void
282 bprint(Instr *i, char *fmt, ...)
283 {
284 	i->curr = doprint(i->curr, i->end, fmt, (&fmt+1));
285 }
286 
287 static int
288 decode(ulong pc, Instr *i)
289 {
290 	long w;
291 
292 	if (get4(mymap, pc, &w) < 0) {
293 		werrstr("can't read instruction: %r");
294 		return -1;
295 	}
296 	i->op = (w >> 30) & 0x03;
297 	i->rd = (w >> 25) & 0x1F;
298 	i->op2 = (w >> 22) & 0x07;
299 	i->a = (w >> 29) & 0x01;
300 	i->cond = (w >> 25) & 0x0F;
301 	i->op3 = (w >> 19) & 0x3F;
302 	i->rs1 = (w >> 14) & 0x1F;
303 	i->i = (w >> 13) & 0x01;
304 	i->asi = (w >> 5) & 0xFF;
305 	i->rs2 = (w >> 0) & 0x1F;
306 	i->simm13 = (w >> 0) & 0x1FFF;
307 	if(i->simm13 & (1<<12))
308 		i->simm13 |= ~((1<<13)-1);
309 	i->opf = (w >> 5) & 0x1FF;
310 	i->immdisp22 = (w >> 0) & 0x3FFFFF;
311 	i->simmdisp22 = i->immdisp22;
312 	if(i->simmdisp22 & (1<<21))
313 		i->simmdisp22 |= ~((1<<22)-1);
314 	i->disp30 = (w >> 0) & 0x3FFFFFFF;
315 	i->w0 = w;
316 	i->target = -1;
317 	i->addr = pc;
318 	i->size = 1;
319 	return 1;
320 }
321 
322 static int
323 mkinstr(ulong pc, Instr *i)
324 {
325 	Instr xi;
326 
327 	if (decode(pc, i) < 0)
328 		return -1;
329 	if(i->op==0 && i->op2==4 && !dascase){	/* SETHI */
330 		if (decode(pc+4, &xi) < 0)
331 			return -1;
332 		if(xi.op==2 && xi.op3==0)		/* ADD */
333 		if(xi.i == 1 && xi.rs1 == i->rd){	/* immediate to same reg */
334 			i->imm32 = xi.simm13 + (i->immdisp22<<10);
335 			i->target = xi.rd;
336 			i->w1 = xi.w0;
337 			i->size++;
338 			return 1;
339 		}
340 	}
341 	if(i->op==2 && i->opf==1 && !dascase){	/* FMOVS */
342 		if (decode(pc+4, &xi) < 0)
343 			return -1;
344 		if(i->op==2 && i->opf==1)		/* FMOVS */
345 		if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){	/* next pair */
346 			i->w1 = xi.w0;
347 			i->size++;
348 		}
349 	}
350 	return 1;
351 }
352 
353 static int
354 printins(Map *map, ulong pc, char *buf, int n)
355 {
356 	Instr instr;
357 	void (*f)(Instr*, char*);
358 
359 	mymap = map;
360 	memset(&instr, 0, sizeof(instr));
361 	instr.curr = buf;
362 	instr.end = buf+n-1;
363 	if (mkinstr(pc, &instr) < 0)
364 		return -1;
365 	switch(instr.op){
366 	case 0:
367 		f = sparcop0[instr.op2].f;
368 		if(f)
369 			(*f)(&instr, sparcop0[instr.op2].mnemonic);
370 		else
371 			bprint(&instr, "unknown %lux", instr.w0);
372 		break;
373 
374 	case 1:
375 		bprint(&instr, "%X", "CALL\t");
376 		instr.curr += symoff(instr.curr, instr.end-instr.curr,
377 					pc+instr.disp30*4, CTEXT);
378 		if (!dascase)
379 			bprint(&instr, "(SB)");
380 		break;
381 
382 	case 2:
383 		f = sparcop2[instr.op3].f;
384 		if(f)
385 			(*f)(&instr, sparcop2[instr.op3].mnemonic);
386 		else
387 			bprint(&instr, "unknown %lux", instr.w0);
388 		break;
389 
390 	case 3:
391 		f = sparcop3[instr.op3].f;
392 		if(f)
393 			(*f)(&instr, sparcop3[instr.op3].mnemonic);
394 		else
395 			bprint(&instr, "unknown %lux", instr.w0);
396 		break;
397 	}
398 	if (instr.err) {
399 		if (instr.curr != buf)
400 			bprint(&instr, "\t\t;");
401 		bprint(&instr, instr.err);
402 	}
403 	return instr.size*4;
404 }
405 
406 /* convert to lower case from upper, according to dascase */
407 static int
408 Xconv(void *oa, Fconv *f)
409 {
410 	char buf[128];
411 	char *s, *t;
412 
413 	if(dascase){
414 		for(s=*(char**)oa,t=buf; *t = *s; s++,t++)
415 			if('A'<=*t && *t<='Z')
416 				*t += 'a'-'A';
417 		strconv(buf, f);
418 	}else
419 		strconv(*(char**)oa, f);
420 	return sizeof(char*);
421 }
422 
423 static int
424 sparcinst(Map *map, ulong pc, char modifier, char *buf, int n)
425 {
426 	static int fmtinstalled = 0;
427 
428 		/* a modifier of 'I' toggles the dissassembler type */
429 	if (!fmtinstalled) {
430 		fmtinstalled = 1;
431 		fmtinstall('X', Xconv);
432 	}
433 	if ((asstype == ASUNSPARC && modifier == 'i')
434 		|| (asstype == ASPARC && modifier == 'I'))
435 		dascase = 'a'-'A';
436 	else
437 		dascase = 0;
438 	return printins(map, pc, buf, n);
439 }
440 
441 static int
442 sparcdas(Map *map, ulong pc, char *buf, int n)
443 {
444 	Instr instr;
445 
446 	mymap = map;
447 	memset(&instr, 0, sizeof(instr));
448 	instr.curr = buf;
449 	instr.end = buf+n-1;
450 	if (mkinstr(pc, &instr) < 0)
451 		return -1;
452 	if (instr.end-instr.curr > 8)
453 		instr.curr = _hexify(instr.curr, instr.w0, 7);
454 	if (instr.end-instr.curr > 9 && instr.size == 2) {
455 		*instr.curr++ = ' ';
456 		instr.curr = _hexify(instr.curr, instr.w1, 7);
457 	}
458 	*instr.curr = 0;
459 	return instr.size*4;
460 }
461 
462 static int
463 sparcinstlen(Map *map, ulong pc)
464 {
465 	Instr i;
466 
467 	mymap = map;
468 	if (mkinstr(pc, &i) < 0)
469 		return -1;
470 	return i.size*4;
471 }
472 
473 static int
474 plocal(Instr *i)
475 {
476 	int offset;
477 	Symbol s;
478 
479 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
480 		return -1;
481 	if (s.value > i->simm13) {
482 		if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
483 			bprint(i, "%s+%d(SP)", s.name, s.value);
484 			return 1;
485 		}
486 	} else {
487 		offset = i->simm13-s.value;
488 		if (getauto(&s, offset-4, CPARAM, &s)) {
489 			bprint(i, "%s+%d(FP)", s.name, offset);
490 			return 1;
491 		}
492 	}
493 	return -1;
494 }
495 
496 static void
497 address(Instr *i)
498 {
499 	Symbol s, s2;
500 	long off, off1;
501 
502 	if (i->rs1 == 1 && plocal(i) >= 0)
503 		return;
504 	off = mach->sb+i->simm13;
505 	if(i->rs1 == 2	&& findsym(off, CANY, &s)
506 			&& s.value-off < 4096
507 			&& (s.class == CDATA || s.class == CTEXT)) {
508 		if(off==s.value && s.name[0]=='$'){
509 			off1 = 0;
510 			get4(mymap, s.value, &off1);
511 			if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
512 				bprint(i, "$%s(SB)", s2.name);
513 				return;
514 			}
515 		}
516 		bprint(i, "%s", s.name);
517 		if (s.value != off)
518 			bprint(i, "+%lux", s.value-off);
519 		bprint(i, "(SB)");
520 		return;
521 	}
522 	bprint(i, "%lux(R%d)", i->simm13, i->rs1);
523 }
524 
525 static void
526 unimp(Instr *i, char *m)
527 {
528 	bprint(i, "%X", m);
529 }
530 
531 static char	*bratab[16] = {	/* page 91 */
532 	[0X8]	"A",
533 	[0X0]	"N",
534 	[0X9]	"NE",
535 	[0X1]	"E",
536 	[0XA]	"G",
537 	[0X2]	"LE",
538 	[0XB]	"GE",
539 	[0X3]	"L",
540 	[0XC]	"GU",
541 	[0X4]	"LEU",
542 	[0XD]	"CC",
543 	[0X5]	"CS",
544 	[0XE]	"POS",
545 	[0X6]	"NEG",
546 	[0XF]	"VC",
547 	[0X7]	"VS",
548 };
549 
550 static char	*fbratab[16] = {	/* page 91 */
551 	[0X8]	"A",
552 	[0X0]	"N",
553 	[0X7]	"U",
554 	[0X6]	"G",
555 	[0X5]	"UG",
556 	[0X4]	"L",
557 	[0X3]	"UL",
558 	[0X2]	"LG",
559 	[0X1]	"NE",
560 	[0X9]	"E",
561 	[0XA]	"UE",
562 	[0XB]	"GE",
563 	[0XC]	"UGE",
564 	[0XD]	"LE",
565 	[0XE]	"ULE",
566 	[0XF]	"O",
567 };
568 
569 static char	*cbratab[16] = {	/* page 91 */
570 	[0X8]	"A",
571 	[0X0]	"N",
572 	[0X7]	"3",
573 	[0X6]	"2",
574 	[0X5]	"23",
575 	[0X4]	"1",
576 	[0X3]	"13",
577 	[0X2]	"12",
578 	[0X1]	"123",
579 	[0X9]	"0",
580 	[0XA]	"03",
581 	[0XB]	"02",
582 	[0XC]	"023",
583 	[0XD]	"01",
584 	[0XE]	"013",
585 	[0XF]	"012",
586 };
587 
588 static void
589 bra1(Instr *i, char *m, char *tab[])
590 {
591 	long imm;
592 
593 	imm = i->simmdisp22;
594 	if(i->a)
595 		bprint(i, "%X%X.%c\t", m, tab[i->cond], 'A'+dascase);
596 	else
597 		bprint(i, "%X%X\t", m, tab[i->cond]);
598 	i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
599 	if (!dascase)
600 		bprint(i, "(SB)");
601 }
602 
603 static void
604 bra(Instr *i, char *m)			/* page 91 */
605 {
606 	bra1(i, m, bratab);
607 }
608 
609 static void
610 fbra(Instr *i, char *m)			/* page 93 */
611 {
612 	bra1(i, m, fbratab);
613 }
614 
615 static void
616 cbra(Instr *i, char *m)			/* page 95 */
617 {
618 	bra1(i, m, cbratab);
619 }
620 
621 static void
622 trap(Instr *i, char *m)			/* page 101 */
623 {
624 	if(i->i == 0)
625 		bprint(i, "%X%X\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
626 	else
627 		bprint(i, "%X%X\t$%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
628 }
629 
630 static void
631 sethi(Instr *i, char *m)		/* page 89 */
632 {
633 	ulong imm;
634 
635 	imm = i->immdisp22<<10;
636 	if(dascase){
637 		bprint(i, "%X\t%lux, R%d", m, imm, i->rd);
638 		return;
639 	}
640 	if(imm==0 && i->rd==0){
641 		bprint(i, "NOP");
642 		return;
643 	}
644 	if(i->target < 0){
645 		bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
646 		return;
647 	}
648 	bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
649 }
650 
651 static char ldtab[] = {
652 	'W',
653 	'B',
654 	'H',
655 	'D',
656 };
657 
658 static char*
659 moveinstr(int op3, char *m)
660 {
661 	char *s;
662 	int c;
663 	static char buf[8];
664 
665 	if(!dascase){
666 		/* batshit cases */
667 		if(op3 == 0xF || op3 == 0x1F)
668 			return "SWAP";
669 		if(op3 == 0xD || op3 == 0x1D)
670 			return "TAS";	/* really LDSTUB */
671 		c = ldtab[op3&3];
672 		s = "";
673 		if((op3&11)==1 || (op3&11)==2)
674 			s="U";
675 		sprint(buf, "MOV%c%s", c, s);
676 		return buf;
677 	}
678 	return m;
679 }
680 
681 static void
682 load(Instr *i, char *m)			/* page 68 */
683 {
684 	m = moveinstr(i->op3, m);
685 	if(i->i == 0)
686 		bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
687 	else{
688 		bprint(i, "%s\t", m);
689 		address(i);
690 		bprint(i, ", R%d", i->rd);
691 	}
692 }
693 
694 static void
695 loada(Instr *i, char *m)		/* page 68 */
696 {
697 	m = moveinstr(i->op3, m);
698 	if(i->i == 0)
699 		bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
700 	else
701 		bprint(i, "unknown ld asi %lux", i->w0);
702 }
703 
704 static void
705 store(Instr *i, char *m)		/* page 74 */
706 {
707 	m = moveinstr(i->op3, m);
708 	if(i->i == 0)
709 		bprint(i, "%s\tR%d, (R%d+R%d)",
710 				m, i->rd, i->rs1, i->rs2);
711 	else{
712 		bprint(i, "%s\tR%d, ", m, i->rd);
713 		address(i);
714 	}
715 }
716 
717 static void
718 storea(Instr *i, char *m)		/* page 74 */
719 {
720 	m = moveinstr(i->op3, m);
721 	if(i->i == 0)
722 		bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
723 	else
724 		bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
725 }
726 
727 void
728 shift(Instr *i, char *m)	/* page 88 */
729 {
730 	if(i->i == 0){
731 		if(i->rs1 == i->rd)
732 			if(dascase)
733 				bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
734 			else
735 				bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
736 		else
737 			if(dascase)
738 				bprint(i, "%X\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
739 			else
740 				bprint(i, "%X\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
741 	}else{
742 		if(i->rs1 == i->rd)
743 			if(dascase)
744 				bprint(i, "%X\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
745 			else
746 				bprint(i, "%X\tR%d, $%d", m,  i->rs1, i->simm13&0x1F);
747 		else
748 			if(dascase)
749 				bprint(i, "%X\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
750 			else
751 				bprint(i, "%X\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
752 	}
753 }
754 
755 static void
756 add(Instr *i, char *m)	/* page 82 */
757 {
758 	if(i->i == 0){
759 		if(dascase)
760 			bprint(i, "%X\tR%d, R%d", m, i->rs1, i->rs2);
761 		else
762 			if(i->op3==2 && i->rs1==0 && i->rd)  /* OR R2, R0, R1 */
763 				bprint(i, "MOVW\tR%d", i->rs2);
764 			else
765 				bprint(i, "%X\tR%d, R%d", m, i->rs2, i->rs1);
766 	}else{
767 		if(dascase)
768 			bprint(i, "%X\tR%d, $%lux", m, i->rs1, i->simm13);
769 		else
770 			if(i->op3==0 && i->rd && i->rs1==0)	/* ADD $x, R0, R1 */
771 				bprint(i, "MOVW\t$%lux", i->simm13);
772 			else if(i->op3==0 && i->rd && i->rs1==2){
773 				/* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
774 				bprint(i, "MOVW\t$");
775 				address(i);
776 			} else
777 				bprint(i, "%X\t$%lux, R%d", m, i->simm13, i->rs1);
778 	}
779 	if(i->rs1 != i->rd)
780 		bprint(i, ", R%d", i->rd);
781 }
782 
783 static void
784 cmp(Instr *i, char *m)
785 {
786 	if(dascase || i->rd){
787 		add(i, m);
788 		return;
789 	}
790 	if(i->i == 0)
791 		bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
792 	else
793 		bprint(i, "CMP\tR%d, $%lux", i->rs1, i->simm13);
794 }
795 
796 static char *regtab[4] = {
797 	"Y",
798 	"PSR",
799 	"WIM",
800 	"TBR",
801 };
802 
803 static void
804 wr(Instr *i, char *m)		/* page 82 */
805 {
806 	if(dascase){
807 		if(i->i == 0)
808 			bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
809 		else
810 			bprint(i, "%s\tR%d, $%lux", m, i->rs1, i->simm13);
811 	}else{
812 		if(i->i && i->simm13==0)
813 			bprint(i, "MOVW\tR%d", i->rs1);
814 		else if(i->i == 0)
815 			bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
816 		else
817 			bprint(i, "wr\t$%lux, R%d", i->simm13, i->rs1);
818 	}
819 	bprint(i, ", %s", regtab[i->op3&3]);
820 }
821 
822 static void
823 rd(Instr *i, char *m)		/* page 103 */
824 {
825 	if(i->rs1==15 && i->rd==0){
826 		m = "stbar";
827 		if(!dascase)
828 			m = "STBAR";
829 		bprint(i, "%s", m);
830 	}else{
831 		if(!dascase)
832 			m = "MOVW";
833 		bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
834 	}
835 }
836 
837 static void
838 jmpl(Instr *i, char *m)		/* page 82 */
839 {
840 	if(i->i == 0){
841 		if(i->rd == 15)
842 			bprint(i, "%X\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
843 		else
844 			bprint(i, "%X\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
845 	}else{
846 		if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
847 			bprint(i, "RETURN");
848 		else{
849 			bprint(i, "%X\t", m);
850 			address(i);
851 			bprint(i, ", R%d", i->rd);
852 		}
853 	}
854 }
855 
856 static void
857 loadf(Instr *i, char *m)		/* page 70 */
858 {
859 	if(!dascase){
860 		m = "FMOVD";
861 		if(i->op3 == 0x20)
862 			m = "FMOVF";
863 		else if(i->op3 == 0x21)
864 			m = "MOVW";
865 	}
866 	if(i->i == 0)
867 		bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
868 	else{
869 		bprint(i, "%s\t", m);
870 		address(i);
871 	}
872 	if(i->op3 == 0x21)
873 		bprint(i, ", FSR");
874 	else
875 		bprint(i, ", R%d", i->rd);
876 }
877 
878 static
879 void storef(Instr *i, char *m)		/* page 70 */
880 {
881 	if(!dascase){
882 		m = "FMOVD";
883 		if(i->op3 == 0x25 || i->op3 == 0x26)
884 			m = "MOVW";
885 		else if(i->op3 == 0x20)
886 			m = "FMOVF";
887 	}
888 	bprint(i, "%s\t", m);
889 	if(i->op3 == 0x25)
890 		bprint(i, "FSR, ");
891 	else if(i->op3 == 0x26)
892 		bprint(i, "FQ, ");
893 	else
894 		bprint(i, "R%d, ", i->rd);
895 	if(i->i == 0)
896 		bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
897 	else
898 		address(i);
899 }
900 
901 static
902 void loadc(Instr *i, char *m)			/* page 72 */
903 {
904 	if(i->i == 0)
905 		bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
906 	else{
907 		bprint(i, "%s\t", m);
908 		address(i);
909 		bprint(i, ", C%d", i->rd);
910 	}
911 }
912 
913 static
914 void loadcsr(Instr *i, char *m)			/* page 72 */
915 {
916 	if(i->i == 0)
917 		bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
918 	else{
919 		bprint(i, "%s\t", m);
920 		address(i);
921 		bprint(i, ", CSR");
922 	}
923 }
924 
925 static struct{
926 	int	opf;
927 	char	*name;
928 } fptab1[] = {			/* ignores rs1 */
929 	0xC4,	"FITOS",	/* page 109 */
930 	0xC8,	"FITOD",
931 	0xCC,	"FITOX",
932 
933 	0xD1,	"FSTOI",	/* page 110 */
934 	0xD2,	"FDTOI",
935 	0xD3,	"FXTOI",
936 
937 	0xC9,	"FSTOD",	/* page 111 */
938 	0xCD,	"FSTOX",
939 	0xC6,	"FDTOS",
940 	0xCE,	"FDTOX",
941 	0xC7,	"FXTOS",
942 	0xCB,	"FXTOD",
943 
944 	0x01,	"FMOVS",	/* page 112 */
945 	0x05,	"FNEGS",
946 	0x09,	"FABSS",
947 
948 	0x29,	"FSQRTS", 	/* page 113 */
949 	0x2A,	"FSQRTD",
950 	0x2B,	"FSQRTX",
951 
952 	0,	0,
953 };
954 
955 static struct{
956 	int	opf;
957 	char	*name;
958 } fptab2[] = {			/* uses rs1 */
959 
960 	0x41,	"FADDS",	/* page 114 */
961 	0x42,	"FADDD",
962 	0x43,	"FADDX",
963 	0x45,	"FSUBS",
964 	0x46,	"FSUBD",
965 	0x47,	"FSUBX",
966 
967 	0x49,	"FMULS",	/* page 115 */
968 	0x4A,	"FMULD",
969 	0x4B,	"FMULX",
970 	0x4D,	"FDIVS",
971 	0x4E,	"FDIVD",
972 	0x4F,	"FDIVX",
973 
974 	0x51,	"FCMPS",	/* page 116 */
975 	0x52,	"FCMPD",
976 	0x53,	"FCMPX",
977 	0x55,	"FCMPES",
978 	0x56,	"FCMPED",
979 	0x57,	"FCMPEX",
980 
981 	0, 0
982 };
983 
984 static void
985 fpop(Instr *i, char *m)	/* page 108-116 */
986 {
987 	int j;
988 
989 	if(dascase==0 && i->size==2){
990 		bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
991 		return;
992 	}
993 	for(j=0; fptab1[j].name; j++)
994 		if(fptab1[j].opf == i->opf){
995 			bprint(i, "%X\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
996 			return;
997 		}
998 	for(j=0; fptab2[j].name; j++)
999 		if(fptab2[j].opf == i->opf){
1000 			bprint(i, "%X\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
1001 			return;
1002 		}
1003 	bprint(i, "%X%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
1004 }
1005 
1006 static int
1007 sparcfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
1008 {
1009 	ulong w, r1, r2;
1010 	char buf[8];
1011 	Instr i;
1012 
1013 	mymap = map;
1014 	if (mkinstr(pc, &i) < 0)
1015 		return -1;
1016 	w = i.w0;
1017 	switch(w & 0xC1C00000){
1018 	case 0x00800000:		/* branch on int cond */
1019 	case 0x01800000:		/* branch on fp cond */
1020 	case 0x01C00000:		/* branch on copr cond */
1021 		foll[0] = pc+8;
1022 		foll[1] = pc + (i.simmdisp22<<2);
1023 		return 2;
1024 	}
1025 
1026 	if((w&0xC0000000) == 0x40000000){	/* CALL */
1027 		foll[0] = pc + (i.disp30<<2);
1028 		return 1;
1029 	}
1030 
1031 	if((w&0xC1F80000) == 0x81C00000){	/* JMPL */
1032 		sprint(buf, "R%d", (w>>14)&0xF);
1033 		r1 = (*rget)(map, buf);
1034 		if(w & 0x2000)			/* JMPL R1+simm13 */
1035 			r2 = i.simm13;
1036 		else{				/* JMPL R1+R2 */
1037 			sprint(buf, "R%d", w&0xF);
1038 			r2 = (*rget)(map, buf);
1039 		}
1040 		foll[0] = r1 + r2;
1041 		return 1;
1042 	}
1043 	foll[0] = pc+i.size*4;
1044 	return 1;
1045 }
1046