xref: /inferno-os/utils/libmach/vcodas.c (revision c094a1409b780cc543c077e8469fdb28b4c90afb)
1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 
5 	/* mips native disassembler */
6 
7 typedef struct {
8 	long 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, ulong pc)
285 {
286 	long 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 static void
309 bprint(Instr *i, char *fmt, ...)
310 {
311 	va_list arg;
312 
313 	va_start(arg, fmt);
314 	i->curr = vseprint(i->curr, i->end, fmt, arg);
315 	va_end(arg);
316 }
317 
318 static void
319 format(char *mnemonic, Instr *i, char *f)
320 {
321 	if (mnemonic)
322 		format(0, i, mnemonic);
323 	if (f == 0)
324 		return;
325 	if (i->curr < i->end)
326 		*i->curr++ = '\t';
327 	for ( ; *f && i->curr < i->end; f++) {
328 		if (*f != '%') {
329 			*i->curr++ = *f;
330 			continue;
331 		}
332 		switch (*++f) {
333 
334 		case 's':
335 			bprint(i, "%d", i->rs);
336 			break;
337 
338 		case 't':
339 			bprint(i, "%d", i->rt);
340 			break;
341 
342 		case 'd':
343 			bprint(i, "%d", i->rd);
344 			break;
345 
346 		case 'a':
347 			bprint(i, "%d", i->sa);
348 			break;
349 
350 		case 'l':
351 			if (i->rs == 30) {
352 				i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
353 				bprint(i, "(SB)");
354 			} else
355 				bprint(i, "%lx(r%d)", i->immediate, i->rs);
356 			break;
357 
358 		case 'i':
359 			bprint(i, "$%lx", i->immediate);
360 			break;
361 
362 		case 'u':
363 			*i->curr++ = '$';
364 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
365 			bprint(i, "(SB)");
366 			break;
367 
368 		case 'j':
369 			i->curr += symoff(i->curr, i->end-i->curr,
370 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
371 			bprint(i, "(SB)");
372 			break;
373 
374 		case 'b':
375 			i->curr += symoff(i->curr, i->end-i->curr,
376 				(i->immediate<<2)+i->addr+4, CANY);
377 			break;
378 
379 		case 'c':
380 			bprint(i, "%lux", i->cofun);
381 			break;
382 
383 		case 'w':
384 			bprint(i, "[%lux]", i->w0);
385 			break;
386 
387 		case 'f':
388 			*i->curr++ = fsub[i->rs & 0x0F];
389 			break;
390 
391 		case '\0':
392 			*i->curr++ = '%';
393 			return;
394 
395 		default:
396 			bprint(i, "%%%c", *f);
397 			break;
398 		}
399 	}
400 }
401 
402 static void
403 copz(int cop, Instr *i)
404 {
405 	char *f, *m, buf[16];
406 
407 	m = buf;
408 	f = "%t,%d";
409 	switch (i->rs) {
410 
411 	case 0:
412 		sprint(buf, "mfc%d", cop);
413 		break;
414 
415 	case 2:
416 		sprint(buf, "cfc%d", cop);
417 		break;
418 
419 	case 4:
420 		sprint(buf, "mtc%d", cop);
421 		break;
422 
423 	case 6:
424 		sprint(buf, "ctc%d", cop);
425 		break;
426 
427 	case 8:
428 		f = "%b";
429 		switch (i->rt) {
430 
431 		case 0:
432 			sprint(buf, "bc%df", cop);
433 			break;
434 
435 		case 1:
436 			sprint(buf, "bc%dt", cop);
437 			break;
438 
439 		case 2:
440 			sprint(buf, "bc%dfl", cop);
441 			break;
442 
443 		case 3:
444 			sprint(buf, "bc%dtl", cop);
445 			break;
446 
447 		default:
448 			sprint(buf, "cop%d", cop);
449 			f = mipscoxxx;
450 			break;
451 		}
452 		break;
453 
454 	default:
455 		sprint(buf, "cop%d", cop);
456 		if (i->rs & 0x10)
457 			f = "function %c";
458 		else
459 			f = mipscoxxx;
460 		break;
461 	}
462 	format(m, i, f);
463 }
464 
465 static void
466 cop0(Instr *i)
467 {
468 	char *m = 0;
469 
470 	if (i->rs >= 0x10) {
471 		switch (i->cofun) {
472 
473 		case 1:
474 			m = "tlbr";
475 			break;
476 
477 		case 2:
478 			m = "tlbwi";
479 			break;
480 
481 		case 6:
482 			m = "tlbwr";
483 			break;
484 
485 		case 8:
486 			m = "tlbp";
487 			break;
488 
489 		case 16:
490 			m = "rfe";
491 			break;
492 
493 		case 32:
494 			m = "eret";
495 			break;
496 		}
497 		if (m) {
498 			format(m, i, 0);
499 			if (i->curr < i->end)
500 				*i->curr++ = 0;
501 			return;
502 		}
503 	}
504 	copz(0, i);
505 }
506 
507 int
508 _mipscoinst(Map *map, ulong pc, char *buf, int n)
509 {
510 	Instr i;
511 	Opcode *o;
512 	uchar op;
513 
514 	i.curr = buf;
515 	i.end = buf+n-1;
516 	if (mkinstr(&i, map, pc) < 0)
517 		return -1;
518 	switch (i.op) {
519 
520 	case 0x00:					/* SPECIAL */
521 		o = sopcodes;
522 		op = i.function;
523 		break;
524 
525 	case 0x01:					/* REGIMM */
526 		o = ropcodes;
527 		op = i.rt;
528 		break;
529 
530 	case 0x10:					/* COP0 */
531 		cop0(&i);
532 		return 4;
533 
534 	case 0x11:					/* COP1 */
535 		if (i.rs & 0x10) {
536 			o = fopcodes;
537 			op = i.function;
538 			break;
539 		}
540 		/*FALLTHROUGH*/
541 	case 0x12:					/* COP2 */
542 	case 0x13:					/* COP3 */
543 		copz(i.op-0x10, &i);
544 		return 4;
545 
546 	default:
547 		o = opcodes;
548 		op = i.op;
549 		break;
550 	}
551 	format(o[op].mnemonic, &i, o[op].mipsco);
552 	return 4;
553 }
554