xref: /inferno-os/libinterp/das-mips.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include <lib9.h>
2 
3 /* mips native disassembler */
4 
5 typedef struct {
6 	long addr;			/* pc of instr */
7 	uchar op;			/* bits 31-26 */
8 	uchar rs;			/* bits 25-21 */
9 	uchar rt;			/* bits 20-16 */
10 	uchar rd;			/* bits 15-11 */
11 	uchar sa;			/* bits 10-6 */
12 	uchar function;			/* bits 5-0 */
13 	long immediate;			/* bits 15-0 */
14 	ulong cofun;			/* bits 24-0 */
15 	ulong target;			/* bits 25-0 */
16 	long w0;
17 	char *curr;			/* current fill point */
18 	char *end;			/* end of buffer */
19 	char *err;
20 } Instr;
21 
22 typedef struct {
23 	char *mnemonic;
24 	char *mipsco;
25 } Opcode;
26 
27 static char mipscoload[] = "r%t,%l";
28 static char mipscoalui[] = "r%t,r%s,%i";
29 static char mipscoalu3op[] = "r%d,r%s,r%t";
30 static char mipscoboc[] = "r%s,r%t,%b";
31 static char mipscoboc0[] = "r%s,%b";
32 static char mipscorsrt[] = "r%s,r%t";
33 static char mipscorsi[] = "r%s,%i";
34 static char mipscoxxx[] = "%w";
35 static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
36 static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
37 static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
38 
39 static Opcode opcodes[64] = {
40 	0,		0,
41 	0,		0,
42 	"j",		"%j",
43 	"jal",		"%j",
44 	"beq",		mipscoboc,
45 	"bne",		mipscoboc,
46 	"blez",		mipscoboc0,
47 	"bgtz",		mipscoboc0,
48 	"addi",		mipscoalui,
49 	"addiu",	mipscoalui,
50 	"slti",		mipscoalui,
51 	"sltiu",	mipscoalui,
52 	"andi",		mipscoalui,
53 	"ori",		mipscoalui,
54 	"xori",		mipscoalui,
55 	"lui",		"r%t,%u",
56 	"cop0",		0,
57 	"cop1",		0,
58 	"cop2",		0,
59 	"cop3",		0,
60 	"beql",		mipscoboc,
61 	"bnel",		mipscoboc,
62 	"blezl",	mipscoboc0,
63 	"bgtzl",	mipscoboc0,
64 	"instr18",	mipscoxxx,
65 	"instr19",	mipscoxxx,
66 	"instr1A",	mipscoxxx,
67 	"instr1B",	mipscoxxx,
68 	"instr1C",	mipscoxxx,
69 	"instr1D",	mipscoxxx,
70 	"instr1E",	mipscoxxx,
71 	"instr1F",	mipscoxxx,
72 	"lb",		mipscoload,
73 	"lh",		mipscoload,
74 	"lwl",		mipscoload,
75 	"lw",		mipscoload,
76 	"lbu",		mipscoload,
77 	"lhu",		mipscoload,
78 	"lwr",		mipscoload,
79 	"instr27",	mipscoxxx,
80 	"sb",		mipscoload,
81 	"sh",		mipscoload,
82 	"swl",		mipscoload,
83 	"sw",		mipscoload,
84 	"instr2C",	mipscoxxx,
85 	"instr2D",	mipscoxxx,
86 	"swr",		mipscoload,
87 	"cache",	"",
88 	"ll",		mipscoload,
89 	"lwc1",		mipscoload,
90 	"lwc2",		mipscoload,
91 	"lwc3",		mipscoload,
92 	"instr34",	mipscoxxx,
93 	"ld",		mipscoload,
94 	"ld",		mipscoload,
95 	"ld",		mipscoload,
96 	"sc",		mipscoload,
97 	"swc1",		mipscoload,
98 	"swc2",		mipscoload,
99 	"swc3",		mipscoload,
100 	"instr3C",	mipscoxxx,
101 	"sd",		mipscoload,
102 	"sd",		mipscoload,
103 	"sd",		mipscoload,
104 };
105 
106 static Opcode sopcodes[64] = {
107 	"sll",		"r%d,r%t,$%a",
108 	"special01",	mipscoxxx,
109 	"srl",		"r%d,r%t,$%a",
110 	"sra",		"r%d,r%t,$%a",
111 	"sllv",		"r%d,r%t,R%s",
112 	"special05",	mipscoxxx,
113 	"srlv",		"r%d,r%t,r%s",
114 	"srav",		"r%d,r%t,r%s",
115 	"jr",		"r%s",
116 	"jalr",		"r%d,r%s",
117 	"special0A",	mipscoxxx,
118 	"special0B",	mipscoxxx,
119 	"syscall",	"",
120 	"break",	"",
121 	"special0E",	mipscoxxx,
122 	"sync",		"",
123 	"mfhi",		"r%d",
124 	"mthi",		"r%s",
125 	"mflo",		"r%d",
126 	"mtlo",		"r%s",
127 	"special14",	mipscoxxx,
128 	"special15",	mipscoxxx,
129 	"special16",	mipscoxxx,
130 	"special17",	mipscoxxx,
131 	"mult",		mipscorsrt,
132 	"multu",	mipscorsrt,
133 	"div",		mipscorsrt,
134 	"divu",		mipscorsrt,
135 	"special1C",	mipscoxxx,
136 	"special1D",	mipscoxxx,
137 	"special1E",	mipscoxxx,
138 	"special1F",	mipscoxxx,
139 	"add",		mipscoalu3op,
140 	"addu",		mipscoalu3op,
141 	"sub",		mipscoalu3op,
142 	"subu",		mipscoalu3op,
143 	"and",		mipscoalu3op,
144 	"or",		mipscoalu3op,
145 	"xor",		mipscoalu3op,
146 	"nor",		mipscoalu3op,
147 	"special28",	mipscoxxx,
148 	"special29",	mipscoxxx,
149 	"slt",		mipscoalu3op,
150 	"sltu",		mipscoalu3op,
151 	"special2C",	mipscoxxx,
152 	"special2D",	mipscoxxx,
153 	"special2E",	mipscoxxx,
154 	"special2F",	mipscoxxx,
155 	"tge",		mipscorsrt,
156 	"tgeu",		mipscorsrt,
157 	"tlt",		mipscorsrt,
158 	"tltu",		mipscorsrt,
159 	"teq",		mipscorsrt,
160 	"special35",	mipscoxxx,
161 	"tne",		mipscorsrt,
162 	"special37",	mipscoxxx,
163 	"special38",	mipscoxxx,
164 	"special39",	mipscoxxx,
165 	"special3A",	mipscoxxx,
166 	"special3B",	mipscoxxx,
167 	"special3C",	mipscoxxx,
168 	"special3D",	mipscoxxx,
169 	"special3E",	mipscoxxx,
170 	"special3F",	mipscoxxx,
171 };
172 
173 static Opcode ropcodes[32] = {
174 	"bltz",		mipscoboc0,
175 	"bgez",		mipscoboc0,
176 	"bltzl",	mipscoboc0,
177 	"bgezl",	mipscoboc0,
178 	"regimm04",	mipscoxxx,
179 	"regimm05",	mipscoxxx,
180 	"regimm06",	mipscoxxx,
181 	"regimm07",	mipscoxxx,
182 	"tgei",		mipscorsi,
183 	"tgeiu",	mipscorsi,
184 	"tlti",		mipscorsi,
185 	"tltiu",	mipscorsi,
186 	"teqi",		mipscorsi,
187 	"regimm0D",	mipscoxxx,
188 	"tnei",		mipscorsi,
189 	"regimm0F",	mipscoxxx,
190 	"bltzal",	mipscoboc0,
191 	"bgezal",	mipscoboc0,
192 	"bltzall",	mipscoboc0,
193 	"bgezall",	mipscoboc0,
194 	"regimm14",	mipscoxxx,
195 	"regimm15",	mipscoxxx,
196 	"regimm16",	mipscoxxx,
197 	"regimm17",	mipscoxxx,
198 	"regimm18",	mipscoxxx,
199 	"regimm19",	mipscoxxx,
200 	"regimm1A",	mipscoxxx,
201 	"regimm1B",	mipscoxxx,
202 	"regimm1C",	mipscoxxx,
203 	"regimm1D",	mipscoxxx,
204 	"regimm1E",	mipscoxxx,
205 	"regimm1F",	mipscoxxx,
206 };
207 
208 static Opcode fopcodes[64] = {
209 	"add.%f",	mipscofp3,
210 	"sub.%f",	mipscofp3,
211 	"mul.%f",	mipscofp3,
212 	"div.%f",	mipscofp3,
213 	"sqrt.%f",	mipscofp2,
214 	"abs.%f",	mipscofp2,
215 	"mov.%f",	mipscofp2,
216 	"neg.%f",	mipscofp2,
217 	"finstr08",	mipscoxxx,
218 	"finstr09",	mipscoxxx,
219 	"finstr0A",	mipscoxxx,
220 	"finstr0B",	mipscoxxx,
221 	"round.w.%f",	mipscofp2,
222 	"trunc.w%f",	mipscofp2,
223 	"ceil.w%f",	mipscofp2,
224 	"floor.w%f",	mipscofp2,
225 	"finstr10",	mipscoxxx,
226 	"finstr11",	mipscoxxx,
227 	"finstr12",	mipscoxxx,
228 	"finstr13",	mipscoxxx,
229 	"finstr14",	mipscoxxx,
230 	"finstr15",	mipscoxxx,
231 	"finstr16",	mipscoxxx,
232 	"finstr17",	mipscoxxx,
233 	"finstr18",	mipscoxxx,
234 	"finstr19",	mipscoxxx,
235 	"finstr1A",	mipscoxxx,
236 	"finstr1B",	mipscoxxx,
237 	"finstr1C",	mipscoxxx,
238 	"finstr1D",	mipscoxxx,
239 	"finstr1E",	mipscoxxx,
240 	"finstr1F",	mipscoxxx,
241 	"cvt.s.%f",	mipscofp2,
242 	"cvt.d.%f",	mipscofp2,
243 	"cvt.e.%f",	mipscofp2,
244 	"cvt.q.%f",	mipscofp2,
245 	"cvt.w.%f",	mipscofp2,
246 	"finstr25",	mipscoxxx,
247 	"finstr26",	mipscoxxx,
248 	"finstr27",	mipscoxxx,
249 	"finstr28",	mipscoxxx,
250 	"finstr29",	mipscoxxx,
251 	"finstr2A",	mipscoxxx,
252 	"finstr2B",	mipscoxxx,
253 	"finstr2C",	mipscoxxx,
254 	"finstr2D",	mipscoxxx,
255 	"finstr2E",	mipscoxxx,
256 	"finstr2F",	mipscoxxx,
257 	"c.f.%f",	mipscofpc,
258 	"c.un.%f",	mipscofpc,
259 	"c.eq.%f",	mipscofpc,
260 	"c.ueq.%f",	mipscofpc,
261 	"c.olt.%f",	mipscofpc,
262 	"c.ult.%f",	mipscofpc,
263 	"c.ole.%f",	mipscofpc,
264 	"c.ule.%f",	mipscofpc,
265 	"c.sf.%f",	mipscofpc,
266 	"c.ngle.%f",	mipscofpc,
267 	"c.seq.%f",	mipscofpc,
268 	"c.ngl.%f",	mipscofpc,
269 	"c.lt.%f",	mipscofpc,
270 	"c.nge.%f",	mipscofpc,
271 	"c.le.%f",	mipscofpc,
272 	"c.ngt.%f",	mipscofpc,
273 };
274 
275 static char fsub[16] = {
276 	's', 'd', 'e', 'q', 'w', '?', '?', '?',
277 	'?', '?', '?', '?', '?', '?', '?', '?'
278 };
279 
280 
281 static void
282 bprint(Instr *i, char *fmt, ...)
283 {
284 	va_list arg;
285 
286 	va_start(arg, fmt);
287 	i->curr = vseprint(i->curr, i->end, fmt, arg);
288 	va_end(arg);
289 }
290 
291 static void
292 format(char *mnemonic, Instr *i, char *f)
293 {
294 	if (mnemonic)
295 		format(0, i, mnemonic);
296 	if (f == 0)
297 		return;
298 	if (i->curr < i->end)
299 		*i->curr++ = '\t';
300 	for ( ; *f && i->curr < i->end; f++) {
301 		if (*f != '%') {
302 			*i->curr++ = *f;
303 			continue;
304 		}
305 		switch (*++f) {
306 
307 		case 's':
308 			bprint(i, "%d", i->rs);
309 			break;
310 
311 		case 't':
312 			bprint(i, "%d", i->rt);
313 			break;
314 
315 		case 'd':
316 			bprint(i, "%d", i->rd);
317 			break;
318 
319 		case 'a':
320 			bprint(i, "%d", i->sa);
321 			break;
322 
323 		case 'l':
324 			bprint(i, "%d(r%d)", i->immediate, i->rs);
325 			break;
326 
327 		case 'u':
328 		case 'i':
329 			bprint(i, "$%d", i->immediate);
330 			break;
331 
332 		case 'j':
333 			bprint(i, "0x%lux", (i->target<<2)|(i->addr & 0xF0000000));
334 			break;
335 
336 		case 'b':
337 			bprint(i, "0x%lux", (i->immediate<<2)+i->addr+4);
338 			break;
339 
340 		case 'c':
341 			bprint(i, "0x%lux", i->cofun);
342 			break;
343 
344 		case 'w':
345 			bprint(i, "[0x%lux]", i->w0);
346 			break;
347 
348 		case 'f':
349 			*i->curr++ = fsub[i->rs & 0x0F];
350 			break;
351 
352 		case '\0':
353 			*i->curr++ = '%';
354 			return;
355 
356 		default:
357 			bprint(i, "%%%c", *f);
358 			break;
359 		}
360 	}
361 }
362 
363 static void
364 copz(int cop, Instr *i)
365 {
366 	char *f, *m, buf[16];
367 
368 	m = buf;
369 	f = "%t,%d";
370 	switch (i->rs) {
371 
372 	case 0:
373 		sprint(buf, "mfc%d", cop);
374 		break;
375 
376 	case 2:
377 		sprint(buf, "cfc%d", cop);
378 		break;
379 
380 	case 4:
381 		sprint(buf, "mtc%d", cop);
382 		break;
383 
384 	case 6:
385 		sprint(buf, "ctc%d", cop);
386 		break;
387 
388 	case 8:
389 		f = "%b";
390 		switch (i->rt) {
391 
392 		case 0:
393 			sprint(buf, "bc%df", cop);
394 			break;
395 
396 		case 1:
397 			sprint(buf, "bc%dt", cop);
398 			break;
399 
400 		case 2:
401 			sprint(buf, "bc%dfl", cop);
402 			break;
403 
404 		case 3:
405 			sprint(buf, "bc%dtl", cop);
406 			break;
407 
408 		default:
409 			sprint(buf, "cop%d", cop);
410 			f = mipscoxxx;
411 			break;
412 		}
413 		break;
414 
415 	default:
416 		sprint(buf, "cop%d", cop);
417 		if (i->rs & 0x10)
418 			f = "function %c";
419 		else
420 			f = mipscoxxx;
421 		break;
422 	}
423 	format(m, i, f);
424 }
425 
426 static void
427 cop0(Instr *i)
428 {
429 	char *m = 0;
430 
431 	if (i->rs >= 0x10) {
432 		switch (i->cofun) {
433 
434 		case 1:
435 			m = "tlbr";
436 			break;
437 
438 		case 2:
439 			m = "tlbwi";
440 			break;
441 
442 		case 6:
443 			m = "tlbwr";
444 			break;
445 
446 		case 8:
447 			m = "tlbp";
448 			break;
449 
450 		case 16:
451 			m = "rfe";
452 			break;
453 
454 		case 32:
455 			m = "eret";
456 			break;
457 		}
458 		if (m) {
459 			format(m, i, 0);
460 			if (i->curr < i->end)
461 				*i->curr++ = 0;
462 			return;
463 		}
464 	}
465 	copz(0, i);
466 }
467 
468 void
469 das(ulong *pc)
470 {
471 	Instr i;
472 	char buf[100];
473 	Opcode *o;
474 	uchar op;
475 	ulong w;
476 
477 	w = *pc;
478 
479 	i.addr = (ulong)pc;
480 	i.op = (w >> 26) & 0x3F;
481 	i.rs = (w >> 21) & 0x1F;
482 	i.rt = (w >> 16) & 0x1F;
483 	i.rd = (w >> 11) & 0x1F;
484 	i.sa = (w >> 6) & 0x1F;
485 	i.function = w & 0x3F;
486 	i.immediate = w & 0x0000FFFF;
487 	if(i.immediate & 0x8000)
488 		i.immediate |= ~0x0000FFFF;
489 	i.cofun = w & 0x01FFFFFF;
490 	i.target = w & 0x03FFFFFF;
491 	i.w0 = w;
492 	i.curr = buf;
493 	i.end = buf+sizeof(buf)-1;
494 
495 	i.curr += sprint(i.curr, "	%.8p %.8lux", pc, w);
496 
497 	o = opcodes;
498 	op = i.op;
499 	switch (i.op) {
500 
501 	case 0x00:					/* SPECIAL */
502 		o = sopcodes;
503 		op = i.function;
504 		break;
505 
506 	case 0x01:					/* REGIMM */
507 		o = ropcodes;
508 		op = i.rt;
509 		break;
510 
511 	case 0x10:					/* COP0 */
512 		cop0(&i);
513 		break;
514 
515 	case 0x11:					/* COP1 */
516 		if (i.rs & 0x10) {
517 			o = fopcodes;
518 			op = i.function;
519 			break;
520 		}
521 		/*FALLTHROUGH*/
522 	case 0x12:					/* COP2 */
523 	case 0x13:					/* COP3 */
524 		copz(i.op-0x10, &i);
525 		break;
526 	}
527 	format(o[op].mnemonic, &i, o[op].mipsco);
528 	*i.curr++ = '\n';
529 	*i.curr = 0;
530 	print("%s", buf);
531 }
532