]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/vdb.c
merge
[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         {0, 0, 0, 0xD},         /* 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         {0, 0, 0, 0xD},         /* 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");
419         else if (i->rd == i->rt)
420                 format(o->mnemonic, i, "$%a,R%d");
421         else
422                 format(o->mnemonic, i, o->ken);
423 }
424
425 static void
426 sl32(Opcode *o, Instr *i)
427 {
428         i->sa += 32;
429         if (i->rd == i->rt)
430                 format(o->mnemonic, i, "$%a,R%d");
431         else
432                 format(o->mnemonic, i, o->ken);
433 }
434
435 static void
436 sllv(Opcode *o, Instr *i)
437 {
438         if (i->rd == i->rt)
439                 format(o->mnemonic, i, "R%s,R%d");
440         else
441                 format(o->mnemonic, i, o->ken);
442 }
443
444 static void
445 jal(Opcode *o, Instr *i)
446 {
447         if (i->rd == 31)
448                 format("JAL", i, "(R%s)");
449         else
450                 format(o->mnemonic, i, o->ken);
451 }
452
453 static void
454 add(Opcode *o, Instr *i)
455 {
456         if (i->rd == i->rs)
457                 format(o->mnemonic, i, "R%t,R%d");
458         else if (i->rd == i->rt)
459                 format(o->mnemonic, i, "R%s,R%d");
460         else
461                 format(o->mnemonic, i, o->ken);
462 }
463
464 static void
465 sub(Opcode *o, Instr *i)
466 {
467         if (i->rd == i->rs)
468                 format(o->mnemonic, i, "R%t,R%d");
469         else
470                 format(o->mnemonic, i, o->ken);
471 }
472
473 static void
474 or(Opcode *o, Instr *i)
475 {
476         if (i->rs == 0 && i->rt == 0)
477                 format("MOVW", i, "$0,R%d");
478         else if (i->rs == 0)
479                 format("MOVW", i, "R%t,R%d");
480         else if (i->rt == 0)
481                 format("MOVW", i, "R%s,R%d");
482         else
483                 add(o, i);
484 }
485
486 static void
487 nor(Opcode *o, Instr *i)
488 {
489         if (i->rs == 0 && i->rt == 0 && i->rd == 0)
490                 format("NOP", i, 0);
491         else
492                 add(o, i);
493 }
494
495 static char mipscoload[] = "r%t,%l";
496 static char mipsload[] = "%l,R%t";
497 static char mipsstore[] = "R%t,%l";
498 static char mipsalui[] = "%i,R%s,R%t";
499 static char mipsalu3op[] = "R%t,R%s,R%d";
500 static char mipsrtrs[] = "R%t,R%s";
501 static char mipscorsrt[] = "r%s,r%t";
502 static char mipscorsi[] = "r%s,%i";
503 static char mipscoxxx[] = "%w";
504 static char mipscofp3[] = "f%a,f%d,f%t";        /* fd,fs,ft */
505 static char mipsfp3[] = "F%t,F%d,F%a";
506 static char mipscofp2[] = "f%a,f%d";            /* fd,fs */
507 static char mipsfp2[] = "F%d,F%a";
508 static char mipscofpc[] = "f%d,f%t";            /* fs,ft */
509 static char mipsfpc[] = "F%t,F%d";
510
511 static Opcode opcodes[64] = {
512         0,              0,      0,
513         0,              0,      0,
514         "JMP",          0,      "%j",
515         "JAL",          0,      "%j",
516         "BEQ",     branch,      0,
517         "BNE",     branch,      0,
518         "BLEZ",    branch,      0,
519         "BGTZ",    branch,      0,
520         "ADD",       addi,      mipsalui,
521         "ADDU",      addi,      mipsalui,
522         "SGT",          0,      mipsalui,
523         "SGTU",         0,      mipsalui,
524         "AND",       andi,      mipsalui,
525         "OR",        andi,      mipsalui,
526         "XOR",       andi,      mipsalui,
527         "MOVW",         0,      "$%u,R%t",
528         "cop0",         0,      0,
529         "cop1",         0,      0,
530         "cop2",         0,      0,
531         "cop3",         0,      0,
532         "BEQL",    branch,      0,
533         "BNEL",    branch,      0,
534         "BLEZL",   branch,      0,
535         "BGTZL",   branch,      0,
536         "instr18",      0,      mipscoxxx,
537         "instr19",      0,      mipscoxxx,
538         "MOVVL",     load,      mipsload,
539         "MOVVR",     load,      mipsload,
540         "instr1C",      0,      mipscoxxx,
541         "instr1D",      0,      mipscoxxx,
542         "instr1E",      0,      mipscoxxx,
543         "instr1F",      0,      mipscoxxx,
544         "MOVB",      load,      mipsload,
545         "MOVH",      load,      mipsload,
546         "lwl",          0,      mipscoload,
547         "MOVW",      load,      mipsload,
548         "MOVBU",     load,      mipsload,
549         "MOVHU",     load,      mipsload,
550         "lwr",          0,      mipscoload,
551         "instr27",      0,      mipscoxxx,
552         "MOVB",     store,      mipsstore,
553         "MOVH",     store,      mipsstore,
554         "swl",          0,      mipscoload,
555         "MOVW",     store,      mipsstore,
556         "MOVVL",    store,      mipsstore,
557         "MOVVR",    store,      mipsstore,
558         "swr",          0,      mipscoload,
559         "CACHE",        0,      "%C,%l",
560         "ll",           0,      mipscoload,
561         "MOVW",      lwc1,      mipscoload,
562         "lwc2",         0,      mipscoload,
563         "lwc3",         0,      mipscoload,
564         "instr34",      0,      mipscoxxx,
565         "ldc1",         0,      mipscoload,
566         "ldc2",         0,      mipscoload,
567         "MOVV",     load,       mipsload,
568         "sc",           0,      mipscoload,
569         "swc1",      swc1,      mipscoload,
570         "swc2",         0,      mipscoload,
571         "swc3",         0,      mipscoload,
572         "instr3C",      0,      mipscoxxx,
573         "sdc1",         0,      mipscoload,
574         "sdc2",         0,      mipscoload,
575         "MOVV",     store,      mipsstore,
576 };
577
578 static Opcode sopcodes[64] = {
579         "SLL",        sll,      "$%a,R%t,R%d",
580         "special01",    0,      mipscoxxx,
581         "SRL",        sll,      "$%a,R%t,R%d",
582         "SRA",        sll,      "$%a,R%t,R%d",
583         "SLL",       sllv,      "R%s,R%t,R%d",
584         "special05",    0,      mipscoxxx,
585         "SRL",       sllv,      "R%s,R%t,R%d",
586         "SRA",       sllv,      "R%s,R%t,R%d",
587         "JMP",          0,      "(R%s)",
588         "jal",        jal,      "r%d,r%s",
589         "special0A",    0,      mipscoxxx,
590         "special0B",    0,      mipscoxxx,
591         "SYSCALL",      0,      0,
592         "BREAK",        0,      0,
593         "special0E",    0,      mipscoxxx,
594         "SYNC",         0,      0,
595         "MOVW",         0,      "HI,R%d",
596         "MOVW",         0,      "R%s,HI",
597         "MOVW",         0,      "LO,R%d",
598         "MOVW",         0,      "R%s,LO",
599         "SLLV",      sllv,      "R%s,R%t,R%d",
600         "special15",    0,      mipscoxxx,
601         "SRLV",      sllv,      "R%s,R%t,R%d",
602         "SRAV",      sllv,      "R%s,R%t,R%d",
603         "MUL",          0,      mipsrtrs,
604         "MULU",         0,      mipsrtrs,
605         "DIV",          0,      mipsrtrs,
606         "DIVU",         0,      mipsrtrs,
607         "special1C",    0,      mipscoxxx,
608         "special1D",    0,      mipscoxxx,
609         "DDIV",         0,      "R%s,R%t",
610         "special1F",    0,      mipscoxxx,
611         "ADD",        add,      mipsalu3op,
612         "ADDU",       add,      mipsalu3op,
613         "SUB",        sub,      mipsalu3op,
614         "SUBU",       sub,      mipsalu3op,
615         "AND",        add,      mipsalu3op,
616         "OR",          or,      mipsalu3op,
617         "XOR",        add,      mipsalu3op,
618         "NOR",        nor,      mipsalu3op,
619         "special28",    0,      mipscoxxx,
620         "special29",    0,      mipscoxxx,
621         "SGT",          0,      mipsalu3op,
622         "SGTU",         0,      mipsalu3op,
623         "special2C",    0,      mipscoxxx,
624         "special2D",    0,      mipscoxxx,
625         "special2E",    0,      mipscoxxx,
626         "DSUBU",        0,      "R%s,R%t,R%d",
627         "tge",          0,      mipscorsrt,
628         "tgeu",         0,      mipscorsrt,
629         "tlt",          0,      mipscorsrt,
630         "tltu",         0,      mipscorsrt,
631         "teq",          0,      mipscorsrt,
632         "special35",    0,      mipscoxxx,
633         "tne",          0,      mipscorsrt,
634         "special37",    0,      mipscoxxx,
635         "SLLV",       sll,      "$%a,R%t,R%d",
636         "special39",    0,      mipscoxxx,
637         "SRLV",       sll,      "$%a,R%t,R%d",
638         "SRAV",       sll,      "$%a,R%t,R%d",
639         "SLLV",      sl32,      "$%a,R%t,R%d",
640         "special3D",    0,      mipscoxxx,
641         "SRLV",      sl32,      "$%a,R%t,R%d",
642         "SRAV",      sl32,      "$%a,R%t,R%d",
643 };
644
645 static Opcode ropcodes[32] = {
646         "BLTZ",    branch,      0,
647         "BGEZ",    branch,      0,
648         "BLTZL",   branch,      0,
649         "BGEZL",   branch,      0,
650         "regimm04",     0,      mipscoxxx,
651         "regimm05",     0,      mipscoxxx,
652         "regimm06",     0,      mipscoxxx,
653         "regimm07",     0,      mipscoxxx,
654         "tgei",         0,      mipscorsi,
655         "tgeiu",        0,      mipscorsi,
656         "tlti",         0,      mipscorsi,
657         "tltiu",        0,      mipscorsi,
658         "teqi",         0,      mipscorsi,
659         "regimm0D",     0,      mipscoxxx,
660         "tnei",         0,      mipscorsi,
661         "regimm0F",     0,      mipscoxxx,
662         "BLTZAL",  branch,      0,
663         "BGEZAL",  branch,      0,
664         "BLTZALL", branch,      0,
665         "BGEZALL", branch,      0,
666         "regimm14",     0,      mipscoxxx,
667         "regimm15",     0,      mipscoxxx,
668         "regimm16",     0,      mipscoxxx,
669         "regimm17",     0,      mipscoxxx,
670         "regimm18",     0,      mipscoxxx,
671         "regimm19",     0,      mipscoxxx,
672         "regimm1A",     0,      mipscoxxx,
673         "regimm1B",     0,      mipscoxxx,
674         "regimm1C",     0,      mipscoxxx,
675         "regimm1D",     0,      mipscoxxx,
676         "regimm1E",     0,      mipscoxxx,
677         "regimm1F",     0,      mipscoxxx,
678 };
679
680 static Opcode fopcodes[64] = {
681         "ADD%f",        0,      mipsfp3,
682         "SUB%f",        0,      mipsfp3,
683         "MUL%f",        0,      mipsfp3,
684         "DIV%f",        0,      mipsfp3,
685         "sqrt.%f",      0,      mipscofp2,
686         "ABS%f",        0,      mipsfp2,
687         "MOV%f",        0,      mipsfp2,
688         "NEG%f",        0,      mipsfp2,
689         "finstr08",     0,      mipscoxxx,
690         "finstr09",     0,      mipscoxxx,
691         "finstr0A",     0,      mipscoxxx,
692         "finstr0B",     0,      mipscoxxx,
693         "round.w.%f",   0,      mipscofp2,
694         "trunc.w%f",    0,      mipscofp2,
695         "ceil.w%f",     0,      mipscofp2,
696         "floor.w%f",    0,      mipscofp2,
697         "finstr10",     0,      mipscoxxx,
698         "finstr11",     0,      mipscoxxx,
699         "finstr12",     0,      mipscoxxx,
700         "finstr13",     0,      mipscoxxx,
701         "finstr14",     0,      mipscoxxx,
702         "finstr15",     0,      mipscoxxx,
703         "finstr16",     0,      mipscoxxx,
704         "finstr17",     0,      mipscoxxx,
705         "finstr18",     0,      mipscoxxx,
706         "finstr19",     0,      mipscoxxx,
707         "finstr1A",     0,      mipscoxxx,
708         "finstr1B",     0,      mipscoxxx,
709         "finstr1C",     0,      mipscoxxx,
710         "finstr1D",     0,      mipscoxxx,
711         "finstr1E",     0,      mipscoxxx,
712         "finstr1F",     0,      mipscoxxx,
713         "cvt.s.%f",     0,      mipscofp2,
714         "cvt.d.%f",     0,      mipscofp2,
715         "cvt.e.%f",     0,      mipscofp2,
716         "cvt.q.%f",     0,      mipscofp2,
717         "cvt.w.%f",     0,      mipscofp2,
718         "finstr25",     0,      mipscoxxx,
719         "finstr26",     0,      mipscoxxx,
720         "finstr27",     0,      mipscoxxx,
721         "finstr28",     0,      mipscoxxx,
722         "finstr29",     0,      mipscoxxx,
723         "finstr2A",     0,      mipscoxxx,
724         "finstr2B",     0,      mipscoxxx,
725         "finstr2C",     0,      mipscoxxx,
726         "finstr2D",     0,      mipscoxxx,
727         "finstr2E",     0,      mipscoxxx,
728         "finstr2F",     0,      mipscoxxx,
729         "c.f.%f",       0,      mipscofpc,
730         "c.un.%f",      0,      mipscofpc,
731         "CMPEQ%f",      0,      mipsfpc,
732         "c.ueq.%f",     0,      mipscofpc,
733         "c.olt.%f",     0,      mipscofpc,
734         "c.ult.%f",     0,      mipscofpc,
735         "c.ole.%f",     0,      mipscofpc,
736         "c.ule.%f",     0,      mipscofpc,
737         "c.sf.%f",      0,      mipscofpc,
738         "c.ngle.%f",    0,      mipscofpc,
739         "c.seq.%f",     0,      mipscofpc,
740         "c.ngl.%f",     0,      mipscofpc,
741         "CMPGT%f",      0,      mipsfpc,
742         "c.nge.%f",     0,      mipscofpc,
743         "CMPGE%f",      0,      mipsfpc,
744         "c.ngt.%f",     0,      mipscofpc,
745 };
746
747 static char *cop0regs[32] = {
748         "INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
749         "CONTEXT", "PageMask", "Wired", "Error",
750         "BADVADDR", "Count", "TLBVIRT", "Compare",
751         "STATUS", "CAUSE", "EPC", "PRID",
752         "Config", "LLadr", "WatchLo", "WatchHi",
753         "20", "21", "22", "23",
754         "24", "25", "26", "CacheErr",
755         "TagLo", "TagHi", "ErrorEPC", "31"
756 };
757
758 static char fsub[16] = {
759         'F', 'D', 'e', 'q', 'W', '?', '?', '?',
760         '?', '?', '?', '?', '?', '?', '?', '?'
761 };
762
763 static char *cacheps[] = {
764         "I", "D", "SI", "SD"
765 };
766
767 static char *cacheop[] = {
768         "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
769 };
770
771 static void
772 format(char *mnemonic, Instr *i, char *f)
773 {
774         if (mnemonic)
775                 format(0, i, mnemonic);
776         if (f == 0)
777                 return;
778         if (mnemonic)
779                 if (i->curr < i->end)
780                         *i->curr++ = '\t';
781         for ( ; *f && i->curr < i->end; f++) {
782                 if (*f != '%') {
783                         *i->curr++ = *f;
784                         continue;
785                 }
786                 switch (*++f) {
787
788                 case 's':
789                         bprint(i, "%d", i->rs);
790                         break;
791
792                 case 't':
793                         bprint(i, "%d", i->rt);
794                         break;
795
796                 case 'd':
797                         bprint(i, "%d", i->rd);
798                         break;
799
800                 case 'a':
801                         bprint(i, "%d", i->sa);
802                         break;
803
804                 case 'l':
805                         bprint(i, "%lx(R%d)",i->immediate, i->rs);
806                         break;
807
808                 case 'i':
809                         bprint(i, "$%lx", i->immediate);
810                         break;
811
812                 case 'u':
813                         i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
814                         bprint(i, "(SB)");
815                         break;
816
817                 case 'j':
818                         i->curr += symoff(i->curr, i->end-i->curr,
819                                 (i->target<<2)|(i->addr & 0xF0000000), CANY);
820                         bprint(i, "(SB)");
821                         break;
822
823                 case 'b':
824                         i->curr += symoff(i->curr, i->end-i->curr,
825                                 (i->immediate<<2)+i->addr+4, CANY);
826                         break;
827
828                 case 'c':
829                         bprint(i, "$%lx", i->cofun);
830                         break;
831
832                 case 'w':
833                         bprint(i, "[%lux]", i->w0);
834                         break;
835
836                 case 'm':
837                         bprint(i, "M(%s)", cop0regs[i->rd]);
838                         break;
839
840                 case 'f':
841                         *i->curr++ = fsub[i->rs & 0x0F];
842                         break;
843
844                 case 'C':
845                         bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
846                         break;
847
848                 case '\0':
849                         *i->curr++ = '%';
850                         return;
851
852                 default:
853                         bprint(i, "%%%c", *f);
854                         break;
855                 }
856         }
857         *i->curr = 0;
858 }
859
860 static void
861 copz(int cop, Instr *i)
862 {
863         char *f, *m, buf[16];
864
865         m = buf;
866         f = "%t,%d";
867         switch (i->rs) {
868
869         case 0:
870                 sprint(buf, "mfc%d", cop);
871                 break;
872
873         case 2:
874                 sprint(buf, "cfc%d", cop);
875                 break;
876
877         case 4:
878                 sprint(buf, "mtc%d", cop);
879                 break;
880
881         case 6:
882                 sprint(buf, "ctc%d", cop);
883                 break;
884
885         case 8:
886                 f = "%b";
887                 switch (i->rt) {
888
889                 case 0:
890                         sprint(buf, "bc%df", cop);
891                         break;
892
893                 case 1:
894                         sprint(buf, "bc%dt", cop);
895                         break;
896
897                 case 2:
898                         sprint(buf, "bc%dfl", cop);
899                         break;
900
901                 case 3:
902                         sprint(buf, "bc%dtl", cop);
903                         break;
904
905                 default:
906                         sprint(buf, "cop%d", cop);
907                         f = mipscoxxx;
908                         break;
909                 }
910                 break;
911
912         default:
913                 sprint(buf, "cop%d", cop);
914                 if (i->rs & 0x10)
915                         f = "function %c";
916                 else
917                         f = mipscoxxx;
918                 break;
919         }
920         format(m, i, f);
921 }
922
923 static void
924 cop0(Instr *i)
925 {
926         char *m = 0;
927
928         if (i->rs < 8) {
929                 switch (i->rs) {
930
931                 case 0:
932                 case 1:
933                         format("MOVW", i, "%m,R%t");
934                         return;
935
936                 case 4:
937                 case 5:
938                         format("MOVW", i, "R%t,%m");
939                         return;
940                 }
941         }
942         else if (i->rs >= 0x10) {
943                 switch (i->cofun) {
944         
945                 case 1:
946                         m = "TLBR";
947                         break;
948         
949                 case 2:
950                         m = "TLBWI";
951                         break;
952         
953                 case 6:
954                         m = "TLBWR";
955                         break;
956         
957                 case 8:
958                         m = "TLBP";
959                         break;
960         
961                 case 16:
962                         m = "RFE";
963                         break;
964         
965                 case 32:
966                         m = "ERET";
967                         break;
968                 }
969                 if (m) {
970                         format(m, i, 0);
971                         return;
972                 }
973         }
974         copz(0, i);
975 }
976
977 static void
978 cop1(Instr *i)
979 {
980         char *m = "MOVW";
981
982         switch (i->rs) {
983
984         case 0:
985                 format(m, i, "F%d,R%t");
986                 return;
987
988         case 2:
989                 format(m, i, "FCR%d,R%t");
990                 return;
991
992         case 4:
993                 format(m, i, "R%t,F%d");
994                 return;
995
996         case 6:
997                 format(m, i, "R%t,FCR%d");
998                 return;
999
1000         case 8:
1001                 switch (i->rt) {
1002
1003                 case 0:
1004                         format("BFPF", i, "%b");
1005                         return;
1006
1007                 case 1:
1008                         format("BFPT", i, "%b");
1009                         return;
1010                 }
1011                 break;
1012         }
1013         copz(1, i);
1014 }
1015
1016 static int
1017 printins(Map *map, uvlong pc, char *buf, int n)
1018 {
1019         Instr i;
1020         Opcode *o;
1021         uchar op;
1022
1023         i.curr = buf;
1024         i.end = buf+n-1;
1025         mymap = map;
1026         if (mkinstr(pc, &i) < 0)
1027                 return -1;
1028         switch (i.op) {
1029
1030         case 0x00:                                      /* SPECIAL */
1031                 o = sopcodes;
1032                 op = i.function;
1033                 break;
1034
1035         case 0x01:                                      /* REGIMM */
1036                 o = ropcodes;
1037                 op = i.rt;
1038                 break;
1039
1040         case 0x10:                                      /* COP0 */
1041                 cop0(&i);
1042                 return i.size*4;
1043
1044         case 0x11:                                      /* COP1 */
1045                 if (i.rs & 0x10) {
1046                         o = fopcodes;
1047                         op = i.function;
1048                         break;
1049                 }
1050                 cop1(&i);
1051                 return i.size*4;
1052
1053         case 0x12:                                      /* COP2 */
1054         case 0x13:                                      /* COP3 */
1055                 copz(i.op-0x10, &i);
1056                 return i.size*4;
1057
1058         default:
1059                 o = opcodes;
1060                 op = i.op;
1061                 break;
1062         }
1063         if (o[op].f)
1064                 (*o[op].f)(&o[op], &i);
1065         else
1066                 format(o[op].mnemonic, &i, o[op].ken);
1067         return i.size*4;
1068 }
1069
1070 extern  int     _mipscoinst(Map *, uvlong, char*, int);
1071
1072         /* modifier 'I' toggles the default disassembler type */
1073 static int
1074 mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1075 {
1076         if ((asstype == AMIPSCO && modifier == 'i')
1077                 || (asstype == AMIPS && modifier == 'I'))
1078                 return _mipscoinst(map, pc, buf, n);
1079         else
1080                 return printins(map, pc, buf, n);
1081 }
1082
1083 static int
1084 mipsdas(Map *map, uvlong pc, char *buf, int n)
1085 {
1086         Instr i;
1087
1088         i.curr = buf;
1089         i.end = buf+n;
1090         mymap = map;
1091         if (mkinstr(pc, &i) < 0)
1092                 return -1;
1093         if (i.end-i.curr > 8)
1094                 i.curr = _hexify(buf, i.w0, 7);
1095         if (i.size == 2 && i.end-i.curr > 9) {
1096                 *i.curr++ = ' ';
1097                 i.curr = _hexify(i.curr, i.w1, 7);
1098         }
1099         *i.curr = 0;
1100         return i.size*4;
1101 }
1102
1103 static int
1104 mipsinstlen(Map *map, uvlong pc)
1105 {
1106         Instr i;
1107
1108         mymap = map;
1109         if (mkinstr(pc, &i) < 0)
1110                 return -1;
1111         return i.size*4;
1112 }
1113
1114 static int
1115 mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1116 {
1117         ulong w, l;
1118         char buf[8];
1119         Instr i;
1120
1121         mymap = map;
1122         if (mkinstr(pc, &i) < 0)
1123                 return -1;
1124         w = i.w0;
1125         if((w&0xF3600000) == 0x41000000){       /* branch on coprocessor */
1126     Conditional:
1127                 foll[0] = pc+8;
1128                 l = ((w&0xFFFF)<<2);
1129                 if(w & 0x8000)
1130                         l |= 0xFFFC0000;
1131                 foll[1] = pc+4 + l;
1132                 return 2;
1133         }
1134
1135         l = (w&0xFC000000)>>26;
1136         switch(l){
1137         case 0:         /* SPECIAL */
1138                 if((w&0x3E) == 0x08){   /* JR, JALR */
1139                         sprint(buf, "R%ld", (w>>21)&0x1F);
1140                         foll[0] = (*rget)(map, buf);
1141                         return 1;
1142                 }
1143                 foll[0] = pc+i.size*4;
1144                 return 1;
1145         case 0x30:      /* Load-Linked followed by NOP, STC */
1146                 foll[0] = pc+12;
1147                 return 1;
1148         case 1:         /* BCOND */
1149         case 4:         /* BEQ */
1150         case 20:        /* BEQL */
1151         case 5:         /* BNE */
1152         case 21:        /* BNEL */
1153         case 6:         /* BLEZ */
1154         case 22:        /* BLEZL */
1155         case 7:         /* BGTZ */
1156         case 23:        /* BGTZL */
1157                 goto Conditional;
1158         case 2:         /* J */
1159         case 3:         /* JAL */
1160                 foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1161                 return 1;
1162         }
1163
1164         foll[0] = pc+i.size*4;
1165         return 1;
1166 }