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