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