xref: /inferno-os/libinterp/das-mips.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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
bprint(Instr * i,char * fmt,...)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
format(char * mnemonic,Instr * i,char * f)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
copz(int cop,Instr * i)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
cop0(Instr * i)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
das(ulong * pc)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