17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <mach.h>
57dd7cddfSDavid du Colombier
659cc4ca5SDavid du Colombier static int debug = 0;
759cc4ca5SDavid du Colombier
859cc4ca5SDavid du Colombier #define BITS(a, b) ((1<<(b+1))-(1<<a))
959cc4ca5SDavid du Colombier
1059cc4ca5SDavid du Colombier #define LSR(v, s) ((ulong)(v) >> (s))
1159cc4ca5SDavid du Colombier #define ASR(v, s) ((long)(v) >> (s))
1259cc4ca5SDavid du Colombier #define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
1359cc4ca5SDavid du Colombier
1459cc4ca5SDavid du Colombier
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier typedef struct Instr Instr;
177dd7cddfSDavid du Colombier struct Instr
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier Map *map;
207dd7cddfSDavid du Colombier ulong w;
214de34a7eSDavid du Colombier uvlong addr;
227dd7cddfSDavid du Colombier uchar op; /* super opcode */
237dd7cddfSDavid du Colombier
247dd7cddfSDavid du Colombier uchar cond; /* bits 28-31 */
2559cc4ca5SDavid du Colombier uchar store; /* bit 20 */
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier uchar rd; /* bits 12-15 */
287dd7cddfSDavid du Colombier uchar rn; /* bits 16-19 */
2959cc4ca5SDavid du Colombier uchar rs; /* bits 0-11 (shifter operand) */
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier long imm; /* rotated imm */
327dd7cddfSDavid du Colombier char* curr; /* fill point in buffer */
337dd7cddfSDavid du Colombier char* end; /* end of buffer */
347dd7cddfSDavid du Colombier char* err; /* error message */
357dd7cddfSDavid du Colombier };
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier typedef struct Opcode Opcode;
387dd7cddfSDavid du Colombier struct Opcode
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier char* o;
4159cc4ca5SDavid du Colombier void (*fmt)(Opcode*, Instr*);
424de34a7eSDavid du Colombier uvlong (*foll)(Map*, Rgetter, Instr*, uvlong);
437dd7cddfSDavid du Colombier char* a;
447dd7cddfSDavid du Colombier };
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier static void format(char*, Instr*, char*);
477dd7cddfSDavid du Colombier static char FRAMENAME[] = ".frame";
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier /*
507dd7cddfSDavid du Colombier * Arm-specific debugger interface
517dd7cddfSDavid du Colombier */
527dd7cddfSDavid du Colombier
5359cc4ca5SDavid du Colombier static char *armexcep(Map*, Rgetter);
544de34a7eSDavid du Colombier static int armfoll(Map*, uvlong, Rgetter, uvlong*);
554de34a7eSDavid du Colombier static int arminst(Map*, uvlong, char, char*, int);
564de34a7eSDavid du Colombier static int armdas(Map*, uvlong, char*, int);
574de34a7eSDavid du Colombier static int arminstlen(Map*, uvlong);
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier /*
607dd7cddfSDavid du Colombier * Debugger interface
617dd7cddfSDavid du Colombier */
627dd7cddfSDavid du Colombier Machdata armmach =
637dd7cddfSDavid du Colombier {
646bbfed0dSDavid du Colombier {0x70, 0x00, 0x20, 0xE1}, /* break point */ /* E1200070 */
657dd7cddfSDavid du Colombier 4, /* break point size */
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier leswab, /* short to local byte order */
687dd7cddfSDavid du Colombier leswal, /* long to local byte order */
697dd7cddfSDavid du Colombier leswav, /* long to local byte order */
707dd7cddfSDavid du Colombier risctrace, /* C traceback */
717dd7cddfSDavid du Colombier riscframe, /* Frame finder */
7259cc4ca5SDavid du Colombier armexcep, /* print exception */
737dd7cddfSDavid du Colombier 0, /* breakpoint fixup */
747dd7cddfSDavid du Colombier 0, /* single precision float printer */
757dd7cddfSDavid du Colombier 0, /* double precision float printer */
767dd7cddfSDavid du Colombier armfoll, /* following addresses */
777dd7cddfSDavid du Colombier arminst, /* print instruction */
787dd7cddfSDavid du Colombier armdas, /* dissembler */
797dd7cddfSDavid du Colombier arminstlen, /* instruction size */
807dd7cddfSDavid du Colombier };
817dd7cddfSDavid du Colombier
8259cc4ca5SDavid du Colombier static char*
armexcep(Map * map,Rgetter rget)8359cc4ca5SDavid du Colombier armexcep(Map *map, Rgetter rget)
8459cc4ca5SDavid du Colombier {
854de34a7eSDavid du Colombier uvlong c;
8659cc4ca5SDavid du Colombier
8759cc4ca5SDavid du Colombier c = (*rget)(map, "TYPE");
884de34a7eSDavid du Colombier switch ((int)c&0x1f) {
8959cc4ca5SDavid du Colombier case 0x11:
9059cc4ca5SDavid du Colombier return "Fiq interrupt";
9159cc4ca5SDavid du Colombier case 0x12:
9259cc4ca5SDavid du Colombier return "Mirq interrupt";
9359cc4ca5SDavid du Colombier case 0x13:
9459cc4ca5SDavid du Colombier return "SVC/SWI Exception";
9559cc4ca5SDavid du Colombier case 0x17:
96*f1b2ee28SDavid du Colombier return "Prefetch Abort/Breakpoint";
9759cc4ca5SDavid du Colombier case 0x18:
9859cc4ca5SDavid du Colombier return "Data Abort";
9959cc4ca5SDavid du Colombier case 0x1b:
10059cc4ca5SDavid du Colombier return "Undefined instruction/Breakpoint";
10159cc4ca5SDavid du Colombier case 0x1f:
10259cc4ca5SDavid du Colombier return "Sys trap";
10359cc4ca5SDavid du Colombier default:
10459cc4ca5SDavid du Colombier return "Undefined trap";
10559cc4ca5SDavid du Colombier }
10659cc4ca5SDavid du Colombier }
10759cc4ca5SDavid du Colombier
1087dd7cddfSDavid du Colombier static
1097dd7cddfSDavid du Colombier char* cond[16] =
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier "EQ", "NE", "CS", "CC",
1127dd7cddfSDavid du Colombier "MI", "PL", "VS", "VC",
1137dd7cddfSDavid du Colombier "HI", "LS", "GE", "LT",
1147dd7cddfSDavid du Colombier "GT", "LE", 0, "NV"
1157dd7cddfSDavid du Colombier };
1167dd7cddfSDavid du Colombier
1177dd7cddfSDavid du Colombier static
1187dd7cddfSDavid du Colombier char* shtype[4] =
1197dd7cddfSDavid du Colombier {
1207dd7cddfSDavid du Colombier "<<", ">>", "->", "@>"
1217dd7cddfSDavid du Colombier };
1227dd7cddfSDavid du Colombier
12359cc4ca5SDavid du Colombier static
12459cc4ca5SDavid du Colombier char *hb[4] =
1257dd7cddfSDavid du Colombier {
12659cc4ca5SDavid du Colombier "???", "HU", "B", "H"
12759cc4ca5SDavid du Colombier };
12859cc4ca5SDavid du Colombier
12959cc4ca5SDavid du Colombier static
13059cc4ca5SDavid du Colombier char* addsub[2] =
13159cc4ca5SDavid du Colombier {
13259cc4ca5SDavid du Colombier "-", "+",
13359cc4ca5SDavid du Colombier };
13459cc4ca5SDavid du Colombier
13559cc4ca5SDavid du Colombier int
armclass(long w)13659cc4ca5SDavid du Colombier armclass(long w)
13759cc4ca5SDavid du Colombier {
1389b7bf7dfSDavid du Colombier int op, done, cp;
13959cc4ca5SDavid du Colombier
14059cc4ca5SDavid du Colombier op = (w >> 25) & 0x7;
1417dd7cddfSDavid du Colombier switch(op) {
1427dd7cddfSDavid du Colombier case 0: /* data processing r,r,r */
143*f1b2ee28SDavid du Colombier if((w & 0x0ff00080) == 0x01200000) {
144*f1b2ee28SDavid du Colombier op = (w >> 4) & 0x7;
145*f1b2ee28SDavid du Colombier if(op == 7)
146*f1b2ee28SDavid du Colombier op = 124; /* bkpt */
147*f1b2ee28SDavid du Colombier else if (op > 0 && op < 4)
148*f1b2ee28SDavid du Colombier op += 124; /* bx, blx */
149*f1b2ee28SDavid du Colombier else
150*f1b2ee28SDavid du Colombier op = 92; /* unk */
151*f1b2ee28SDavid du Colombier break;
152*f1b2ee28SDavid du Colombier }
1537dd7cddfSDavid du Colombier op = ((w >> 4) & 0xf);
1547dd7cddfSDavid du Colombier if(op == 0x9) {
1554f4ac6b1SDavid du Colombier op = 48+16; /* mul, swp or *rex */
1564f4ac6b1SDavid du Colombier if((w & 0x0ff00fff) == 0x01900f9f) {
1574f4ac6b1SDavid du Colombier op = 93; /* ldrex */
1584f4ac6b1SDavid du Colombier break;
1594f4ac6b1SDavid du Colombier }
1604f4ac6b1SDavid du Colombier if((w & 0x0ff00ff0) == 0x01800f90) {
1614f4ac6b1SDavid du Colombier op = 94; /* strex */
1624f4ac6b1SDavid du Colombier break;
1634f4ac6b1SDavid du Colombier }
1647dd7cddfSDavid du Colombier if(w & (1<<24)) {
1657dd7cddfSDavid du Colombier op += 2;
1667dd7cddfSDavid du Colombier if(w & (1<<22))
1674f4ac6b1SDavid du Colombier op++; /* swpb */
1687dd7cddfSDavid du Colombier break;
1697dd7cddfSDavid du Colombier }
17080ee5cbfSDavid du Colombier if(w & (1<<23)) { /* mullu */
17180ee5cbfSDavid du Colombier op = (48+24+4+4+2+2+4);
17280ee5cbfSDavid du Colombier if(w & (1<<22)) /* mull */
17380ee5cbfSDavid du Colombier op += 2;
17480ee5cbfSDavid du Colombier }
1757dd7cddfSDavid du Colombier if(w & (1<<21))
1767dd7cddfSDavid du Colombier op++; /* mla */
1777dd7cddfSDavid du Colombier break;
1787dd7cddfSDavid du Colombier }
17959cc4ca5SDavid du Colombier if((op & 0x9) == 0x9) /* ld/st byte/half s/u */
18059cc4ca5SDavid du Colombier {
18159cc4ca5SDavid du Colombier op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
18259cc4ca5SDavid du Colombier break;
18359cc4ca5SDavid du Colombier }
1847dd7cddfSDavid du Colombier op = (w >> 21) & 0xf;
1857dd7cddfSDavid du Colombier if(w & (1<<4))
1867dd7cddfSDavid du Colombier op += 32;
1877dd7cddfSDavid du Colombier else
1889a747e4fSDavid du Colombier if((w & (31<<7)) || (w & (1<<5)))
1897dd7cddfSDavid du Colombier op += 16;
1907dd7cddfSDavid du Colombier break;
1917dd7cddfSDavid du Colombier case 1: /* data processing i,r,r */
1927dd7cddfSDavid du Colombier op = (48) + ((w >> 21) & 0xf);
1937dd7cddfSDavid du Colombier break;
1947dd7cddfSDavid du Colombier case 2: /* load/store byte/word i(r) */
1954f4ac6b1SDavid du Colombier if ((w & 0xffffff8f) == 0xf57ff00f) { /* barriers, clrex */
1964f4ac6b1SDavid du Colombier done = 1;
1974f4ac6b1SDavid du Colombier switch ((w >> 4) & 7) {
1984f4ac6b1SDavid du Colombier case 1:
1994f4ac6b1SDavid du Colombier op = 95; /* clrex */
2004f4ac6b1SDavid du Colombier break;
2014f4ac6b1SDavid du Colombier case 4:
2024f4ac6b1SDavid du Colombier op = 96; /* dsb */
2034f4ac6b1SDavid du Colombier break;
2044f4ac6b1SDavid du Colombier case 5:
2054f4ac6b1SDavid du Colombier op = 97; /* dmb */
2064f4ac6b1SDavid du Colombier break;
2074f4ac6b1SDavid du Colombier case 6:
2084f4ac6b1SDavid du Colombier op = 98; /* isb */
2094f4ac6b1SDavid du Colombier break;
2104f4ac6b1SDavid du Colombier default:
2114f4ac6b1SDavid du Colombier done = 0;
2124f4ac6b1SDavid du Colombier break;
2134f4ac6b1SDavid du Colombier }
2144f4ac6b1SDavid du Colombier if (done)
2154f4ac6b1SDavid du Colombier break;
2164f4ac6b1SDavid du Colombier }
21759cc4ca5SDavid du Colombier op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
2187dd7cddfSDavid du Colombier break;
2197dd7cddfSDavid du Colombier case 3: /* load/store byte/word (r)(r) */
22059cc4ca5SDavid du Colombier op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
2217dd7cddfSDavid du Colombier break;
2227dd7cddfSDavid du Colombier case 4: /* block data transfer (r)(r) */
2236ca8a7e3SDavid du Colombier if ((w & 0xfe50ffff) == 0xf8100a00) { /* v7 RFE */
2246ca8a7e3SDavid du Colombier op = 99;
2256ca8a7e3SDavid du Colombier break;
2266ca8a7e3SDavid du Colombier }
22759cc4ca5SDavid du Colombier op = (48+24+4+4) + ((w >> 20) & 0x1);
2287dd7cddfSDavid du Colombier break;
2297dd7cddfSDavid du Colombier case 5: /* branch / branch link */
23059cc4ca5SDavid du Colombier op = (48+24+4+4+2) + ((w >> 24) & 0x1);
2317dd7cddfSDavid du Colombier break;
2327dd7cddfSDavid du Colombier case 7: /* coprocessor crap */
2339b7bf7dfSDavid du Colombier cp = (w >> 8) & 0xF;
2349b7bf7dfSDavid du Colombier if(cp == 10 || cp == 11){ /* vfp */
2359b7bf7dfSDavid du Colombier if((w >> 4) & 0x1){
2369b7bf7dfSDavid du Colombier /* vfp register transfer */
2379b7bf7dfSDavid du Colombier switch((w >> 21) & 0x7){
2389b7bf7dfSDavid du Colombier case 0:
2399b7bf7dfSDavid du Colombier op = 118 + ((w >> 20) & 0x1);
2409b7bf7dfSDavid du Colombier break;
2419b7bf7dfSDavid du Colombier case 7:
2429b7bf7dfSDavid du Colombier op = 118+2 + ((w >> 20) & 0x1);
2439b7bf7dfSDavid du Colombier break;
2449b7bf7dfSDavid du Colombier default:
2459b7bf7dfSDavid du Colombier op = (48+24+4+4+2+2+4+4);
2469b7bf7dfSDavid du Colombier break;
2479b7bf7dfSDavid du Colombier }
2489b7bf7dfSDavid du Colombier break;
2499b7bf7dfSDavid du Colombier }
2509b7bf7dfSDavid du Colombier /* vfp data processing */
2519b7bf7dfSDavid du Colombier if(((w >> 23) & 0x1) == 0){
2529b7bf7dfSDavid du Colombier op = 100 + ((w >> 19) & 0x6) + ((w >> 6) & 0x1);
2539b7bf7dfSDavid du Colombier break;
2549b7bf7dfSDavid du Colombier }
2559b7bf7dfSDavid du Colombier switch(((w >> 19) & 0x6) + ((w >> 6) & 0x1)){
2569b7bf7dfSDavid du Colombier case 0:
2579b7bf7dfSDavid du Colombier op = 108;
2589b7bf7dfSDavid du Colombier break;
2599b7bf7dfSDavid du Colombier case 7:
2606bbfed0dSDavid du Colombier if(((w >> 19) & 0x1) == 0){
2619b7bf7dfSDavid du Colombier if(((w >> 17) & 0x1) == 0)
2629b7bf7dfSDavid du Colombier op = 109 + ((w >> 16) & 0x4) +
2639b7bf7dfSDavid du Colombier ((w >> 15) & 0x2) +
2649b7bf7dfSDavid du Colombier ((w >> 7) & 0x1);
2659b7bf7dfSDavid du Colombier else if(((w >> 16) & 0x7) == 0x7)
2669b7bf7dfSDavid du Colombier op = 117;
2676bbfed0dSDavid du Colombier }else
2689b7bf7dfSDavid du Colombier switch((w >> 16) & 0x7){
2699b7bf7dfSDavid du Colombier case 0:
2709b7bf7dfSDavid du Colombier case 4:
2719b7bf7dfSDavid du Colombier case 5:
2729b7bf7dfSDavid du Colombier op = 117;
2739b7bf7dfSDavid du Colombier break;
2749b7bf7dfSDavid du Colombier }
2759b7bf7dfSDavid du Colombier break;
2769b7bf7dfSDavid du Colombier }
2779b7bf7dfSDavid du Colombier if(op == 7)
2789b7bf7dfSDavid du Colombier op = (48+24+4+4+2+2+4+4);
2799b7bf7dfSDavid du Colombier break;
2809b7bf7dfSDavid du Colombier }
28159cc4ca5SDavid du Colombier op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
2827dd7cddfSDavid du Colombier break;
2839b7bf7dfSDavid du Colombier case 6: /* vfp load / store */
2849b7bf7dfSDavid du Colombier if(((w >> 21) &0x9) == 0x8){
2859b7bf7dfSDavid du Colombier op = 122 + ((w >> 20) & 0x1);
2869b7bf7dfSDavid du Colombier break;
2879b7bf7dfSDavid du Colombier }
2889b7bf7dfSDavid du Colombier /* fall through */
2897dd7cddfSDavid du Colombier default:
29080ee5cbfSDavid du Colombier op = (48+24+4+4+2+2+4+4);
2917dd7cddfSDavid du Colombier break;
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier return op;
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier static int
decode(Map * map,uvlong pc,Instr * i)2974de34a7eSDavid du Colombier decode(Map *map, uvlong pc, Instr *i)
2987dd7cddfSDavid du Colombier {
2994de34a7eSDavid du Colombier ulong w;
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier if(get4(map, pc, &w) < 0) {
3027dd7cddfSDavid du Colombier werrstr("can't read instruction: %r");
3037dd7cddfSDavid du Colombier return -1;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier i->w = w;
3067dd7cddfSDavid du Colombier i->addr = pc;
30759cc4ca5SDavid du Colombier i->cond = (w >> 28) & 0xF;
30859cc4ca5SDavid du Colombier i->op = armclass(w);
3097dd7cddfSDavid du Colombier i->map = map;
3107dd7cddfSDavid du Colombier return 1;
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier
3131bd28109SDavid du Colombier #pragma varargck argpos bprint 2
3141bd28109SDavid du Colombier
3157dd7cddfSDavid du Colombier static void
bprint(Instr * i,char * fmt,...)3167dd7cddfSDavid du Colombier bprint(Instr *i, char *fmt, ...)
3177dd7cddfSDavid du Colombier {
3187dd7cddfSDavid du Colombier va_list arg;
3197dd7cddfSDavid du Colombier
3207dd7cddfSDavid du Colombier va_start(arg, fmt);
3219a747e4fSDavid du Colombier i->curr = vseprint(i->curr, i->end, fmt, arg);
3227dd7cddfSDavid du Colombier va_end(arg);
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier
3257dd7cddfSDavid du Colombier static int
plocal(Instr * i)32659cc4ca5SDavid du Colombier plocal(Instr *i)
3277dd7cddfSDavid du Colombier {
3287dd7cddfSDavid du Colombier char *reg;
3297dd7cddfSDavid du Colombier Symbol s;
33059cc4ca5SDavid du Colombier char *fn;
33159cc4ca5SDavid du Colombier int class;
33259cc4ca5SDavid du Colombier int offset;
3337dd7cddfSDavid du Colombier
33459cc4ca5SDavid du Colombier if(!findsym(i->addr, CTEXT, &s)) {
3354de34a7eSDavid du Colombier if(debug)fprint(2,"fn not found @%llux: %r\n", i->addr);
3367dd7cddfSDavid du Colombier return 0;
33759cc4ca5SDavid du Colombier }
33859cc4ca5SDavid du Colombier fn = s.name;
33959cc4ca5SDavid du Colombier if (!findlocal(&s, FRAMENAME, &s)) {
34059cc4ca5SDavid du Colombier if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
34159cc4ca5SDavid du Colombier return 0;
34259cc4ca5SDavid du Colombier }
3437dd7cddfSDavid du Colombier if(s.value > i->imm) {
34459cc4ca5SDavid du Colombier class = CAUTO;
34559cc4ca5SDavid du Colombier offset = s.value-i->imm;
3467dd7cddfSDavid du Colombier reg = "(SP)";
3477dd7cddfSDavid du Colombier } else {
34859cc4ca5SDavid du Colombier class = CPARAM;
34959cc4ca5SDavid du Colombier offset = i->imm-s.value-4;
3507dd7cddfSDavid du Colombier reg = "(FP)";
3517dd7cddfSDavid du Colombier }
35259cc4ca5SDavid du Colombier if(!getauto(&s, offset, class, &s)) {
35359cc4ca5SDavid du Colombier if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
35459cc4ca5SDavid du Colombier class == CAUTO ? " auto" : "param", offset);
35559cc4ca5SDavid du Colombier return 0;
35659cc4ca5SDavid du Colombier }
3571bd28109SDavid du Colombier bprint(i, "%s%c%lld%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
3587dd7cddfSDavid du Colombier return 1;
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier
36159cc4ca5SDavid du Colombier /*
36259cc4ca5SDavid du Colombier * Print value v as name[+offset]
36359cc4ca5SDavid du Colombier */
36459cc4ca5SDavid du Colombier static int
gsymoff(char * buf,int n,ulong v,int space)36548207d97SDavid du Colombier gsymoff(char *buf, int n, ulong v, int space)
36659cc4ca5SDavid du Colombier {
36759cc4ca5SDavid du Colombier Symbol s;
36859cc4ca5SDavid du Colombier int r;
36959cc4ca5SDavid du Colombier long delta;
37059cc4ca5SDavid du Colombier
37159cc4ca5SDavid du Colombier r = delta = 0; /* to shut compiler up */
37259cc4ca5SDavid du Colombier if (v) {
37359cc4ca5SDavid du Colombier r = findsym(v, space, &s);
37459cc4ca5SDavid du Colombier if (r)
37559cc4ca5SDavid du Colombier delta = v-s.value;
37659cc4ca5SDavid du Colombier if (delta < 0)
37759cc4ca5SDavid du Colombier delta = -delta;
37859cc4ca5SDavid du Colombier }
37959cc4ca5SDavid du Colombier if (v == 0 || r == 0 || delta >= 4096)
38059cc4ca5SDavid du Colombier return snprint(buf, n, "#%lux", v);
38159cc4ca5SDavid du Colombier if (strcmp(s.name, ".string") == 0)
38259cc4ca5SDavid du Colombier return snprint(buf, n, "#%lux", v);
38359cc4ca5SDavid du Colombier if (!delta)
38459cc4ca5SDavid du Colombier return snprint(buf, n, "%s", s.name);
38559cc4ca5SDavid du Colombier if (s.type != 't' && s.type != 'T')
3863806af99SDavid du Colombier return snprint(buf, n, "%s+%llux", s.name, v-s.value);
38759cc4ca5SDavid du Colombier else
38859cc4ca5SDavid du Colombier return snprint(buf, n, "#%lux", v);
38959cc4ca5SDavid du Colombier }
39059cc4ca5SDavid du Colombier
3917dd7cddfSDavid du Colombier static void
armdps(Opcode * o,Instr * i)3927dd7cddfSDavid du Colombier armdps(Opcode *o, Instr *i)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier i->store = (i->w >> 20) & 1;
39559cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
39659cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
39759cc4ca5SDavid du Colombier i->rs = (i->w >> 0) & 0xf;
3987dd7cddfSDavid du Colombier if(i->rn == 15 && i->rs == 0) {
3997dd7cddfSDavid du Colombier if(i->op == 8) {
4007dd7cddfSDavid du Colombier format("MOVW", i,"CPSR, R%d");
4017dd7cddfSDavid du Colombier return;
4027dd7cddfSDavid du Colombier } else
4037dd7cddfSDavid du Colombier if(i->op == 10) {
4047dd7cddfSDavid du Colombier format("MOVW", i,"SPSR, R%d");
4057dd7cddfSDavid du Colombier return;
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier } else
4087dd7cddfSDavid du Colombier if(i->rn == 9 && i->rd == 15) {
4097dd7cddfSDavid du Colombier if(i->op == 9) {
4107dd7cddfSDavid du Colombier format("MOVW", i, "R%s, CPSR");
4117dd7cddfSDavid du Colombier return;
4127dd7cddfSDavid du Colombier } else
4137dd7cddfSDavid du Colombier if(i->op == 11) {
4147dd7cddfSDavid du Colombier format("MOVW", i, "R%s, SPSR");
4157dd7cddfSDavid du Colombier return;
4167dd7cddfSDavid du Colombier }
4177dd7cddfSDavid du Colombier }
4186bbfed0dSDavid du Colombier if(i->rd == 15) {
4196bbfed0dSDavid du Colombier if(i->op == 120) {
4206bbfed0dSDavid du Colombier format("MOVW", i, "PSR, %x");
4216bbfed0dSDavid du Colombier return;
4226bbfed0dSDavid du Colombier } else
4236bbfed0dSDavid du Colombier if(i->op == 121) {
4246bbfed0dSDavid du Colombier format("MOVW", i, "%x, PSR");
4256bbfed0dSDavid du Colombier return;
4266bbfed0dSDavid du Colombier }
4276bbfed0dSDavid du Colombier }
4287dd7cddfSDavid du Colombier format(o->o, i, o->a);
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier
4317dd7cddfSDavid du Colombier static void
armdpi(Opcode * o,Instr * i)4327dd7cddfSDavid du Colombier armdpi(Opcode *o, Instr *i)
4337dd7cddfSDavid du Colombier {
4347dd7cddfSDavid du Colombier ulong v;
4357dd7cddfSDavid du Colombier int c;
4367dd7cddfSDavid du Colombier
43759cc4ca5SDavid du Colombier v = (i->w >> 0) & 0xff;
4387dd7cddfSDavid du Colombier c = (i->w >> 8) & 0xf;
4397dd7cddfSDavid du Colombier while(c) {
4407dd7cddfSDavid du Colombier v = (v<<30) | (v>>2);
4417dd7cddfSDavid du Colombier c--;
4427dd7cddfSDavid du Colombier }
4437dd7cddfSDavid du Colombier i->imm = v;
4447dd7cddfSDavid du Colombier i->store = (i->w >> 20) & 1;
44559cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
44659cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
44759cc4ca5SDavid du Colombier i->rs = i->w&0x0f;
4487dd7cddfSDavid du Colombier
4497dd7cddfSDavid du Colombier /* RET is encoded as ADD #0,R14,R15 */
45059cc4ca5SDavid du Colombier if((i->w & 0x0fffffff) == 0x028ef000){
45159cc4ca5SDavid du Colombier format("RET%C", i, "");
4527dd7cddfSDavid du Colombier return;
45359cc4ca5SDavid du Colombier }
45459cc4ca5SDavid du Colombier if((i->w & 0x0ff0ffff) == 0x0280f000){
45559cc4ca5SDavid du Colombier format("B%C", i, "0(R%n)");
45659cc4ca5SDavid du Colombier return;
45759cc4ca5SDavid du Colombier }
4587dd7cddfSDavid du Colombier format(o->o, i, o->a);
4597dd7cddfSDavid du Colombier }
4607dd7cddfSDavid du Colombier
4617dd7cddfSDavid du Colombier static void
armsdti(Opcode * o,Instr * i)4627dd7cddfSDavid du Colombier armsdti(Opcode *o, Instr *i)
4637dd7cddfSDavid du Colombier {
4647dd7cddfSDavid du Colombier ulong v;
4657dd7cddfSDavid du Colombier
46659cc4ca5SDavid du Colombier v = i->w & 0xfff;
4677dd7cddfSDavid du Colombier if(!(i->w & (1<<23)))
4687dd7cddfSDavid du Colombier v = -v;
4697dd7cddfSDavid du Colombier i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
4707dd7cddfSDavid du Colombier i->imm = v;
47159cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
47259cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
47359cc4ca5SDavid du Colombier /* RET is encoded as LW.P x,R13,R15 */
47459cc4ca5SDavid du Colombier if ((i->w & 0x0ffff000) == 0x049df000)
47559cc4ca5SDavid du Colombier {
47659cc4ca5SDavid du Colombier format("RET%C%p", i, "%I");
47759cc4ca5SDavid du Colombier return;
47859cc4ca5SDavid du Colombier }
47959cc4ca5SDavid du Colombier format(o->o, i, o->a);
48059cc4ca5SDavid du Colombier }
48159cc4ca5SDavid du Colombier
4829b7bf7dfSDavid du Colombier static void
armvstdi(Opcode * o,Instr * i)4839b7bf7dfSDavid du Colombier armvstdi(Opcode *o, Instr *i)
4849b7bf7dfSDavid du Colombier {
4859b7bf7dfSDavid du Colombier ulong v;
4869b7bf7dfSDavid du Colombier
4879b7bf7dfSDavid du Colombier v = (i->w & 0xff) << 2;
4889b7bf7dfSDavid du Colombier if(!(i->w & (1<<23)))
4899b7bf7dfSDavid du Colombier v = -v;
4909b7bf7dfSDavid du Colombier i->imm = v;
4919b7bf7dfSDavid du Colombier i->rn = (i->w >> 16) & 0xf;
4929b7bf7dfSDavid du Colombier i->rd = (i->w >> 12) & 0xf;
4939b7bf7dfSDavid du Colombier format(o->o, i, o->a);
4949b7bf7dfSDavid du Colombier }
4959b7bf7dfSDavid du Colombier
49659cc4ca5SDavid du Colombier /* arm V4 ld/st halfword, signed byte */
49759cc4ca5SDavid du Colombier static void
armhwby(Opcode * o,Instr * i)49859cc4ca5SDavid du Colombier armhwby(Opcode *o, Instr *i)
49959cc4ca5SDavid du Colombier {
50059cc4ca5SDavid du Colombier i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
50159cc4ca5SDavid du Colombier i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
50259cc4ca5SDavid du Colombier if (!(i->w & (1 << 23)))
50359cc4ca5SDavid du Colombier i->imm = - i->imm;
50459cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
50559cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
50659cc4ca5SDavid du Colombier i->rs = (i->w >> 0) & 0xf;
5077dd7cddfSDavid du Colombier format(o->o, i, o->a);
5087dd7cddfSDavid du Colombier }
5097dd7cddfSDavid du Colombier
5107dd7cddfSDavid du Colombier static void
armsdts(Opcode * o,Instr * i)5117dd7cddfSDavid du Colombier armsdts(Opcode *o, Instr *i)
5127dd7cddfSDavid du Colombier {
5137dd7cddfSDavid du Colombier i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
51459cc4ca5SDavid du Colombier i->rs = (i->w >> 0) & 0xf;
51559cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
51659cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
5177dd7cddfSDavid du Colombier format(o->o, i, o->a);
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier static void
armbdt(Opcode * o,Instr * i)5217dd7cddfSDavid du Colombier armbdt(Opcode *o, Instr *i)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier i->store = (i->w >> 21) & 0x3; /* S & W bits */
52459cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
5257dd7cddfSDavid du Colombier i->imm = i->w & 0xffff;
5267dd7cddfSDavid du Colombier if(i->w == 0xe8fd8000)
5277dd7cddfSDavid du Colombier format("RFE", i, "");
5287dd7cddfSDavid du Colombier else
5297dd7cddfSDavid du Colombier format(o->o, i, o->a);
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier
5327dd7cddfSDavid du Colombier static void
armund(Opcode * o,Instr * i)5337dd7cddfSDavid du Colombier armund(Opcode *o, Instr *i)
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier format(o->o, i, o->a);
5367dd7cddfSDavid du Colombier }
5377dd7cddfSDavid du Colombier
5387dd7cddfSDavid du Colombier static void
armcdt(Opcode * o,Instr * i)5397dd7cddfSDavid du Colombier armcdt(Opcode *o, Instr *i)
5407dd7cddfSDavid du Colombier {
5417dd7cddfSDavid du Colombier format(o->o, i, o->a);
5427dd7cddfSDavid du Colombier }
5437dd7cddfSDavid du Colombier
5447dd7cddfSDavid du Colombier static void
armunk(Opcode * o,Instr * i)5457dd7cddfSDavid du Colombier armunk(Opcode *o, Instr *i)
5467dd7cddfSDavid du Colombier {
5477dd7cddfSDavid du Colombier format(o->o, i, o->a);
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier
5507dd7cddfSDavid du Colombier static void
armb(Opcode * o,Instr * i)5517dd7cddfSDavid du Colombier armb(Opcode *o, Instr *i)
5527dd7cddfSDavid du Colombier {
5537dd7cddfSDavid du Colombier ulong v;
5547dd7cddfSDavid du Colombier
5557dd7cddfSDavid du Colombier v = i->w & 0xffffff;
55659cc4ca5SDavid du Colombier if(v & 0x800000)
5577dd7cddfSDavid du Colombier v |= ~0xffffff;
5587dd7cddfSDavid du Colombier i->imm = (v<<2) + i->addr + 8;
5597dd7cddfSDavid du Colombier format(o->o, i, o->a);
5607dd7cddfSDavid du Colombier }
5617dd7cddfSDavid du Colombier
5627dd7cddfSDavid du Colombier static void
armbpt(Opcode * o,Instr * i)563*f1b2ee28SDavid du Colombier armbpt(Opcode *o, Instr *i)
564*f1b2ee28SDavid du Colombier {
565*f1b2ee28SDavid du Colombier i->imm = ((i->w >> 4) & 0xfff0) | (i->w &0xf);
566*f1b2ee28SDavid du Colombier format(o->o, i, o->a);
567*f1b2ee28SDavid du Colombier }
568*f1b2ee28SDavid du Colombier
569*f1b2ee28SDavid du Colombier static void
armco(Opcode * o,Instr * i)5707dd7cddfSDavid du Colombier armco(Opcode *o, Instr *i) /* coprocessor instructions */
5717dd7cddfSDavid du Colombier {
5727dd7cddfSDavid du Colombier int op, p, cp;
5737dd7cddfSDavid du Colombier
5747dd7cddfSDavid du Colombier char buf[1024];
5757dd7cddfSDavid du Colombier
57659cc4ca5SDavid du Colombier i->rn = (i->w >> 16) & 0xf;
57759cc4ca5SDavid du Colombier i->rd = (i->w >> 12) & 0xf;
57859cc4ca5SDavid du Colombier i->rs = i->w&0xf;
5797dd7cddfSDavid du Colombier cp = (i->w >> 8) & 0xf;
5807dd7cddfSDavid du Colombier p = (i->w >> 5) & 0x7;
58159cc4ca5SDavid du Colombier if(i->w&(1<<4)) {
58259cc4ca5SDavid du Colombier op = (i->w >> 21) & 0x07;
5833468a491SDavid du Colombier snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
5847dd7cddfSDavid du Colombier } else {
58559cc4ca5SDavid du Colombier op = (i->w >> 20) & 0x0f;
5863468a491SDavid du Colombier snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier format(o->o, i, buf);
5897dd7cddfSDavid du Colombier }
5907dd7cddfSDavid du Colombier
59159cc4ca5SDavid du Colombier static int
armcondpass(Map * map,Rgetter rget,uchar cond)59259cc4ca5SDavid du Colombier armcondpass(Map *map, Rgetter rget, uchar cond)
5937dd7cddfSDavid du Colombier {
5944de34a7eSDavid du Colombier uvlong psr;
59559cc4ca5SDavid du Colombier uchar n;
59659cc4ca5SDavid du Colombier uchar z;
59759cc4ca5SDavid du Colombier uchar c;
59859cc4ca5SDavid du Colombier uchar v;
59959cc4ca5SDavid du Colombier
60059cc4ca5SDavid du Colombier psr = rget(map, "PSR");
60159cc4ca5SDavid du Colombier n = (psr >> 31) & 1;
60259cc4ca5SDavid du Colombier z = (psr >> 30) & 1;
60359cc4ca5SDavid du Colombier c = (psr >> 29) & 1;
60459cc4ca5SDavid du Colombier v = (psr >> 28) & 1;
60559cc4ca5SDavid du Colombier
60659cc4ca5SDavid du Colombier switch(cond) {
607ec46fab0SDavid du Colombier default:
60859cc4ca5SDavid du Colombier case 0: return z;
60959cc4ca5SDavid du Colombier case 1: return !z;
61059cc4ca5SDavid du Colombier case 2: return c;
61159cc4ca5SDavid du Colombier case 3: return !c;
61259cc4ca5SDavid du Colombier case 4: return n;
61359cc4ca5SDavid du Colombier case 5: return !n;
61459cc4ca5SDavid du Colombier case 6: return v;
61559cc4ca5SDavid du Colombier case 7: return !v;
61659cc4ca5SDavid du Colombier case 8: return c && !z;
61759cc4ca5SDavid du Colombier case 9: return !c || z;
61859cc4ca5SDavid du Colombier case 10: return n == v;
61959cc4ca5SDavid du Colombier case 11: return n != v;
62059cc4ca5SDavid du Colombier case 12: return !z && (n == v);
6216bbfed0dSDavid du Colombier case 13: return z || (n != v);
62259cc4ca5SDavid du Colombier case 14: return 1;
62359cc4ca5SDavid du Colombier case 15: return 0;
62459cc4ca5SDavid du Colombier }
62559cc4ca5SDavid du Colombier }
62659cc4ca5SDavid du Colombier
62759cc4ca5SDavid du Colombier static ulong
armshiftval(Map * map,Rgetter rget,Instr * i)62859cc4ca5SDavid du Colombier armshiftval(Map *map, Rgetter rget, Instr *i)
62959cc4ca5SDavid du Colombier {
63059cc4ca5SDavid du Colombier if(i->w & (1 << 25)) { /* immediate */
63159cc4ca5SDavid du Colombier ulong imm = i->w & BITS(0, 7);
63259cc4ca5SDavid du Colombier ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
63359cc4ca5SDavid du Colombier return ROR(imm, s);
63459cc4ca5SDavid du Colombier } else {
6357dd7cddfSDavid du Colombier char buf[8];
63659cc4ca5SDavid du Colombier ulong v;
63759cc4ca5SDavid du Colombier ulong s = (i->w & BITS(7,11)) >> 7;
6387dd7cddfSDavid du Colombier
63959cc4ca5SDavid du Colombier sprint(buf, "R%ld", i->w & 0xf);
64059cc4ca5SDavid du Colombier v = rget(map, buf);
6417dd7cddfSDavid du Colombier
64259cc4ca5SDavid du Colombier switch((i->w & BITS(4, 6)) >> 4) {
643ec46fab0SDavid du Colombier default:
6447dd7cddfSDavid du Colombier case 0: /* LSLIMM */
6457dd7cddfSDavid du Colombier return v << s;
6467dd7cddfSDavid du Colombier case 1: /* LSLREG */
64759cc4ca5SDavid du Colombier sprint(buf, "R%lud", s >> 1);
64859cc4ca5SDavid du Colombier s = rget(map, buf) & 0xFF;
64959cc4ca5SDavid du Colombier if(s >= 32) return 0;
6507dd7cddfSDavid du Colombier return v << s;
6517dd7cddfSDavid du Colombier case 2: /* LSRIMM */
65259cc4ca5SDavid du Colombier return LSR(v, s);
6537dd7cddfSDavid du Colombier case 3: /* LSRREG */
6547dd7cddfSDavid du Colombier sprint(buf, "R%ld", s >> 1);
65559cc4ca5SDavid du Colombier s = rget(map, buf) & 0xFF;
65659cc4ca5SDavid du Colombier if(s >= 32) return 0;
65759cc4ca5SDavid du Colombier return LSR(v, s);
6587dd7cddfSDavid du Colombier case 4: /* ASRIMM */
6597dd7cddfSDavid du Colombier if(s == 0) {
66059cc4ca5SDavid du Colombier if((v & (1U<<31)) == 0)
6617dd7cddfSDavid du Colombier return 0;
66259cc4ca5SDavid du Colombier return 0xFFFFFFFF;
6637dd7cddfSDavid du Colombier }
66459cc4ca5SDavid du Colombier return ASR(v, s);
6657dd7cddfSDavid du Colombier case 5: /* ASRREG */
6667dd7cddfSDavid du Colombier sprint(buf, "R%ld", s >> 1);
66759cc4ca5SDavid du Colombier s = rget(map, buf) & 0xFF;
6687dd7cddfSDavid du Colombier if(s >= 32) {
66959cc4ca5SDavid du Colombier if((v & (1U<<31)) == 0)
6707dd7cddfSDavid du Colombier return 0;
67159cc4ca5SDavid du Colombier return 0xFFFFFFFF;
6727dd7cddfSDavid du Colombier }
67359cc4ca5SDavid du Colombier return ASR(v, s);
6747dd7cddfSDavid du Colombier case 6: /* RORIMM */
67559cc4ca5SDavid du Colombier if(s == 0) {
67659cc4ca5SDavid du Colombier ulong c = (rget(map, "PSR") >> 29) & 1;
67759cc4ca5SDavid du Colombier
67859cc4ca5SDavid du Colombier return (c << 31) | LSR(v, 1);
67959cc4ca5SDavid du Colombier }
6807dd7cddfSDavid du Colombier return ROR(v, s);
6817dd7cddfSDavid du Colombier case 7: /* RORREG */
68259cc4ca5SDavid du Colombier sprint(buf, "R%ld", (s>>1)&0xF);
68359cc4ca5SDavid du Colombier s = rget(map, buf);
68459cc4ca5SDavid du Colombier if(s == 0 || (s & 0xF) == 0)
6857dd7cddfSDavid du Colombier return v;
68659cc4ca5SDavid du Colombier return ROR(v, s & 0xF);
6877dd7cddfSDavid du Colombier }
68859cc4ca5SDavid du Colombier }
68959cc4ca5SDavid du Colombier }
69059cc4ca5SDavid du Colombier
69159cc4ca5SDavid du Colombier static int
nbits(ulong v)69259cc4ca5SDavid du Colombier nbits(ulong v)
69359cc4ca5SDavid du Colombier {
69459cc4ca5SDavid du Colombier int n = 0;
69559cc4ca5SDavid du Colombier int i;
69659cc4ca5SDavid du Colombier
69759cc4ca5SDavid du Colombier for(i=0; i < 32 ; i++) {
69859cc4ca5SDavid du Colombier if(v & 1) ++n;
69959cc4ca5SDavid du Colombier v >>= 1;
70059cc4ca5SDavid du Colombier }
70159cc4ca5SDavid du Colombier
70259cc4ca5SDavid du Colombier return n;
7037dd7cddfSDavid du Colombier }
7047dd7cddfSDavid du Colombier
7057dd7cddfSDavid du Colombier static ulong
armmaddr(Map * map,Rgetter rget,Instr * i)70659cc4ca5SDavid du Colombier armmaddr(Map *map, Rgetter rget, Instr *i)
70759cc4ca5SDavid du Colombier {
70859cc4ca5SDavid du Colombier ulong v;
70959cc4ca5SDavid du Colombier ulong nb;
71059cc4ca5SDavid du Colombier char buf[8];
71159cc4ca5SDavid du Colombier ulong rn;
71259cc4ca5SDavid du Colombier
71359cc4ca5SDavid du Colombier rn = (i->w >> 16) & 0xf;
71459cc4ca5SDavid du Colombier sprint(buf,"R%ld", rn);
71559cc4ca5SDavid du Colombier
71659cc4ca5SDavid du Colombier v = rget(map, buf);
71759cc4ca5SDavid du Colombier nb = nbits(i->w & ((1 << 15) - 1));
71859cc4ca5SDavid du Colombier
71959cc4ca5SDavid du Colombier switch((i->w >> 23) & 3) {
720ec46fab0SDavid du Colombier default:
72159cc4ca5SDavid du Colombier case 0: return (v - (nb*4)) + 4;
72259cc4ca5SDavid du Colombier case 1: return v;
72359cc4ca5SDavid du Colombier case 2: return v - (nb*4);
72459cc4ca5SDavid du Colombier case 3: return v + 4;
72559cc4ca5SDavid du Colombier }
72659cc4ca5SDavid du Colombier }
72759cc4ca5SDavid du Colombier
7284de34a7eSDavid du Colombier static uvlong
armaddr(Map * map,Rgetter rget,Instr * i)72959cc4ca5SDavid du Colombier armaddr(Map *map, Rgetter rget, Instr *i)
7307dd7cddfSDavid du Colombier {
7317dd7cddfSDavid du Colombier char buf[8];
73259cc4ca5SDavid du Colombier ulong rn;
7337dd7cddfSDavid du Colombier
7346ca8a7e3SDavid du Colombier snprint(buf, sizeof(buf), "R%ld", (i->w >> 16) & 0xf);
73559cc4ca5SDavid du Colombier rn = rget(map, buf);
7367dd7cddfSDavid du Colombier
7376ca8a7e3SDavid du Colombier if((i->w & (1<<24)) == 0) /* POSTIDX */
7386ca8a7e3SDavid du Colombier return rn;
7397dd7cddfSDavid du Colombier
74059cc4ca5SDavid du Colombier if((i->w & (1<<25)) == 0) { /* OFFSET */
74159cc4ca5SDavid du Colombier if(i->w & (1U<<23))
7426ca8a7e3SDavid du Colombier return rn + (i->w & BITS(0,11));
7436ca8a7e3SDavid du Colombier return rn - (i->w & BITS(0,11));
74459cc4ca5SDavid du Colombier } else { /* REGOFF */
74559cc4ca5SDavid du Colombier ulong index = 0;
74659cc4ca5SDavid du Colombier uchar c;
74759cc4ca5SDavid du Colombier uchar rm;
7487dd7cddfSDavid du Colombier
74959cc4ca5SDavid du Colombier sprint(buf, "R%ld", i->w & 0xf);
75059cc4ca5SDavid du Colombier rm = rget(map, buf);
75159cc4ca5SDavid du Colombier
75259cc4ca5SDavid du Colombier switch((i->w & BITS(5,6)) >> 5) {
75359cc4ca5SDavid du Colombier case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
75459cc4ca5SDavid du Colombier case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
75559cc4ca5SDavid du Colombier case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
7567dd7cddfSDavid du Colombier case 3:
75759cc4ca5SDavid du Colombier if((i->w & BITS(7,11)) == 0) {
75859cc4ca5SDavid du Colombier c = (rget(map, "PSR") >> 29) & 1;
75959cc4ca5SDavid du Colombier index = c << 31 | LSR(rm, 1);
76059cc4ca5SDavid du Colombier } else {
76159cc4ca5SDavid du Colombier index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
76259cc4ca5SDavid du Colombier }
7637dd7cddfSDavid du Colombier break;
7647dd7cddfSDavid du Colombier }
76559cc4ca5SDavid du Colombier if(i->w & (1<<23))
76659cc4ca5SDavid du Colombier return rn + index;
76759cc4ca5SDavid du Colombier return rn - index;
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier }
7707dd7cddfSDavid du Colombier
7714de34a7eSDavid du Colombier static uvlong
armfadd(Map * map,Rgetter rget,Instr * i,uvlong pc)7724de34a7eSDavid du Colombier armfadd(Map *map, Rgetter rget, Instr *i, uvlong pc)
7737dd7cddfSDavid du Colombier {
7747dd7cddfSDavid du Colombier char buf[8];
77559cc4ca5SDavid du Colombier int r;
7767dd7cddfSDavid du Colombier
77759cc4ca5SDavid du Colombier r = (i->w >> 12) & 0xf;
77859cc4ca5SDavid du Colombier if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
77959cc4ca5SDavid du Colombier return pc+4;
7807dd7cddfSDavid du Colombier
78159cc4ca5SDavid du Colombier r = (i->w >> 16) & 0xf;
78259cc4ca5SDavid du Colombier sprint(buf, "R%d", r);
7837dd7cddfSDavid du Colombier
78459cc4ca5SDavid du Colombier return rget(map, buf) + armshiftval(map, rget, i);
7857dd7cddfSDavid du Colombier }
78659cc4ca5SDavid du Colombier
7874de34a7eSDavid du Colombier static uvlong
armfbx(Map * map,Rgetter rget,Instr * i,uvlong pc)788*f1b2ee28SDavid du Colombier armfbx(Map *map, Rgetter rget, Instr *i, uvlong pc)
789*f1b2ee28SDavid du Colombier {
790*f1b2ee28SDavid du Colombier char buf[8];
791*f1b2ee28SDavid du Colombier int r;
792*f1b2ee28SDavid du Colombier
793*f1b2ee28SDavid du Colombier if(!armcondpass(map, rget, (i->w>>28)&0xf))
794*f1b2ee28SDavid du Colombier return pc+4;
795*f1b2ee28SDavid du Colombier r = (i->w >> 0) & 0xf;
796*f1b2ee28SDavid du Colombier sprint(buf, "R%d", r);
797*f1b2ee28SDavid du Colombier return rget(map, buf);
798*f1b2ee28SDavid du Colombier }
799*f1b2ee28SDavid du Colombier
800*f1b2ee28SDavid du Colombier static uvlong
armfmovm(Map * map,Rgetter rget,Instr * i,uvlong pc)8014de34a7eSDavid du Colombier armfmovm(Map *map, Rgetter rget, Instr *i, uvlong pc)
80259cc4ca5SDavid du Colombier {
80359cc4ca5SDavid du Colombier ulong v;
80459cc4ca5SDavid du Colombier ulong addr;
80559cc4ca5SDavid du Colombier
80659cc4ca5SDavid du Colombier v = i->w & 1<<15;
80759cc4ca5SDavid du Colombier if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
80859cc4ca5SDavid du Colombier return pc+4;
80959cc4ca5SDavid du Colombier
81059cc4ca5SDavid du Colombier addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
8114de34a7eSDavid du Colombier if(get4(map, addr, &v) < 0) {
81259cc4ca5SDavid du Colombier werrstr("can't read addr: %r");
81359cc4ca5SDavid du Colombier return -1;
81459cc4ca5SDavid du Colombier }
81559cc4ca5SDavid du Colombier return v;
81659cc4ca5SDavid du Colombier }
81759cc4ca5SDavid du Colombier
8184de34a7eSDavid du Colombier static uvlong
armfbranch(Map * map,Rgetter rget,Instr * i,uvlong pc)8194de34a7eSDavid du Colombier armfbranch(Map *map, Rgetter rget, Instr *i, uvlong pc)
82059cc4ca5SDavid du Colombier {
82159cc4ca5SDavid du Colombier if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
82259cc4ca5SDavid du Colombier return pc+4;
82359cc4ca5SDavid du Colombier
82459cc4ca5SDavid du Colombier return pc + (((signed long)i->w << 8) >> 6) + 8;
82559cc4ca5SDavid du Colombier }
82659cc4ca5SDavid du Colombier
8274de34a7eSDavid du Colombier static uvlong
armfmov(Map * map,Rgetter rget,Instr * i,uvlong pc)8284de34a7eSDavid du Colombier armfmov(Map *map, Rgetter rget, Instr *i, uvlong pc)
82959cc4ca5SDavid du Colombier {
8304de34a7eSDavid du Colombier ulong rd, v;
83159cc4ca5SDavid du Colombier
83259cc4ca5SDavid du Colombier rd = (i->w >> 12) & 0xf;
83359cc4ca5SDavid du Colombier if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
83459cc4ca5SDavid du Colombier return pc+4;
83559cc4ca5SDavid du Colombier
83659cc4ca5SDavid du Colombier /* LDR */
83759cc4ca5SDavid du Colombier /* BUG: Needs LDH/B, too */
838b85a8364SDavid du Colombier if(((i->w>>26)&0x3) == 1) {
8394de34a7eSDavid du Colombier if(get4(map, armaddr(map, rget, i), &v) < 0) {
84059cc4ca5SDavid du Colombier werrstr("can't read instruction: %r");
84159cc4ca5SDavid du Colombier return pc+4;
84259cc4ca5SDavid du Colombier }
84359cc4ca5SDavid du Colombier return v;
84459cc4ca5SDavid du Colombier }
84559cc4ca5SDavid du Colombier
84659cc4ca5SDavid du Colombier /* MOV */
84759cc4ca5SDavid du Colombier v = armshiftval(map, rget, i);
84859cc4ca5SDavid du Colombier
84959cc4ca5SDavid du Colombier return v;
8507dd7cddfSDavid du Colombier }
8517dd7cddfSDavid du Colombier
8527dd7cddfSDavid du Colombier static Opcode opcodes[] =
8537dd7cddfSDavid du Colombier {
85459cc4ca5SDavid du Colombier "AND%C%S", armdps, 0, "R%s,R%n,R%d",
85559cc4ca5SDavid du Colombier "EOR%C%S", armdps, 0, "R%s,R%n,R%d",
85659cc4ca5SDavid du Colombier "SUB%C%S", armdps, 0, "R%s,R%n,R%d",
85759cc4ca5SDavid du Colombier "RSB%C%S", armdps, 0, "R%s,R%n,R%d",
85859cc4ca5SDavid du Colombier "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
85959cc4ca5SDavid du Colombier "ADC%C%S", armdps, 0, "R%s,R%n,R%d",
86059cc4ca5SDavid du Colombier "SBC%C%S", armdps, 0, "R%s,R%n,R%d",
86159cc4ca5SDavid du Colombier "RSC%C%S", armdps, 0, "R%s,R%n,R%d",
86259cc4ca5SDavid du Colombier "TST%C%S", armdps, 0, "R%s,R%n",
86359cc4ca5SDavid du Colombier "TEQ%C%S", armdps, 0, "R%s,R%n",
86459cc4ca5SDavid du Colombier "CMP%C%S", armdps, 0, "R%s,R%n",
86559cc4ca5SDavid du Colombier "CMN%C%S", armdps, 0, "R%s,R%n",
86659cc4ca5SDavid du Colombier "ORR%C%S", armdps, 0, "R%s,R%n,R%d",
86759cc4ca5SDavid du Colombier "MOVW%C%S", armdps, armfmov, "R%s,R%d",
86859cc4ca5SDavid du Colombier "BIC%C%S", armdps, 0, "R%s,R%n,R%d",
86959cc4ca5SDavid du Colombier "MVN%C%S", armdps, 0, "R%s,R%d",
8707dd7cddfSDavid du Colombier
87159cc4ca5SDavid du Colombier /* 16 */
87259cc4ca5SDavid du Colombier "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87359cc4ca5SDavid du Colombier "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87459cc4ca5SDavid du Colombier "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87559cc4ca5SDavid du Colombier "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87659cc4ca5SDavid du Colombier "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
87759cc4ca5SDavid du Colombier "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87859cc4ca5SDavid du Colombier "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
87959cc4ca5SDavid du Colombier "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
88059cc4ca5SDavid du Colombier "TST%C%S", armdps, 0, "(R%s%h%m),R%n",
88159cc4ca5SDavid du Colombier "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
88259cc4ca5SDavid du Colombier "CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
88359cc4ca5SDavid du Colombier "CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
88459cc4ca5SDavid du Colombier "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
88559cc4ca5SDavid du Colombier "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
88659cc4ca5SDavid du Colombier "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
88759cc4ca5SDavid du Colombier "MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
8887dd7cddfSDavid du Colombier
88959cc4ca5SDavid du Colombier /* 32 */
89059cc4ca5SDavid du Colombier "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89159cc4ca5SDavid du Colombier "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89259cc4ca5SDavid du Colombier "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89359cc4ca5SDavid du Colombier "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89459cc4ca5SDavid du Colombier "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
89559cc4ca5SDavid du Colombier "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89659cc4ca5SDavid du Colombier "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89759cc4ca5SDavid du Colombier "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
89859cc4ca5SDavid du Colombier "TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
89959cc4ca5SDavid du Colombier "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
90059cc4ca5SDavid du Colombier "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
90159cc4ca5SDavid du Colombier "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
90259cc4ca5SDavid du Colombier "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
90359cc4ca5SDavid du Colombier "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
90459cc4ca5SDavid du Colombier "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
90559cc4ca5SDavid du Colombier "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
9067dd7cddfSDavid du Colombier
90759cc4ca5SDavid du Colombier /* 48 */
90859cc4ca5SDavid du Colombier "AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
90959cc4ca5SDavid du Colombier "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
91059cc4ca5SDavid du Colombier "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
91159cc4ca5SDavid du Colombier "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
91259cc4ca5SDavid du Colombier "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
91359cc4ca5SDavid du Colombier "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
91459cc4ca5SDavid du Colombier "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
91559cc4ca5SDavid du Colombier "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
91659cc4ca5SDavid du Colombier "TST%C%S", armdpi, 0, "$#%i,R%n",
91759cc4ca5SDavid du Colombier "TEQ%C%S", armdpi, 0, "$#%i,R%n",
91859cc4ca5SDavid du Colombier "CMP%C%S", armdpi, 0, "$#%i,R%n",
91959cc4ca5SDavid du Colombier "CMN%C%S", armdpi, 0, "$#%i,R%n",
92059cc4ca5SDavid du Colombier "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
92159cc4ca5SDavid du Colombier "MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
92259cc4ca5SDavid du Colombier "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
92359cc4ca5SDavid du Colombier "MVN%C%S", armdpi, 0, "$#%i,R%d",
9247dd7cddfSDavid du Colombier
92559cc4ca5SDavid du Colombier /* 48+16 */
92680ee5cbfSDavid du Colombier "MUL%C%S", armdpi, 0, "R%M,R%s,R%n",
92780ee5cbfSDavid du Colombier "MULA%C%S", armdpi, 0, "R%M,R%s,R%n,R%d",
92859cc4ca5SDavid du Colombier "SWPW", armdpi, 0, "R%s,(R%n),R%d",
92959cc4ca5SDavid du Colombier "SWPB", armdpi, 0, "R%s,(R%n),R%d",
9307dd7cddfSDavid du Colombier
93159cc4ca5SDavid du Colombier /* 48+16+4 */
93259cc4ca5SDavid du Colombier "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)",
93359cc4ca5SDavid du Colombier "MOV%u%C%p", armhwby, 0, "R%d,%I",
93459cc4ca5SDavid du Colombier "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d",
93559cc4ca5SDavid du Colombier "MOV%u%C%p", armhwby, armfmov, "%I,R%d",
9367dd7cddfSDavid du Colombier
93759cc4ca5SDavid du Colombier /* 48+24 */
93859cc4ca5SDavid du Colombier "MOVW%C%p", armsdti, 0, "R%d,%I",
93959cc4ca5SDavid du Colombier "MOVB%C%p", armsdti, 0, "R%d,%I",
94059cc4ca5SDavid du Colombier "MOVW%C%p", armsdti, armfmov, "%I,R%d",
94159cc4ca5SDavid du Colombier "MOVBU%C%p", armsdti, armfmov, "%I,R%d",
9427dd7cddfSDavid du Colombier
94359cc4ca5SDavid du Colombier "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
94459cc4ca5SDavid du Colombier "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
94559cc4ca5SDavid du Colombier "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
94659cc4ca5SDavid du Colombier "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
9477dd7cddfSDavid du Colombier
94859cc4ca5SDavid du Colombier "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
94959cc4ca5SDavid du Colombier "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
9507dd7cddfSDavid du Colombier
95159cc4ca5SDavid du Colombier "B%C", armb, armfbranch, "%b",
95259cc4ca5SDavid du Colombier "BL%C", armb, armfbranch, "%b",
9537dd7cddfSDavid du Colombier
95459cc4ca5SDavid du Colombier "CDP%C", armco, 0, "",
95559cc4ca5SDavid du Colombier "CDP%C", armco, 0, "",
95659cc4ca5SDavid du Colombier "MCR%C", armco, 0, "",
95759cc4ca5SDavid du Colombier "MRC%C", armco, 0, "",
95859cc4ca5SDavid du Colombier
95980ee5cbfSDavid du Colombier /* 48+24+4+4+2+2+4 */
96080ee5cbfSDavid du Colombier "MULLU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
96180ee5cbfSDavid du Colombier "MULALU%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
96280ee5cbfSDavid du Colombier "MULL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
96380ee5cbfSDavid du Colombier "MULAL%C%S", armdpi, 0, "R%M,R%s,(R%n,R%d)",
96480ee5cbfSDavid du Colombier
9654f4ac6b1SDavid du Colombier /* 48+24+4+4+2+2+4+4 = 92 */
96659cc4ca5SDavid du Colombier "UNK", armunk, 0, "",
9674f4ac6b1SDavid du Colombier
9686ca8a7e3SDavid du Colombier /* new v7 arch instructions */
9694f4ac6b1SDavid du Colombier /* 93 */
9704f4ac6b1SDavid du Colombier "LDREX", armdpi, 0, "(R%n),R%d",
9714f4ac6b1SDavid du Colombier "STREX", armdpi, 0, "R%s,(R%n),R%d",
9724f4ac6b1SDavid du Colombier "CLREX", armunk, 0, "",
9734f4ac6b1SDavid du Colombier
9744f4ac6b1SDavid du Colombier /* 96 */
9754f4ac6b1SDavid du Colombier "DSB", armunk, 0, "",
9764f4ac6b1SDavid du Colombier "DMB", armunk, 0, "",
9774f4ac6b1SDavid du Colombier "ISB", armunk, 0, "",
9786ca8a7e3SDavid du Colombier
9796ca8a7e3SDavid du Colombier /* 99 */
9806ca8a7e3SDavid du Colombier "RFEV7%P%a", armbdt, 0, "(R%n)",
9819b7bf7dfSDavid du Colombier
9829b7bf7dfSDavid du Colombier /* 100 */
9839b7bf7dfSDavid du Colombier "MLA%f%C", armdps, 0, "F%s,F%n,F%d",
9849b7bf7dfSDavid du Colombier "MLS%f%C", armdps, 0, "F%s,F%n,F%d",
9859b7bf7dfSDavid du Colombier "NMLS%f%C", armdps, 0, "F%s,F%n,F%d",
9869b7bf7dfSDavid du Colombier "NMLA%f%C", armdps, 0, "F%s,F%n,F%d",
9879b7bf7dfSDavid du Colombier "MUL%f%C", armdps, 0, "F%s,F%n,F%d",
9889b7bf7dfSDavid du Colombier "NMUL%f%C", armdps, 0, "F%s,F%n,F%d",
9899b7bf7dfSDavid du Colombier "ADD%f%C", armdps, 0, "F%s,F%n,F%d",
9909b7bf7dfSDavid du Colombier "SUB%f%C", armdps, 0, "F%s,F%n,F%d",
9919b7bf7dfSDavid du Colombier "DIV%f%C", armdps, 0, "F%s,F%n,F%d",
9929b7bf7dfSDavid du Colombier
9939b7bf7dfSDavid du Colombier /* 109 */
9949b7bf7dfSDavid du Colombier "MOV%f%C", armdps, 0, "F%s,F%d",
9959b7bf7dfSDavid du Colombier "ABS%f%C", armdps, 0, "F%s,F%d",
9969b7bf7dfSDavid du Colombier "NEG%f%C", armdps, 0, "F%s,F%d",
9979b7bf7dfSDavid du Colombier "SQRT%f%C", armdps, 0, "F%s,F%d",
9989b7bf7dfSDavid du Colombier "CMP%f%C", armdps, 0, "F%s,F%d",
9999b7bf7dfSDavid du Colombier "CMPE%f%C", armdps, 0, "F%s,F%d",
10009b7bf7dfSDavid du Colombier "CMP%f%C", armdps, 0, "$0.0,F%d",
10019b7bf7dfSDavid du Colombier "CMPE%f%C", armdps, 0, "$0.0,F%d",
10029b7bf7dfSDavid du Colombier
10039b7bf7dfSDavid du Colombier /* 117 */
10049b7bf7dfSDavid du Colombier "MOV%F%R%C", armdps, 0, "F%s,F%d",
10059b7bf7dfSDavid du Colombier
10069b7bf7dfSDavid du Colombier /* 118 */
10079b7bf7dfSDavid du Colombier "MOVW%C", armdps, 0, "R%d,F%n",
10089b7bf7dfSDavid du Colombier "MOVW%C", armdps, 0, "F%n,R%d",
10099b7bf7dfSDavid du Colombier "MOVW%C", armdps, 0, "R%d,%x",
10109b7bf7dfSDavid du Colombier "MOVW%C", armdps, 0, "%x,R%d",
10119b7bf7dfSDavid du Colombier
10129b7bf7dfSDavid du Colombier /* 122 */
10139b7bf7dfSDavid du Colombier "MOV%f%C", armvstdi, 0, "F%d,%I",
10149b7bf7dfSDavid du Colombier "MOV%f%C", armvstdi, 0, "%I,F%d",
1015*f1b2ee28SDavid du Colombier
1016*f1b2ee28SDavid du Colombier /* 124 */
1017*f1b2ee28SDavid du Colombier "BKPT%C", armbpt, 0, "$#%i",
1018*f1b2ee28SDavid du Colombier "BX%C", armdps, armfbx, "(R%s)",
1019*f1b2ee28SDavid du Colombier "BXJ%C", armdps, armfbx, "(R%s)",
1020*f1b2ee28SDavid du Colombier "BLX%C", armdps, armfbx, "(R%s)",
10217dd7cddfSDavid du Colombier };
10227dd7cddfSDavid du Colombier
102359cc4ca5SDavid du Colombier static void
gaddr(Instr * i)102459cc4ca5SDavid du Colombier gaddr(Instr *i)
102559cc4ca5SDavid du Colombier {
102659cc4ca5SDavid du Colombier *i->curr++ = '$';
102759cc4ca5SDavid du Colombier i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
102859cc4ca5SDavid du Colombier }
102959cc4ca5SDavid du Colombier
10307dd7cddfSDavid du Colombier static char *mode[] = { 0, "IA", "DB", "IB" };
10317dd7cddfSDavid du Colombier static char *pw[] = { "P", "PW", 0, "W" };
10327dd7cddfSDavid du Colombier static char *sw[] = { 0, "W", "S", "SW" };
10337dd7cddfSDavid du Colombier
10347dd7cddfSDavid du Colombier static void
format(char * mnemonic,Instr * i,char * f)10357dd7cddfSDavid du Colombier format(char *mnemonic, Instr *i, char *f)
10367dd7cddfSDavid du Colombier {
10377dd7cddfSDavid du Colombier int j, k, m, n;
103859cc4ca5SDavid du Colombier int g;
103959cc4ca5SDavid du Colombier char *fmt;
10407dd7cddfSDavid du Colombier
10417dd7cddfSDavid du Colombier if(mnemonic)
10427dd7cddfSDavid du Colombier format(0, i, mnemonic);
10437dd7cddfSDavid du Colombier if(f == 0)
10447dd7cddfSDavid du Colombier return;
10457dd7cddfSDavid du Colombier if(mnemonic)
10467dd7cddfSDavid du Colombier if(i->curr < i->end)
10477dd7cddfSDavid du Colombier *i->curr++ = '\t';
10487dd7cddfSDavid du Colombier for ( ; *f && i->curr < i->end; f++) {
10497dd7cddfSDavid du Colombier if(*f != '%') {
10507dd7cddfSDavid du Colombier *i->curr++ = *f;
10517dd7cddfSDavid du Colombier continue;
10527dd7cddfSDavid du Colombier }
10537dd7cddfSDavid du Colombier switch (*++f) {
10547dd7cddfSDavid du Colombier
10557dd7cddfSDavid du Colombier case 'C': /* .CONDITION */
10567dd7cddfSDavid du Colombier if(cond[i->cond])
10577dd7cddfSDavid du Colombier bprint(i, ".%s", cond[i->cond]);
10587dd7cddfSDavid du Colombier break;
10597dd7cddfSDavid du Colombier
10607dd7cddfSDavid du Colombier case 'S': /* .STORE */
10617dd7cddfSDavid du Colombier if(i->store)
10627dd7cddfSDavid du Colombier bprint(i, ".S");
10637dd7cddfSDavid du Colombier break;
10647dd7cddfSDavid du Colombier
10657dd7cddfSDavid du Colombier case 'P': /* P & U bits for block move */
10667dd7cddfSDavid du Colombier n = (i->w >>23) & 0x3;
10677dd7cddfSDavid du Colombier if (mode[n])
10687dd7cddfSDavid du Colombier bprint(i, ".%s", mode[n]);
10697dd7cddfSDavid du Colombier break;
10707dd7cddfSDavid du Colombier
10717dd7cddfSDavid du Colombier case 'p': /* P & W bits for single data xfer*/
10727dd7cddfSDavid du Colombier if (pw[i->store])
10737dd7cddfSDavid du Colombier bprint(i, ".%s", pw[i->store]);
10747dd7cddfSDavid du Colombier break;
10757dd7cddfSDavid du Colombier
10767dd7cddfSDavid du Colombier case 'a': /* S & W bits for single data xfer*/
10777dd7cddfSDavid du Colombier if (sw[i->store])
10787dd7cddfSDavid du Colombier bprint(i, ".%s", sw[i->store]);
10797dd7cddfSDavid du Colombier break;
10807dd7cddfSDavid du Colombier
10817dd7cddfSDavid du Colombier case 's':
10827dd7cddfSDavid du Colombier bprint(i, "%d", i->rs & 0xf);
10837dd7cddfSDavid du Colombier break;
10847dd7cddfSDavid du Colombier
108559cc4ca5SDavid du Colombier case 'M':
10861bd28109SDavid du Colombier bprint(i, "%lud", (i->w>>8) & 0xf);
108759cc4ca5SDavid du Colombier break;
108859cc4ca5SDavid du Colombier
10897dd7cddfSDavid du Colombier case 'm':
10901bd28109SDavid du Colombier bprint(i, "%lud", (i->w>>7) & 0x1f);
10917dd7cddfSDavid du Colombier break;
10927dd7cddfSDavid du Colombier
10937dd7cddfSDavid du Colombier case 'h':
109459cc4ca5SDavid du Colombier bprint(i, shtype[(i->w>>5) & 0x3]);
109559cc4ca5SDavid du Colombier break;
109659cc4ca5SDavid du Colombier
109759cc4ca5SDavid du Colombier case 'u': /* Signed/unsigned Byte/Halfword */
109859cc4ca5SDavid du Colombier bprint(i, hb[(i->w>>5) & 0x3]);
109959cc4ca5SDavid du Colombier break;
110059cc4ca5SDavid du Colombier
110159cc4ca5SDavid du Colombier case 'I':
110259cc4ca5SDavid du Colombier if (i->rn == 13) {
110359cc4ca5SDavid du Colombier if (plocal(i))
110459cc4ca5SDavid du Colombier break;
110559cc4ca5SDavid du Colombier }
110659cc4ca5SDavid du Colombier g = 0;
110759cc4ca5SDavid du Colombier fmt = "#%lx(R%d)";
110859cc4ca5SDavid du Colombier if (i->rn == 15) {
110959cc4ca5SDavid du Colombier /* convert load of offset(PC) to a load immediate */
11104de34a7eSDavid du Colombier if (get4(i->map, i->addr+i->imm+8, (ulong*)&i->imm) > 0)
111159cc4ca5SDavid du Colombier {
111259cc4ca5SDavid du Colombier g = 1;
111359cc4ca5SDavid du Colombier fmt = "";
111459cc4ca5SDavid du Colombier }
111559cc4ca5SDavid du Colombier }
111659cc4ca5SDavid du Colombier if (mach->sb)
111759cc4ca5SDavid du Colombier {
111859cc4ca5SDavid du Colombier if (i->rd == 11) {
111959cc4ca5SDavid du Colombier ulong nxti;
112059cc4ca5SDavid du Colombier
11214de34a7eSDavid du Colombier if (get4(i->map, i->addr+4, &nxti) > 0) {
112259cc4ca5SDavid du Colombier if ((nxti & 0x0e0f0fff) == 0x060c000b) {
112359cc4ca5SDavid du Colombier i->imm += mach->sb;
112459cc4ca5SDavid du Colombier g = 1;
112559cc4ca5SDavid du Colombier fmt = "-SB";
112659cc4ca5SDavid du Colombier }
112759cc4ca5SDavid du Colombier }
112859cc4ca5SDavid du Colombier }
112959cc4ca5SDavid du Colombier if (i->rn == 12)
113059cc4ca5SDavid du Colombier {
113159cc4ca5SDavid du Colombier i->imm += mach->sb;
113259cc4ca5SDavid du Colombier g = 1;
113359cc4ca5SDavid du Colombier fmt = "-SB(SB)";
113459cc4ca5SDavid du Colombier }
113559cc4ca5SDavid du Colombier }
113659cc4ca5SDavid du Colombier if (g)
113759cc4ca5SDavid du Colombier {
113859cc4ca5SDavid du Colombier gaddr(i);
113959cc4ca5SDavid du Colombier bprint(i, fmt, i->rn);
114059cc4ca5SDavid du Colombier }
114159cc4ca5SDavid du Colombier else
114259cc4ca5SDavid du Colombier bprint(i, fmt, i->imm, i->rn);
114359cc4ca5SDavid du Colombier break;
114459cc4ca5SDavid du Colombier case 'U': /* Add/subtract from base */
114559cc4ca5SDavid du Colombier bprint(i, addsub[(i->w >> 23) & 1]);
11467dd7cddfSDavid du Colombier break;
11477dd7cddfSDavid du Colombier
11487dd7cddfSDavid du Colombier case 'n':
11497dd7cddfSDavid du Colombier bprint(i, "%d", i->rn);
11507dd7cddfSDavid du Colombier break;
11517dd7cddfSDavid du Colombier
11527dd7cddfSDavid du Colombier case 'd':
11537dd7cddfSDavid du Colombier bprint(i, "%d", i->rd);
11547dd7cddfSDavid du Colombier break;
11557dd7cddfSDavid du Colombier
11567dd7cddfSDavid du Colombier case 'i':
11577dd7cddfSDavid du Colombier bprint(i, "%lux", i->imm);
11587dd7cddfSDavid du Colombier break;
11597dd7cddfSDavid du Colombier
11607dd7cddfSDavid du Colombier case 'b':
11617dd7cddfSDavid du Colombier i->curr += symoff(i->curr, i->end-i->curr,
116248207d97SDavid du Colombier (ulong)i->imm, CTEXT);
116359cc4ca5SDavid du Colombier break;
116459cc4ca5SDavid du Colombier
116559cc4ca5SDavid du Colombier case 'g':
116659cc4ca5SDavid du Colombier i->curr += gsymoff(i->curr, i->end-i->curr,
11677dd7cddfSDavid du Colombier i->imm, CANY);
11687dd7cddfSDavid du Colombier break;
11697dd7cddfSDavid du Colombier
11709b7bf7dfSDavid du Colombier case 'f':
11719b7bf7dfSDavid du Colombier switch((i->w >> 8) & 0xF){
11729b7bf7dfSDavid du Colombier case 10:
11739b7bf7dfSDavid du Colombier bprint(i, "F");
11749b7bf7dfSDavid du Colombier break;
11759b7bf7dfSDavid du Colombier case 11:
11769b7bf7dfSDavid du Colombier bprint(i, "D");
11779b7bf7dfSDavid du Colombier break;
11789b7bf7dfSDavid du Colombier }
11799b7bf7dfSDavid du Colombier break;
11809b7bf7dfSDavid du Colombier
11819b7bf7dfSDavid du Colombier case 'F':
11829b7bf7dfSDavid du Colombier switch(((i->w >> 15) & 0xE) + ((i->w >> 8) & 0x1)){
11839b7bf7dfSDavid du Colombier case 0x0:
11849b7bf7dfSDavid du Colombier bprint(i, ((i->w >> 7) & 0x1)? "WF" : "WF.U");
11859b7bf7dfSDavid du Colombier break;
11869b7bf7dfSDavid du Colombier case 0x1:
11879b7bf7dfSDavid du Colombier bprint(i, ((i->w >> 7) & 0x1)? "WD" : "WD.U");
11889b7bf7dfSDavid du Colombier break;
11899b7bf7dfSDavid du Colombier case 0x8:
11909b7bf7dfSDavid du Colombier bprint(i, "FW.U");
11919b7bf7dfSDavid du Colombier break;
11929b7bf7dfSDavid du Colombier case 0x9:
11939b7bf7dfSDavid du Colombier bprint(i, "DW.U");
11949b7bf7dfSDavid du Colombier break;
11959b7bf7dfSDavid du Colombier case 0xA:
11969b7bf7dfSDavid du Colombier bprint(i, "FW");
11979b7bf7dfSDavid du Colombier break;
11989b7bf7dfSDavid du Colombier case 0xB:
11999b7bf7dfSDavid du Colombier bprint(i, "DW");
12009b7bf7dfSDavid du Colombier break;
12019b7bf7dfSDavid du Colombier case 0xE:
12029b7bf7dfSDavid du Colombier bprint(i, "FD");
12039b7bf7dfSDavid du Colombier break;
12049b7bf7dfSDavid du Colombier case 0xF:
12059b7bf7dfSDavid du Colombier bprint(i, "DF");
12069b7bf7dfSDavid du Colombier break;
12079b7bf7dfSDavid du Colombier }
12089b7bf7dfSDavid du Colombier break;
12099b7bf7dfSDavid du Colombier
12109b7bf7dfSDavid du Colombier case 'R':
12119b7bf7dfSDavid du Colombier if(((i->w >> 7) & 0x1) == 0)
12129b7bf7dfSDavid du Colombier bprint(i, "R");
12139b7bf7dfSDavid du Colombier break;
12149b7bf7dfSDavid du Colombier
12159b7bf7dfSDavid du Colombier case 'x':
12169b7bf7dfSDavid du Colombier switch(i->rn){
12179b7bf7dfSDavid du Colombier case 0:
12189b7bf7dfSDavid du Colombier bprint(i, "FPSID");
12199b7bf7dfSDavid du Colombier break;
12209b7bf7dfSDavid du Colombier case 1:
12219b7bf7dfSDavid du Colombier bprint(i, "FPSCR");
12229b7bf7dfSDavid du Colombier break;
12239b7bf7dfSDavid du Colombier case 2:
12249b7bf7dfSDavid du Colombier bprint(i, "FPEXC");
12259b7bf7dfSDavid du Colombier break;
12269b7bf7dfSDavid du Colombier default:
12279b7bf7dfSDavid du Colombier bprint(i, "FPS(%d)", i->rn);
12289b7bf7dfSDavid du Colombier break;
12299b7bf7dfSDavid du Colombier }
12309b7bf7dfSDavid du Colombier break;
12319b7bf7dfSDavid du Colombier
12327dd7cddfSDavid du Colombier case 'r':
12337dd7cddfSDavid du Colombier n = i->imm&0xffff;
12347dd7cddfSDavid du Colombier j = 0;
12357dd7cddfSDavid du Colombier k = 0;
12367dd7cddfSDavid du Colombier while(n) {
12377dd7cddfSDavid du Colombier m = j;
12387dd7cddfSDavid du Colombier while(n&0x1) {
12397dd7cddfSDavid du Colombier j++;
12407dd7cddfSDavid du Colombier n >>= 1;
12417dd7cddfSDavid du Colombier }
12427dd7cddfSDavid du Colombier if(j != m) {
12437dd7cddfSDavid du Colombier if(k)
12447dd7cddfSDavid du Colombier bprint(i, ",");
12457dd7cddfSDavid du Colombier if(j == m+1)
12467dd7cddfSDavid du Colombier bprint(i, "R%d", m);
12477dd7cddfSDavid du Colombier else
12487dd7cddfSDavid du Colombier bprint(i, "R%d-R%d", m, j-1);
12497dd7cddfSDavid du Colombier k = 1;
12507dd7cddfSDavid du Colombier }
12517dd7cddfSDavid du Colombier j++;
12527dd7cddfSDavid du Colombier n >>= 1;
12537dd7cddfSDavid du Colombier }
12547dd7cddfSDavid du Colombier break;
12557dd7cddfSDavid du Colombier
12567dd7cddfSDavid du Colombier case '\0':
12577dd7cddfSDavid du Colombier *i->curr++ = '%';
12587dd7cddfSDavid du Colombier return;
12597dd7cddfSDavid du Colombier
12607dd7cddfSDavid du Colombier default:
12617dd7cddfSDavid du Colombier bprint(i, "%%%c", *f);
12627dd7cddfSDavid du Colombier break;
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier }
12657dd7cddfSDavid du Colombier *i->curr = 0;
12667dd7cddfSDavid du Colombier }
12677dd7cddfSDavid du Colombier
12687dd7cddfSDavid du Colombier static int
printins(Map * map,uvlong pc,char * buf,int n)12694de34a7eSDavid du Colombier printins(Map *map, uvlong pc, char *buf, int n)
12707dd7cddfSDavid du Colombier {
12717dd7cddfSDavid du Colombier Instr i;
12727dd7cddfSDavid du Colombier
12737dd7cddfSDavid du Colombier i.curr = buf;
12747dd7cddfSDavid du Colombier i.end = buf+n-1;
12757dd7cddfSDavid du Colombier if(decode(map, pc, &i) < 0)
12767dd7cddfSDavid du Colombier return -1;
12777dd7cddfSDavid du Colombier
127859cc4ca5SDavid du Colombier (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
12797dd7cddfSDavid du Colombier return 4;
12807dd7cddfSDavid du Colombier }
12817dd7cddfSDavid du Colombier
12827dd7cddfSDavid du Colombier static int
arminst(Map * map,uvlong pc,char modifier,char * buf,int n)12834de34a7eSDavid du Colombier arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
12847dd7cddfSDavid du Colombier {
128559cc4ca5SDavid du Colombier USED(modifier);
12867dd7cddfSDavid du Colombier return printins(map, pc, buf, n);
12877dd7cddfSDavid du Colombier }
12887dd7cddfSDavid du Colombier
12897dd7cddfSDavid du Colombier static int
armdas(Map * map,uvlong pc,char * buf,int n)12904de34a7eSDavid du Colombier armdas(Map *map, uvlong pc, char *buf, int n)
12917dd7cddfSDavid du Colombier {
12927dd7cddfSDavid du Colombier Instr i;
12937dd7cddfSDavid du Colombier
12947dd7cddfSDavid du Colombier i.curr = buf;
12957dd7cddfSDavid du Colombier i.end = buf+n;
12967dd7cddfSDavid du Colombier if(decode(map, pc, &i) < 0)
12977dd7cddfSDavid du Colombier return -1;
12987dd7cddfSDavid du Colombier if(i.end-i.curr > 8)
12997dd7cddfSDavid du Colombier i.curr = _hexify(buf, i.w, 7);
13007dd7cddfSDavid du Colombier *i.curr = 0;
13017dd7cddfSDavid du Colombier return 4;
13027dd7cddfSDavid du Colombier }
13037dd7cddfSDavid du Colombier
13047dd7cddfSDavid du Colombier static int
arminstlen(Map * map,uvlong pc)13054de34a7eSDavid du Colombier arminstlen(Map *map, uvlong pc)
13067dd7cddfSDavid du Colombier {
13077dd7cddfSDavid du Colombier Instr i;
13087dd7cddfSDavid du Colombier
13097dd7cddfSDavid du Colombier if(decode(map, pc, &i) < 0)
13107dd7cddfSDavid du Colombier return -1;
13117dd7cddfSDavid du Colombier return 4;
13127dd7cddfSDavid du Colombier }
13137dd7cddfSDavid du Colombier
13147dd7cddfSDavid du Colombier static int
armfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)13154de34a7eSDavid du Colombier armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
13167dd7cddfSDavid du Colombier {
13174de34a7eSDavid du Colombier uvlong d;
13187dd7cddfSDavid du Colombier Instr i;
13197dd7cddfSDavid du Colombier
13207dd7cddfSDavid du Colombier if(decode(map, pc, &i) < 0)
13217dd7cddfSDavid du Colombier return -1;
13227dd7cddfSDavid du Colombier
132359cc4ca5SDavid du Colombier if(opcodes[i.op].foll) {
132459cc4ca5SDavid du Colombier d = (*opcodes[i.op].foll)(map, rget, &i, pc);
132559cc4ca5SDavid du Colombier if(d == -1)
132659cc4ca5SDavid du Colombier return -1;
13277dd7cddfSDavid du Colombier } else
132859cc4ca5SDavid du Colombier d = pc+4;
132959cc4ca5SDavid du Colombier
133059cc4ca5SDavid du Colombier foll[0] = d;
13317dd7cddfSDavid du Colombier return 1;
13327dd7cddfSDavid du Colombier }
1333