1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <mach.h>
5219b2ee8SDavid du Colombier /*
6219b2ee8SDavid du Colombier * Mips-specific debugger interface
7219b2ee8SDavid du Colombier */
8219b2ee8SDavid du Colombier
9219b2ee8SDavid du Colombier static char *mipsexcep(Map*, Rgetter);
104de34a7eSDavid du Colombier static int mipsfoll(Map*, uvlong, Rgetter, uvlong*);
114de34a7eSDavid du Colombier static int mipsinst(Map*, uvlong, char, char*, int);
124de34a7eSDavid du Colombier static int mipsdas(Map*, uvlong, char*, int);
134de34a7eSDavid du Colombier static int mipsinstlen(Map*, uvlong);
147dd7cddfSDavid du Colombier
15219b2ee8SDavid du Colombier /*
16219b2ee8SDavid du Colombier * Debugger interface
17219b2ee8SDavid du Colombier */
18219b2ee8SDavid du Colombier Machdata mipsmach =
19219b2ee8SDavid du Colombier {
20219b2ee8SDavid du Colombier {0, 0, 0, 0xD}, /* break point */
21219b2ee8SDavid du Colombier 4, /* break point size */
22219b2ee8SDavid du Colombier
23219b2ee8SDavid du Colombier beswab, /* short to local byte order */
24219b2ee8SDavid du Colombier beswal, /* long to local byte order */
257dd7cddfSDavid du Colombier beswav, /* vlong to local byte order */
26219b2ee8SDavid du Colombier risctrace, /* C traceback */
27219b2ee8SDavid du Colombier riscframe, /* Frame finder */
28219b2ee8SDavid du Colombier mipsexcep, /* print exception */
29219b2ee8SDavid du Colombier 0, /* breakpoint fixup */
30219b2ee8SDavid du Colombier beieeesftos, /* single precision float printer */
31*426f2a32SDavid du Colombier /*
32*426f2a32SDavid du Colombier * this works for doubles in memory, but FP register pairs have
33*426f2a32SDavid du Colombier * the words in little-endian order, so they will print as
34*426f2a32SDavid du Colombier * denormalised doubles.
35*426f2a32SDavid du Colombier */
36*426f2a32SDavid du Colombier beieeedftos, /* double precision float printer */
37219b2ee8SDavid du Colombier mipsfoll, /* following addresses */
38219b2ee8SDavid du Colombier mipsinst, /* print instruction */
39219b2ee8SDavid du Colombier mipsdas, /* dissembler */
40219b2ee8SDavid du Colombier mipsinstlen, /* instruction size */
41219b2ee8SDavid du Colombier };
42219b2ee8SDavid du Colombier
431a4050f5SDavid du Colombier Machdata mipsmachle =
441a4050f5SDavid du Colombier {
451a4050f5SDavid du Colombier {0, 0, 0, 0xD}, /* break point */
461a4050f5SDavid du Colombier 4, /* break point size */
471a4050f5SDavid du Colombier
481a4050f5SDavid du Colombier leswab, /* short to local byte order */
491a4050f5SDavid du Colombier leswal, /* long to local byte order */
501a4050f5SDavid du Colombier leswav, /* vlong to local byte order */
511a4050f5SDavid du Colombier risctrace, /* C traceback */
521a4050f5SDavid du Colombier riscframe, /* Frame finder */
531a4050f5SDavid du Colombier mipsexcep, /* print exception */
541a4050f5SDavid du Colombier 0, /* breakpoint fixup */
551a4050f5SDavid du Colombier leieeesftos, /* single precision float printer */
56*426f2a32SDavid du Colombier leieeedftos, /* double precision float printer */
571a4050f5SDavid du Colombier mipsfoll, /* following addresses */
581a4050f5SDavid du Colombier mipsinst, /* print instruction */
591a4050f5SDavid du Colombier mipsdas, /* dissembler */
601a4050f5SDavid du Colombier mipsinstlen, /* instruction size */
611a4050f5SDavid du Colombier };
621a4050f5SDavid du Colombier
637dd7cddfSDavid du Colombier /*
6459cc4ca5SDavid du Colombier * mips r4k little-endian
657dd7cddfSDavid du Colombier */
667dd7cddfSDavid du Colombier Machdata mipsmach2le =
677dd7cddfSDavid du Colombier {
687dd7cddfSDavid du Colombier {0, 0, 0, 0xD}, /* break point */
697dd7cddfSDavid du Colombier 4, /* break point size */
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier leswab, /* short to local byte order */
727dd7cddfSDavid du Colombier leswal, /* long to local byte order */
737dd7cddfSDavid du Colombier leswav, /* vlong to local byte order */
747dd7cddfSDavid du Colombier risctrace, /* C traceback */
757dd7cddfSDavid du Colombier riscframe, /* Frame finder */
767dd7cddfSDavid du Colombier mipsexcep, /* print exception */
777dd7cddfSDavid du Colombier 0, /* breakpoint fixup */
787dd7cddfSDavid du Colombier leieeesftos, /* single precision float printer */
79*426f2a32SDavid du Colombier leieeedftos, /* double precision float printer */
807dd7cddfSDavid du Colombier mipsfoll, /* following addresses */
817dd7cddfSDavid du Colombier mipsinst, /* print instruction */
827dd7cddfSDavid du Colombier mipsdas, /* dissembler */
837dd7cddfSDavid du Colombier mipsinstlen, /* instruction size */
847dd7cddfSDavid du Colombier };
857dd7cddfSDavid du Colombier
8659cc4ca5SDavid du Colombier /*
8759cc4ca5SDavid du Colombier * mips r4k big-endian
8859cc4ca5SDavid du Colombier */
8959cc4ca5SDavid du Colombier Machdata mipsmach2be =
9059cc4ca5SDavid du Colombier {
9159cc4ca5SDavid du Colombier {0, 0, 0, 0xD}, /* break point */
9259cc4ca5SDavid du Colombier 4, /* break point size */
9359cc4ca5SDavid du Colombier
9459cc4ca5SDavid du Colombier beswab, /* short to local byte order */
9559cc4ca5SDavid du Colombier beswal, /* long to local byte order */
9659cc4ca5SDavid du Colombier beswav, /* vlong to local byte order */
9759cc4ca5SDavid du Colombier risctrace, /* C traceback */
9859cc4ca5SDavid du Colombier riscframe, /* Frame finder */
9959cc4ca5SDavid du Colombier mipsexcep, /* print exception */
10059cc4ca5SDavid du Colombier 0, /* breakpoint fixup */
10159cc4ca5SDavid du Colombier beieeesftos, /* single precision float printer */
102*426f2a32SDavid du Colombier beieeedftos, /* double precision float printer */
10359cc4ca5SDavid du Colombier mipsfoll, /* following addresses */
10459cc4ca5SDavid du Colombier mipsinst, /* print instruction */
10559cc4ca5SDavid du Colombier mipsdas, /* dissembler */
10659cc4ca5SDavid du Colombier mipsinstlen, /* instruction size */
10759cc4ca5SDavid du Colombier };
10859cc4ca5SDavid du Colombier
10959cc4ca5SDavid du Colombier
110219b2ee8SDavid du Colombier static char *excname[] =
111219b2ee8SDavid du Colombier {
112219b2ee8SDavid du Colombier "external interrupt",
113219b2ee8SDavid du Colombier "TLB modification",
114219b2ee8SDavid du Colombier "TLB miss (load or fetch)",
115219b2ee8SDavid du Colombier "TLB miss (store)",
116219b2ee8SDavid du Colombier "address error (load or fetch)",
117219b2ee8SDavid du Colombier "address error (store)",
118219b2ee8SDavid du Colombier "bus error (fetch)",
119219b2ee8SDavid du Colombier "bus error (data load or store)",
120219b2ee8SDavid du Colombier "system call",
121219b2ee8SDavid du Colombier "breakpoint",
122219b2ee8SDavid du Colombier "reserved instruction",
123219b2ee8SDavid du Colombier "coprocessor unusable",
124219b2ee8SDavid du Colombier "arithmetic overflow",
125219b2ee8SDavid du Colombier "undefined 13",
126219b2ee8SDavid du Colombier "undefined 14",
127219b2ee8SDavid du Colombier "system call",
128219b2ee8SDavid du Colombier /* the following is made up */
129219b2ee8SDavid du Colombier "floating point exception" /* FPEXC */
130219b2ee8SDavid du Colombier };
131219b2ee8SDavid du Colombier
132219b2ee8SDavid du Colombier static char*
mipsexcep(Map * map,Rgetter rget)133219b2ee8SDavid du Colombier mipsexcep(Map *map, Rgetter rget)
134219b2ee8SDavid du Colombier {
135219b2ee8SDavid du Colombier int e;
136219b2ee8SDavid du Colombier long c;
137219b2ee8SDavid du Colombier
138219b2ee8SDavid du Colombier c = (*rget)(map, "CAUSE");
1394e3613abSDavid du Colombier /* i don't think this applies to any current machines */
1404e3613abSDavid du Colombier if(0 && c & 0x00002000) /* INTR3 */
141219b2ee8SDavid du Colombier e = 16; /* Floating point exception */
142219b2ee8SDavid du Colombier else
143219b2ee8SDavid du Colombier e = (c>>2)&0x0F;
144219b2ee8SDavid du Colombier return excname[e];
145219b2ee8SDavid du Colombier }
146219b2ee8SDavid du Colombier
147219b2ee8SDavid du Colombier /* mips disassembler and related functions */
148219b2ee8SDavid du Colombier
149219b2ee8SDavid du Colombier static char FRAMENAME[] = ".frame";
150219b2ee8SDavid du Colombier
151219b2ee8SDavid du Colombier typedef struct {
1524de34a7eSDavid du Colombier uvlong addr;
153219b2ee8SDavid du Colombier uchar op; /* bits 31-26 */
154219b2ee8SDavid du Colombier uchar rs; /* bits 25-21 */
155219b2ee8SDavid du Colombier uchar rt; /* bits 20-16 */
156219b2ee8SDavid du Colombier uchar rd; /* bits 15-11 */
157219b2ee8SDavid du Colombier uchar sa; /* bits 10-6 */
158219b2ee8SDavid du Colombier uchar function; /* bits 5-0 */
159219b2ee8SDavid du Colombier long immediate; /* bits 15-0 */
160219b2ee8SDavid du Colombier ulong cofun; /* bits 24-0 */
161219b2ee8SDavid du Colombier ulong target; /* bits 25-0 */
162219b2ee8SDavid du Colombier long w0;
163219b2ee8SDavid du Colombier long w1;
164219b2ee8SDavid du Colombier int size; /* instruction size */
165219b2ee8SDavid du Colombier char *curr; /* fill point in buffer */
166219b2ee8SDavid du Colombier char *end; /* end of buffer */
167219b2ee8SDavid du Colombier char *err; /* error message */
168219b2ee8SDavid du Colombier } Instr;
169219b2ee8SDavid du Colombier
170219b2ee8SDavid du Colombier static Map *mymap;
171219b2ee8SDavid du Colombier
172219b2ee8SDavid du Colombier static int
decode(uvlong pc,Instr * i)1734de34a7eSDavid du Colombier decode(uvlong pc, Instr *i)
174219b2ee8SDavid du Colombier {
1754de34a7eSDavid du Colombier ulong w;
176219b2ee8SDavid du Colombier
177219b2ee8SDavid du Colombier if (get4(mymap, pc, &w) < 0) {
178219b2ee8SDavid du Colombier werrstr("can't read instruction: %r");
179219b2ee8SDavid du Colombier return -1;
180219b2ee8SDavid du Colombier }
1817dd7cddfSDavid du Colombier
182219b2ee8SDavid du Colombier i->addr = pc;
183219b2ee8SDavid du Colombier i->size = 1;
184219b2ee8SDavid du Colombier i->op = (w >> 26) & 0x3F;
185219b2ee8SDavid du Colombier i->rs = (w >> 21) & 0x1F;
186219b2ee8SDavid du Colombier i->rt = (w >> 16) & 0x1F;
187219b2ee8SDavid du Colombier i->rd = (w >> 11) & 0x1F;
188219b2ee8SDavid du Colombier i->sa = (w >> 6) & 0x1F;
189219b2ee8SDavid du Colombier i->function = w & 0x3F;
190219b2ee8SDavid du Colombier i->immediate = w & 0x0000FFFF;
191219b2ee8SDavid du Colombier if (i->immediate & 0x8000)
192219b2ee8SDavid du Colombier i->immediate |= ~0x0000FFFF;
193219b2ee8SDavid du Colombier i->cofun = w & 0x01FFFFFF;
194219b2ee8SDavid du Colombier i->target = w & 0x03FFFFFF;
195219b2ee8SDavid du Colombier i->w0 = w;
196219b2ee8SDavid du Colombier return 1;
197219b2ee8SDavid du Colombier }
198219b2ee8SDavid du Colombier
199219b2ee8SDavid du Colombier static int
mkinstr(uvlong pc,Instr * i)2004de34a7eSDavid du Colombier mkinstr(uvlong pc, Instr *i)
201219b2ee8SDavid du Colombier {
202219b2ee8SDavid du Colombier Instr x;
203219b2ee8SDavid du Colombier
204219b2ee8SDavid du Colombier if (decode(pc, i) < 0)
205219b2ee8SDavid du Colombier return -1;
206219b2ee8SDavid du Colombier /*
207219b2ee8SDavid du Colombier * if it's a LUI followed by an ORI,
208219b2ee8SDavid du Colombier * it's an immediate load of a large constant.
209219b2ee8SDavid du Colombier * fix the LUI immediate in any case.
210219b2ee8SDavid du Colombier */
211219b2ee8SDavid du Colombier if (i->op == 0x0F) {
212219b2ee8SDavid du Colombier if (decode(pc+4, &x) < 0)
213219b2ee8SDavid du Colombier return 0;
214219b2ee8SDavid du Colombier i->immediate <<= 16;
215219b2ee8SDavid du Colombier if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
216219b2ee8SDavid du Colombier i->immediate |= (x.immediate & 0xFFFF);
217219b2ee8SDavid du Colombier i->w1 = x.w0;
218219b2ee8SDavid du Colombier i->size++;
219219b2ee8SDavid du Colombier return 1;
220219b2ee8SDavid du Colombier }
221219b2ee8SDavid du Colombier }
222219b2ee8SDavid du Colombier /*
223219b2ee8SDavid du Colombier * if it's a LWC1 followed by another LWC1
224219b2ee8SDavid du Colombier * into an adjacent register, it's a load of
225219b2ee8SDavid du Colombier * a floating point double.
226219b2ee8SDavid du Colombier */
227219b2ee8SDavid du Colombier else if (i->op == 0x31 && (i->rt & 0x01)) {
228219b2ee8SDavid du Colombier if (decode(pc+4, &x) < 0)
229219b2ee8SDavid du Colombier return 0;
230219b2ee8SDavid du Colombier if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
231219b2ee8SDavid du Colombier i->rt -= 1;
232219b2ee8SDavid du Colombier i->w1 = x.w0;
233219b2ee8SDavid du Colombier i->size++;
234219b2ee8SDavid du Colombier return 1;
235219b2ee8SDavid du Colombier }
236219b2ee8SDavid du Colombier }
237219b2ee8SDavid du Colombier /*
238219b2ee8SDavid du Colombier * similarly for double stores
239219b2ee8SDavid du Colombier */
240219b2ee8SDavid du Colombier else if (i->op == 0x39 && (i->rt & 0x01)) {
241219b2ee8SDavid du Colombier if (decode(pc+4, &x) < 0)
242219b2ee8SDavid du Colombier return 0;
243219b2ee8SDavid du Colombier if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
244219b2ee8SDavid du Colombier i->rt -= 1;
245219b2ee8SDavid du Colombier i->w1 = x.w0;
246219b2ee8SDavid du Colombier i->size++;
247219b2ee8SDavid du Colombier }
248219b2ee8SDavid du Colombier }
249219b2ee8SDavid du Colombier return 1;
250219b2ee8SDavid du Colombier }
251219b2ee8SDavid du Colombier
2521bd28109SDavid du Colombier #pragma varargck argpos bprint 2
2531bd28109SDavid du Colombier
254219b2ee8SDavid du Colombier static void
bprint(Instr * i,char * fmt,...)255219b2ee8SDavid du Colombier bprint(Instr *i, char *fmt, ...)
256219b2ee8SDavid du Colombier {
2577dd7cddfSDavid du Colombier va_list arg;
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier va_start(arg, fmt);
2609a747e4fSDavid du Colombier i->curr = vseprint(i->curr, i->end, fmt, arg);
2617dd7cddfSDavid du Colombier va_end(arg);
262219b2ee8SDavid du Colombier }
263219b2ee8SDavid du Colombier
264219b2ee8SDavid du Colombier typedef struct Opcode Opcode;
265219b2ee8SDavid du Colombier
266219b2ee8SDavid du Colombier struct Opcode {
267219b2ee8SDavid du Colombier char *mnemonic;
268219b2ee8SDavid du Colombier void (*f)(Opcode *, Instr *);
269219b2ee8SDavid du Colombier char *ken;
270219b2ee8SDavid du Colombier };
271219b2ee8SDavid du Colombier
272219b2ee8SDavid du Colombier static void format(char *, Instr *, char *);
273219b2ee8SDavid du Colombier
274219b2ee8SDavid du Colombier static void
branch(Opcode * o,Instr * i)275219b2ee8SDavid du Colombier branch(Opcode *o, Instr *i)
276219b2ee8SDavid du Colombier {
277219b2ee8SDavid du Colombier if (i->rs == 0 && i->rt == 0)
278219b2ee8SDavid du Colombier format("JMP", i, "%b");
279219b2ee8SDavid du Colombier else if (i->rs == 0)
280219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%t,%b");
281219b2ee8SDavid du Colombier else if (i->rt < 2)
282219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%s,%b");
283219b2ee8SDavid du Colombier else
284219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%s,R%t,%b");
285219b2ee8SDavid du Colombier }
286219b2ee8SDavid du Colombier
287219b2ee8SDavid du Colombier static void
addi(Opcode * o,Instr * i)288219b2ee8SDavid du Colombier addi(Opcode *o, Instr *i)
289219b2ee8SDavid du Colombier {
290219b2ee8SDavid du Colombier if (i->rs == i->rt)
291219b2ee8SDavid du Colombier format(o->mnemonic, i, "%i,R%t");
292219b2ee8SDavid du Colombier else if (i->rs == 0)
293219b2ee8SDavid du Colombier format("MOVW", i, "%i,R%t");
294219b2ee8SDavid du Colombier else if (i->rs == 30) {
295219b2ee8SDavid du Colombier bprint(i, "MOVW\t$");
296219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr,
297219b2ee8SDavid du Colombier i->immediate+mach->sb, CANY);
298219b2ee8SDavid du Colombier bprint(i, "(SB),R%d", i->rt);
299219b2ee8SDavid du Colombier }
300219b2ee8SDavid du Colombier else
301219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
302219b2ee8SDavid du Colombier }
303219b2ee8SDavid du Colombier
304219b2ee8SDavid du Colombier static void
andi(Opcode * o,Instr * i)305219b2ee8SDavid du Colombier andi(Opcode *o, Instr *i)
306219b2ee8SDavid du Colombier {
307219b2ee8SDavid du Colombier if (i->rs == i->rt)
308219b2ee8SDavid du Colombier format(o->mnemonic, i, "%i,R%t");
309219b2ee8SDavid du Colombier else
310219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
311219b2ee8SDavid du Colombier }
312219b2ee8SDavid du Colombier
313219b2ee8SDavid du Colombier static int
plocal(Instr * i,char * m,char r,int store)314219b2ee8SDavid du Colombier plocal(Instr *i, char *m, char r, int store)
315219b2ee8SDavid du Colombier {
316219b2ee8SDavid du Colombier int offset;
317219b2ee8SDavid du Colombier char *reg;
318219b2ee8SDavid du Colombier Symbol s;
319219b2ee8SDavid du Colombier
320219b2ee8SDavid du Colombier if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
321219b2ee8SDavid du Colombier return 0;
322219b2ee8SDavid du Colombier if (s.value > i->immediate) {
323219b2ee8SDavid du Colombier if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
324219b2ee8SDavid du Colombier return 0;
325219b2ee8SDavid du Colombier reg = "(SP)";
326219b2ee8SDavid du Colombier offset = i->immediate;
327219b2ee8SDavid du Colombier } else {
328219b2ee8SDavid du Colombier offset = i->immediate-s.value;
329219b2ee8SDavid du Colombier if (!getauto(&s, offset-4, CPARAM, &s))
330219b2ee8SDavid du Colombier return 0;
331219b2ee8SDavid du Colombier reg = "(FP)";
332219b2ee8SDavid du Colombier }
333219b2ee8SDavid du Colombier if (store)
334219b2ee8SDavid du Colombier bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
335219b2ee8SDavid du Colombier else
336219b2ee8SDavid du Colombier bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
337219b2ee8SDavid du Colombier return 1;
338219b2ee8SDavid du Colombier }
339219b2ee8SDavid du Colombier
340219b2ee8SDavid du Colombier static void
lw(Opcode * o,Instr * i,char r)341219b2ee8SDavid du Colombier lw(Opcode *o, Instr *i, char r)
342219b2ee8SDavid du Colombier {
343219b2ee8SDavid du Colombier char *m;
344219b2ee8SDavid du Colombier
345219b2ee8SDavid du Colombier if (r == 'F') {
346219b2ee8SDavid du Colombier if (i->size == 2)
347219b2ee8SDavid du Colombier m = "MOVD";
348219b2ee8SDavid du Colombier else
349219b2ee8SDavid du Colombier m = "MOVF";
350219b2ee8SDavid du Colombier }
351219b2ee8SDavid du Colombier else
352219b2ee8SDavid du Colombier m = o->mnemonic;
353219b2ee8SDavid du Colombier if (i->rs == 29 && plocal(i, m, r, 0))
354219b2ee8SDavid du Colombier return;
355219b2ee8SDavid du Colombier
356219b2ee8SDavid du Colombier if (i->rs == 30 && mach->sb) {
357219b2ee8SDavid du Colombier bprint(i, "%s\t", m);
358219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
359219b2ee8SDavid du Colombier bprint(i, "(SB),%c%d", r, i->rt);
360219b2ee8SDavid du Colombier return;
361219b2ee8SDavid du Colombier }
362219b2ee8SDavid du Colombier if (r == 'F')
363219b2ee8SDavid du Colombier format(m, i, "%l,F%t");
364219b2ee8SDavid du Colombier else
365219b2ee8SDavid du Colombier format(m, i, o->ken);
366219b2ee8SDavid du Colombier }
367219b2ee8SDavid du Colombier
368219b2ee8SDavid du Colombier static void
load(Opcode * o,Instr * i)369219b2ee8SDavid du Colombier load(Opcode *o, Instr *i)
370219b2ee8SDavid du Colombier {
371219b2ee8SDavid du Colombier lw(o, i, 'R');
372219b2ee8SDavid du Colombier }
373219b2ee8SDavid du Colombier
374219b2ee8SDavid du Colombier static void
lwc1(Opcode * o,Instr * i)375219b2ee8SDavid du Colombier lwc1(Opcode *o, Instr *i)
376219b2ee8SDavid du Colombier {
377219b2ee8SDavid du Colombier lw(o, i, 'F');
378219b2ee8SDavid du Colombier }
379219b2ee8SDavid du Colombier
380219b2ee8SDavid du Colombier static void
sw(Opcode * o,Instr * i,char r)381219b2ee8SDavid du Colombier sw(Opcode *o, Instr *i, char r)
382219b2ee8SDavid du Colombier {
383219b2ee8SDavid du Colombier char *m;
384219b2ee8SDavid du Colombier
385219b2ee8SDavid du Colombier if (r == 'F') {
386219b2ee8SDavid du Colombier if (i->size == 2)
387219b2ee8SDavid du Colombier m = "MOVD";
388219b2ee8SDavid du Colombier else
389219b2ee8SDavid du Colombier m = "MOVF";
390219b2ee8SDavid du Colombier }
391219b2ee8SDavid du Colombier else
392219b2ee8SDavid du Colombier m = o->mnemonic;
393219b2ee8SDavid du Colombier if (i->rs == 29 && plocal(i, m, r, 1))
394219b2ee8SDavid du Colombier return;
395219b2ee8SDavid du Colombier
396219b2ee8SDavid du Colombier if (i->rs == 30 && mach->sb) {
397219b2ee8SDavid du Colombier bprint(i, "%s\t%c%d,", m, r, i->rt);
398219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
399219b2ee8SDavid du Colombier bprint(i, "(SB)");
400219b2ee8SDavid du Colombier return;
401219b2ee8SDavid du Colombier }
402219b2ee8SDavid du Colombier if (r == 'F')
403219b2ee8SDavid du Colombier format(m, i, "F%t,%l");
404219b2ee8SDavid du Colombier else
405219b2ee8SDavid du Colombier format(m, i, o->ken);
406219b2ee8SDavid du Colombier }
407219b2ee8SDavid du Colombier
408219b2ee8SDavid du Colombier static void
store(Opcode * o,Instr * i)409219b2ee8SDavid du Colombier store(Opcode *o, Instr *i)
410219b2ee8SDavid du Colombier {
411219b2ee8SDavid du Colombier sw(o, i, 'R');
412219b2ee8SDavid du Colombier }
413219b2ee8SDavid du Colombier
414219b2ee8SDavid du Colombier static void
swc1(Opcode * o,Instr * i)415219b2ee8SDavid du Colombier swc1(Opcode *o, Instr *i)
416219b2ee8SDavid du Colombier {
417219b2ee8SDavid du Colombier sw(o, i, 'F');
418219b2ee8SDavid du Colombier }
419219b2ee8SDavid du Colombier
420219b2ee8SDavid du Colombier static void
sll(Opcode * o,Instr * i)421219b2ee8SDavid du Colombier sll(Opcode *o, Instr *i)
422219b2ee8SDavid du Colombier {
423219b2ee8SDavid du Colombier if (i->w0 == 0)
424eaba85aaSDavid du Colombier bprint(i, "NOOP"); /* unofficial nop */
425eaba85aaSDavid du Colombier else if (i->w0 == 0xc0) /* 0xc0: SLL $3,R0 */
426eaba85aaSDavid du Colombier bprint(i, "EHB");
427219b2ee8SDavid du Colombier else if (i->rd == i->rt)
428219b2ee8SDavid du Colombier format(o->mnemonic, i, "$%a,R%d");
429219b2ee8SDavid du Colombier else
430219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
431219b2ee8SDavid du Colombier }
432219b2ee8SDavid du Colombier
433219b2ee8SDavid du Colombier static void
sl32(Opcode * o,Instr * i)434219b2ee8SDavid du Colombier sl32(Opcode *o, Instr *i)
435219b2ee8SDavid du Colombier {
436219b2ee8SDavid du Colombier i->sa += 32;
437219b2ee8SDavid du Colombier if (i->rd == i->rt)
438219b2ee8SDavid du Colombier format(o->mnemonic, i, "$%a,R%d");
439219b2ee8SDavid du Colombier else
440219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
441219b2ee8SDavid du Colombier }
442219b2ee8SDavid du Colombier
443219b2ee8SDavid du Colombier static void
sllv(Opcode * o,Instr * i)444219b2ee8SDavid du Colombier sllv(Opcode *o, Instr *i)
445219b2ee8SDavid du Colombier {
446219b2ee8SDavid du Colombier if (i->rd == i->rt)
447219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%s,R%d");
448219b2ee8SDavid du Colombier else
449219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
450219b2ee8SDavid du Colombier }
451219b2ee8SDavid du Colombier
452219b2ee8SDavid du Colombier static void
jal(Opcode * o,Instr * i)453219b2ee8SDavid du Colombier jal(Opcode *o, Instr *i)
454219b2ee8SDavid du Colombier {
455219b2ee8SDavid du Colombier if (i->rd == 31)
456219b2ee8SDavid du Colombier format("JAL", i, "(R%s)");
457219b2ee8SDavid du Colombier else
458219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
459219b2ee8SDavid du Colombier }
460219b2ee8SDavid du Colombier
461219b2ee8SDavid du Colombier static void
add(Opcode * o,Instr * i)462219b2ee8SDavid du Colombier add(Opcode *o, Instr *i)
463219b2ee8SDavid du Colombier {
464219b2ee8SDavid du Colombier if (i->rd == i->rs)
465219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%t,R%d");
466219b2ee8SDavid du Colombier else if (i->rd == i->rt)
467219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%s,R%d");
468219b2ee8SDavid du Colombier else
469219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
470219b2ee8SDavid du Colombier }
471219b2ee8SDavid du Colombier
472219b2ee8SDavid du Colombier static void
sub(Opcode * o,Instr * i)473219b2ee8SDavid du Colombier sub(Opcode *o, Instr *i)
474219b2ee8SDavid du Colombier {
475219b2ee8SDavid du Colombier if (i->rd == i->rs)
476219b2ee8SDavid du Colombier format(o->mnemonic, i, "R%t,R%d");
477219b2ee8SDavid du Colombier else
478219b2ee8SDavid du Colombier format(o->mnemonic, i, o->ken);
479219b2ee8SDavid du Colombier }
480219b2ee8SDavid du Colombier
481219b2ee8SDavid du Colombier static void
or(Opcode * o,Instr * i)482219b2ee8SDavid du Colombier or(Opcode *o, Instr *i)
483219b2ee8SDavid du Colombier {
484219b2ee8SDavid du Colombier if (i->rs == 0 && i->rt == 0)
485219b2ee8SDavid du Colombier format("MOVW", i, "$0,R%d");
486219b2ee8SDavid du Colombier else if (i->rs == 0)
487219b2ee8SDavid du Colombier format("MOVW", i, "R%t,R%d");
488219b2ee8SDavid du Colombier else if (i->rt == 0)
489219b2ee8SDavid du Colombier format("MOVW", i, "R%s,R%d");
490219b2ee8SDavid du Colombier else
491219b2ee8SDavid du Colombier add(o, i);
492219b2ee8SDavid du Colombier }
493219b2ee8SDavid du Colombier
494219b2ee8SDavid du Colombier static void
nor(Opcode * o,Instr * i)495219b2ee8SDavid du Colombier nor(Opcode *o, Instr *i)
496219b2ee8SDavid du Colombier {
497219b2ee8SDavid du Colombier if (i->rs == 0 && i->rt == 0 && i->rd == 0)
498219b2ee8SDavid du Colombier format("NOP", i, 0);
499219b2ee8SDavid du Colombier else
500219b2ee8SDavid du Colombier add(o, i);
501219b2ee8SDavid du Colombier }
502219b2ee8SDavid du Colombier
503219b2ee8SDavid du Colombier static char mipscoload[] = "r%t,%l";
504219b2ee8SDavid du Colombier static char mipsload[] = "%l,R%t";
505219b2ee8SDavid du Colombier static char mipsstore[] = "R%t,%l";
506219b2ee8SDavid du Colombier static char mipsalui[] = "%i,R%s,R%t";
507219b2ee8SDavid du Colombier static char mipsalu3op[] = "R%t,R%s,R%d";
508219b2ee8SDavid du Colombier static char mipsrtrs[] = "R%t,R%s";
509219b2ee8SDavid du Colombier static char mipscorsrt[] = "r%s,r%t";
510219b2ee8SDavid du Colombier static char mipscorsi[] = "r%s,%i";
511219b2ee8SDavid du Colombier static char mipscoxxx[] = "%w";
512219b2ee8SDavid du Colombier static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
513219b2ee8SDavid du Colombier static char mipsfp3[] = "F%t,F%d,F%a";
514219b2ee8SDavid du Colombier static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
515219b2ee8SDavid du Colombier static char mipsfp2[] = "F%d,F%a";
516219b2ee8SDavid du Colombier static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
517219b2ee8SDavid du Colombier static char mipsfpc[] = "F%t,F%d";
518219b2ee8SDavid du Colombier
519219b2ee8SDavid du Colombier static Opcode opcodes[64] = {
520219b2ee8SDavid du Colombier 0, 0, 0,
521219b2ee8SDavid du Colombier 0, 0, 0,
522219b2ee8SDavid du Colombier "JMP", 0, "%j",
523219b2ee8SDavid du Colombier "JAL", 0, "%j",
524219b2ee8SDavid du Colombier "BEQ", branch, 0,
525219b2ee8SDavid du Colombier "BNE", branch, 0,
526219b2ee8SDavid du Colombier "BLEZ", branch, 0,
527219b2ee8SDavid du Colombier "BGTZ", branch, 0,
528219b2ee8SDavid du Colombier "ADD", addi, mipsalui,
529219b2ee8SDavid du Colombier "ADDU", addi, mipsalui,
530219b2ee8SDavid du Colombier "SGT", 0, mipsalui,
531219b2ee8SDavid du Colombier "SGTU", 0, mipsalui,
532219b2ee8SDavid du Colombier "AND", andi, mipsalui,
533219b2ee8SDavid du Colombier "OR", andi, mipsalui,
534219b2ee8SDavid du Colombier "XOR", andi, mipsalui,
535219b2ee8SDavid du Colombier "MOVW", 0, "$%u,R%t",
536219b2ee8SDavid du Colombier "cop0", 0, 0,
537219b2ee8SDavid du Colombier "cop1", 0, 0,
538219b2ee8SDavid du Colombier "cop2", 0, 0,
539219b2ee8SDavid du Colombier "cop3", 0, 0,
540219b2ee8SDavid du Colombier "BEQL", branch, 0,
541219b2ee8SDavid du Colombier "BNEL", branch, 0,
542219b2ee8SDavid du Colombier "BLEZL", branch, 0,
543219b2ee8SDavid du Colombier "BGTZL", branch, 0,
544219b2ee8SDavid du Colombier "instr18", 0, mipscoxxx,
545219b2ee8SDavid du Colombier "instr19", 0, mipscoxxx,
546219b2ee8SDavid du Colombier "MOVVL", load, mipsload,
547219b2ee8SDavid du Colombier "MOVVR", load, mipsload,
548219b2ee8SDavid du Colombier "instr1C", 0, mipscoxxx,
549219b2ee8SDavid du Colombier "instr1D", 0, mipscoxxx,
550219b2ee8SDavid du Colombier "instr1E", 0, mipscoxxx,
551219b2ee8SDavid du Colombier "instr1F", 0, mipscoxxx,
552219b2ee8SDavid du Colombier "MOVB", load, mipsload,
553219b2ee8SDavid du Colombier "MOVH", load, mipsload,
554219b2ee8SDavid du Colombier "lwl", 0, mipscoload,
555219b2ee8SDavid du Colombier "MOVW", load, mipsload,
556219b2ee8SDavid du Colombier "MOVBU", load, mipsload,
557219b2ee8SDavid du Colombier "MOVHU", load, mipsload,
558219b2ee8SDavid du Colombier "lwr", 0, mipscoload,
559219b2ee8SDavid du Colombier "instr27", 0, mipscoxxx,
560219b2ee8SDavid du Colombier "MOVB", store, mipsstore,
561219b2ee8SDavid du Colombier "MOVH", store, mipsstore,
562219b2ee8SDavid du Colombier "swl", 0, mipscoload,
563219b2ee8SDavid du Colombier "MOVW", store, mipsstore,
564219b2ee8SDavid du Colombier "MOVVL", store, mipsstore,
565219b2ee8SDavid du Colombier "MOVVR", store, mipsstore,
566219b2ee8SDavid du Colombier "swr", 0, mipscoload,
567219b2ee8SDavid du Colombier "CACHE", 0, "%C,%l",
568219b2ee8SDavid du Colombier "ll", 0, mipscoload,
569219b2ee8SDavid du Colombier "MOVW", lwc1, mipscoload,
570219b2ee8SDavid du Colombier "lwc2", 0, mipscoload,
571219b2ee8SDavid du Colombier "lwc3", 0, mipscoload,
572219b2ee8SDavid du Colombier "instr34", 0, mipscoxxx,
573219b2ee8SDavid du Colombier "ldc1", 0, mipscoload,
574219b2ee8SDavid du Colombier "ldc2", 0, mipscoload,
575219b2ee8SDavid du Colombier "MOVV", load, mipsload,
576219b2ee8SDavid du Colombier "sc", 0, mipscoload,
577219b2ee8SDavid du Colombier "swc1", swc1, mipscoload,
578219b2ee8SDavid du Colombier "swc2", 0, mipscoload,
579219b2ee8SDavid du Colombier "swc3", 0, mipscoload,
580219b2ee8SDavid du Colombier "instr3C", 0, mipscoxxx,
581219b2ee8SDavid du Colombier "sdc1", 0, mipscoload,
582219b2ee8SDavid du Colombier "sdc2", 0, mipscoload,
583219b2ee8SDavid du Colombier "MOVV", store, mipsstore,
584219b2ee8SDavid du Colombier };
585219b2ee8SDavid du Colombier
586219b2ee8SDavid du Colombier static Opcode sopcodes[64] = {
587219b2ee8SDavid du Colombier "SLL", sll, "$%a,R%t,R%d",
588219b2ee8SDavid du Colombier "special01", 0, mipscoxxx,
589219b2ee8SDavid du Colombier "SRL", sll, "$%a,R%t,R%d",
590219b2ee8SDavid du Colombier "SRA", sll, "$%a,R%t,R%d",
591219b2ee8SDavid du Colombier "SLL", sllv, "R%s,R%t,R%d",
592219b2ee8SDavid du Colombier "special05", 0, mipscoxxx,
593219b2ee8SDavid du Colombier "SRL", sllv, "R%s,R%t,R%d",
594219b2ee8SDavid du Colombier "SRA", sllv, "R%s,R%t,R%d",
595219b2ee8SDavid du Colombier "JMP", 0, "(R%s)",
596219b2ee8SDavid du Colombier "jal", jal, "r%d,r%s",
597219b2ee8SDavid du Colombier "special0A", 0, mipscoxxx,
598219b2ee8SDavid du Colombier "special0B", 0, mipscoxxx,
599219b2ee8SDavid du Colombier "SYSCALL", 0, 0,
600219b2ee8SDavid du Colombier "BREAK", 0, 0,
601219b2ee8SDavid du Colombier "special0E", 0, mipscoxxx,
602219b2ee8SDavid du Colombier "SYNC", 0, 0,
603219b2ee8SDavid du Colombier "MOVW", 0, "HI,R%d",
604219b2ee8SDavid du Colombier "MOVW", 0, "R%s,HI",
605219b2ee8SDavid du Colombier "MOVW", 0, "LO,R%d",
606219b2ee8SDavid du Colombier "MOVW", 0, "R%s,LO",
607219b2ee8SDavid du Colombier "SLLV", sllv, "R%s,R%t,R%d",
608219b2ee8SDavid du Colombier "special15", 0, mipscoxxx,
609219b2ee8SDavid du Colombier "SRLV", sllv, "R%s,R%t,R%d",
610219b2ee8SDavid du Colombier "SRAV", sllv, "R%s,R%t,R%d",
611219b2ee8SDavid du Colombier "MUL", 0, mipsrtrs,
612219b2ee8SDavid du Colombier "MULU", 0, mipsrtrs,
613219b2ee8SDavid du Colombier "DIV", 0, mipsrtrs,
614219b2ee8SDavid du Colombier "DIVU", 0, mipsrtrs,
615219b2ee8SDavid du Colombier "special1C", 0, mipscoxxx,
616219b2ee8SDavid du Colombier "special1D", 0, mipscoxxx,
6177dd7cddfSDavid du Colombier "DDIV", 0, "R%s,R%t",
618219b2ee8SDavid du Colombier "special1F", 0, mipscoxxx,
619219b2ee8SDavid du Colombier "ADD", add, mipsalu3op,
620219b2ee8SDavid du Colombier "ADDU", add, mipsalu3op,
621219b2ee8SDavid du Colombier "SUB", sub, mipsalu3op,
622219b2ee8SDavid du Colombier "SUBU", sub, mipsalu3op,
623219b2ee8SDavid du Colombier "AND", add, mipsalu3op,
624219b2ee8SDavid du Colombier "OR", or, mipsalu3op,
625219b2ee8SDavid du Colombier "XOR", add, mipsalu3op,
626219b2ee8SDavid du Colombier "NOR", nor, mipsalu3op,
627219b2ee8SDavid du Colombier "special28", 0, mipscoxxx,
628219b2ee8SDavid du Colombier "special29", 0, mipscoxxx,
629219b2ee8SDavid du Colombier "SGT", 0, mipsalu3op,
630219b2ee8SDavid du Colombier "SGTU", 0, mipsalu3op,
631219b2ee8SDavid du Colombier "special2C", 0, mipscoxxx,
632219b2ee8SDavid du Colombier "special2D", 0, mipscoxxx,
633219b2ee8SDavid du Colombier "special2E", 0, mipscoxxx,
6347dd7cddfSDavid du Colombier "DSUBU", 0, "R%s,R%t,R%d",
635219b2ee8SDavid du Colombier "tge", 0, mipscorsrt,
636219b2ee8SDavid du Colombier "tgeu", 0, mipscorsrt,
637219b2ee8SDavid du Colombier "tlt", 0, mipscorsrt,
638219b2ee8SDavid du Colombier "tltu", 0, mipscorsrt,
639219b2ee8SDavid du Colombier "teq", 0, mipscorsrt,
640219b2ee8SDavid du Colombier "special35", 0, mipscoxxx,
641219b2ee8SDavid du Colombier "tne", 0, mipscorsrt,
642219b2ee8SDavid du Colombier "special37", 0, mipscoxxx,
643219b2ee8SDavid du Colombier "SLLV", sll, "$%a,R%t,R%d",
644219b2ee8SDavid du Colombier "special39", 0, mipscoxxx,
645219b2ee8SDavid du Colombier "SRLV", sll, "$%a,R%t,R%d",
646219b2ee8SDavid du Colombier "SRAV", sll, "$%a,R%t,R%d",
647219b2ee8SDavid du Colombier "SLLV", sl32, "$%a,R%t,R%d",
648219b2ee8SDavid du Colombier "special3D", 0, mipscoxxx,
649219b2ee8SDavid du Colombier "SRLV", sl32, "$%a,R%t,R%d",
650219b2ee8SDavid du Colombier "SRAV", sl32, "$%a,R%t,R%d",
651219b2ee8SDavid du Colombier };
652219b2ee8SDavid du Colombier
653219b2ee8SDavid du Colombier static Opcode ropcodes[32] = {
654219b2ee8SDavid du Colombier "BLTZ", branch, 0,
655219b2ee8SDavid du Colombier "BGEZ", branch, 0,
656219b2ee8SDavid du Colombier "BLTZL", branch, 0,
657219b2ee8SDavid du Colombier "BGEZL", branch, 0,
658219b2ee8SDavid du Colombier "regimm04", 0, mipscoxxx,
659219b2ee8SDavid du Colombier "regimm05", 0, mipscoxxx,
660219b2ee8SDavid du Colombier "regimm06", 0, mipscoxxx,
661219b2ee8SDavid du Colombier "regimm07", 0, mipscoxxx,
662219b2ee8SDavid du Colombier "tgei", 0, mipscorsi,
663219b2ee8SDavid du Colombier "tgeiu", 0, mipscorsi,
664219b2ee8SDavid du Colombier "tlti", 0, mipscorsi,
665219b2ee8SDavid du Colombier "tltiu", 0, mipscorsi,
666219b2ee8SDavid du Colombier "teqi", 0, mipscorsi,
667219b2ee8SDavid du Colombier "regimm0D", 0, mipscoxxx,
668219b2ee8SDavid du Colombier "tnei", 0, mipscorsi,
669219b2ee8SDavid du Colombier "regimm0F", 0, mipscoxxx,
670219b2ee8SDavid du Colombier "BLTZAL", branch, 0,
671219b2ee8SDavid du Colombier "BGEZAL", branch, 0,
672219b2ee8SDavid du Colombier "BLTZALL", branch, 0,
673219b2ee8SDavid du Colombier "BGEZALL", branch, 0,
674219b2ee8SDavid du Colombier "regimm14", 0, mipscoxxx,
675219b2ee8SDavid du Colombier "regimm15", 0, mipscoxxx,
676219b2ee8SDavid du Colombier "regimm16", 0, mipscoxxx,
677219b2ee8SDavid du Colombier "regimm17", 0, mipscoxxx,
678219b2ee8SDavid du Colombier "regimm18", 0, mipscoxxx,
679219b2ee8SDavid du Colombier "regimm19", 0, mipscoxxx,
680219b2ee8SDavid du Colombier "regimm1A", 0, mipscoxxx,
681219b2ee8SDavid du Colombier "regimm1B", 0, mipscoxxx,
682219b2ee8SDavid du Colombier "regimm1C", 0, mipscoxxx,
683219b2ee8SDavid du Colombier "regimm1D", 0, mipscoxxx,
684219b2ee8SDavid du Colombier "regimm1E", 0, mipscoxxx,
685219b2ee8SDavid du Colombier "regimm1F", 0, mipscoxxx,
686219b2ee8SDavid du Colombier };
687219b2ee8SDavid du Colombier
688219b2ee8SDavid du Colombier static Opcode fopcodes[64] = {
689219b2ee8SDavid du Colombier "ADD%f", 0, mipsfp3,
690219b2ee8SDavid du Colombier "SUB%f", 0, mipsfp3,
691219b2ee8SDavid du Colombier "MUL%f", 0, mipsfp3,
692219b2ee8SDavid du Colombier "DIV%f", 0, mipsfp3,
693219b2ee8SDavid du Colombier "sqrt.%f", 0, mipscofp2,
694219b2ee8SDavid du Colombier "ABS%f", 0, mipsfp2,
695219b2ee8SDavid du Colombier "MOV%f", 0, mipsfp2,
696219b2ee8SDavid du Colombier "NEG%f", 0, mipsfp2,
697219b2ee8SDavid du Colombier "finstr08", 0, mipscoxxx,
698219b2ee8SDavid du Colombier "finstr09", 0, mipscoxxx,
699219b2ee8SDavid du Colombier "finstr0A", 0, mipscoxxx,
700219b2ee8SDavid du Colombier "finstr0B", 0, mipscoxxx,
701219b2ee8SDavid du Colombier "round.w.%f", 0, mipscofp2,
702219b2ee8SDavid du Colombier "trunc.w%f", 0, mipscofp2,
703219b2ee8SDavid du Colombier "ceil.w%f", 0, mipscofp2,
704219b2ee8SDavid du Colombier "floor.w%f", 0, mipscofp2,
705219b2ee8SDavid du Colombier "finstr10", 0, mipscoxxx,
706219b2ee8SDavid du Colombier "finstr11", 0, mipscoxxx,
707219b2ee8SDavid du Colombier "finstr12", 0, mipscoxxx,
708219b2ee8SDavid du Colombier "finstr13", 0, mipscoxxx,
709219b2ee8SDavid du Colombier "finstr14", 0, mipscoxxx,
710219b2ee8SDavid du Colombier "finstr15", 0, mipscoxxx,
711219b2ee8SDavid du Colombier "finstr16", 0, mipscoxxx,
712219b2ee8SDavid du Colombier "finstr17", 0, mipscoxxx,
713219b2ee8SDavid du Colombier "finstr18", 0, mipscoxxx,
714219b2ee8SDavid du Colombier "finstr19", 0, mipscoxxx,
715219b2ee8SDavid du Colombier "finstr1A", 0, mipscoxxx,
716219b2ee8SDavid du Colombier "finstr1B", 0, mipscoxxx,
717219b2ee8SDavid du Colombier "finstr1C", 0, mipscoxxx,
718219b2ee8SDavid du Colombier "finstr1D", 0, mipscoxxx,
719219b2ee8SDavid du Colombier "finstr1E", 0, mipscoxxx,
720219b2ee8SDavid du Colombier "finstr1F", 0, mipscoxxx,
721219b2ee8SDavid du Colombier "cvt.s.%f", 0, mipscofp2,
722219b2ee8SDavid du Colombier "cvt.d.%f", 0, mipscofp2,
723219b2ee8SDavid du Colombier "cvt.e.%f", 0, mipscofp2,
724219b2ee8SDavid du Colombier "cvt.q.%f", 0, mipscofp2,
725219b2ee8SDavid du Colombier "cvt.w.%f", 0, mipscofp2,
726219b2ee8SDavid du Colombier "finstr25", 0, mipscoxxx,
727219b2ee8SDavid du Colombier "finstr26", 0, mipscoxxx,
728219b2ee8SDavid du Colombier "finstr27", 0, mipscoxxx,
729219b2ee8SDavid du Colombier "finstr28", 0, mipscoxxx,
730219b2ee8SDavid du Colombier "finstr29", 0, mipscoxxx,
731219b2ee8SDavid du Colombier "finstr2A", 0, mipscoxxx,
732219b2ee8SDavid du Colombier "finstr2B", 0, mipscoxxx,
733219b2ee8SDavid du Colombier "finstr2C", 0, mipscoxxx,
734219b2ee8SDavid du Colombier "finstr2D", 0, mipscoxxx,
735219b2ee8SDavid du Colombier "finstr2E", 0, mipscoxxx,
736219b2ee8SDavid du Colombier "finstr2F", 0, mipscoxxx,
737219b2ee8SDavid du Colombier "c.f.%f", 0, mipscofpc,
738219b2ee8SDavid du Colombier "c.un.%f", 0, mipscofpc,
739219b2ee8SDavid du Colombier "CMPEQ%f", 0, mipsfpc,
740219b2ee8SDavid du Colombier "c.ueq.%f", 0, mipscofpc,
741219b2ee8SDavid du Colombier "c.olt.%f", 0, mipscofpc,
742219b2ee8SDavid du Colombier "c.ult.%f", 0, mipscofpc,
743219b2ee8SDavid du Colombier "c.ole.%f", 0, mipscofpc,
744219b2ee8SDavid du Colombier "c.ule.%f", 0, mipscofpc,
745219b2ee8SDavid du Colombier "c.sf.%f", 0, mipscofpc,
746219b2ee8SDavid du Colombier "c.ngle.%f", 0, mipscofpc,
747219b2ee8SDavid du Colombier "c.seq.%f", 0, mipscofpc,
748219b2ee8SDavid du Colombier "c.ngl.%f", 0, mipscofpc,
749219b2ee8SDavid du Colombier "CMPGT%f", 0, mipsfpc,
750219b2ee8SDavid du Colombier "c.nge.%f", 0, mipscofpc,
751219b2ee8SDavid du Colombier "CMPGE%f", 0, mipsfpc,
752219b2ee8SDavid du Colombier "c.ngt.%f", 0, mipscofpc,
753219b2ee8SDavid du Colombier };
754219b2ee8SDavid du Colombier
755219b2ee8SDavid du Colombier static char *cop0regs[32] = {
756219b2ee8SDavid du Colombier "INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
757219b2ee8SDavid du Colombier "CONTEXT", "PageMask", "Wired", "Error",
758219b2ee8SDavid du Colombier "BADVADDR", "Count", "TLBVIRT", "Compare",
759219b2ee8SDavid du Colombier "STATUS", "CAUSE", "EPC", "PRID",
760219b2ee8SDavid du Colombier "Config", "LLadr", "WatchLo", "WatchHi",
761219b2ee8SDavid du Colombier "20", "21", "22", "23",
762219b2ee8SDavid du Colombier "24", "25", "26", "CacheErr",
763219b2ee8SDavid du Colombier "TagLo", "TagHi", "ErrorEPC", "31"
764219b2ee8SDavid du Colombier };
765219b2ee8SDavid du Colombier
766219b2ee8SDavid du Colombier static char fsub[16] = {
767219b2ee8SDavid du Colombier 'F', 'D', 'e', 'q', 'W', '?', '?', '?',
768219b2ee8SDavid du Colombier '?', '?', '?', '?', '?', '?', '?', '?'
769219b2ee8SDavid du Colombier };
770219b2ee8SDavid du Colombier
771219b2ee8SDavid du Colombier static char *cacheps[] = {
772219b2ee8SDavid du Colombier "I", "D", "SI", "SD"
773219b2ee8SDavid du Colombier };
774219b2ee8SDavid du Colombier
775219b2ee8SDavid du Colombier static char *cacheop[] = {
776219b2ee8SDavid du Colombier "IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
777219b2ee8SDavid du Colombier };
778219b2ee8SDavid du Colombier
779219b2ee8SDavid du Colombier static void
format(char * mnemonic,Instr * i,char * f)780219b2ee8SDavid du Colombier format(char *mnemonic, Instr *i, char *f)
781219b2ee8SDavid du Colombier {
782219b2ee8SDavid du Colombier if (mnemonic)
783219b2ee8SDavid du Colombier format(0, i, mnemonic);
784219b2ee8SDavid du Colombier if (f == 0)
785219b2ee8SDavid du Colombier return;
786219b2ee8SDavid du Colombier if (mnemonic)
787219b2ee8SDavid du Colombier if (i->curr < i->end)
788219b2ee8SDavid du Colombier *i->curr++ = '\t';
789219b2ee8SDavid du Colombier for ( ; *f && i->curr < i->end; f++) {
790219b2ee8SDavid du Colombier if (*f != '%') {
791219b2ee8SDavid du Colombier *i->curr++ = *f;
792219b2ee8SDavid du Colombier continue;
793219b2ee8SDavid du Colombier }
794219b2ee8SDavid du Colombier switch (*++f) {
795219b2ee8SDavid du Colombier
796219b2ee8SDavid du Colombier case 's':
797219b2ee8SDavid du Colombier bprint(i, "%d", i->rs);
798219b2ee8SDavid du Colombier break;
799219b2ee8SDavid du Colombier
800219b2ee8SDavid du Colombier case 't':
801219b2ee8SDavid du Colombier bprint(i, "%d", i->rt);
802219b2ee8SDavid du Colombier break;
803219b2ee8SDavid du Colombier
804219b2ee8SDavid du Colombier case 'd':
805219b2ee8SDavid du Colombier bprint(i, "%d", i->rd);
806219b2ee8SDavid du Colombier break;
807219b2ee8SDavid du Colombier
808219b2ee8SDavid du Colombier case 'a':
809219b2ee8SDavid du Colombier bprint(i, "%d", i->sa);
810219b2ee8SDavid du Colombier break;
811219b2ee8SDavid du Colombier
812219b2ee8SDavid du Colombier case 'l':
813219b2ee8SDavid du Colombier bprint(i, "%lx(R%d)",i->immediate, i->rs);
814219b2ee8SDavid du Colombier break;
815219b2ee8SDavid du Colombier
816219b2ee8SDavid du Colombier case 'i':
817219b2ee8SDavid du Colombier bprint(i, "$%lx", i->immediate);
818219b2ee8SDavid du Colombier break;
819219b2ee8SDavid du Colombier
820219b2ee8SDavid du Colombier case 'u':
821219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
822219b2ee8SDavid du Colombier bprint(i, "(SB)");
823219b2ee8SDavid du Colombier break;
824219b2ee8SDavid du Colombier
825219b2ee8SDavid du Colombier case 'j':
826219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr,
827219b2ee8SDavid du Colombier (i->target<<2)|(i->addr & 0xF0000000), CANY);
828219b2ee8SDavid du Colombier bprint(i, "(SB)");
829219b2ee8SDavid du Colombier break;
830219b2ee8SDavid du Colombier
831219b2ee8SDavid du Colombier case 'b':
832219b2ee8SDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr,
833219b2ee8SDavid du Colombier (i->immediate<<2)+i->addr+4, CANY);
834219b2ee8SDavid du Colombier break;
835219b2ee8SDavid du Colombier
836219b2ee8SDavid du Colombier case 'c':
837219b2ee8SDavid du Colombier bprint(i, "$%lx", i->cofun);
838219b2ee8SDavid du Colombier break;
839219b2ee8SDavid du Colombier
840219b2ee8SDavid du Colombier case 'w':
841219b2ee8SDavid du Colombier bprint(i, "[%lux]", i->w0);
842219b2ee8SDavid du Colombier break;
843219b2ee8SDavid du Colombier
844219b2ee8SDavid du Colombier case 'm':
845219b2ee8SDavid du Colombier bprint(i, "M(%s)", cop0regs[i->rd]);
846219b2ee8SDavid du Colombier break;
847219b2ee8SDavid du Colombier
848219b2ee8SDavid du Colombier case 'f':
849219b2ee8SDavid du Colombier *i->curr++ = fsub[i->rs & 0x0F];
850219b2ee8SDavid du Colombier break;
851219b2ee8SDavid du Colombier
852219b2ee8SDavid du Colombier case 'C':
853219b2ee8SDavid du Colombier bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
854219b2ee8SDavid du Colombier break;
855219b2ee8SDavid du Colombier
856219b2ee8SDavid du Colombier case '\0':
857219b2ee8SDavid du Colombier *i->curr++ = '%';
858219b2ee8SDavid du Colombier return;
859219b2ee8SDavid du Colombier
860219b2ee8SDavid du Colombier default:
861219b2ee8SDavid du Colombier bprint(i, "%%%c", *f);
862219b2ee8SDavid du Colombier break;
863219b2ee8SDavid du Colombier }
864219b2ee8SDavid du Colombier }
865219b2ee8SDavid du Colombier *i->curr = 0;
866219b2ee8SDavid du Colombier }
867219b2ee8SDavid du Colombier
868219b2ee8SDavid du Colombier static void
copz(int cop,Instr * i)869219b2ee8SDavid du Colombier copz(int cop, Instr *i)
870219b2ee8SDavid du Colombier {
871219b2ee8SDavid du Colombier char *f, *m, buf[16];
872219b2ee8SDavid du Colombier
873219b2ee8SDavid du Colombier m = buf;
874219b2ee8SDavid du Colombier f = "%t,%d";
875219b2ee8SDavid du Colombier switch (i->rs) {
876219b2ee8SDavid du Colombier
877219b2ee8SDavid du Colombier case 0:
878219b2ee8SDavid du Colombier sprint(buf, "mfc%d", cop);
879219b2ee8SDavid du Colombier break;
880219b2ee8SDavid du Colombier
881219b2ee8SDavid du Colombier case 2:
882219b2ee8SDavid du Colombier sprint(buf, "cfc%d", cop);
883219b2ee8SDavid du Colombier break;
884219b2ee8SDavid du Colombier
885219b2ee8SDavid du Colombier case 4:
886219b2ee8SDavid du Colombier sprint(buf, "mtc%d", cop);
887219b2ee8SDavid du Colombier break;
888219b2ee8SDavid du Colombier
889219b2ee8SDavid du Colombier case 6:
890219b2ee8SDavid du Colombier sprint(buf, "ctc%d", cop);
891219b2ee8SDavid du Colombier break;
892219b2ee8SDavid du Colombier
893219b2ee8SDavid du Colombier case 8:
894219b2ee8SDavid du Colombier f = "%b";
895219b2ee8SDavid du Colombier switch (i->rt) {
896219b2ee8SDavid du Colombier
897219b2ee8SDavid du Colombier case 0:
898219b2ee8SDavid du Colombier sprint(buf, "bc%df", cop);
899219b2ee8SDavid du Colombier break;
900219b2ee8SDavid du Colombier
901219b2ee8SDavid du Colombier case 1:
902219b2ee8SDavid du Colombier sprint(buf, "bc%dt", cop);
903219b2ee8SDavid du Colombier break;
904219b2ee8SDavid du Colombier
905219b2ee8SDavid du Colombier case 2:
906219b2ee8SDavid du Colombier sprint(buf, "bc%dfl", cop);
907219b2ee8SDavid du Colombier break;
908219b2ee8SDavid du Colombier
909219b2ee8SDavid du Colombier case 3:
910219b2ee8SDavid du Colombier sprint(buf, "bc%dtl", cop);
911219b2ee8SDavid du Colombier break;
912219b2ee8SDavid du Colombier
913219b2ee8SDavid du Colombier default:
914219b2ee8SDavid du Colombier sprint(buf, "cop%d", cop);
915219b2ee8SDavid du Colombier f = mipscoxxx;
916219b2ee8SDavid du Colombier break;
917219b2ee8SDavid du Colombier }
918219b2ee8SDavid du Colombier break;
919219b2ee8SDavid du Colombier
920219b2ee8SDavid du Colombier default:
921219b2ee8SDavid du Colombier sprint(buf, "cop%d", cop);
922219b2ee8SDavid du Colombier if (i->rs & 0x10)
923219b2ee8SDavid du Colombier f = "function %c";
924219b2ee8SDavid du Colombier else
925219b2ee8SDavid du Colombier f = mipscoxxx;
926219b2ee8SDavid du Colombier break;
927219b2ee8SDavid du Colombier }
928219b2ee8SDavid du Colombier format(m, i, f);
929219b2ee8SDavid du Colombier }
930219b2ee8SDavid du Colombier
931219b2ee8SDavid du Colombier static void
cop0(Instr * i)932219b2ee8SDavid du Colombier cop0(Instr *i)
933219b2ee8SDavid du Colombier {
934219b2ee8SDavid du Colombier char *m = 0;
935219b2ee8SDavid du Colombier
936219b2ee8SDavid du Colombier if (i->rs < 8) {
937219b2ee8SDavid du Colombier switch (i->rs) {
938219b2ee8SDavid du Colombier
939219b2ee8SDavid du Colombier case 0:
940219b2ee8SDavid du Colombier case 1:
941219b2ee8SDavid du Colombier format("MOVW", i, "%m,R%t");
942219b2ee8SDavid du Colombier return;
943219b2ee8SDavid du Colombier
944219b2ee8SDavid du Colombier case 4:
945219b2ee8SDavid du Colombier case 5:
946219b2ee8SDavid du Colombier format("MOVW", i, "R%t,%m");
947219b2ee8SDavid du Colombier return;
948219b2ee8SDavid du Colombier }
949219b2ee8SDavid du Colombier }
950219b2ee8SDavid du Colombier else if (i->rs >= 0x10) {
951219b2ee8SDavid du Colombier switch (i->cofun) {
952219b2ee8SDavid du Colombier
953219b2ee8SDavid du Colombier case 1:
954219b2ee8SDavid du Colombier m = "TLBR";
955219b2ee8SDavid du Colombier break;
956219b2ee8SDavid du Colombier
957219b2ee8SDavid du Colombier case 2:
958219b2ee8SDavid du Colombier m = "TLBWI";
959219b2ee8SDavid du Colombier break;
960219b2ee8SDavid du Colombier
961219b2ee8SDavid du Colombier case 6:
962219b2ee8SDavid du Colombier m = "TLBWR";
963219b2ee8SDavid du Colombier break;
964219b2ee8SDavid du Colombier
965219b2ee8SDavid du Colombier case 8:
966219b2ee8SDavid du Colombier m = "TLBP";
967219b2ee8SDavid du Colombier break;
968219b2ee8SDavid du Colombier
969219b2ee8SDavid du Colombier case 16:
970219b2ee8SDavid du Colombier m = "RFE";
971219b2ee8SDavid du Colombier break;
972219b2ee8SDavid du Colombier
973eaba85aaSDavid du Colombier case 24:
974219b2ee8SDavid du Colombier m = "ERET";
975219b2ee8SDavid du Colombier break;
976eaba85aaSDavid du Colombier
977eaba85aaSDavid du Colombier case 32:
978eaba85aaSDavid du Colombier m = "WAIT";
979eaba85aaSDavid du Colombier break;
980219b2ee8SDavid du Colombier }
981219b2ee8SDavid du Colombier if (m) {
982219b2ee8SDavid du Colombier format(m, i, 0);
983219b2ee8SDavid du Colombier return;
984219b2ee8SDavid du Colombier }
985219b2ee8SDavid du Colombier }
986219b2ee8SDavid du Colombier copz(0, i);
987219b2ee8SDavid du Colombier }
988219b2ee8SDavid du Colombier
989219b2ee8SDavid du Colombier static void
cop1(Instr * i)990219b2ee8SDavid du Colombier cop1(Instr *i)
991219b2ee8SDavid du Colombier {
992219b2ee8SDavid du Colombier char *m = "MOVW";
993219b2ee8SDavid du Colombier
994219b2ee8SDavid du Colombier switch (i->rs) {
995219b2ee8SDavid du Colombier
996219b2ee8SDavid du Colombier case 0:
997219b2ee8SDavid du Colombier format(m, i, "F%d,R%t");
998219b2ee8SDavid du Colombier return;
999219b2ee8SDavid du Colombier
1000219b2ee8SDavid du Colombier case 2:
1001219b2ee8SDavid du Colombier format(m, i, "FCR%d,R%t");
1002219b2ee8SDavid du Colombier return;
1003219b2ee8SDavid du Colombier
1004219b2ee8SDavid du Colombier case 4:
1005219b2ee8SDavid du Colombier format(m, i, "R%t,F%d");
1006219b2ee8SDavid du Colombier return;
1007219b2ee8SDavid du Colombier
1008219b2ee8SDavid du Colombier case 6:
1009219b2ee8SDavid du Colombier format(m, i, "R%t,FCR%d");
1010219b2ee8SDavid du Colombier return;
1011219b2ee8SDavid du Colombier
1012219b2ee8SDavid du Colombier case 8:
1013219b2ee8SDavid du Colombier switch (i->rt) {
1014219b2ee8SDavid du Colombier
1015219b2ee8SDavid du Colombier case 0:
1016219b2ee8SDavid du Colombier format("BFPF", i, "%b");
1017219b2ee8SDavid du Colombier return;
1018219b2ee8SDavid du Colombier
1019219b2ee8SDavid du Colombier case 1:
1020219b2ee8SDavid du Colombier format("BFPT", i, "%b");
1021219b2ee8SDavid du Colombier return;
1022219b2ee8SDavid du Colombier }
1023219b2ee8SDavid du Colombier break;
1024219b2ee8SDavid du Colombier }
1025219b2ee8SDavid du Colombier copz(1, i);
1026219b2ee8SDavid du Colombier }
1027219b2ee8SDavid du Colombier
1028219b2ee8SDavid du Colombier static int
printins(Map * map,uvlong pc,char * buf,int n)10294de34a7eSDavid du Colombier printins(Map *map, uvlong pc, char *buf, int n)
1030219b2ee8SDavid du Colombier {
1031219b2ee8SDavid du Colombier Instr i;
1032219b2ee8SDavid du Colombier Opcode *o;
1033219b2ee8SDavid du Colombier uchar op;
1034219b2ee8SDavid du Colombier
1035219b2ee8SDavid du Colombier i.curr = buf;
1036219b2ee8SDavid du Colombier i.end = buf+n-1;
1037219b2ee8SDavid du Colombier mymap = map;
1038219b2ee8SDavid du Colombier if (mkinstr(pc, &i) < 0)
1039219b2ee8SDavid du Colombier return -1;
1040219b2ee8SDavid du Colombier switch (i.op) {
1041219b2ee8SDavid du Colombier
1042219b2ee8SDavid du Colombier case 0x00: /* SPECIAL */
1043219b2ee8SDavid du Colombier o = sopcodes;
1044219b2ee8SDavid du Colombier op = i.function;
1045219b2ee8SDavid du Colombier break;
1046219b2ee8SDavid du Colombier
1047219b2ee8SDavid du Colombier case 0x01: /* REGIMM */
1048219b2ee8SDavid du Colombier o = ropcodes;
1049219b2ee8SDavid du Colombier op = i.rt;
1050219b2ee8SDavid du Colombier break;
1051219b2ee8SDavid du Colombier
1052219b2ee8SDavid du Colombier case 0x10: /* COP0 */
1053219b2ee8SDavid du Colombier cop0(&i);
1054219b2ee8SDavid du Colombier return i.size*4;
1055219b2ee8SDavid du Colombier
1056219b2ee8SDavid du Colombier case 0x11: /* COP1 */
1057219b2ee8SDavid du Colombier if (i.rs & 0x10) {
1058219b2ee8SDavid du Colombier o = fopcodes;
1059219b2ee8SDavid du Colombier op = i.function;
1060219b2ee8SDavid du Colombier break;
1061219b2ee8SDavid du Colombier }
1062219b2ee8SDavid du Colombier cop1(&i);
1063219b2ee8SDavid du Colombier return i.size*4;
1064219b2ee8SDavid du Colombier
1065219b2ee8SDavid du Colombier case 0x12: /* COP2 */
1066219b2ee8SDavid du Colombier case 0x13: /* COP3 */
1067219b2ee8SDavid du Colombier copz(i.op-0x10, &i);
1068219b2ee8SDavid du Colombier return i.size*4;
1069219b2ee8SDavid du Colombier
1070219b2ee8SDavid du Colombier default:
1071219b2ee8SDavid du Colombier o = opcodes;
1072219b2ee8SDavid du Colombier op = i.op;
1073219b2ee8SDavid du Colombier break;
1074219b2ee8SDavid du Colombier }
1075219b2ee8SDavid du Colombier if (o[op].f)
1076219b2ee8SDavid du Colombier (*o[op].f)(&o[op], &i);
1077219b2ee8SDavid du Colombier else
1078219b2ee8SDavid du Colombier format(o[op].mnemonic, &i, o[op].ken);
1079219b2ee8SDavid du Colombier return i.size*4;
1080219b2ee8SDavid du Colombier }
1081219b2ee8SDavid du Colombier
10824de34a7eSDavid du Colombier extern int _mipscoinst(Map *, uvlong, char*, int);
1083219b2ee8SDavid du Colombier
1084219b2ee8SDavid du Colombier /* modifier 'I' toggles the default disassembler type */
1085219b2ee8SDavid du Colombier static int
mipsinst(Map * map,uvlong pc,char modifier,char * buf,int n)10864de34a7eSDavid du Colombier mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1087219b2ee8SDavid du Colombier {
1088219b2ee8SDavid du Colombier if ((asstype == AMIPSCO && modifier == 'i')
1089219b2ee8SDavid du Colombier || (asstype == AMIPS && modifier == 'I'))
1090219b2ee8SDavid du Colombier return _mipscoinst(map, pc, buf, n);
1091219b2ee8SDavid du Colombier else
1092219b2ee8SDavid du Colombier return printins(map, pc, buf, n);
1093219b2ee8SDavid du Colombier }
1094219b2ee8SDavid du Colombier
1095219b2ee8SDavid du Colombier static int
mipsdas(Map * map,uvlong pc,char * buf,int n)10964de34a7eSDavid du Colombier mipsdas(Map *map, uvlong pc, char *buf, int n)
1097219b2ee8SDavid du Colombier {
1098219b2ee8SDavid du Colombier Instr i;
1099219b2ee8SDavid du Colombier
1100219b2ee8SDavid du Colombier i.curr = buf;
1101219b2ee8SDavid du Colombier i.end = buf+n;
1102219b2ee8SDavid du Colombier mymap = map;
1103219b2ee8SDavid du Colombier if (mkinstr(pc, &i) < 0)
1104219b2ee8SDavid du Colombier return -1;
1105219b2ee8SDavid du Colombier if (i.end-i.curr > 8)
1106219b2ee8SDavid du Colombier i.curr = _hexify(buf, i.w0, 7);
1107219b2ee8SDavid du Colombier if (i.size == 2 && i.end-i.curr > 9) {
1108219b2ee8SDavid du Colombier *i.curr++ = ' ';
1109219b2ee8SDavid du Colombier i.curr = _hexify(i.curr, i.w1, 7);
1110219b2ee8SDavid du Colombier }
1111219b2ee8SDavid du Colombier *i.curr = 0;
1112219b2ee8SDavid du Colombier return i.size*4;
1113219b2ee8SDavid du Colombier }
1114219b2ee8SDavid du Colombier
1115219b2ee8SDavid du Colombier static int
mipsinstlen(Map * map,uvlong pc)11164de34a7eSDavid du Colombier mipsinstlen(Map *map, uvlong pc)
1117219b2ee8SDavid du Colombier {
1118219b2ee8SDavid du Colombier Instr i;
1119219b2ee8SDavid du Colombier
1120219b2ee8SDavid du Colombier mymap = map;
1121219b2ee8SDavid du Colombier if (mkinstr(pc, &i) < 0)
1122219b2ee8SDavid du Colombier return -1;
1123219b2ee8SDavid du Colombier return i.size*4;
1124219b2ee8SDavid du Colombier }
1125219b2ee8SDavid du Colombier
1126219b2ee8SDavid du Colombier static int
mipsfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)11274de34a7eSDavid du Colombier mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1128219b2ee8SDavid du Colombier {
1129219b2ee8SDavid du Colombier ulong w, l;
1130219b2ee8SDavid du Colombier char buf[8];
1131219b2ee8SDavid du Colombier Instr i;
1132219b2ee8SDavid du Colombier
1133219b2ee8SDavid du Colombier mymap = map;
1134219b2ee8SDavid du Colombier if (mkinstr(pc, &i) < 0)
1135219b2ee8SDavid du Colombier return -1;
1136219b2ee8SDavid du Colombier w = i.w0;
1137219b2ee8SDavid du Colombier if((w&0xF3600000) == 0x41000000){ /* branch on coprocessor */
1138219b2ee8SDavid du Colombier Conditional:
1139219b2ee8SDavid du Colombier foll[0] = pc+8;
1140219b2ee8SDavid du Colombier l = ((w&0xFFFF)<<2);
1141219b2ee8SDavid du Colombier if(w & 0x8000)
1142219b2ee8SDavid du Colombier l |= 0xFFFC0000;
1143219b2ee8SDavid du Colombier foll[1] = pc+4 + l;
1144219b2ee8SDavid du Colombier return 2;
1145219b2ee8SDavid du Colombier }
1146219b2ee8SDavid du Colombier
1147219b2ee8SDavid du Colombier l = (w&0xFC000000)>>26;
1148219b2ee8SDavid du Colombier switch(l){
1149219b2ee8SDavid du Colombier case 0: /* SPECIAL */
1150219b2ee8SDavid du Colombier if((w&0x3E) == 0x08){ /* JR, JALR */
11517dd7cddfSDavid du Colombier sprint(buf, "R%ld", (w>>21)&0x1F);
1152219b2ee8SDavid du Colombier foll[0] = (*rget)(map, buf);
1153219b2ee8SDavid du Colombier return 1;
1154219b2ee8SDavid du Colombier }
1155219b2ee8SDavid du Colombier foll[0] = pc+i.size*4;
1156219b2ee8SDavid du Colombier return 1;
1157219b2ee8SDavid du Colombier case 0x30: /* Load-Linked followed by NOP, STC */
1158219b2ee8SDavid du Colombier foll[0] = pc+12;
1159219b2ee8SDavid du Colombier return 1;
1160219b2ee8SDavid du Colombier case 1: /* BCOND */
1161219b2ee8SDavid du Colombier case 4: /* BEQ */
11627dd7cddfSDavid du Colombier case 20: /* BEQL */
1163219b2ee8SDavid du Colombier case 5: /* BNE */
11647dd7cddfSDavid du Colombier case 21: /* BNEL */
1165219b2ee8SDavid du Colombier case 6: /* BLEZ */
11667dd7cddfSDavid du Colombier case 22: /* BLEZL */
1167219b2ee8SDavid du Colombier case 7: /* BGTZ */
11687dd7cddfSDavid du Colombier case 23: /* BGTZL */
1169219b2ee8SDavid du Colombier goto Conditional;
1170219b2ee8SDavid du Colombier case 2: /* J */
1171219b2ee8SDavid du Colombier case 3: /* JAL */
1172219b2ee8SDavid du Colombier foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1173219b2ee8SDavid du Colombier return 1;
1174219b2ee8SDavid du Colombier }
1175219b2ee8SDavid du Colombier
1176219b2ee8SDavid du Colombier foll[0] = pc+i.size*4;
1177219b2ee8SDavid du Colombier return 1;
1178219b2ee8SDavid du Colombier }
1179