]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/vdb.c
6001813c18893f7decf97a4be64351a0909410f5
[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                         bprint(i, "M(%s)", cop0regs[i->rd]);
840                         break;
841
842                 case 'f':
843                         *i->curr++ = fsub[i->rs & 0x0F];
844                         break;
845
846                 case 'C':
847                         bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
848                         break;
849
850                 case '\0':
851                         *i->curr++ = '%';
852                         return;
853
854                 default:
855                         bprint(i, "%%%c", *f);
856                         break;
857                 }
858         }
859         *i->curr = 0;
860 }
861
862 static void
863 copz(int cop, Instr *i)
864 {
865         char *f, *m, buf[16];
866
867         m = buf;
868         f = "%t,%d";
869         switch (i->rs) {
870
871         case 0:
872                 sprint(buf, "mfc%d", cop);
873                 break;
874
875         case 2:
876                 sprint(buf, "cfc%d", cop);
877                 break;
878
879         case 4:
880                 sprint(buf, "mtc%d", cop);
881                 break;
882
883         case 6:
884                 sprint(buf, "ctc%d", cop);
885                 break;
886
887         case 8:
888                 f = "%b";
889                 switch (i->rt) {
890
891                 case 0:
892                         sprint(buf, "bc%df", cop);
893                         break;
894
895                 case 1:
896                         sprint(buf, "bc%dt", cop);
897                         break;
898
899                 case 2:
900                         sprint(buf, "bc%dfl", cop);
901                         break;
902
903                 case 3:
904                         sprint(buf, "bc%dtl", cop);
905                         break;
906
907                 default:
908                         sprint(buf, "cop%d", cop);
909                         f = mipscoxxx;
910                         break;
911                 }
912                 break;
913
914         default:
915                 sprint(buf, "cop%d", cop);
916                 if (i->rs & 0x10)
917                         f = "function %c";
918                 else
919                         f = mipscoxxx;
920                 break;
921         }
922         format(m, i, f);
923 }
924
925 static void
926 cop0(Instr *i)
927 {
928         char *m = 0;
929
930         if (i->rs < 8) {
931                 switch (i->rs) {
932
933                 case 0:
934                 case 1:
935                         format("MOVW", i, "%m,R%t");
936                         return;
937
938                 case 4:
939                 case 5:
940                         format("MOVW", i, "R%t,%m");
941                         return;
942                 }
943         }
944         else if (i->rs >= 0x10) {
945                 switch (i->cofun) {
946         
947                 case 1:
948                         m = "TLBR";
949                         break;
950         
951                 case 2:
952                         m = "TLBWI";
953                         break;
954         
955                 case 6:
956                         m = "TLBWR";
957                         break;
958         
959                 case 8:
960                         m = "TLBP";
961                         break;
962         
963                 case 16:
964                         m = "RFE";
965                         break;
966         
967                 case 24:
968                         m = "ERET";
969                         break;
970
971                 case 32:
972                         m = "WAIT";
973                         break;
974                 }
975                 if (m) {
976                         format(m, i, 0);
977                         return;
978                 }
979         }
980         copz(0, i);
981 }
982
983 static void
984 cop1(Instr *i)
985 {
986         char *m = "MOVW";
987
988         switch (i->rs) {
989
990         case 0:
991                 format(m, i, "F%d,R%t");
992                 return;
993
994         case 2:
995                 format(m, i, "FCR%d,R%t");
996                 return;
997
998         case 4:
999                 format(m, i, "R%t,F%d");
1000                 return;
1001
1002         case 6:
1003                 format(m, i, "R%t,FCR%d");
1004                 return;
1005
1006         case 8:
1007                 switch (i->rt) {
1008
1009                 case 0:
1010                         format("BFPF", i, "%b");
1011                         return;
1012
1013                 case 1:
1014                         format("BFPT", i, "%b");
1015                         return;
1016                 }
1017                 break;
1018         }
1019         copz(1, i);
1020 }
1021
1022 static int
1023 printins(Map *map, uvlong pc, char *buf, int n)
1024 {
1025         Instr i;
1026         Opcode *o;
1027         uchar op;
1028
1029         i.curr = buf;
1030         i.end = buf+n-1;
1031         mymap = map;
1032         if (mkinstr(pc, &i) < 0)
1033                 return -1;
1034         switch (i.op) {
1035
1036         case 0x00:                                      /* SPECIAL */
1037                 o = sopcodes;
1038                 op = i.function;
1039                 break;
1040
1041         case 0x01:                                      /* REGIMM */
1042                 o = ropcodes;
1043                 op = i.rt;
1044                 break;
1045
1046         case 0x10:                                      /* COP0 */
1047                 cop0(&i);
1048                 return i.size*4;
1049
1050         case 0x11:                                      /* COP1 */
1051                 if (i.rs & 0x10) {
1052                         o = fopcodes;
1053                         op = i.function;
1054                         break;
1055                 }
1056                 cop1(&i);
1057                 return i.size*4;
1058
1059         case 0x12:                                      /* COP2 */
1060         case 0x13:                                      /* COP3 */
1061                 copz(i.op-0x10, &i);
1062                 return i.size*4;
1063
1064         default:
1065                 o = opcodes;
1066                 op = i.op;
1067                 break;
1068         }
1069         if (o[op].f)
1070                 (*o[op].f)(&o[op], &i);
1071         else
1072                 format(o[op].mnemonic, &i, o[op].ken);
1073         return i.size*4;
1074 }
1075
1076 extern  int     _mipscoinst(Map *, uvlong, char*, int);
1077
1078         /* modifier 'I' toggles the default disassembler type */
1079 static int
1080 mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1081 {
1082         if ((asstype == AMIPSCO && modifier == 'i')
1083                 || (asstype == AMIPS && modifier == 'I'))
1084                 return _mipscoinst(map, pc, buf, n);
1085         else
1086                 return printins(map, pc, buf, n);
1087 }
1088
1089 static int
1090 mipsdas(Map *map, uvlong pc, char *buf, int n)
1091 {
1092         Instr i;
1093
1094         i.curr = buf;
1095         i.end = buf+n;
1096         mymap = map;
1097         if (mkinstr(pc, &i) < 0)
1098                 return -1;
1099         if (i.end-i.curr > 8)
1100                 i.curr = _hexify(buf, i.w0, 7);
1101         if (i.size == 2 && i.end-i.curr > 9) {
1102                 *i.curr++ = ' ';
1103                 i.curr = _hexify(i.curr, i.w1, 7);
1104         }
1105         *i.curr = 0;
1106         return i.size*4;
1107 }
1108
1109 static int
1110 mipsinstlen(Map *map, uvlong pc)
1111 {
1112         Instr i;
1113
1114         mymap = map;
1115         if (mkinstr(pc, &i) < 0)
1116                 return -1;
1117         return i.size*4;
1118 }
1119
1120 static int
1121 mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1122 {
1123         ulong w, l;
1124         char buf[8];
1125         Instr i;
1126
1127         mymap = map;
1128         if (mkinstr(pc, &i) < 0)
1129                 return -1;
1130         w = i.w0;
1131         if((w&0xF3600000) == 0x41000000){       /* branch on coprocessor */
1132     Conditional:
1133                 foll[0] = pc+8;
1134                 l = ((w&0xFFFF)<<2);
1135                 if(w & 0x8000)
1136                         l |= 0xFFFC0000;
1137                 foll[1] = pc+4 + l;
1138                 return 2;
1139         }
1140
1141         l = (w&0xFC000000)>>26;
1142         switch(l){
1143         case 0:         /* SPECIAL */
1144                 if((w&0x3E) == 0x08){   /* JR, JALR */
1145                         sprint(buf, "R%ld", (w>>21)&0x1F);
1146                         foll[0] = (*rget)(map, buf);
1147                         return 1;
1148                 }
1149                 foll[0] = pc+i.size*4;
1150                 return 1;
1151         case 0x30:      /* Load-Linked followed by NOP, STC */
1152                 foll[0] = pc+12;
1153                 return 1;
1154         case 1:         /* BCOND */
1155         case 4:         /* BEQ */
1156         case 20:        /* BEQL */
1157         case 5:         /* BNE */
1158         case 21:        /* BNEL */
1159         case 6:         /* BLEZ */
1160         case 22:        /* BLEZL */
1161         case 7:         /* BGTZ */
1162         case 23:        /* BGTZL */
1163                 goto Conditional;
1164         case 2:         /* J */
1165         case 3:         /* JAL */
1166                 foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1167                 return 1;
1168         }
1169
1170         foll[0] = pc+i.size*4;
1171         return 1;
1172 }