|
|
1.1 root 1: /*
2: * MIPS32 emulation for qemu: main translation routines.
3: *
4: * Copyright (c) 2004-2005 Jocelyn Mayer
5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: */
20:
21: #include <stdarg.h>
22: #include <stdlib.h>
23: #include <stdio.h>
24: #include <string.h>
25: #include <inttypes.h>
26:
27: #include "cpu.h"
28: #include "exec-all.h"
29: #include "disas.h"
30:
31: #define MIPS_DEBUG_DISAS
32: //#define MIPS_SINGLE_STEP
33:
34: enum {
35: #define DEF(s, n, copy_size) INDEX_op_ ## s,
36: #include "opc.h"
37: #undef DEF
38: NB_OPS,
39: };
40:
41: static uint16_t *gen_opc_ptr;
42: static uint32_t *gen_opparam_ptr;
43:
44: #include "gen-op.h"
45:
46: /* MIPS opcodes */
47: #define EXT_SPECIAL 0x100
48: #define EXT_SPECIAL2 0x200
49: #define EXT_REGIMM 0x300
50: #define EXT_CP0 0x400
51: #define EXT_CP1 0x500
52: #define EXT_CP2 0x600
53: #define EXT_CP3 0x700
54:
55: enum {
56: /* indirect opcode tables */
57: OPC_SPECIAL = 0x00,
58: OPC_BREGIMM = 0x01,
59: OPC_CP0 = 0x10,
60: OPC_CP1 = 0x11,
61: OPC_CP2 = 0x12,
62: OPC_CP3 = 0x13,
63: OPC_SPECIAL2 = 0x1C,
64: /* arithmetic with immediate */
65: OPC_ADDI = 0x08,
66: OPC_ADDIU = 0x09,
67: OPC_SLTI = 0x0A,
68: OPC_SLTIU = 0x0B,
69: OPC_ANDI = 0x0C,
70: OPC_ORI = 0x0D,
71: OPC_XORI = 0x0E,
72: OPC_LUI = 0x0F,
73: /* Jump and branches */
74: OPC_J = 0x02,
75: OPC_JAL = 0x03,
76: OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
77: OPC_BEQL = 0x14,
78: OPC_BNE = 0x05,
79: OPC_BNEL = 0x15,
80: OPC_BLEZ = 0x06,
81: OPC_BLEZL = 0x16,
82: OPC_BGTZ = 0x07,
83: OPC_BGTZL = 0x17,
84: OPC_JALX = 0x1D, /* MIPS 16 only */
85: /* Load and stores */
86: OPC_LB = 0x20,
87: OPC_LH = 0x21,
88: OPC_LWL = 0x22,
89: OPC_LW = 0x23,
90: OPC_LBU = 0x24,
91: OPC_LHU = 0x25,
92: OPC_LWR = 0x26,
93: OPC_SB = 0x28,
94: OPC_SH = 0x29,
95: OPC_SWL = 0x2A,
96: OPC_SW = 0x2B,
97: OPC_SWR = 0x2E,
98: OPC_LL = 0x30,
99: OPC_SC = 0x38,
100: /* Floating point load/store */
101: OPC_LWC1 = 0x31,
102: OPC_LWC2 = 0x32,
103: OPC_LDC1 = 0x35,
104: OPC_LDC2 = 0x36,
105: OPC_SWC1 = 0x39,
106: OPC_SWC2 = 0x3A,
107: OPC_SDC1 = 0x3D,
108: OPC_SDC2 = 0x3E,
109: /* Cache and prefetch */
110: OPC_CACHE = 0x2F,
111: OPC_PREF = 0x33,
112: };
113:
114: /* MIPS special opcodes */
115: enum {
116: /* Shifts */
117: OPC_SLL = 0x00 | EXT_SPECIAL,
118: /* NOP is SLL r0, r0, 0 */
119: /* SSNOP is SLL r0, r0, 1 */
120: OPC_SRL = 0x02 | EXT_SPECIAL,
121: OPC_SRA = 0x03 | EXT_SPECIAL,
122: OPC_SLLV = 0x04 | EXT_SPECIAL,
123: OPC_SRLV = 0x06 | EXT_SPECIAL,
124: OPC_SRAV = 0x07 | EXT_SPECIAL,
125: /* Multiplication / division */
126: OPC_MULT = 0x18 | EXT_SPECIAL,
127: OPC_MULTU = 0x19 | EXT_SPECIAL,
128: OPC_DIV = 0x1A | EXT_SPECIAL,
129: OPC_DIVU = 0x1B | EXT_SPECIAL,
130: /* 2 registers arithmetic / logic */
131: OPC_ADD = 0x20 | EXT_SPECIAL,
132: OPC_ADDU = 0x21 | EXT_SPECIAL,
133: OPC_SUB = 0x22 | EXT_SPECIAL,
134: OPC_SUBU = 0x23 | EXT_SPECIAL,
135: OPC_AND = 0x24 | EXT_SPECIAL,
136: OPC_OR = 0x25 | EXT_SPECIAL,
137: OPC_XOR = 0x26 | EXT_SPECIAL,
138: OPC_NOR = 0x27 | EXT_SPECIAL,
139: OPC_SLT = 0x2A | EXT_SPECIAL,
140: OPC_SLTU = 0x2B | EXT_SPECIAL,
141: /* Jumps */
142: OPC_JR = 0x08 | EXT_SPECIAL,
143: OPC_JALR = 0x09 | EXT_SPECIAL,
144: /* Traps */
145: OPC_TGE = 0x30 | EXT_SPECIAL,
146: OPC_TGEU = 0x31 | EXT_SPECIAL,
147: OPC_TLT = 0x32 | EXT_SPECIAL,
148: OPC_TLTU = 0x33 | EXT_SPECIAL,
149: OPC_TEQ = 0x34 | EXT_SPECIAL,
150: OPC_TNE = 0x36 | EXT_SPECIAL,
151: /* HI / LO registers load & stores */
152: OPC_MFHI = 0x10 | EXT_SPECIAL,
153: OPC_MTHI = 0x11 | EXT_SPECIAL,
154: OPC_MFLO = 0x12 | EXT_SPECIAL,
155: OPC_MTLO = 0x13 | EXT_SPECIAL,
156: /* Conditional moves */
157: OPC_MOVZ = 0x0A | EXT_SPECIAL,
158: OPC_MOVN = 0x0B | EXT_SPECIAL,
159:
160: OPC_MOVCI = 0x01 | EXT_SPECIAL,
161:
162: /* Special */
163: OPC_PMON = 0x05 | EXT_SPECIAL,
164: OPC_SYSCALL = 0x0C | EXT_SPECIAL,
165: OPC_BREAK = 0x0D | EXT_SPECIAL,
166: OPC_SYNC = 0x0F | EXT_SPECIAL,
167: };
168:
169: enum {
170: /* Mutiply & xxx operations */
171: OPC_MADD = 0x00 | EXT_SPECIAL2,
172: OPC_MADDU = 0x01 | EXT_SPECIAL2,
173: OPC_MUL = 0x02 | EXT_SPECIAL2,
174: OPC_MSUB = 0x04 | EXT_SPECIAL2,
175: OPC_MSUBU = 0x05 | EXT_SPECIAL2,
176: /* Misc */
177: OPC_CLZ = 0x20 | EXT_SPECIAL2,
178: OPC_CLO = 0x21 | EXT_SPECIAL2,
179: /* Special */
180: OPC_SDBBP = 0x3F | EXT_SPECIAL2,
181: };
182:
183: /* Branch REGIMM */
184: enum {
185: OPC_BLTZ = 0x00 | EXT_REGIMM,
186: OPC_BLTZL = 0x02 | EXT_REGIMM,
187: OPC_BGEZ = 0x01 | EXT_REGIMM,
188: OPC_BGEZL = 0x03 | EXT_REGIMM,
189: OPC_BLTZAL = 0x10 | EXT_REGIMM,
190: OPC_BLTZALL = 0x12 | EXT_REGIMM,
191: OPC_BGEZAL = 0x11 | EXT_REGIMM,
192: OPC_BGEZALL = 0x13 | EXT_REGIMM,
193: OPC_TGEI = 0x08 | EXT_REGIMM,
194: OPC_TGEIU = 0x09 | EXT_REGIMM,
195: OPC_TLTI = 0x0A | EXT_REGIMM,
196: OPC_TLTIU = 0x0B | EXT_REGIMM,
197: OPC_TEQI = 0x0C | EXT_REGIMM,
198: OPC_TNEI = 0x0E | EXT_REGIMM,
199: };
200:
201: enum {
202: /* Coprocessor 0 (MMU) */
203: OPC_MFC0 = 0x00 | EXT_CP0,
204: OPC_MTC0 = 0x04 | EXT_CP0,
205: OPC_TLBR = 0x01 | EXT_CP0,
206: OPC_TLBWI = 0x02 | EXT_CP0,
207: OPC_TLBWR = 0x06 | EXT_CP0,
208: OPC_TLBP = 0x08 | EXT_CP0,
209: OPC_ERET = 0x18 | EXT_CP0,
210: OPC_DERET = 0x1F | EXT_CP0,
211: OPC_WAIT = 0x20 | EXT_CP0,
212: };
213:
214: const unsigned char *regnames[] =
215: { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
216: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
217: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
218: "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
219:
220: /* Warning: no function for r0 register (hard wired to zero) */
221: #define GEN32(func, NAME) \
222: static GenOpFunc *NAME ## _table [32] = { \
223: NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
224: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
225: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
226: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
227: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
228: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
229: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
230: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
231: }; \
232: static inline void func(int n) \
233: { \
234: NAME ## _table[n](); \
235: }
236:
237: /* General purpose registers moves */
238: GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
239: GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
240: GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
241:
242: GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
243: GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
244:
245: typedef struct DisasContext {
246: struct TranslationBlock *tb;
247: target_ulong pc, saved_pc;
248: uint32_t opcode;
249: /* Routine used to access memory */
250: int mem_idx;
251: uint32_t hflags, saved_hflags;
252: uint32_t CP0_Status;
253: int bstate;
254: target_ulong btarget;
255: } DisasContext;
256:
257: enum {
258: BS_NONE = 0, /* We go out of the TB without reaching a branch or an
259: * exception condition
260: */
261: BS_STOP = 1, /* We want to stop translation for any reason */
262: BS_BRANCH = 2, /* We reached a branch condition */
263: BS_EXCP = 3, /* We reached an exception condition */
264: };
265:
266: #if defined MIPS_DEBUG_DISAS
267: #define MIPS_DEBUG(fmt, args...) \
268: do { \
269: if (loglevel & CPU_LOG_TB_IN_ASM) { \
270: fprintf(logfile, "%08x: %08x " fmt "\n", \
271: ctx->pc, ctx->opcode , ##args); \
272: } \
273: } while (0)
274: #else
275: #define MIPS_DEBUG(fmt, args...) do { } while(0)
276: #endif
277:
278: #define MIPS_INVAL(op) \
279: do { \
280: MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \
281: ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
282: } while (0)
283:
284: #define GEN_LOAD_REG_TN(Tn, Rn) \
285: do { \
286: if (Rn == 0) { \
287: glue(gen_op_reset_, Tn)(); \
288: } else { \
289: glue(gen_op_load_gpr_, Tn)(Rn); \
290: } \
291: } while (0)
292:
293: #define GEN_LOAD_IMM_TN(Tn, Imm) \
294: do { \
295: if (Imm == 0) { \
296: glue(gen_op_reset_, Tn)(); \
297: } else { \
298: glue(gen_op_set_, Tn)(Imm); \
299: } \
300: } while (0)
301:
302: #define GEN_STORE_TN_REG(Rn, Tn) \
303: do { \
304: if (Rn != 0) { \
305: glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
306: } \
307: } while (0)
308:
309: static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
310: {
311: #if defined MIPS_DEBUG_DISAS
312: if (loglevel & CPU_LOG_TB_IN_ASM) {
313: fprintf(logfile, "hflags %08x saved %08x\n",
314: ctx->hflags, ctx->saved_hflags);
315: }
316: #endif
317: if (do_save_pc && ctx->pc != ctx->saved_pc) {
318: gen_op_save_pc(ctx->pc);
319: ctx->saved_pc = ctx->pc;
320: }
321: if (ctx->hflags != ctx->saved_hflags) {
322: gen_op_save_state(ctx->hflags);
323: ctx->saved_hflags = ctx->hflags;
324: if (ctx->hflags & MIPS_HFLAG_BR) {
325: gen_op_save_breg_target();
326: } else if (ctx->hflags & MIPS_HFLAG_B) {
327: gen_op_save_btarget(ctx->btarget);
328: } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
329: gen_op_save_bcond();
330: gen_op_save_btarget(ctx->btarget);
331: }
332: }
333: }
334:
335: static inline void generate_exception (DisasContext *ctx, int excp)
336: {
337: #if defined MIPS_DEBUG_DISAS
338: if (loglevel & CPU_LOG_TB_IN_ASM)
339: fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
340: #endif
341: save_cpu_state(ctx, 1);
342: gen_op_raise_exception(excp);
343: ctx->bstate = BS_EXCP;
344: }
345:
346: #if defined(CONFIG_USER_ONLY)
347: #define op_ldst(name) gen_op_##name##_raw()
348: #define OP_LD_TABLE(width)
349: #define OP_ST_TABLE(width)
350: #else
351: #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
352: #define OP_LD_TABLE(width) \
353: static GenOpFunc *gen_op_l##width[] = { \
354: &gen_op_l##width##_user, \
355: &gen_op_l##width##_kernel, \
356: }
357: #define OP_ST_TABLE(width) \
358: static GenOpFunc *gen_op_s##width[] = { \
359: &gen_op_s##width##_user, \
360: &gen_op_s##width##_kernel, \
361: }
362: #endif
363:
364: #ifdef TARGET_MIPS64
365: OP_LD_TABLE(d);
366: OP_LD_TABLE(dl);
367: OP_LD_TABLE(dr);
368: OP_ST_TABLE(d);
369: OP_ST_TABLE(dl);
370: OP_ST_TABLE(dr);
371: #endif
372: OP_LD_TABLE(w);
373: OP_LD_TABLE(wl);
374: OP_LD_TABLE(wr);
375: OP_ST_TABLE(w);
376: OP_ST_TABLE(wl);
377: OP_ST_TABLE(wr);
378: OP_LD_TABLE(h);
379: OP_LD_TABLE(hu);
380: OP_ST_TABLE(h);
381: OP_LD_TABLE(b);
382: OP_LD_TABLE(bu);
383: OP_ST_TABLE(b);
384: OP_LD_TABLE(l);
385: OP_ST_TABLE(c);
386:
387: /* Load and store */
388: static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
389: int base, int16_t offset)
390: {
391: const unsigned char *opn = "unk";
392:
393: if (base == 0) {
394: GEN_LOAD_IMM_TN(T0, offset);
395: } else if (offset == 0) {
396: gen_op_load_gpr_T0(base);
397: } else {
398: gen_op_load_gpr_T0(base);
399: gen_op_set_T1(offset);
400: gen_op_add();
401: }
402: /* Don't do NOP if destination is zero: we must perform the actual
403: * memory access
404: */
405: switch (opc) {
406: #if defined(TARGET_MIPS64)
407: case OPC_LD:
408: #if defined (MIPS_HAS_UNALIGNED_LS)
409: case OPC_ULD:
410: #endif
411: op_ldst(ld);
412: GEN_STORE_TN_REG(rt, T0);
413: opn = "ld";
414: break;
415: case OPC_SD:
416: #if defined (MIPS_HAS_UNALIGNED_LS)
417: case OPC_USD:
418: #endif
419: GEN_LOAD_REG_TN(T1, rt);
420: op_ldst(sd);
421: opn = "sd";
422: break;
423: case OPC_LDL:
424: op_ldst(ldl);
425: GEN_STORE_TN_REG(rt, T0);
426: opn = "ldl";
427: break;
428: case OPC_SDL:
429: GEN_LOAD_REG_TN(T1, rt);
430: op_ldst(sdl);
431: opn = "sdl";
432: break;
433: case OPC_LDR:
434: op_ldst(ldr);
435: GEN_STORE_TN_REG(rt, T0);
436: opn = "ldr";
437: break;
438: case OPC_SDR:
439: GEN_LOAD_REG_TN(T1, rt);
440: op_ldst(sdr);
441: opn = "sdr";
442: break;
443: #endif
444: case OPC_LW:
445: #if defined (MIPS_HAS_UNALIGNED_LS)
446: case OPC_ULW:
447: #endif
448: op_ldst(lw);
449: GEN_STORE_TN_REG(rt, T0);
450: opn = "lw";
451: break;
452: case OPC_SW:
453: #if defined (MIPS_HAS_UNALIGNED_LS)
454: case OPC_USW:
455: #endif
456: GEN_LOAD_REG_TN(T1, rt);
457: op_ldst(sw);
458: opn = "sw";
459: break;
460: case OPC_LH:
461: #if defined (MIPS_HAS_UNALIGNED_LS)
462: case OPC_ULH:
463: #endif
464: op_ldst(lh);
465: GEN_STORE_TN_REG(rt, T0);
466: opn = "lh";
467: break;
468: case OPC_SH:
469: #if defined (MIPS_HAS_UNALIGNED_LS)
470: case OPC_USH:
471: #endif
472: GEN_LOAD_REG_TN(T1, rt);
473: op_ldst(sh);
474: opn = "sh";
475: break;
476: case OPC_LHU:
477: #if defined (MIPS_HAS_UNALIGNED_LS)
478: case OPC_ULHU:
479: #endif
480: op_ldst(lhu);
481: GEN_STORE_TN_REG(rt, T0);
482: opn = "lhu";
483: break;
484: case OPC_LB:
485: op_ldst(lb);
486: GEN_STORE_TN_REG(rt, T0);
487: opn = "lb";
488: break;
489: case OPC_SB:
490: GEN_LOAD_REG_TN(T1, rt);
491: op_ldst(sb);
492: opn = "sb";
493: break;
494: case OPC_LBU:
495: op_ldst(lbu);
496: GEN_STORE_TN_REG(rt, T0);
497: opn = "lbu";
498: break;
499: case OPC_LWL:
500: GEN_LOAD_REG_TN(T1, rt);
501: op_ldst(lwl);
502: GEN_STORE_TN_REG(rt, T0);
503: opn = "lwl";
504: break;
505: case OPC_SWL:
506: GEN_LOAD_REG_TN(T1, rt);
507: op_ldst(swl);
508: opn = "swr";
509: break;
510: case OPC_LWR:
511: GEN_LOAD_REG_TN(T1, rt);
512: op_ldst(lwr);
513: GEN_STORE_TN_REG(rt, T0);
514: opn = "lwr";
515: break;
516: case OPC_SWR:
517: GEN_LOAD_REG_TN(T1, rt);
518: op_ldst(swr);
519: opn = "swr";
520: break;
521: case OPC_LL:
522: op_ldst(ll);
523: GEN_STORE_TN_REG(rt, T0);
524: opn = "ll";
525: break;
526: case OPC_SC:
527: GEN_LOAD_REG_TN(T1, rt);
528: op_ldst(sc);
529: GEN_STORE_TN_REG(rt, T0);
530: opn = "sc";
531: break;
532: default:
533: MIPS_INVAL("load/store");
534: generate_exception(ctx, EXCP_RI);
535: return;
536: }
537: MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
538: }
539:
540: /* Arithmetic with immediate operand */
541: static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
542: int rs, int16_t imm)
543: {
544: uint32_t uimm;
545: const unsigned char *opn = "unk";
546:
547: if (rt == 0 && opc != OPC_ADDI) {
548: /* if no destination, treat it as a NOP
549: * For addi, we must generate the overflow exception when needed.
550: */
551: MIPS_DEBUG("NOP");
552: return;
553: }
554: if (opc == OPC_ADDI || opc == OPC_ADDIU ||
555: opc == OPC_SLTI || opc == OPC_SLTIU)
556: uimm = (int32_t)imm; /* Sign extent to 32 bits */
557: else
558: uimm = (uint16_t)imm;
559: if (opc != OPC_LUI) {
560: GEN_LOAD_REG_TN(T0, rs);
561: GEN_LOAD_IMM_TN(T1, uimm);
562: } else {
563: uimm = uimm << 16;
564: GEN_LOAD_IMM_TN(T0, uimm);
565: }
566: switch (opc) {
567: case OPC_ADDI:
568: save_cpu_state(ctx, 1);
569: gen_op_addo();
570: opn = "addi";
571: break;
572: case OPC_ADDIU:
573: gen_op_add();
574: opn = "addiu";
575: break;
576: case OPC_SLTI:
577: gen_op_lt();
578: opn = "slti";
579: break;
580: case OPC_SLTIU:
581: gen_op_ltu();
582: opn = "sltiu";
583: break;
584: case OPC_ANDI:
585: gen_op_and();
586: opn = "andi";
587: break;
588: case OPC_ORI:
589: gen_op_or();
590: opn = "ori";
591: break;
592: case OPC_XORI:
593: gen_op_xor();
594: opn = "xori";
595: break;
596: case OPC_LUI:
597: opn = "lui";
598: break;
599: case OPC_SLL:
600: gen_op_sll();
601: opn = "sll";
602: break;
603: case OPC_SRA:
604: gen_op_sra();
605: opn = "sra";
606: break;
607: case OPC_SRL:
608: gen_op_srl();
609: opn = "srl";
610: break;
611: default:
612: MIPS_INVAL("imm arith");
613: generate_exception(ctx, EXCP_RI);
614: return;
615: }
616: GEN_STORE_TN_REG(rt, T0);
617: MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
618: }
619:
620: /* Arithmetic */
621: static void gen_arith (DisasContext *ctx, uint16_t opc,
622: int rd, int rs, int rt)
623: {
624: const unsigned char *opn = "unk";
625:
626: if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
627: /* if no destination, treat it as a NOP
628: * For add & sub, we must generate the overflow exception when needed.
629: */
630: MIPS_DEBUG("NOP");
631: return;
632: }
633: GEN_LOAD_REG_TN(T0, rs);
634: GEN_LOAD_REG_TN(T1, rt);
635: switch (opc) {
636: case OPC_ADD:
637: save_cpu_state(ctx, 1);
638: gen_op_addo();
639: opn = "add";
640: break;
641: case OPC_ADDU:
642: gen_op_add();
643: opn = "addu";
644: break;
645: case OPC_SUB:
646: save_cpu_state(ctx, 1);
647: gen_op_subo();
648: opn = "sub";
649: break;
650: case OPC_SUBU:
651: gen_op_sub();
652: opn = "subu";
653: break;
654: case OPC_SLT:
655: gen_op_lt();
656: opn = "slt";
657: break;
658: case OPC_SLTU:
659: gen_op_ltu();
660: opn = "sltu";
661: break;
662: case OPC_AND:
663: gen_op_and();
664: opn = "and";
665: break;
666: case OPC_NOR:
667: gen_op_nor();
668: opn = "nor";
669: break;
670: case OPC_OR:
671: gen_op_or();
672: opn = "or";
673: break;
674: case OPC_XOR:
675: gen_op_xor();
676: opn = "xor";
677: break;
678: case OPC_MUL:
679: gen_op_mul();
680: opn = "mul";
681: break;
682: case OPC_MOVN:
683: gen_op_movn(rd);
684: opn = "movn";
685: goto print;
686: case OPC_MOVZ:
687: gen_op_movz(rd);
688: opn = "movz";
689: goto print;
690: case OPC_SLLV:
691: gen_op_sllv();
692: opn = "sllv";
693: break;
694: case OPC_SRAV:
695: gen_op_srav();
696: opn = "srav";
697: break;
698: case OPC_SRLV:
699: gen_op_srlv();
700: opn = "srlv";
701: break;
702: default:
703: MIPS_INVAL("arith");
704: generate_exception(ctx, EXCP_RI);
705: return;
706: }
707: GEN_STORE_TN_REG(rd, T0);
708: print:
709: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
710: }
711:
712: /* Arithmetic on HI/LO registers */
713: static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
714: {
715: const unsigned char *opn = "unk";
716:
717: if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
718: /* Treat as a NOP */
719: MIPS_DEBUG("NOP");
720: return;
721: }
722: switch (opc) {
723: case OPC_MFHI:
724: gen_op_load_HI();
725: GEN_STORE_TN_REG(reg, T0);
726: opn = "mfhi";
727: break;
728: case OPC_MFLO:
729: gen_op_load_LO();
730: GEN_STORE_TN_REG(reg, T0);
731: opn = "mflo";
732: break;
733: case OPC_MTHI:
734: GEN_LOAD_REG_TN(T0, reg);
735: gen_op_store_HI();
736: opn = "mthi";
737: break;
738: case OPC_MTLO:
739: GEN_LOAD_REG_TN(T0, reg);
740: gen_op_store_LO();
741: opn = "mtlo";
742: break;
743: default:
744: MIPS_INVAL("HILO");
745: generate_exception(ctx, EXCP_RI);
746: return;
747: }
748: MIPS_DEBUG("%s %s", opn, regnames[reg]);
749: }
750:
751: static void gen_muldiv (DisasContext *ctx, uint16_t opc,
752: int rs, int rt)
753: {
754: const unsigned char *opn = "unk";
755:
756: GEN_LOAD_REG_TN(T0, rs);
757: GEN_LOAD_REG_TN(T1, rt);
758: switch (opc) {
759: case OPC_DIV:
760: gen_op_div();
761: opn = "div";
762: break;
763: case OPC_DIVU:
764: gen_op_divu();
765: opn = "divu";
766: break;
767: case OPC_MULT:
768: gen_op_mult();
769: opn = "mult";
770: break;
771: case OPC_MULTU:
772: gen_op_multu();
773: opn = "multu";
774: break;
775: case OPC_MADD:
776: gen_op_madd();
777: opn = "madd";
778: break;
779: case OPC_MADDU:
780: gen_op_maddu();
781: opn = "maddu";
782: break;
783: case OPC_MSUB:
784: gen_op_msub();
785: opn = "msub";
786: break;
787: case OPC_MSUBU:
788: gen_op_msubu();
789: opn = "msubu";
790: break;
791: default:
792: MIPS_INVAL("mul/div");
793: generate_exception(ctx, EXCP_RI);
794: return;
795: }
796: MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
797: }
798:
799: static void gen_cl (DisasContext *ctx, uint16_t opc,
800: int rd, int rs)
801: {
802: const unsigned char *opn = "unk";
803: if (rd == 0) {
804: /* Treat as a NOP */
805: MIPS_DEBUG("NOP");
806: return;
807: }
808: GEN_LOAD_REG_TN(T0, rs);
809: switch (opc) {
810: case OPC_CLO:
811: /* CLO */
812: gen_op_clo();
813: opn = "clo";
814: break;
815: case OPC_CLZ:
816: /* CLZ */
817: gen_op_clz();
818: opn = "clz";
819: break;
820: default:
821: MIPS_INVAL("CLx");
822: generate_exception(ctx, EXCP_RI);
823: return;
824: }
825: gen_op_store_T0_gpr(rd);
826: MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
827: }
828:
829: /* Traps */
830: static void gen_trap (DisasContext *ctx, uint16_t opc,
831: int rs, int rt, int16_t imm)
832: {
833: int cond;
834:
835: cond = 0;
836: /* Load needed operands */
837: switch (opc) {
838: case OPC_TEQ:
839: case OPC_TGE:
840: case OPC_TGEU:
841: case OPC_TLT:
842: case OPC_TLTU:
843: case OPC_TNE:
844: /* Compare two registers */
845: if (rs != rt) {
846: GEN_LOAD_REG_TN(T0, rs);
847: GEN_LOAD_REG_TN(T1, rt);
848: cond = 1;
849: }
850: case OPC_TEQI:
851: case OPC_TGEI:
852: case OPC_TGEIU:
853: case OPC_TLTI:
854: case OPC_TLTIU:
855: case OPC_TNEI:
856: /* Compare register to immediate */
857: if (rs != 0 || imm != 0) {
858: GEN_LOAD_REG_TN(T0, rs);
859: GEN_LOAD_IMM_TN(T1, (int32_t)imm);
860: cond = 1;
861: }
862: break;
863: }
864: if (cond == 0) {
865: switch (opc) {
866: case OPC_TEQ: /* rs == rs */
867: case OPC_TEQI: /* r0 == 0 */
868: case OPC_TGE: /* rs >= rs */
869: case OPC_TGEI: /* r0 >= 0 */
870: case OPC_TGEU: /* rs >= rs unsigned */
871: case OPC_TGEIU: /* r0 >= 0 unsigned */
872: /* Always trap */
873: gen_op_set_T0(1);
874: break;
875: case OPC_TLT: /* rs < rs */
876: case OPC_TLTI: /* r0 < 0 */
877: case OPC_TLTU: /* rs < rs unsigned */
878: case OPC_TLTIU: /* r0 < 0 unsigned */
879: case OPC_TNE: /* rs != rs */
880: case OPC_TNEI: /* r0 != 0 */
881: /* Never trap: treat as NOP */
882: return;
883: default:
884: MIPS_INVAL("TRAP");
885: generate_exception(ctx, EXCP_RI);
886: return;
887: }
888: } else {
889: switch (opc) {
890: case OPC_TEQ:
891: case OPC_TEQI:
892: gen_op_eq();
893: break;
894: case OPC_TGE:
895: case OPC_TGEI:
896: gen_op_ge();
897: break;
898: case OPC_TGEU:
899: case OPC_TGEIU:
900: gen_op_geu();
901: break;
902: case OPC_TLT:
903: case OPC_TLTI:
904: gen_op_lt();
905: break;
906: case OPC_TLTU:
907: case OPC_TLTIU:
908: gen_op_ltu();
909: break;
910: case OPC_TNE:
911: case OPC_TNEI:
912: gen_op_ne();
913: break;
914: default:
915: MIPS_INVAL("TRAP");
916: generate_exception(ctx, EXCP_RI);
917: return;
918: }
919: }
920: save_cpu_state(ctx, 1);
921: gen_op_trap();
922: ctx->bstate = BS_STOP;
923: }
924:
925: /* Branches (before delay slot) */
926: static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
927: int rs, int rt, int32_t offset)
928: {
929: target_ulong btarget;
930: int blink, bcond;
931:
932: btarget = -1;
933: blink = 0;
934: bcond = 0;
935: /* Load needed operands */
936: switch (opc) {
937: case OPC_BEQ:
938: case OPC_BEQL:
939: case OPC_BNE:
940: case OPC_BNEL:
941: /* Compare two registers */
942: if (rs != rt) {
943: GEN_LOAD_REG_TN(T0, rs);
944: GEN_LOAD_REG_TN(T1, rt);
945: bcond = 1;
946: }
947: btarget = ctx->pc + 4 + offset;
948: break;
949: case OPC_BGEZ:
950: case OPC_BGEZAL:
951: case OPC_BGEZALL:
952: case OPC_BGEZL:
953: case OPC_BGTZ:
954: case OPC_BGTZL:
955: case OPC_BLEZ:
956: case OPC_BLEZL:
957: case OPC_BLTZ:
958: case OPC_BLTZAL:
959: case OPC_BLTZALL:
960: case OPC_BLTZL:
961: /* Compare to zero */
962: if (rs != 0) {
963: gen_op_load_gpr_T0(rs);
964: bcond = 1;
965: }
966: btarget = ctx->pc + 4 + offset;
967: break;
968: case OPC_J:
969: case OPC_JAL:
970: /* Jump to immediate */
971: btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
972: break;
973: case OPC_JR:
974: case OPC_JALR:
975: /* Jump to register */
976: if (offset != 0) {
977: /* Only hint = 0 is valid */
978: generate_exception(ctx, EXCP_RI);
979: return;
980: }
981: GEN_LOAD_REG_TN(T2, rs);
982: break;
983: default:
984: MIPS_INVAL("branch/jump");
985: generate_exception(ctx, EXCP_RI);
986: return;
987: }
988: if (bcond == 0) {
989: /* No condition to be computed */
990: switch (opc) {
991: case OPC_BEQ: /* rx == rx */
992: case OPC_BEQL: /* rx == rx likely */
993: case OPC_BGEZ: /* 0 >= 0 */
994: case OPC_BGEZL: /* 0 >= 0 likely */
995: case OPC_BLEZ: /* 0 <= 0 */
996: case OPC_BLEZL: /* 0 <= 0 likely */
997: /* Always take */
998: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
999: MIPS_DEBUG("balways");
1000: break;
1001: case OPC_BGEZAL: /* 0 >= 0 */
1002: case OPC_BGEZALL: /* 0 >= 0 likely */
1003: /* Always take and link */
1004: blink = 31;
1005: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
1006: MIPS_DEBUG("balways and link");
1007: break;
1008: case OPC_BNE: /* rx != rx */
1009: case OPC_BGTZ: /* 0 > 0 */
1010: case OPC_BLTZ: /* 0 < 0 */
1011: case OPC_BLTZAL: /* 0 < 0 */
1012: /* Treated as NOP */
1013: MIPS_DEBUG("bnever (NOP)");
1014: return;
1015: case OPC_BNEL: /* rx != rx likely */
1016: case OPC_BGTZL: /* 0 > 0 likely */
1017: case OPC_BLTZALL: /* 0 < 0 likely */
1018: case OPC_BLTZL: /* 0 < 0 likely */
1019: /* Skip the instruction in the delay slot */
1020: MIPS_DEBUG("bnever and skip");
1021: gen_op_branch((long)ctx->tb, ctx->pc + 4);
1022: return;
1023: case OPC_J:
1024: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
1025: MIPS_DEBUG("j %08x", btarget);
1026: break;
1027: case OPC_JAL:
1028: blink = 31;
1029: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
1030: MIPS_DEBUG("jal %08x", btarget);
1031: break;
1032: case OPC_JR:
1033: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
1034: MIPS_DEBUG("jr %s", regnames[rs]);
1035: break;
1036: case OPC_JALR:
1037: blink = rt;
1038: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
1039: MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1040: break;
1041: default:
1042: MIPS_INVAL("branch/jump");
1043: generate_exception(ctx, EXCP_RI);
1044: return;
1045: }
1046: } else {
1047: switch (opc) {
1048: case OPC_BEQ:
1049: gen_op_eq();
1050: MIPS_DEBUG("beq %s, %s, %08x",
1051: regnames[rs], regnames[rt], btarget);
1052: goto not_likely;
1053: case OPC_BEQL:
1054: gen_op_eq();
1055: MIPS_DEBUG("beql %s, %s, %08x",
1056: regnames[rs], regnames[rt], btarget);
1057: goto likely;
1058: case OPC_BNE:
1059: gen_op_ne();
1060: MIPS_DEBUG("bne %s, %s, %08x",
1061: regnames[rs], regnames[rt], btarget);
1062: goto not_likely;
1063: case OPC_BNEL:
1064: gen_op_ne();
1065: MIPS_DEBUG("bnel %s, %s, %08x",
1066: regnames[rs], regnames[rt], btarget);
1067: goto likely;
1068: case OPC_BGEZ:
1069: gen_op_gez();
1070: MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1071: goto not_likely;
1072: case OPC_BGEZL:
1073: gen_op_gez();
1074: MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1075: goto likely;
1076: case OPC_BGEZAL:
1077: gen_op_gez();
1078: MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1079: blink = 31;
1080: goto not_likely;
1081: case OPC_BGEZALL:
1082: gen_op_gez();
1083: blink = 31;
1084: MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1085: goto likely;
1086: case OPC_BGTZ:
1087: gen_op_gtz();
1088: MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1089: goto not_likely;
1090: case OPC_BGTZL:
1091: gen_op_gtz();
1092: MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1093: goto likely;
1094: case OPC_BLEZ:
1095: gen_op_lez();
1096: MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1097: goto not_likely;
1098: case OPC_BLEZL:
1099: gen_op_lez();
1100: MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1101: goto likely;
1102: case OPC_BLTZ:
1103: gen_op_ltz();
1104: MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1105: goto not_likely;
1106: case OPC_BLTZL:
1107: gen_op_ltz();
1108: MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1109: goto likely;
1110: case OPC_BLTZAL:
1111: gen_op_ltz();
1112: blink = 31;
1113: MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1114: not_likely:
1115: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC;
1116: break;
1117: case OPC_BLTZALL:
1118: gen_op_ltz();
1119: blink = 31;
1120: MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1121: likely:
1122: ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL;
1123: break;
1124: }
1125: gen_op_set_bcond();
1126: }
1127: MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1128: blink, ctx->hflags, btarget);
1129: ctx->btarget = btarget;
1130: if (blink > 0) {
1131: gen_op_set_T0(ctx->pc + 8);
1132: gen_op_store_T0_gpr(blink);
1133: }
1134: return;
1135: }
1136:
1137: /* CP0 (MMU and control) */
1138: static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1139: {
1140: const unsigned char *opn = "unk";
1141:
1142: if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1143: !(ctx->hflags & MIPS_HFLAG_UM) &&
1144: !(ctx->hflags & MIPS_HFLAG_ERL) &&
1145: !(ctx->hflags & MIPS_HFLAG_EXL)) {
1146: if (loglevel & CPU_LOG_TB_IN_ASM) {
1147: fprintf(logfile, "CP0 is not usable\n");
1148: }
1149: gen_op_raise_exception_err(EXCP_CpU, 0);
1150: return;
1151: }
1152: switch (opc) {
1153: case OPC_MFC0:
1154: if (rt == 0) {
1155: /* Treat as NOP */
1156: return;
1157: }
1158: gen_op_mfc0(rd, ctx->opcode & 0x7);
1159: gen_op_store_T0_gpr(rt);
1160: opn = "mfc0";
1161: break;
1162: case OPC_MTC0:
1163: /* If we get an exception, we want to restart at next instruction */
1164: ctx->pc += 4;
1165: save_cpu_state(ctx, 1);
1166: ctx->pc -= 4;
1167: GEN_LOAD_REG_TN(T0, rt);
1168: gen_op_mtc0(rd, ctx->opcode & 0x7);
1169: /* Stop translation as we may have switched the execution mode */
1170: ctx->bstate = BS_STOP;
1171: opn = "mtc0";
1172: break;
1173: #if defined(MIPS_USES_R4K_TLB)
1174: case OPC_TLBWI:
1175: gen_op_tlbwi();
1176: opn = "tlbwi";
1177: break;
1178: case OPC_TLBWR:
1179: gen_op_tlbwr();
1180: opn = "tlbwr";
1181: break;
1182: case OPC_TLBP:
1183: gen_op_tlbp();
1184: opn = "tlbp";
1185: break;
1186: case OPC_TLBR:
1187: gen_op_tlbr();
1188: opn = "tlbr";
1189: break;
1190: #endif
1191: case OPC_ERET:
1192: opn = "eret";
1193: save_cpu_state(ctx, 0);
1194: gen_op_eret();
1195: ctx->bstate = BS_EXCP;
1196: break;
1197: case OPC_DERET:
1198: opn = "deret";
1199: if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1200: generate_exception(ctx, EXCP_RI);
1201: } else {
1202: save_cpu_state(ctx, 0);
1203: gen_op_deret();
1204: ctx->bstate = BS_EXCP;
1205: }
1206: break;
1207: /* XXX: TODO: WAIT */
1208: default:
1209: if (loglevel & CPU_LOG_TB_IN_ASM) {
1210: fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1211: ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1212: ((ctx->opcode >> 16) & 0x1F));
1213: }
1214: generate_exception(ctx, EXCP_RI);
1215: return;
1216: }
1217: MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1218: }
1219:
1220: /* Coprocessor 1 (FPU) */
1221:
1222: /* ISA extensions */
1223: /* MIPS16 extension to MIPS32 */
1224: /* SmartMIPS extension to MIPS32 */
1225:
1226: #ifdef TARGET_MIPS64
1227: static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1228: {
1229: if (func == 0x02 && rd == 0) {
1230: /* NOP */
1231: return;
1232: }
1233: if (rs == 0 || rt == 0) {
1234: gen_op_reset_T0();
1235: gen_op_save64();
1236: } else {
1237: gen_op_load_gpr_T0(rs);
1238: gen_op_load_gpr_T1(rt);
1239: gen_op_save64();
1240: if (func & 0x01)
1241: gen_op_mul64u();
1242: else
1243: gen_op_mul64s();
1244: }
1245: if (func & 0x02)
1246: gen_op_add64();
1247: else
1248: gen_op_sub64();
1249: }
1250:
1251: /* Coprocessor 3 (FPU) */
1252:
1253: /* MDMX extension to MIPS64 */
1254: /* MIPS-3D extension to MIPS64 */
1255:
1256: #endif
1257:
1258: static void decode_opc (DisasContext *ctx)
1259: {
1260: int32_t offset;
1261: int rs, rt, rd, sa;
1262: uint16_t op, op1;
1263: int16_t imm;
1264:
1265: if ((ctx->hflags & MIPS_HFLAG_DS) &&
1266: (ctx->hflags & MIPS_HFLAG_BL)) {
1267: /* Handle blikely not taken case */
1268: MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1269: gen_op_blikely((long)ctx->tb, ctx->pc + 4,
1270: ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
1271: }
1272: op = ctx->opcode >> 26;
1273: rs = ((ctx->opcode >> 21) & 0x1F);
1274: rt = ((ctx->opcode >> 16) & 0x1F);
1275: rd = ((ctx->opcode >> 11) & 0x1F);
1276: sa = ((ctx->opcode >> 6) & 0x1F);
1277: imm = (int16_t)ctx->opcode;
1278: switch (op) {
1279: case 0x00: /* Special opcode */
1280: op1 = ctx->opcode & 0x3F;
1281: switch (op1) {
1282: case 0x00: /* Arithmetic with immediate */
1283: case 0x02 ... 0x03:
1284: gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1285: break;
1286: case 0x04: /* Arithmetic */
1287: case 0x06 ... 0x07:
1288: case 0x0A ... 0x0B:
1289: case 0x20 ... 0x27:
1290: case 0x2A ... 0x2B:
1291: gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1292: break;
1293: case 0x18 ... 0x1B: /* MULT / DIV */
1294: gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1295: break;
1296: case 0x08 ... 0x09: /* Jumps */
1297: gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1298: return;
1299: case 0x30 ... 0x34: /* Traps */
1300: case 0x36:
1301: gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1302: break;
1303: case 0x10: /* Move from HI/LO */
1304: case 0x12:
1305: gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1306: break;
1307: case 0x11:
1308: case 0x13: /* Move to HI/LO */
1309: gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1310: break;
1311: case 0x0C: /* SYSCALL */
1312: generate_exception(ctx, EXCP_SYSCALL);
1313: break;
1314: case 0x0D: /* BREAK */
1315: generate_exception(ctx, EXCP_BREAK);
1316: break;
1317: case 0x0F: /* SYNC */
1318: /* Treat as a noop */
1319: break;
1320: case 0x05: /* Pmon entry point */
1321: gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1322: break;
1323: #if defined (MIPS_HAS_MOVCI)
1324: case 0x01: /* MOVCI */
1325: #endif
1326: #if defined (TARGET_MIPS64)
1327: case 0x14: /* MIPS64 specific opcodes */
1328: case 0x16:
1329: case 0x17:
1330: case 0x1C ... 0x1F:
1331: case 0x2C ... 0x2F:
1332: case 0x37:
1333: case 0x39 ... 0x3B:
1334: case 0x3E ... 0x3F:
1335: #endif
1336: default: /* Invalid */
1337: MIPS_INVAL("special");
1338: generate_exception(ctx, EXCP_RI);
1339: break;
1340: }
1341: break;
1342: case 0x1C: /* Special2 opcode */
1343: op1 = ctx->opcode & 0x3F;
1344: switch (op1) {
1345: #if defined (MIPS_USES_R4K_EXT)
1346: /* Those instructions are not part of MIPS32 core */
1347: case 0x00 ... 0x01: /* Multiply and add/sub */
1348: case 0x04 ... 0x05:
1349: gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1350: break;
1351: case 0x02: /* MUL */
1352: gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1353: break;
1354: case 0x20 ... 0x21: /* CLO / CLZ */
1355: gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1356: break;
1357: #endif
1358: case 0x3F: /* SDBBP */
1359: /* XXX: not clear which exception should be raised
1360: * when in debug mode...
1361: */
1362: if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1363: generate_exception(ctx, EXCP_DBp);
1364: } else {
1365: generate_exception(ctx, EXCP_DBp);
1366: }
1367: /* Treat as a noop */
1368: break;
1369: default: /* Invalid */
1370: MIPS_INVAL("special2");
1371: generate_exception(ctx, EXCP_RI);
1372: break;
1373: }
1374: break;
1375: case 0x01: /* B REGIMM opcode */
1376: op1 = ((ctx->opcode >> 16) & 0x1F);
1377: switch (op1) {
1378: case 0x00 ... 0x03: /* REGIMM branches */
1379: case 0x10 ... 0x13:
1380: gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
1381: return;
1382: case 0x08 ... 0x0C: /* Traps */
1383: case 0x0E:
1384: gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
1385: break;
1386: default: /* Invalid */
1387: MIPS_INVAL("REGIMM");
1388: generate_exception(ctx, EXCP_RI);
1389: break;
1390: }
1391: break;
1392: case 0x10: /* CP0 opcode */
1393: op1 = ((ctx->opcode >> 21) & 0x1F);
1394: switch (op1) {
1395: case 0x00:
1396: case 0x04:
1397: gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
1398: break;
1399: default:
1400: gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd);
1401: break;
1402: }
1403: break;
1404: case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
1405: gen_arith_imm(ctx, op, rt, rs, imm);
1406: break;
1407: case 0x02 ... 0x03: /* Jump */
1408: offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
1409: gen_compute_branch(ctx, op, rs, rt, offset);
1410: return;
1411: case 0x04 ... 0x07: /* Branch */
1412: case 0x14 ... 0x17:
1413: gen_compute_branch(ctx, op, rs, rt, imm << 2);
1414: return;
1415: case 0x20 ... 0x26: /* Load and stores */
1416: case 0x28 ... 0x2E:
1417: case 0x30:
1418: case 0x38:
1419: gen_ldst(ctx, op, rt, rs, imm);
1420: break;
1421: case 0x2F: /* Cache operation */
1422: /* Treat as a noop */
1423: break;
1424: case 0x33: /* Prefetch */
1425: /* Treat as a noop */
1426: break;
1427: case 0x3F: /* HACK */
1428: break;
1429: #if defined(MIPS_USES_FPU)
1430: case 0x31 ... 0x32: /* Floating point load/store */
1431: case 0x35 ... 0x36:
1432: case 0x3A ... 0x3B:
1433: case 0x3D ... 0x3E:
1434: /* Not implemented */
1435: /* XXX: not correct */
1436: #endif
1437: case 0x11: /* CP1 opcode */
1438: /* Not implemented */
1439: /* XXX: not correct */
1440: case 0x12: /* CP2 opcode */
1441: /* Not implemented */
1442: /* XXX: not correct */
1443: case 0x13: /* CP3 opcode */
1444: /* Not implemented */
1445: /* XXX: not correct */
1446: #if defined (TARGET_MIPS64)
1447: case 0x18 ... 0x1B:
1448: case 0x27:
1449: case 0x34:
1450: case 0x37:
1451: /* MIPS64 opcodes */
1452: #endif
1453: #if defined (MIPS_HAS_JALX)
1454: case 0x1D:
1455: /* JALX: not implemented */
1456: #endif
1457: case 0x1E:
1458: /* ASE specific */
1459: #if defined (MIPS_HAS_LSC)
1460: case 0x31: /* LWC1 */
1461: case 0x32: /* LWC2 */
1462: case 0x35: /* SDC1 */
1463: case 0x36: /* SDC2 */
1464: #endif
1465: default: /* Invalid */
1466: MIPS_INVAL("");
1467: generate_exception(ctx, EXCP_RI);
1468: break;
1469: }
1470: if (ctx->hflags & MIPS_HFLAG_DS) {
1471: int hflags = ctx->hflags;
1472: /* Branches completion */
1473: ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS);
1474: ctx->bstate = BS_BRANCH;
1475: save_cpu_state(ctx, 0);
1476: switch (hflags & MIPS_HFLAG_BMASK) {
1477: case MIPS_HFLAG_B:
1478: /* unconditional branch */
1479: MIPS_DEBUG("unconditional branch");
1480: gen_op_branch((long)ctx->tb, ctx->btarget);
1481: break;
1482: case MIPS_HFLAG_BL:
1483: /* blikely taken case */
1484: MIPS_DEBUG("blikely branch taken");
1485: gen_op_branch((long)ctx->tb, ctx->btarget);
1486: break;
1487: case MIPS_HFLAG_BC:
1488: /* Conditional branch */
1489: MIPS_DEBUG("conditional branch");
1490: gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4);
1491: break;
1492: case MIPS_HFLAG_BR:
1493: /* unconditional branch to register */
1494: MIPS_DEBUG("branch to register");
1495: gen_op_breg();
1496: break;
1497: default:
1498: MIPS_DEBUG("unknown branch");
1499: break;
1500: }
1501: }
1502: }
1503:
1504: int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1505: int search_pc)
1506: {
1507: DisasContext ctx, *ctxp = &ctx;
1508: target_ulong pc_start;
1509: uint16_t *gen_opc_end;
1510: int j, lj = -1;
1511:
1512: pc_start = tb->pc;
1513: gen_opc_ptr = gen_opc_buf;
1514: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1515: gen_opparam_ptr = gen_opparam_buf;
1516: ctx.pc = pc_start;
1517: ctx.tb = tb;
1518: ctx.bstate = BS_NONE;
1519: /* Restore delay slot state */
1520: ctx.hflags = env->hflags;
1521: ctx.saved_hflags = ctx.hflags;
1522: if (ctx.hflags & MIPS_HFLAG_BR) {
1523: gen_op_restore_breg_target();
1524: } else if (ctx.hflags & MIPS_HFLAG_B) {
1525: ctx.btarget = env->btarget;
1526: } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1527: /* If we are in the delay slot of a conditional branch,
1528: * restore the branch condition from env->bcond to T2
1529: */
1530: ctx.btarget = env->btarget;
1531: gen_op_restore_bcond();
1532: }
1533: #if defined(CONFIG_USER_ONLY)
1534: ctx.mem_idx = 0;
1535: #else
1536: ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
1537: #endif
1538: ctx.CP0_Status = env->CP0_Status;
1539: #ifdef DEBUG_DISAS
1540: if (loglevel & CPU_LOG_TB_CPU) {
1541: fprintf(logfile, "------------------------------------------------\n");
1542: cpu_dump_state(env, logfile, fprintf, 0);
1543: }
1544: #endif
1545: #if defined MIPS_DEBUG_DISAS
1546: if (loglevel & CPU_LOG_TB_IN_ASM)
1547: fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
1548: tb, ctx.mem_idx, ctx.hflags, env->hflags);
1549: #endif
1550: while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1551: if (search_pc) {
1552: j = gen_opc_ptr - gen_opc_buf;
1553: save_cpu_state(ctxp, 1);
1554: if (lj < j) {
1555: lj++;
1556: while (lj < j)
1557: gen_opc_instr_start[lj++] = 0;
1558: gen_opc_pc[lj] = ctx.pc;
1559: gen_opc_instr_start[lj] = 1;
1560: }
1561: }
1562: ctx.opcode = ldl_code(ctx.pc);
1563: decode_opc(&ctx);
1564: ctx.pc += 4;
1565: if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1566: break;
1567: #if defined (MIPS_SINGLE_STEP)
1568: break;
1569: #endif
1570: }
1571: if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1572: save_cpu_state(ctxp, 0);
1573: gen_op_branch((long)ctx.tb, ctx.pc);
1574: }
1575: gen_op_reset_T0();
1576: /* Generate the return instruction */
1577: gen_op_exit_tb();
1578: *gen_opc_ptr = INDEX_op_end;
1579: if (search_pc) {
1580: j = gen_opc_ptr - gen_opc_buf;
1581: lj++;
1582: while (lj <= j)
1583: gen_opc_instr_start[lj++] = 0;
1584: tb->size = 0;
1585: } else {
1586: tb->size = ctx.pc - pc_start;
1587: }
1588: #ifdef DEBUG_DISAS
1589: #if defined MIPS_DEBUG_DISAS
1590: if (loglevel & CPU_LOG_TB_IN_ASM)
1591: fprintf(logfile, "\n");
1592: #endif
1593: if (loglevel & CPU_LOG_TB_IN_ASM) {
1594: fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1595: target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1596: fprintf(logfile, "\n");
1597: }
1598: if (loglevel & CPU_LOG_TB_OP) {
1599: fprintf(logfile, "OP:\n");
1600: dump_ops(gen_opc_buf, gen_opparam_buf);
1601: fprintf(logfile, "\n");
1602: }
1603: if (loglevel & CPU_LOG_TB_CPU) {
1604: fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1605: }
1606: #endif
1607:
1608: return 0;
1609: }
1610:
1611: int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1612: {
1613: return gen_intermediate_code_internal(env, tb, 0);
1614: }
1615:
1616: int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1617: {
1618: return gen_intermediate_code_internal(env, tb, 1);
1619: }
1620:
1621: void cpu_dump_state (CPUState *env, FILE *f,
1622: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1623: int flags)
1624: {
1625: uint32_t c0_status;
1626: int i;
1627:
1628: cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1629: env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1630: for (i = 0; i < 32; i++) {
1631: if ((i & 3) == 0)
1632: cpu_fprintf(f, "GPR%02d:", i);
1633: cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1634: if ((i & 3) == 3)
1635: cpu_fprintf(f, "\n");
1636: }
1637:
1638: c0_status = env->CP0_Status;
1639: if (env->hflags & MIPS_HFLAG_UM)
1640: c0_status |= (1 << CP0St_UM);
1641: if (env->hflags & MIPS_HFLAG_ERL)
1642: c0_status |= (1 << CP0St_ERL);
1643: if (env->hflags & MIPS_HFLAG_EXL)
1644: c0_status |= (1 << CP0St_EXL);
1645:
1646: cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
1647: c0_status, env->CP0_Cause, env->CP0_EPC);
1648: cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1649: env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1650: }
1651:
1652: CPUMIPSState *cpu_mips_init (void)
1653: {
1654: CPUMIPSState *env;
1655:
1656: cpu_exec_init();
1657: env = qemu_mallocz(sizeof(CPUMIPSState));
1658: if (!env)
1659: return NULL;
1660: tlb_flush(env, 1);
1661: /* Minimal init */
1662: env->PC = 0xBFC00000;
1663: #if defined (MIPS_USES_R4K_TLB)
1664: env->CP0_random = MIPS_TLB_NB - 1;
1665: #endif
1666: env->CP0_Wired = 0;
1667: env->CP0_Config0 = MIPS_CONFIG0;
1668: #if defined (MIPS_CONFIG1)
1669: env->CP0_Config1 = MIPS_CONFIG1;
1670: #endif
1671: #if defined (MIPS_CONFIG2)
1672: env->CP0_Config2 = MIPS_CONFIG2;
1673: #endif
1674: #if defined (MIPS_CONFIG3)
1675: env->CP0_Config3 = MIPS_CONFIG3;
1676: #endif
1677: env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1678: env->CP0_WatchLo = 0;
1679: env->hflags = MIPS_HFLAG_ERL;
1680: /* Count register increments in debug mode, EJTAG version 1 */
1681: env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1682: env->CP0_PRid = MIPS_CPU;
1683: env->exception_index = EXCP_NONE;
1684:
1685: cpu_single_env = env;
1686:
1687: return env;
1688: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.