|
|
1.1 root 1: /*
2: * MIPS32 emulation for qemu: main translation routines.
3: *
4: * Copyright (c) 2004-2005 Jocelyn Mayer
1.1.1.4 ! root 5: * Copyright (c) 2006 Marius Groeger (FPU operations)
1.1 root 6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * Lesser General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
18: * License along with this library; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: #include <stdarg.h>
23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <string.h>
26: #include <inttypes.h>
27:
28: #include "cpu.h"
29: #include "exec-all.h"
30: #include "disas.h"
31:
1.1.1.2 root 32: //#define MIPS_DEBUG_DISAS
1.1 root 33: //#define MIPS_SINGLE_STEP
34:
1.1.1.2 root 35: #ifdef USE_DIRECT_JUMP
36: #define TBPARAM(x)
37: #else
38: #define TBPARAM(x) (long)(x)
39: #endif
40:
1.1 root 41: enum {
42: #define DEF(s, n, copy_size) INDEX_op_ ## s,
43: #include "opc.h"
44: #undef DEF
45: NB_OPS,
46: };
47:
48: static uint16_t *gen_opc_ptr;
49: static uint32_t *gen_opparam_ptr;
50:
51: #include "gen-op.h"
52:
53: /* MIPS opcodes */
54: #define EXT_SPECIAL 0x100
55: #define EXT_SPECIAL2 0x200
56: #define EXT_REGIMM 0x300
57: #define EXT_CP0 0x400
58: #define EXT_CP1 0x500
59: #define EXT_CP2 0x600
60: #define EXT_CP3 0x700
61:
62: enum {
63: /* indirect opcode tables */
64: OPC_SPECIAL = 0x00,
65: OPC_BREGIMM = 0x01,
66: OPC_CP0 = 0x10,
67: OPC_CP1 = 0x11,
68: OPC_CP2 = 0x12,
69: OPC_CP3 = 0x13,
70: OPC_SPECIAL2 = 0x1C,
71: /* arithmetic with immediate */
72: OPC_ADDI = 0x08,
73: OPC_ADDIU = 0x09,
74: OPC_SLTI = 0x0A,
75: OPC_SLTIU = 0x0B,
76: OPC_ANDI = 0x0C,
77: OPC_ORI = 0x0D,
78: OPC_XORI = 0x0E,
79: OPC_LUI = 0x0F,
80: /* Jump and branches */
81: OPC_J = 0x02,
82: OPC_JAL = 0x03,
83: OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
84: OPC_BEQL = 0x14,
85: OPC_BNE = 0x05,
86: OPC_BNEL = 0x15,
87: OPC_BLEZ = 0x06,
88: OPC_BLEZL = 0x16,
89: OPC_BGTZ = 0x07,
90: OPC_BGTZL = 0x17,
91: OPC_JALX = 0x1D, /* MIPS 16 only */
92: /* Load and stores */
93: OPC_LB = 0x20,
94: OPC_LH = 0x21,
95: OPC_LWL = 0x22,
96: OPC_LW = 0x23,
97: OPC_LBU = 0x24,
98: OPC_LHU = 0x25,
99: OPC_LWR = 0x26,
1.1.1.4 ! root 100: OPC_LWU = 0x27,
1.1 root 101: OPC_SB = 0x28,
102: OPC_SH = 0x29,
103: OPC_SWL = 0x2A,
104: OPC_SW = 0x2B,
105: OPC_SWR = 0x2E,
106: OPC_LL = 0x30,
107: OPC_SC = 0x38,
108: /* Floating point load/store */
109: OPC_LWC1 = 0x31,
110: OPC_LWC2 = 0x32,
111: OPC_LDC1 = 0x35,
112: OPC_LDC2 = 0x36,
113: OPC_SWC1 = 0x39,
114: OPC_SWC2 = 0x3A,
115: OPC_SDC1 = 0x3D,
116: OPC_SDC2 = 0x3E,
117: /* Cache and prefetch */
118: OPC_CACHE = 0x2F,
119: OPC_PREF = 0x33,
120: };
121:
122: /* MIPS special opcodes */
123: enum {
124: /* Shifts */
125: OPC_SLL = 0x00 | EXT_SPECIAL,
126: /* NOP is SLL r0, r0, 0 */
127: /* SSNOP is SLL r0, r0, 1 */
128: OPC_SRL = 0x02 | EXT_SPECIAL,
129: OPC_SRA = 0x03 | EXT_SPECIAL,
130: OPC_SLLV = 0x04 | EXT_SPECIAL,
131: OPC_SRLV = 0x06 | EXT_SPECIAL,
132: OPC_SRAV = 0x07 | EXT_SPECIAL,
133: /* Multiplication / division */
134: OPC_MULT = 0x18 | EXT_SPECIAL,
135: OPC_MULTU = 0x19 | EXT_SPECIAL,
136: OPC_DIV = 0x1A | EXT_SPECIAL,
137: OPC_DIVU = 0x1B | EXT_SPECIAL,
138: /* 2 registers arithmetic / logic */
139: OPC_ADD = 0x20 | EXT_SPECIAL,
140: OPC_ADDU = 0x21 | EXT_SPECIAL,
141: OPC_SUB = 0x22 | EXT_SPECIAL,
142: OPC_SUBU = 0x23 | EXT_SPECIAL,
143: OPC_AND = 0x24 | EXT_SPECIAL,
144: OPC_OR = 0x25 | EXT_SPECIAL,
145: OPC_XOR = 0x26 | EXT_SPECIAL,
146: OPC_NOR = 0x27 | EXT_SPECIAL,
147: OPC_SLT = 0x2A | EXT_SPECIAL,
148: OPC_SLTU = 0x2B | EXT_SPECIAL,
149: /* Jumps */
150: OPC_JR = 0x08 | EXT_SPECIAL,
151: OPC_JALR = 0x09 | EXT_SPECIAL,
152: /* Traps */
153: OPC_TGE = 0x30 | EXT_SPECIAL,
154: OPC_TGEU = 0x31 | EXT_SPECIAL,
155: OPC_TLT = 0x32 | EXT_SPECIAL,
156: OPC_TLTU = 0x33 | EXT_SPECIAL,
157: OPC_TEQ = 0x34 | EXT_SPECIAL,
158: OPC_TNE = 0x36 | EXT_SPECIAL,
159: /* HI / LO registers load & stores */
160: OPC_MFHI = 0x10 | EXT_SPECIAL,
161: OPC_MTHI = 0x11 | EXT_SPECIAL,
162: OPC_MFLO = 0x12 | EXT_SPECIAL,
163: OPC_MTLO = 0x13 | EXT_SPECIAL,
164: /* Conditional moves */
165: OPC_MOVZ = 0x0A | EXT_SPECIAL,
166: OPC_MOVN = 0x0B | EXT_SPECIAL,
167:
168: OPC_MOVCI = 0x01 | EXT_SPECIAL,
169:
170: /* Special */
171: OPC_PMON = 0x05 | EXT_SPECIAL,
172: OPC_SYSCALL = 0x0C | EXT_SPECIAL,
173: OPC_BREAK = 0x0D | EXT_SPECIAL,
174: OPC_SYNC = 0x0F | EXT_SPECIAL,
175: };
176:
177: enum {
178: /* Mutiply & xxx operations */
179: OPC_MADD = 0x00 | EXT_SPECIAL2,
180: OPC_MADDU = 0x01 | EXT_SPECIAL2,
181: OPC_MUL = 0x02 | EXT_SPECIAL2,
182: OPC_MSUB = 0x04 | EXT_SPECIAL2,
183: OPC_MSUBU = 0x05 | EXT_SPECIAL2,
184: /* Misc */
185: OPC_CLZ = 0x20 | EXT_SPECIAL2,
186: OPC_CLO = 0x21 | EXT_SPECIAL2,
187: /* Special */
188: OPC_SDBBP = 0x3F | EXT_SPECIAL2,
189: };
190:
191: /* Branch REGIMM */
192: enum {
193: OPC_BLTZ = 0x00 | EXT_REGIMM,
194: OPC_BLTZL = 0x02 | EXT_REGIMM,
195: OPC_BGEZ = 0x01 | EXT_REGIMM,
196: OPC_BGEZL = 0x03 | EXT_REGIMM,
197: OPC_BLTZAL = 0x10 | EXT_REGIMM,
198: OPC_BLTZALL = 0x12 | EXT_REGIMM,
199: OPC_BGEZAL = 0x11 | EXT_REGIMM,
200: OPC_BGEZALL = 0x13 | EXT_REGIMM,
201: OPC_TGEI = 0x08 | EXT_REGIMM,
202: OPC_TGEIU = 0x09 | EXT_REGIMM,
203: OPC_TLTI = 0x0A | EXT_REGIMM,
204: OPC_TLTIU = 0x0B | EXT_REGIMM,
205: OPC_TEQI = 0x0C | EXT_REGIMM,
206: OPC_TNEI = 0x0E | EXT_REGIMM,
207: };
208:
209: enum {
210: /* Coprocessor 0 (MMU) */
211: OPC_MFC0 = 0x00 | EXT_CP0,
212: OPC_MTC0 = 0x04 | EXT_CP0,
213: OPC_TLBR = 0x01 | EXT_CP0,
214: OPC_TLBWI = 0x02 | EXT_CP0,
215: OPC_TLBWR = 0x06 | EXT_CP0,
216: OPC_TLBP = 0x08 | EXT_CP0,
217: OPC_ERET = 0x18 | EXT_CP0,
218: OPC_DERET = 0x1F | EXT_CP0,
219: OPC_WAIT = 0x20 | EXT_CP0,
220: };
221:
1.1.1.4 ! root 222: #ifdef MIPS_USES_FPU
! 223: enum {
! 224: /* Coprocessor 1 (FPU) */
! 225: OPC_MFC1 = 0x00 | EXT_CP1,
! 226: OPC_MTC1 = 0x04 | EXT_CP1,
! 227: OPC_CFC1 = 0x02 | EXT_CP1,
! 228: OPC_CTC1 = 0x06 | EXT_CP1,
! 229: };
! 230: #endif
! 231:
1.1 root 232: const unsigned char *regnames[] =
233: { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
234: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
235: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
236: "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
237:
238: /* Warning: no function for r0 register (hard wired to zero) */
239: #define GEN32(func, NAME) \
240: static GenOpFunc *NAME ## _table [32] = { \
241: NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
242: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
243: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
244: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
245: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
246: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
247: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
248: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
249: }; \
250: static inline void func(int n) \
251: { \
252: NAME ## _table[n](); \
253: }
254:
255: /* General purpose registers moves */
256: GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
257: GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
258: GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
259:
260: GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
261: GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
262:
1.1.1.4 ! root 263: #ifdef MIPS_USES_FPU
! 264: const unsigned char *fregnames[] =
! 265: { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
! 266: "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
! 267: "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
! 268: "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
! 269:
! 270: # define SFGEN32(func, NAME) \
! 271: static GenOpFunc *NAME ## _table [32] = { \
! 272: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
! 273: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
! 274: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
! 275: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
! 276: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
! 277: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
! 278: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
! 279: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
! 280: }; \
! 281: static inline void func(int n) \
! 282: { \
! 283: NAME ## _table[n](); \
! 284: }
! 285:
! 286: # define DFGEN32(func, NAME) \
! 287: static GenOpFunc *NAME ## _table [32] = { \
! 288: NAME ## 0, 0, NAME ## 2, 0, \
! 289: NAME ## 4, 0, NAME ## 6, 0, \
! 290: NAME ## 8, 0, NAME ## 10, 0, \
! 291: NAME ## 12, 0, NAME ## 14, 0, \
! 292: NAME ## 16, 0, NAME ## 18, 0, \
! 293: NAME ## 20, 0, NAME ## 22, 0, \
! 294: NAME ## 24, 0, NAME ## 26, 0, \
! 295: NAME ## 28, 0, NAME ## 30, 0, \
! 296: }; \
! 297: static inline void func(int n) \
! 298: { \
! 299: NAME ## _table[n](); \
! 300: }
! 301:
! 302: SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
! 303: SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
! 304:
! 305: SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
! 306: SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
! 307:
! 308: SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
! 309: SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
! 310:
! 311: DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
! 312: DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
! 313:
! 314: DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
! 315: DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
! 316:
! 317: DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
! 318: DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
! 319:
! 320: #define FOP_CONDS(fmt) \
! 321: static GenOpFunc * cond_ ## fmt ## _table[16] = { \
! 322: gen_op_cmp_ ## fmt ## _f, \
! 323: gen_op_cmp_ ## fmt ## _un, \
! 324: gen_op_cmp_ ## fmt ## _eq, \
! 325: gen_op_cmp_ ## fmt ## _ueq, \
! 326: gen_op_cmp_ ## fmt ## _olt, \
! 327: gen_op_cmp_ ## fmt ## _ult, \
! 328: gen_op_cmp_ ## fmt ## _ole, \
! 329: gen_op_cmp_ ## fmt ## _ule, \
! 330: gen_op_cmp_ ## fmt ## _sf, \
! 331: gen_op_cmp_ ## fmt ## _ngle, \
! 332: gen_op_cmp_ ## fmt ## _seq, \
! 333: gen_op_cmp_ ## fmt ## _ngl, \
! 334: gen_op_cmp_ ## fmt ## _lt, \
! 335: gen_op_cmp_ ## fmt ## _nge, \
! 336: gen_op_cmp_ ## fmt ## _le, \
! 337: gen_op_cmp_ ## fmt ## _ngt, \
! 338: }; \
! 339: static inline void gen_cmp_ ## fmt(int n) \
! 340: { \
! 341: cond_ ## fmt ## _table[n](); \
! 342: }
! 343:
! 344: FOP_CONDS(d)
! 345: FOP_CONDS(s)
! 346:
! 347: #endif
! 348:
1.1 root 349: typedef struct DisasContext {
350: struct TranslationBlock *tb;
351: target_ulong pc, saved_pc;
352: uint32_t opcode;
353: /* Routine used to access memory */
354: int mem_idx;
355: uint32_t hflags, saved_hflags;
356: uint32_t CP0_Status;
357: int bstate;
358: target_ulong btarget;
359: } DisasContext;
360:
361: enum {
362: BS_NONE = 0, /* We go out of the TB without reaching a branch or an
363: * exception condition
364: */
365: BS_STOP = 1, /* We want to stop translation for any reason */
366: BS_BRANCH = 2, /* We reached a branch condition */
367: BS_EXCP = 3, /* We reached an exception condition */
368: };
369:
370: #if defined MIPS_DEBUG_DISAS
371: #define MIPS_DEBUG(fmt, args...) \
372: do { \
373: if (loglevel & CPU_LOG_TB_IN_ASM) { \
374: fprintf(logfile, "%08x: %08x " fmt "\n", \
375: ctx->pc, ctx->opcode , ##args); \
376: } \
377: } while (0)
378: #else
379: #define MIPS_DEBUG(fmt, args...) do { } while(0)
380: #endif
381:
382: #define MIPS_INVAL(op) \
383: do { \
384: MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \
385: ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
386: } while (0)
387:
388: #define GEN_LOAD_REG_TN(Tn, Rn) \
389: do { \
390: if (Rn == 0) { \
391: glue(gen_op_reset_, Tn)(); \
392: } else { \
393: glue(gen_op_load_gpr_, Tn)(Rn); \
394: } \
395: } while (0)
396:
397: #define GEN_LOAD_IMM_TN(Tn, Imm) \
398: do { \
399: if (Imm == 0) { \
400: glue(gen_op_reset_, Tn)(); \
401: } else { \
402: glue(gen_op_set_, Tn)(Imm); \
403: } \
404: } while (0)
405:
406: #define GEN_STORE_TN_REG(Rn, Tn) \
407: do { \
408: if (Rn != 0) { \
409: glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
410: } \
411: } while (0)
412:
1.1.1.4 ! root 413: #ifdef MIPS_USES_FPU
! 414:
! 415: # define GEN_LOAD_FREG_FTN(FTn, Fn) \
! 416: do { \
! 417: glue(gen_op_load_fpr_, FTn)(Fn); \
! 418: } while (0)
! 419:
! 420: #define GEN_STORE_FTN_FREG(Fn, FTn) \
! 421: do { \
! 422: glue(gen_op_store_fpr_, FTn)(Fn); \
! 423: } while (0)
! 424:
! 425: #endif
! 426:
1.1 root 427: static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
428: {
429: #if defined MIPS_DEBUG_DISAS
430: if (loglevel & CPU_LOG_TB_IN_ASM) {
431: fprintf(logfile, "hflags %08x saved %08x\n",
432: ctx->hflags, ctx->saved_hflags);
433: }
434: #endif
435: if (do_save_pc && ctx->pc != ctx->saved_pc) {
436: gen_op_save_pc(ctx->pc);
437: ctx->saved_pc = ctx->pc;
438: }
439: if (ctx->hflags != ctx->saved_hflags) {
440: gen_op_save_state(ctx->hflags);
441: ctx->saved_hflags = ctx->hflags;
442: if (ctx->hflags & MIPS_HFLAG_BR) {
443: gen_op_save_breg_target();
444: } else if (ctx->hflags & MIPS_HFLAG_B) {
445: gen_op_save_btarget(ctx->btarget);
446: } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
447: gen_op_save_bcond();
448: gen_op_save_btarget(ctx->btarget);
449: }
450: }
451: }
452:
1.1.1.2 root 453: static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
1.1 root 454: {
455: #if defined MIPS_DEBUG_DISAS
456: if (loglevel & CPU_LOG_TB_IN_ASM)
457: fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
458: #endif
459: save_cpu_state(ctx, 1);
1.1.1.2 root 460: if (err == 0)
461: gen_op_raise_exception(excp);
462: else
463: gen_op_raise_exception_err(excp, err);
1.1 root 464: ctx->bstate = BS_EXCP;
465: }
466:
1.1.1.2 root 467: static inline void generate_exception (DisasContext *ctx, int excp)
468: {
469: generate_exception_err (ctx, excp, 0);
470: }
471:
1.1 root 472: #if defined(CONFIG_USER_ONLY)
473: #define op_ldst(name) gen_op_##name##_raw()
474: #define OP_LD_TABLE(width)
475: #define OP_ST_TABLE(width)
476: #else
477: #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
478: #define OP_LD_TABLE(width) \
479: static GenOpFunc *gen_op_l##width[] = { \
480: &gen_op_l##width##_user, \
481: &gen_op_l##width##_kernel, \
482: }
483: #define OP_ST_TABLE(width) \
484: static GenOpFunc *gen_op_s##width[] = { \
485: &gen_op_s##width##_user, \
486: &gen_op_s##width##_kernel, \
487: }
488: #endif
489:
490: #ifdef TARGET_MIPS64
491: OP_LD_TABLE(d);
492: OP_LD_TABLE(dl);
493: OP_LD_TABLE(dr);
494: OP_ST_TABLE(d);
495: OP_ST_TABLE(dl);
496: OP_ST_TABLE(dr);
497: #endif
498: OP_LD_TABLE(w);
1.1.1.4 ! root 499: OP_LD_TABLE(wu);
1.1 root 500: OP_LD_TABLE(wl);
501: OP_LD_TABLE(wr);
502: OP_ST_TABLE(w);
503: OP_ST_TABLE(wl);
504: OP_ST_TABLE(wr);
505: OP_LD_TABLE(h);
506: OP_LD_TABLE(hu);
507: OP_ST_TABLE(h);
508: OP_LD_TABLE(b);
509: OP_LD_TABLE(bu);
510: OP_ST_TABLE(b);
511: OP_LD_TABLE(l);
512: OP_ST_TABLE(c);
1.1.1.4 ! root 513: #ifdef MIPS_USES_FPU
! 514: OP_LD_TABLE(wc1);
! 515: OP_ST_TABLE(wc1);
! 516: OP_LD_TABLE(dc1);
! 517: OP_ST_TABLE(dc1);
! 518: #endif
1.1 root 519:
520: /* Load and store */
521: static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
522: int base, int16_t offset)
523: {
524: const unsigned char *opn = "unk";
525:
526: if (base == 0) {
527: GEN_LOAD_IMM_TN(T0, offset);
528: } else if (offset == 0) {
529: gen_op_load_gpr_T0(base);
530: } else {
531: gen_op_load_gpr_T0(base);
532: gen_op_set_T1(offset);
533: gen_op_add();
534: }
535: /* Don't do NOP if destination is zero: we must perform the actual
536: * memory access
537: */
538: switch (opc) {
539: #if defined(TARGET_MIPS64)
540: case OPC_LD:
541: #if defined (MIPS_HAS_UNALIGNED_LS)
542: case OPC_ULD:
543: #endif
544: op_ldst(ld);
545: GEN_STORE_TN_REG(rt, T0);
546: opn = "ld";
547: break;
548: case OPC_SD:
549: #if defined (MIPS_HAS_UNALIGNED_LS)
550: case OPC_USD:
551: #endif
552: GEN_LOAD_REG_TN(T1, rt);
553: op_ldst(sd);
554: opn = "sd";
555: break;
556: case OPC_LDL:
557: op_ldst(ldl);
558: GEN_STORE_TN_REG(rt, T0);
559: opn = "ldl";
560: break;
561: case OPC_SDL:
562: GEN_LOAD_REG_TN(T1, rt);
563: op_ldst(sdl);
564: opn = "sdl";
565: break;
566: case OPC_LDR:
567: op_ldst(ldr);
568: GEN_STORE_TN_REG(rt, T0);
569: opn = "ldr";
570: break;
571: case OPC_SDR:
572: GEN_LOAD_REG_TN(T1, rt);
573: op_ldst(sdr);
574: opn = "sdr";
575: break;
576: #endif
577: case OPC_LW:
578: #if defined (MIPS_HAS_UNALIGNED_LS)
579: case OPC_ULW:
580: #endif
581: op_ldst(lw);
582: GEN_STORE_TN_REG(rt, T0);
583: opn = "lw";
584: break;
1.1.1.4 ! root 585: case OPC_LWU:
! 586: op_ldst(lwu);
! 587: GEN_STORE_TN_REG(rt, T0);
! 588: opn = "lwu";
! 589: break;
1.1 root 590: case OPC_SW:
591: #if defined (MIPS_HAS_UNALIGNED_LS)
592: case OPC_USW:
593: #endif
594: GEN_LOAD_REG_TN(T1, rt);
595: op_ldst(sw);
596: opn = "sw";
597: break;
598: case OPC_LH:
599: #if defined (MIPS_HAS_UNALIGNED_LS)
600: case OPC_ULH:
601: #endif
602: op_ldst(lh);
603: GEN_STORE_TN_REG(rt, T0);
604: opn = "lh";
605: break;
606: case OPC_SH:
607: #if defined (MIPS_HAS_UNALIGNED_LS)
608: case OPC_USH:
609: #endif
610: GEN_LOAD_REG_TN(T1, rt);
611: op_ldst(sh);
612: opn = "sh";
613: break;
614: case OPC_LHU:
615: #if defined (MIPS_HAS_UNALIGNED_LS)
616: case OPC_ULHU:
617: #endif
618: op_ldst(lhu);
619: GEN_STORE_TN_REG(rt, T0);
620: opn = "lhu";
621: break;
622: case OPC_LB:
623: op_ldst(lb);
624: GEN_STORE_TN_REG(rt, T0);
625: opn = "lb";
626: break;
627: case OPC_SB:
628: GEN_LOAD_REG_TN(T1, rt);
629: op_ldst(sb);
630: opn = "sb";
631: break;
632: case OPC_LBU:
633: op_ldst(lbu);
634: GEN_STORE_TN_REG(rt, T0);
635: opn = "lbu";
636: break;
637: case OPC_LWL:
638: GEN_LOAD_REG_TN(T1, rt);
639: op_ldst(lwl);
640: GEN_STORE_TN_REG(rt, T0);
641: opn = "lwl";
642: break;
643: case OPC_SWL:
644: GEN_LOAD_REG_TN(T1, rt);
645: op_ldst(swl);
646: opn = "swr";
647: break;
648: case OPC_LWR:
649: GEN_LOAD_REG_TN(T1, rt);
650: op_ldst(lwr);
651: GEN_STORE_TN_REG(rt, T0);
652: opn = "lwr";
653: break;
654: case OPC_SWR:
655: GEN_LOAD_REG_TN(T1, rt);
656: op_ldst(swr);
657: opn = "swr";
658: break;
659: case OPC_LL:
660: op_ldst(ll);
661: GEN_STORE_TN_REG(rt, T0);
662: opn = "ll";
663: break;
664: case OPC_SC:
665: GEN_LOAD_REG_TN(T1, rt);
666: op_ldst(sc);
667: GEN_STORE_TN_REG(rt, T0);
668: opn = "sc";
669: break;
670: default:
671: MIPS_INVAL("load/store");
672: generate_exception(ctx, EXCP_RI);
673: return;
674: }
675: MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
676: }
677:
1.1.1.4 ! root 678: #ifdef MIPS_USES_FPU
! 679:
! 680: /* Load and store */
! 681: static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
! 682: int base, int16_t offset)
! 683: {
! 684: const unsigned char *opn = "unk";
! 685:
! 686: if (base == 0) {
! 687: GEN_LOAD_IMM_TN(T0, offset);
! 688: } else if (offset == 0) {
! 689: gen_op_load_gpr_T0(base);
! 690: } else {
! 691: gen_op_load_gpr_T0(base);
! 692: gen_op_set_T1(offset);
! 693: gen_op_add();
! 694: }
! 695: /* Don't do NOP if destination is zero: we must perform the actual
! 696: * memory access
! 697: */
! 698: switch (opc) {
! 699: case OPC_LWC1:
! 700: op_ldst(lwc1);
! 701: GEN_STORE_FTN_FREG(ft, WT0);
! 702: opn = "lwc1";
! 703: break;
! 704: case OPC_SWC1:
! 705: GEN_LOAD_FREG_FTN(WT0, ft);
! 706: op_ldst(swc1);
! 707: opn = "swc1";
! 708: break;
! 709: case OPC_LDC1:
! 710: op_ldst(ldc1);
! 711: GEN_STORE_FTN_FREG(ft, DT0);
! 712: opn = "ldc1";
! 713: break;
! 714: case OPC_SDC1:
! 715: GEN_LOAD_FREG_FTN(DT0, ft);
! 716: op_ldst(sdc1);
! 717: opn = "sdc1";
! 718: break;
! 719: default:
! 720: MIPS_INVAL("float load/store");
! 721: generate_exception(ctx, EXCP_CpU);
! 722: return;
! 723: }
! 724: MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
! 725: }
! 726: #endif
! 727:
1.1 root 728: /* Arithmetic with immediate operand */
729: static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
730: int rs, int16_t imm)
731: {
732: uint32_t uimm;
733: const unsigned char *opn = "unk";
734:
735: if (rt == 0 && opc != OPC_ADDI) {
736: /* if no destination, treat it as a NOP
737: * For addi, we must generate the overflow exception when needed.
738: */
739: MIPS_DEBUG("NOP");
740: return;
741: }
742: if (opc == OPC_ADDI || opc == OPC_ADDIU ||
743: opc == OPC_SLTI || opc == OPC_SLTIU)
744: uimm = (int32_t)imm; /* Sign extent to 32 bits */
745: else
746: uimm = (uint16_t)imm;
747: if (opc != OPC_LUI) {
748: GEN_LOAD_REG_TN(T0, rs);
749: GEN_LOAD_IMM_TN(T1, uimm);
750: } else {
751: uimm = uimm << 16;
752: GEN_LOAD_IMM_TN(T0, uimm);
753: }
754: switch (opc) {
755: case OPC_ADDI:
756: save_cpu_state(ctx, 1);
757: gen_op_addo();
758: opn = "addi";
759: break;
760: case OPC_ADDIU:
761: gen_op_add();
762: opn = "addiu";
763: break;
764: case OPC_SLTI:
765: gen_op_lt();
766: opn = "slti";
767: break;
768: case OPC_SLTIU:
769: gen_op_ltu();
770: opn = "sltiu";
771: break;
772: case OPC_ANDI:
773: gen_op_and();
774: opn = "andi";
775: break;
776: case OPC_ORI:
777: gen_op_or();
778: opn = "ori";
779: break;
780: case OPC_XORI:
781: gen_op_xor();
782: opn = "xori";
783: break;
784: case OPC_LUI:
785: opn = "lui";
786: break;
787: case OPC_SLL:
788: gen_op_sll();
789: opn = "sll";
790: break;
791: case OPC_SRA:
792: gen_op_sra();
793: opn = "sra";
794: break;
795: case OPC_SRL:
796: gen_op_srl();
797: opn = "srl";
798: break;
799: default:
800: MIPS_INVAL("imm arith");
801: generate_exception(ctx, EXCP_RI);
802: return;
803: }
804: GEN_STORE_TN_REG(rt, T0);
805: MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
806: }
807:
808: /* Arithmetic */
809: static void gen_arith (DisasContext *ctx, uint16_t opc,
810: int rd, int rs, int rt)
811: {
812: const unsigned char *opn = "unk";
813:
814: if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
815: /* if no destination, treat it as a NOP
816: * For add & sub, we must generate the overflow exception when needed.
817: */
818: MIPS_DEBUG("NOP");
819: return;
820: }
821: GEN_LOAD_REG_TN(T0, rs);
822: GEN_LOAD_REG_TN(T1, rt);
823: switch (opc) {
824: case OPC_ADD:
825: save_cpu_state(ctx, 1);
826: gen_op_addo();
827: opn = "add";
828: break;
829: case OPC_ADDU:
830: gen_op_add();
831: opn = "addu";
832: break;
833: case OPC_SUB:
834: save_cpu_state(ctx, 1);
835: gen_op_subo();
836: opn = "sub";
837: break;
838: case OPC_SUBU:
839: gen_op_sub();
840: opn = "subu";
841: break;
842: case OPC_SLT:
843: gen_op_lt();
844: opn = "slt";
845: break;
846: case OPC_SLTU:
847: gen_op_ltu();
848: opn = "sltu";
849: break;
850: case OPC_AND:
851: gen_op_and();
852: opn = "and";
853: break;
854: case OPC_NOR:
855: gen_op_nor();
856: opn = "nor";
857: break;
858: case OPC_OR:
859: gen_op_or();
860: opn = "or";
861: break;
862: case OPC_XOR:
863: gen_op_xor();
864: opn = "xor";
865: break;
866: case OPC_MUL:
867: gen_op_mul();
868: opn = "mul";
869: break;
870: case OPC_MOVN:
871: gen_op_movn(rd);
872: opn = "movn";
873: goto print;
874: case OPC_MOVZ:
875: gen_op_movz(rd);
876: opn = "movz";
877: goto print;
878: case OPC_SLLV:
879: gen_op_sllv();
880: opn = "sllv";
881: break;
882: case OPC_SRAV:
883: gen_op_srav();
884: opn = "srav";
885: break;
886: case OPC_SRLV:
887: gen_op_srlv();
888: opn = "srlv";
889: break;
890: default:
891: MIPS_INVAL("arith");
892: generate_exception(ctx, EXCP_RI);
893: return;
894: }
895: GEN_STORE_TN_REG(rd, T0);
896: print:
897: MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
898: }
899:
900: /* Arithmetic on HI/LO registers */
901: static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
902: {
903: const unsigned char *opn = "unk";
904:
905: if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
906: /* Treat as a NOP */
907: MIPS_DEBUG("NOP");
908: return;
909: }
910: switch (opc) {
911: case OPC_MFHI:
912: gen_op_load_HI();
913: GEN_STORE_TN_REG(reg, T0);
914: opn = "mfhi";
915: break;
916: case OPC_MFLO:
917: gen_op_load_LO();
918: GEN_STORE_TN_REG(reg, T0);
919: opn = "mflo";
920: break;
921: case OPC_MTHI:
922: GEN_LOAD_REG_TN(T0, reg);
923: gen_op_store_HI();
924: opn = "mthi";
925: break;
926: case OPC_MTLO:
927: GEN_LOAD_REG_TN(T0, reg);
928: gen_op_store_LO();
929: opn = "mtlo";
930: break;
931: default:
932: MIPS_INVAL("HILO");
933: generate_exception(ctx, EXCP_RI);
934: return;
935: }
936: MIPS_DEBUG("%s %s", opn, regnames[reg]);
937: }
938:
939: static void gen_muldiv (DisasContext *ctx, uint16_t opc,
940: int rs, int rt)
941: {
942: const unsigned char *opn = "unk";
943:
944: GEN_LOAD_REG_TN(T0, rs);
945: GEN_LOAD_REG_TN(T1, rt);
946: switch (opc) {
947: case OPC_DIV:
948: gen_op_div();
949: opn = "div";
950: break;
951: case OPC_DIVU:
952: gen_op_divu();
953: opn = "divu";
954: break;
955: case OPC_MULT:
956: gen_op_mult();
957: opn = "mult";
958: break;
959: case OPC_MULTU:
960: gen_op_multu();
961: opn = "multu";
962: break;
963: case OPC_MADD:
964: gen_op_madd();
965: opn = "madd";
966: break;
967: case OPC_MADDU:
968: gen_op_maddu();
969: opn = "maddu";
970: break;
971: case OPC_MSUB:
972: gen_op_msub();
973: opn = "msub";
974: break;
975: case OPC_MSUBU:
976: gen_op_msubu();
977: opn = "msubu";
978: break;
979: default:
980: MIPS_INVAL("mul/div");
981: generate_exception(ctx, EXCP_RI);
982: return;
983: }
984: MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
985: }
986:
987: static void gen_cl (DisasContext *ctx, uint16_t opc,
988: int rd, int rs)
989: {
990: const unsigned char *opn = "unk";
991: if (rd == 0) {
992: /* Treat as a NOP */
993: MIPS_DEBUG("NOP");
994: return;
995: }
996: GEN_LOAD_REG_TN(T0, rs);
997: switch (opc) {
998: case OPC_CLO:
999: /* CLO */
1000: gen_op_clo();
1001: opn = "clo";
1002: break;
1003: case OPC_CLZ:
1004: /* CLZ */
1005: gen_op_clz();
1006: opn = "clz";
1007: break;
1008: default:
1009: MIPS_INVAL("CLx");
1010: generate_exception(ctx, EXCP_RI);
1011: return;
1012: }
1013: gen_op_store_T0_gpr(rd);
1014: MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
1015: }
1016:
1017: /* Traps */
1018: static void gen_trap (DisasContext *ctx, uint16_t opc,
1019: int rs, int rt, int16_t imm)
1020: {
1021: int cond;
1022:
1023: cond = 0;
1024: /* Load needed operands */
1025: switch (opc) {
1026: case OPC_TEQ:
1027: case OPC_TGE:
1028: case OPC_TGEU:
1029: case OPC_TLT:
1030: case OPC_TLTU:
1031: case OPC_TNE:
1032: /* Compare two registers */
1033: if (rs != rt) {
1034: GEN_LOAD_REG_TN(T0, rs);
1035: GEN_LOAD_REG_TN(T1, rt);
1036: cond = 1;
1037: }
1038: case OPC_TEQI:
1039: case OPC_TGEI:
1040: case OPC_TGEIU:
1041: case OPC_TLTI:
1042: case OPC_TLTIU:
1043: case OPC_TNEI:
1044: /* Compare register to immediate */
1045: if (rs != 0 || imm != 0) {
1046: GEN_LOAD_REG_TN(T0, rs);
1047: GEN_LOAD_IMM_TN(T1, (int32_t)imm);
1048: cond = 1;
1049: }
1050: break;
1051: }
1052: if (cond == 0) {
1053: switch (opc) {
1054: case OPC_TEQ: /* rs == rs */
1055: case OPC_TEQI: /* r0 == 0 */
1056: case OPC_TGE: /* rs >= rs */
1057: case OPC_TGEI: /* r0 >= 0 */
1058: case OPC_TGEU: /* rs >= rs unsigned */
1059: case OPC_TGEIU: /* r0 >= 0 unsigned */
1060: /* Always trap */
1061: gen_op_set_T0(1);
1062: break;
1063: case OPC_TLT: /* rs < rs */
1064: case OPC_TLTI: /* r0 < 0 */
1065: case OPC_TLTU: /* rs < rs unsigned */
1066: case OPC_TLTIU: /* r0 < 0 unsigned */
1067: case OPC_TNE: /* rs != rs */
1068: case OPC_TNEI: /* r0 != 0 */
1069: /* Never trap: treat as NOP */
1070: return;
1071: default:
1072: MIPS_INVAL("TRAP");
1073: generate_exception(ctx, EXCP_RI);
1074: return;
1075: }
1076: } else {
1077: switch (opc) {
1078: case OPC_TEQ:
1079: case OPC_TEQI:
1080: gen_op_eq();
1081: break;
1082: case OPC_TGE:
1083: case OPC_TGEI:
1084: gen_op_ge();
1085: break;
1086: case OPC_TGEU:
1087: case OPC_TGEIU:
1088: gen_op_geu();
1089: break;
1090: case OPC_TLT:
1091: case OPC_TLTI:
1092: gen_op_lt();
1093: break;
1094: case OPC_TLTU:
1095: case OPC_TLTIU:
1096: gen_op_ltu();
1097: break;
1098: case OPC_TNE:
1099: case OPC_TNEI:
1100: gen_op_ne();
1101: break;
1102: default:
1103: MIPS_INVAL("TRAP");
1104: generate_exception(ctx, EXCP_RI);
1105: return;
1106: }
1107: }
1108: save_cpu_state(ctx, 1);
1109: gen_op_trap();
1110: ctx->bstate = BS_STOP;
1111: }
1112:
1.1.1.2 root 1113: static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
1114: {
1115: TranslationBlock *tb;
1116: tb = ctx->tb;
1117: if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1118: if (n == 0)
1119: gen_op_goto_tb0(TBPARAM(tb));
1120: else
1121: gen_op_goto_tb1(TBPARAM(tb));
1122: gen_op_save_pc(dest);
1123: gen_op_set_T0((long)tb + n);
1124: gen_op_exit_tb();
1125: } else {
1126: gen_op_save_pc(dest);
1127: gen_op_set_T0(0);
1128: gen_op_exit_tb();
1129: }
1130: }
1131:
1.1 root 1132: /* Branches (before delay slot) */
1133: static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
1134: int rs, int rt, int32_t offset)
1135: {
1136: target_ulong btarget;
1137: int blink, bcond;
1138:
1139: btarget = -1;
1140: blink = 0;
1141: bcond = 0;
1142: /* Load needed operands */
1143: switch (opc) {
1144: case OPC_BEQ:
1145: case OPC_BEQL:
1146: case OPC_BNE:
1147: case OPC_BNEL:
1148: /* Compare two registers */
1149: if (rs != rt) {
1150: GEN_LOAD_REG_TN(T0, rs);
1151: GEN_LOAD_REG_TN(T1, rt);
1152: bcond = 1;
1153: }
1154: btarget = ctx->pc + 4 + offset;
1155: break;
1156: case OPC_BGEZ:
1157: case OPC_BGEZAL:
1158: case OPC_BGEZALL:
1159: case OPC_BGEZL:
1160: case OPC_BGTZ:
1161: case OPC_BGTZL:
1162: case OPC_BLEZ:
1163: case OPC_BLEZL:
1164: case OPC_BLTZ:
1165: case OPC_BLTZAL:
1166: case OPC_BLTZALL:
1167: case OPC_BLTZL:
1168: /* Compare to zero */
1169: if (rs != 0) {
1170: gen_op_load_gpr_T0(rs);
1171: bcond = 1;
1172: }
1173: btarget = ctx->pc + 4 + offset;
1174: break;
1175: case OPC_J:
1176: case OPC_JAL:
1177: /* Jump to immediate */
1178: btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
1179: break;
1180: case OPC_JR:
1181: case OPC_JALR:
1182: /* Jump to register */
1183: if (offset != 0) {
1184: /* Only hint = 0 is valid */
1185: generate_exception(ctx, EXCP_RI);
1186: return;
1187: }
1188: GEN_LOAD_REG_TN(T2, rs);
1189: break;
1190: default:
1191: MIPS_INVAL("branch/jump");
1192: generate_exception(ctx, EXCP_RI);
1193: return;
1194: }
1195: if (bcond == 0) {
1196: /* No condition to be computed */
1197: switch (opc) {
1198: case OPC_BEQ: /* rx == rx */
1199: case OPC_BEQL: /* rx == rx likely */
1200: case OPC_BGEZ: /* 0 >= 0 */
1201: case OPC_BGEZL: /* 0 >= 0 likely */
1202: case OPC_BLEZ: /* 0 <= 0 */
1203: case OPC_BLEZL: /* 0 <= 0 likely */
1204: /* Always take */
1.1.1.2 root 1205: ctx->hflags |= MIPS_HFLAG_B;
1.1 root 1206: MIPS_DEBUG("balways");
1207: break;
1208: case OPC_BGEZAL: /* 0 >= 0 */
1209: case OPC_BGEZALL: /* 0 >= 0 likely */
1210: /* Always take and link */
1211: blink = 31;
1.1.1.2 root 1212: ctx->hflags |= MIPS_HFLAG_B;
1.1 root 1213: MIPS_DEBUG("balways and link");
1214: break;
1215: case OPC_BNE: /* rx != rx */
1216: case OPC_BGTZ: /* 0 > 0 */
1217: case OPC_BLTZ: /* 0 < 0 */
1218: /* Treated as NOP */
1219: MIPS_DEBUG("bnever (NOP)");
1220: return;
1.1.1.2 root 1221: case OPC_BLTZAL: /* 0 < 0 */
1222: gen_op_set_T0(ctx->pc + 8);
1223: gen_op_store_T0_gpr(31);
1224: return;
1225: case OPC_BLTZALL: /* 0 < 0 likely */
1226: gen_op_set_T0(ctx->pc + 8);
1227: gen_op_store_T0_gpr(31);
1228: gen_goto_tb(ctx, 0, ctx->pc + 4);
1229: return;
1.1 root 1230: case OPC_BNEL: /* rx != rx likely */
1231: case OPC_BGTZL: /* 0 > 0 likely */
1232: case OPC_BLTZL: /* 0 < 0 likely */
1233: /* Skip the instruction in the delay slot */
1234: MIPS_DEBUG("bnever and skip");
1.1.1.2 root 1235: gen_goto_tb(ctx, 0, ctx->pc + 4);
1.1 root 1236: return;
1237: case OPC_J:
1.1.1.2 root 1238: ctx->hflags |= MIPS_HFLAG_B;
1.1 root 1239: MIPS_DEBUG("j %08x", btarget);
1240: break;
1241: case OPC_JAL:
1242: blink = 31;
1.1.1.2 root 1243: ctx->hflags |= MIPS_HFLAG_B;
1.1 root 1244: MIPS_DEBUG("jal %08x", btarget);
1245: break;
1246: case OPC_JR:
1.1.1.2 root 1247: ctx->hflags |= MIPS_HFLAG_BR;
1.1 root 1248: MIPS_DEBUG("jr %s", regnames[rs]);
1249: break;
1250: case OPC_JALR:
1251: blink = rt;
1.1.1.2 root 1252: ctx->hflags |= MIPS_HFLAG_BR;
1.1 root 1253: MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1254: break;
1255: default:
1256: MIPS_INVAL("branch/jump");
1257: generate_exception(ctx, EXCP_RI);
1258: return;
1259: }
1260: } else {
1261: switch (opc) {
1262: case OPC_BEQ:
1263: gen_op_eq();
1264: MIPS_DEBUG("beq %s, %s, %08x",
1265: regnames[rs], regnames[rt], btarget);
1266: goto not_likely;
1267: case OPC_BEQL:
1268: gen_op_eq();
1269: MIPS_DEBUG("beql %s, %s, %08x",
1270: regnames[rs], regnames[rt], btarget);
1271: goto likely;
1272: case OPC_BNE:
1273: gen_op_ne();
1274: MIPS_DEBUG("bne %s, %s, %08x",
1275: regnames[rs], regnames[rt], btarget);
1276: goto not_likely;
1277: case OPC_BNEL:
1278: gen_op_ne();
1279: MIPS_DEBUG("bnel %s, %s, %08x",
1280: regnames[rs], regnames[rt], btarget);
1281: goto likely;
1282: case OPC_BGEZ:
1283: gen_op_gez();
1284: MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1285: goto not_likely;
1286: case OPC_BGEZL:
1287: gen_op_gez();
1288: MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1289: goto likely;
1290: case OPC_BGEZAL:
1291: gen_op_gez();
1292: MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1293: blink = 31;
1294: goto not_likely;
1295: case OPC_BGEZALL:
1296: gen_op_gez();
1297: blink = 31;
1298: MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1299: goto likely;
1300: case OPC_BGTZ:
1301: gen_op_gtz();
1302: MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1303: goto not_likely;
1304: case OPC_BGTZL:
1305: gen_op_gtz();
1306: MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1307: goto likely;
1308: case OPC_BLEZ:
1309: gen_op_lez();
1310: MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1311: goto not_likely;
1312: case OPC_BLEZL:
1313: gen_op_lez();
1314: MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1315: goto likely;
1316: case OPC_BLTZ:
1317: gen_op_ltz();
1318: MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1319: goto not_likely;
1320: case OPC_BLTZL:
1321: gen_op_ltz();
1322: MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1323: goto likely;
1324: case OPC_BLTZAL:
1325: gen_op_ltz();
1326: blink = 31;
1327: MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1328: not_likely:
1.1.1.2 root 1329: ctx->hflags |= MIPS_HFLAG_BC;
1.1 root 1330: break;
1331: case OPC_BLTZALL:
1332: gen_op_ltz();
1333: blink = 31;
1334: MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1335: likely:
1.1.1.2 root 1336: ctx->hflags |= MIPS_HFLAG_BL;
1.1 root 1337: break;
1338: }
1339: gen_op_set_bcond();
1340: }
1341: MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1342: blink, ctx->hflags, btarget);
1343: ctx->btarget = btarget;
1344: if (blink > 0) {
1345: gen_op_set_T0(ctx->pc + 8);
1346: gen_op_store_T0_gpr(blink);
1347: }
1348: return;
1349: }
1350:
1351: /* CP0 (MMU and control) */
1352: static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1353: {
1354: const unsigned char *opn = "unk";
1355:
1356: if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1.1.1.3 root 1357: (ctx->hflags & MIPS_HFLAG_UM) &&
1.1 root 1358: !(ctx->hflags & MIPS_HFLAG_ERL) &&
1359: !(ctx->hflags & MIPS_HFLAG_EXL)) {
1360: if (loglevel & CPU_LOG_TB_IN_ASM) {
1361: fprintf(logfile, "CP0 is not usable\n");
1362: }
1.1.1.2 root 1363: generate_exception_err (ctx, EXCP_CpU, 0);
1.1 root 1364: return;
1365: }
1.1.1.4 ! root 1366:
1.1 root 1367: switch (opc) {
1368: case OPC_MFC0:
1369: if (rt == 0) {
1370: /* Treat as NOP */
1371: return;
1372: }
1373: gen_op_mfc0(rd, ctx->opcode & 0x7);
1374: gen_op_store_T0_gpr(rt);
1375: opn = "mfc0";
1376: break;
1377: case OPC_MTC0:
1378: /* If we get an exception, we want to restart at next instruction */
1379: ctx->pc += 4;
1380: save_cpu_state(ctx, 1);
1381: ctx->pc -= 4;
1382: GEN_LOAD_REG_TN(T0, rt);
1383: gen_op_mtc0(rd, ctx->opcode & 0x7);
1384: /* Stop translation as we may have switched the execution mode */
1385: ctx->bstate = BS_STOP;
1386: opn = "mtc0";
1387: break;
1388: #if defined(MIPS_USES_R4K_TLB)
1389: case OPC_TLBWI:
1390: gen_op_tlbwi();
1391: opn = "tlbwi";
1392: break;
1393: case OPC_TLBWR:
1394: gen_op_tlbwr();
1395: opn = "tlbwr";
1396: break;
1397: case OPC_TLBP:
1398: gen_op_tlbp();
1399: opn = "tlbp";
1400: break;
1401: case OPC_TLBR:
1402: gen_op_tlbr();
1403: opn = "tlbr";
1404: break;
1405: #endif
1406: case OPC_ERET:
1407: opn = "eret";
1408: save_cpu_state(ctx, 0);
1409: gen_op_eret();
1410: ctx->bstate = BS_EXCP;
1411: break;
1412: case OPC_DERET:
1413: opn = "deret";
1414: if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1415: generate_exception(ctx, EXCP_RI);
1416: } else {
1417: save_cpu_state(ctx, 0);
1418: gen_op_deret();
1419: ctx->bstate = BS_EXCP;
1420: }
1421: break;
1.1.1.2 root 1422: case OPC_WAIT:
1423: opn = "wait";
1424: /* If we get an exception, we want to restart at next instruction */
1425: ctx->pc += 4;
1426: save_cpu_state(ctx, 1);
1427: ctx->pc -= 4;
1428: gen_op_wait();
1429: ctx->bstate = BS_EXCP;
1430: break;
1.1 root 1431: default:
1432: if (loglevel & CPU_LOG_TB_IN_ASM) {
1433: fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1434: ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1435: ((ctx->opcode >> 16) & 0x1F));
1436: }
1437: generate_exception(ctx, EXCP_RI);
1438: return;
1439: }
1440: MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1441: }
1442:
1.1.1.4 ! root 1443: #ifdef MIPS_USES_FPU
! 1444: /* CP1 Branches (before delay slot) */
! 1445: static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
! 1446: int32_t offset)
! 1447: {
! 1448: target_ulong btarget;
! 1449:
! 1450: btarget = ctx->pc + 4 + offset;
! 1451:
! 1452: switch (cond) {
! 1453: case 0x0000: /* bc1f */
! 1454: gen_op_bc1f();
! 1455: MIPS_DEBUG("bc1f %08x", btarget);
! 1456: goto not_likely;
! 1457: case 0x0002: /* bc1fl */
! 1458: gen_op_bc1f();
! 1459: MIPS_DEBUG("bc1fl %08x", btarget);
! 1460: goto likely;
! 1461: case 0x0001: /* bc1t */
! 1462: gen_op_bc1t();
! 1463: MIPS_DEBUG("bc1t %08x", btarget);
! 1464: not_likely:
! 1465: ctx->hflags |= MIPS_HFLAG_BC;
! 1466: break;
! 1467: case 0x0003: /* bc1tl */
! 1468: gen_op_bc1t();
! 1469: MIPS_DEBUG("bc1tl %08x", btarget);
! 1470: likely:
! 1471: ctx->hflags |= MIPS_HFLAG_BL;
! 1472: break;
! 1473: default:
! 1474: MIPS_INVAL("cp1 branch/jump");
! 1475: generate_exception(ctx, EXCP_RI);
! 1476: return;
! 1477: }
! 1478: gen_op_set_bcond();
! 1479:
! 1480: MIPS_DEBUG("enter ds: cond %02x target %08x",
! 1481: ctx->hflags, btarget);
! 1482: ctx->btarget = btarget;
! 1483:
! 1484: return;
! 1485: }
! 1486:
1.1 root 1487: /* Coprocessor 1 (FPU) */
1.1.1.4 ! root 1488: static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
! 1489: {
! 1490: const unsigned char *opn = "unk";
! 1491:
! 1492: switch (opc) {
! 1493: case OPC_MFC1:
! 1494: GEN_LOAD_FREG_FTN(WT0, fs);
! 1495: gen_op_mfc1();
! 1496: GEN_STORE_TN_REG(rt, T0);
! 1497: opn = "mfc1";
! 1498: break;
! 1499: case OPC_MTC1:
! 1500: GEN_LOAD_REG_TN(T0, rt);
! 1501: gen_op_mtc1();
! 1502: GEN_STORE_FTN_FREG(fs, WT0);
! 1503: opn = "mtc1";
! 1504: break;
! 1505: case OPC_CFC1:
! 1506: if (fs != 0 && fs != 31) {
! 1507: MIPS_INVAL("cfc1 freg");
! 1508: generate_exception(ctx, EXCP_RI);
! 1509: return;
! 1510: }
! 1511: GEN_LOAD_IMM_TN(T1, fs);
! 1512: gen_op_cfc1();
! 1513: GEN_STORE_TN_REG(rt, T0);
! 1514: opn = "cfc1";
! 1515: break;
! 1516: case OPC_CTC1:
! 1517: if (fs != 0 && fs != 31) {
! 1518: MIPS_INVAL("ctc1 freg");
! 1519: generate_exception(ctx, EXCP_RI);
! 1520: return;
! 1521: }
! 1522: GEN_LOAD_IMM_TN(T1, fs);
! 1523: GEN_LOAD_REG_TN(T0, rt);
! 1524: gen_op_ctc1();
! 1525: opn = "ctc1";
! 1526: break;
! 1527: default:
! 1528: if (loglevel & CPU_LOG_TB_IN_ASM) {
! 1529: fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
! 1530: ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
! 1531: ((ctx->opcode >> 16) & 0x1F));
! 1532: }
! 1533: generate_exception(ctx, EXCP_RI);
! 1534: return;
! 1535: }
! 1536: MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
! 1537: }
! 1538:
! 1539: /* verify if floating point register is valid; an operation is not defined
! 1540: * if bit 0 of any register specification is set and the FR bit in the
! 1541: * Status register equals zero, since the register numbers specify an
! 1542: * even-odd pair of adjacent coprocessor general registers. When the FR bit
! 1543: * in the Status register equals one, both even and odd register numbers
! 1544: * are valid.
! 1545: *
! 1546: * Multiple float registers can be checked by calling
! 1547: * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
! 1548: */
! 1549: #define CHECK_FR(ctx, freg) do { \
! 1550: if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
! 1551: generate_exception(ctx, EXCP_RI); \
! 1552: return; \
! 1553: } \
! 1554: } while(0)
! 1555:
! 1556: #define FOP(func, fmt) (((fmt) << 21) | (func))
! 1557:
! 1558: static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
! 1559: {
! 1560: const unsigned char *opn = "unk";
! 1561: const char *condnames[] = {
! 1562: "c.f",
! 1563: "c.un",
! 1564: "c.eq",
! 1565: "c.ueq",
! 1566: "c.olt",
! 1567: "c.ult",
! 1568: "c.ole",
! 1569: "c.ule",
! 1570: "c.sf",
! 1571: "c.ngle",
! 1572: "c.seq",
! 1573: "c.ngl",
! 1574: "c.lt",
! 1575: "c.nge",
! 1576: "c.le",
! 1577: "c.ngt",
! 1578: };
! 1579: int binary = 0;
! 1580:
! 1581: switch (ctx->opcode & FOP(0x3f, 0x1f)) {
! 1582: case FOP(0, 17):
! 1583: CHECK_FR(ctx, fs | ft | fd);
! 1584: GEN_LOAD_FREG_FTN(DT0, fs);
! 1585: GEN_LOAD_FREG_FTN(DT1, ft);
! 1586: gen_op_float_add_d();
! 1587: GEN_STORE_FTN_FREG(fd, DT2);
! 1588: opn = "add.d";
! 1589: binary = 1;
! 1590: break;
! 1591: case FOP(1, 17):
! 1592: CHECK_FR(ctx, fs | ft | fd);
! 1593: GEN_LOAD_FREG_FTN(DT0, fs);
! 1594: GEN_LOAD_FREG_FTN(DT1, ft);
! 1595: gen_op_float_sub_d();
! 1596: GEN_STORE_FTN_FREG(fd, DT2);
! 1597: opn = "sub.d";
! 1598: binary = 1;
! 1599: break;
! 1600: case FOP(2, 17):
! 1601: CHECK_FR(ctx, fs | ft | fd);
! 1602: GEN_LOAD_FREG_FTN(DT0, fs);
! 1603: GEN_LOAD_FREG_FTN(DT1, ft);
! 1604: gen_op_float_mul_d();
! 1605: GEN_STORE_FTN_FREG(fd, DT2);
! 1606: opn = "mul.d";
! 1607: binary = 1;
! 1608: break;
! 1609: case FOP(3, 17):
! 1610: CHECK_FR(ctx, fs | ft | fd);
! 1611: GEN_LOAD_FREG_FTN(DT0, fs);
! 1612: GEN_LOAD_FREG_FTN(DT1, ft);
! 1613: gen_op_float_div_d();
! 1614: GEN_STORE_FTN_FREG(fd, DT2);
! 1615: opn = "div.d";
! 1616: binary = 1;
! 1617: break;
! 1618: case FOP(4, 17):
! 1619: CHECK_FR(ctx, fs | fd);
! 1620: GEN_LOAD_FREG_FTN(DT0, fs);
! 1621: gen_op_float_sqrt_d();
! 1622: GEN_STORE_FTN_FREG(fd, DT2);
! 1623: opn = "sqrt.d";
! 1624: break;
! 1625: case FOP(5, 17):
! 1626: CHECK_FR(ctx, fs | fd);
! 1627: GEN_LOAD_FREG_FTN(DT0, fs);
! 1628: gen_op_float_abs_d();
! 1629: GEN_STORE_FTN_FREG(fd, DT2);
! 1630: opn = "abs.d";
! 1631: break;
! 1632: case FOP(6, 17):
! 1633: CHECK_FR(ctx, fs | fd);
! 1634: GEN_LOAD_FREG_FTN(DT0, fs);
! 1635: gen_op_float_mov_d();
! 1636: GEN_STORE_FTN_FREG(fd, DT2);
! 1637: opn = "mov.d";
! 1638: break;
! 1639: case FOP(7, 17):
! 1640: CHECK_FR(ctx, fs | fd);
! 1641: GEN_LOAD_FREG_FTN(DT0, fs);
! 1642: gen_op_float_chs_d();
! 1643: GEN_STORE_FTN_FREG(fd, DT2);
! 1644: opn = "neg.d";
! 1645: break;
! 1646: /* 8 - round.l */
! 1647: /* 9 - trunc.l */
! 1648: /* 10 - ceil.l */
! 1649: /* 11 - floor.l */
! 1650: case FOP(12, 17):
! 1651: CHECK_FR(ctx, fs | fd);
! 1652: GEN_LOAD_FREG_FTN(DT0, fs);
! 1653: gen_op_float_roundw_d();
! 1654: GEN_STORE_FTN_FREG(fd, WT2);
! 1655: opn = "round.w.d";
! 1656: break;
! 1657: case FOP(13, 17):
! 1658: CHECK_FR(ctx, fs | fd);
! 1659: GEN_LOAD_FREG_FTN(DT0, fs);
! 1660: gen_op_float_truncw_d();
! 1661: GEN_STORE_FTN_FREG(fd, WT2);
! 1662: opn = "trunc.w.d";
! 1663: break;
! 1664: case FOP(14, 17):
! 1665: CHECK_FR(ctx, fs | fd);
! 1666: GEN_LOAD_FREG_FTN(DT0, fs);
! 1667: gen_op_float_ceilw_d();
! 1668: GEN_STORE_FTN_FREG(fd, WT2);
! 1669: opn = "ceil.w.d";
! 1670: break;
! 1671: case FOP(15, 17):
! 1672: CHECK_FR(ctx, fs | fd);
! 1673: GEN_LOAD_FREG_FTN(DT0, fs);
! 1674: gen_op_float_floorw_d();
! 1675: GEN_STORE_FTN_FREG(fd, WT2);
! 1676: opn = "ceil.w.d";
! 1677: break;
! 1678: case FOP(33, 20): /* cvt.d.w */
! 1679: CHECK_FR(ctx, fs | fd);
! 1680: GEN_LOAD_FREG_FTN(WT0, fs);
! 1681: gen_op_float_cvtd_w();
! 1682: GEN_STORE_FTN_FREG(fd, DT2);
! 1683: opn = "cvt.d.w";
! 1684: break;
! 1685: case FOP(48, 17):
! 1686: case FOP(49, 17):
! 1687: case FOP(50, 17):
! 1688: case FOP(51, 17):
! 1689: case FOP(52, 17):
! 1690: case FOP(53, 17):
! 1691: case FOP(54, 17):
! 1692: case FOP(55, 17):
! 1693: case FOP(56, 17):
! 1694: case FOP(57, 17):
! 1695: case FOP(58, 17):
! 1696: case FOP(59, 17):
! 1697: case FOP(60, 17):
! 1698: case FOP(61, 17):
! 1699: case FOP(62, 17):
! 1700: case FOP(63, 17):
! 1701: CHECK_FR(ctx, fs | ft);
! 1702: GEN_LOAD_FREG_FTN(DT0, fs);
! 1703: GEN_LOAD_FREG_FTN(DT1, ft);
! 1704: gen_cmp_d(func-48);
! 1705: opn = condnames[func-48];
! 1706: break;
! 1707: case FOP(0, 16):
! 1708: CHECK_FR(ctx, fs | ft | fd);
! 1709: GEN_LOAD_FREG_FTN(WT0, fs);
! 1710: GEN_LOAD_FREG_FTN(WT1, ft);
! 1711: gen_op_float_add_s();
! 1712: GEN_STORE_FTN_FREG(fd, WT2);
! 1713: opn = "add.s";
! 1714: binary = 1;
! 1715: break;
! 1716: case FOP(1, 16):
! 1717: CHECK_FR(ctx, fs | ft | fd);
! 1718: GEN_LOAD_FREG_FTN(WT0, fs);
! 1719: GEN_LOAD_FREG_FTN(WT1, ft);
! 1720: gen_op_float_sub_s();
! 1721: GEN_STORE_FTN_FREG(fd, WT2);
! 1722: opn = "sub.s";
! 1723: binary = 1;
! 1724: break;
! 1725: case FOP(2, 16):
! 1726: CHECK_FR(ctx, fs | ft | fd);
! 1727: GEN_LOAD_FREG_FTN(WT0, fs);
! 1728: GEN_LOAD_FREG_FTN(WT1, ft);
! 1729: gen_op_float_mul_s();
! 1730: GEN_STORE_FTN_FREG(fd, WT2);
! 1731: opn = "mul.s";
! 1732: binary = 1;
! 1733: break;
! 1734: case FOP(3, 16):
! 1735: CHECK_FR(ctx, fs | ft | fd);
! 1736: GEN_LOAD_FREG_FTN(WT0, fs);
! 1737: GEN_LOAD_FREG_FTN(WT1, ft);
! 1738: gen_op_float_div_s();
! 1739: GEN_STORE_FTN_FREG(fd, WT2);
! 1740: opn = "div.s";
! 1741: binary = 1;
! 1742: break;
! 1743: case FOP(4, 16):
! 1744: CHECK_FR(ctx, fs | fd);
! 1745: GEN_LOAD_FREG_FTN(WT0, fs);
! 1746: gen_op_float_sqrt_s();
! 1747: GEN_STORE_FTN_FREG(fd, WT2);
! 1748: opn = "sqrt.s";
! 1749: break;
! 1750: case FOP(5, 16):
! 1751: CHECK_FR(ctx, fs | fd);
! 1752: GEN_LOAD_FREG_FTN(WT0, fs);
! 1753: gen_op_float_abs_s();
! 1754: GEN_STORE_FTN_FREG(fd, WT2);
! 1755: opn = "abs.s";
! 1756: break;
! 1757: case FOP(6, 16):
! 1758: CHECK_FR(ctx, fs | fd);
! 1759: GEN_LOAD_FREG_FTN(WT0, fs);
! 1760: gen_op_float_mov_s();
! 1761: GEN_STORE_FTN_FREG(fd, WT2);
! 1762: opn = "mov.s";
! 1763: break;
! 1764: case FOP(7, 16):
! 1765: CHECK_FR(ctx, fs | fd);
! 1766: GEN_LOAD_FREG_FTN(WT0, fs);
! 1767: gen_op_float_chs_s();
! 1768: GEN_STORE_FTN_FREG(fd, WT2);
! 1769: opn = "neg.s";
! 1770: break;
! 1771: case FOP(12, 16):
! 1772: CHECK_FR(ctx, fs | fd);
! 1773: GEN_LOAD_FREG_FTN(WT0, fs);
! 1774: gen_op_float_roundw_s();
! 1775: GEN_STORE_FTN_FREG(fd, WT2);
! 1776: opn = "round.w.s";
! 1777: break;
! 1778: case FOP(13, 16):
! 1779: CHECK_FR(ctx, fs | fd);
! 1780: GEN_LOAD_FREG_FTN(WT0, fs);
! 1781: gen_op_float_truncw_s();
! 1782: GEN_STORE_FTN_FREG(fd, WT2);
! 1783: opn = "trunc.w.s";
! 1784: break;
! 1785: case FOP(32, 20): /* cvt.s.w */
! 1786: CHECK_FR(ctx, fs | fd);
! 1787: GEN_LOAD_FREG_FTN(WT0, fs);
! 1788: gen_op_float_cvts_w();
! 1789: GEN_STORE_FTN_FREG(fd, WT2);
! 1790: opn = "cvt.s.w";
! 1791: break;
! 1792: case FOP(36, 16): /* cvt.w.s */
! 1793: CHECK_FR(ctx, fs | fd);
! 1794: GEN_LOAD_FREG_FTN(WT0, fs);
! 1795: gen_op_float_cvtw_s();
! 1796: GEN_STORE_FTN_FREG(fd, WT2);
! 1797: opn = "cvt.w.s";
! 1798: break;
! 1799: case FOP(36, 17): /* cvt.w.d */
! 1800: CHECK_FR(ctx, fs | fd);
! 1801: GEN_LOAD_FREG_FTN(WT0, fs);
! 1802: gen_op_float_cvtw_d();
! 1803: GEN_STORE_FTN_FREG(fd, WT2);
! 1804: opn = "cvt.w.d";
! 1805: break;
! 1806: case FOP(48, 16):
! 1807: case FOP(49, 16):
! 1808: case FOP(50, 16):
! 1809: case FOP(51, 16):
! 1810: case FOP(52, 16):
! 1811: case FOP(53, 16):
! 1812: case FOP(54, 16):
! 1813: case FOP(55, 16):
! 1814: case FOP(56, 16):
! 1815: case FOP(57, 16):
! 1816: case FOP(58, 16):
! 1817: case FOP(59, 16):
! 1818: case FOP(60, 16):
! 1819: case FOP(61, 16):
! 1820: case FOP(62, 16):
! 1821: case FOP(63, 16):
! 1822: CHECK_FR(ctx, fs | ft);
! 1823: GEN_LOAD_FREG_FTN(WT0, fs);
! 1824: GEN_LOAD_FREG_FTN(WT1, ft);
! 1825: gen_cmp_s(func-48);
! 1826: opn = condnames[func-48];
! 1827: break;
! 1828: default:
! 1829: if (loglevel & CPU_LOG_TB_IN_ASM) {
! 1830: fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
! 1831: ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
! 1832: ((ctx->opcode >> 16) & 0x1F));
! 1833: }
! 1834: generate_exception(ctx, EXCP_RI);
! 1835: return;
! 1836: }
! 1837: if (binary)
! 1838: MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
! 1839: else
! 1840: MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
! 1841: }
! 1842: #endif
1.1 root 1843:
1844: /* ISA extensions */
1845: /* MIPS16 extension to MIPS32 */
1846: /* SmartMIPS extension to MIPS32 */
1847:
1848: #ifdef TARGET_MIPS64
1849: static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1850: {
1851: if (func == 0x02 && rd == 0) {
1852: /* NOP */
1853: return;
1854: }
1855: if (rs == 0 || rt == 0) {
1856: gen_op_reset_T0();
1857: gen_op_save64();
1858: } else {
1859: gen_op_load_gpr_T0(rs);
1860: gen_op_load_gpr_T1(rt);
1861: gen_op_save64();
1862: if (func & 0x01)
1863: gen_op_mul64u();
1864: else
1865: gen_op_mul64s();
1866: }
1867: if (func & 0x02)
1868: gen_op_add64();
1869: else
1870: gen_op_sub64();
1871: }
1872:
1873: /* Coprocessor 3 (FPU) */
1874:
1875: /* MDMX extension to MIPS64 */
1876: /* MIPS-3D extension to MIPS64 */
1877:
1878: #endif
1879:
1.1.1.2 root 1880: static void gen_blikely(DisasContext *ctx)
1881: {
1882: int l1;
1883: l1 = gen_new_label();
1884: gen_op_jnz_T2(l1);
1885: gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
1886: gen_goto_tb(ctx, 1, ctx->pc + 4);
1887: gen_set_label(l1);
1888: }
1889:
1.1 root 1890: static void decode_opc (DisasContext *ctx)
1891: {
1892: int32_t offset;
1893: int rs, rt, rd, sa;
1894: uint16_t op, op1;
1895: int16_t imm;
1896:
1.1.1.4 ! root 1897: /* make sure instructions are on a word boundary */
! 1898: if (ctx->pc & 0x3) {
! 1899: generate_exception(ctx, EXCP_AdEL);
! 1900: return;
! 1901: }
! 1902:
1.1.1.2 root 1903: if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
1.1 root 1904: /* Handle blikely not taken case */
1905: MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1.1.1.2 root 1906: gen_blikely(ctx);
1.1 root 1907: }
1908: op = ctx->opcode >> 26;
1909: rs = ((ctx->opcode >> 21) & 0x1F);
1910: rt = ((ctx->opcode >> 16) & 0x1F);
1911: rd = ((ctx->opcode >> 11) & 0x1F);
1912: sa = ((ctx->opcode >> 6) & 0x1F);
1913: imm = (int16_t)ctx->opcode;
1914: switch (op) {
1915: case 0x00: /* Special opcode */
1916: op1 = ctx->opcode & 0x3F;
1917: switch (op1) {
1918: case 0x00: /* Arithmetic with immediate */
1919: case 0x02 ... 0x03:
1920: gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1921: break;
1922: case 0x04: /* Arithmetic */
1923: case 0x06 ... 0x07:
1924: case 0x0A ... 0x0B:
1925: case 0x20 ... 0x27:
1926: case 0x2A ... 0x2B:
1927: gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1928: break;
1929: case 0x18 ... 0x1B: /* MULT / DIV */
1930: gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1931: break;
1932: case 0x08 ... 0x09: /* Jumps */
1933: gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1934: return;
1935: case 0x30 ... 0x34: /* Traps */
1936: case 0x36:
1937: gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1938: break;
1939: case 0x10: /* Move from HI/LO */
1940: case 0x12:
1941: gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1942: break;
1943: case 0x11:
1944: case 0x13: /* Move to HI/LO */
1945: gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1946: break;
1947: case 0x0C: /* SYSCALL */
1948: generate_exception(ctx, EXCP_SYSCALL);
1949: break;
1950: case 0x0D: /* BREAK */
1951: generate_exception(ctx, EXCP_BREAK);
1952: break;
1953: case 0x0F: /* SYNC */
1954: /* Treat as a noop */
1955: break;
1956: case 0x05: /* Pmon entry point */
1957: gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1958: break;
1.1.1.2 root 1959:
1.1 root 1960: case 0x01: /* MOVCI */
1.1.1.2 root 1961: #if defined (MIPS_HAS_MOVCI)
1962: /* XXX */
1963: #else
1964: /* Not implemented */
1965: generate_exception_err (ctx, EXCP_CpU, 1);
1.1 root 1966: #endif
1.1.1.2 root 1967: break;
1968:
1.1 root 1969: #if defined (TARGET_MIPS64)
1970: case 0x14: /* MIPS64 specific opcodes */
1971: case 0x16:
1972: case 0x17:
1973: case 0x1C ... 0x1F:
1974: case 0x2C ... 0x2F:
1975: case 0x37:
1976: case 0x39 ... 0x3B:
1977: case 0x3E ... 0x3F:
1978: #endif
1979: default: /* Invalid */
1980: MIPS_INVAL("special");
1981: generate_exception(ctx, EXCP_RI);
1982: break;
1983: }
1984: break;
1985: case 0x1C: /* Special2 opcode */
1986: op1 = ctx->opcode & 0x3F;
1987: switch (op1) {
1988: #if defined (MIPS_USES_R4K_EXT)
1989: /* Those instructions are not part of MIPS32 core */
1990: case 0x00 ... 0x01: /* Multiply and add/sub */
1991: case 0x04 ... 0x05:
1992: gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1993: break;
1994: case 0x02: /* MUL */
1995: gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1996: break;
1997: case 0x20 ... 0x21: /* CLO / CLZ */
1998: gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1999: break;
2000: #endif
2001: case 0x3F: /* SDBBP */
2002: /* XXX: not clear which exception should be raised
2003: * when in debug mode...
2004: */
2005: if (!(ctx->hflags & MIPS_HFLAG_DM)) {
2006: generate_exception(ctx, EXCP_DBp);
2007: } else {
2008: generate_exception(ctx, EXCP_DBp);
2009: }
2010: /* Treat as a noop */
2011: break;
2012: default: /* Invalid */
2013: MIPS_INVAL("special2");
2014: generate_exception(ctx, EXCP_RI);
2015: break;
2016: }
2017: break;
2018: case 0x01: /* B REGIMM opcode */
2019: op1 = ((ctx->opcode >> 16) & 0x1F);
2020: switch (op1) {
2021: case 0x00 ... 0x03: /* REGIMM branches */
2022: case 0x10 ... 0x13:
2023: gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
2024: return;
2025: case 0x08 ... 0x0C: /* Traps */
2026: case 0x0E:
2027: gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
2028: break;
2029: default: /* Invalid */
2030: MIPS_INVAL("REGIMM");
2031: generate_exception(ctx, EXCP_RI);
2032: break;
2033: }
2034: break;
2035: case 0x10: /* CP0 opcode */
2036: op1 = ((ctx->opcode >> 21) & 0x1F);
2037: switch (op1) {
2038: case 0x00:
2039: case 0x04:
2040: gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
2041: break;
2042: default:
1.1.1.2 root 2043: gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
1.1 root 2044: break;
2045: }
2046: break;
2047: case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
2048: gen_arith_imm(ctx, op, rt, rs, imm);
2049: break;
2050: case 0x02 ... 0x03: /* Jump */
2051: offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
2052: gen_compute_branch(ctx, op, rs, rt, offset);
2053: return;
2054: case 0x04 ... 0x07: /* Branch */
2055: case 0x14 ... 0x17:
2056: gen_compute_branch(ctx, op, rs, rt, imm << 2);
2057: return;
1.1.1.4 ! root 2058: case 0x20 ... 0x2E: /* Load and stores */
1.1 root 2059: case 0x30:
2060: case 0x38:
2061: gen_ldst(ctx, op, rt, rs, imm);
2062: break;
2063: case 0x2F: /* Cache operation */
2064: /* Treat as a noop */
2065: break;
2066: case 0x33: /* Prefetch */
2067: /* Treat as a noop */
2068: break;
2069: case 0x3F: /* HACK */
2070: break;
1.1.1.2 root 2071:
2072: /* Floating point. */
2073: case 0x31: /* LWC1 */
2074: case 0x35: /* LDC1 */
2075: case 0x39: /* SWC1 */
2076: case 0x3D: /* SDC1 */
1.1.1.4 ! root 2077: #if defined(MIPS_USES_FPU)
! 2078: gen_op_cp1_enabled();
! 2079: gen_flt_ldst(ctx, op, rt, rs, imm);
! 2080: #else
! 2081: generate_exception_err(ctx, EXCP_CpU, 1);
! 2082: #endif
! 2083: break;
! 2084:
1.1.1.2 root 2085: case 0x11: /* CP1 opcode */
1.1 root 2086: #if defined(MIPS_USES_FPU)
1.1.1.4 ! root 2087: gen_op_cp1_enabled();
! 2088: op1 = ((ctx->opcode >> 21) & 0x1F);
! 2089: switch (op1) {
! 2090: case 0x00: /* mfc1 */
! 2091: case 0x02: /* cfc1 */
! 2092: case 0x04: /* mtc1 */
! 2093: case 0x06: /* ctc1 */
! 2094: gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
! 2095: break;
! 2096: case 0x08: /* bc */
! 2097: gen_compute_branch1(ctx, rt, imm << 2);
! 2098: return;
! 2099: case 0x10: /* 16: fmt=single fp */
! 2100: case 0x11: /* 17: fmt=double fp */
! 2101: case 0x14: /* 20: fmt=32bit fixed */
! 2102: case 0x15: /* 21: fmt=64bit fixed */
! 2103: gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
! 2104: break;
! 2105: default:
! 2106: generate_exception_err(ctx, EXCP_RI, 1);
! 2107: break;
! 2108: }
! 2109: break;
1.1.1.2 root 2110: #else
2111: generate_exception_err(ctx, EXCP_CpU, 1);
1.1 root 2112: #endif
1.1.1.2 root 2113: break;
2114:
2115: /* COP2. */
2116: case 0x32: /* LWC2 */
2117: case 0x36: /* LDC2 */
2118: case 0x3A: /* SWC2 */
2119: case 0x3E: /* SDC2 */
1.1 root 2120: case 0x12: /* CP2 opcode */
2121: /* Not implemented */
1.1.1.2 root 2122: generate_exception_err(ctx, EXCP_CpU, 2);
2123: break;
2124:
1.1 root 2125: case 0x13: /* CP3 opcode */
2126: /* Not implemented */
1.1.1.2 root 2127: generate_exception_err(ctx, EXCP_CpU, 3);
2128: break;
2129:
1.1 root 2130: #if defined (TARGET_MIPS64)
2131: case 0x18 ... 0x1B:
2132: case 0x27:
2133: case 0x34:
2134: case 0x37:
2135: /* MIPS64 opcodes */
2136: #endif
2137: #if defined (MIPS_HAS_JALX)
2138: case 0x1D:
2139: /* JALX: not implemented */
2140: #endif
2141: case 0x1E:
2142: /* ASE specific */
2143: default: /* Invalid */
2144: MIPS_INVAL("");
2145: generate_exception(ctx, EXCP_RI);
2146: break;
2147: }
1.1.1.2 root 2148: if (ctx->hflags & MIPS_HFLAG_BMASK) {
1.1 root 2149: int hflags = ctx->hflags;
2150: /* Branches completion */
1.1.1.2 root 2151: ctx->hflags &= ~MIPS_HFLAG_BMASK;
1.1 root 2152: ctx->bstate = BS_BRANCH;
2153: save_cpu_state(ctx, 0);
2154: switch (hflags & MIPS_HFLAG_BMASK) {
2155: case MIPS_HFLAG_B:
2156: /* unconditional branch */
2157: MIPS_DEBUG("unconditional branch");
1.1.1.2 root 2158: gen_goto_tb(ctx, 0, ctx->btarget);
1.1 root 2159: break;
2160: case MIPS_HFLAG_BL:
2161: /* blikely taken case */
2162: MIPS_DEBUG("blikely branch taken");
1.1.1.2 root 2163: gen_goto_tb(ctx, 0, ctx->btarget);
1.1 root 2164: break;
2165: case MIPS_HFLAG_BC:
2166: /* Conditional branch */
2167: MIPS_DEBUG("conditional branch");
1.1.1.2 root 2168: {
2169: int l1;
2170: l1 = gen_new_label();
2171: gen_op_jnz_T2(l1);
2172: gen_goto_tb(ctx, 1, ctx->pc + 4);
2173: gen_set_label(l1);
2174: gen_goto_tb(ctx, 0, ctx->btarget);
2175: }
1.1 root 2176: break;
2177: case MIPS_HFLAG_BR:
2178: /* unconditional branch to register */
2179: MIPS_DEBUG("branch to register");
2180: gen_op_breg();
2181: break;
2182: default:
2183: MIPS_DEBUG("unknown branch");
2184: break;
2185: }
2186: }
2187: }
2188:
2189: int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
2190: int search_pc)
2191: {
2192: DisasContext ctx, *ctxp = &ctx;
2193: target_ulong pc_start;
2194: uint16_t *gen_opc_end;
2195: int j, lj = -1;
2196:
1.1.1.2 root 2197: if (search_pc && loglevel)
1.1.1.4 ! root 2198: fprintf (logfile, "search pc %d\n", search_pc);
1.1.1.2 root 2199:
1.1 root 2200: pc_start = tb->pc;
2201: gen_opc_ptr = gen_opc_buf;
2202: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2203: gen_opparam_ptr = gen_opparam_buf;
1.1.1.2 root 2204: nb_gen_labels = 0;
1.1 root 2205: ctx.pc = pc_start;
1.1.1.2 root 2206: ctx.saved_pc = -1;
1.1 root 2207: ctx.tb = tb;
2208: ctx.bstate = BS_NONE;
1.1.1.2 root 2209: /* Restore delay slot state from the tb context. */
2210: ctx.hflags = tb->flags;
1.1 root 2211: ctx.saved_hflags = ctx.hflags;
2212: if (ctx.hflags & MIPS_HFLAG_BR) {
2213: gen_op_restore_breg_target();
2214: } else if (ctx.hflags & MIPS_HFLAG_B) {
2215: ctx.btarget = env->btarget;
2216: } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
2217: /* If we are in the delay slot of a conditional branch,
2218: * restore the branch condition from env->bcond to T2
2219: */
2220: ctx.btarget = env->btarget;
2221: gen_op_restore_bcond();
2222: }
2223: #if defined(CONFIG_USER_ONLY)
2224: ctx.mem_idx = 0;
2225: #else
1.1.1.4 ! root 2226: ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
1.1 root 2227: #endif
2228: ctx.CP0_Status = env->CP0_Status;
2229: #ifdef DEBUG_DISAS
2230: if (loglevel & CPU_LOG_TB_CPU) {
2231: fprintf(logfile, "------------------------------------------------\n");
1.1.1.2 root 2232: /* FIXME: This may print out stale hflags from env... */
1.1 root 2233: cpu_dump_state(env, logfile, fprintf, 0);
2234: }
2235: #endif
2236: #if defined MIPS_DEBUG_DISAS
2237: if (loglevel & CPU_LOG_TB_IN_ASM)
1.1.1.2 root 2238: fprintf(logfile, "\ntb %p super %d cond %04x\n",
2239: tb, ctx.mem_idx, ctx.hflags);
1.1 root 2240: #endif
2241: while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1.1.1.2 root 2242: if (env->nb_breakpoints > 0) {
2243: for(j = 0; j < env->nb_breakpoints; j++) {
2244: if (env->breakpoints[j] == ctx.pc) {
2245: save_cpu_state(ctxp, 1);
2246: ctx.bstate = BS_BRANCH;
2247: gen_op_debug();
2248: goto done_generating;
2249: }
2250: }
2251: }
2252:
1.1 root 2253: if (search_pc) {
2254: j = gen_opc_ptr - gen_opc_buf;
2255: if (lj < j) {
2256: lj++;
2257: while (lj < j)
2258: gen_opc_instr_start[lj++] = 0;
2259: }
1.1.1.2 root 2260: gen_opc_pc[lj] = ctx.pc;
2261: gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
2262: gen_opc_instr_start[lj] = 1;
1.1 root 2263: }
2264: ctx.opcode = ldl_code(ctx.pc);
2265: decode_opc(&ctx);
2266: ctx.pc += 4;
1.1.1.2 root 2267:
2268: if (env->singlestep_enabled)
2269: break;
2270:
1.1 root 2271: if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
2272: break;
1.1.1.2 root 2273:
1.1 root 2274: #if defined (MIPS_SINGLE_STEP)
2275: break;
2276: #endif
2277: }
1.1.1.2 root 2278: if (env->singlestep_enabled) {
2279: save_cpu_state(ctxp, ctx.bstate == BS_NONE);
2280: gen_op_debug();
2281: goto done_generating;
2282: }
2283: else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1.1 root 2284: save_cpu_state(ctxp, 0);
1.1.1.2 root 2285: gen_goto_tb(&ctx, 0, ctx.pc);
1.1 root 2286: }
2287: gen_op_reset_T0();
2288: /* Generate the return instruction */
2289: gen_op_exit_tb();
1.1.1.2 root 2290: done_generating:
1.1 root 2291: *gen_opc_ptr = INDEX_op_end;
2292: if (search_pc) {
2293: j = gen_opc_ptr - gen_opc_buf;
2294: lj++;
2295: while (lj <= j)
2296: gen_opc_instr_start[lj++] = 0;
2297: tb->size = 0;
2298: } else {
2299: tb->size = ctx.pc - pc_start;
2300: }
2301: #ifdef DEBUG_DISAS
2302: #if defined MIPS_DEBUG_DISAS
2303: if (loglevel & CPU_LOG_TB_IN_ASM)
2304: fprintf(logfile, "\n");
2305: #endif
2306: if (loglevel & CPU_LOG_TB_IN_ASM) {
2307: fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1.1.1.4 ! root 2308: target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1.1 root 2309: fprintf(logfile, "\n");
2310: }
2311: if (loglevel & CPU_LOG_TB_OP) {
2312: fprintf(logfile, "OP:\n");
2313: dump_ops(gen_opc_buf, gen_opparam_buf);
2314: fprintf(logfile, "\n");
2315: }
2316: if (loglevel & CPU_LOG_TB_CPU) {
2317: fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
2318: }
2319: #endif
2320:
2321: return 0;
2322: }
2323:
2324: int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
2325: {
2326: return gen_intermediate_code_internal(env, tb, 0);
2327: }
2328:
2329: int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
2330: {
2331: return gen_intermediate_code_internal(env, tb, 1);
2332: }
2333:
1.1.1.4 ! root 2334: #ifdef MIPS_USES_FPU
! 2335: void fpu_dump_state(CPUState *env, FILE *f,
! 2336: int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
! 2337: int flags)
! 2338: {
! 2339: int i;
! 2340:
! 2341: # define printfpr(fp) do { \
! 2342: fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
! 2343: (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
! 2344: } while(0)
! 2345:
! 2346: fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n",
! 2347: env->fcr0, env->fcr31,
! 2348: (env->CP0_Status & (1<<CP0St_FR)) != 0);
! 2349: fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
! 2350: fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
! 2351: fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
! 2352: for(i=0; i < 32; i+=2) {
! 2353: fpu_fprintf(f, "f%02d: ", i);
! 2354: printfpr(FPR(env, i));
! 2355: }
! 2356:
! 2357: #undef printfpr
! 2358: }
! 2359:
! 2360: void dump_fpu(CPUState *env)
! 2361: {
! 2362: if (loglevel) {
! 2363: fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
! 2364: env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
! 2365: fpu_dump_state(env, logfile, fprintf, 0);
! 2366: }
! 2367: }
! 2368: #endif /* MIPS_USES_FPU */
! 2369:
1.1 root 2370: void cpu_dump_state (CPUState *env, FILE *f,
2371: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2372: int flags)
2373: {
2374: uint32_t c0_status;
2375: int i;
2376:
2377: cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
2378: env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
2379: for (i = 0; i < 32; i++) {
2380: if ((i & 3) == 0)
2381: cpu_fprintf(f, "GPR%02d:", i);
2382: cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
2383: if ((i & 3) == 3)
2384: cpu_fprintf(f, "\n");
2385: }
2386:
2387: c0_status = env->CP0_Status;
2388: if (env->hflags & MIPS_HFLAG_UM)
2389: c0_status |= (1 << CP0St_UM);
2390: if (env->hflags & MIPS_HFLAG_ERL)
2391: c0_status |= (1 << CP0St_ERL);
2392: if (env->hflags & MIPS_HFLAG_EXL)
2393: c0_status |= (1 << CP0St_EXL);
2394:
2395: cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
2396: c0_status, env->CP0_Cause, env->CP0_EPC);
2397: cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
2398: env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1.1.1.4 ! root 2399: #ifdef MIPS_USES_FPU
! 2400: fpu_dump_state(env, f, cpu_fprintf, flags);
! 2401: #endif
1.1 root 2402: }
2403:
2404: CPUMIPSState *cpu_mips_init (void)
2405: {
2406: CPUMIPSState *env;
2407:
2408: env = qemu_mallocz(sizeof(CPUMIPSState));
2409: if (!env)
2410: return NULL;
1.1.1.2 root 2411: cpu_exec_init(env);
1.1 root 2412: tlb_flush(env, 1);
2413: /* Minimal init */
2414: env->PC = 0xBFC00000;
2415: #if defined (MIPS_USES_R4K_TLB)
2416: env->CP0_random = MIPS_TLB_NB - 1;
2417: #endif
2418: env->CP0_Wired = 0;
2419: env->CP0_Config0 = MIPS_CONFIG0;
2420: #if defined (MIPS_CONFIG1)
2421: env->CP0_Config1 = MIPS_CONFIG1;
2422: #endif
2423: #if defined (MIPS_CONFIG2)
2424: env->CP0_Config2 = MIPS_CONFIG2;
2425: #endif
2426: #if defined (MIPS_CONFIG3)
2427: env->CP0_Config3 = MIPS_CONFIG3;
2428: #endif
2429: env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
2430: env->CP0_WatchLo = 0;
2431: env->hflags = MIPS_HFLAG_ERL;
2432: /* Count register increments in debug mode, EJTAG version 1 */
2433: env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
2434: env->CP0_PRid = MIPS_CPU;
2435: env->exception_index = EXCP_NONE;
1.1.1.2 root 2436: #if defined(CONFIG_USER_ONLY)
2437: env->hflags |= MIPS_HFLAG_UM;
2438: #endif
1.1.1.4 ! root 2439: #ifdef MIPS_USES_FPU
! 2440: env->fcr0 = MIPS_FCR0;
! 2441: #endif
1.1 root 2442: return env;
2443: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.