regtest: add check for -Wl,--no-warn-execstack
[valgrind.git] / VEX / priv / guest_nanomips_toIR.c
blob3827ac3fc0bce098c4db58ac11b27e1131e1b779
2 /*--------------------------------------------------------------------*/
3 /*--- begin guest_nanomips_toIR.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2017-2018 RT-RK
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
27 The GNU General Public License is contained in the file COPYING.
30 /* Translates nanoMIPS code to IR. */
32 #include "libvex_basictypes.h"
33 #include "libvex_ir.h"
34 #include "libvex.h"
35 #include "libvex_guest_mips32.h"
37 #include "main_util.h"
38 #include "main_globals.h"
39 #include "guest_generic_bb_to_IR.h"
40 #include "guest_nanomips_defs.h"
42 #define P16 0x4
44 #define DIP(format, args...) \
45 if (vex_traceflags & VEX_TRACE_FE) \
46 vex_printf(format, ## args)
48 #define OFFB_PC offsetof(VexGuestMIPS32State, guest_PC)
50 #define ILLEGAL_INSTRUCTON \
51 dres->jk_StopHere = Ijk_SigILL; \
52 dres->whatNext = Dis_StopHere;
54 #define LLADDR_INVALID (mkU32(0xFFFFFFFF))
56 /* MOD: The IRSB* into which we're generating code. */
57 static IRSB *irsb;
59 /* CONST: The guest address for the instruction currently being
60 translated. */
61 static Addr32 guest_PC_curr_instr;
63 /* Do a endian load of a 16-bit word, regardless of the endianness of the
64 underlying host. */
65 static inline UShort getUShort(const UChar * p)
67 UShort w = 0;
68 #if defined (_MIPSEL)
69 w = (w << 8) | p[1];
70 w = (w << 8) | p[0];
71 #elif defined (_MIPSEB)
72 w = (w << 8) | p[0];
73 w = (w << 8) | p[1];
74 #endif
75 return w;
78 /* Do a endian load of a 32-bit code word. */
79 static inline UInt getUInt(const UChar * p)
81 return (getUShort(p) << 16) | getUShort(p + 2);
84 const UChar GPR3_list[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
85 const UChar GPR4_list[] = { 8, 9, 10, 11, 4, 5, 6, 7, 16, 17, 18, 19,
86 20, 21, 22, 23
88 const UChar GPR4_zero_list[] = { 8, 9, 10, 0, 4, 5, 6, 7, 16, 17, 18,
89 19, 20, 21, 22, 23
91 const UChar GPR3_src_store_list[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
92 const UChar GPR2_reg1_list[] = { 4, 5, 6, 7 };
93 const UChar GPR2_reg2_list[] = { 5, 6, 7, 8 };
95 static UInt integerGuestRegOffset(UInt iregNo)
97 /* Maybe we should use formula ??? */
98 switch (iregNo) {
99 case 0:
100 return offsetof(VexGuestMIPS32State, guest_r0);
102 case 1:
103 return offsetof(VexGuestMIPS32State, guest_r1);
105 case 2:
106 return offsetof(VexGuestMIPS32State, guest_r2);
108 case 3:
109 return offsetof(VexGuestMIPS32State, guest_r3);
111 case 4:
112 return offsetof(VexGuestMIPS32State, guest_r4);
114 case 5:
115 return offsetof(VexGuestMIPS32State, guest_r5);
117 case 6:
118 return offsetof(VexGuestMIPS32State, guest_r6);
120 case 7:
121 return offsetof(VexGuestMIPS32State, guest_r7);
123 case 8:
124 return offsetof(VexGuestMIPS32State, guest_r8);
126 case 9:
127 return offsetof(VexGuestMIPS32State, guest_r9);
129 case 10:
130 return offsetof(VexGuestMIPS32State, guest_r10);
132 case 11:
133 return offsetof(VexGuestMIPS32State, guest_r11);
135 case 12:
136 return offsetof(VexGuestMIPS32State, guest_r12);
138 case 13:
139 return offsetof(VexGuestMIPS32State, guest_r13);
141 case 14:
142 return offsetof(VexGuestMIPS32State, guest_r14);
144 case 15:
145 return offsetof(VexGuestMIPS32State, guest_r15);
147 case 16:
148 return offsetof(VexGuestMIPS32State, guest_r16);
150 case 17:
151 return offsetof(VexGuestMIPS32State, guest_r17);
153 case 18:
154 return offsetof(VexGuestMIPS32State, guest_r18);
156 case 19:
157 return offsetof(VexGuestMIPS32State, guest_r19);
159 case 20:
160 return offsetof(VexGuestMIPS32State, guest_r20);
162 case 21:
163 return offsetof(VexGuestMIPS32State, guest_r21);
165 case 22:
166 return offsetof(VexGuestMIPS32State, guest_r22);
168 case 23:
169 return offsetof(VexGuestMIPS32State, guest_r23);
171 case 24:
172 return offsetof(VexGuestMIPS32State, guest_r24);
174 case 25:
175 return offsetof(VexGuestMIPS32State, guest_r25);
177 case 26:
178 return offsetof(VexGuestMIPS32State, guest_r26);
180 case 27:
181 return offsetof(VexGuestMIPS32State, guest_r27);
183 case 28:
184 return offsetof(VexGuestMIPS32State, guest_r28);
186 case 29:
187 return offsetof(VexGuestMIPS32State, guest_r29);
189 case 30:
190 return offsetof(VexGuestMIPS32State, guest_r30);
192 case 31:
193 return offsetof(VexGuestMIPS32State, guest_r31);
196 vassert(0);
197 return 0;
200 /* Add a statement to the list held by "irsb". */
201 static void stmt(IRStmt * st)
203 addStmtToIRSB(irsb, st);
206 static IRExpr *mkU8(UInt i)
208 vassert(i < 256);
209 return IRExpr_Const(IRConst_U8((UChar) i));
212 /* Create an expression node for a 32-bit integer constant. */
213 static IRExpr *mkU32(UInt i)
215 return IRExpr_Const(IRConst_U32(i));
218 static void putPC(IRExpr * e)
220 stmt(IRStmt_Put(OFFB_PC, e));
223 static void putIReg(UInt archreg, IRExpr * e)
225 vassert(archreg < 32);
227 if (archreg != 0)
228 stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
231 static IRExpr *getIReg(UInt iregNo)
233 if (0 == iregNo) {
234 return mkU32(0x0);
235 } else {
236 IRType ty = Ity_I32;
237 vassert(iregNo < 32);
238 return IRExpr_Get(integerGuestRegOffset(iregNo), ty);
242 static void putLLaddr(IRExpr * e)
244 stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLaddr), e));
247 static IRExpr *getLLaddr(void)
249 return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLaddr), Ity_I32);
252 static void putLLdata(IRExpr * e)
254 stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e));
257 static IRExpr *getLLdata(void)
259 return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata), Ity_I32);
262 static void putLLdata64(IRExpr * e)
264 stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata64), e));
267 static IRExpr *getLLdata64(void)
269 return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata64), Ity_I64);
272 static IRExpr *unop(IROp op, IRExpr * a)
274 return IRExpr_Unop(op, a);
277 static IRExpr *binop(IROp op, IRExpr * a1, IRExpr * a2)
279 return IRExpr_Binop(op, a1, a2);
282 static IRExpr *qop(IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3, IRExpr * a4)
284 return IRExpr_Qop(op, a1, a2, a3, a4);
287 /* Generate a new temporary of the given type. */
288 static IRTemp newTemp(IRType ty)
290 vassert(isPlausibleIRType(ty));
291 return newIRTemp(irsb->tyenv, ty);
294 static void assign(IRTemp dst, IRExpr * e)
296 stmt(IRStmt_WrTmp(dst, e));
299 static void store(IRExpr * addr, IRExpr * data)
301 #if defined (_MIPSEL)
302 stmt(IRStmt_Store(Iend_LE, addr, data));
303 #elif defined (_MIPSEB)
304 stmt(IRStmt_Store(Iend_BE, addr, data));
305 #endif
308 static IRExpr *load(IRType ty, IRExpr * addr)
310 IRExpr *load1 = NULL;
311 #if defined (_MIPSEL)
312 load1 = IRExpr_Load(Iend_LE, ty, addr);
313 #elif defined (_MIPSEB)
314 load1 = IRExpr_Load(Iend_BE, ty, addr);
315 #endif
316 return load1;
319 static IRExpr *mkexpr(IRTemp tmp)
321 return IRExpr_RdTmp(tmp);
324 static UInt extend_sign(UInt value, UChar from_nbits)
326 UChar shift = 32 - from_nbits;
327 return (UInt)((((Int) value) << shift) >> shift);
330 static void ir_for_branch(DisResult *dres, IRExpr *guard, UChar length,
331 Int offset)
333 dres->whatNext = Dis_StopHere;
334 dres->jk_StopHere = Ijk_Boring;
335 stmt(IRStmt_Exit(guard, Ijk_Boring,
336 IRConst_U32(guest_PC_curr_instr + length + offset),
337 OFFB_PC));
338 putPC(mkU32(guest_PC_curr_instr + length));
341 static void nano_plsu12(DisResult *dres, UInt cins)
343 UChar rs = (cins >> 16) & 0x1F;
344 UChar rt = (cins >> 21) & 0x1F;
345 UShort u = cins & 0x0FFF;
347 switch ((cins >> 12) & 0x0F) {
348 case PLSU12_LB: { /* lb[u12] */
349 DIP("lb[u12] r%u %u(r%u)", rt, u, rs);
350 putIReg(rt, unop(Iop_8Sto32,
351 load(Ity_I8, binop(Iop_Add32, getIReg(rs), mkU32(u)))));
352 break;
355 case PLSU12_LH: { /* lh[u12] */
356 DIP("lh[u12] r%u %u(r%u)", rt, u, rs);
357 putIReg(rt, unop(Iop_16Sto32,
358 load(Ity_I16, binop(Iop_Add32, getIReg(rs), mkU32(u)))));
359 break;
362 case PLSU12_LW: { /* lw[u12] */
363 DIP("lw[u12] r%u %u(r%u)", rt, u, rs);
364 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
365 break;
368 case PLSU12_LD: { /* ld[u12] */
369 DIP("ld[u12] r%u %u(r%u)", rt, u, rs);
370 vassert(0);
371 break;
374 case PLSU12_SB: { /* sb[u12] */
375 DIP("sb[12] r%u %u(r%u)", rt, u, rs);
376 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), unop(Iop_32to8, getIReg(rt)));
377 break;
380 case PLSU12_SH: { /* sh[u12] */
381 DIP("sh[u12] r%u %u(r%u)", rt, u, rs);
382 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), unop(Iop_32to16, getIReg(rt)));
383 break;
386 case PLSU12_SW: { /* sw[u12] */
387 DIP("sw[u12] r%u, %u(r%u)", rt, u, rs);
388 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
389 break;
392 case PLSU12_SD: { /* sd[u12] */
393 DIP("sd[u12] r%u, %u(r%u)", rt, u, rs);
394 vassert(0);
397 case PLSU12_LBU: { /* lbu[u12] */
398 DIP("lbu r%u, %u(r%u)", rt, u, rs);
399 putIReg(rt, unop(Iop_8Uto32,
400 load(Ity_I8, binop(Iop_Add32, getIReg(rs), mkU32(u)))));
401 break;
404 case PLSU12_LHU: { /* lhu[u12] */
405 DIP("lhu[u12] r%u %u(r%u)", rt, u, rs);
406 putIReg(rt, unop(Iop_16Uto32,
407 load(Ity_I16, binop(Iop_Add32, getIReg(rs), mkU32(u)))));
408 break;
411 case PLSU12_LWC1: { /* lwc1[u12] */
412 DIP("lwc1[u12] r%u %u(r%u)", rt, u, rs);
413 vassert(0);
414 break;
417 case PLSU12_LDC1: { /* ldc1[u12] */
418 DIP("ldc1[u12] r%u %u(r%u)", rt, u, rs);
419 vassert(0);
420 break;
423 case PLSU12_PREF: { /* pref[u12] */
424 DIP("pref[u12] r%u %u(r%u)", rt, u, rs);
425 break;
428 case PLSU12_LWU: { /* lwu[u12] */
429 DIP("lwu[u12] r%u %u(r%u)", rt, u, rs);
430 vassert(0);
431 break;
434 case PLSU12_SWC1: { /* swc1[u12] */
435 DIP("swc1[u12] r%u %u(r%u)", rt, u, rs);
436 vassert(0);
437 break;
440 case PLSU12_SDC1: { /* sdc1[u12] */
441 DIP("sdc1[u12] r%u %u(r%u)", rt, u, rs);
442 vassert(0);
443 break;
446 default:
447 vassert(0);
451 static void nano_pl32a0(DisResult *dres, UInt cins)
453 UChar rd = (cins >> 11) & 0x1F;
454 UChar rs = (cins >> 16) & 0x1F;
455 UChar rt = (cins >> 21) & 0x1F;
456 IRTemp t1 = newTemp(Ity_I32);
457 IRTemp t2 = newTemp(Ity_I64);
459 switch ((cins >> 3) & 0x07F) {
460 case _POOL32A0_PTRAP: {
461 if ((cins >> 10) & 0x01) { /* tne */
462 DIP("tne r%u, r%u", rs, rt);
463 stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
464 getIReg(rt)), Ijk_SigTRAP,
465 IRConst_U32(guest_PC_curr_instr + 4),
466 OFFB_PC));
467 } else { /* teq */
468 UChar trap_code = (cins >> 11) & 0x1F;
469 DIP("teq r%u, r%u %u", rs, rt, trap_code);
470 if (trap_code == 7)
471 stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
472 getIReg(rt)), Ijk_SigFPE_IntDiv,
473 IRConst_U32(guest_PC_curr_instr + 4),
474 OFFB_PC));
475 else if (trap_code == 6)
476 stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
477 getIReg(rt)), Ijk_SigFPE_IntOvf,
478 IRConst_U32(guest_PC_curr_instr + 4),
479 OFFB_PC));
480 else
481 stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
482 getIReg(rt)), Ijk_SigTRAP,
483 IRConst_U32(guest_PC_curr_instr + 4),
484 OFFB_PC));
487 break;
490 case _POOL32A0_SEB: { /* seb */
491 DIP("seb r%u, r%u", rs, rt);
492 putIReg(rt, unop(Iop_8Sto32, unop(Iop_32to8, getIReg(rs))));
493 break;
496 case _POOL32A0_SEH: { /* seh */
497 DIP("seh r%u, r%u", rs, rt);
498 putIReg(rt, unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rs))));
499 break;
502 case _POOL32A0_SLLV: { /* sllv */
503 DIP("sllv r%u, r%u, r%u", rd, rs, rt);
504 assign(t1, binop(Iop_And32, getIReg(rt), mkU32(0x1f)));
505 putIReg(rd, binop(Iop_Shl32, getIReg(rs), unop(Iop_32to8,
506 mkexpr(t1))));
507 break;
510 case _POOL32A0_MUL32: { /* mul */
511 DIP("mul[32] r%u, r%u, r%u", rd, rs, rt);
512 putIReg(rd, unop(Iop_64to32, binop(Iop_MullS32, getIReg(rt),
513 getIReg(rs))));
514 break;
517 case _POOL32A0_MUH: { /* muh */
518 DIP("muh r%u, r%u, r%u", rd, rs, rt);
519 putIReg(rd, unop(Iop_64HIto32, binop(Iop_MullS32, getIReg(rt),
520 getIReg(rs))));
521 break;
524 case _POOL32A0_MULU: { /* mulu */
525 DIP("mulu r%u, r%u, r%u", rd, rs, rt);
526 putIReg(rd, unop(Iop_64to32, binop(Iop_MullU32, getIReg(rt),
527 getIReg(rs))));
528 break;
531 case _POOL32A0_MUHU: { /* muhu */
532 DIP("muhu r%u, r%u, r%u", rd, rs, rt);
533 putIReg(rd, unop(Iop_64HIto32, binop(Iop_MullU32, getIReg(rt),
534 getIReg(rs))));
535 break;
538 case _POOL32A0_DIV: { /* div */
539 DIP("div r%u, r%u, r%u", rd, rs, rt);
540 putIReg(rd, binop(Iop_DivS32, getIReg(rs), getIReg(rt)));
541 break;
544 case _POOL32A0_MOD: { /* mod */
545 DIP("mod r%u, r%u, r%u", rd, rs, rt);
546 putIReg(rd, unop(Iop_64HIto32, binop(Iop_DivModS32to32, getIReg(rs),
547 getIReg(rt))));
548 break;
551 case _POOL32A0_DIVU: { /* divu */
552 DIP("divu r%u, r%u, r%u", rd, rs, rt);
553 putIReg(rd, binop(Iop_DivU32, getIReg(rs), getIReg(rt)));
554 break;
557 case _POOL32A0_MODU: { /* modu */
558 DIP("modu r%u, r%u, r%u", rd, rs, rt);
559 putIReg(rd, unop(Iop_64HIto32, binop(Iop_DivModU32to32, getIReg(rs),
560 getIReg(rt))));
561 break;
564 case _POOL32A0_SRLV: { /* srlv */
565 DIP("srlv r%u, r%u, r%u", rd, rs, rt);
566 assign(t1, binop(Iop_And32, getIReg(rt), mkU32(0x1f)));
567 putIReg(rd, binop(Iop_Shr32,
568 getIReg(rs), unop(Iop_32to8, mkexpr(t1))));
569 break;
572 case _POOL32A0_SRAV: { /* srav */
573 DIP("srav r%u, r%u, r%u", rd, rs, rt);
574 assign(t1, binop(Iop_And32, getIReg(rt), mkU32(0x1f)));
575 putIReg(rd, binop(Iop_Sar32,
576 getIReg(rs), unop(Iop_32to8, mkexpr(t1))));
577 break;
580 case _POOL32A0_ROTRV: { /* rotrv */
581 DIP("rotv r%u, r%u, r%u", rd, rs, rt);
582 assign(t1, binop(Iop_And32, getIReg(rt), mkU32(0x1f)));
583 assign(t2, binop(Iop_32HLto64, getIReg(rs), getIReg(rs)));
584 putIReg(rd, unop(Iop_64to32,
585 binop(Iop_Shr64,
586 mkexpr(t2), unop(Iop_32to8, mkexpr(t1)))));
587 break;
590 case _POOL32A0_AND32: { /* and[32] */
591 DIP("and[32] r%u, r%u, r%u", rd, rs, rt);
592 putIReg(rd, binop(Iop_And32, getIReg(rs), getIReg(rt)));
593 break;
596 case _POOL32A0_ADD: { /* add */
597 DIP("add r%u, r%u, r%u", rd, rs, rt);
598 // if overflows(sum, nbits=32): raise exception('OV')
599 putIReg(rd, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
600 break;
603 case _POOL32A0_ADDU32: { /* addu[32] */
604 DIP("addu[32] r%u, r%u, r%u", rd, rs, rt);
605 putIReg(rd, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
606 break;
609 case _POOL32A0_SUB: { /* sub */
610 DIP("sub r%u, r%u, r%u", rd, rs, rt);
611 // if overflows(result, nbits=32): raise exception('OV')
612 putIReg(rd, binop(Iop_Sub32, getIReg(rs), getIReg(rt)));
613 break;
616 case _POOL32A0_SUBU32: { /* subu[32] */
617 DIP("subu[32] r%u, r%u, r%u", rd, rs, rt);
618 putIReg(rd, binop(Iop_Sub32, getIReg(rs), getIReg(rt)));
619 break;
622 case _POOL32A0_OR32: { /* or[32] */
623 DIP("or[32] r%u, r%u, r%u", rd, rs, rt);
624 putIReg(rd, binop(Iop_Or32, getIReg(rs), getIReg(rt)));
625 break;
628 case _POOL32A0_NOR: { /* nor */
629 DIP("nor r%u, r%u, r%u", rd, rs, rt);
630 putIReg(rd, unop(Iop_Not32, binop(Iop_Or32, getIReg(rs),
631 getIReg(rt))));
632 break;
635 case _POOL32A0_XOR32: { /* xor[32] */
636 DIP("xor[32] r%u, r%u, r%u", rd, rs, rt);
637 putIReg(rd, binop(Iop_Xor32, getIReg(rs), getIReg(rt)));
638 break;
641 case _POOL32A0_SLT: { /* slt */
642 DIP("slt r%u, r%u, r%u", rd, rs, rt);
643 putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
644 getIReg(rt))));
645 break;
648 case _POOL32A0_PSLTU: { /* p.sltu */
649 if (rd == 0) {
650 vassert(0);
651 } else { /* sltu */
652 DIP("sltu r%u, r%u, r%u", rd, rs, rt);
653 putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
654 getIReg(rt))));
657 break;
660 case _POOL32A0_SOV: { /* sov */
661 IRTemp t33 = newTemp(Ity_I32);
662 IRTemp t0 = newTemp(Ity_I32);
663 DIP("sov r%u, r%u, r%u", rd, rs, rt);
664 assign(t1, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
665 assign(t33, binop(Iop_Add32,
666 binop(Iop_Sar32, getIReg(rs), mkU8(1)),
667 binop(Iop_Sar32, getIReg(rt), mkU8(1))));
668 assign(t0, binop(Iop_And32,
669 binop(Iop_And32,
670 getIReg(rs), getIReg(rt)), mkU32(1)));
671 putIReg(rd, unop(Iop_1Uto32,
672 binop(Iop_CmpNE32,
673 binop(Iop_Sar32, mkexpr(t1), mkU8(1)),
674 binop(Iop_Add32, mkexpr(t33), mkexpr(t0)))));
675 // GPR[rd] = 1 if overflows(sum, nbits=32) else 0
676 break;
679 case _POOL32A0_PCMOVE: { /* p.cmove */
680 if (cins & 0x400) { /* movn */
681 DIP("movn r%u, r%u, r%u", rd, rs, rt);
682 putIReg(rd, IRExpr_ITE(binop(Iop_CmpNE32, getIReg(rt), mkU32(0x00)),
683 getIReg(rs), getIReg(rd)));
684 } else { /* movz */
685 DIP("movz r%u, r%u, r%u", rd, rs, rt);
686 putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x00)),
687 getIReg(rs), getIReg(rd)));
690 break;
693 case _POOL32A0_RDHWR: /* RDHWR */
694 DIP("rdhwr r%u, r%u", rt, rs);
696 if (rs == 29) {
697 putIReg(rt, IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR),
698 Ity_I32));
699 break;
700 } else if (rs <= 3) {
701 IRExpr** arg = mkIRExprVec_1(mkU32(rs));
702 IRTemp val = newTemp(Ity_I32);
703 IRDirty *d = unsafeIRDirty_1_N(val,
705 "nanomips_dirtyhelper_rdhwr",
706 &nanomips_dirtyhelper_rdhwr,
707 arg);
708 stmt(IRStmt_Dirty(d));
709 putIReg(rt, mkexpr(val));
710 break;
711 } else {
712 vex_printf("Unsupported RDHWR variant");
713 vassert(0);
716 default:
717 vex_printf("Unrecognized _POOL32A0 instruction %08X",
718 (cins >> 3) & 0x07F);
719 vassert(0);
723 static void nano_pplsx(DisResult *dres, UInt cins)
725 UChar rd = (cins >> 11) & 0x1F;
726 UChar rs = (cins >> 16) & 0x1F;
727 UChar rt = (cins >> 21) & 0x1F;
729 switch ((cins >> 7) & 0x0F) {
730 case LBX: { /* lbx */
731 DIP("lbx r%u, %u(r%u)", rd, rs, rt);
732 putIReg(rd, unop(Iop_8Sto32,
733 load(Ity_I8,
734 binop(Iop_Add32, getIReg(rs), getIReg(rt)))));
735 break;
738 case SBX: { /* sbx */
739 DIP("sbx r%u %u(r%u)", rd, rs, rt);
740 store(binop(Iop_Add32, getIReg(rs), getIReg(rt)),
741 unop(Iop_32to8, getIReg(rd)));
742 break;
745 case LBUX: { /* lbux */
746 DIP("lbux r%u, %u(r%u)", rd, rs, rt);
747 putIReg(rd, unop(Iop_8Uto32,
748 load(Ity_I8,
749 binop(Iop_Add32, getIReg(rs), getIReg(rt)))));
750 break;
753 case LHX: {
754 DIP("lhx r%u, %u(r%u)", rd, rs, rt);
755 putIReg(rd, unop(Iop_16Sto32,
756 load(Ity_I16,
757 binop(Iop_Add32, getIReg(rs), getIReg(rt)))));
758 break;
761 case SHX: {
762 DIP("shx r%u %u(r%u)", rd, rs, rt);
763 store(binop(Iop_Add32, getIReg(rs), getIReg(rt)), unop(Iop_32to16,
764 getIReg(rd)));
765 break;
768 case LHUX: {
769 DIP("lbux r%u, %u(r%u)", rd, rs, rt);
770 putIReg(rd, unop(Iop_16Uto32,
771 load(Ity_I16,
772 binop(Iop_Add32, getIReg(rs), getIReg(rt)))));
773 break;
776 case LWX: {
777 DIP("lwx r%u, %u(r%u)", rd, rs, rt);
778 putIReg(rd, load(Ity_I32, binop(Iop_Add32, getIReg(rs), getIReg(rt))));
779 break;
782 case SWX: {
783 DIP("swx r%u %u(r%u)", rd, rs, rt);
784 store(binop(Iop_Add32, getIReg(rs), getIReg(rt)), getIReg(rd));
785 break;
788 default:
789 vassert(0);
790 break;
794 static void nano_pplsxs(DisResult *dres, UInt cins)
796 UChar rd = (cins >> 11) & 0x1F;
797 UChar rs = (cins >> 16) & 0x1F;
798 UChar rt = (cins >> 21) & 0x1F;
800 switch ((cins >> 7) & 0x0F) {
801 case LHXS: {
802 DIP("lhxs r%u, %u(r%u)", rd, rs, rt);
803 putIReg(rd, unop(Iop_16Sto32,
804 load(Ity_I16,
805 binop(Iop_Add32,
806 binop(Iop_Shl32, getIReg(rs), mkU8(0x01)),
807 getIReg(rt)))));
808 break;
811 case SHXS: {
812 DIP("shxs r%u %u(r%u)", rd, rs, rt);
813 store(binop(Iop_Add32,
814 binop(Iop_Shl32, getIReg(rs), mkU8(0x01)),
815 getIReg(rt)),
816 unop(Iop_32to16, getIReg(rd)));
817 break;
820 case LHUXS: {
821 DIP("lbuxs r%u, %u(r%u)", rd, rs, rt);
822 putIReg(rd, unop(Iop_16Uto32,
823 load(Ity_I16,
824 binop(Iop_Add32,
825 binop(Iop_Shl32, getIReg(rs), mkU8(0x01)),
826 getIReg(rt)))));
827 break;
830 case LWXS32: {
831 DIP("lwxs[32] r%u, r%u(r%u)", rd, rs, rt);
832 putIReg(rd, load(Ity_I32,
833 binop(Iop_Add32,
834 binop(Iop_Shl32, getIReg(rs), mkU8(0x02)),
835 getIReg(rt))));
836 break;
839 case SWXS: {
840 DIP("swxs r%u %u(r%u)", rd, rs, rt);
841 store(binop(Iop_Add32,
842 binop(Iop_Shl32, getIReg(rs), mkU8(0x02)),
843 getIReg(rt)),
844 getIReg(rd));
845 break;
848 default:
849 vassert(0);
850 break;
854 static void nano_plsx(DisResult *dres, UInt cins)
856 if ((cins >> 6) & 0x01) {
857 nano_pplsxs(dres, cins);
858 } else {
859 nano_pplsx(dres, cins);
863 static void nano_pool32Axf_4(DisResult *dres, UInt cins)
865 UChar rs = (cins >> 16) & 0x1F;
866 UChar rt = (cins >> 21) & 0x1F;
867 IRTemp t1;
869 switch ((cins >> 9) & 0x7F) {
870 case nano_POOL32Axf4_CLO: { /* clo */
871 DIP("clo r%u, r%u", rt, rs);
872 t1 = newTemp(Ity_I1);
873 assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0xffffffff)));
874 putIReg(rt, IRExpr_ITE(mkexpr(t1),
875 mkU32(0x00000020),
876 unop(Iop_Clz32,
877 unop(Iop_Not32, getIReg(rs)))));
878 break;
881 case nano_POOL32Axf4_CLZ: { /* clz */
882 DIP("clz r%u, r%u", rt, rs);
883 putIReg(rt, unop(Iop_Clz32, getIReg(rs)));
884 break;
889 static void nano_p32Axf(DisResult *dres, UInt cins)
891 switch ((cins >> 6) & 0x7) {
892 case POOL32aXF_4:
893 nano_pool32Axf_4(dres, cins);
894 break;
896 case POOL32aXF_5:
897 vassert(0);
898 break;
900 default:
901 vex_printf("Unrecognized pool32Axf instruction %08X\n", cins);
902 vassert(0);
903 break;
907 static void nano_pool32a7(DisResult *dres, UInt cins)
909 UChar rd = (cins >> 11) & 0x1F;
910 UChar rs = (cins >> 16) & 0x1F;
911 UChar rt = (cins >> 21) & 0x1F;
912 UChar u2 = (cins >> 9) & 0x03;
913 UChar shift = (cins >> 6) & 0x1F;
915 switch ((cins >> 3) & 7) {
916 case _POOL32A7_PLSX:
917 nano_plsx(dres, cins);
918 break;
920 case _POOL32A7_LSA: { /* lsa */
921 DIP("lsa r%u r%u, r%u", rd, rs, rt);
922 putIReg(rd, binop(Iop_Add32, binop(Iop_Shl32, getIReg(rs), mkU8(u2)),
923 getIReg(rt)));
924 break;
927 case _POOL32A7_EXTW: { /*extw*/
928 DIP("extw r%u r%u, r%u, %u", rd, rs, rt, shift);
929 IRTemp t1 = newTemp(Ity_I64);
930 assign(t1, binop(Iop_32HLto64, getIReg(rt), getIReg(rs)));
931 putIReg(rd, unop(Iop_64to32, binop(Iop_Shr64, mkexpr(t1),
932 mkU8(shift))));
933 break;
936 case _POOL32A7_P32Axf: {
937 nano_p32Axf(dres, cins);
938 break;
941 default:
942 vex_printf("Unrecognized _POOL32A7 instruction %08X", cins);
943 vassert(0);
947 static void nano_p32a(DisResult *dres, UInt cins)
949 switch (cins & 0x7) {
950 case P32A_POOL32A0:
951 nano_pl32a0(dres, cins);
952 break;
954 case P32A_POOL32A7:
955 nano_pool32a7(dres, cins);
956 break;
958 default:
959 vex_printf("Unrecognized P32A instruction %08X", cins);
960 vassert(0);
964 static void nano_pbal(DisResult *dres, UInt cins)
966 Int s = extend_sign((cins & 0x1FFFFFE) | ((cins & 1) << 25), 26);
968 if (cins & 0x2000000) { /* BALC[32] */
969 DIP("balc %0X", guest_PC_curr_instr + 4 + s);
970 putIReg(31, mkU32(guest_PC_curr_instr + 4));
971 dres->jk_StopHere = Ijk_Call;
972 } else { /* BC[32] */
973 DIP("bc %0X", guest_PC_curr_instr + 4 + s);
974 dres->jk_StopHere = Ijk_Boring;
977 putPC(mkU32(guest_PC_curr_instr + 4 + s));
978 dres->whatNext = Dis_StopHere;
981 static void nano_ppsr(DisResult *dres, UInt cins)
983 UInt u = cins & 0xFF8;
984 UChar count = (cins >> 16) & 0x0F;
985 UChar rt = (cins >> 21) & 0x1F;
986 UChar counter = 0;
987 Bool jr = True;
989 switch (cins & 0x03) {
990 case 0x00: { /* save[32] */
991 DIP("save %u, r%u-r%u", u, (rt & 0x1fu) | (rt & 0x10u),
992 ((rt + count - 1) & 0x1fu) | (rt & 0x10u));
994 IRTemp t1 = newTemp(Ity_I32);
995 assign(t1, getIReg(29));
997 putIReg(29, binop(Iop_Sub32, mkexpr(t1), mkU32(u)));
999 while (counter != count) {
1000 Bool use_gp = (cins & 0x04) && (counter + 1 == count);
1001 UChar this_rt = use_gp ? 28 : (UChar)((rt + counter) & 0x1f)
1002 | (rt & 0x10);
1003 Int offset = -((counter + 1) << 2);
1004 store(binop(Iop_Add32, mkexpr(t1), mkU32(offset)),
1005 getIReg(this_rt));
1006 counter++;
1009 break;
1012 case 0x02: /* restore[32] */
1013 jr = False; //falls through common restore(.jrc) implementation
1015 case 0x03: { /* restore.jrc[32] */
1016 DIP("restore%s %u, r%u-r%u", jr ? ".jrc" : "", u,
1017 ((rt + count - 1) & 0x1fu) | (rt & 0x10u),
1018 (rt & 0x1fu) | (rt & 0x10u));
1020 while (counter != count) {
1021 Bool use_gp = (cins & 0x04) && (counter + 1 == count);
1022 UChar this_rt = use_gp ? 28 : ((rt + counter) & 0x1F) | (rt & 0x10);
1023 Int offset = u - ((counter + 1) << 2);
1024 putIReg(this_rt,load(Ity_I32, binop(Iop_Add32,
1025 getIReg(29), mkU32(offset))));
1026 // if this_rt == 29: raise UNPREDICTABLE()
1027 counter++;
1030 putIReg(29, binop(Iop_Add32, getIReg(29), mkU32(u)));
1032 if (jr) {
1033 putPC(getIReg(31));
1034 dres->whatNext = Dis_StopHere;
1035 dres->jk_StopHere = Ijk_Ret;
1038 break;
1041 default:
1042 vassert(0);
1046 static void nano_psrf(UInt cins)
1048 switch (cins & 0x03) {
1049 case 0x00: { /* savef */
1050 vex_printf("Instruction savef is missing documentation.\n");
1051 vassert(0);
1052 break;
1055 case 0x02: { /* restoref */
1056 vex_printf("Instruction restoref is missing documentation.\n");
1057 vassert(0);
1058 break;
1061 default:
1062 vassert(0);
1066 static void nano_psr(DisResult *dres, UInt cins)
1068 switch ((cins >> 20) & 0x1) {
1069 case 0x00: /* pp.sr */
1070 nano_ppsr(dres, cins);
1071 break;
1073 case 0x01: /* p.sr.f */
1074 nano_psrf(cins);
1075 break;
1077 default:
1078 vassert(0);
1079 break;
1083 static void nano_pri(DisResult *dres, UInt cins)
1085 switch ((cins >> 19) & 3) {
1086 case PRI_SIGRIE:
1087 ILLEGAL_INSTRUCTON
1088 break;
1090 case PRI_PSYSCALL:
1091 if (cins & 0x40000) { /* HYPCALL */
1092 vex_printf("Instruction HYPCALL is missing documentation.\n");
1093 vassert(0);
1094 } else { /* SYSCALL[32] */
1095 DIP("syscall %u", cins & 0x3FFFF);
1096 dres->jk_StopHere = Ijk_Sys_syscall;
1097 dres->whatNext = Dis_StopHere;
1100 break;
1102 case PRI_BREAK: /* BREAK[32] */
1103 DIP("break %u", cins & 0x7FFFF);
1104 dres->jk_StopHere = Ijk_SigTRAP;
1105 dres->whatNext = Dis_StopHere;
1106 break;
1108 case PRI_SDBBP:
1109 vex_printf("Instruction SDBBP is not supported.\n");
1110 vassert(0);
1111 break;
1113 default:
1114 vassert(0);
1118 static void nano_psll(UInt cins)
1120 UChar rt = (cins >> 21) & 0x1F;
1121 UChar rs = (cins >> 16) & 0x1F;
1122 UChar shift = cins & 0x1F;
1124 if (rt == 0 && shift == 0) { /* nop[32] */
1125 DIP("nop[32]");
1126 return;
1129 if (rt == 0 && shift == 3) { /* ehb */
1130 DIP("ehb");
1131 vassert(0);
1132 return;
1135 if (rt == 0 && shift == 5) { /* pause */
1136 DIP("pause");
1137 vassert(0);
1138 // pause_until_llbit_clears();
1139 return;
1142 if (rt == 0 && shift == 6) { /* sync */
1143 DIP("sync 0x%x", rs);
1144 /* Just ignore it. */
1145 return;
1148 DIP("sll r%u, r%u, %u", rt, rs, shift);
1149 putIReg(rt, binop(Iop_Shl32, getIReg(rs), mkU8(shift)));
1150 return;
1153 static void nano_pshift(UInt cins)
1155 UChar rt = (cins >> 21) & 0x1F;
1156 UChar rs = (cins >> 16) & 0x1F;
1157 UChar shift = cins & 0x1F;
1159 switch ((cins >> 5) & 0xF) {
1160 case PSLL: { /* p.sll */
1161 nano_psll(cins);
1162 break;
1165 case SRL32: /* srl[32] */
1166 DIP("srl[32] r%u, r%u, %u", rt, rs, shift);
1167 putIReg(rt, binop(Iop_Shr32, getIReg(rs), mkU8(shift)));
1168 break;
1170 case SRA: /* sra */
1171 DIP("sra r%u, r%u, %u", rt, rs, shift);
1172 putIReg(rt, binop(Iop_Sar32, getIReg(rs), mkU8(shift)));
1173 break;
1175 case ROTR: /* rotr */
1176 DIP("rotr r%u, r%u, %u", rt, rs, shift);
1177 IRTemp t1 = newTemp(Ity_I64);
1178 assign(t1, binop(Iop_32HLto64, getIReg(rs), getIReg(rs)));
1179 putIReg(rt, unop(Iop_64to32, binop(Iop_Shr64, mkexpr(t1),
1180 mkU8(shift))));
1181 break;
1183 case DSLL: { /* dsll */
1184 DIP("dsll r%u, r%u, %u", rt, rs, shift);
1185 vassert(0);
1186 break;
1189 case DSLL32: { /* dsll32 */
1190 DIP("dsll32 r%u, r%u, %u", rt, rs, shift);
1191 vassert(0);
1192 break;
1195 case DSRL: { /* dsrl */
1196 DIP("dsrl r%u, r%u, %u", rt, rs, shift);
1197 vassert(0);
1198 break;
1201 case DSRL32: { /* dsrl32 */
1202 DIP("dsrl32 r%u, r%u, %u", rt, rs, shift);
1203 vassert(0);
1204 break;
1207 case DSRA: { /* dsra */
1208 DIP("dsra r%u, r%u, %u", rt, rs, shift);
1209 vassert(0);
1210 break;
1213 case DSRA32: { /* dsra32 */
1214 DIP("dsra32 r%u, r%u, %u", rt, rs, shift);
1215 vassert(0);
1216 break;
1219 case DROTR: { /* drotr */
1220 DIP("drotr r%u, r%u, %u", rt, rs, shift);
1221 vassert(0);
1222 break;
1225 case DROTR32: { /* drotr32 */
1226 DIP("drotr32 r%u, r%u, %u", rt, rs, shift);
1227 vassert(0);
1228 break;
1231 default:
1232 vassert(0);
1236 static void nano_protx(UInt cins)
1238 UChar rt = (cins >> 21) & 0x1F;
1239 UChar rs = (cins >> 16) & 0x1F;
1240 UChar shift = cins & 0x1F;
1241 UChar shiftx = ((cins >> 7) & 0xF) << 1;
1242 UChar stripe = (cins & 0x40) ? 1 : 0;
1244 switch ((cins >> 5) & 0x41) {
1245 case 0x00: { /* rotx */
1246 DIP("rotx r%u, r%u, %u, %u, %u", rt, rs, shift, shiftx, stripe);
1247 putIReg(rt, qop(Iop_Rotx32, getIReg(rs), mkU8(shift),
1248 mkU8(shiftx), mkU8(stripe)));
1249 break;
1252 default:
1253 vassert(0);
1254 break;
1259 static void nano_pins(UInt cins)
1261 UChar rt = (cins >> 21) & 0x1F;
1262 UChar rs = (cins >> 16) & 0x1F;
1263 UChar lsb = cins & 0x1F;
1264 UChar msbd = (cins >> 6) & 0x1F;
1266 switch ((cins >> 5) & 0x41) {
1267 case 0x00: { /* ins */
1268 UChar size = 1 + msbd - lsb;
1269 DIP("ins r%u, r%u, %u, %u", rt, rs, lsb, size);
1270 UInt mask = ((1 << size) - 1) << lsb;
1271 putIReg(rt, binop(Iop_Or32, binop(Iop_And32, getIReg(rt),
1272 mkU32(~mask)),
1273 binop(Iop_And32,
1274 binop(Iop_Shl32,
1275 getIReg(rs), mkU8(lsb)),
1276 mkU32(mask))));
1277 break;
1280 case 0x01: { /* dins */
1281 vassert(0);
1282 break;
1285 case 0x40: { /* dinsm */
1286 vassert(0);
1287 break;
1290 case 0x41: { /* dins */
1291 vassert(0);
1292 break;
1295 default:
1296 vassert(0);
1300 static void nano_pext(UInt cins)
1302 UChar rt = (cins >> 21) & 0x1F;
1303 UChar rs = (cins >> 16) & 0x1F;
1304 UChar lsb = cins & 0x1F;
1305 UChar msbd = (cins >> 6) & 0x1F;
1307 switch ((cins >> 5) & 0x41) {
1308 case 0x00: { /* ext */
1309 DIP("ext r%u, r%u, %u, %u", rt, rs, lsb, msbd + 1u);
1311 if (msbd + 1 + lsb > 32) vassert(0);
1313 putIReg(rt, binop(Iop_And32, binop(Iop_Shr32, getIReg(rs), mkU8(lsb)),
1314 mkU32((1 << (msbd + 1)) - 1)));
1315 break;
1318 case 0x01: { /* dextu */
1319 vassert(0);
1320 break;
1323 case 0x40: { /* dextm */
1324 vassert(0);
1325 break;
1328 case 0x41: { /* dext */
1329 vassert(0);
1330 break;
1333 default:
1334 vassert(0);
1338 static void nano_pool16c00(UInt cins)
1340 UChar rs = GPR3_list[(cins >> 4) & 0x07];
1341 UChar rt = GPR3_list[(cins >> 7) & 0x07];
1343 switch (cins & 0x0C) {
1344 case POOL16C00_NOT: { /* not[16] */
1345 DIP("not[16] r%u, r%u", rt, rs);
1346 putIReg(rt, unop(Iop_Not32, getIReg(rs)));
1347 break;
1350 case POOL16C00_XOR: { /* xor[16] */
1351 DIP("xor[16] r%u, r%u", rt, rs);
1352 putIReg(rt, binop(Iop_Xor32, getIReg(rs), getIReg(rt)));
1353 break;
1356 case POOL16C00_AND: { /* and[16] */
1357 DIP("and[16] r%u, r%u", rt, rs);
1358 putIReg(rt, binop(Iop_And32, getIReg(rs), getIReg(rt)));
1359 break;
1362 case POOL16C00_OR: { /* or[16] */
1363 DIP("or[16] r%u, r%u", rt, rs);
1364 putIReg(rt, binop(Iop_Or32, getIReg(rs), getIReg(rt)));
1365 break;
1370 static void nano_pu12(DisResult *dres, UInt cins)
1372 UChar rs = (cins >> 16) & 0x1F;
1373 UChar rt = (cins >> 21) & 0x1F;
1374 UShort u = cins & 0x0FFF;
1376 switch ((cins >> 12) & 0x0F) {
1377 case PU12_ORI: { /* ori */
1378 DIP("ori r%u, r%u, %u", rt, rs, u);
1379 putIReg(rt, binop(Iop_Or32, getIReg(rs), mkU32(u)));
1380 break;
1383 case PU12_XORI: { /* xori */
1384 DIP("xori r%u, r%u, %u", rt, rs, u);
1385 putIReg(rt, binop(Iop_Xor32, getIReg(rs), mkU32(u)));
1386 break;
1389 case PU12_ANDI: { /* andi */
1390 DIP("andi r%u, r%u, %u", rt, rs, u);
1391 putIReg(rt, binop(Iop_And32, getIReg(rs), mkU32(u)));
1392 break;
1395 case PU12_PSR: /* p.sr */
1396 nano_psr(dres, cins);
1397 break;
1399 case PU12_SLTI: { /* slti */
1400 DIP("slti r%u, r%u, %u", rt, rs, u);
1401 putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
1402 mkU32(u))));
1403 break;
1406 case PU12_SLTIU: { /* sltiu */
1407 DIP("sltiu r%u, r%u, %u", rt, rs, u);
1408 putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
1409 mkU32(u))));
1410 break;
1413 case PU12_SEQI: { /* seqi */
1414 DIP("seqi r%u, r%u, %u", rt, rs, u);
1415 putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpEQ32, getIReg(rs),
1416 mkU32(u))));
1417 break;
1420 case PU12_ADDIU_NEG: { /* addiu[neg] */
1421 DIP("addiu[neg] r%u, r%u, %u", rt, rs, u);
1422 putIReg(rt, binop(Iop_Sub32, getIReg(rs), mkU32(u)));
1423 break;
1426 case PU12_PSHIFT: /* p.shift */
1427 nano_pshift(cins);
1428 break;
1430 case PU12_PROTX: /* p.rotx */
1431 nano_protx(cins);
1432 break;
1434 case PU12_PINS: /* p.ins */
1435 nano_pins(cins);
1436 break;
1438 case PU12_PEXT: /* p.ext */
1439 nano_pext(cins);
1440 break;
1442 default:
1443 vassert(0);
1447 static void nano_pbr1(DisResult *dres, UInt cins)
1449 UChar rs = (cins >> 16) & 0x1F;
1450 UChar rt = (cins >> 21) & 0x1F;
1451 Short s = (Short)((cins & 0x3FFE) |
1452 ((cins & 1) << 14) | ((cins & 1) << 15));
1454 switch ((cins >> 14) & 0x3) {
1455 case PBR1_BEQC32: { /* BEQC[32] */
1456 DIP("beqc[32] r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 4 + (Int)s);
1457 ir_for_branch(dres, binop(Iop_CmpEQ32, getIReg(rt), getIReg(rs)),
1458 4, (Int)s);
1459 break;
1462 case PBR1_PBR3A: { /* P.BR3A */
1463 vassert(0);
1464 break;
1467 case PBR1_BGEC: { /* BGEC */
1468 DIP("bgec r%u, r%u, %X", rs, rt, guest_PC_curr_instr + 4 + (Int)s);
1469 ir_for_branch(dres, binop(Iop_CmpLE32S, getIReg(rt), getIReg(rs)),
1470 4, (Int)s);
1471 break;
1474 case PBR1_BGEUC: { /* bgeuc */
1475 DIP("bgeuc r%u, r%u, %X", rs, rt, guest_PC_curr_instr + 4 + (Int)s);
1476 ir_for_branch(dres, binop(Iop_CmpLE32U, getIReg(rt), getIReg(rs)),
1477 4, (Int)s);
1478 break;
1481 default:
1482 vex_printf("Unsupported p.br1 instruction %08X", cins);
1483 vassert(0);
1487 static void nano_pbr2(DisResult *dres, UInt cins)
1489 UChar rs = (cins >> 16) & 0x1F;
1490 UChar rt = (cins >> 21) & 0x1F;
1491 Short s = (Short)((cins & 0x3FFE) |
1492 ((cins & 1) << 14) | ((cins & 1) << 15));
1494 switch ((cins >> 14) & 0x3) {
1495 case PBR2_BNEC32: { /* BNEC[32] */
1496 DIP("bnec r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 4 + (Int)s);
1497 ir_for_branch(dres, binop(Iop_CmpNE32, getIReg(rt), getIReg(rs)),
1498 4, (Int)s);
1499 break;
1502 case PBR2_BLTC: { /* BLTC */
1503 DIP("bltc r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 4 + (Int)s);
1504 ir_for_branch(dres, binop(Iop_CmpLT32S, getIReg(rs), getIReg(rt)),
1505 4, (Int)s);
1506 break;
1509 case PBR2_BLTUC: { /* BLTUC */
1510 DIP("bltuc r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 4 + (Int)s);
1511 ir_for_branch(dres, binop(Iop_CmpLT32U, getIReg(rs), getIReg(rt)),
1512 4, (Int)s);
1513 break;
1516 default:
1517 vex_printf("Unsupported p.br2 instruction %08X", cins);
1518 vassert(0);
1522 static void nano_pbri(DisResult *dres, UInt cins)
1524 UChar rt = (cins >> 21) & 0x1F;
1525 Int s = extend_sign((cins & 0x7FE) | ((cins & 0x01) << 11), 12);
1526 UChar bit = (cins >> 11) & 0x3F;
1527 UInt u = (cins >> 11) & 0x7F;
1529 switch ((cins >> 18) & 0x07) {
1530 case PBRI_BEQIC: {
1531 DIP("beqic r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1532 ir_for_branch(dres, binop(Iop_CmpEQ32, getIReg(rt), mkU32(u)),
1533 4, (Int)s);
1534 break;
1537 case PBRI_BBEQZC: {
1538 DIP("bbeqzc r%u, %u, %0X", rt, bit, guest_PC_curr_instr + 4 + s);
1540 if (bit >= 32) {
1541 ILLEGAL_INSTRUCTON
1542 return;
1545 ir_for_branch(dres,
1546 binop(Iop_CmpEQ32,
1547 binop(Iop_And32,
1548 binop(Iop_Shr32, getIReg(rt), mkU8(bit)),
1549 mkU32(1)),
1550 mkU32(0)), 4, s);
1551 break;
1554 case PBRI_BGEIC: { /* bgeic */
1555 DIP("bgeic r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1556 ir_for_branch(dres, binop(Iop_CmpLE32S, mkU32(u), getIReg(rt)),
1557 4, (Int)s);
1558 break;
1561 case PBRI_BGEIUC: { /* bgeiuc */
1562 DIP("bgeiuc r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1563 ir_for_branch(dres, binop(Iop_CmpLE32U, mkU32(u), getIReg(rt)),
1564 4, (Int)s);
1565 break;
1568 case PBRI_BNEIC: {
1569 DIP("bneic r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1570 ir_for_branch(dres,
1571 binop(Iop_CmpNE32, getIReg(rt), mkU32(u)), 4, s);
1572 break;
1575 case PBRI_BBNEZC: {
1576 DIP("bbnezc r%u, %u, %0X", rt, bit, guest_PC_curr_instr + 4 + s);
1578 if (bit >= 32) {
1579 ILLEGAL_INSTRUCTON
1580 return;
1583 ir_for_branch(dres,
1584 binop(Iop_CmpNE32,
1585 binop(Iop_And32,
1586 binop(Iop_Shr32, getIReg(rt), mkU8(bit)),
1587 mkU32(1)),
1588 mkU32(0)), 4, s);
1589 break;
1592 case PBRI_BLTIC: {
1593 DIP("bltic r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1594 ir_for_branch(dres, binop(Iop_CmpLT32S, getIReg(rt), mkU32(u)),
1595 4, (Int)s);
1596 break;
1599 case PBRI_BLTIUC: {
1600 DIP("bltiuc r%u, %u, %0X", rt, u, guest_PC_curr_instr + 4 + s);
1601 ir_for_branch(dres, binop(Iop_CmpLT32U, getIReg(rt), mkU32(u)),
1602 4, (Int)s);
1603 break;
1606 default:
1607 vex_printf("Unsupported p.bri instruction %08X", cins);
1608 vassert(0);
1612 static void nano_pprefs9(DisResult *dres, UInt cins)
1614 UChar hint = (cins >> 21) & 0x1F;
1615 UChar rs = (cins >> 16) & 0x1F;
1616 UChar s = extend_sign((cins & 0xFF) | ((cins >> 7) & 0x100), 9);
1618 if (hint == 31) { /* synci */
1619 DIP("synci %u(r%u)", s, rs);
1620 vassert(0);
1621 } else { /* pref[s9] */
1622 DIP("pref[s9] %u, %u(r%u)", hint, s, rs);
1623 vassert(0);
1627 static void nano_plss0(DisResult *dres, UInt cins)
1629 UChar rs = (cins >> 16) & 0x1F;
1630 UChar rt = (cins >> 21) & 0x1F;
1631 Int s = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFF), 9);
1633 switch ((cins >> 11) & 0xf) {
1634 case LBS9: { /* lb[s9] */
1635 DIP("lb[s9] r%u %d(r%u)", rt, s, rs);
1636 putIReg(rt, unop(Iop_8Sto32,
1637 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
1638 mkU32(s)))));
1639 break;
1642 case LHS9: { /* lh[s9] */
1643 DIP("lh[s9] r%u %d(r%u)", rt, s, rs);
1644 putIReg(rt, unop(Iop_16Sto32,
1645 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
1646 mkU32(s)))));
1647 break;
1650 case LWS9: { /* lw[s9] */
1651 DIP("lw[s9] r%u %d(r%u)", rt, s, rs);
1652 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(s))));
1653 break;
1656 case LDS9: { /* ld[s9] */
1657 DIP("ld[s9] r%u %d(r%u)", rt, s, rs);
1658 vassert(0);
1659 break;
1662 case SBS9: { /* sb[s9] */
1663 DIP("sb[s9] r%u %d(r%u)", rt, s, rs);
1664 store(binop(Iop_Add32, getIReg(rs), mkU32(s)), unop(Iop_32to8,
1665 getIReg(rt)));
1666 break;
1669 case SHS9: { /* sh[s9] */
1670 DIP("sh[s9] r%u %d(r%u)", rt, s, rs);
1671 store(binop(Iop_Add32, getIReg(rs), mkU32(s)), unop(Iop_32to16,
1672 getIReg(rt)));
1673 break;
1676 case SWS9: { /* sw[s9] */
1677 DIP("sw[s9] r%u %d(r%u)", rt, s, rs);
1678 store(binop(Iop_Add32, getIReg(rs), mkU32(s)), getIReg(rt));
1679 break;
1682 case SDS9: { /* sd[s9] */
1683 DIP("sd[s9] r%u %d(r%u)", rt, s, rs);
1684 vassert(0);
1685 break;
1688 case LBUS9: { /* lbu[s9] */
1689 DIP("lbu[s9] r%u %d(r%u)", rt, s, rs);
1690 putIReg(rt, unop(Iop_8Uto32,
1691 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
1692 mkU32(s)))));
1693 break;
1696 case LHUS9: { /* lhu[s9] */
1697 DIP("lhu[s9] r%u %d(r%u)", rt, s, rs);
1698 putIReg(rt, unop(Iop_16Uto32,
1699 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
1700 mkU32(s)))));
1701 break;
1704 case LWC1S9: { /* lwc1[s9] */
1705 DIP("lwc1[s9] r%u %d(r%u)", rt, s, rs);
1706 vassert(0);
1707 break;
1710 case LDC1S9: { /* ldc1[s9] */
1711 DIP("ldc1[s9] r%u %d(r%u)", rt, s, rs);
1712 vassert(0);
1713 break;
1716 case PPREFS9: { /* p.pref[s9] pool */
1717 nano_pprefs9(dres, cins);
1718 break;
1721 case LWUS9: { /* lwu[s9] */
1722 DIP("lwu[s9] r%u %d(r%u)", rt, s, rs);
1723 vassert(0);
1724 break;
1727 case SWC1S9: { /* swc1[s9] */
1728 DIP("swc1[s9] r%u %d(r%u)", rt, s, rs);
1729 vassert(0);
1730 break;
1733 case SDC1S9: { /* sdc1[s9] */
1734 DIP("sdc1[s9] r%u %d(r%u)", rt, s, rs);
1735 vassert(0);
1736 break;
1741 static void nano_pll(DisResult *dres, UInt cins)
1743 IRTemp t1, t2;
1744 UChar rs = (cins >> 16) & 0x1F;
1745 UChar rt = (cins >> 21) & 0x1F;
1746 UInt s = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFC), 9);
1748 switch (cins & 0x03) {
1749 case LL: {
1750 DIP("ll r%u %u(r%u)", rt, s, rs);
1751 t1 = newTemp(Ity_I32);
1752 t2 = newTemp(Ity_I32);
1753 assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(s)));
1754 assign(t2, load(Ity_I32, mkexpr(t1)));
1755 putLLaddr(mkexpr(t1));
1756 putLLdata(mkexpr(t2));
1757 putIReg(rt, mkexpr(t2));
1758 break;
1761 case LLWP: {
1762 UChar ru = (cins >> 3) & 0x1F;
1763 DIP("llwp r%u %u(r%u)", rt, s, rs);
1764 if (rt == ru) vassert(0);
1765 t1 = newTemp(Ity_I32);
1766 t2 = newTemp(Ity_I64);
1767 assign(t1, getIReg(rs));
1768 assign(t2, load(Ity_I64, mkexpr(t1)));
1769 putLLaddr(mkexpr(t1));
1770 putLLdata64(mkexpr(t2));
1771 putIReg(rt, unop(Iop_64to32, mkexpr(t2)));
1772 putIReg(ru, unop(Iop_64HIto32, mkexpr(t2)));
1773 break;
1776 default:
1777 vassert(0);
1781 static void nano_psc(DisResult *dres, UInt cins)
1783 IRTemp t1, t2, t3, t4, t5;
1784 UChar rs = (cins >> 16) & 0x1F;
1785 UChar rt = (cins >> 21) & 0x1F;
1786 UInt s = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFC), 9);
1788 switch (cins & 0x03) {
1789 case SC: {
1790 DIP("sc r%u %u(r%u)", rt, s, rs);
1792 t1 = newTemp(Ity_I32);
1793 t2 = newTemp(Ity_I1);
1794 t3 = newTemp(Ity_I32);
1796 assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(s)));
1798 assign(t2, binop(Iop_CmpNE32,
1799 mkexpr(t1), getLLaddr()));
1800 assign(t3, getIReg(rt));
1801 putLLaddr(LLADDR_INVALID);
1802 putIReg(rt, getIReg(0));
1804 stmt(IRStmt_Exit(mkexpr(t2), Ijk_Boring,
1805 IRConst_U32(guest_PC_curr_instr + 4),
1806 OFFB_PC));
1808 t4 = newTemp(Ity_I32);
1809 t5 = newTemp(Ity_I32);
1811 assign(t5, getLLdata());
1813 stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */
1814 MIPS_IEND, mkexpr(t1), /* addr */
1815 NULL, mkexpr(t5), /* expected value */
1816 NULL, mkexpr(t3) /* new value */)));
1818 putIReg(rt, unop(Iop_1Uto32,
1819 binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5))));
1820 break;
1823 case SCWP: {
1824 UChar ru = (cins >> 3) & 0x1F;
1825 DIP("scwp r%u %u(r%u)", rt, s, rs);
1826 t1 = newTemp(Ity_I32);
1827 t2 = newTemp(Ity_I1);
1829 IRTemp oldHi, oldLo, expHi, expLo;
1830 oldHi = newTemp(Ity_I32);
1831 oldLo = newTemp(Ity_I32);
1832 expHi = newTemp(Ity_I32);
1833 expLo = newTemp(Ity_I32);
1835 assign(t2, binop(Iop_CmpNE32,
1836 getIReg(rs), getLLaddr()));
1838 putLLaddr(LLADDR_INVALID);
1839 putIReg(rt, getIReg(0));
1841 stmt(IRStmt_Exit(mkexpr(t2), Ijk_Boring,
1842 IRConst_U32(guest_PC_curr_instr + 4),
1843 OFFB_PC));
1845 assign(expHi, unop(Iop_64HIto32, getLLdata64()));
1846 assign(expLo, unop(Iop_64to32, getLLdata64()));
1849 stmt(IRStmt_CAS(mkIRCAS(oldHi, oldLo, /* old_mem */
1850 MIPS_IEND, getIReg(rs), /* addr */
1851 mkexpr(expHi), mkexpr(expLo), /* expected value */
1852 getIReg(ru), getIReg(rt) /* new value */)));
1854 putIReg(rt, binop(Iop_And32,
1855 unop(Iop_1Uto32,
1856 binop(Iop_CmpEQ32, mkexpr(oldHi), mkexpr(expHi))),
1857 unop(Iop_1Uto32,
1858 binop(Iop_CmpEQ32, mkexpr(oldLo), mkexpr(expLo)))));
1859 break;
1862 default:
1863 vassert(0);
1867 static void nano_plss1(DisResult *dres, UInt cins)
1869 UChar rs = (cins >> 16) & 0x1F;
1870 UChar rt = (cins >> 21) & 0x1F;
1871 UInt s = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFF), 9);
1873 switch ((cins >> 11) & 0x0F) {
1874 case ASET_ACLER: {
1875 vassert(0);
1876 break;
1879 case UALH: { /* ualh */
1880 DIP("ualh r%u %u(r%u)", rt, s, rs);
1881 putIReg(rt, unop(Iop_16Sto32,
1882 load(Ity_I16, binop(Iop_Add32, getIReg(rs), mkU32(s)))));
1883 break;
1886 case UASH: { /* uash */
1887 DIP("uash r%u %u(r%u)", rt, s, rs);
1888 store(binop(Iop_Add32, getIReg(rs), mkU32(s)), unop(Iop_32to16, getIReg(rt)));
1889 break;
1892 case CACHE: { /* cache */
1893 vassert(0);
1894 break;
1897 case LWC2: {
1898 vassert(0);
1899 break;
1902 case SWC2: {
1903 vassert(0);
1904 break;
1907 case LDC2: {
1908 vassert(0);
1909 break;
1912 case SDC2: {
1913 vassert(0);
1914 break;
1917 case PLL: {
1918 nano_pll(dres, cins);
1919 break;
1922 case PSC: {
1923 nano_psc(dres, cins);
1924 break;
1927 case PLLD: {
1928 vassert(0);
1929 break;
1932 case PSCD: {
1933 vassert(0);
1934 break;
1937 default:
1938 vex_printf("Unrecognized P.LS.S1 instruction %08X", cins);
1939 vassert(0);
1943 static void nano_plswm(DisResult *dres, UInt cins)
1945 UChar rs = (cins >> 16) & 0x1F;
1946 UChar rt = (cins >> 21) & 0x1F;
1947 Int offset = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFF), 9);
1948 UChar count3 = (cins >> 12) & 0x07;
1949 UChar count = count3 ? count3 : 8;
1950 UChar counter = 0;
1951 UChar rt_tmp;
1952 Int offset_tmp;
1954 if ((cins >> 11) & 0x01) { /* swm */
1955 DIP("swm r%u, %d(r%u), %u", rt, offset, rs, count);
1957 while (counter != count) {
1958 rt_tmp = rt ? (rt & 0x10) | ((rt + counter) & 0x1F) : 0;
1959 offset_tmp = offset + (counter << 2);
1960 store(binop(Iop_Add32, getIReg(rs), mkU32(offset_tmp)),
1961 getIReg(rt_tmp));
1962 counter++;
1964 } else { /* lwm */
1965 DIP("lwm r%u, %d(r%u), %u", rt, offset, rs, count);
1967 while (counter != count) {
1968 rt_tmp = (rt & 0x10) | ((rt + counter) & 0x1F);
1969 offset_tmp = offset + (counter << 2);
1970 putIReg(rt_tmp, load(Ity_I32, binop(Iop_Add32, getIReg(rs),
1971 mkU32(offset_tmp))));
1973 if ((rt_tmp == rs) && (counter != count - 1)) {
1974 // raise UNPREDICTABLE()
1977 counter++;
1983 static void nano_plsuawm(DisResult *dres, UInt cins)
1985 UChar rs = (cins >> 16) & 0x1F;
1986 UChar rt = (cins >> 21) & 0x1F;
1987 UInt s = extend_sign(((cins >> 7) & 0x100) | (cins & 0xFF), 9);
1988 UChar count3 = (cins >> 12) & 0x07;
1989 UChar count = count3 ? count3 : 8;
1990 UChar counter = 0;
1991 UInt offset = s;
1992 UChar rt_tmp, offset_tmp;
1994 if ((cins >> 11) & 0x01) { /* uaswm */
1996 DIP("uaswm r%u, %d(r%u), %u", rt, (int)offset, rs, count);
1998 while (counter != count) {
1999 rt_tmp = rt ? (rt & 0x10) | ((rt + counter) & 0x1F) : 0;
2000 offset_tmp = offset + (counter << 2);
2001 store(binop(Iop_Add32, getIReg(rs), mkU32(offset_tmp)),
2002 getIReg(rt_tmp));
2003 counter+=1;
2006 } else { /* ualwm */
2008 DIP("ualwm r%u, %d(r%u), %u", rt, (int)offset, rs, count);
2010 while (counter != count) {
2011 rt_tmp = (rt & 0x10) | ((rt + counter) & 0x1F);
2012 offset_tmp = offset + (counter << 2);
2013 putIReg(rt_tmp, load(Ity_I32, binop(Iop_Add32, getIReg(rs),
2014 mkU32(offset_tmp))));
2016 if ((rt_tmp == rs) && (counter != count - 1)) {
2017 vassert(0);
2018 // raise UNPREDICTABLE()
2020 counter+=1;
2026 static void nano_plss9(DisResult *dres, UInt cins)
2028 switch ((cins >> 8) & 0x7) {
2029 case PLSS0: { /* p.ls.s0 */
2030 nano_plss0(dres, cins);
2031 break;
2034 case PLSS1: {
2035 nano_plss1(dres, cins);
2036 break;
2039 case PLSE0: {
2040 vassert(0);
2041 break;
2044 case PLSWM: {
2045 nano_plswm(dres, cins);
2046 break;
2049 case PLSUAWM: {
2050 nano_plsuawm(dres, cins);
2051 break;
2054 case PLSDM: {
2055 vassert(0);
2056 break;
2059 case PLSUADM: {
2060 vassert(0);
2061 break;
2066 static void nano_p16a1(DisResult *dres, UShort cins)
2068 if (cins & 0x40) { /* ADDIU[R1.SP] */
2069 UChar rs = 29;
2070 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2071 UChar u = (cins & 0x3F) << 2;
2072 DIP("ADDIU[R1.SP] r%u, %u", rt, u);
2073 putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(u)));
2074 } else {
2075 vassert(0);
2079 static void nano_p16a2(DisResult *dres, UShort cins)
2081 if (cins & 0x08) { /* P.ADDIU[RS5] */
2082 UChar rt = (cins >> 5) & 0x1F;
2084 if (rt != 0) { /* ADDIU[RS5] */
2085 Int s = extend_sign((cins & 0x07) | ((cins >> 1) & 0x08), 4);
2086 DIP("addiu r%u, r%u, %d", rt, rt, s);
2087 putIReg(rt, binop(Iop_Add32, getIReg(rt), mkU32(s)));
2088 } else {
2089 DIP("nop");
2091 } else { /* ADDIU[R2] */
2092 UChar rs = GPR3_list[(cins >> 4) & 0x07];
2093 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2094 UChar u = (cins & 0x07) << 2;
2095 DIP("addiu r%u, r%u, 0x%X", rt, rs, u);
2096 putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(u)));
2100 static void nano_p16ri(DisResult *dres, UShort cins)
2102 switch ((cins >> 3) & 0x03) {
2103 case RI_PSYSCALL: {
2104 if (cins & 0x4) { /* HYPCALL[16] */
2105 vex_printf("Instruction HYPCALL is missing documentation.\n");
2106 vassert(0);
2107 } else { /* SYSCALL[16] */
2108 DIP("syscall %u", cins & 0x3u);
2109 dres->jk_StopHere = Ijk_Sys_syscall;
2110 dres->whatNext = Dis_StopHere;
2113 break;
2116 case RI_BREAK: { /* BREAK[16] */
2117 DIP("break %u", cins & 0x7u);
2118 dres->jk_StopHere = Ijk_SigTRAP;
2119 dres->whatNext = Dis_StopHere;
2120 break;
2123 case RI_SDBBP: {
2124 vex_printf("Instruction SDBBP is not supported.\n");
2125 vassert(0);
2130 static void nano_p16mv(DisResult *dres, UShort cins)
2132 UChar rs = cins & 0x1F;
2133 UChar rt = (cins >> 5) & 0x1f;
2135 if (rt != 0) {
2136 DIP("move r%u, r%u", rt, rs);
2137 putIReg(rt, getIReg(rs));
2138 } else {
2139 nano_p16ri(dres, cins);
2143 static void nano_p16shift(DisResult *dres, UShort cins)
2145 UChar rs = GPR3_list[(cins >> 4) & 0x07];
2146 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2147 UChar shift = cins & 0x07;
2149 if (cins & 0x08) { /* slr[16] */
2150 DIP("slr r%u, r%u, %u ", rt, rs, shift);
2151 putIReg(rt, binop(Iop_Shr32, getIReg(rs), mkU8(shift != 0 ? shift : 8)));
2152 } else { /* sll[16] */
2153 DIP("sll r%u, r%u, %u ", rt, rs, shift);
2154 putIReg(rt, binop(Iop_Shl32, getIReg(rs), mkU8(shift != 0 ? shift : 8)));
2158 static void nano_p16c(DisResult *dres, UShort cins)
2160 switch (cins & 0x03) {
2161 case 0x00: { /* POOL16C_0 */
2162 nano_pool16c00(cins);
2163 break;
2166 case 0x01:
2167 case 0x03: { /* LWXS[16] */
2168 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2169 UChar rs = GPR3_list[(cins >> 4) & 0x07];
2170 UChar rd = GPR3_list[(cins >> 1) & 0x07];
2171 DIP("lwxs[32] r%u, %u(r%u)", rd, rs, rt);
2172 putIReg(rd, load(Ity_I32,
2173 binop(Iop_Add32, binop(Iop_Shl32, getIReg(rs),
2174 mkU8(0x02)),
2175 getIReg(rt))));
2176 break;
2179 default:
2180 vassert(0);
2184 static void nano_p16br(DisResult *dres, UShort cins)
2186 UChar u = (cins & 0x0f) << 1;
2188 if (0 == u) {
2189 UChar rt = (cins >> 5) & 0x1F;
2191 if (cins & 0x10) { /* JALRC[16] */
2192 DIP("jalrc r%u", rt);
2193 putIReg(31, mkU32(guest_PC_curr_instr + 2));
2194 dres->jk_StopHere = Ijk_Call;
2195 } else { /* JRC */
2196 DIP("jrc r%u", rt);
2197 dres->jk_StopHere = rt != 31 ? Ijk_Boring : Ijk_Ret;
2200 putPC(getIReg(rt));
2201 dres->whatNext = Dis_StopHere;
2202 } else {
2203 UChar rt3 = (cins >> 7) & 0x07;
2204 UChar rs3 = (cins >> 4) & 0x07;
2205 UChar rt = GPR3_list[rt3];
2206 UChar rs = GPR3_list[rs3];
2208 if (rs3 < rt3) { /* beqc[16] */
2209 DIP("beqc r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 2 + u);
2210 ir_for_branch(dres, binop(Iop_CmpEQ32, getIReg(rt), getIReg(rs)),
2211 2, (Int)u);
2212 } else { /* bnec[16] */
2213 DIP("bnec r%u, r%u, %X", rt, rs, guest_PC_curr_instr + 2 + u);
2214 ir_for_branch(dres, binop(Iop_CmpNE32, getIReg(rt), getIReg(rs)),
2215 2, (Int)u);
2220 static void nano_p16sr(DisResult *dres, UShort cins)
2222 UChar u = cins & 0xF0;
2223 UChar count = cins & 0x0F;
2224 UChar counter = 0;
2225 UChar rt = cins & 0x200 ? 31 : 30;
2227 if (cins & 0x100) { /* RESTORE.JRC[16] */
2228 DIP("restore.jrc %u, r%u-r%u", u, (rt & 0x1fu) | (rt & 0x10u),
2229 ((rt + count - 1) & 0x1fu) | (rt & 0x10u));
2231 while (counter != count) {
2232 UChar this_rt = ((rt + counter) & 0x1F) | (rt & 0x10);
2233 Int offset = u - ((counter + 1) << 2);
2234 putIReg(this_rt, load(Ity_I32, binop(Iop_Add32, getIReg(29),
2235 mkU32(offset))));
2236 // if this_rt == 29: raise UNPREDICTABLE()
2237 counter++;
2240 putIReg(29, binop(Iop_Add32, getIReg(29), mkU32(u)));
2241 putPC(getIReg(31));
2242 dres->whatNext = Dis_StopHere;
2243 dres->jk_StopHere = Ijk_Ret;
2244 } else { /* SAVE[16] */
2245 DIP("save %u, r%u-r%u", u, (rt & 0x1fu) | (rt & 0x10u),
2246 ((rt + count - 1) & 0x1fu) | (rt & 0x10u));
2248 IRTemp t1 = newTemp(Ity_I32);
2249 assign(t1, getIReg(29));
2251 putIReg(29, binop(Iop_Sub32, mkexpr(t1), mkU32(u)));
2253 while (counter != count) {
2254 UChar this_rt = ((rt + counter) & 0x1f) | (rt & 0x10);
2255 Int offset = -((counter + 1) << 2);
2256 store(binop(Iop_Add32, mkexpr(t1), mkU32(offset)), getIReg(this_rt));
2257 counter++;
2262 static void nano_p16lb(DisResult *dres, UShort cins)
2264 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2265 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2266 UChar u = cins & 0x3;
2268 switch ((cins >> 2) & 0x3) {
2269 case 0x0: /* LB[16] */
2270 DIP("lb[16] r%u %u(r%u)", rt, u, rs);
2271 putIReg(rt, unop(Iop_8Sto32,
2272 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
2273 mkU32(u)))));
2274 break;
2276 case 0x1: /* SB[16] */
2277 rt = GPR3_src_store_list[(cins >> 7) & 0x7];
2278 DIP("sb[16] r%u %u(r%u)", rt, u, rs);
2279 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), unop(Iop_32to8,
2280 getIReg(rt)));
2281 break;
2283 case 0x2: /* LBU[16] */
2284 DIP("lbu[16] r%u %u(r%u)", rt, u, rs);
2285 putIReg(rt, unop(Iop_8Uto32,
2286 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
2287 mkU32(u)))));
2288 break;
2290 default:
2291 vex_printf("Unrecognized bytes %04x\n", cins);
2292 vassert(0);
2296 static void nano_p16lh(DisResult *dres, UShort cins)
2298 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2299 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2300 UChar u = cins & 0x06;
2302 switch (cins & 0x09) {
2303 case 0x0: /* LH[16] */
2304 DIP("lh[16] r%u %u(r%u)", rt, u, rs);
2305 putIReg(rt, unop(Iop_16Sto32,
2306 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
2307 mkU32(u)))));
2308 break;
2310 case 0x1: /* SH[16] */
2311 rt = GPR3_src_store_list[(cins >> 7) & 0x7];
2312 DIP("sh[16] r%u %u(r%u)", rt, u, rs);
2313 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), unop(Iop_32to16,
2314 getIReg(rt)));
2315 break;
2317 case 0x8: /* LHU[16] */
2318 DIP("lhu[16] r%u %u(r%u)", rt, u, rs);
2319 putIReg(rt, unop(Iop_16Uto32,
2320 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
2321 mkU32(u)))));
2322 break;
2324 default:
2325 vex_printf("Unrecognized bytes %04x\n", cins);
2326 vassert(0);
2330 static void nano_p164x4(DisResult *dres, UShort cins)
2332 UChar rt = GPR4_list[((cins >> 6) & 0x08) | ((cins >> 5) & 0x07)];
2333 UChar rs = GPR4_list[((cins >> 1) & 0x08) | (cins & 0x07)];
2334 UChar rd = rt;
2336 switch (cins & 0x108) {
2337 case 0x00: { /* ADDU[4x4] */
2338 DIP("addu[4x4] r%u, r%u, r%u", rd, rs, rt);
2339 putIReg(rd, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
2340 break;
2343 case 0x08: { /* MUL[4x4] */
2344 DIP("mul[4x4] r%u, r%u, r%u", rd, rs, rt);
2345 putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
2346 break;
2349 default:
2350 vassert(0);
2354 static void nano_pgpbh(DisResult *dres, UInt cins)
2356 UChar rt = (cins >> 21) & 0x1F;
2357 UChar rs = 28;
2358 UInt u = cins & 0x3FFFF;
2360 switch ((cins >> 18) & 7) {
2361 case LBGP: { /* lb[gp] */
2362 DIP("lb[gp] r%u %u(r%u)", rt, u, rs);
2363 putIReg(rt, unop(Iop_8Sto32,
2364 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
2365 mkU32(u)))));
2366 break;
2369 case SBGP: { /* sb[gp] */
2370 DIP("sb[gp] r%u %u(r%u)", rt, u, rs);
2371 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), unop(Iop_32to8,
2372 getIReg(rt)));
2373 break;
2376 case LBUGP: { /* lbu[gp] */
2377 DIP("lbu[gp] r%u %u(r%u)", rt, u, rs);
2378 putIReg(rt, unop(Iop_8Uto32,
2379 load(Ity_I8, binop(Iop_Add32, getIReg(rs),
2380 mkU32(u)))));
2381 break;
2384 case ADDIUGPB: { /* addiu[gp.b] */
2385 DIP("addiu r%u, r%u, 0x%X", rt, rs, u);
2386 putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(u)));
2387 break;
2390 case PGPLH: {
2391 if (cins & 0x01) { /* lhu[gp] */
2392 DIP("lhu[gp] r%u %u(r%u)", rt, u, rs);
2393 putIReg(rt, unop(Iop_16Uto32,
2394 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
2395 mkU32(u & 0x3FFFE)))));
2396 } else { /* lh[gp] */
2397 DIP("lh[gp] r%u %u(r%u)", rt, u, rs);
2398 putIReg(rt, unop(Iop_16Sto32,
2399 load(Ity_I16, binop(Iop_Add32, getIReg(rs),
2400 mkU32(u & 0x3FFFE)))));
2403 break;
2406 case PGPSH: {
2407 if (cins & 0x01) {
2408 vassert(0);
2409 } else { /* sh[gp] */
2410 DIP("sh[gp] r%u %u(r%u)", rt, u, rs);
2411 store(binop(Iop_Add32, getIReg(rs), mkU32(u & 0x3FFFE)),
2412 unop(Iop_32to16, getIReg(rt)));
2415 break;
2418 case PGPCP1: {
2419 vassert(0);
2420 break;
2423 case PGPM64: {
2424 vassert(0);
2425 break;
2430 static void nano_pj(DisResult *dres, UInt cins)
2432 UChar rt = (cins >> 21) & 0x1F;
2433 UChar rs = (cins >> 16) & 0x1F;
2435 switch ((cins >> 12) & 0x0F) {
2436 case JALRC32: { /* JARLC[32] */
2437 DIP("jalrc[32] r%u, r%u", rt, rs);
2438 putIReg(rt, mkU32(guest_PC_curr_instr + 4));
2439 putPC(getIReg(rs));
2440 dres->jk_StopHere = Ijk_Call;
2441 dres->whatNext = Dis_StopHere;
2442 break;
2445 case JALRCHB: {
2446 DIP("jalrc.hb r%u r%u", rt, rs);
2447 putIReg(rt, mkU32(guest_PC_curr_instr + 4));
2448 putPC(getIReg(rs));
2449 dres->jk_StopHere = Ijk_Call;
2450 dres->whatNext = Dis_StopHere;
2451 // clear_hazards()
2452 break;
2455 case PBALRSC: {
2456 if (rt == 0) { /* brsc */
2457 DIP("brsc r%u", rs);
2458 IRTemp t1 = newTemp(Ity_I32);
2459 assign(t1, binop(Iop_Add32, mkU32(guest_PC_curr_instr + 4),
2460 binop(Iop_Shl32, getIReg(rs), mkU8(0x01))));
2461 putPC(mkexpr(t1));
2462 } else { /* balrsc */
2463 DIP("balrsc r%u, r%u", rs, rt);
2464 IRTemp t1 = newTemp(Ity_I32);
2465 assign(t1, binop(Iop_Add32, mkU32(guest_PC_curr_instr + 4),
2466 binop(Iop_Shl32, getIReg(rs), mkU8(0x01))));
2467 putIReg(rt, mkU32(guest_PC_curr_instr + 4));
2468 putPC(mkexpr(t1));
2470 dres->jk_StopHere = Ijk_Boring;
2471 dres->whatNext = Dis_StopHere;
2472 break;
2477 static void nano_pgpw(DisResult *dres, UInt cins)
2479 UChar rt = (cins >> 21) & 0x1F;
2480 UChar rs = 28;
2481 UInt u = cins & 0x1FFFFC;
2483 switch (cins & 0x03) {
2484 case PGPW_ADDIU: { /* addiu[gp.w] */
2485 DIP("addiu[gp.w] r%u, r%u, %u", rt, rs, u);
2486 putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(u)));
2487 break;
2490 case PGPW_LW: { /* lw[gp] */
2491 DIP("lw[gp] r%u, %u(r%u)", rt, u, rs);
2492 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
2493 break;
2496 case PGPW_SW: { /* sw[gp] */
2497 DIP("sw[gp] r%u, %u(r%u)", rt, u, rs);
2498 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
2499 break;
2504 static void dis_nanoMIPS16(DisResult *dres, UShort cins)
2506 switch (cins >> 10) {
2507 case P16A2:
2508 nano_p16a2(dres, cins);
2509 break;
2511 case BC16: {
2512 Int s = extend_sign((cins & 0x3FE) | ((cins & 1) << 10), 11);
2513 DIP("bc %0X", guest_PC_curr_instr + 2 + s);
2514 putPC(mkU32(guest_PC_curr_instr + 2 + s));
2515 dres->jk_StopHere = Ijk_Boring;
2516 dres->whatNext = Dis_StopHere;
2517 break;
2520 case P16MV:
2521 nano_p16mv(dres, cins);
2522 break;
2524 case P16SHIFT:
2525 nano_p16shift(dres, cins);
2526 break;
2528 case P16C:
2529 nano_p16c(dres, cins);
2530 break;
2532 case P16BR:
2533 nano_p16br(dres, cins);
2534 break;
2535 break;
2537 case P16ADDU: {
2538 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2539 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2540 UChar rd = GPR3_list[(cins >> 1) & 0x7];
2542 if (cins & 1) { /* SUBU[16] */
2543 DIP("subu r%u, r%u, r%u", rd, rs, rt);
2544 putIReg(rd, binop(Iop_Sub32, getIReg(rs), getIReg(rt)));
2545 } else { /* ADDU[16] */
2546 DIP("addu r%u, r%u, r%u", rd, rs, rt);
2547 putIReg(rd, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
2550 break;
2553 case LI16: {
2554 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2555 UChar eu = cins & 0x7F;
2556 Int s;
2558 if (eu == 127) s = -1;
2559 else s = eu;
2561 DIP("li r%u, %d", rt, s);
2562 putIReg(rt, mkU32(s));
2563 break;
2566 case BNEZC16: {
2567 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2568 Int s = (Char)((cins & 0x7E) | (cins << 7));
2569 DIP("bnezc r%u, %X", rt, guest_PC_curr_instr + 2 + s);
2570 ir_for_branch(dres, binop(Iop_CmpNE32, getIReg(rt), mkU32(0)), 2, s);
2571 break;
2574 case BEQZC16: {
2575 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2576 Int s = (Char)((cins & 0x7E) | (cins << 7));
2577 DIP("beqzc r%u, %X", rt, guest_PC_curr_instr + 2 + s);
2578 ir_for_branch(dres, binop(Iop_CmpEQ32, getIReg(rt), mkU32(0)), 2, s);
2579 break;
2582 case P16LB:
2583 nano_p16lb(dres, cins);
2584 break;
2586 case P16LH:
2587 nano_p16lh(dres, cins);
2588 break;
2590 case P16SR:
2591 nano_p16sr(dres, cins);
2592 break;
2594 case P16A1:
2595 nano_p16a1(dres, cins);
2596 break;
2598 case ANDI16: { /* ANDI[16] */
2599 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2600 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2601 UChar eu = cins & 0xF;
2602 UInt u;
2604 if (eu == 12) u = 0x00FF;
2605 else if (eu == 13) u = 0xFFFF;
2606 else u = (UInt)eu;
2608 DIP("andi[16] r%u, r%u, %u", rt, rs, u);
2609 putIReg(rt, binop(Iop_And32, getIReg(rs), mkU32(u)));
2610 break;
2613 case LW16: { /* LW[16] */
2614 UChar rt = GPR3_list[(cins >> 7) & 0x7];
2615 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2616 UChar u = (cins & 0x0F) << 2;
2617 DIP("lw[16] r%u, %u(r%u)", rt, u, rs);
2618 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
2619 break;
2622 case LWSP: { /* LW[SP] */
2623 UChar rt = (cins >> 5) & 0x1F;
2624 UChar rs = 29;
2625 UChar u = (cins & 0x1F) << 2;
2626 DIP("lw[SP] r%u, %u(r%u)", rt, u, rs);
2627 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
2628 break;
2631 case LWGP16: { /* LW[GP16] */
2632 UChar rt = GPR3_list[(cins >> 7) & 0x07];
2633 UChar rs = 28;
2634 UInt u = (cins & 0x7F) << 2;
2635 DIP("lw[GP16] r%u, %u(r%u)", rt, u, rs);
2636 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
2637 break;
2640 case LW4X4: { /* LW[4x4] */
2641 UChar rt = GPR4_list[((cins >> 6) & 0x08) | ((cins >> 5) & 0x07)];
2642 UChar rs = GPR4_list[((cins >> 1) & 0x08) | (cins & 0x07)];
2643 UChar u = (cins & 0x08) | ((cins >> 6) & 0x04);
2644 DIP("lw[4x4] r%u, %u(r%u)", rt, u, rs);
2645 putIReg(rt, load(Ity_I32, binop(Iop_Add32, getIReg(rs), mkU32(u))));
2646 break;
2649 case SW16: { /* SW[16] */
2650 UChar rt = GPR3_src_store_list[(cins >> 7) & 0x7];
2651 UChar rs = GPR3_list[(cins >> 4) & 0x7];
2652 UChar u = (cins & 0x0F) << 2;
2653 DIP("sw[16] r%u, %u(r%u)", rt, u, rs);
2654 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
2655 break;
2658 case SWSP: { /* SW[SP] */
2659 UChar rt = (cins >> 5) & 0x1F;
2660 UChar rs = 29;
2661 UChar u = (cins & 0x1F) << 2;
2662 DIP("sw[SP] r%u, %u(r%u)", rt, u, rs);
2663 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
2664 break;
2667 case SWGP16: { /* SW[GP16] */
2668 UChar rt = GPR3_src_store_list[(cins >> 7) & 0x07];
2669 UChar rs = 28;
2670 UInt u = (cins & 0x7F) << 2;
2671 DIP("sw[GP16] r%u, %u(r%u)", rt, u, rs);
2672 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
2673 break;
2676 case SW4X4: { /* SW[4x4] */
2677 UChar rt = GPR4_zero_list[((cins >> 6) & 0x08) | ((cins >> 5) & 0x07)];
2678 UChar rs = GPR4_list[((cins >> 1) & 0x08) | (cins & 0x07)];
2679 UChar u = (cins & 0x08) | ((cins >> 6) & 0x04);
2680 DIP("sw[4x4] r%u, %u(r%u)", rt, u, rs);
2681 store(binop(Iop_Add32, getIReg(rs), mkU32(u)), getIReg(rt));
2682 break;
2685 case P164X4: { /* P16.4X4 pool */
2686 nano_p164x4(dres, cins);
2687 break;
2690 case MOVEP: { /* MOVEP */
2691 UChar rd1 = GPR2_reg1_list[((cins >> 2) & 0x02) | ((cins >> 8) & 0x01)];
2692 UChar rd2 = GPR2_reg2_list[((cins >> 2) & 0x02) | ((cins >> 8) & 0x01)];
2693 UChar rs1 = GPR4_zero_list[((cins >> 1) & 0x08) | (cins & 0x07)];
2694 UChar rs2 = GPR4_zero_list[((cins >> 6) & 0x08) | ((cins >> 5) & 0x07)];
2695 DIP("MOVEP r%u, r%u, r%u, r%u", rd1, rd2, rs1, rs2);
2696 putIReg(rd1, getIReg(rs1));
2697 putIReg(rd2, getIReg(rs2));
2698 break;
2701 case MOVEPREV: { /* MOVEP[REV] */
2702 UChar rd1 = GPR4_list[((cins >> 1) & 0x08) | (cins & 0x07)];
2703 UChar rd2 = GPR4_list[((cins >> 6) & 0x08) | ((cins >> 5) & 0x07)];
2704 UChar rs1 = GPR2_reg1_list[((cins >> 2) & 0x02) | ((cins >> 8) & 0x01)];
2705 UChar rs2 = GPR2_reg2_list[((cins >> 2) & 0x02) | ((cins >> 8) & 0x01)];
2706 DIP("MOVEP r%u, r%u, r%u, r%u", rd1, rd2, rs1, rs2);
2707 putIReg(rd1, getIReg(rs1));
2708 putIReg(rd2, getIReg(rs2));
2709 break;
2712 case BALC16: {
2713 Int s = extend_sign((cins & 0x3FE) | ((cins & 0x1) << 10), 11);
2714 DIP("balc %0X", guest_PC_curr_instr + 2 + s);
2715 putIReg(31, mkU32(guest_PC_curr_instr + 2));
2716 putPC(mkU32(guest_PC_curr_instr + 2 + s));
2717 dres->whatNext = Dis_StopHere;
2718 dres->jk_StopHere = Ijk_Call;
2719 break;
2722 default:
2723 vex_printf("Unsupported 16bit: %04X\n", cins);
2724 vassert(0);
2725 break;
2728 dres->len = 2;
2731 static void dis_nanoMIPS32(DisResult *dres, UInt cins)
2734 switch (cins >> 26) {
2735 case P_ADDIURI: {
2736 UChar rt = (cins >> 21) & 0x1F;
2738 if (rt != 0) {
2739 UChar rs = (cins >> 16) & 0x1F;
2740 UInt u = cins & 0xFFFF;
2741 DIP("addiu r%u, r%u, %u", rt, rs, u);
2742 putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(u)));
2743 } else {
2744 nano_pri(dres, cins);
2747 break;
2750 case ADDIUPC32: {
2751 UChar rt = (cins >> 21) & 0x1F;
2752 Int s = extend_sign((cins & 0x1FFFFE) | ((cins & 1) << 21), 22);
2753 DIP("addiupc r%u, 0x%X", rt, guest_PC_curr_instr + 4 + s);
2754 putIReg(rt, mkU32(guest_PC_curr_instr + 4 + s));
2755 break;
2758 case MOVE_BALC: {
2759 Int s = extend_sign((cins & 0x1FFFFE) | ((cins & 1) << 21), 22);
2760 UChar rt = GPR4_zero_list[((cins >> 21) & 0x07)
2761 | ((cins >> 22) & 0x08)];
2762 UChar rd = (cins & 0x1000000) ? 5 : 4; /* GPR1_list */
2763 DIP("move.balc r%u, r%u, %0X", rd, rt, guest_PC_curr_instr + 4 + s);
2764 putIReg(rd, getIReg(rt));
2765 putIReg(31, mkU32(guest_PC_curr_instr + 4));
2766 putPC(mkU32(guest_PC_curr_instr + 4 + s));
2767 dres->jk_StopHere = Ijk_Call;
2768 dres->whatNext = Dis_StopHere;
2769 break;
2772 case PLSU12:
2773 nano_plsu12(dres, cins);
2774 break;
2776 case PGPW:
2777 nano_pgpw(dres, cins);
2778 break;
2780 case PU12:
2781 nano_pu12(dres, cins);
2782 break;
2784 case P32A:
2785 nano_p32a(dres, cins);
2786 break;
2788 case PGPBH:
2789 nano_pgpbh(dres, cins);
2790 break;
2792 case PBAL:
2793 nano_pbal(dres, cins);
2794 break;
2796 case PBR1:
2797 nano_pbr1(dres, cins);
2798 break;
2800 case PBR2:
2801 nano_pbr2(dres, cins);
2802 break;
2804 case PBRI:
2805 nano_pbri(dres, cins);
2806 break;
2808 case PLSS9:
2809 nano_plss9(dres, cins);
2810 break;
2812 case P_LUI:
2813 if (cins & 0x02) { /* ALUIPC */
2814 UChar rt = (cins >> 21) & 0x1F;
2815 UInt s = (cins & 0x1FF000) | ((cins & 0xFFC) << 19) | (cins << 31);
2816 DIP("aluipc r%u %08X", rt, s);
2817 putIReg(rt, binop(Iop_And32, mkU32(guest_PC_curr_instr + s + 4),
2818 unop(Iop_Not32, mkU32(0xFFF))));
2819 } else { /* LUI */
2820 UChar rt = (cins >> 21) & 0x1F;
2821 UInt s = (cins & 0x1FF000) | ((cins & 0xFFC) << 19) | (cins << 31);
2822 DIP("lui r%u %08X", rt, s);
2823 putIReg(rt, mkU32(s));
2826 break;
2828 case PJ: {
2829 nano_pj(dres, cins);
2830 break;
2833 default:
2834 vex_printf("Unsupported 32bit: %08X\n", cins);
2835 vassert(0);
2836 break;
2839 dres->len = 4;
2842 static void dis_nanoMIPS48(DisResult *dres, ULong cins)
2845 UChar rt = (cins >> 37) & 0x1F;
2846 UInt x = (UInt)cins;
2848 switch ((cins >> 32) & 0x1F) {
2849 case P48I_LI:
2850 DIP("li r%u, 0x%X", rt, x);
2851 putIReg(rt, mkU32(x));
2852 break;
2854 case P48I_ADDIU:
2855 DIP("addiu r%u, r%u, 0x%X", rt, rt, x);
2856 putIReg(rt, binop(Iop_Add32, getIReg(rt), mkU32(x)));
2857 break;
2859 case P48I_ADDIU_GP:
2860 DIP("addiu r%u, r28, 0x%X", rt, x);
2861 putIReg(rt, binop(Iop_Add32, getIReg(28), mkU32(x)));
2862 break;
2864 case P48I_ADDIUPC:
2865 DIP("addiupc r%u, 0x%X", rt, x);
2866 putIReg(rt, mkU32(guest_PC_curr_instr + x + 6));
2867 break;
2869 case P48I_LWPC:
2870 DIP("lwpc r%u, 0x%X", rt, x);
2871 putIReg(rt, load(Ity_I32, mkU32(guest_PC_curr_instr + 6 + x)));
2872 break;
2874 case P48I_SWPC:
2875 DIP("swpc r%u, 0x%X", rt, x);
2876 store(mkU32(guest_PC_curr_instr + 6 + x), getIReg(rt));
2877 break;
2879 default:
2880 vex_printf("Unsupported 48bit: %012llX\n", cins);
2881 vassert(0);
2882 break;
2885 dres->len = 6;
2888 static Bool check_for_special_requests_nanoMIPS(DisResult *dres,
2889 const UChar *code)
2891 /* 8000 c04d srl zero, zero, 13
2892 8000 c05d srl zero, zero, 29
2893 8000 c043 srl zero, zero, 3
2894 8000 c053 srl zero, zero, 19 */
2895 const UInt word1 = 0x8000C04D;
2896 const UInt word2 = 0x8000C05D;
2897 const UInt word3 = 0x8000C043;
2898 const UInt word4 = 0x8000C053;
2899 if (getUInt(code + 0) == word1 && getUInt(code + 4) == word2 &&
2900 getUInt(code + 8) == word3 && getUInt(code + 12) == word4) {
2901 /* Got a "Special" instruction preamble. Which one is it? */
2902 if (getUInt(code + 16) == 0x218C6290 /* or t0, t0, t0 */ ) {
2903 /* $a7 = client_request ( $t0 ) */
2904 DIP("a7 = client_request(t0)");
2905 dres->jk_StopHere = Ijk_ClientReq;
2906 dres->whatNext = Dis_StopHere;
2907 dres->len = 20;
2908 return True;
2909 } else if (getUInt(code + 16) == 0x21AD6A90 /* or t1, t1, t1 */ ) {
2910 /* $a7 = guest_NRADDR */
2911 DIP("a7 = guest_NRADDR");
2912 putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS32State, guest_NRADDR),
2913 Ity_I32));
2914 dres->len = 20;
2915 return True;
2916 } else if (getUInt(code + 16) == 0x21CE7290 /* or t2, t2, t2 */ ) {
2917 /* branch-and-link-to-noredir $25 */
2918 DIP("branch-and-link-to-noredir t9");
2919 putIReg(31, mkU32(guest_PC_curr_instr + 20));
2920 putPC(getIReg(25));
2921 dres->jk_StopHere = Ijk_NoRedir;
2922 dres->whatNext = Dis_StopHere;
2923 dres->len = 20;
2924 return True;
2925 } else if (getUInt(code + 16) == 0x21EF7A90 /* or t3, t3, t3 */ ) {
2926 /* IR injection */
2927 DIP("IR injection");
2928 #if defined (_MIPSEL)
2929 vex_inject_ir(irsb, Iend_LE);
2930 #elif defined (_MIPSEB)
2931 vex_inject_ir(irsb, Iend_BE);
2932 #endif
2934 stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMSTART),
2935 mkU32(guest_PC_curr_instr)));
2936 stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMLEN),
2937 mkU32(20)));
2939 dres->whatNext = Dis_StopHere;
2940 dres->jk_StopHere = Ijk_InvalICache;
2941 dres->len = 20;
2942 return True;
2945 return False;
2949 /*------------------------------------------------------------*/
2950 /*--- Disassemble a single instruction ---*/
2951 /*------------------------------------------------------------*/
2953 /* Disassemble a single instruction into IR. The instruction is
2954 located in host memory at guest_instr, and has guest IP of
2955 guest_PC_curr_instr, which will have been set before the call
2956 here. */
2959 /* Disassemble a single instruction into IR. The instruction
2960 is located in host memory at &guest_code[delta]. */
2961 DisResult disInstr_nanoMIPS( IRSB* irsb_IN,
2962 const UChar* guest_code_IN,
2963 Long delta,
2964 Addr guest_IP,
2965 VexArch guest_arch,
2966 const VexArchInfo* archinfo,
2967 const VexAbiInfo* abiinfo,
2968 VexEndness host_endness_IN,
2969 Bool sigill_diag_IN )
2971 DisResult dres;
2972 const UChar *code;
2973 vassert(guest_arch == VexArchNANOMIPS);
2975 /* Set result defaults. */
2976 dres.whatNext = Dis_Continue;
2977 dres.len = 0;
2978 dres.jk_StopHere = Ijk_INVALID;
2979 dres.hint = Dis_HintNone;
2981 irsb = irsb_IN;
2982 guest_PC_curr_instr = (Addr32)guest_IP;
2984 code = guest_code_IN + delta;
2986 if (!check_for_special_requests_nanoMIPS(&dres, code)) {
2987 UShort cins = getUShort(code);
2988 nanoMIPSopcodes opcode = cins >> 10;
2990 if (opcode & P16) dis_nanoMIPS16(&dres, cins);
2991 else if (opcode == P48I) {
2992 ULong cinsl = (((ULong) cins ) << 32) |
2993 (((ULong) getUShort(code + 4)) << 16) |
2994 getUShort(code + 2);
2995 dis_nanoMIPS48(&dres, cinsl);
2996 } else {
2997 UInt cinsi = (((UInt) cins ) << 16) | getUShort(code + 2);
2998 dis_nanoMIPS32(&dres, cinsi);
3002 if ((dres.whatNext == Dis_Continue) ||
3003 (dres.jk_StopHere == Ijk_Sys_syscall) ||
3004 (dres.jk_StopHere == Ijk_SigTRAP) ||
3005 (dres.jk_StopHere == Ijk_SigILL) ||
3006 (dres.jk_StopHere == Ijk_ClientReq) ||
3007 (dres.jk_StopHere == Ijk_NoRedir) ||
3008 (dres.jk_StopHere == Ijk_InvalICache)) {
3009 putPC(mkU32(guest_PC_curr_instr + dres.len));
3012 return dres;
3016 /*--------------------------------------------------------------------*/
3017 /*--- end guest_nanomips_toIR.c ---*/
3018 /*--------------------------------------------------------------------*/