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