]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/vdb.c
1445ff273091261ff7772c5055e6c748af72ecef
[plan9front.git] / sys / src / libmach / vdb.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 /*
6  * Mips-specific debugger interface
7  */
8
9 static  char    *mipsexcep(Map*, Rgetter);
10 static  int     mipsfoll(Map*, uvlong, Rgetter, uvlong*);
11 static  int     mipsinst(Map*, uvlong, char, char*, int);
12 static  int     mipsdas(Map*, uvlong, char*, int);
13 static  int     mipsinstlen(Map*, uvlong);
14
15 /*
16  *      Debugger interface
17  */
18 Machdata mipsmach =
19 {
20         {0, 0, 0, 0xD},         /* break point */
21         4,                      /* break point size */
22
23         beswab,                 /* short to local byte order */
24         beswal,                 /* long to local byte order */
25         beswav,                 /* vlong to local byte order */
26         risctrace,              /* C traceback */
27         riscframe,              /* Frame finder */
28         mipsexcep,              /* print exception */
29         0,                      /* breakpoint fixup */
30         beieeesftos,            /* single precision float printer */
31         beieeedftos,            /* double precisioin float printer */
32         mipsfoll,               /* following addresses */
33         mipsinst,               /* print instruction */
34         mipsdas,                /* dissembler */
35         mipsinstlen,            /* instruction size */
36 };
37
38 Machdata mipsmachle =
39 {
40         {0xD, 0, 0, 0},         /* break point */
41         4,                      /* break point size */
42
43         leswab,                 /* short to local byte order */
44         leswal,                 /* long to local byte order */
45         leswav,                 /* vlong to local byte order */
46         risctrace,              /* C traceback */
47         riscframe,              /* Frame finder */
48         mipsexcep,              /* print exception */
49         0,                      /* breakpoint fixup */
50         leieeesftos,            /* single precision float printer */
51         leieeedftos,            /* double precisioin float printer */
52         mipsfoll,               /* following addresses */
53         mipsinst,               /* print instruction */
54         mipsdas,                /* dissembler */
55         mipsinstlen,            /* instruction size */
56 };
57
58 /*
59  *      mips r4k little-endian
60  */
61 Machdata mipsmach2le =
62 {
63         {0xD, 0, 0, 0},         /* break point */
64         4,                      /* break point size */
65
66         leswab,                 /* short to local byte order */
67         leswal,                 /* long to local byte order */
68         leswav,                 /* vlong to local byte order */
69         risctrace,              /* C traceback */
70         riscframe,              /* Frame finder */
71         mipsexcep,              /* print exception */
72         0,                      /* breakpoint fixup */
73         leieeesftos,            /* single precision float printer */
74         leieeedftos,            /* double precisioin float printer */
75         mipsfoll,               /* following addresses */
76         mipsinst,               /* print instruction */
77         mipsdas,                /* dissembler */
78         mipsinstlen,            /* instruction size */
79 };
80
81 /*
82  *      mips r4k big-endian
83  */
84 Machdata mipsmach2be =
85 {
86         {0, 0, 0, 0xD},         /* break point */
87         4,                      /* break point size */
88
89         beswab,                 /* short to local byte order */
90         beswal,                 /* long to local byte order */
91         beswav,                 /* vlong to local byte order */
92         risctrace,              /* C traceback */
93         riscframe,              /* Frame finder */
94         mipsexcep,              /* print exception */
95         0,                      /* breakpoint fixup */
96         beieeesftos,            /* single precision float printer */
97         beieeedftos,            /* double precisioin float printer */
98         mipsfoll,               /* following addresses */
99         mipsinst,               /* print instruction */
100         mipsdas,                /* dissembler */
101         mipsinstlen,            /* instruction size */
102 };
103
104
105 static char *excname[] =
106 {
107         "external interrupt",
108         "TLB modification",
109         "TLB miss (load or fetch)",
110         "TLB miss (store)",
111         "address error (load or fetch)",
112         "address error (store)",
113         "bus error (fetch)",
114         "bus error (data load or store)",
115         "system call",
116         "breakpoint",
117         "reserved instruction",
118         "coprocessor unusable",
119         "arithmetic overflow",
120         "undefined 13",
121         "undefined 14",
122         "system call",
123         /* the following is made up */
124         "floating point exception"              /* FPEXC */
125 };
126
127 static char*
128 mipsexcep(Map *map, Rgetter rget)
129 {
130         int e;
131         long c;
132
133         c = (*rget)(map, "CAUSE");
134         if(c & 0x00002000)      /* INTR3 */
135                 e = 16;         /* Floating point exception */
136         else
137                 e = (c>>2)&0x0F;
138         return excname[e];
139 }
140
141         /* mips disassembler and related functions */
142
143 static  char FRAMENAME[] = ".frame";
144
145 typedef struct {
146         uvlong addr;
147         uchar op;                       /* bits 31-26 */
148         uchar rs;                       /* bits 25-21 */
149         uchar rt;                       /* bits 20-16 */
150         uchar rd;                       /* bits 15-11 */
151         uchar sa;                       /* bits 10-6 */
152         uchar function;                 /* bits 5-0 */
153         long immediate;                 /* bits 15-0 */
154         ulong cofun;                    /* bits 24-0 */
155         ulong target;                   /* bits 25-0 */
156         long w0;
157         long w1;
158         int size;                       /* instruction size */
159         char *curr;                     /* fill point in buffer */
160         char *end;                      /* end of buffer */
161         char *err;                      /* error message */
162 } Instr;
163
164 static Map *mymap;
165
166 static int
167 decode(uvlong pc, Instr *i)
168 {
169         ulong w;
170
171         if (get4(mymap, pc, &w) < 0) {
172                 werrstr("can't read instruction: %r");
173                 return -1;
174         }
175
176         i->addr = pc;
177         i->size = 1;
178         i->op = (w >> 26) & 0x3F;
179         i->rs = (w >> 21) & 0x1F;
180         i->rt = (w >> 16) & 0x1F;
181         i->rd = (w >> 11) & 0x1F;
182         i->sa = (w >> 6) & 0x1F;
183         i->function = w & 0x3F;
184         i->immediate = w & 0x0000FFFF;
185         if (i->immediate & 0x8000)
186                 i->immediate |= ~0x0000FFFF;
187         i->cofun = w & 0x01FFFFFF;
188         i->target = w & 0x03FFFFFF;
189         i->w0 = w;
190         return 1;
191 }
192
193 static int
194 mkinstr(uvlong pc, Instr *i)
195 {
196         Instr x;
197
198         if (decode(pc, i) < 0)
199                 return -1;
200         /*
201          * if it's a LUI followed by an ORI,
202          * it's an immediate load of a large constant.
203          * fix the LUI immediate in any case.
204          */
205         if (i->op == 0x0F) {
206                 if (decode(pc+4, &x) < 0)
207                         return 0;
208                 i->immediate <<= 16;
209                 if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
210                         i->immediate |= (x.immediate & 0xFFFF);
211                         i->w1 = x.w0;
212                         i->size++;
213                         return 1;
214                 }
215         }
216         /*
217          * if it's a LWC1 followed by another LWC1
218          * into an adjacent register, it's a load of
219          * a floating point double.
220          */
221         else if (i->op == 0x31 && (i->rt & 0x01)) {
222                 if (decode(pc+4, &x) < 0)
223                         return 0;
224                 if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
225                         i->rt -= 1;
226                         i->w1 = x.w0;
227                         i->size++;
228                         return 1;
229                 }
230         }
231         /*
232          * similarly for double stores
233          */
234         else if (i->op == 0x39 && (i->rt & 0x01)) {
235                 if (decode(pc+4, &x) < 0)
236                         return 0;
237                 if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
238                         i->rt -= 1;
239                         i->w1 = x.w0;
240                         i->size++;
241                 }
242         }
243         return 1;
244 }
245
246 #pragma varargck        argpos  bprint          2
247
248 static void
249 bprint(Instr *i, char *fmt, ...)
250 {
251         va_list arg;
252
253         va_start(arg, fmt);
254         i->curr = vseprint(i->curr, i->end, fmt, arg);
255         va_end(arg);
256 }
257
258 typedef struct Opcode Opcode;
259
260 struct Opcode {
261         char *mnemonic;
262         void (*f)(Opcode *, Instr *);
263         char *ken;
264 };
265
266 static void format(char *, Instr *, char *);
267
268 static void
269 branch(Opcode *o, Instr *i)
270 {
271         if (i->rs == 0 && i->rt == 0)
272                 format("JMP", i, "%b");
273         else if (i->rs == 0)
274                 format(o->mnemonic, i, "R%t,%b");
275         else if (i->rt < 2)
276                 format(o->mnemonic, i, "R%s,%b");
277         else
278                 format(o->mnemonic, i, "R%s,R%t,%b");
279 }
280
281 static void
282 addi(Opcode *o, Instr *i)
283 {
284         if (i->rs == i->rt)
285                 format(o->mnemonic, i, "%i,R%t");
286         else if (i->rs == 0)
287                 format("MOVW", i, "%i,R%t");
288         else if (i->rs == 30) {
289                 bprint(i, "MOVW\t$");
290                 i->curr += symoff(i->curr, i->end-i->curr,
291                                         i->immediate+mach->sb, CANY);
292                 bprint(i, "(SB),R%d", i->rt);
293         }
294         else
295                 format(o->mnemonic, i, o->ken);
296 }
297
298 static void
299 andi(Opcode *o, Instr *i)
300 {
301         if (i->rs == i->rt)
302                 format(o->mnemonic, i, "%i,R%t");
303         else
304                 format(o->mnemonic, i, o->ken);
305 }
306
307 static int
308 plocal(Instr *i, char *m, char r, int store)
309 {
310         int offset;
311         char *reg;
312         Symbol s;
313
314         if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
315                 return 0;
316         if (s.value > i->immediate) {
317                 if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
318                         return 0;
319                 reg = "(SP)";
320                 offset = i->immediate;
321         } else {
322                 offset = i->immediate-s.value;
323                 if (!getauto(&s, offset-4, CPARAM, &s))
324                         return 0;
325                 reg = "(FP)";
326         }
327         if (store)
328                 bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
329         else
330                 bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
331         return 1;
332 }
333
334 static void
335 lw(Opcode *o, Instr *i, char r)
336 {
337         char *m;
338
339         if (r == 'F') {
340                 if (i->size == 2)
341                         m = "MOVD";
342                 else
343                         m = "MOVF";
344         }
345         else
346                 m = o->mnemonic;
347         if (i->rs == 29 && plocal(i, m, r, 0))
348                         return;
349
350         if (i->rs == 30 && mach->sb) {
351                 bprint(i, "%s\t", m);
352                 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
353                 bprint(i, "(SB),%c%d", r, i->rt);
354                 return;
355         }
356         if (r == 'F')
357                 format(m, i, "%l,F%t");
358         else
359                 format(m, i, o->ken);
360 }
361
362 static void
363 load(Opcode *o, Instr *i)
364 {
365         lw(o, i, 'R');
366 }
367
368 static void
369 lwc1(Opcode *o, Instr *i)
370 {
371         lw(o, i, 'F');
372 }
373
374 static void
375 sw(Opcode *o, Instr *i, char r)
376 {
377         char *m;
378
379         if (r == 'F') {
380                 if (i->size == 2)
381                         m = "MOVD";
382                 else
383                         m = "MOVF";
384         }
385         else
386                 m = o->mnemonic;
387         if (i->rs == 29 && plocal(i, m, r, 1))
388                         return;
389
390         if (i->rs == 30 && mach->sb) {
391                 bprint(i, "%s\t%c%d,", m, r, i->rt);
392                 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
393                 bprint(i, "(SB)");
394                 return;
395         }
396         if (r == 'F')
397                 format(m, i, "F%t,%l");
398         else
399                 format(m, i, o->ken);
400 }
401
402 static void
403 store(Opcode *o, Instr *i)
404 {
405         sw(o, i, 'R');
406 }
407
408 static void
409 swc1(Opcode *o, Instr *i)
410 {
411         sw(o, i, 'F');
412 }
413
414 static void
415 sll(Opcode *o, Instr *i)
416 {
417         if (i->w0 == 0)
418                 bprint(i, "NOOP");      /* unofficial nop */
419         else if (i->w0 == 0xc0)         /* 0xc0: SLL $3,R0 */
420                 bprint(i, "EHB");
421         else if (i->rd == i->rt)
422                 format(o->mnemonic, i, "$%a,R%d");
423         else
424                 format(o->mnemonic, i, o->ken);
425 }
426
427 static void
428 sl32(Opcode *o, Instr *i)
429 {
430         i->sa += 32;
431         if (i->rd == i->rt)
432                 format(o->mnemonic, i, "$%a,R%d");
433         else
434                 format(o->mnemonic, i, o->ken);
435 }
436
437 static void
438 sllv(Opcode *o, Instr *i)
439 {
440         if (i->rd == i->rt)
441                 format(o->mnemonic, i, "R%s,R%d");
442         else
443                 format(o->mnemonic, i, o->ken);
444 }
445
446 static void
447 jal(Opcode *o, Instr *i)
448 {
449         if (i->rd == 31)
450                 format("JAL", i, "(R%s)");
451         else
452                 format(o->mnemonic, i, o->ken);
453 }
454
455 static void
456 add(Opcode *o, Instr *i)
457 {
458         if (i->rd == i->rs)
459                 format(o->mnemonic, i, "R%t,R%d");
460         else if (i->rd == i->rt)
461                 format(o->mnemonic, i, "R%s,R%d");
462         else
463                 format(o->mnemonic, i, o->ken);
464 }
465
466 static void
467 sub(Opcode *o, Instr *i)
468 {
469         if (i->rd == i->rs)
470                 format(o->mnemonic, i, "R%t,R%d");
471         else
472                 format(o->mnemonic, i, o->ken);
473 }
474
475 static void
476 or(Opcode *o, Instr *i)
477 {
478         if (i->rs == 0 && i->rt == 0)
479                 format("MOVW", i, "$0,R%d");
480         else if (i->rs == 0)
481                 format("MOVW", i, "R%t,R%d");
482         else if (i->rt == 0)
483                 format("MOVW", i, "R%s,R%d");
484         else
485                 add(o, i);
486 }
487
488 static void
489 nor(Opcode *o, Instr *i)
490 {
491         if (i->rs == 0 && i->rt == 0 && i->rd == 0)
492                 format("NOP", i, 0);
493         else
494                 add(o, i);
495 }
496
497 static char mipscoload[] = "r%t,%l";
498 static char mipsload[] = "%l,R%t";
499 static char mipsstore[] = "R%t,%l";
500 static char mipsalui[] = "%i,R%s,R%t";
501 static char mipsalu3op[] = "R%t,R%s,R%d";
502 static char mipsrtrs[] = "R%t,R%s";
503 static char mipscorsrt[] = "r%s,r%t";
504 static char mipscorsi[] = "r%s,%i";
505 static char mipscoxxx[] = "%w";
506 static char mipscofp3[] = "f%a,f%d,f%t";        /* fd,fs,ft */
507 static char mipsfp3[] = "F%t,F%d,F%a";
508 static char mipscofp2[] = "f%a,f%d";            /* fd,fs */
509 static char mipsfp2[] = "F%d,F%a";
510 static char mipscofpc[] = "f%d,f%t";            /* fs,ft */
511 static char mipsfpc[] = "F%t,F%d";
512
513 static Opcode opcodes[64] = {
514         0,              0,      0,
515         0,              0,      0,
516         "JMP",          0,      "%j",
517         "JAL",          0,      "%j",
518         "BEQ",     branch,      0,
519         "BNE",     branch,      0,
520         "BLEZ",    branch,      0,
521         "BGTZ",    branch,      0,
522         "ADD",       addi,      mipsalui,
523         "ADDU",      addi,      mipsalui,
524         "SGT",          0,      mipsalui,
525         "SGTU",         0,      mipsalui,
526         "AND",       andi,      mipsalui,
527         "OR",        andi,      mipsalui,
528         "XOR",       andi,      mipsalui,
529         "MOVW",         0,      "$%u,R%t",
530         "cop0",         0,      0,
531         "cop1",         0,      0,
532         "cop2",         0,      0,
533         "cop3",         0,      0,
534         "BEQL",    branch,      0,
535         "BNEL",    branch,      0,
536         "BLEZL",   branch,      0,
537         "BGTZL",   branch,      0,
538         "instr18",      0,      mipscoxxx,
539         "instr19",      0,      mipscoxxx,
540         "MOVVL",     load,      mipsload,
541         "MOVVR",     load,      mipsload,
542         "instr1C",      0,      mipscoxxx,
543         "instr1D",      0,      mipscoxxx,
544         "instr1E",      0,      mipscoxxx,
545         "instr1F",      0,      mipscoxxx,
546         "MOVB",      load,      mipsload,
547         "MOVH",      load,      mipsload,
548         "lwl",          0,      mipscoload,
549         "MOVW",      load,      mipsload,
550         "MOVBU",     load,      mipsload,
551         "MOVHU",     load,      mipsload,
552         "lwr",          0,      mipscoload,
553         "instr27",      0,      mipscoxxx,
554         "MOVB",     store,      mipsstore,
555         "MOVH",     store,      mipsstore,
556         "swl",          0,      mipscoload,
557         "MOVW",     store,      mipsstore,
558         "MOVVL",    store,      mipsstore,
559         "MOVVR",    store,      mipsstore,
560         "swr",          0,      mipscoload,
561         "CACHE",        0,      "%C,%l",
562         "ll",           0,      mipscoload,
563         "MOVW",      lwc1,      mipscoload,
564         "lwc2",         0,      mipscoload,
565         "lwc3",         0,      mipscoload,
566         "instr34",      0,      mipscoxxx,
567         "ldc1",         0,      mipscoload,
568         "ldc2",         0,      mipscoload,
569         "MOVV",     load,       mipsload,
570         "sc",           0,      mipscoload,
571         "swc1",      swc1,      mipscoload,
572         "swc2",         0,      mipscoload,
573         "swc3",         0,      mipscoload,
574         "instr3C",      0,      mipscoxxx,
575         "sdc1",         0,      mipscoload,
576         "sdc2",         0,      mipscoload,
577         "MOVV",     store,      mipsstore,
578 };
579
580 static Opcode sopcodes[64] = {
581         "SLL",        sll,      "$%a,R%t,R%d",
582         "special01",    0,      mipscoxxx,
583         "SRL",        sll,      "$%a,R%t,R%d",
584         "SRA",        sll,      "$%a,R%t,R%d",
585         "SLL",       sllv,      "R%s,R%t,R%d",
586         "special05",    0,      mipscoxxx,
587         "SRL",       sllv,      "R%s,R%t,R%d",
588         "SRA",       sllv,      "R%s,R%t,R%d",
589         "JMP",          0,      "(R%s)",
590         "jal",        jal,      "r%d,r%s",
591         "special0A",    0,      mipscoxxx,
592         "special0B",    0,      mipscoxxx,
593         "SYSCALL",      0,      0,
594         "BREAK",        0,      0,
595         "special0E",    0,      mipscoxxx,
596         "SYNC",         0,      0,
597         "MOVW",         0,      "HI,R%d",
598         "MOVW",         0,      "R%s,HI",
599         "MOVW",         0,      "LO,R%d",
600         "MOVW",         0,      "R%s,LO",
601         "SLLV",      sllv,      "R%s,R%t,R%d",
602         "special15",    0,      mipscoxxx,
603         "SRLV",      sllv,      "R%s,R%t,R%d",
604         "SRAV",      sllv,      "R%s,R%t,R%d",
605         "MUL",          0,      mipsrtrs,
606         "MULU",         0,      mipsrtrs,
607         "DIV",          0,      mipsrtrs,
608         "DIVU",         0,      mipsrtrs,
609         "special1C",    0,      mipscoxxx,
610         "special1D",    0,      mipscoxxx,
611         "DDIV",         0,      "R%s,R%t",
612         "special1F",    0,      mipscoxxx,
613         "ADD",        add,      mipsalu3op,
614         "ADDU",       add,      mipsalu3op,
615         "SUB",        sub,      mipsalu3op,
616         "SUBU",       sub,      mipsalu3op,
617         "AND",        add,      mipsalu3op,
618         "OR",          or,      mipsalu3op,
619         "XOR",        add,      mipsalu3op,
620         "NOR",        nor,      mipsalu3op,
621         "special28",    0,      mipscoxxx,
622         "special29",    0,      mipscoxxx,
623         "SGT",          0,      mipsalu3op,
624         "SGTU",         0,      mipsalu3op,
625         "special2C",    0,      mipscoxxx,
626         "special2D",    0,      mipscoxxx,
627         "special2E",    0,      mipscoxxx,
628         "DSUBU",        0,      "R%s,R%t,R%d",
629         "tge",          0,      mipscorsrt,
630         "tgeu",         0,      mipscorsrt,
631         "tlt",          0,      mipscorsrt,
632         "tltu",         0,      mipscorsrt,
633         "teq",          0,      mipscorsrt,
634         "special35",    0,      mipscoxxx,
635         "tne",          0,      mipscorsrt,
636         "special37",    0,      mipscoxxx,
637         "SLLV",       sll,      "$%a,R%t,R%d",
638         "special39",    0,      mipscoxxx,
639         "SRLV",       sll,      "$%a,R%t,R%d",
640         "SRAV",       sll,      "$%a,R%t,R%d",
641         "SLLV",      sl32,      "$%a,R%t,R%d",
642         "special3D",    0,      mipscoxxx,
643         "SRLV",      sl32,      "$%a,R%t,R%d",
644         "SRAV",      sl32,      "$%a,R%t,R%d",
645 };
646
647 static Opcode ropcodes[32] = {
648         "BLTZ",    branch,      0,
649         "BGEZ",    branch,      0,
650         "BLTZL",   branch,      0,
651         "BGEZL",   branch,      0,
652         "regimm04",     0,      mipscoxxx,
653         "regimm05",     0,      mipscoxxx,
654         "regimm06",     0,      mipscoxxx,
655         "regimm07",     0,      mipscoxxx,
656         "tgei",         0,      mipscorsi,
657         "tgeiu",        0,      mipscorsi,
658         "tlti",         0,      mipscorsi,
659         "tltiu",        0,      mipscorsi,
660         "teqi",         0,      mipscorsi,
661         "regimm0D",     0,      mipscoxxx,
662         "tnei",         0,      mipscorsi,
663         "regimm0F",     0,      mipscoxxx,
664         "BLTZAL",  branch,      0,
665         "BGEZAL",  branch,      0,
666         "BLTZALL", branch,      0,
667         "BGEZALL", branch,      0,
668         "regimm14",     0,      mipscoxxx,
669         "regimm15",     0,      mipscoxxx,
670         "regimm16",     0,      mipscoxxx,
671         "regimm17",     0,      mipscoxxx,
672         "regimm18",     0,      mipscoxxx,
673         "regimm19",     0,      mipscoxxx,
674         "regimm1A",     0,      mipscoxxx,
675         "regimm1B",     0,      mipscoxxx,
676         "regimm1C",     0,      mipscoxxx,
677         "regimm1D",     0,      mipscoxxx,
678         "regimm1E",     0,      mipscoxxx,
679         "regimm1F",     0,      mipscoxxx,
680 };
681
682 static Opcode fopcodes[64] = {
683         "ADD%f",        0,      mipsfp3,
684         "SUB%f",        0,      mipsfp3,
685         "MUL%f",        0,      mipsfp3,
686         "DIV%f",        0,      mipsfp3,
687         "sqrt.%f",      0,      mipscofp2,
688         "ABS%f",        0,      mipsfp2,
689         "MOV%f",        0,      mipsfp2,
690         "NEG%f",        0,      mipsfp2,
691         "finstr08",     0,      mipscoxxx,
692         "finstr09",     0,      mipscoxxx,
693         "finstr0A",     0,      mipscoxxx,
694         "finstr0B",     0,      mipscoxxx,
695         "round.w.%f",   0,      mipscofp2,
696         "trunc.w%f",    0,      mipscofp2,
697         "ceil.w%f",     0,      mipscofp2,
698         "floor.w%f",    0,      mipscofp2,
699         "finstr10",     0,      mipscoxxx,
700         "finstr11",     0,      mipscoxxx,
701         "finstr12",     0,      mipscoxxx,
702         "finstr13",     0,      mipscoxxx,
703         "finstr14",     0,      mipscoxxx,
704         "finstr15",     0,      mipscoxxx,
705         "finstr16",     0,      mipscoxxx,
706         "finstr17",     0,      mipscoxxx,
707         "finstr18",     0,      mipscoxxx,
708         "finstr19",     0,      mipscoxxx,
709         "finstr1A",     0,      mipscoxxx,
710         "finstr1B",     0,      mipscoxxx,
711         "finstr1C",     0,      mipscoxxx,
712         "finstr1D",     0,      mipscoxxx,
713         "finstr1E",     0,      mipscoxxx,
714         "finstr1F",     0,      mipscoxxx,
715         "cvt.s.%f",     0,      mipscofp2,
716         "cvt.d.%f",     0,      mipscofp2,
717         "cvt.e.%f",     0,      mipscofp2,
718         "cvt.q.%f",     0,      mipscofp2,
719         "cvt.w.%f",     0,      mipscofp2,
720         "finstr25",     0,      mipscoxxx,
721         "finstr26",     0,      mipscoxxx,
722         "finstr27",     0,      mipscoxxx,
723         "finstr28",     0,      mipscoxxx,
724         "finstr29",     0,      mipscoxxx,
725         "finstr2A",     0,      mipscoxxx,
726         "finstr2B",     0,      mipscoxxx,
727         "finstr2C",     0,      mipscoxxx,
728         "finstr2D",     0,      mipscoxxx,
729         "finstr2E",     0,      mipscoxxx,
730         "finstr2F",     0,      mipscoxxx,
731         "c.f.%f",       0,      mipscofpc,
732         "c.un.%f",      0,      mipscofpc,
733         "CMPEQ%f",      0,      mipsfpc,
734         "c.ueq.%f",     0,      mipscofpc,
735         "c.olt.%f",     0,      mipscofpc,
736         "c.ult.%f",     0,      mipscofpc,
737         "c.ole.%f",     0,      mipscofpc,
738         "c.ule.%f",     0,      mipscofpc,
739         "c.sf.%f",      0,      mipscofpc,
740         "c.ngle.%f",    0,      mipscofpc,
741         "c.seq.%f",     0,      mipscofpc,
742         "c.ngl.%f",     0,      mipscofpc,
743         "CMPGT%f",      0,      mipsfpc,
744         "c.nge.%f",     0,      mipscofpc,
745         "CMPGE%f",      0,      mipsfpc,
746         "c.ngt.%f",     0,      mipscofpc,
747 };
748
749 static char *cop0regs[32] = {
750         "INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
751         "CONTEXT", "PageMask", "Wired", "Error",
752         "BADVADDR", "Count", "TLBVIRT", "Compare",
753         "STATUS", "CAUSE", "EPC", "PRID",
754         "Config", "LLadr", "WatchLo", "WatchHi",
755         "20", "21", "22", "23",
756         "24", "25", "26", "CacheErr",
757         "TagLo", "TagHi", "ErrorEPC", "31"
758 };
759
760 static char fsub[16] = {
761         'F', 'D', 'e', 'q', 'W', '?', '?', '?',
762         '?', '?', '?', '?', '?', '?', '?', '?'
763 };
764
765 static char *cacheps[] = {
766         "I", "D", "SI", "SD"
767 };
768
769 static char *cacheop[] = {
770         "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
771 };
772
773 static void
774 format(char *mnemonic, Instr *i, char *f)
775 {
776         if (mnemonic)
777                 format(0, i, mnemonic);
778         if (f == 0)
779                 return;
780         if (mnemonic)
781                 if (i->curr < i->end)
782                         *i->curr++ = '\t';
783         for ( ; *f && i->curr < i->end; f++) {
784                 if (*f != '%') {
785                         *i->curr++ = *f;
786                         continue;
787                 }
788                 switch (*++f) {
789
790                 case 's':
791                         bprint(i, "%d", i->rs);
792                         break;
793
794                 case 't':
795                         bprint(i, "%d", i->rt);
796                         break;
797
798                 case 'd':
799                         bprint(i, "%d", i->rd);
800                         break;
801
802                 case 'a':
803                         bprint(i, "%d", i->sa);
804                         break;
805
806                 case 'l':
807                         bprint(i, "%lx(R%d)",i->immediate, i->rs);
808                         break;
809
810                 case 'i':
811                         bprint(i, "$%lx", i->immediate);
812                         break;
813
814                 case 'u':
815                         i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
816                         bprint(i, "(SB)");
817                         break;
818
819                 case 'j':
820                         i->curr += symoff(i->curr, i->end-i->curr,
821                                 (i->target<<2)|(i->addr & 0xF0000000), CANY);
822                         bprint(i, "(SB)");
823                         break;
824
825                 case 'b':
826                         i->curr += symoff(i->curr, i->end-i->curr,
827                                 (i->immediate<<2)+i->addr+4, CANY);
828                         break;
829
830                 case 'c':
831                         bprint(i, "$%lx", i->cofun);
832                         break;
833
834                 case 'w':
835                         bprint(i, "[%lux]", i->w0);
836                         break;
837
838                 case 'm':
839                         if(i->function != 0)
840                                 bprint(i, "M(%s),%d", cop0regs[i->rd], i->function);
841                         else
842                                 bprint(i, "M(%s)", cop0regs[i->rd]);
843                         break;
844
845                 case 'f':
846                         *i->curr++ = fsub[i->rs & 0x0F];
847                         break;
848
849                 case 'C':
850                         bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
851                         break;
852
853                 case '\0':
854                         *i->curr++ = '%';
855                         return;
856
857                 default:
858                         bprint(i, "%%%c", *f);
859                         break;
860                 }
861         }
862         *i->curr = 0;
863 }
864
865 static void
866 copz(int cop, Instr *i)
867 {
868         char *f, *m, buf[16];
869
870         m = buf;
871         f = "%t,%d";
872         switch (i->rs) {
873
874         case 0:
875                 sprint(buf, "mfc%d", cop);
876                 break;
877
878         case 2:
879                 sprint(buf, "cfc%d", cop);
880                 break;
881
882         case 4:
883                 sprint(buf, "mtc%d", cop);
884                 break;
885
886         case 6:
887                 sprint(buf, "ctc%d", cop);
888                 break;
889
890         case 8:
891                 f = "%b";
892                 switch (i->rt) {
893
894                 case 0:
895                         sprint(buf, "bc%df", cop);
896                         break;
897
898                 case 1:
899                         sprint(buf, "bc%dt", cop);
900                         break;
901
902                 case 2:
903                         sprint(buf, "bc%dfl", cop);
904                         break;
905
906                 case 3:
907                         sprint(buf, "bc%dtl", cop);
908                         break;
909
910                 default:
911                         sprint(buf, "cop%d", cop);
912                         f = mipscoxxx;
913                         break;
914                 }
915                 break;
916
917         default:
918                 sprint(buf, "cop%d", cop);
919                 if (i->rs & 0x10)
920                         f = "function %c";
921                 else
922                         f = mipscoxxx;
923                 break;
924         }
925         format(m, i, f);
926 }
927
928 static void
929 cop0(Instr *i)
930 {
931         char *m = 0;
932
933         if (i->rs < 8) {
934                 switch (i->rs) {
935
936                 case 0:
937                 case 1:
938                         format("MOVW", i, "%m,R%t");
939                         return;
940
941                 case 4:
942                 case 5:
943                         format("MOVW", i, "R%t,%m");
944                         return;
945                 }
946         }
947         else if (i->rs >= 0x10) {
948                 switch (i->cofun) {
949         
950                 case 1:
951                         m = "TLBR";
952                         break;
953         
954                 case 2:
955                         m = "TLBWI";
956                         break;
957         
958                 case 6:
959                         m = "TLBWR";
960                         break;
961         
962                 case 8:
963                         m = "TLBP";
964                         break;
965         
966                 case 16:
967                         m = "RFE";
968                         break;
969         
970                 case 24:
971                         m = "ERET";
972                         break;
973
974                 case 32:
975                         m = "WAIT";
976                         break;
977                 }
978                 if (m) {
979                         format(m, i, 0);
980                         return;
981                 }
982         }
983         copz(0, i);
984 }
985
986 static void
987 cop1(Instr *i)
988 {
989         char *m = "MOVW";
990
991         switch (i->rs) {
992
993         case 0:
994                 format(m, i, "F%d,R%t");
995                 return;
996
997         case 2:
998                 format(m, i, "FCR%d,R%t");
999                 return;
1000
1001         case 4:
1002                 format(m, i, "R%t,F%d");
1003                 return;
1004
1005         case 6:
1006                 format(m, i, "R%t,FCR%d");
1007                 return;
1008
1009         case 8:
1010                 switch (i->rt) {
1011
1012                 case 0:
1013                         format("BFPF", i, "%b");
1014                         return;
1015
1016                 case 1:
1017                         format("BFPT", i, "%b");
1018                         return;
1019                 }
1020                 break;
1021         }
1022         copz(1, i);
1023 }
1024
1025 static int
1026 printins(Map *map, uvlong pc, char *buf, int n)
1027 {
1028         Instr i;
1029         Opcode *o;
1030         uchar op;
1031
1032         i.curr = buf;
1033         i.end = buf+n-1;
1034         mymap = map;
1035         if (mkinstr(pc, &i) < 0)
1036                 return -1;
1037         switch (i.op) {
1038
1039         case 0x00:                                      /* SPECIAL */
1040                 o = sopcodes;
1041                 op = i.function;
1042                 break;
1043
1044         case 0x01:                                      /* REGIMM */
1045                 o = ropcodes;
1046                 op = i.rt;
1047                 break;
1048
1049         case 0x10:                                      /* COP0 */
1050                 cop0(&i);
1051                 return i.size*4;
1052
1053         case 0x11:                                      /* COP1 */
1054                 if (i.rs & 0x10) {
1055                         o = fopcodes;
1056                         op = i.function;
1057                         break;
1058                 }
1059                 cop1(&i);
1060                 return i.size*4;
1061
1062         case 0x12:                                      /* COP2 */
1063         case 0x13:                                      /* COP3 */
1064                 copz(i.op-0x10, &i);
1065                 return i.size*4;
1066
1067         default:
1068                 o = opcodes;
1069                 op = i.op;
1070                 break;
1071         }
1072         if (o[op].f)
1073                 (*o[op].f)(&o[op], &i);
1074         else
1075                 format(o[op].mnemonic, &i, o[op].ken);
1076         return i.size*4;
1077 }
1078
1079 extern  int     _mipscoinst(Map *, uvlong, char*, int);
1080
1081         /* modifier 'I' toggles the default disassembler type */
1082 static int
1083 mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1084 {
1085         if ((asstype == AMIPSCO && modifier == 'i')
1086                 || (asstype == AMIPS && modifier == 'I'))
1087                 return _mipscoinst(map, pc, buf, n);
1088         else
1089                 return printins(map, pc, buf, n);
1090 }
1091
1092 static int
1093 mipsdas(Map *map, uvlong pc, char *buf, int n)
1094 {
1095         Instr i;
1096
1097         i.curr = buf;
1098         i.end = buf+n;
1099         mymap = map;
1100         if (mkinstr(pc, &i) < 0)
1101                 return -1;
1102         if (i.end-i.curr > 8)
1103                 i.curr = _hexify(buf, i.w0, 7);
1104         if (i.size == 2 && i.end-i.curr > 9) {
1105                 *i.curr++ = ' ';
1106                 i.curr = _hexify(i.curr, i.w1, 7);
1107         }
1108         *i.curr = 0;
1109         return i.size*4;
1110 }
1111
1112 static int
1113 mipsinstlen(Map *map, uvlong pc)
1114 {
1115         Instr i;
1116
1117         mymap = map;
1118         if (mkinstr(pc, &i) < 0)
1119                 return -1;
1120         return i.size*4;
1121 }
1122
1123 static int
1124 mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1125 {
1126         ulong w, l;
1127         char buf[8];
1128         Instr i;
1129
1130         mymap = map;
1131         if (mkinstr(pc, &i) < 0)
1132                 return -1;
1133         w = i.w0;
1134         if((w&0xF3600000) == 0x41000000){       /* branch on coprocessor */
1135     Conditional:
1136                 foll[0] = pc+8;
1137                 l = ((w&0xFFFF)<<2);
1138                 if(w & 0x8000)
1139                         l |= 0xFFFC0000;
1140                 foll[1] = pc+4 + l;
1141                 return 2;
1142         }
1143
1144         l = (w&0xFC000000)>>26;
1145         switch(l){
1146         case 0:         /* SPECIAL */
1147                 if((w&0x3E) == 0x08){   /* JR, JALR */
1148                         sprint(buf, "R%ld", (w>>21)&0x1F);
1149                         foll[0] = (*rget)(map, buf);
1150                         return 1;
1151                 }
1152                 foll[0] = pc+i.size*4;
1153                 return 1;
1154         case 0x30:      /* Load-Linked followed by NOP, STC */
1155                 foll[0] = pc+12;
1156                 return 1;
1157         case 1:         /* BCOND */
1158         case 4:         /* BEQ */
1159         case 20:        /* BEQL */
1160         case 5:         /* BNE */
1161         case 21:        /* BNEL */
1162         case 6:         /* BLEZ */
1163         case 22:        /* BLEZL */
1164         case 7:         /* BGTZ */
1165         case 23:        /* BGTZL */
1166                 goto Conditional;
1167         case 2:         /* J */
1168         case 3:         /* JAL */
1169                 foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1170                 return 1;
1171         }
1172
1173         foll[0] = pc+i.size*4;
1174         return 1;
1175 }