#include #include #include #include #include #include "arm64_printer.h" #include "debug.h" static const char* Xt[] = {"xEmu", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "xRAX", "xRCX", "xRDX", "xRBX", "xRSP", "xRBP", "xRSI", "xRDI", "xR8", "xR9", "xR10", "xR11", "xR12", "xR13", "xR14", "xR15", "xFlags", "xRIP", "x28", "FP", "LR", "xZR"}; static const char* XtSp[] = {"xEmu", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "xRAX", "xRCX", "xRDX", "xRBX", "xRSP", "xRBP", "xRSI", "xRDI", "xR8", "xR9", "xR10", "xR11", "xR12", "xR13", "xR14", "xR15", "xFlags", "xRIP", "x28", "FP", "LR", "SP"}; static const char* Wt[] = {"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "wEAX", "wECX", "wEDX", "wEBX", "wESP", "wEBP", "wESI", "wEDI", "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15", "wFlags", "w27", "w28", "w29", "w30", "wZR"}; static const char* WtSp[] = {"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "wEAX", "wECX", "wEDX", "wEBX", "wESP", "wEBP", "wESI", "wEDI", "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15", "wFlags", "w27", "w28", "w29", "w30", "wSP"}; static const char* conds[] = {"cEQ", "cNE", "cCS", "cCC", "cMI", "cPL", "cVS", "cVC", "cHI", "cLS", "cGE", "cLT", "cGT", "cLE", "c__", "inv"}; #define abs(A) (((A)<0)?(-(A)):(A)) typedef struct arm64_print_s { int N, S, U, L, Q, A, R; int t, n, m, d, t2, a; int f, c, o, h, p; int i, r, s; int x, w; } arm64_print_t; uint64_t DecodeBitMasks(int N, int imms, int immr) { int len = 31-__builtin_clz((N<<6) | ((~imms)&0b111111)); if(len<1) return 0; int levels = (1<>r)|(mask<<(e-r)); if(e<64) { mask&=((1LL<>i)&1; switch(*mask) { case '0': if(v!=0) return 0; break; case '1': if(v!=1) return 0; break; case 'N': a->N = (a->N<<1) | v; break; case 'S': a->S = (a->S<<1) | v; break; case 'U': a->U = (a->U<<1) | v; break; case 'A': a->A = (a->A<<1) | v; break; case 'R': a->R = (a->R<<1) | v; break; case 'L': a->L = (a->L<<1) | v; break; case 'Q': a->Q = (a->Q<<1) | v; break; case 't': a->t = (a->t<<1) | v; break; case '2': a->t2 = (a->t2<<1) | v; break; case 'n': a->n = (a->n<<1) | v; break; case 'p': a->p = (a->p<<1) | v; break; case 'm': a->m = (a->m<<1) | v; break; case 'a': a->a = (a->a<<1) | v; break; case 'd': a->d = (a->d<<1) | v; break; case 'f': a->f = (a->f<<1) | v; break; case 'c': a->c = (a->c<<1) | v; break; case 'i': a->i = (a->i<<1) | v; break; case 'r': a->r = (a->r<<1) | v; break; case 's': a->s = (a->s<<1) | v; break; case 'o': a->o = (a->o<<1) | v; break; case 'h': a->h = (a->h<<1) | v; break; case 'w': a->w = (a->w<<1) | v; break; case 'x': a->x = (a->x<<1) | v; break; default: printf_log(LOG_NONE, "Warning, printer mask use unhandled '%c'\n", *mask); } mask++; --i; } return 1; } int64_t signExtend(uint32_t val, int sz) { int64_t ret = val; if((val>>(sz-1))&1) ret |= (0xffffffffffffffffll<>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDUR %s, [%s], %s0x%x", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x111000010iiiiiiiii11nnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDUR %s, [%s, %s0x%x]!", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x111000010iiiiiiiii00nnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "00111000010iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "01111000010iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "001110001x0iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "011110001x0iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "10111000100iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x111000000iiiiiiiii00nnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "STUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "00111000000iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "STURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "01111000000iiiiiiiii00nnnnnttttt", &a)) { int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "STURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = (imm)<>30)&1)?3:2; int offset = signExtend(imm, 19)<<2; snprintf(buff, sizeof(buff), "LDR %s, [#%+d]\t;%p", (size==2)?Wt[Rt]:Xt[Rt], offset, (void*)(addr+offset)); return buff; } if(isMask(opcode, "10011000iiiiiiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 19)<<2; snprintf(buff, sizeof(buff), "LDRSW %s, [#%+d]\t;%p", Xt[Rt], offset, (void*)(addr+offset)); return buff; } if(isMask(opcode, "ff011100iiiiiiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 19)<<2; const char* Y[] = {"S", "D", "Q", "?"}; snprintf(buff, sizeof(buff), "LDR %s%d, [#%+d]\t;%p", Y[sf], Rt, offset, (void*)(addr+offset)); return buff; } if(isMask(opcode, "1x111000011mmmmmoooS10nnnnnttttt", &a)) { int size = (opcode>>30)&3; const char* extend[] = {"?0", "?1", "UXTW", "LSL", "?4", "?5", "SXTW", "SXTX"}; int amount = size*a.S; if(option==3 && !amount) snprintf(buff, sizeof(buff), "LDR %s, [%s, %s]", (size==2)?Wt[Rt]:Xt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm]); else snprintf(buff, sizeof(buff), "LDR %s, [%s, %s, %s %d]", (size==2)?Wt[Rt]:Xt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount); return buff; } if(isMask(opcode, "1x111000000iiiiiiiii01nnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "STR %s, [%s], %s0x%x", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x111000000iiiiiiiii11nnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "STR %s, [%s, %s0x%x]!", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "1x11100100iiiiiiiiiiiinnnnnttttt", &a)) { int size = (opcode>>30)&3; int offset = (imm)<>30)&3; const char* extend[] = {"?0", "?1", "UXTW", "LSL", "?4", "?5", "SXTW", "SXTX"}; int amount = size*a.S; if(option==3 && !amount) snprintf(buff, sizeof(buff), "STR %s, [%s, %s]", (size==2)?Wt[Rt]:Xt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm]); else snprintf(buff, sizeof(buff), "STR %s, [%s, %s, %s %d]", (size==2)?Wt[Rt]:Xt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount); return buff; } if(isMask(opcode, "00111000001mmmmmoooS10nnnnnttttt", &a)) { const char* extend[] = {"?0", "?1", "UXTW", "LSL", "?4", "?5", "SXTW", "SXTX"}; int amount = a.S; if(option==3 && !amount) snprintf(buff, sizeof(buff), "STRB %s, [%s, %s]", Wt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm]); else snprintf(buff, sizeof(buff), "STRB %s, [%s, %s, %s %d]", Wt[Rt], XtSp[Rn], ((option&1)==0)?Wt[Rm]:Xt[Rm], extend[option], amount); return buff; } if(isMask(opcode, "0x111000010iiiiiiiii01nnnnnttttt", &a)) { int size = a.x; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDR%c %s, [%s], %s0x%x", size?'H':'B', Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "0x111000010iiiiiiiii11nnnnnttttt", &a)) { int size = a.x; int offset = signExtend(imm, 9); snprintf(buff, sizeof(buff), "LDR%c %s, [%s, %s0x%x]!", size?'H':'B', Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } if(isMask(opcode, "0x11100101iiiiiiiiiiiinnnnnttttt", &a)) { int size = a.x; int offset = (imm)<=immr) snprintf(buff, sizeof(buff), "UBFX %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1); else snprintf(buff, sizeof(buff), "UBFM %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms); return buff; } if(isMask(opcode, "f0011010110mmmmm001010nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "ASR %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); return buff; } if(isMask(opcode, "f00100110Nrrrrrrssssssnnnnnddddd", &a)) { if(sf && imms==0b111111) snprintf(buff, sizeof(buff), "ASR %s, %s, %d", Xt[Rd], Xt[Rn], immr); else if(!sf && imms==0b011111) snprintf(buff, sizeof(buff), "ASR %s, %s, %d", Wt[Rd], Wt[Rn], immr); else if(immr==0 && imms==0b000111) snprintf(buff, sizeof(buff), "SXTB %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]); else if(immr==0 && imms==0b001111) snprintf(buff, sizeof(buff), "SXTH %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]); else if(sf && immr==0 && imms==0b011111) snprintf(buff, sizeof(buff), "SXTW %s, %s", Xt[Rd], Wt[Rn]); else if(imms>=immr) snprintf(buff, sizeof(buff), "SBFX %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1); else snprintf(buff, sizeof(buff), "SBFM %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms); return buff; } if(isMask(opcode, "f00100111N0mmmmmssssssnnnnnddddd", &a)) { if(Rn==Rm) snprintf(buff, sizeof(buff), "ROR %s, %s, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], imms); else snprintf(buff, sizeof(buff), "EXTR %s, %s, %s, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], imms); return buff; } if(isMask(opcode, "f0011010110mmmmm001011nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "ROR %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); return buff; } if(isMask(opcode, "f0011010110mmmmm001001nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "LSR %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); return buff; } if(isMask(opcode, "f0011010110mmmmm001000nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "LSL %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]); return buff; } if(isMask(opcode, "f01100110Nrrrrrrssssssnnnnnddddd", &a)) { if(imms>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "000101iiiiiiiiiiiiiiiiiiiiiiiiii", &a)) { int offset = signExtend(imm, 26)<<2; snprintf(buff, sizeof(buff), "B #+%di\t; %p", offset>>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "f0110100iiiiiiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 19)<<2; snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "f0110101iiiiiiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 19)<<2; snprintf(buff, sizeof(buff), "CBNZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "s0110110sssssiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 14)<<2; snprintf(buff, sizeof(buff), "TBZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "s0110111sssssiiiiiiiiiiiiiittttt", &a)) { int offset = signExtend(imm, 14)<<2; snprintf(buff, sizeof(buff), "TBNZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset)); return buff; } if(isMask(opcode, "f0011010100mmmmmcccc01nnnnnddddd", &a)) { if(Rm!=31 && (cond&0b1110)!=0b1110 && Rn!=31 && Rn==Rm) snprintf(buff, sizeof(buff), "CINC %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond^1]); else if(Rm==31 && (cond&0b1110)!=0b1110 && Rn==31) snprintf(buff, sizeof(buff), "CSET %s,%s", sf?Xt[Rd]:Wt[Rd], conds[cond^1]); else snprintf(buff, sizeof(buff), "CSINC %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]); return buff; } if(isMask(opcode, "f1011010100mmmmmcccc00nnnnnddddd", &a)) { if(Rm!=31 && (cond&0b1110)!=0b1110 && Rn!=31 && Rn==Rm) snprintf(buff, sizeof(buff), "CINV %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond^1]); else if(Rm==31 && (cond&0b1110)!=0b1110 && Rn==31) snprintf(buff, sizeof(buff), "CSETM %s,%s", sf?Xt[Rd]:Wt[Rd], conds[cond^1]); else snprintf(buff, sizeof(buff), "CSINV %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]); return buff; } if(isMask(opcode, "f1011010100mmmmmcccc01nnnnnddddd", &a)) { if((cond&0b1110)!=0b1110 && Rn==Rm) snprintf(buff, sizeof(buff), "CNEG %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], conds[cond^1]); else snprintf(buff, sizeof(buff), "CSNEG %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]); return buff; } if(isMask(opcode, "f0011010100mmmmmcccc00nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "CSEL %s, %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond]); return buff; } if(isMask(opcode, "f1111010010mmmmmcccc00nnnnn0iiii", &a)) { snprintf(buff, sizeof(buff), "CCMP %s, %s, %s 0x%x", sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], conds[cond], imm); return buff; } // MISC Bits if(isMask(opcode, "f10110101100000000010onnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "CL%c %s, %s", option?'S':'Z', sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]); return buff; } if(isMask(opcode, "f101101011000000000000nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "RBIT %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn]); return buff; } if(isMask(opcode, "f1011010110000000000oonnnnnddddd", &a)) { if(!sf && option==2) snprintf(buff, sizeof(buff), "REV %s, %s", Wt[Rd], Wt[Rn]); else if (sf && option==3) snprintf(buff, sizeof(buff), "REV %s, %s", Xt[Rd], Xt[Rn]); else snprintf(buff, sizeof(buff), "REV%d %s, %s", 8< nzcv //o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0100(4) op2=2 => fpcr if(a.o==1 && a.p==3 && a.n==4 && a.m==2 && a.t2==0) reg="nzcv"; else if(a.o==1 && a.p==3 && a.n==4 && a.m==4 && a.t2==2) reg="fpcr"; if(!reg) snprintf(buff, sizeof(buff), "MSR S%d_%d_%d_%d_%d, %s", 2+a.o, a.p, a.n, a.m, a.t2, Xt[Rt]); else snprintf(buff, sizeof(buff), "MSR %s, %s", reg, Xt[Rt]); return buff; } if(isMask(opcode, "110101010011opppnnnnmmmm222ttttt", &a)) { const char* reg=NULL; //o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0010(2) op2=0 => nzcv //o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0100(4) op2=2 => fpcr if(a.o==1 && a.p==3 && a.n==4 && a.m==2 && a.t2==0) reg="nzcv"; else if(a.o==1 && a.p==3 && a.n==4 && a.m==4 && a.t2==2) reg="fpcr"; if(!reg) snprintf(buff, sizeof(buff), "MRS %s, S%d_%d_%d_%d_%d", Xt[Rt], 2+a.o, a.p, a.n, a.m, a.t2); else snprintf(buff, sizeof(buff), "MRS %s, %s", Xt[Rt], reg); return buff; } // ----------- NEON / FPU // VORR/VAND/VBIC/VORN if(isMask(opcode, "0Q001110101mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; if(Rn==Rm) snprintf(buff, sizeof(buff), "VMOV %c%d, %c%d", q, Rd, q, Rn); else snprintf(buff, sizeof(buff), "VORR %c%d, %c%d, %c%d", q, Rd, q, Rn, q, Rm); return buff; } if(isMask(opcode, "0Q001110111mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; snprintf(buff, sizeof(buff), "VORN %c%d, %c%d, %c%d", q, Rd, q, Rn, q, Rm); return buff; } if(isMask(opcode, "0Q001110001mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; snprintf(buff, sizeof(buff), "VAND %c%d, %c%d, %c%d", q, Rd, q, Rn, q, Rm); return buff; } if(isMask(opcode, "0Q001110011mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; snprintf(buff, sizeof(buff), "VBIC %c%d, %c%d, %c%d", q, Rd, q, Rn, q, Rm); return buff; } // UMOV if(isMask(opcode, "0Q001110000rrrrr001111nnnnnddddd", &a)) { char s = '?'; int sz=0; if(a.Q==0 && immr&1) {s='B'; sz=0; } else if(a.Q==0 && (immr&3)==2) {s='H'; sz=1; } else if(a.Q==0 && (immr&7)==4) {s='S'; sz=2; } else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; } int index = (immr)>>(sz+1); if(sz>2) snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index); else snprintf(buff, sizeof(buff), "UMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index); return buff; } // SMOV if(isMask(opcode, "0Q001110000rrrrr001011nnnnnddddd", &a)) { char s = '?'; int sz=0; if(a.Q==0 && immr&1) {s='B'; sz=0; } else if(/*a.Q==0 &&*/ (immr&3)==2) {s='H'; sz=1; } else if(/*a.Q==0 &&*/ (immr&7)==4) {s='S'; sz=2; } else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; } int index = (immr)>>(sz+1); if(sz>2) snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index); else snprintf(buff, sizeof(buff), "SMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index); return buff; } // VEOR if(isMask(opcode, "0Q101110001mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; snprintf(buff, sizeof(buff), "VEOR %c%d, %c%d, %c%d", q, Rd, q, Rn, q, Rm); return buff; } // VADD / VSUB if(isMask(opcode, "0QU01110ff1mmmmm100001nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd = Y[((sf)<<1) | a.Q]; snprintf(buff, sizeof(buff), "V%s V%d.%s, V%d.%s, V%d.%s", a.U?"SUB":"ADD", Rd, Vd, Rn, Vd, Rm, Vd); return buff; } // VMUL if(isMask(opcode, "0Q001110ff1mmmmm100111nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd = Y[((sf)<<1) | a.Q]; snprintf(buff, sizeof(buff), "VMUL V%d.%s, V%d.%s, V%d.%s", Rd, Vd, Rn, Vd, Rm, Vd); return buff; } // VBIT / VBIF if(isMask(opcode, "0Q1011101o1mmmmm000111nnnnnddddd", &a)) { char q = a.Q?'Q':'D'; snprintf(buff, sizeof(buff), "VBI%c %c%d, %c%d, %c%d", a.o?'F':'T', q, Rd, q, Rn, q, Rm); return buff; } // CMP if(isMask(opcode, "0Q101110ff1mmmmm100011nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd = Y[((sf)<<1) | a.Q]; snprintf(buff, sizeof(buff), "VCMEQ V%d.%s, V%d.%s, V%d.%s", Rd, Vd, Rn, Vd, Rm, Vd); return buff; } // CMP zero if(isMask(opcode, "0QU01110ff100000100o10nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Z[] = {"GT", "GE", "EQ", "LE"}; const char* Vd = Y[((sf)<<1) | a.Q]; const char* Cond = Z[(a.o << 1 | a.U)]; snprintf(buff, sizeof(buff), "VCM%s V%d.%s, V%d.%s, #0", Cond, Rd, Vd, Rn, Vd); return buff; } // CMPLT zero if(isMask(opcode, "0Q001110ff100000101010nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd = Y[((sf)<<1) | a.Q]; snprintf(buff, sizeof(buff), "VCMLT V%d.%s, V%d.%s, #0", Rd, Vd, Rn, Vd); return buff; } // MIN/MAX if(isMask(opcode, "0QU01110ff1mmmmm0110o1nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd = Y[((sf)<<1) | a.Q]; snprintf(buff, sizeof(buff), "%c%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.o?"MIN":"MAX", Rd, Vd, Rn, Vd, Rm, Vd); return buff; } // MOV immediate (not)shifted 8bits if(isMask(opcode, "0Q00111100000iii111001iiiiiddddd", &a)) { const char* Y[] = {"8B", "16B"}; const char* Vd = Y[a.Q]; snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm); return buff; } // MOV immediate notshifted 16bits & 32bits if(isMask(opcode, "0Q00111100000iiif00001iiiiiddddd", &a)) { const char* Y[] = {"2S", "4S", "4H", "8H"}; const char* Vd = Y[(sf<<1)| a.Q]; int sh = 0; snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm<>1; idx2 = imms; } else if((immr&3)==2) {s='H'; idx1=(immr)>>2; idx2=(imms)>>1;} else if((immr&7)==4) {s='S'; idx1=(immr)>>3; idx2=(imms)>>2;} else if((immr&15)==8) {s='D'; idx1=(immr)>>4; idx2=(imms)>>3;} snprintf(buff, sizeof(buff), "INS V%d.%c[%d], V%d.%c[%d]", Rd, s, idx1, Rn, s, idx2); return buff; } if(isMask(opcode, "01001110000rrrrr000111nnnnnddddd", &a)) { char s = '?', R = 0; int idx1=0; if(immr&1) {s='B'; idx1=(immr)>>1; } else if((immr&3)==2) {s='H'; idx1=(immr)>>2;} else if((immr&7)==4) {s='S'; idx1=(immr)>>3;} else if((immr&15)==8) {s='D'; idx1=(immr)>>4; R=1;} snprintf(buff, sizeof(buff), "INS V%d.%c[%d], %s", Rd, s, idx1, R?Xt[Rn]:Wt[Rn]); return buff; } // ADR if(isMask(opcode, "0ss10000iiiiiiiiiiiiiiiiiiiddddd", &a)) { snprintf(buff, sizeof(buff), "ADR, %s, %"PRId64, Xt[Rd], signExtend((imm)<<2|(imms), 20)); return buff; } // LDR / STR if(isMask(opcode, "ss111101cciiiiiiiiiiiinnnnnttttt", &a)) { char s = '?'; int size=imms; int op=0; if(size==0 && opc==1) {s='B';} else if(size==1 && opc==1) {s='H';} else if(size==2 && opc==1) {s='S';} else if(size==3 && opc==1) {s='D';} else if(size==0 && opc==3) {s='Q'; size = 4;} else if(size==0 && opc==0) {s='B'; op=1;} else if(size==1 && opc==0) {s='H'; op=1;} else if(size==2 && opc==0) {s='S'; op=1;} else if(size==3 && opc==0) {s='D'; op=1;} else if(size==0 && opc==2) {s='Q'; op=1; size = 4;} int offset = imm<>scale; break; case 0: idx = (a.Q<<3) | (a.S<<2) | sf; break; case 1: idx = (a.Q<<2) | (a.S<<1) | (sf>>1); break; case 2: if(!(sf&1)) idx = (a.Q<<1) | a.S; else { scale = 3; idx = a.Q; } break; } if(!option && a.L && scale==3) snprintf(buff, sizeof(buff), "LD1R {V%d.%d%s}, [%s]", Rt, idx, Y[scale], XtSp[Rn]); else snprintf(buff, sizeof(buff), "%s1 {V%d.%s}[%d], [%s]", a.L?"LD":"ST", Rt, Y[scale], idx, XtSp[Rn]); return buff; } // LDUR/STUR if(isMask(opcode, "ff111100cL0iiiiiiiii00nnnnnttttt", &a)) { const char* Y[] = {"B", "H", "S", "D", "Q"}; int sz = sf; if(sz==0 && a.c) sz = 4; int offset = signExtend(imm, 9); if(!offset) snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn]); else snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset)); return buff; } // LDR/STR vector immediate if(isMask(opcode, "ff111101cLiiiiiiiiiiiinnnnnttttt", &a)) { const char* Y[] = {"B", "H", "S", "D", "Q"}; int sz = sf; if(sz==0 && a.c) sz = 4; int offset = imm<>sz) - 1; const char* Vd = Y[(sz<<1)|a.Q]; const char* Vn = Z[sz]; snprintf(buff, sizeof(buff), "DUP V%d.%s, V%d.%s[%d]", Rd, Vd, Rn, Vn, sh); return buff; } if(isMask(opcode, "0Q001110000iiiii000011nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; int sz = 3; if((imm&0b0001)==0b0001) sz=0; else if((imm&0b0011)==0b0010) sz=1; else if((imm&0b0111)==0b0100) sz=2; const char* Vd = Y[(sz<<1)|a.Q]; snprintf(buff, sizeof(buff), "DUP V%d.%s, X%d", Rd, Vd, Rn); return buff; } // AES if(isMask(opcode, "0100111000101000010f10nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "AES%c V%d.16B, V%d.16B", sf?'D':'E', Rd, Rn); return buff; } if(isMask(opcode, "0100111000101000011f10nnnnnddddd", &a)) { snprintf(buff, sizeof(buff), "AES%sMC V%d.16B, V%d.16B", sf?"I":"", Rd, Rn); return buff; } // PMULL if(isMask(opcode, "0Q001110ff1mmmmm111000nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "??", "??", "??", "??", "1D", "2D"}; const char* Z[] = {"8H", "??", "??", "1Q"}; int sz = sf; const char* Vn = Y[(sz<<1)|a.Q]; const char* Vd = Z[sz]; snprintf(buff, sizeof(buff), "PMULL%s V%d.%s, V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn); return buff; } // [S/U]MULL if(isMask(opcode, "0QU01110ff1mmmmm110000nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"}; const char* Z[] = {"8H", "4S", "2D", "??"}; int sz = sf; const char* Vn = Y[(sz<<1)|a.Q]; const char* Vd = Z[sz]; snprintf(buff, sizeof(buff), "%cMULL%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn); return buff; } //XTN(2) if(isMask(opcode, "0Q001110ff100001001010nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"}; const char* Z[] = {"8H", "4S", "2D", "??"}; int sz = sf; const char* Vd = Y[(sz<<1)|a.Q]; const char* Vn = Z[sz]; snprintf(buff, sizeof(buff), "XTN%s V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn); return buff; } // DMB if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) { const char* barrier[] = { "???", "???", "???", "???", // 0-3 "???", "???", "???", "???", // 4-7 "???", "ISHLD", "ISHST", "ISH", // 8-11 "???", "LD", "ST", "SY" // 12-15 }; snprintf(buff, sizeof(buff), "DMB %s", barrier[Rn]); return buff; } // DSB if(isMask(opcode, "11010101000000110011nnnn10011111", &a)) { const char* barrier[] = { "???", "???", "???", "???", // 0-3 "???", "???", "???", "???", // 4-7 "???", "ISHLD", "ISHST", "ISH", // 8-11 "???", "LD", "ST", "SY" // 12-15 }; snprintf(buff, sizeof(buff), "DSB %s", barrier[Rn]); return buff; } // CASxw if(isMask(opcode, "1f0010001L1ssssso11111nnnnnttttt", &a)) { snprintf(buff, sizeof(buff), "CAS%s%s %s, %s, [%s]", a.o?"A":"", a.L?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]); return buff; } // CAS B/H if(isMask(opcode, "0f0010001L1ssssso11111nnnnnttttt", &a)) { snprintf(buff, sizeof(buff), "CAS%s%s%s %s, %s, [%s]", a.o?"A":"", a.L?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]); return buff; } // CASPxw if(isMask(opcode, "0f0010000L1ssssso11111nnnnnttttt", &a)) { snprintf(buff, sizeof(buff), "CASP%s%s %s,%s, %s,%s, [%s]", a.o?"A":"", a.L?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rs+1]:Wt[Rs+1], sf?Xt[Rt]:Wt[Rt], sf?Xt[Rt+1]:Wt[Rt+1], XtSp[Rn]); return buff; } // SWPxw if(isMask(opcode, "1f111000AR1sssss100000nnnnnttttt", &a)) { snprintf(buff, sizeof(buff), "SWP%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]); return buff; } // SWP B/H if(isMask(opcode, "0f111000AR1sssss100000nnnnnttttt", &a)) { snprintf(buff, sizeof(buff), "SWP%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]); return buff; } // LDXXXxw if(isMask(opcode, "1f111000AR1sssss0ooo00nnnnnttttt", &a)) { const char* ops[] = { "ADD", "CLR", "EOR", "SET", "SMAX, SMIN", "UMAX", "UMIN" }; if((Rt == 0b11111) && !a.A) { snprintf(buff, sizeof(buff), "ST%s%s %s, [%s]", ops[a.o], a.R?"L":"", sf?Xt[Rs]:Wt[Rs], XtSp[Rn]); } else { snprintf(buff, sizeof(buff), "LD%s%s%s %s, %s, [%s]", ops[a.o], a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]); } return buff; } // LDXXX B/H if(isMask(opcode, "0f111000AR1sssss0ooo00nnnnnttttt", &a)) { const char* ops[] = { "ADD", "CLR", "EOR", "SET", "SMAX, SMIN", "UMAX", "UMIN" }; if((Rt == 0b11111) && !a.A) { snprintf(buff, sizeof(buff), "ST%s%s%s %s, [%s]", ops[a.o], a.R?"L":"", sf?"H":"B", Xt[Rs], XtSp[Rn]); } else { snprintf(buff, sizeof(buff), "LD%s%s%s%s %s, %s, [%s]", ops[a.o], a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]); } return buff; } // AXFLAG if(isMask(opcode, "11010101000000000100000001011111", &a)) { snprintf(buff, sizeof(buff), "AXFLAG"); return buff; } // XAFLAG if(isMask(opcode, "11010101000000000100000000111111", &a)) { snprintf(buff, sizeof(buff), "XAFLAG"); return buff; } // CFINV if(isMask(opcode, "11010101000000000100000000011111", &a)) { snprintf(buff, sizeof(buff), "CFINV"); return buff; } // RMIF if(isMask(opcode, "10111010000iiiiii00001nnnnn0oooo", &a)) { snprintf(buff, sizeof(buff), "RMIF %s, #%d, #0x%x", Xt[Rn], imm, opc); return buff; } // SETF if(isMask(opcode, "00111010000000000f0010nnnnn01101", &a)) { snprintf(buff, sizeof(buff), "SETF%d %s", 8<