]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/kdb.c
pc: replace duplicated and broken mmu flush code in vunmap()
[plan9front.git] / sys / src / libmach / kdb.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5
6 /*
7  * Sparc-specific debugger interface
8  */
9
10 static  char    *sparcexcep(Map*, Rgetter);
11 static  int     sparcfoll(Map*, uvlong, Rgetter, uvlong*);
12 static  int     sparcinst(Map*, uvlong, char, char*, int);
13 static  int     sparcdas(Map*, uvlong, char*, int);
14 static  int     sparcinstlen(Map*, uvlong);
15
16 Machdata sparcmach =
17 {
18         {0x91, 0xd0, 0x20, 0x01},       /* breakpoint: TA $1 */
19         4,                      /* break point size */
20
21         beswab,                 /* convert short to local byte order */
22         beswal,                 /* convert long to local byte order */
23         beswav,                 /* convert vlong to local byte order */
24         risctrace,              /* C traceback */
25         riscframe,              /* frame finder */
26         sparcexcep,             /* print exception */
27         0,                      /* breakpoint fixup */
28         beieeesftos,            /* single precision float printer */
29         beieeedftos,            /* double precision float printer */
30         sparcfoll,              /* following addresses */
31         sparcinst,              /* print instruction */
32         sparcdas,               /* dissembler */
33         sparcinstlen,           /* instruction size */
34 };
35
36 static char *trapname[] =
37 {
38         "reset",
39         "instruction access exception",
40         "illegal instruction",
41         "privileged instruction",
42         "fp disabled",
43         "window overflow",
44         "window underflow",
45         "unaligned address",
46         "fp exception",
47         "data access exception",
48         "tag overflow",
49 };
50
51 static char*
52 excname(ulong tbr)
53 {
54         static char buf[32];
55
56         if(tbr < sizeof trapname/sizeof(char*))
57                 return trapname[tbr];
58         if(tbr >= 130)
59                 sprint(buf, "trap instruction %ld", tbr-128);
60         else if(17<=tbr && tbr<=31)
61                 sprint(buf, "interrupt level %ld", tbr-16);
62         else switch(tbr){
63         case 36:
64                 return "cp disabled";
65         case 40:
66                 return "cp exception";
67         case 128:
68                 return "syscall";
69         case 129:
70                 return "breakpoint";
71         default:
72                 sprint(buf, "unknown trap %ld", tbr);
73         }
74         return buf;
75 }
76
77 static char*
78 sparcexcep(Map *map, Rgetter rget)
79 {
80         long tbr;
81
82         tbr = (*rget)(map, "TBR");
83         tbr = (tbr&0xFFF)>>4;
84         return excname(tbr);
85 }
86
87         /* Sparc disassembler and related functions */
88
89 struct opcode {
90         char    *mnemonic;
91         void    (*f)(struct instr*, char*);
92         int     flag;
93 };
94
95 static  char FRAMENAME[] = ".frame";
96
97 typedef struct instr Instr;
98
99 struct instr {
100         uchar   op;             /* bits 31-30 */
101         uchar   rd;             /* bits 29-25 */
102         uchar   op2;            /* bits 24-22 */
103         uchar   a;              /* bit  29    */
104         uchar   cond;           /* bits 28-25 */
105         uchar   op3;            /* bits 24-19 */
106         uchar   rs1;            /* bits 18-14 */
107         uchar   i;              /* bit  13    */
108         uchar   asi;            /* bits 12-05 */
109         uchar   rs2;            /* bits 04-00 */
110         short   simm13;         /* bits 12-00, signed */
111         ushort  opf;            /* bits 13-05 */
112         ulong   immdisp22;      /* bits 21-00 */
113         ulong   simmdisp22;     /* bits 21-00, signed */
114         ulong   disp30;         /* bits 30-00 */
115         ulong   imm32;          /* SETHI+ADD constant */
116         int     target;         /* SETHI+ADD dest reg */
117         long    w0;
118         long    w1;
119         uvlong  addr;           /* pc of instruction */
120         char    *curr;          /* current fill level in output buffer */
121         char    *end;           /* end of buffer */
122         int     size;           /* number of longs in instr */
123         char    *err;           /* errmsg */
124 };
125
126 static  Map     *mymap;         /* disassembler context */
127 static  int     dascase;
128
129 static int      mkinstr(uvlong, Instr*);
130 static void     bra1(Instr*, char*, char*[]);
131 static void     bra(Instr*, char*);
132 static void     fbra(Instr*, char*);
133 static void     cbra(Instr*, char*);
134 static void     unimp(Instr*, char*);
135 static void     fpop(Instr*, char*);
136 static void     shift(Instr*, char*);
137 static void     sethi(Instr*, char*);
138 static void     load(Instr*, char*);
139 static void     loada(Instr*, char*);
140 static void     store(Instr*, char*);
141 static void     storea(Instr*, char*);
142 static void     add(Instr*, char*);
143 static void     cmp(Instr*, char*);
144 static void     wr(Instr*, char*);
145 static void     jmpl(Instr*, char*);
146 static void     rd(Instr*, char*);
147 static void     loadf(Instr*, char*);
148 static void     storef(Instr*, char*);
149 static void     loadc(Instr*, char*);
150 static void     loadcsr(Instr*, char*);
151 static void     trap(Instr*, char*);
152
153 static struct opcode sparcop0[8] = {
154         [0]     "UNIMP",        unimp,  0,      /* page 137 */
155         [2]     "B",            bra,    0,      /* page 119 */
156         [4]     "SETHI",        sethi,  0,      /* page 104 */
157         [6]     "FB",           fbra,   0,      /* page 121 */
158         [7]     "CB",           cbra,   0,      /* page 123 */
159 };
160
161 static struct opcode sparcop2[64] = {
162         [0x00]  "ADD",          add,    0,      /* page 108 */
163         [0x10]  "ADDCC",        add,    0,
164         [0x08]  "ADDX",         add,    0,
165         [0x18]  "ADDXCC",       add,    0,
166
167         [0x20]  "TADD",         add,    0,      /* page 109 */
168         [0x22]  "TADDCCTV",     add,    0,
169
170         [0x04]  "SUB",          add,    0,      /* page 110 */
171         [0x14]  "SUBCC",        cmp,    0,
172         [0x0C]  "SUBX",         add,    0,
173         [0x1C]  "SUBXCC",       add,    0,
174
175         [0x21]  "TSUB",         add,    0,      /* page 111 */
176         [0x23]  "TSUBCCTV",     add,    0,
177
178         [0x24]  "MULSCC",       add,    0,      /* page 112 */
179
180         [0x0A]  "UMUL",         add,    0,      /* page 113 */
181         [0x0B]  "SMUL",         add,    0,
182         [0x1A]  "UMULCC",       add,    0,
183         [0x1B]  "SMULCC",       add,    0,
184
185         [0x0E]  "UDIV",         add,    0,      /* page 115 */
186         [0x0F]  "SDIV",         add,    0,
187         [0x1E]  "UDIVCC",       add,    0,
188         [0x1F]  "SDIVCC",       add,    0,
189
190         [0x01]  "AND",          add,    0,      /* page 106 */
191         [0x11]  "ANDCC",        add,    0,
192         [0x05]  "ANDN",         add,    0,
193         [0x15]  "ANDNCC",       add,    0,
194         [0x02]  "OR",           add,    0,
195         [0x12]  "ORCC",         add,    0,
196         [0x06]  "ORN",          add,    0,
197         [0x16]  "ORNCC",        add,    0,
198         [0x03]  "XOR",          add,    0,
199         [0x13]  "XORCC",        add,    0,
200         [0x07]  "XORN",         add,    0,
201         [0x17]  "XORNCC",       add,    0,
202
203         [0x25]  "SLL",          shift,  0,      /* page 107 */
204         [0x26]  "SRL",          shift,  0,
205         [0x27]  "SRA",          shift,  0,
206
207         [0x3C]  "SAVE",         add,    0,      /* page 117 */
208         [0x3D]  "RESTORE",      add,    0,
209
210         [0x38]  "JMPL",         jmpl,   0,      /* page 126 */
211
212         [0x39]  "RETT",         add,    0,      /* page 127 */
213
214         [0x3A]  "T",            trap,   0,      /* page 129 */
215
216         [0x28]  "rdy",          rd,     0,      /* page 131 */
217         [0x29]  "rdpsr",        rd,     0,
218         [0x2A]  "rdwim",        rd,     0,
219         [0x2B]  "rdtbr",        rd,     0,
220
221         [0x30]  "wry",          wr,     0,      /* page 133 */
222         [0x31]  "wrpsr",        wr,     0,
223         [0x32]  "wrwim",        wr,     0,
224         [0x33]  "wrtbr",        wr,     0,
225
226         [0x3B]  "flush",        add,    0,      /* page 138 */
227
228         [0x34]  "FPOP",         fpop,   0,      /* page 140 */
229         [0x35]  "FPOP",         fpop,   0,
230 };
231
232 static struct opcode sparcop3[64]={
233         [0x09]  "ldsb",         load,   0,      /* page 90 */
234         [0x19]  "ldsba",        loada,  0,
235         [0x0A]  "ldsh",         load,   0,
236         [0x1A]  "ldsha",        loada,  0,
237         [0x01]  "ldub",         load,   0,
238         [0x11]  "lduba",        loada,  0,
239         [0x02]  "lduh",         load,   0,
240         [0x12]  "lduha",        loada,  0,
241         [0x00]  "ld",           load,   0,
242         [0x10]  "lda",          loada,  0,
243         [0x03]  "ldd",          load,   0,
244         [0x13]  "ldda",         loada,  0,
245
246         [0x20]  "ldf",          loadf,  0,      /* page 92 */
247         [0x23]  "lddf",         loadf,  0,
248         [0x21]  "ldfsr",        loadf,0,
249
250         [0x30]  "ldc",          loadc,  0,      /* page 94 */
251         [0x33]  "lddc",         loadc,  0,
252         [0x31]  "ldcsr",        loadcsr,0,
253
254         [0x05]  "stb",          store,  0,      /* page 95 */
255         [0x15]  "stba",         storea, 0,
256         [0x06]  "sth",          store,  0,
257         [0x16]  "stha",         storea, 0,
258         [0x04]  "st",           store,  0,
259         [0x14]  "sta",          storea, 0,
260         [0x07]  "std",          store,  0,
261         [0x17]  "stda",         storea, 0,
262
263         [0x24]  "stf",          storef, 0,      /* page 97 */
264         [0x27]  "stdf",         storef, 0,
265         [0x25]  "stfsr",        storef,0,
266         [0x26]  "stdfq",        storef,0,
267
268         [0x34]  "stc",          loadc,  0,      /* page 99 */
269         [0x37]  "stdc",         loadc,  0,
270         [0x35]  "stcsr",        loadcsr,0,
271         [0x36]  "stdcq",        loadcsr,0,
272
273         [0x0D]  "ldstub",       store,  0,      /* page 101 */
274         [0x1D]  "ldstuba",      storea, 0,
275
276         [0x0F]  "swap",         load,   0,      /* page 102 */
277         [0x1F]  "swapa",        loada,  0,
278 };
279
280 #pragma varargck        argpos  bprint  2
281 #pragma varargck        type    "T"     char*
282
283 /* convert to lower case from upper, according to dascase */
284 static int
285 Tfmt(Fmt *f)
286 {
287         char buf[128];
288         char *s, *t, *oa;
289
290         oa = va_arg(f->args, char*);
291         if(dascase){
292                 for(s=oa,t=buf; *t = *s; s++,t++)
293                         if('A'<=*t && *t<='Z')
294                                 *t += 'a'-'A';
295                 return fmtstrcpy(f, buf);
296         }
297         return fmtstrcpy(f, oa);
298 }
299
300 static void
301 bprint(Instr *i, char *fmt, ...)
302 {
303         va_list arg;
304
305         va_start(arg, fmt);
306         i->curr = vseprint(i->curr, i->end, fmt, arg);
307         va_end(arg);
308 }
309
310 static int
311 decode(uvlong pc, Instr *i)
312 {
313         ulong w;
314
315         if (get4(mymap, pc, &w) < 0) {
316                 werrstr("can't read instruction: %r");
317                 return -1;
318         }
319         i->op = (w >> 30) & 0x03;
320         i->rd = (w >> 25) & 0x1F;
321         i->op2 = (w >> 22) & 0x07;
322         i->a = (w >> 29) & 0x01;
323         i->cond = (w >> 25) & 0x0F;
324         i->op3 = (w >> 19) & 0x3F;
325         i->rs1 = (w >> 14) & 0x1F;
326         i->i = (w >> 13) & 0x01;
327         i->asi = (w >> 5) & 0xFF;
328         i->rs2 = (w >> 0) & 0x1F;
329         i->simm13 = (w >> 0) & 0x1FFF;
330         if(i->simm13 & (1<<12))
331                 i->simm13 |= ~((1<<13)-1);
332         i->opf = (w >> 5) & 0x1FF;
333         i->immdisp22 = (w >> 0) & 0x3FFFFF;
334         i->simmdisp22 = i->immdisp22;
335         if(i->simmdisp22 & (1<<21))
336                 i->simmdisp22 |= ~((1<<22)-1);
337         i->disp30 = (w >> 0) & 0x3FFFFFFF;
338         i->w0 = w;
339         i->target = -1;
340         i->addr = pc;
341         i->size = 1;
342         return 1;
343 }
344
345 static int
346 mkinstr(uvlong pc, Instr *i)
347 {
348         Instr xi;
349
350         if (decode(pc, i) < 0)
351                 return -1;
352         if(i->op==0 && i->op2==4 && !dascase){  /* SETHI */
353                 if (decode(pc+4, &xi) < 0)
354                         return -1;
355                 if(xi.op==2 && xi.op3==0)               /* ADD */
356                 if(xi.i == 1 && xi.rs1 == i->rd){       /* immediate to same reg */
357                         i->imm32 = xi.simm13 + (i->immdisp22<<10);
358                         i->target = xi.rd;
359                         i->w1 = xi.w0;
360                         i->size++;
361                         return 1;
362                 }
363         }
364         if(i->op==2 && i->opf==1 && !dascase){  /* FMOVS */
365                 if (decode(pc+4, &xi) < 0)
366                         return -1;
367                 if(i->op==2 && i->opf==1)               /* FMOVS */
368                 if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
369                         i->w1 = xi.w0;
370                         i->size++;
371                 }
372         }
373         return 1;
374 }
375
376 static int
377 printins(Map *map, uvlong pc, char *buf, int n)
378 {
379         Instr instr;
380         void (*f)(Instr*, char*);
381
382         mymap = map;
383         memset(&instr, 0, sizeof(instr));
384         instr.curr = buf;
385         instr.end = buf+n-1;
386         if (mkinstr(pc, &instr) < 0)
387                 return -1;
388         switch(instr.op){
389         case 0:
390                 f = sparcop0[instr.op2].f;
391                 if(f)
392                         (*f)(&instr, sparcop0[instr.op2].mnemonic);
393                 else
394                         bprint(&instr, "unknown %lux", instr.w0);
395                 break;
396
397         case 1:
398                 bprint(&instr, "%T", "CALL\t");
399                 instr.curr += symoff(instr.curr, instr.end-instr.curr,
400                                         pc+instr.disp30*4, CTEXT);
401                 if (!dascase)
402                         bprint(&instr, "(SB)");
403                 break;
404
405         case 2:
406                 f = sparcop2[instr.op3].f;
407                 if(f)
408                         (*f)(&instr, sparcop2[instr.op3].mnemonic);
409                 else
410                         bprint(&instr, "unknown %lux", instr.w0);
411                 break;
412
413         case 3:
414                 f = sparcop3[instr.op3].f;
415                 if(f)
416                         (*f)(&instr, sparcop3[instr.op3].mnemonic);
417                 else
418                         bprint(&instr, "unknown %lux", instr.w0);
419                 break;
420         }
421         if (instr.err) {
422                 if (instr.curr != buf)
423                         bprint(&instr, "\t\t;");
424                 bprint(&instr, instr.err);
425         }
426         return instr.size*4;
427 }
428
429 static int
430 sparcinst(Map *map, uvlong pc, char modifier, char *buf, int n)
431 {
432         static int fmtinstalled = 0;
433
434                 /* a modifier of 'I' toggles the dissassembler type */
435         if (!fmtinstalled) {
436                 fmtinstalled = 1;
437                 fmtinstall('T', Tfmt);
438         }
439         if ((asstype == ASUNSPARC && modifier == 'i')
440                 || (asstype == ASPARC && modifier == 'I'))
441                 dascase = 'a'-'A';
442         else
443                 dascase = 0;
444         return printins(map, pc, buf, n);
445 }
446
447 static int
448 sparcdas(Map *map, uvlong pc, char *buf, int n)
449 {
450         Instr instr;
451
452         mymap = map;
453         memset(&instr, 0, sizeof(instr));
454         instr.curr = buf;
455         instr.end = buf+n-1;
456         if (mkinstr(pc, &instr) < 0)
457                 return -1;
458         if (instr.end-instr.curr > 8)
459                 instr.curr = _hexify(instr.curr, instr.w0, 7);
460         if (instr.end-instr.curr > 9 && instr.size == 2) {
461                 *instr.curr++ = ' ';
462                 instr.curr = _hexify(instr.curr, instr.w1, 7);
463         }
464         *instr.curr = 0;
465         return instr.size*4;
466 }
467
468 static int
469 sparcinstlen(Map *map, uvlong pc)
470 {
471         Instr i;
472
473         mymap = map;
474         if (mkinstr(pc, &i) < 0)
475                 return -1;
476         return i.size*4;
477 }
478
479 static int
480 plocal(Instr *i)
481 {
482         int offset;
483         Symbol s;
484
485         if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
486                 return -1;
487         if (s.value > i->simm13) {
488                 if(getauto(&s, s.value-i->simm13, CAUTO, &s)) {
489                         bprint(i, "%s+%lld(SP)", s.name, s.value);
490                         return 1;
491                 }
492         } else {
493                 offset = i->simm13-s.value;
494                 if (getauto(&s, offset-4, CPARAM, &s)) {
495                         bprint(i, "%s+%d(FP)", s.name, offset);
496                         return 1;
497                 }
498         }
499         return -1;
500 }
501
502 static void
503 address(Instr *i)
504 {
505         Symbol s, s2;
506         uvlong off, off1;
507
508         if (i->rs1 == 1 && plocal(i) >= 0)
509                 return;
510         off = mach->sb+i->simm13;
511         if(i->rs1 == 2  && findsym(off, CANY, &s)
512                         && s.value-off < 4096
513                         && (s.class == CDATA || s.class == CTEXT)) {
514                 if(off==s.value && s.name[0]=='$'){
515                         off1 = 0;
516                         geta(mymap, s.value, &off1);
517                         if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
518                                 bprint(i, "$%s(SB)", s2.name);
519                                 return;
520                         }
521                 }
522                 bprint(i, "%s", s.name);
523                 if (s.value != off)
524                         bprint(i, "+%llux", s.value-off);
525                 bprint(i, "(SB)");
526                 return;
527         }
528         bprint(i, "%ux(R%d)", i->simm13, i->rs1);
529 }
530
531 static void
532 unimp(Instr *i, char *m)
533 {
534         bprint(i, "%T", m);
535 }
536
537 static char     *bratab[16] = { /* page 91 */
538         [0X8]   "A",
539         [0X0]   "N",
540         [0X9]   "NE",
541         [0X1]   "E",
542         [0XA]   "G",
543         [0X2]   "LE",
544         [0XB]   "GE",
545         [0X3]   "L",
546         [0XC]   "GU",
547         [0X4]   "LEU",
548         [0XD]   "CC",
549         [0X5]   "CS",
550         [0XE]   "POS",
551         [0X6]   "NEG",
552         [0XF]   "VC",
553         [0X7]   "VS",
554 };
555
556 static char     *fbratab[16] = {        /* page 91 */
557         [0X8]   "A",
558         [0X0]   "N",
559         [0X7]   "U",
560         [0X6]   "G",
561         [0X5]   "UG",
562         [0X4]   "L",
563         [0X3]   "UL",
564         [0X2]   "LG",
565         [0X1]   "NE",
566         [0X9]   "E",
567         [0XA]   "UE",
568         [0XB]   "GE",
569         [0XC]   "UGE",
570         [0XD]   "LE",
571         [0XE]   "ULE",
572         [0XF]   "O",
573 };
574
575 static char     *cbratab[16] = {        /* page 91 */
576         [0X8]   "A",
577         [0X0]   "N",
578         [0X7]   "3",
579         [0X6]   "2",
580         [0X5]   "23",
581         [0X4]   "1",
582         [0X3]   "13",
583         [0X2]   "12",
584         [0X1]   "123",
585         [0X9]   "0",
586         [0XA]   "03",
587         [0XB]   "02",
588         [0XC]   "023",
589         [0XD]   "01",
590         [0XE]   "013",
591         [0XF]   "012",
592 };
593
594 static void
595 bra1(Instr *i, char *m, char *tab[])
596 {
597         long imm;
598
599         imm = i->simmdisp22;
600         if(i->a)
601                 bprint(i, "%T%T.%c\t", m, tab[i->cond], 'A'+dascase);
602         else
603                 bprint(i, "%T%T\t", m, tab[i->cond]);
604         i->curr += symoff(i->curr, i->end-i->curr, i->addr+4*imm, CTEXT);
605         if (!dascase)
606                 bprint(i, "(SB)");
607 }
608
609 static void
610 bra(Instr *i, char *m)                  /* page 91 */
611 {
612         bra1(i, m, bratab);
613 }
614
615 static void
616 fbra(Instr *i, char *m)                 /* page 93 */
617 {
618         bra1(i, m, fbratab);
619 }
620
621 static void
622 cbra(Instr *i, char *m)                 /* page 95 */
623 {
624         bra1(i, m, cbratab);
625 }
626
627 static void
628 trap(Instr *i, char *m)                 /* page 101 */
629 {
630         if(i->i == 0)
631                 bprint(i, "%T%T\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
632         else
633                 bprint(i, "%T%T\t$%ux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
634 }
635
636 static void
637 sethi(Instr *i, char *m)                /* page 89 */
638 {
639         ulong imm;
640
641         imm = i->immdisp22<<10;
642         if(dascase){
643                 bprint(i, "%T\t%lux, R%d", m, imm, i->rd);
644                 return;
645         }
646         if(imm==0 && i->rd==0){
647                 bprint(i, "NOP");
648                 return;
649         }
650         if(i->target < 0){
651                 bprint(i, "MOVW\t$%lux, R%d", imm, i->rd);
652                 return;
653         }
654         bprint(i, "MOVW\t$%lux, R%d", i->imm32, i->target);
655 }
656
657 static char ldtab[] = {
658         'W',
659         'B',
660         'H',
661         'D',
662 };
663
664 static char*
665 moveinstr(int op3, char *m)
666 {
667         char *s;
668         int c;
669         static char buf[8];
670
671         if(!dascase){
672                 /* batshit cases */
673                 if(op3 == 0xF || op3 == 0x1F)
674                         return "SWAP";
675                 if(op3 == 0xD || op3 == 0x1D)
676                         return "TAS";   /* really LDSTUB */
677                 c = ldtab[op3&3];
678                 s = "";
679                 if((op3&11)==1 || (op3&11)==2)
680                         s="U";
681                 sprint(buf, "MOV%c%s", c, s);
682                 return buf;
683         }
684         return m;
685 }
686
687 static void
688 load(Instr *i, char *m)                 /* page 68 */
689 {
690         m = moveinstr(i->op3, m);
691         if(i->i == 0)
692                 bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
693         else{
694                 bprint(i, "%s\t", m);
695                 address(i);
696                 bprint(i, ", R%d", i->rd);
697         }
698 }
699
700 static void
701 loada(Instr *i, char *m)                /* page 68 */
702 {
703         m = moveinstr(i->op3, m);
704         if(i->i == 0)
705                 bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
706         else
707                 bprint(i, "unknown ld asi %lux", i->w0);
708 }
709
710 static void
711 store(Instr *i, char *m)                /* page 74 */
712 {
713         m = moveinstr(i->op3, m);
714         if(i->i == 0)
715                 bprint(i, "%s\tR%d, (R%d+R%d)",
716                                 m, i->rd, i->rs1, i->rs2);
717         else{
718                 bprint(i, "%s\tR%d, ", m, i->rd);
719                 address(i);
720         }
721 }
722
723 static void
724 storea(Instr *i, char *m)               /* page 74 */
725 {
726         m = moveinstr(i->op3, m);
727         if(i->i == 0)
728                 bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
729         else
730                 bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
731 }
732
733 static void
734 shift(Instr *i, char *m)        /* page 88 */
735 {
736         if(i->i == 0){
737                 if(i->rs1 == i->rd)
738                         if(dascase)
739                                 bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
740                         else
741                                 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
742                 else
743                         if(dascase)
744                                 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
745                         else
746                                 bprint(i, "%T\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
747         }else{
748                 if(i->rs1 == i->rd)
749                         if(dascase)
750                                 bprint(i, "%T\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
751                         else
752                                 bprint(i, "%T\tR%d, $%d", m,  i->rs1, i->simm13&0x1F);
753                 else
754                         if(dascase)
755                                 bprint(i, "%T\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
756                         else
757                                 bprint(i, "%T\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
758         }
759 }
760
761 static void
762 add(Instr *i, char *m)  /* page 82 */
763 {
764         if(i->i == 0){
765                 if(dascase)
766                         bprint(i, "%T\tR%d, R%d", m, i->rs1, i->rs2);
767                 else
768                         if(i->op3==2 && i->rs1==0 && i->rd)  /* OR R2, R0, R1 */
769                                 bprint(i, "MOVW\tR%d", i->rs2);
770                         else
771                                 bprint(i, "%T\tR%d, R%d", m, i->rs2, i->rs1);
772         }else{
773                 if(dascase)
774                         bprint(i, "%T\tR%d, $%ux", m, i->rs1, i->simm13);
775                 else
776                         if(i->op3==0 && i->rd && i->rs1==0)     /* ADD $x, R0, R1 */
777                                 bprint(i, "MOVW\t$%ux", i->simm13);
778                         else if(i->op3==0 && i->rd && i->rs1==2){
779                                 /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
780                                 bprint(i, "MOVW\t$");
781                                 address(i);
782                         } else
783                                 bprint(i, "%T\t$%ux, R%d", m, i->simm13, i->rs1);
784         }
785         if(i->rs1 != i->rd)
786                 bprint(i, ", R%d", i->rd);
787 }
788
789 static void
790 cmp(Instr *i, char *m)
791 {
792         if(dascase || i->rd){
793                 add(i, m);
794                 return;
795         }
796         if(i->i == 0)
797                 bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
798         else
799                 bprint(i, "CMP\tR%d, $%ux", i->rs1, i->simm13);
800 }
801
802 static char *regtab[4] = {
803         "Y",
804         "PSR",
805         "WIM",
806         "TBR",
807 };
808
809 static void
810 wr(Instr *i, char *m)           /* page 82 */
811 {
812         if(dascase){
813                 if(i->i == 0)
814                         bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
815                 else
816                         bprint(i, "%s\tR%d, $%ux", m, i->rs1, i->simm13);
817         }else{
818                 if(i->i && i->simm13==0)
819                         bprint(i, "MOVW\tR%d", i->rs1);
820                 else if(i->i == 0)
821                         bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
822                 else
823                         bprint(i, "wr\t$%ux, R%d", i->simm13, i->rs1);
824         }
825         bprint(i, ", %s", regtab[i->op3&3]);
826 }
827
828 static void
829 rd(Instr *i, char *m)           /* page 103 */
830 {
831         if(i->rs1==15 && i->rd==0){
832                 m = "stbar";
833                 if(!dascase)
834                         m = "STBAR";
835                 bprint(i, "%s", m);
836         }else{
837                 if(!dascase)
838                         m = "MOVW";
839                 bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
840         }
841 }
842
843 static void
844 jmpl(Instr *i, char *m)         /* page 82 */
845 {
846         if(i->i == 0){
847                 if(i->rd == 15)
848                         bprint(i, "%T\t(R%d+R%d)", "CALL", i->rs2, i->rs1);
849                 else
850                         bprint(i, "%T\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
851         }else{
852                 if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
853                         bprint(i, "RETURN");
854                 else{
855                         bprint(i, "%T\t", m);
856                         address(i);
857                         bprint(i, ", R%d", i->rd);
858                 }
859         }
860 }
861
862 static void
863 loadf(Instr *i, char *m)                /* page 70 */
864 {
865         if(!dascase){
866                 m = "FMOVD";
867                 if(i->op3 == 0x20)
868                         m = "FMOVF";
869                 else if(i->op3 == 0x21)
870                         m = "MOVW";
871         }
872         if(i->i == 0)
873                 bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
874         else{
875                 bprint(i, "%s\t", m);
876                 address(i);
877         }
878         if(i->op3 == 0x21)
879                 bprint(i, ", FSR");
880         else
881                 bprint(i, ", R%d", i->rd);
882 }
883
884 static void
885 storef(Instr *i, char *m)               /* page 70 */
886 {
887         if(!dascase){
888                 m = "FMOVD";
889                 if(i->op3 == 0x25 || i->op3 == 0x26)
890                         m = "MOVW";
891                 else if(i->op3 == 0x20)
892                         m = "FMOVF";
893         }
894         bprint(i, "%s\t", m);
895         if(i->op3 == 0x25)
896                 bprint(i, "FSR, ");
897         else if(i->op3 == 0x26)
898                 bprint(i, "FQ, ");
899         else
900                 bprint(i, "R%d, ", i->rd);
901         if(i->i == 0)
902                 bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
903         else
904                 address(i);
905 }
906
907 static void
908 loadc(Instr *i, char *m)                        /* page 72 */
909 {
910         if(i->i == 0)
911                 bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
912         else{
913                 bprint(i, "%s\t", m);
914                 address(i);
915                 bprint(i, ", C%d", i->rd);
916         }
917 }
918
919 static void
920 loadcsr(Instr *i, char *m)                      /* page 72 */
921 {
922         if(i->i == 0)
923                 bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
924         else{
925                 bprint(i, "%s\t", m);
926                 address(i);
927                 bprint(i, ", CSR");
928         }
929 }
930
931 static struct{
932         int     opf;
933         char    *name;
934 } fptab1[] = {                  /* ignores rs1 */
935         0xC4,   "FITOS",        /* page 109 */
936         0xC8,   "FITOD",
937         0xCC,   "FITOX",
938
939         0xD1,   "FSTOI",        /* page 110 */
940         0xD2,   "FDTOI",
941         0xD3,   "FXTOI",
942
943         0xC9,   "FSTOD",        /* page 111 */
944         0xCD,   "FSTOX",
945         0xC6,   "FDTOS",
946         0xCE,   "FDTOX",
947         0xC7,   "FXTOS",
948         0xCB,   "FXTOD",
949
950         0x01,   "FMOVS",        /* page 112 */
951         0x05,   "FNEGS",
952         0x09,   "FABSS",
953
954         0x29,   "FSQRTS",       /* page 113 */
955         0x2A,   "FSQRTD",
956         0x2B,   "FSQRTX",
957
958         0,      0,
959 };
960
961 static struct{
962         int     opf;
963         char    *name;
964 } fptab2[] = {                  /* uses rs1 */
965
966         0x41,   "FADDS",        /* page 114 */
967         0x42,   "FADDD",
968         0x43,   "FADDX",
969         0x45,   "FSUBS",
970         0x46,   "FSUBD",
971         0x47,   "FSUBX",
972
973         0x49,   "FMULS",        /* page 115 */
974         0x4A,   "FMULD",
975         0x4B,   "FMULX",
976         0x4D,   "FDIVS",
977         0x4E,   "FDIVD",
978         0x4F,   "FDIVX",
979
980         0x51,   "FCMPS",        /* page 116 */
981         0x52,   "FCMPD",
982         0x53,   "FCMPX",
983         0x55,   "FCMPES",
984         0x56,   "FCMPED",
985         0x57,   "FCMPEX",
986
987         0, 0
988 };
989
990 static void
991 fpop(Instr *i, char *m) /* page 108-116 */
992 {
993         int j;
994
995         if(dascase==0 && i->size==2){
996                 bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
997                 return;
998         }
999         for(j=0; fptab1[j].name; j++)
1000                 if(fptab1[j].opf == i->opf){
1001                         bprint(i, "%T\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
1002                         return;
1003                 }
1004         for(j=0; fptab2[j].name; j++)
1005                 if(fptab2[j].opf == i->opf){
1006                         bprint(i, "%T\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
1007                         return;
1008                 }
1009         bprint(i, "%T%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
1010 }
1011
1012 static int
1013 sparcfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1014 {
1015         ulong w, r1, r2;
1016         char buf[8];
1017         Instr i;
1018
1019         mymap = map;
1020         if (mkinstr(pc, &i) < 0)
1021                 return -1;
1022         w = i.w0;
1023         switch(w & 0xC1C00000){
1024         case 0x00800000:                /* branch on int cond */
1025         case 0x01800000:                /* branch on fp cond */
1026         case 0x01C00000:                /* branch on copr cond */
1027                 foll[0] = pc+8;
1028                 foll[1] = pc + (i.simmdisp22<<2);
1029                 return 2;
1030         }
1031
1032         if((w&0xC0000000) == 0x40000000){       /* CALL */
1033                 foll[0] = pc + (i.disp30<<2);
1034                 return 1;
1035         }
1036
1037         if((w&0xC1F80000) == 0x81C00000){       /* JMPL */
1038                 sprint(buf, "R%ld", (w>>14)&0xF);
1039                 r1 = (*rget)(map, buf);
1040                 if(w & 0x2000)                  /* JMPL R1+simm13 */
1041                         r2 = i.simm13;
1042                 else{                           /* JMPL R1+R2 */
1043                         sprint(buf, "R%ld", w&0xF);
1044                         r2 = (*rget)(map, buf);
1045                 }
1046                 foll[0] = r1 + r2;
1047                 return 1;
1048         }
1049         foll[0] = pc+i.size*4;
1050         return 1;
1051 }