Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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