]> git.proxmox.com Git - mirror_qemu.git/blob - target-mips/translate.c
Dynamically translate MIPS mfc0 instructions.
[mirror_qemu.git] / target-mips / translate.c
1 /*
2 * MIPS32 emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 * Copyright (c) 2006 Marius Groeger (FPU operations)
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
32 //#define MIPS_DEBUG_DISAS
33 //#define MIPS_SINGLE_STEP
34
35 #ifdef USE_DIRECT_JUMP
36 #define TBPARAM(x)
37 #else
38 #define TBPARAM(x) (long)(x)
39 #endif
40
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,
100 OPC_LWU = 0x27,
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
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
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
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
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
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
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
453 static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
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);
460 if (err == 0)
461 gen_op_raise_exception(excp);
462 else
463 gen_op_raise_exception_err(excp, err);
464 ctx->bstate = BS_EXCP;
465 }
466
467 static inline void generate_exception (DisasContext *ctx, int excp)
468 {
469 generate_exception_err (ctx, excp, 0);
470 }
471
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);
499 OP_LD_TABLE(wu);
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);
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
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;
585 case OPC_LWU:
586 op_ldst(lwu);
587 GEN_STORE_TN_REG(rt, T0);
588 opn = "lwu";
589 break;
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
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
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
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
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 */
1205 ctx->hflags |= MIPS_HFLAG_B;
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;
1212 ctx->hflags |= MIPS_HFLAG_B;
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;
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;
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");
1235 gen_goto_tb(ctx, 0, ctx->pc + 4);
1236 return;
1237 case OPC_J:
1238 ctx->hflags |= MIPS_HFLAG_B;
1239 MIPS_DEBUG("j %08x", btarget);
1240 break;
1241 case OPC_JAL:
1242 blink = 31;
1243 ctx->hflags |= MIPS_HFLAG_B;
1244 MIPS_DEBUG("jal %08x", btarget);
1245 break;
1246 case OPC_JR:
1247 ctx->hflags |= MIPS_HFLAG_BR;
1248 MIPS_DEBUG("jr %s", regnames[rs]);
1249 break;
1250 case OPC_JALR:
1251 blink = rt;
1252 ctx->hflags |= MIPS_HFLAG_BR;
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:
1329 ctx->hflags |= MIPS_HFLAG_BC;
1330 break;
1331 case OPC_BLTZALL:
1332 gen_op_ltz();
1333 blink = 31;
1334 MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1335 likely:
1336 ctx->hflags |= MIPS_HFLAG_BL;
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_mfc0 (DisasContext *ctx, int reg, int sel)
1353 {
1354 const unsigned char *rn;
1355
1356 if (sel != 0 && reg != 16 && reg != 28) {
1357 rn = "invalid";
1358 goto die;
1359 }
1360 switch (reg) {
1361 case 0:
1362 gen_op_mfc0_index();
1363 rn = "Index";
1364 break;
1365 case 1:
1366 gen_op_mfc0_random();
1367 rn = "Random";
1368 break;
1369 case 2:
1370 gen_op_mfc0_entrylo0();
1371 rn = "EntryLo0";
1372 break;
1373 case 3:
1374 gen_op_mfc0_entrylo1();
1375 rn = "EntryLo1";
1376 break;
1377 case 4:
1378 gen_op_mfc0_context();
1379 rn = "Context";
1380 break;
1381 case 5:
1382 gen_op_mfc0_pagemask();
1383 rn = "PageMask";
1384 break;
1385 case 6:
1386 gen_op_mfc0_wired();
1387 rn = "Wired";
1388 break;
1389 case 8:
1390 gen_op_mfc0_badvaddr();
1391 rn = "BadVaddr";
1392 break;
1393 case 9:
1394 gen_op_mfc0_count();
1395 rn = "Count";
1396 break;
1397 case 10:
1398 gen_op_mfc0_entryhi();
1399 rn = "EntryHi";
1400 break;
1401 case 11:
1402 gen_op_mfc0_compare();
1403 rn = "Compare";
1404 break;
1405 case 12:
1406 gen_op_mfc0_status();
1407 rn = "Status";
1408 break;
1409 case 13:
1410 gen_op_mfc0_cause();
1411 rn = "Cause";
1412 break;
1413 case 14:
1414 gen_op_mfc0_epc();
1415 rn = "EPC";
1416 break;
1417 case 15:
1418 gen_op_mfc0_prid();
1419 rn = "PRid";
1420 break;
1421 case 16:
1422 switch (sel) {
1423 case 0:
1424 gen_op_mfc0_config0();
1425 rn = "Config";
1426 break;
1427 case 1:
1428 gen_op_mfc0_config1();
1429 rn = "Config1";
1430 break;
1431 default:
1432 rn = "Unknown config register";
1433 goto die;
1434 }
1435 break;
1436 case 17:
1437 gen_op_mfc0_lladdr();
1438 rn = "LLAddr";
1439 break;
1440 case 18:
1441 gen_op_mfc0_watchlo();
1442 rn = "WatchLo";
1443 break;
1444 case 19:
1445 gen_op_mfc0_watchhi();
1446 rn = "WatchHi";
1447 break;
1448 case 23:
1449 gen_op_mfc0_debug();
1450 rn = "Debug";
1451 break;
1452 case 24:
1453 gen_op_mfc0_depc();
1454 rn = "DEPC";
1455 break;
1456 case 28:
1457 switch (sel) {
1458 case 0:
1459 gen_op_mfc0_taglo();
1460 rn = "TagLo";
1461 break;
1462 case 1:
1463 gen_op_mfc0_datalo();
1464 rn = "DataLo";
1465 break;
1466 default:
1467 rn = "unknown sel";
1468 goto die;
1469 }
1470 break;
1471 case 30:
1472 gen_op_mfc0_errorepc();
1473 rn = "ErrorEPC";
1474 break;
1475 case 31:
1476 gen_op_mfc0_desave();
1477 rn = "DESAVE";
1478 break;
1479 default:
1480 rn = "unknown";
1481 goto die;
1482 }
1483 #if defined MIPS_DEBUG_DISAS
1484 if (loglevel & CPU_LOG_TB_IN_ASM) {
1485 fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
1486 env->PC, rn, T0, reg, sel);
1487 }
1488 #endif
1489 return;
1490
1491 die:
1492 #if defined MIPS_DEBUG_DISAS
1493 if (loglevel & CPU_LOG_TB_IN_ASM) {
1494 fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
1495 env->PC, rn, T0, reg, sel);
1496 }
1497 #endif
1498 generate_exception(ctx, EXCP_RI);
1499 }
1500
1501 static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1502 {
1503 const unsigned char *opn = "unk";
1504
1505 if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1506 (ctx->hflags & MIPS_HFLAG_UM) &&
1507 !(ctx->hflags & MIPS_HFLAG_ERL) &&
1508 !(ctx->hflags & MIPS_HFLAG_EXL)) {
1509 if (loglevel & CPU_LOG_TB_IN_ASM) {
1510 fprintf(logfile, "CP0 is not usable\n");
1511 }
1512 generate_exception_err (ctx, EXCP_CpU, 0);
1513 return;
1514 }
1515
1516 switch (opc) {
1517 case OPC_MFC0:
1518 if (rt == 0) {
1519 /* Treat as NOP */
1520 return;
1521 }
1522 gen_mfc0(ctx, rd, ctx->opcode & 0x7);
1523 gen_op_store_T0_gpr(rt);
1524 opn = "mfc0";
1525 break;
1526 case OPC_MTC0:
1527 /* If we get an exception, we want to restart at next instruction */
1528 ctx->pc += 4;
1529 save_cpu_state(ctx, 1);
1530 ctx->pc -= 4;
1531 GEN_LOAD_REG_TN(T0, rt);
1532 gen_op_mtc0(rd, ctx->opcode & 0x7);
1533 /* Stop translation as we may have switched the execution mode */
1534 ctx->bstate = BS_STOP;
1535 opn = "mtc0";
1536 break;
1537 #if defined(MIPS_USES_R4K_TLB)
1538 case OPC_TLBWI:
1539 gen_op_tlbwi();
1540 opn = "tlbwi";
1541 break;
1542 case OPC_TLBWR:
1543 gen_op_tlbwr();
1544 opn = "tlbwr";
1545 break;
1546 case OPC_TLBP:
1547 gen_op_tlbp();
1548 opn = "tlbp";
1549 break;
1550 case OPC_TLBR:
1551 gen_op_tlbr();
1552 opn = "tlbr";
1553 break;
1554 #endif
1555 case OPC_ERET:
1556 opn = "eret";
1557 save_cpu_state(ctx, 0);
1558 gen_op_eret();
1559 ctx->bstate = BS_EXCP;
1560 break;
1561 case OPC_DERET:
1562 opn = "deret";
1563 if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1564 generate_exception(ctx, EXCP_RI);
1565 } else {
1566 save_cpu_state(ctx, 0);
1567 gen_op_deret();
1568 ctx->bstate = BS_EXCP;
1569 }
1570 break;
1571 case OPC_WAIT:
1572 opn = "wait";
1573 /* If we get an exception, we want to restart at next instruction */
1574 ctx->pc += 4;
1575 save_cpu_state(ctx, 1);
1576 ctx->pc -= 4;
1577 gen_op_wait();
1578 ctx->bstate = BS_EXCP;
1579 break;
1580 default:
1581 if (loglevel & CPU_LOG_TB_IN_ASM) {
1582 fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1583 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1584 ((ctx->opcode >> 16) & 0x1F));
1585 }
1586 generate_exception(ctx, EXCP_RI);
1587 return;
1588 }
1589 MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1590 }
1591
1592 #ifdef MIPS_USES_FPU
1593 /* CP1 Branches (before delay slot) */
1594 static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
1595 int32_t offset)
1596 {
1597 target_ulong btarget;
1598
1599 btarget = ctx->pc + 4 + offset;
1600
1601 switch (cond) {
1602 case 0x0000: /* bc1f */
1603 gen_op_bc1f();
1604 MIPS_DEBUG("bc1f %08x", btarget);
1605 goto not_likely;
1606 case 0x0002: /* bc1fl */
1607 gen_op_bc1f();
1608 MIPS_DEBUG("bc1fl %08x", btarget);
1609 goto likely;
1610 case 0x0001: /* bc1t */
1611 gen_op_bc1t();
1612 MIPS_DEBUG("bc1t %08x", btarget);
1613 not_likely:
1614 ctx->hflags |= MIPS_HFLAG_BC;
1615 break;
1616 case 0x0003: /* bc1tl */
1617 gen_op_bc1t();
1618 MIPS_DEBUG("bc1tl %08x", btarget);
1619 likely:
1620 ctx->hflags |= MIPS_HFLAG_BL;
1621 break;
1622 default:
1623 MIPS_INVAL("cp1 branch/jump");
1624 generate_exception(ctx, EXCP_RI);
1625 return;
1626 }
1627 gen_op_set_bcond();
1628
1629 MIPS_DEBUG("enter ds: cond %02x target %08x",
1630 ctx->hflags, btarget);
1631 ctx->btarget = btarget;
1632
1633 return;
1634 }
1635
1636 /* Coprocessor 1 (FPU) */
1637 static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
1638 {
1639 const unsigned char *opn = "unk";
1640
1641 switch (opc) {
1642 case OPC_MFC1:
1643 GEN_LOAD_FREG_FTN(WT0, fs);
1644 gen_op_mfc1();
1645 GEN_STORE_TN_REG(rt, T0);
1646 opn = "mfc1";
1647 break;
1648 case OPC_MTC1:
1649 GEN_LOAD_REG_TN(T0, rt);
1650 gen_op_mtc1();
1651 GEN_STORE_FTN_FREG(fs, WT0);
1652 opn = "mtc1";
1653 break;
1654 case OPC_CFC1:
1655 if (fs != 0 && fs != 31) {
1656 MIPS_INVAL("cfc1 freg");
1657 generate_exception(ctx, EXCP_RI);
1658 return;
1659 }
1660 GEN_LOAD_IMM_TN(T1, fs);
1661 gen_op_cfc1();
1662 GEN_STORE_TN_REG(rt, T0);
1663 opn = "cfc1";
1664 break;
1665 case OPC_CTC1:
1666 if (fs != 0 && fs != 31) {
1667 MIPS_INVAL("ctc1 freg");
1668 generate_exception(ctx, EXCP_RI);
1669 return;
1670 }
1671 GEN_LOAD_IMM_TN(T1, fs);
1672 GEN_LOAD_REG_TN(T0, rt);
1673 gen_op_ctc1();
1674 opn = "ctc1";
1675 break;
1676 default:
1677 if (loglevel & CPU_LOG_TB_IN_ASM) {
1678 fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
1679 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1680 ((ctx->opcode >> 16) & 0x1F));
1681 }
1682 generate_exception(ctx, EXCP_RI);
1683 return;
1684 }
1685 MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
1686 }
1687
1688 /* verify if floating point register is valid; an operation is not defined
1689 * if bit 0 of any register specification is set and the FR bit in the
1690 * Status register equals zero, since the register numbers specify an
1691 * even-odd pair of adjacent coprocessor general registers. When the FR bit
1692 * in the Status register equals one, both even and odd register numbers
1693 * are valid.
1694 *
1695 * Multiple float registers can be checked by calling
1696 * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
1697 */
1698 #define CHECK_FR(ctx, freg) do { \
1699 if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
1700 generate_exception(ctx, EXCP_RI); \
1701 return; \
1702 } \
1703 } while(0)
1704
1705 #define FOP(func, fmt) (((fmt) << 21) | (func))
1706
1707 static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
1708 {
1709 const unsigned char *opn = "unk";
1710 const char *condnames[] = {
1711 "c.f",
1712 "c.un",
1713 "c.eq",
1714 "c.ueq",
1715 "c.olt",
1716 "c.ult",
1717 "c.ole",
1718 "c.ule",
1719 "c.sf",
1720 "c.ngle",
1721 "c.seq",
1722 "c.ngl",
1723 "c.lt",
1724 "c.nge",
1725 "c.le",
1726 "c.ngt",
1727 };
1728 int binary = 0;
1729
1730 switch (ctx->opcode & FOP(0x3f, 0x1f)) {
1731 case FOP(0, 17):
1732 CHECK_FR(ctx, fs | ft | fd);
1733 GEN_LOAD_FREG_FTN(DT0, fs);
1734 GEN_LOAD_FREG_FTN(DT1, ft);
1735 gen_op_float_add_d();
1736 GEN_STORE_FTN_FREG(fd, DT2);
1737 opn = "add.d";
1738 binary = 1;
1739 break;
1740 case FOP(1, 17):
1741 CHECK_FR(ctx, fs | ft | fd);
1742 GEN_LOAD_FREG_FTN(DT0, fs);
1743 GEN_LOAD_FREG_FTN(DT1, ft);
1744 gen_op_float_sub_d();
1745 GEN_STORE_FTN_FREG(fd, DT2);
1746 opn = "sub.d";
1747 binary = 1;
1748 break;
1749 case FOP(2, 17):
1750 CHECK_FR(ctx, fs | ft | fd);
1751 GEN_LOAD_FREG_FTN(DT0, fs);
1752 GEN_LOAD_FREG_FTN(DT1, ft);
1753 gen_op_float_mul_d();
1754 GEN_STORE_FTN_FREG(fd, DT2);
1755 opn = "mul.d";
1756 binary = 1;
1757 break;
1758 case FOP(3, 17):
1759 CHECK_FR(ctx, fs | ft | fd);
1760 GEN_LOAD_FREG_FTN(DT0, fs);
1761 GEN_LOAD_FREG_FTN(DT1, ft);
1762 gen_op_float_div_d();
1763 GEN_STORE_FTN_FREG(fd, DT2);
1764 opn = "div.d";
1765 binary = 1;
1766 break;
1767 case FOP(4, 17):
1768 CHECK_FR(ctx, fs | fd);
1769 GEN_LOAD_FREG_FTN(DT0, fs);
1770 gen_op_float_sqrt_d();
1771 GEN_STORE_FTN_FREG(fd, DT2);
1772 opn = "sqrt.d";
1773 break;
1774 case FOP(5, 17):
1775 CHECK_FR(ctx, fs | fd);
1776 GEN_LOAD_FREG_FTN(DT0, fs);
1777 gen_op_float_abs_d();
1778 GEN_STORE_FTN_FREG(fd, DT2);
1779 opn = "abs.d";
1780 break;
1781 case FOP(6, 17):
1782 CHECK_FR(ctx, fs | fd);
1783 GEN_LOAD_FREG_FTN(DT0, fs);
1784 gen_op_float_mov_d();
1785 GEN_STORE_FTN_FREG(fd, DT2);
1786 opn = "mov.d";
1787 break;
1788 case FOP(7, 17):
1789 CHECK_FR(ctx, fs | fd);
1790 GEN_LOAD_FREG_FTN(DT0, fs);
1791 gen_op_float_chs_d();
1792 GEN_STORE_FTN_FREG(fd, DT2);
1793 opn = "neg.d";
1794 break;
1795 /* 8 - round.l */
1796 /* 9 - trunc.l */
1797 /* 10 - ceil.l */
1798 /* 11 - floor.l */
1799 case FOP(12, 17):
1800 CHECK_FR(ctx, fs | fd);
1801 GEN_LOAD_FREG_FTN(DT0, fs);
1802 gen_op_float_roundw_d();
1803 GEN_STORE_FTN_FREG(fd, WT2);
1804 opn = "round.w.d";
1805 break;
1806 case FOP(13, 17):
1807 CHECK_FR(ctx, fs | fd);
1808 GEN_LOAD_FREG_FTN(DT0, fs);
1809 gen_op_float_truncw_d();
1810 GEN_STORE_FTN_FREG(fd, WT2);
1811 opn = "trunc.w.d";
1812 break;
1813 case FOP(14, 17):
1814 CHECK_FR(ctx, fs | fd);
1815 GEN_LOAD_FREG_FTN(DT0, fs);
1816 gen_op_float_ceilw_d();
1817 GEN_STORE_FTN_FREG(fd, WT2);
1818 opn = "ceil.w.d";
1819 break;
1820 case FOP(15, 17):
1821 CHECK_FR(ctx, fs | fd);
1822 GEN_LOAD_FREG_FTN(DT0, fs);
1823 gen_op_float_floorw_d();
1824 GEN_STORE_FTN_FREG(fd, WT2);
1825 opn = "ceil.w.d";
1826 break;
1827 case FOP(33, 16): /* cvt.d.s */
1828 CHECK_FR(ctx, fs | fd);
1829 GEN_LOAD_FREG_FTN(WT0, fs);
1830 gen_op_float_cvtd_s();
1831 GEN_STORE_FTN_FREG(fd, DT2);
1832 opn = "cvt.d.s";
1833 break;
1834 case FOP(33, 20): /* cvt.d.w */
1835 CHECK_FR(ctx, fs | fd);
1836 GEN_LOAD_FREG_FTN(WT0, fs);
1837 gen_op_float_cvtd_w();
1838 GEN_STORE_FTN_FREG(fd, DT2);
1839 opn = "cvt.d.w";
1840 break;
1841 case FOP(48, 17):
1842 case FOP(49, 17):
1843 case FOP(50, 17):
1844 case FOP(51, 17):
1845 case FOP(52, 17):
1846 case FOP(53, 17):
1847 case FOP(54, 17):
1848 case FOP(55, 17):
1849 case FOP(56, 17):
1850 case FOP(57, 17):
1851 case FOP(58, 17):
1852 case FOP(59, 17):
1853 case FOP(60, 17):
1854 case FOP(61, 17):
1855 case FOP(62, 17):
1856 case FOP(63, 17):
1857 CHECK_FR(ctx, fs | ft);
1858 GEN_LOAD_FREG_FTN(DT0, fs);
1859 GEN_LOAD_FREG_FTN(DT1, ft);
1860 gen_cmp_d(func-48);
1861 opn = condnames[func-48];
1862 break;
1863 case FOP(0, 16):
1864 CHECK_FR(ctx, fs | ft | fd);
1865 GEN_LOAD_FREG_FTN(WT0, fs);
1866 GEN_LOAD_FREG_FTN(WT1, ft);
1867 gen_op_float_add_s();
1868 GEN_STORE_FTN_FREG(fd, WT2);
1869 opn = "add.s";
1870 binary = 1;
1871 break;
1872 case FOP(1, 16):
1873 CHECK_FR(ctx, fs | ft | fd);
1874 GEN_LOAD_FREG_FTN(WT0, fs);
1875 GEN_LOAD_FREG_FTN(WT1, ft);
1876 gen_op_float_sub_s();
1877 GEN_STORE_FTN_FREG(fd, WT2);
1878 opn = "sub.s";
1879 binary = 1;
1880 break;
1881 case FOP(2, 16):
1882 CHECK_FR(ctx, fs | ft | fd);
1883 GEN_LOAD_FREG_FTN(WT0, fs);
1884 GEN_LOAD_FREG_FTN(WT1, ft);
1885 gen_op_float_mul_s();
1886 GEN_STORE_FTN_FREG(fd, WT2);
1887 opn = "mul.s";
1888 binary = 1;
1889 break;
1890 case FOP(3, 16):
1891 CHECK_FR(ctx, fs | ft | fd);
1892 GEN_LOAD_FREG_FTN(WT0, fs);
1893 GEN_LOAD_FREG_FTN(WT1, ft);
1894 gen_op_float_div_s();
1895 GEN_STORE_FTN_FREG(fd, WT2);
1896 opn = "div.s";
1897 binary = 1;
1898 break;
1899 case FOP(4, 16):
1900 CHECK_FR(ctx, fs | fd);
1901 GEN_LOAD_FREG_FTN(WT0, fs);
1902 gen_op_float_sqrt_s();
1903 GEN_STORE_FTN_FREG(fd, WT2);
1904 opn = "sqrt.s";
1905 break;
1906 case FOP(5, 16):
1907 CHECK_FR(ctx, fs | fd);
1908 GEN_LOAD_FREG_FTN(WT0, fs);
1909 gen_op_float_abs_s();
1910 GEN_STORE_FTN_FREG(fd, WT2);
1911 opn = "abs.s";
1912 break;
1913 case FOP(6, 16):
1914 CHECK_FR(ctx, fs | fd);
1915 GEN_LOAD_FREG_FTN(WT0, fs);
1916 gen_op_float_mov_s();
1917 GEN_STORE_FTN_FREG(fd, WT2);
1918 opn = "mov.s";
1919 break;
1920 case FOP(7, 16):
1921 CHECK_FR(ctx, fs | fd);
1922 GEN_LOAD_FREG_FTN(WT0, fs);
1923 gen_op_float_chs_s();
1924 GEN_STORE_FTN_FREG(fd, WT2);
1925 opn = "neg.s";
1926 break;
1927 case FOP(12, 16):
1928 CHECK_FR(ctx, fs | fd);
1929 GEN_LOAD_FREG_FTN(WT0, fs);
1930 gen_op_float_roundw_s();
1931 GEN_STORE_FTN_FREG(fd, WT2);
1932 opn = "round.w.s";
1933 break;
1934 case FOP(13, 16):
1935 CHECK_FR(ctx, fs | fd);
1936 GEN_LOAD_FREG_FTN(WT0, fs);
1937 gen_op_float_truncw_s();
1938 GEN_STORE_FTN_FREG(fd, WT2);
1939 opn = "trunc.w.s";
1940 break;
1941 case FOP(32, 17): /* cvt.s.d */
1942 CHECK_FR(ctx, fs | fd);
1943 GEN_LOAD_FREG_FTN(DT0, fs);
1944 gen_op_float_cvts_d();
1945 GEN_STORE_FTN_FREG(fd, WT2);
1946 opn = "cvt.s.d";
1947 break;
1948 case FOP(32, 20): /* cvt.s.w */
1949 CHECK_FR(ctx, fs | fd);
1950 GEN_LOAD_FREG_FTN(WT0, fs);
1951 gen_op_float_cvts_w();
1952 GEN_STORE_FTN_FREG(fd, WT2);
1953 opn = "cvt.s.w";
1954 break;
1955 case FOP(36, 16): /* cvt.w.s */
1956 CHECK_FR(ctx, fs | fd);
1957 GEN_LOAD_FREG_FTN(WT0, fs);
1958 gen_op_float_cvtw_s();
1959 GEN_STORE_FTN_FREG(fd, WT2);
1960 opn = "cvt.w.s";
1961 break;
1962 case FOP(36, 17): /* cvt.w.d */
1963 CHECK_FR(ctx, fs | fd);
1964 GEN_LOAD_FREG_FTN(DT0, fs);
1965 gen_op_float_cvtw_d();
1966 GEN_STORE_FTN_FREG(fd, WT2);
1967 opn = "cvt.w.d";
1968 break;
1969 case FOP(48, 16):
1970 case FOP(49, 16):
1971 case FOP(50, 16):
1972 case FOP(51, 16):
1973 case FOP(52, 16):
1974 case FOP(53, 16):
1975 case FOP(54, 16):
1976 case FOP(55, 16):
1977 case FOP(56, 16):
1978 case FOP(57, 16):
1979 case FOP(58, 16):
1980 case FOP(59, 16):
1981 case FOP(60, 16):
1982 case FOP(61, 16):
1983 case FOP(62, 16):
1984 case FOP(63, 16):
1985 CHECK_FR(ctx, fs | ft);
1986 GEN_LOAD_FREG_FTN(WT0, fs);
1987 GEN_LOAD_FREG_FTN(WT1, ft);
1988 gen_cmp_s(func-48);
1989 opn = condnames[func-48];
1990 break;
1991 default:
1992 if (loglevel & CPU_LOG_TB_IN_ASM) {
1993 fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
1994 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1995 ((ctx->opcode >> 16) & 0x1F));
1996 }
1997 generate_exception(ctx, EXCP_RI);
1998 return;
1999 }
2000 if (binary)
2001 MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
2002 else
2003 MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
2004 }
2005 #endif
2006
2007 /* ISA extensions */
2008 /* MIPS16 extension to MIPS32 */
2009 /* SmartMIPS extension to MIPS32 */
2010
2011 #ifdef TARGET_MIPS64
2012 static void gen_arith64 (DisasContext *ctx, uint16_t opc)
2013 {
2014 if (func == 0x02 && rd == 0) {
2015 /* NOP */
2016 return;
2017 }
2018 if (rs == 0 || rt == 0) {
2019 gen_op_reset_T0();
2020 gen_op_save64();
2021 } else {
2022 gen_op_load_gpr_T0(rs);
2023 gen_op_load_gpr_T1(rt);
2024 gen_op_save64();
2025 if (func & 0x01)
2026 gen_op_mul64u();
2027 else
2028 gen_op_mul64s();
2029 }
2030 if (func & 0x02)
2031 gen_op_add64();
2032 else
2033 gen_op_sub64();
2034 }
2035
2036 /* Coprocessor 3 (FPU) */
2037
2038 /* MDMX extension to MIPS64 */
2039 /* MIPS-3D extension to MIPS64 */
2040
2041 #endif
2042
2043 static void gen_blikely(DisasContext *ctx)
2044 {
2045 int l1;
2046 l1 = gen_new_label();
2047 gen_op_jnz_T2(l1);
2048 gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
2049 gen_goto_tb(ctx, 1, ctx->pc + 4);
2050 gen_set_label(l1);
2051 }
2052
2053 static void decode_opc (DisasContext *ctx)
2054 {
2055 int32_t offset;
2056 int rs, rt, rd, sa;
2057 uint16_t op, op1;
2058 int16_t imm;
2059
2060 /* make sure instructions are on a word boundary */
2061 if (ctx->pc & 0x3) {
2062 generate_exception(ctx, EXCP_AdEL);
2063 return;
2064 }
2065
2066 if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
2067 /* Handle blikely not taken case */
2068 MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
2069 gen_blikely(ctx);
2070 }
2071 op = ctx->opcode >> 26;
2072 rs = ((ctx->opcode >> 21) & 0x1F);
2073 rt = ((ctx->opcode >> 16) & 0x1F);
2074 rd = ((ctx->opcode >> 11) & 0x1F);
2075 sa = ((ctx->opcode >> 6) & 0x1F);
2076 imm = (int16_t)ctx->opcode;
2077 switch (op) {
2078 case 0x00: /* Special opcode */
2079 op1 = ctx->opcode & 0x3F;
2080 switch (op1) {
2081 case 0x00: /* Arithmetic with immediate */
2082 case 0x02 ... 0x03:
2083 gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
2084 break;
2085 case 0x04: /* Arithmetic */
2086 case 0x06 ... 0x07:
2087 case 0x0A ... 0x0B:
2088 case 0x20 ... 0x27:
2089 case 0x2A ... 0x2B:
2090 gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
2091 break;
2092 case 0x18 ... 0x1B: /* MULT / DIV */
2093 gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
2094 break;
2095 case 0x08 ... 0x09: /* Jumps */
2096 gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
2097 return;
2098 case 0x30 ... 0x34: /* Traps */
2099 case 0x36:
2100 gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
2101 break;
2102 case 0x10: /* Move from HI/LO */
2103 case 0x12:
2104 gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
2105 break;
2106 case 0x11:
2107 case 0x13: /* Move to HI/LO */
2108 gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
2109 break;
2110 case 0x0C: /* SYSCALL */
2111 generate_exception(ctx, EXCP_SYSCALL);
2112 break;
2113 case 0x0D: /* BREAK */
2114 generate_exception(ctx, EXCP_BREAK);
2115 break;
2116 case 0x0F: /* SYNC */
2117 /* Treat as a noop */
2118 break;
2119 case 0x05: /* Pmon entry point */
2120 gen_op_pmon((ctx->opcode >> 6) & 0x1F);
2121 break;
2122
2123 case 0x01: /* MOVCI */
2124 #if defined (MIPS_HAS_MOVCI)
2125 /* XXX */
2126 #else
2127 /* Not implemented */
2128 generate_exception_err (ctx, EXCP_CpU, 1);
2129 #endif
2130 break;
2131
2132 #if defined (TARGET_MIPS64)
2133 case 0x14: /* MIPS64 specific opcodes */
2134 case 0x16:
2135 case 0x17:
2136 case 0x1C ... 0x1F:
2137 case 0x2C ... 0x2F:
2138 case 0x37:
2139 case 0x39 ... 0x3B:
2140 case 0x3E ... 0x3F:
2141 #endif
2142 default: /* Invalid */
2143 MIPS_INVAL("special");
2144 generate_exception(ctx, EXCP_RI);
2145 break;
2146 }
2147 break;
2148 case 0x1C: /* Special2 opcode */
2149 op1 = ctx->opcode & 0x3F;
2150 switch (op1) {
2151 #if defined (MIPS_USES_R4K_EXT)
2152 /* Those instructions are not part of MIPS32 core */
2153 case 0x00 ... 0x01: /* Multiply and add/sub */
2154 case 0x04 ... 0x05:
2155 gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
2156 break;
2157 case 0x02: /* MUL */
2158 gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
2159 break;
2160 case 0x20 ... 0x21: /* CLO / CLZ */
2161 gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
2162 break;
2163 #endif
2164 case 0x3F: /* SDBBP */
2165 /* XXX: not clear which exception should be raised
2166 * when in debug mode...
2167 */
2168 if (!(ctx->hflags & MIPS_HFLAG_DM)) {
2169 generate_exception(ctx, EXCP_DBp);
2170 } else {
2171 generate_exception(ctx, EXCP_DBp);
2172 }
2173 /* Treat as a noop */
2174 break;
2175 default: /* Invalid */
2176 MIPS_INVAL("special2");
2177 generate_exception(ctx, EXCP_RI);
2178 break;
2179 }
2180 break;
2181 case 0x01: /* B REGIMM opcode */
2182 op1 = ((ctx->opcode >> 16) & 0x1F);
2183 switch (op1) {
2184 case 0x00 ... 0x03: /* REGIMM branches */
2185 case 0x10 ... 0x13:
2186 gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
2187 return;
2188 case 0x08 ... 0x0C: /* Traps */
2189 case 0x0E:
2190 gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
2191 break;
2192 default: /* Invalid */
2193 MIPS_INVAL("REGIMM");
2194 generate_exception(ctx, EXCP_RI);
2195 break;
2196 }
2197 break;
2198 case 0x10: /* CP0 opcode */
2199 op1 = ((ctx->opcode >> 21) & 0x1F);
2200 switch (op1) {
2201 case 0x00:
2202 case 0x04:
2203 gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
2204 break;
2205 default:
2206 gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
2207 break;
2208 }
2209 break;
2210 case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
2211 gen_arith_imm(ctx, op, rt, rs, imm);
2212 break;
2213 case 0x02 ... 0x03: /* Jump */
2214 offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
2215 gen_compute_branch(ctx, op, rs, rt, offset);
2216 return;
2217 case 0x04 ... 0x07: /* Branch */
2218 case 0x14 ... 0x17:
2219 gen_compute_branch(ctx, op, rs, rt, imm << 2);
2220 return;
2221 case 0x20 ... 0x2E: /* Load and stores */
2222 case 0x30:
2223 case 0x38:
2224 gen_ldst(ctx, op, rt, rs, imm);
2225 break;
2226 case 0x2F: /* Cache operation */
2227 /* Treat as a noop */
2228 break;
2229 case 0x33: /* Prefetch */
2230 /* Treat as a noop */
2231 break;
2232 case 0x3F: /* HACK */
2233 break;
2234
2235 /* Floating point. */
2236 case 0x31: /* LWC1 */
2237 case 0x35: /* LDC1 */
2238 case 0x39: /* SWC1 */
2239 case 0x3D: /* SDC1 */
2240 #if defined(MIPS_USES_FPU)
2241 save_cpu_state(ctx, 1);
2242 gen_op_cp1_enabled();
2243 gen_flt_ldst(ctx, op, rt, rs, imm);
2244 #else
2245 generate_exception_err(ctx, EXCP_CpU, 1);
2246 #endif
2247 break;
2248
2249 case 0x11: /* CP1 opcode */
2250 #if defined(MIPS_USES_FPU)
2251 save_cpu_state(ctx, 1);
2252 gen_op_cp1_enabled();
2253 op1 = ((ctx->opcode >> 21) & 0x1F);
2254 switch (op1) {
2255 case 0x00: /* mfc1 */
2256 case 0x02: /* cfc1 */
2257 case 0x04: /* mtc1 */
2258 case 0x06: /* ctc1 */
2259 gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
2260 break;
2261 case 0x08: /* bc */
2262 gen_compute_branch1(ctx, rt, imm << 2);
2263 return;
2264 case 0x10: /* 16: fmt=single fp */
2265 case 0x11: /* 17: fmt=double fp */
2266 case 0x14: /* 20: fmt=32bit fixed */
2267 case 0x15: /* 21: fmt=64bit fixed */
2268 gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
2269 break;
2270 default:
2271 generate_exception_err(ctx, EXCP_RI, 1);
2272 break;
2273 }
2274 break;
2275 #else
2276 generate_exception_err(ctx, EXCP_CpU, 1);
2277 #endif
2278 break;
2279
2280 /* COP2. */
2281 case 0x32: /* LWC2 */
2282 case 0x36: /* LDC2 */
2283 case 0x3A: /* SWC2 */
2284 case 0x3E: /* SDC2 */
2285 case 0x12: /* CP2 opcode */
2286 /* Not implemented */
2287 generate_exception_err(ctx, EXCP_CpU, 2);
2288 break;
2289
2290 case 0x13: /* CP3 opcode */
2291 /* Not implemented */
2292 generate_exception_err(ctx, EXCP_CpU, 3);
2293 break;
2294
2295 #if defined (TARGET_MIPS64)
2296 case 0x18 ... 0x1B:
2297 case 0x27:
2298 case 0x34:
2299 case 0x37:
2300 /* MIPS64 opcodes */
2301 #endif
2302 #if defined (MIPS_HAS_JALX)
2303 case 0x1D:
2304 /* JALX: not implemented */
2305 #endif
2306 case 0x1E:
2307 /* ASE specific */
2308 default: /* Invalid */
2309 MIPS_INVAL("");
2310 generate_exception(ctx, EXCP_RI);
2311 break;
2312 }
2313 if (ctx->hflags & MIPS_HFLAG_BMASK) {
2314 int hflags = ctx->hflags;
2315 /* Branches completion */
2316 ctx->hflags &= ~MIPS_HFLAG_BMASK;
2317 ctx->bstate = BS_BRANCH;
2318 save_cpu_state(ctx, 0);
2319 switch (hflags & MIPS_HFLAG_BMASK) {
2320 case MIPS_HFLAG_B:
2321 /* unconditional branch */
2322 MIPS_DEBUG("unconditional branch");
2323 gen_goto_tb(ctx, 0, ctx->btarget);
2324 break;
2325 case MIPS_HFLAG_BL:
2326 /* blikely taken case */
2327 MIPS_DEBUG("blikely branch taken");
2328 gen_goto_tb(ctx, 0, ctx->btarget);
2329 break;
2330 case MIPS_HFLAG_BC:
2331 /* Conditional branch */
2332 MIPS_DEBUG("conditional branch");
2333 {
2334 int l1;
2335 l1 = gen_new_label();
2336 gen_op_jnz_T2(l1);
2337 gen_goto_tb(ctx, 1, ctx->pc + 4);
2338 gen_set_label(l1);
2339 gen_goto_tb(ctx, 0, ctx->btarget);
2340 }
2341 break;
2342 case MIPS_HFLAG_BR:
2343 /* unconditional branch to register */
2344 MIPS_DEBUG("branch to register");
2345 gen_op_breg();
2346 break;
2347 default:
2348 MIPS_DEBUG("unknown branch");
2349 break;
2350 }
2351 }
2352 }
2353
2354 int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
2355 int search_pc)
2356 {
2357 DisasContext ctx, *ctxp = &ctx;
2358 target_ulong pc_start;
2359 uint16_t *gen_opc_end;
2360 int j, lj = -1;
2361
2362 if (search_pc && loglevel)
2363 fprintf (logfile, "search pc %d\n", search_pc);
2364
2365 pc_start = tb->pc;
2366 gen_opc_ptr = gen_opc_buf;
2367 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2368 gen_opparam_ptr = gen_opparam_buf;
2369 nb_gen_labels = 0;
2370 ctx.pc = pc_start;
2371 ctx.saved_pc = -1;
2372 ctx.tb = tb;
2373 ctx.bstate = BS_NONE;
2374 /* Restore delay slot state from the tb context. */
2375 ctx.hflags = tb->flags;
2376 ctx.saved_hflags = ctx.hflags;
2377 if (ctx.hflags & MIPS_HFLAG_BR) {
2378 gen_op_restore_breg_target();
2379 } else if (ctx.hflags & MIPS_HFLAG_B) {
2380 ctx.btarget = env->btarget;
2381 } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
2382 /* If we are in the delay slot of a conditional branch,
2383 * restore the branch condition from env->bcond to T2
2384 */
2385 ctx.btarget = env->btarget;
2386 gen_op_restore_bcond();
2387 }
2388 #if defined(CONFIG_USER_ONLY)
2389 ctx.mem_idx = 0;
2390 #else
2391 ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
2392 #endif
2393 ctx.CP0_Status = env->CP0_Status;
2394 #ifdef DEBUG_DISAS
2395 if (loglevel & CPU_LOG_TB_CPU) {
2396 fprintf(logfile, "------------------------------------------------\n");
2397 /* FIXME: This may print out stale hflags from env... */
2398 cpu_dump_state(env, logfile, fprintf, 0);
2399 }
2400 #endif
2401 #if defined MIPS_DEBUG_DISAS
2402 if (loglevel & CPU_LOG_TB_IN_ASM)
2403 fprintf(logfile, "\ntb %p super %d cond %04x\n",
2404 tb, ctx.mem_idx, ctx.hflags);
2405 #endif
2406 while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
2407 if (env->nb_breakpoints > 0) {
2408 for(j = 0; j < env->nb_breakpoints; j++) {
2409 if (env->breakpoints[j] == ctx.pc) {
2410 save_cpu_state(ctxp, 1);
2411 ctx.bstate = BS_BRANCH;
2412 gen_op_debug();
2413 goto done_generating;
2414 }
2415 }
2416 }
2417
2418 if (search_pc) {
2419 j = gen_opc_ptr - gen_opc_buf;
2420 if (lj < j) {
2421 lj++;
2422 while (lj < j)
2423 gen_opc_instr_start[lj++] = 0;
2424 }
2425 gen_opc_pc[lj] = ctx.pc;
2426 gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
2427 gen_opc_instr_start[lj] = 1;
2428 }
2429 ctx.opcode = ldl_code(ctx.pc);
2430 decode_opc(&ctx);
2431 ctx.pc += 4;
2432
2433 if (env->singlestep_enabled)
2434 break;
2435
2436 if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
2437 break;
2438
2439 #if defined (MIPS_SINGLE_STEP)
2440 break;
2441 #endif
2442 }
2443 if (env->singlestep_enabled) {
2444 save_cpu_state(ctxp, ctx.bstate == BS_NONE);
2445 gen_op_debug();
2446 goto done_generating;
2447 }
2448 else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
2449 save_cpu_state(ctxp, 0);
2450 gen_goto_tb(&ctx, 0, ctx.pc);
2451 }
2452 gen_op_reset_T0();
2453 /* Generate the return instruction */
2454 gen_op_exit_tb();
2455 done_generating:
2456 *gen_opc_ptr = INDEX_op_end;
2457 if (search_pc) {
2458 j = gen_opc_ptr - gen_opc_buf;
2459 lj++;
2460 while (lj <= j)
2461 gen_opc_instr_start[lj++] = 0;
2462 tb->size = 0;
2463 } else {
2464 tb->size = ctx.pc - pc_start;
2465 }
2466 #ifdef DEBUG_DISAS
2467 #if defined MIPS_DEBUG_DISAS
2468 if (loglevel & CPU_LOG_TB_IN_ASM)
2469 fprintf(logfile, "\n");
2470 #endif
2471 if (loglevel & CPU_LOG_TB_IN_ASM) {
2472 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2473 target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
2474 fprintf(logfile, "\n");
2475 }
2476 if (loglevel & CPU_LOG_TB_OP) {
2477 fprintf(logfile, "OP:\n");
2478 dump_ops(gen_opc_buf, gen_opparam_buf);
2479 fprintf(logfile, "\n");
2480 }
2481 if (loglevel & CPU_LOG_TB_CPU) {
2482 fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
2483 }
2484 #endif
2485
2486 return 0;
2487 }
2488
2489 int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
2490 {
2491 return gen_intermediate_code_internal(env, tb, 0);
2492 }
2493
2494 int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
2495 {
2496 return gen_intermediate_code_internal(env, tb, 1);
2497 }
2498
2499 #ifdef MIPS_USES_FPU
2500 void fpu_dump_state(CPUState *env, FILE *f,
2501 int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
2502 int flags)
2503 {
2504 int i;
2505
2506 # define printfpr(fp) do { \
2507 fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
2508 (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
2509 } while(0)
2510
2511 fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n",
2512 env->fcr0, env->fcr31,
2513 (env->CP0_Status & (1<<CP0St_FR)) != 0);
2514 fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
2515 fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
2516 fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
2517 for(i=0; i < 32; i+=2) {
2518 fpu_fprintf(f, "f%02d: ", i);
2519 printfpr(FPR(env, i));
2520 }
2521
2522 #undef printfpr
2523 }
2524
2525 void dump_fpu(CPUState *env)
2526 {
2527 if (loglevel) {
2528 fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
2529 env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
2530 fpu_dump_state(env, logfile, fprintf, 0);
2531 }
2532 }
2533 #endif /* MIPS_USES_FPU */
2534
2535 void cpu_dump_state (CPUState *env, FILE *f,
2536 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2537 int flags)
2538 {
2539 uint32_t c0_status;
2540 int i;
2541
2542 cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
2543 env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
2544 for (i = 0; i < 32; i++) {
2545 if ((i & 3) == 0)
2546 cpu_fprintf(f, "GPR%02d:", i);
2547 cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
2548 if ((i & 3) == 3)
2549 cpu_fprintf(f, "\n");
2550 }
2551
2552 c0_status = env->CP0_Status;
2553 if (env->hflags & MIPS_HFLAG_UM)
2554 c0_status |= (1 << CP0St_UM);
2555 if (env->hflags & MIPS_HFLAG_ERL)
2556 c0_status |= (1 << CP0St_ERL);
2557 if (env->hflags & MIPS_HFLAG_EXL)
2558 c0_status |= (1 << CP0St_EXL);
2559
2560 cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
2561 c0_status, env->CP0_Cause, env->CP0_EPC);
2562 cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
2563 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
2564 #ifdef MIPS_USES_FPU
2565 fpu_dump_state(env, f, cpu_fprintf, flags);
2566 #endif
2567 }
2568
2569 CPUMIPSState *cpu_mips_init (void)
2570 {
2571 CPUMIPSState *env;
2572
2573 env = qemu_mallocz(sizeof(CPUMIPSState));
2574 if (!env)
2575 return NULL;
2576 cpu_exec_init(env);
2577 cpu_reset(env);
2578 return env;
2579 }
2580
2581 void cpu_reset (CPUMIPSState *env)
2582 {
2583 memset(env, 0, offsetof(CPUMIPSState, breakpoints));
2584
2585 tlb_flush(env, 1);
2586
2587 /* Minimal init */
2588 env->PC = 0xBFC00000;
2589 #if defined (MIPS_USES_R4K_TLB)
2590 env->CP0_random = MIPS_TLB_NB - 1;
2591 env->tlb_in_use = MIPS_TLB_NB;
2592 #endif
2593 env->CP0_Wired = 0;
2594 env->CP0_Config0 = MIPS_CONFIG0;
2595 #if defined (MIPS_CONFIG1)
2596 env->CP0_Config1 = MIPS_CONFIG1;
2597 #endif
2598 #if defined (MIPS_CONFIG2)
2599 env->CP0_Config2 = MIPS_CONFIG2;
2600 #endif
2601 #if defined (MIPS_CONFIG3)
2602 env->CP0_Config3 = MIPS_CONFIG3;
2603 #endif
2604 env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
2605 env->CP0_WatchLo = 0;
2606 env->hflags = MIPS_HFLAG_ERL;
2607 /* Count register increments in debug mode, EJTAG version 1 */
2608 env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
2609 env->CP0_PRid = MIPS_CPU;
2610 env->exception_index = EXCP_NONE;
2611 #if defined(CONFIG_USER_ONLY)
2612 env->hflags |= MIPS_HFLAG_UM;
2613 #endif
2614 #ifdef MIPS_USES_FPU
2615 env->fcr0 = MIPS_FCR0;
2616 #endif
2617 }