#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; 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)); 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 '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), "LDR %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), "LDR %s, [%s, %s0x%x]!", (size==0b10)?Wt[Rt]:Xt[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, "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], Xt[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", Xt[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", Xt[Rt], 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", Xt[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, 0x%x, #%+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, 0x%x, #%+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; } // 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 q = a.Q?'Q':'D'; 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, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, Rn, s, index); else snprintf(buff, sizeof(buff), "UMOV %s, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, 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; } // 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; } // Shift if(isMask(opcode, "0QU011110hhhhrrr000001nnnnnddddd", &a)) { const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"}; const char* Vd ="??"; int s = 0; if(shift==0b0001) {Vd = Y[a.Q]; s=16-((shift)<<3 | immr);} else if((shift&0b1110)==0b0010) {Vd = Y[2+a.Q]; s=32-((shift)<<3 | immr);} else if((shift&0b1100)==0b0100) {Vd = Y[4+a.Q]; s=64-((shift)<<3 | immr);} else if((shift&0b1000)==0b1000) {Vd = Y[6+a.Q]; s=128-((shift)<<3 | immr);} snprintf(buff, sizeof(buff), "%cSHR V%d.%s, V%d.%s, #%d", a.U?'U':'S', Rd, Vd, Rn, Vd, s); return buff; } // INS if(isMask(opcode, "01101110000rrrrr0ssss1nnnnnddddd", &a)) { char s = '?'; int idx1=0, idx2=0; if(immr&1) {s='B'; idx1=(immr)>>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; } // 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<>1); break; case 2: if(!(sf&1)) idx = (a.Q<<1) | a.S; else { scale = 3; idx = a.Q; } break; } 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], Rd, XtSp[Rn]); else snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rd, XtSp[Rn], imm); 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<