Subversion Repositories planix.SVN

Rev

Details | 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
 * Mips-specific debugger interface
7
 */
8
 
9
static	char	*mipsexcep(Map*, Rgetter);
10
static	int	mipsfoll(Map*, uvlong, Rgetter, uvlong*);
11
static	int	mipsinst(Map*, uvlong, char, char*, int);
12
static	int	mipsdas(Map*, uvlong, char*, int);
13
static	int	mipsinstlen(Map*, uvlong);
14
 
15
/*
16
 *	Debugger interface
17
 */
18
Machdata mipsmach =
19
{
20
	{0, 0, 0, 0xD},		/* break point */
21
	4,			/* break point size */
22
 
23
	beswab,			/* short to local byte order */
24
	beswal,			/* long to local byte order */
25
	beswav,			/* vlong to local byte order */
26
	risctrace,		/* C traceback */
27
	riscframe,		/* Frame finder */
28
	mipsexcep,		/* print exception */
29
	0,			/* breakpoint fixup */
30
	beieeesftos,		/* single precision float printer */
31
	/*
32
	 * this works for doubles in memory, but FP register pairs have
33
	 * the words in little-endian order, so they will print as
34
	 * denormalised doubles.
35
	 */
36
	beieeedftos,		/* double precision float printer */
37
	mipsfoll,		/* following addresses */
38
	mipsinst,		/* print instruction */
39
	mipsdas,		/* dissembler */
40
	mipsinstlen,		/* instruction size */
41
};
42
 
43
Machdata mipsmachle =
44
{
45
	{0, 0, 0, 0xD},		/* break point */
46
	4,			/* break point size */
47
 
48
	leswab,			/* short to local byte order */
49
	leswal,			/* long to local byte order */
50
	leswav,			/* vlong to local byte order */
51
	risctrace,		/* C traceback */
52
	riscframe,		/* Frame finder */
53
	mipsexcep,		/* print exception */
54
	0,			/* breakpoint fixup */
55
	leieeesftos,		/* single precision float printer */
56
	leieeedftos,		/* double precision float printer */
57
	mipsfoll,		/* following addresses */
58
	mipsinst,		/* print instruction */
59
	mipsdas,		/* dissembler */
60
	mipsinstlen,		/* instruction size */
61
};
62
 
63
/*
64
 *	mips r4k little-endian
65
 */
66
Machdata mipsmach2le =
67
{
68
	{0, 0, 0, 0xD},		/* break point */
69
	4,			/* break point size */
70
 
71
	leswab,			/* short to local byte order */
72
	leswal,			/* long to local byte order */
73
	leswav,			/* vlong to local byte order */
74
	risctrace,		/* C traceback */
75
	riscframe,		/* Frame finder */
76
	mipsexcep,		/* print exception */
77
	0,			/* breakpoint fixup */
78
	leieeesftos,		/* single precision float printer */
79
	leieeedftos,		/* double precision float printer */
80
	mipsfoll,		/* following addresses */
81
	mipsinst,		/* print instruction */
82
	mipsdas,		/* dissembler */
83
	mipsinstlen,		/* instruction size */
84
};
85
 
86
/*
87
 *	mips r4k big-endian
88
 */
89
Machdata mipsmach2be =
90
{
91
	{0, 0, 0, 0xD},		/* break point */
92
	4,			/* break point size */
93
 
94
	beswab,			/* short to local byte order */
95
	beswal,			/* long to local byte order */
96
	beswav,			/* vlong to local byte order */
97
	risctrace,		/* C traceback */
98
	riscframe,		/* Frame finder */
99
	mipsexcep,		/* print exception */
100
	0,			/* breakpoint fixup */
101
	beieeesftos,		/* single precision float printer */
102
	beieeedftos,		/* double precision float printer */
103
	mipsfoll,		/* following addresses */
104
	mipsinst,		/* print instruction */
105
	mipsdas,		/* dissembler */
106
	mipsinstlen,		/* instruction size */
107
};
108
 
109
 
110
static char *excname[] =
111
{
112
	"external interrupt",
113
	"TLB modification",
114
	"TLB miss (load or fetch)",
115
	"TLB miss (store)",
116
	"address error (load or fetch)",
117
	"address error (store)",
118
	"bus error (fetch)",
119
	"bus error (data load or store)",
120
	"system call",
121
	"breakpoint",
122
	"reserved instruction",
123
	"coprocessor unusable",
124
	"arithmetic overflow",
125
	"undefined 13",
126
	"undefined 14",
127
	"system call",
128
	/* the following is made up */
129
	"floating point exception"		/* FPEXC */
130
};
131
 
132
static char*
133
mipsexcep(Map *map, Rgetter rget)
134
{
135
	int e;
136
	long c;
137
 
138
	c = (*rget)(map, "CAUSE");
139
	/* i don't think this applies to any current machines */
140
	if(0 && c & 0x00002000)	/* INTR3 */
141
		e = 16;		/* Floating point exception */
142
	else
143
		e = (c>>2)&0x0F;
144
	return excname[e];
145
}
146
 
147
	/* mips disassembler and related functions */
148
 
149
static	char FRAMENAME[] = ".frame";
150
 
151
typedef struct {
152
	uvlong addr;
153
	uchar op;			/* bits 31-26 */
154
	uchar rs;			/* bits 25-21 */
155
	uchar rt;			/* bits 20-16 */
156
	uchar rd;			/* bits 15-11 */
157
	uchar sa;			/* bits 10-6 */
158
	uchar function;			/* bits 5-0 */
159
	long immediate;			/* bits 15-0 */
160
	ulong cofun;			/* bits 24-0 */
161
	ulong target;			/* bits 25-0 */
162
	long w0;
163
	long w1;
164
	int size;			/* instruction size */
165
	char *curr;			/* fill point in buffer */
166
	char *end;			/* end of buffer */
167
	char *err;			/* error message */
168
} Instr;
169
 
170
static Map *mymap;
171
 
172
static int
173
decode(uvlong pc, Instr *i)
174
{
175
	ulong w;
176
 
177
	if (get4(mymap, pc, &w) < 0) {
178
		werrstr("can't read instruction: %r");
179
		return -1;
180
	}
181
 
182
	i->addr = pc;
183
	i->size = 1;
184
	i->op = (w >> 26) & 0x3F;
185
	i->rs = (w >> 21) & 0x1F;
186
	i->rt = (w >> 16) & 0x1F;
187
	i->rd = (w >> 11) & 0x1F;
188
	i->sa = (w >> 6) & 0x1F;
189
	i->function = w & 0x3F;
190
	i->immediate = w & 0x0000FFFF;
191
	if (i->immediate & 0x8000)
192
		i->immediate |= ~0x0000FFFF;
193
	i->cofun = w & 0x01FFFFFF;
194
	i->target = w & 0x03FFFFFF;
195
	i->w0 = w;
196
	return 1;
197
}
198
 
199
static int
200
mkinstr(uvlong pc, Instr *i)
201
{
202
	Instr x;
203
 
204
	if (decode(pc, i) < 0)
205
		return -1;
206
	/*
207
	 * if it's a LUI followed by an ORI,
208
	 * it's an immediate load of a large constant.
209
	 * fix the LUI immediate in any case.
210
	 */
211
	if (i->op == 0x0F) {
212
		if (decode(pc+4, &x) < 0)
213
			return 0;
214
		i->immediate <<= 16;
215
		if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
216
			i->immediate |= (x.immediate & 0xFFFF);
217
			i->w1 = x.w0;
218
			i->size++;
219
			return 1;
220
		}
221
	}
222
	/*
223
	 * if it's a LWC1 followed by another LWC1
224
	 * into an adjacent register, it's a load of
225
	 * a floating point double.
226
	 */
227
	else if (i->op == 0x31 && (i->rt & 0x01)) {
228
		if (decode(pc+4, &x) < 0)
229
			return 0;
230
		if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
231
			i->rt -= 1;
232
			i->w1 = x.w0;
233
			i->size++;
234
			return 1;
235
		}
236
	}
237
	/*
238
	 * similarly for double stores
239
	 */
240
	else if (i->op == 0x39 && (i->rt & 0x01)) {
241
		if (decode(pc+4, &x) < 0)
242
			return 0;
243
		if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
244
			i->rt -= 1;
245
			i->w1 = x.w0;
246
			i->size++;
247
		}
248
	}
249
	return 1;
250
}
251
 
252
#pragma	varargck	argpos	bprint		2
253
 
254
static void
255
bprint(Instr *i, char *fmt, ...)
256
{
257
	va_list arg;
258
 
259
	va_start(arg, fmt);
260
	i->curr = vseprint(i->curr, i->end, fmt, arg);
261
	va_end(arg);
262
}
263
 
264
typedef struct Opcode Opcode;
265
 
266
struct Opcode {
267
	char *mnemonic;
268
	void (*f)(Opcode *, Instr *);
269
	char *ken;
270
};
271
 
272
static void format(char *, Instr *, char *);
273
 
274
static void
275
branch(Opcode *o, Instr *i)
276
{
277
	if (i->rs == 0 && i->rt == 0)
278
		format("JMP", i, "%b");
279
	else if (i->rs == 0)
280
		format(o->mnemonic, i, "R%t,%b");
281
	else if (i->rt < 2)
282
		format(o->mnemonic, i, "R%s,%b");
283
	else
284
		format(o->mnemonic, i, "R%s,R%t,%b");
285
}
286
 
287
static void
288
addi(Opcode *o, Instr *i)
289
{
290
	if (i->rs == i->rt)
291
		format(o->mnemonic, i, "%i,R%t");
292
	else if (i->rs == 0)
293
		format("MOVW", i, "%i,R%t");
294
	else if (i->rs == 30) {
295
		bprint(i, "MOVW\t$");
296
		i->curr += symoff(i->curr, i->end-i->curr,
297
					i->immediate+mach->sb, CANY);
298
		bprint(i, "(SB),R%d", i->rt);
299
	}
300
	else
301
		format(o->mnemonic, i, o->ken);
302
}
303
 
304
static void
305
andi(Opcode *o, Instr *i)
306
{
307
	if (i->rs == i->rt)
308
		format(o->mnemonic, i, "%i,R%t");
309
	else
310
		format(o->mnemonic, i, o->ken);
311
}
312
 
313
static int
314
plocal(Instr *i, char *m, char r, int store)
315
{
316
	int offset;
317
	char *reg;
318
	Symbol s;
319
 
320
	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
321
		return 0;
322
	if (s.value > i->immediate) {
323
		if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
324
			return 0;
325
		reg = "(SP)";
326
		offset = i->immediate;
327
	} else {
328
		offset = i->immediate-s.value;
329
		if (!getauto(&s, offset-4, CPARAM, &s))
330
			return 0;
331
		reg = "(FP)";
332
	}
333
	if (store)
334
		bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
335
	else
336
		bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
337
	return 1;
338
}
339
 
340
static void
341
lw(Opcode *o, Instr *i, char r)
342
{
343
	char *m;
344
 
345
	if (r == 'F') {
346
		if (i->size == 2)
347
			m = "MOVD";
348
		else
349
			m = "MOVF";
350
	}
351
	else
352
		m = o->mnemonic;
353
	if (i->rs == 29 && plocal(i, m, r, 0))
354
			return;
355
 
356
	if (i->rs == 30 && mach->sb) {
357
		bprint(i, "%s\t", m);
358
		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
359
		bprint(i, "(SB),%c%d", r, i->rt);
360
		return;
361
	}
362
	if (r == 'F')
363
		format(m, i, "%l,F%t");
364
	else
365
		format(m, i, o->ken);
366
}
367
 
368
static void
369
load(Opcode *o, Instr *i)
370
{
371
	lw(o, i, 'R');
372
}
373
 
374
static void
375
lwc1(Opcode *o, Instr *i)
376
{
377
	lw(o, i, 'F');
378
}
379
 
380
static void
381
sw(Opcode *o, Instr *i, char r)
382
{
383
	char *m;
384
 
385
	if (r == 'F') {
386
		if (i->size == 2)
387
			m = "MOVD";
388
		else
389
			m = "MOVF";
390
	}
391
	else
392
		m = o->mnemonic;
393
	if (i->rs == 29 && plocal(i, m, r, 1))
394
			return;
395
 
396
	if (i->rs == 30 && mach->sb) {
397
		bprint(i, "%s\t%c%d,", m, r, i->rt);
398
		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
399
		bprint(i, "(SB)");
400
		return;
401
	}
402
	if (r == 'F')
403
		format(m, i, "F%t,%l");
404
	else
405
		format(m, i, o->ken);
406
}
407
 
408
static void
409
store(Opcode *o, Instr *i)
410
{
411
	sw(o, i, 'R');
412
}
413
 
414
static void
415
swc1(Opcode *o, Instr *i)
416
{
417
	sw(o, i, 'F');
418
}
419
 
420
static void
421
sll(Opcode *o, Instr *i)
422
{
423
	if (i->w0 == 0)
424
		bprint(i, "NOOP");		/* unofficial nop */
425
	else if (i->w0 == 0xc0)			/* 0xc0: SLL $3,R0 */
426
		bprint(i, "EHB");
427
	else if (i->rd == i->rt)
428
		format(o->mnemonic, i, "$%a,R%d");
429
	else
430
		format(o->mnemonic, i, o->ken);
431
}
432
 
433
static void
434
sl32(Opcode *o, Instr *i)
435
{
436
	i->sa += 32;
437
	if (i->rd == i->rt)
438
		format(o->mnemonic, i, "$%a,R%d");
439
	else
440
		format(o->mnemonic, i, o->ken);
441
}
442
 
443
static void
444
sllv(Opcode *o, Instr *i)
445
{
446
	if (i->rd == i->rt)
447
		format(o->mnemonic, i, "R%s,R%d");
448
	else
449
		format(o->mnemonic, i, o->ken);
450
}
451
 
452
static void
453
jal(Opcode *o, Instr *i)
454
{
455
	if (i->rd == 31)
456
		format("JAL", i, "(R%s)");
457
	else
458
		format(o->mnemonic, i, o->ken);
459
}
460
 
461
static void
462
add(Opcode *o, Instr *i)
463
{
464
	if (i->rd == i->rs)
465
		format(o->mnemonic, i, "R%t,R%d");
466
	else if (i->rd == i->rt)
467
		format(o->mnemonic, i, "R%s,R%d");
468
	else
469
		format(o->mnemonic, i, o->ken);
470
}
471
 
472
static void
473
sub(Opcode *o, Instr *i)
474
{
475
	if (i->rd == i->rs)
476
		format(o->mnemonic, i, "R%t,R%d");
477
	else
478
		format(o->mnemonic, i, o->ken);
479
}
480
 
481
static void
482
or(Opcode *o, Instr *i)
483
{
484
	if (i->rs == 0 && i->rt == 0)
485
		format("MOVW", i, "$0,R%d");
486
	else if (i->rs == 0)
487
		format("MOVW", i, "R%t,R%d");
488
	else if (i->rt == 0)
489
		format("MOVW", i, "R%s,R%d");
490
	else
491
		add(o, i);
492
}
493
 
494
static void
495
nor(Opcode *o, Instr *i)
496
{
497
	if (i->rs == 0 && i->rt == 0 && i->rd == 0)
498
		format("NOP", i, 0);
499
	else
500
		add(o, i);
501
}
502
 
503
static char mipscoload[] = "r%t,%l";
504
static char mipsload[] = "%l,R%t";
505
static char mipsstore[] = "R%t,%l";
506
static char mipsalui[] = "%i,R%s,R%t";
507
static char mipsalu3op[] = "R%t,R%s,R%d";
508
static char mipsrtrs[] = "R%t,R%s";
509
static char mipscorsrt[] = "r%s,r%t";
510
static char mipscorsi[] = "r%s,%i";
511
static char mipscoxxx[] = "%w";
512
static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
513
static char mipsfp3[] = "F%t,F%d,F%a";
514
static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
515
static char mipsfp2[] = "F%d,F%a";
516
static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
517
static char mipsfpc[] = "F%t,F%d";
518
 
519
static Opcode opcodes[64] = {
520
	0,		0,	0,
521
	0,		0,	0,
522
	"JMP",		0,	"%j",
523
	"JAL",		0,	"%j",
524
	"BEQ",	   branch,	0,
525
	"BNE",	   branch,	0,
526
	"BLEZ",	   branch,	0,
527
	"BGTZ",	   branch,	0,
528
	"ADD",	     addi,	mipsalui,
529
	"ADDU",	     addi,	mipsalui,
530
	"SGT",		0,	mipsalui,
531
	"SGTU",		0,	mipsalui,
532
	"AND",	     andi,	mipsalui,
533
	"OR",	     andi,	mipsalui,
534
	"XOR",	     andi,	mipsalui,
535
	"MOVW",		0,	"$%u,R%t",
536
	"cop0",		0,	0,
537
	"cop1",		0,	0,
538
	"cop2",		0,	0,
539
	"cop3",		0,	0,
540
	"BEQL",	   branch,	0,
541
	"BNEL",	   branch,	0,
542
	"BLEZL",   branch,	0,
543
	"BGTZL",   branch,	0,
544
	"instr18",	0,	mipscoxxx,
545
	"instr19",	0,	mipscoxxx,
546
	"MOVVL",     load,	mipsload,
547
	"MOVVR",     load,	mipsload,
548
	"instr1C",	0,	mipscoxxx,
549
	"instr1D",	0,	mipscoxxx,
550
	"instr1E",	0,	mipscoxxx,
551
	"instr1F",	0,	mipscoxxx,
552
	"MOVB",	     load,	mipsload,
553
	"MOVH",	     load,	mipsload,
554
	"lwl",		0,	mipscoload,
555
	"MOVW",	     load,	mipsload,
556
	"MOVBU",     load,	mipsload,
557
	"MOVHU",     load,	mipsload,
558
	"lwr",		0,	mipscoload,
559
	"instr27",	0,	mipscoxxx,
560
	"MOVB",	    store,	mipsstore,
561
	"MOVH",	    store,	mipsstore,
562
	"swl",		0,	mipscoload,
563
	"MOVW",	    store,	mipsstore,
564
	"MOVVL",    store,	mipsstore,
565
	"MOVVR",    store,	mipsstore,
566
	"swr",		0,	mipscoload,
567
	"CACHE",	0,	"%C,%l",
568
	"ll",		0,	mipscoload,
569
	"MOVW",	     lwc1,	mipscoload,
570
	"lwc2",		0,	mipscoload,
571
	"lwc3",		0,	mipscoload,
572
	"instr34",	0,	mipscoxxx,
573
	"ldc1",		0,	mipscoload,
574
	"ldc2",		0,	mipscoload,
575
	"MOVV",	    load,	mipsload,
576
	"sc",		0,	mipscoload,
577
	"swc1",	     swc1,	mipscoload,
578
	"swc2",		0,	mipscoload,
579
	"swc3",		0,	mipscoload,
580
	"instr3C",	0,	mipscoxxx,
581
	"sdc1",		0,	mipscoload,
582
	"sdc2",		0,	mipscoload,
583
	"MOVV",	    store,	mipsstore,
584
};
585
 
586
static Opcode sopcodes[64] = {
587
	"SLL",	      sll,	"$%a,R%t,R%d",
588
	"special01",	0,	mipscoxxx,
589
	"SRL",	      sll,	"$%a,R%t,R%d",
590
	"SRA",	      sll,	"$%a,R%t,R%d",
591
	"SLL",	     sllv,	"R%s,R%t,R%d",
592
	"special05",	0,	mipscoxxx,
593
	"SRL",	     sllv,	"R%s,R%t,R%d",
594
	"SRA",	     sllv,	"R%s,R%t,R%d",
595
	"JMP",		0,	"(R%s)",
596
	"jal",	      jal,	"r%d,r%s",
597
	"special0A",	0,	mipscoxxx,
598
	"special0B",	0,	mipscoxxx,
599
	"SYSCALL",	0,	0,
600
	"BREAK",	0,	0,
601
	"special0E",	0,	mipscoxxx,
602
	"SYNC",		0,	0,
603
	"MOVW",		0,	"HI,R%d",
604
	"MOVW",		0,	"R%s,HI",
605
	"MOVW",		0,	"LO,R%d",
606
	"MOVW",		0,	"R%s,LO",
607
	"SLLV",	     sllv,	"R%s,R%t,R%d",
608
	"special15",	0,	mipscoxxx,
609
	"SRLV",	     sllv,	"R%s,R%t,R%d",
610
	"SRAV",	     sllv,	"R%s,R%t,R%d",
611
	"MUL",		0,	mipsrtrs,
612
	"MULU",		0,	mipsrtrs,
613
	"DIV",		0,	mipsrtrs,
614
	"DIVU",		0,	mipsrtrs,
615
	"special1C",	0,	mipscoxxx,
616
	"special1D",	0,	mipscoxxx,
617
	"DDIV",		0,	"R%s,R%t",
618
	"special1F",	0,	mipscoxxx,
619
	"ADD",	      add,	mipsalu3op,
620
	"ADDU",	      add,	mipsalu3op,
621
	"SUB",	      sub,	mipsalu3op,
622
	"SUBU",	      sub,	mipsalu3op,
623
	"AND",	      add,	mipsalu3op,
624
	"OR",	       or,	mipsalu3op,
625
	"XOR",	      add,	mipsalu3op,
626
	"NOR",	      nor,	mipsalu3op,
627
	"special28",	0,	mipscoxxx,
628
	"special29",	0,	mipscoxxx,
629
	"SGT",		0,	mipsalu3op,
630
	"SGTU",		0,	mipsalu3op,
631
	"special2C",	0,	mipscoxxx,
632
	"special2D",	0,	mipscoxxx,
633
	"special2E",	0,	mipscoxxx,
634
	"DSUBU",	0,	"R%s,R%t,R%d",
635
	"tge",		0,	mipscorsrt,
636
	"tgeu",		0,	mipscorsrt,
637
	"tlt",		0,	mipscorsrt,
638
	"tltu",		0,	mipscorsrt,
639
	"teq",		0,	mipscorsrt,
640
	"special35",	0,	mipscoxxx,
641
	"tne",		0,	mipscorsrt,
642
	"special37",	0,	mipscoxxx,
643
	"SLLV",	      sll,	"$%a,R%t,R%d",
644
	"special39",	0,	mipscoxxx,
645
	"SRLV",	      sll,	"$%a,R%t,R%d",
646
	"SRAV",	      sll,	"$%a,R%t,R%d",
647
	"SLLV",	     sl32,	"$%a,R%t,R%d",
648
	"special3D",	0,	mipscoxxx,
649
	"SRLV",	     sl32,	"$%a,R%t,R%d",
650
	"SRAV",	     sl32,	"$%a,R%t,R%d",
651
};
652
 
653
static Opcode ropcodes[32] = {
654
	"BLTZ",	   branch,	0,
655
	"BGEZ",	   branch,	0,
656
	"BLTZL",   branch,	0,
657
	"BGEZL",   branch,	0,
658
	"regimm04",	0,	mipscoxxx,
659
	"regimm05",	0,	mipscoxxx,
660
	"regimm06",	0,	mipscoxxx,
661
	"regimm07",	0,	mipscoxxx,
662
	"tgei",		0,	mipscorsi,
663
	"tgeiu",	0,	mipscorsi,
664
	"tlti",		0,	mipscorsi,
665
	"tltiu",	0,	mipscorsi,
666
	"teqi",		0,	mipscorsi,
667
	"regimm0D",	0,	mipscoxxx,
668
	"tnei",		0,	mipscorsi,
669
	"regimm0F",	0,	mipscoxxx,
670
	"BLTZAL",  branch,	0,
671
	"BGEZAL",  branch,	0,
672
	"BLTZALL", branch,	0,
673
	"BGEZALL", branch,	0,
674
	"regimm14",	0,	mipscoxxx,
675
	"regimm15",	0,	mipscoxxx,
676
	"regimm16",	0,	mipscoxxx,
677
	"regimm17",	0,	mipscoxxx,
678
	"regimm18",	0,	mipscoxxx,
679
	"regimm19",	0,	mipscoxxx,
680
	"regimm1A",	0,	mipscoxxx,
681
	"regimm1B",	0,	mipscoxxx,
682
	"regimm1C",	0,	mipscoxxx,
683
	"regimm1D",	0,	mipscoxxx,
684
	"regimm1E",	0,	mipscoxxx,
685
	"regimm1F",	0,	mipscoxxx,
686
};
687
 
688
static Opcode fopcodes[64] = {
689
	"ADD%f",	0,	mipsfp3,
690
	"SUB%f",	0,	mipsfp3,
691
	"MUL%f",	0,	mipsfp3,
692
	"DIV%f",	0,	mipsfp3,
693
	"sqrt.%f",	0,	mipscofp2,
694
	"ABS%f",	0,	mipsfp2,
695
	"MOV%f",	0,	mipsfp2,
696
	"NEG%f",	0,	mipsfp2,
697
	"finstr08",	0,	mipscoxxx,
698
	"finstr09",	0,	mipscoxxx,
699
	"finstr0A",	0,	mipscoxxx,
700
	"finstr0B",	0,	mipscoxxx,
701
	"round.w.%f",	0,	mipscofp2,
702
	"trunc.w%f",	0,	mipscofp2,
703
	"ceil.w%f",	0,	mipscofp2,
704
	"floor.w%f",	0,	mipscofp2,
705
	"finstr10",	0,	mipscoxxx,
706
	"finstr11",	0,	mipscoxxx,
707
	"finstr12",	0,	mipscoxxx,
708
	"finstr13",	0,	mipscoxxx,
709
	"finstr14",	0,	mipscoxxx,
710
	"finstr15",	0,	mipscoxxx,
711
	"finstr16",	0,	mipscoxxx,
712
	"finstr17",	0,	mipscoxxx,
713
	"finstr18",	0,	mipscoxxx,
714
	"finstr19",	0,	mipscoxxx,
715
	"finstr1A",	0,	mipscoxxx,
716
	"finstr1B",	0,	mipscoxxx,
717
	"finstr1C",	0,	mipscoxxx,
718
	"finstr1D",	0,	mipscoxxx,
719
	"finstr1E",	0,	mipscoxxx,
720
	"finstr1F",	0,	mipscoxxx,
721
	"cvt.s.%f",	0,	mipscofp2,
722
	"cvt.d.%f",	0,	mipscofp2,
723
	"cvt.e.%f",	0,	mipscofp2,
724
	"cvt.q.%f",	0,	mipscofp2,
725
	"cvt.w.%f",	0,	mipscofp2,
726
	"finstr25",	0,	mipscoxxx,
727
	"finstr26",	0,	mipscoxxx,
728
	"finstr27",	0,	mipscoxxx,
729
	"finstr28",	0,	mipscoxxx,
730
	"finstr29",	0,	mipscoxxx,
731
	"finstr2A",	0,	mipscoxxx,
732
	"finstr2B",	0,	mipscoxxx,
733
	"finstr2C",	0,	mipscoxxx,
734
	"finstr2D",	0,	mipscoxxx,
735
	"finstr2E",	0,	mipscoxxx,
736
	"finstr2F",	0,	mipscoxxx,
737
	"c.f.%f",	0,	mipscofpc,
738
	"c.un.%f",	0,	mipscofpc,
739
	"CMPEQ%f",	0,	mipsfpc,
740
	"c.ueq.%f",	0,	mipscofpc,
741
	"c.olt.%f",	0,	mipscofpc,
742
	"c.ult.%f",	0,	mipscofpc,
743
	"c.ole.%f",	0,	mipscofpc,
744
	"c.ule.%f",	0,	mipscofpc,
745
	"c.sf.%f",	0,	mipscofpc,
746
	"c.ngle.%f",	0,	mipscofpc,
747
	"c.seq.%f",	0,	mipscofpc,
748
	"c.ngl.%f",	0,	mipscofpc,
749
	"CMPGT%f",	0,	mipsfpc,
750
	"c.nge.%f",	0,	mipscofpc,
751
	"CMPGE%f",	0,	mipsfpc,
752
	"c.ngt.%f",	0,	mipscofpc,
753
};
754
 
755
static char *cop0regs[32] = {
756
	"INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
757
	"CONTEXT", "PageMask", "Wired",	"Error",
758
	"BADVADDR", "Count", "TLBVIRT", "Compare",
759
	"STATUS", "CAUSE", "EPC", "PRID",
760
	"Config", "LLadr", "WatchLo", "WatchHi",
761
	"20", "21", "22", "23",
762
	"24", "25", "26", "CacheErr",
763
	"TagLo", "TagHi", "ErrorEPC", "31"
764
};
765
 
766
static char fsub[16] = {
767
	'F', 'D', 'e', 'q', 'W', '?', '?', '?',
768
	'?', '?', '?', '?', '?', '?', '?', '?'
769
};
770
 
771
static char *cacheps[] = {
772
	"I", "D", "SI", "SD"
773
};
774
 
775
static char *cacheop[] = {
776
	"IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
777
};
778
 
779
static void
780
format(char *mnemonic, Instr *i, char *f)
781
{
782
	if (mnemonic)
783
		format(0, i, mnemonic);
784
	if (f == 0)
785
		return;
786
	if (mnemonic)
787
		if (i->curr < i->end)
788
			*i->curr++ = '\t';
789
	for ( ; *f && i->curr < i->end; f++) {
790
		if (*f != '%') {
791
			*i->curr++ = *f;
792
			continue;
793
		}
794
		switch (*++f) {
795
 
796
		case 's':
797
			bprint(i, "%d", i->rs);
798
			break;
799
 
800
		case 't':
801
			bprint(i, "%d", i->rt);
802
			break;
803
 
804
		case 'd':
805
			bprint(i, "%d", i->rd);
806
			break;
807
 
808
		case 'a':
809
			bprint(i, "%d", i->sa);
810
			break;
811
 
812
		case 'l':
813
			bprint(i, "%lx(R%d)",i->immediate, i->rs);
814
			break;
815
 
816
		case 'i':
817
			bprint(i, "$%lx", i->immediate);
818
			break;
819
 
820
		case 'u':
821
			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
822
			bprint(i, "(SB)");
823
			break;
824
 
825
		case 'j':
826
			i->curr += symoff(i->curr, i->end-i->curr,
827
				(i->target<<2)|(i->addr & 0xF0000000), CANY);
828
			bprint(i, "(SB)");
829
			break;
830
 
831
		case 'b':
832
			i->curr += symoff(i->curr, i->end-i->curr,
833
				(i->immediate<<2)+i->addr+4, CANY);
834
			break;
835
 
836
		case 'c':
837
			bprint(i, "$%lx", i->cofun);
838
			break;
839
 
840
		case 'w':
841
			bprint(i, "[%lux]", i->w0);
842
			break;
843
 
844
		case 'm':
845
			bprint(i, "M(%s)", cop0regs[i->rd]);
846
			break;
847
 
848
		case 'f':
849
			*i->curr++ = fsub[i->rs & 0x0F];
850
			break;
851
 
852
		case 'C':
853
			bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
854
			break;
855
 
856
		case '\0':
857
			*i->curr++ = '%';
858
			return;
859
 
860
		default:
861
			bprint(i, "%%%c", *f);
862
			break;
863
		}
864
	}
865
	*i->curr = 0;
866
}
867
 
868
static void
869
copz(int cop, Instr *i)
870
{
871
	char *f, *m, buf[16];
872
 
873
	m = buf;
874
	f = "%t,%d";
875
	switch (i->rs) {
876
 
877
	case 0:
878
		sprint(buf, "mfc%d", cop);
879
		break;
880
 
881
	case 2:
882
		sprint(buf, "cfc%d", cop);
883
		break;
884
 
885
	case 4:
886
		sprint(buf, "mtc%d", cop);
887
		break;
888
 
889
	case 6:
890
		sprint(buf, "ctc%d", cop);
891
		break;
892
 
893
	case 8:
894
		f = "%b";
895
		switch (i->rt) {
896
 
897
		case 0:
898
			sprint(buf, "bc%df", cop);
899
			break;
900
 
901
		case 1:
902
			sprint(buf, "bc%dt", cop);
903
			break;
904
 
905
		case 2:
906
			sprint(buf, "bc%dfl", cop);
907
			break;
908
 
909
		case 3:
910
			sprint(buf, "bc%dtl", cop);
911
			break;
912
 
913
		default:
914
			sprint(buf, "cop%d", cop);
915
			f = mipscoxxx;
916
			break;
917
		}
918
		break;
919
 
920
	default:
921
		sprint(buf, "cop%d", cop);
922
		if (i->rs & 0x10)
923
			f = "function %c";
924
		else
925
			f = mipscoxxx;
926
		break;
927
	}
928
	format(m, i, f);
929
}
930
 
931
static void
932
cop0(Instr *i)
933
{
934
	char *m = 0;
935
 
936
	if (i->rs < 8) {
937
		switch (i->rs) {
938
 
939
		case 0:
940
		case 1:
941
			format("MOVW", i, "%m,R%t");
942
			return;
943
 
944
		case 4:
945
		case 5:
946
			format("MOVW", i, "R%t,%m");
947
			return;
948
		}
949
	}
950
	else if (i->rs >= 0x10) {
951
		switch (i->cofun) {
952
 
953
		case 1:
954
			m = "TLBR";
955
			break;
956
 
957
		case 2:
958
			m = "TLBWI";
959
			break;
960
 
961
		case 6:
962
			m = "TLBWR";
963
			break;
964
 
965
		case 8:
966
			m = "TLBP";
967
			break;
968
 
969
		case 16:
970
			m = "RFE";
971
			break;
972
 
973
		case 24:
974
			m = "ERET";
975
			break;
976
 
977
		case 32:
978
			m = "WAIT";
979
			break;
980
		}
981
		if (m) {
982
			format(m, i, 0);
983
			return;
984
		}
985
	}
986
	copz(0, i);
987
}
988
 
989
static void
990
cop1(Instr *i)
991
{
992
	char *m = "MOVW";
993
 
994
	switch (i->rs) {
995
 
996
	case 0:
997
		format(m, i, "F%d,R%t");
998
		return;
999
 
1000
	case 2:
1001
		format(m, i, "FCR%d,R%t");
1002
		return;
1003
 
1004
	case 4:
1005
		format(m, i, "R%t,F%d");
1006
		return;
1007
 
1008
	case 6:
1009
		format(m, i, "R%t,FCR%d");
1010
		return;
1011
 
1012
	case 8:
1013
		switch (i->rt) {
1014
 
1015
		case 0:
1016
			format("BFPF", i, "%b");
1017
			return;
1018
 
1019
		case 1:
1020
			format("BFPT", i, "%b");
1021
			return;
1022
		}
1023
		break;
1024
	}
1025
	copz(1, i);
1026
}
1027
 
1028
static int
1029
printins(Map *map, uvlong pc, char *buf, int n)
1030
{
1031
	Instr i;
1032
	Opcode *o;
1033
	uchar op;
1034
 
1035
	i.curr = buf;
1036
	i.end = buf+n-1;
1037
	mymap = map;
1038
	if (mkinstr(pc, &i) < 0)
1039
		return -1;
1040
	switch (i.op) {
1041
 
1042
	case 0x00:					/* SPECIAL */
1043
		o = sopcodes;
1044
		op = i.function;
1045
		break;
1046
 
1047
	case 0x01:					/* REGIMM */
1048
		o = ropcodes;
1049
		op = i.rt;
1050
		break;
1051
 
1052
	case 0x10:					/* COP0 */
1053
		cop0(&i);
1054
		return i.size*4;
1055
 
1056
	case 0x11:					/* COP1 */
1057
		if (i.rs & 0x10) {
1058
			o = fopcodes;
1059
			op = i.function;
1060
			break;
1061
		}
1062
		cop1(&i);
1063
		return i.size*4;
1064
 
1065
	case 0x12:					/* COP2 */
1066
	case 0x13:					/* COP3 */
1067
		copz(i.op-0x10, &i);
1068
		return i.size*4;
1069
 
1070
	default:
1071
		o = opcodes;
1072
		op = i.op;
1073
		break;
1074
	}
1075
	if (o[op].f)
1076
		(*o[op].f)(&o[op], &i);
1077
	else
1078
		format(o[op].mnemonic, &i, o[op].ken);
1079
	return i.size*4;
1080
}
1081
 
1082
extern	int	_mipscoinst(Map *, uvlong, char*, int);
1083
 
1084
	/* modifier 'I' toggles the default disassembler type */
1085
static int
1086
mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1087
{
1088
	if ((asstype == AMIPSCO && modifier == 'i')
1089
		|| (asstype == AMIPS && modifier == 'I'))
1090
		return _mipscoinst(map, pc, buf, n);
1091
	else
1092
		return printins(map, pc, buf, n);
1093
}
1094
 
1095
static int
1096
mipsdas(Map *map, uvlong pc, char *buf, int n)
1097
{
1098
	Instr i;
1099
 
1100
	i.curr = buf;
1101
	i.end = buf+n;
1102
	mymap = map;
1103
	if (mkinstr(pc, &i) < 0)
1104
		return -1;
1105
	if (i.end-i.curr > 8)
1106
		i.curr = _hexify(buf, i.w0, 7);
1107
	if (i.size == 2 && i.end-i.curr > 9) {
1108
		*i.curr++ = ' ';
1109
		i.curr = _hexify(i.curr, i.w1, 7);
1110
	}
1111
	*i.curr = 0;
1112
	return i.size*4;
1113
}
1114
 
1115
static int
1116
mipsinstlen(Map *map, uvlong pc)
1117
{
1118
	Instr i;
1119
 
1120
	mymap = map;
1121
	if (mkinstr(pc, &i) < 0)
1122
		return -1;
1123
	return i.size*4;
1124
}
1125
 
1126
static int
1127
mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1128
{
1129
	ulong w, l;
1130
	char buf[8];
1131
	Instr i;
1132
 
1133
	mymap = map;
1134
	if (mkinstr(pc, &i) < 0)
1135
		return -1;
1136
	w = i.w0;
1137
	if((w&0xF3600000) == 0x41000000){	/* branch on coprocessor */
1138
    Conditional:
1139
		foll[0] = pc+8;
1140
		l = ((w&0xFFFF)<<2);
1141
		if(w & 0x8000)
1142
			l |= 0xFFFC0000;
1143
		foll[1] = pc+4 + l;
1144
		return 2;
1145
	}
1146
 
1147
	l = (w&0xFC000000)>>26;
1148
	switch(l){
1149
	case 0:		/* SPECIAL */
1150
		if((w&0x3E) == 0x08){	/* JR, JALR */
1151
			sprint(buf, "R%ld", (w>>21)&0x1F);
1152
			foll[0] = (*rget)(map, buf);
1153
			return 1;
1154
		}
1155
		foll[0] = pc+i.size*4;
1156
		return 1;
1157
	case 0x30:	/* Load-Linked followed by NOP, STC */
1158
		foll[0] = pc+12;
1159
		return 1;
1160
	case 1:		/* BCOND */
1161
	case 4:		/* BEQ */
1162
	case 20:	/* BEQL */
1163
	case 5:		/* BNE */
1164
	case 21:	/* BNEL */
1165
	case 6:		/* BLEZ */
1166
	case 22:	/* BLEZL */
1167
	case 7:		/* BGTZ */
1168
	case 23:	/* BGTZL */
1169
		goto Conditional;
1170
	case 2:		/* J */
1171
	case 3:		/* JAL */
1172
		foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1173
		return 1;
1174
	}
1175
 
1176
	foll[0] = pc+i.size*4;
1177
	return 1;
1178
}