diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libinterp/das-arm.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libinterp/das-arm.c')
| -rw-r--r-- | libinterp/das-arm.c | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/libinterp/das-arm.c b/libinterp/das-arm.c new file mode 100644 index 00000000..9ba90112 --- /dev/null +++ b/libinterp/das-arm.c @@ -0,0 +1,535 @@ +#include <lib9.h> + +typedef struct Instr Instr; +struct Instr +{ + ulong w; + ulong addr; + uchar op; /* super opcode */ + + uchar cond; /* bits 28-31 */ + uchar store; /* bit 20 */ + + uchar rd; /* bits 12-15 */ + uchar rn; /* bits 16-19 */ + uchar rs; /* bits 0-11 */ + + long imm; /* rotated imm */ + char* curr; /* fill point in buffer */ + char* end; /* end of buffer */ + char* err; /* error message */ +}; + +typedef struct Opcode Opcode; +struct Opcode +{ + char* o; + void (*f)(Opcode*, Instr*); + char* a; +}; + +static void format(char*, Instr*, char*); +static int arminst(ulong, char, char*, int); +static int armdas(ulong, char*, int); + +static +char* cond[16] = +{ + "EQ", "NE", "CS", "CC", + "MI", "PL", "VS", "VC", + "HI", "LS", "GE", "LT", + "GT", "LE", 0, "NV" +}; + +static +char* shtype[4] = +{ + "<<", ">>", "->", "@>" +}; + +static int +get4(ulong addr, long *v) +{ + *v = *(ulong*)addr; + return 1; +} + +static char * +_hexify(char *buf, ulong p, int zeros) +{ + ulong d; + + d = p/16; + if(d) + buf = _hexify(buf, d, zeros-1); + else + while(zeros--) + *buf++ = '0'; + *buf++ = "0123456789abcdef"[p&0x0f]; + return buf; +} + +int +armclass(long w) +{ + int op; + + op = (w >> 25) & 0x7; + switch(op) { + case 0: /* data processing r,r,r */ + op = ((w >> 4) & 0xf); + if(op == 0x9) { + op = 48+16; /* mul */ + if(w & (1<<24)) { + op += 2; + if(w & (1<<22)) + op++; /* swap */ + break; + } + if(w & (1<<21)) + op++; /* mla */ + break; + } + op = (w >> 21) & 0xf; + if(w & (1<<4)) + op += 32; + else + if(w & (31<<7)) + op += 16; + break; + case 1: /* data processing i,r,r */ + op = (48) + ((w >> 21) & 0xf); + break; + case 2: /* load/store byte/word i(r) */ + op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 3: /* load/store byte/word (r)(r) */ + op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2); + break; + case 4: /* block data transfer (r)(r) */ + op = (48+20+4+4) + ((w >> 20) & 0x1); + break; + case 5: /* branch / branch link */ + op = (48+20+4+4+2) + ((w >> 24) & 0x1); + break; + case 7: /* coprocessor crap */ + op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1); + break; + default: + op = (48+20+4+4+2+2+4); + break; + } + return op; +} + +static int +decode(ulong pc, Instr *i) +{ + long w; + + get4(pc, &w); + i->w = w; + i->addr = pc; + i->cond = (w >> 28) & 0xF; + i->op = armclass(w); + return 1; +} + +static void +bprint(Instr *i, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + i->curr = vseprint(i->curr, i->end, fmt, arg); + va_end(arg); +} + +static void +armdps(Opcode *o, Instr *i) +{ + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = (i->w >> 0) & 0xf; + if(i->rn == 15 && i->rs == 0) { + if(i->op == 8) { + format("MOVW", i,"CPSR, R%d"); + return; + } else + if(i->op == 10) { + format("MOVW", i,"SPSR, R%d"); + return; + } + } else + if(i->rn == 9 && i->rd == 15) { + if(i->op == 9) { + format("MOVW", i, "R%s, CPSR"); + return; + } else + if(i->op == 11) { + format("MOVW", i, "R%s, SPSR"); + return; + } + } + format(o->o, i, o->a); +} + +static void +armdpi(Opcode *o, Instr *i) +{ + ulong v; + int c; + + v = (i->w >> 0) & 0xff; + c = (i->w >> 8) & 0xf; + while(c) { + v = (v<<30) | (v>>2); + c--; + } + i->imm = v; + i->store = (i->w >> 20) & 1; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0x0f; + + /* RET is encoded as ADD #0,R14,R15 */ + if(i->w == 0xe282f000){ + format("RET", i, ""); + return; + } else + format(o->o, i, o->a); +} + +static void +armsdti(Opcode *o, Instr *i) +{ + ulong v; + + v = (i->w >> 0) & 0xfff; + if(!(i->w & (1<<23))) + v = -v; + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->imm = v; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + /* convert load of offset(PC) to a load immediate */ + if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0) + format(o->o, i, "$#%i,R%d"); + else + format(o->o, i, o->a); +} + +static void +armsdts(Opcode *o, Instr *i) +{ + i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1); + i->rs = (i->w >> 0) & 0xf; + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + format(o->o, i, o->a); +} + +static void +armbdt(Opcode *o, Instr *i) +{ + i->store = (i->w >> 21) & 0x3; /* S & W bits */ + i->rn = (i->w >> 16) & 0xf; + i->imm = i->w & 0xffff; + if(i->w == 0xe8fd8000) + format("RFE", i, ""); + else + format(o->o, i, o->a); +} + +static void +armund(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armcdt(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armunk(Opcode *o, Instr *i) +{ + format(o->o, i, o->a); +} + +static void +armb(Opcode *o, Instr *i) +{ + ulong v; + + v = i->w & 0xffffff; + if(v & 0x800000) + v |= ~0xffffff; + i->imm = (v<<2) + i->addr + 8; + format(o->o, i, o->a); +} + +static void +armco(Opcode *o, Instr *i) /* coprocessor instructions */ +{ + int op, p, cp; + + char buf[1024]; + + i->rn = (i->w >> 16) & 0xf; + i->rd = (i->w >> 12) & 0xf; + i->rs = i->w&0xf; + cp = (i->w >> 8) & 0xf; + p = (i->w >> 5) & 0x7; + if(i->w&0x10) { + op = (i->w >> 20) & 0x0f; + snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } else { + op = (i->w >> 21) & 0x07; + snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p); + } + format(o->o, i, buf); +} + +static Opcode opcodes[] = +{ + "AND%C%S", armdps, "R%s,R%n,R%d", + "EOR%C%S", armdps, "R%s,R%n,R%d", + "SUB%C%S", armdps, "R%s,R%n,R%d", + "RSB%C%S", armdps, "R%s,R%n,R%d", + "ADD%C%S", armdps, "R%s,R%n,R%d", + "ADC%C%S", armdps, "R%s,R%n,R%d", + "SBC%C%S", armdps, "R%s,R%n,R%d", + "RSC%C%S", armdps, "R%s,R%n,R%d", + "TST%C%S", armdps, "R%s,R%n,", + "TEQ%C%S", armdps, "R%s,R%n,", + "CMP%C%S", armdps, "R%s,R%n,", + "CMN%C%S", armdps, "R%s,R%n,", + "ORR%C%S", armdps, "R%s,R%n,R%d", + "MOVW%C%S", armdps, "R%s,R%d", + "BIC%C%S", armdps, "R%s,R%n,R%d", + "MVN%C%S", armdps, "R%s,R%d", + + "AND%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "EOR%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "SUB%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "RSB%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "ADD%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "ADC%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "SBC%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "RSC%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "TST%C%S", armdps, "(R%s%h#%m),R%n,", + "TEQ%C%S", armdps, "(R%s%h#%m),R%n,", + "CMP%C%S", armdps, "(R%s%h#%m),R%n,", + "CMN%C%S", armdps, "(R%s%h#%m),R%n,", + "ORR%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "MOVW%C%S", armdps, "(R%s%h#%m),R%d", + "BIC%C%S", armdps, "(R%s%h#%m),R%n,R%d", + "MVN%C%S", armdps, "(R%s%h#%m),R%d", + + "AND%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "EOR%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "SUB%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "RSB%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "ADD%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "ADC%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "SBC%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "RSC%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "TST%C%S", armdps, "(R%s%hR%m),R%n,", + "TEQ%C%S", armdps, "(R%s%hR%m),R%n,", + "CMP%C%S", armdps, "(R%s%hR%m),R%n,", + "CMN%C%S", armdps, "(R%s%hR%m),R%n,", + "ORR%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "MOVW%C%S", armdps, "(R%s%hR%m),R%d", + "BIC%C%S", armdps, "(R%s%hR%m),R%n,R%d", + "MVN%C%S", armdps, "(R%s%hR%m),R%d", + + "AND%C%S", armdpi, "$#%i,R%n,R%d", + "EOR%C%S", armdpi, "$#%i,R%n,R%d", + "SUB%C%S", armdpi, "$#%i,R%n,R%d", + "RSB%C%S", armdpi, "$#%i,R%n,R%d", + "ADD%C%S", armdpi, "$#%i,R%n,R%d", + "ADC%C%S", armdpi, "$#%i,R%n,R%d", + "SBC%C%S", armdpi, "$#%i,R%n,R%d", + "RSC%C%S", armdpi, "$#%i,R%n,R%d", + "TST%C%S", armdpi, "$#%i,R%n,", + "TEQ%C%S", armdpi, "$#%i,R%n,", + "CMP%C%S", armdpi, "$#%i,R%n,", + "CMN%C%S", armdpi, "$#%i,R%n,", + "ORR%C%S", armdpi, "$#%i,R%n,R%d", + "MOVW%C%S", armdpi, "$#%i,,R%d", + "BIC%C%S", armdpi, "$#%i,R%n,R%d", + "MVN%C%S", armdpi, "$#%i,,R%d", + + "MUL%C%S", armdpi, "R%s,R%m,R%n", + "MULA%C%S", armdpi, "R%s,R%m,R%n,R%d", + "SWPW", armdpi, "R%s,(R%n),R%d", + "SWPB", armdpi, "R%s,(R%n),R%d", + + "MOVW%C%p", armsdti,"R%d,#%i(R%n)", + "MOVB%C%p", armsdti,"R%d,#%i(R%n)", + "MOVW%C%p", armsdti,"#%i(R%n),R%d", + "MOVB%C%p", armsdti,"#%i(R%n),R%d", + + "MOVW%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)", + "MOVB%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)", + "MOVW%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d", + "MOVB%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d", + + "MOVM%C%P%a", armbdt, "R%n,[%r]", + "MOVM%C%P%a", armbdt, "[%r],R%n", + + "B%C", armb, "%b", + "BL%C", armb, "%b", + + "CDP%C", armco, "", + "CDP%C", armco, "", + "MCR%C", armco, "", + "MRC%C", armco, "", + + "UNK", armunk, "", +}; + +static char *mode[] = { 0, "IA", "DB", "IB" }; +static char *pw[] = { "P", "PW", 0, "W" }; +static char *sw[] = { 0, "W", "S", "SW" }; + +static void +format(char *mnemonic, Instr *i, char *f) +{ + int j, k, m, n; + + if(mnemonic) + format(0, i, mnemonic); + if(f == 0) + return; + if(mnemonic) + if(i->curr < i->end) + *i->curr++ = '\t'; + for ( ; *f && i->curr < i->end; f++) { + if(*f != '%') { + *i->curr++ = *f; + continue; + } + switch (*++f) { + + case 'C': /* .CONDITION */ + if(cond[i->cond]) + bprint(i, ".%s", cond[i->cond]); + break; + + case 'S': /* .STORE */ + if(i->store) + bprint(i, ".S"); + break; + + case 'P': /* P & U bits for block move */ + n = (i->w >>23) & 0x3; + if (mode[n]) + bprint(i, ".%s", mode[n]); + break; + + case 'D': /* ~U bit for single data xfer */ + if((i->w & (1<<23)) == 0) + bprint(i, "-"); + break; + + case 'p': /* P & W bits for single data xfer*/ + if (pw[i->store]) + bprint(i, ".%s", pw[i->store]); + break; + + case 'a': /* S & W bits for single data xfer*/ + if (sw[i->store]) + bprint(i, ".%s", sw[i->store]); + break; + + case 's': + bprint(i, "%d", i->rs & 0xf); + break; + + case 'm': + bprint(i, "%d", (i->w>>7) & 0x1f); + break; + + case 'h': + bprint(i, "%s", shtype[(i->w>>5) & 0x3]); + break; + + case 'n': + bprint(i, "%d", i->rn); + break; + + case 'd': + bprint(i, "%d", i->rd); + break; + + case 'i': + bprint(i, "%lux", i->imm); + break; + + case 'b': + bprint(i, "%lux", i->imm); + break; + + case 'r': + n = i->imm&0xffff; + j = 0; + k = 0; + while(n) { + m = j; + while(n&0x1) { + j++; + n >>= 1; + } + if(j != m) { + if(k) + bprint(i, ","); + if(j == m+1) + bprint(i, "R%d", m); + else + bprint(i, "R%d-R%d", m, j-1); + k = 1; + } + j++; + n >>= 1; + } + break; + + case '\0': + *i->curr++ = '%'; + return; + + default: + bprint(i, "%%%c", *f); + break; + } + } + *i->curr = 0; +} + +void +das(ulong *x, int n) +{ + ulong pc; + Instr i; + char buf[128]; + + pc = (ulong)x; + while(n > 0) { + i.curr = buf; + i.end = buf+sizeof(buf)-1; + + if(decode(pc, &i) < 0) + sprint(buf, "???"); + else + (*opcodes[i.op].f)(&opcodes[i.op], &i); + + print("%.8lux %.8lux\t%s\n", pc, i.w, buf); + pc += 4; + n--; + } +} |
