]> git.proxmox.com Git - qemu.git/blame - target-mips/translate.c
Fix comment typo.
[qemu.git] / target-mips / translate.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS32 emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
6ea83fed 5 * Copyright (c) 2006 Marius Groeger (FPU operations)
6af0bf9c
FB
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
eeef26cd 32//#define MIPS_DEBUG_DISAS
6af0bf9c
FB
33//#define MIPS_SINGLE_STEP
34
c53be334
FB
35#ifdef USE_DIRECT_JUMP
36#define TBPARAM(x)
37#else
38#define TBPARAM(x) (long)(x)
39#endif
40
6af0bf9c
FB
41enum {
42#define DEF(s, n, copy_size) INDEX_op_ ## s,
43#include "opc.h"
44#undef DEF
45 NB_OPS,
46};
47
48static uint16_t *gen_opc_ptr;
49static uint32_t *gen_opparam_ptr;
50
51#include "gen-op.h"
52
e37e863f
FB
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
62enum {
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,
d796321b 100 OPC_LWU = 0x27,
e37e863f
FB
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 */
123enum {
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
177enum {
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 */
192enum {
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
209enum {
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
6ea83fed
FB
222#ifdef MIPS_USES_FPU
223enum {
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
6af0bf9c
FB
232const 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) \
240static GenOpFunc *NAME ## _table [32] = { \
241NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
242NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
243NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
244NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
245NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
246NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
247NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
248NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
249}; \
250static inline void func(int n) \
251{ \
252 NAME ## _table[n](); \
253}
254
255/* General purpose registers moves */
256GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
257GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
258GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
259
260GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
261GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
262
6ea83fed
FB
263#ifdef MIPS_USES_FPU
264const 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) \
271static GenOpFunc *NAME ## _table [32] = { \
272NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
273NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
274NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
275NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
276NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
277NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
278NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
279NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
280}; \
281static inline void func(int n) \
282{ \
283 NAME ## _table[n](); \
284}
285
286# define DFGEN32(func, NAME) \
287static GenOpFunc *NAME ## _table [32] = { \
288NAME ## 0, 0, NAME ## 2, 0, \
289NAME ## 4, 0, NAME ## 6, 0, \
290NAME ## 8, 0, NAME ## 10, 0, \
291NAME ## 12, 0, NAME ## 14, 0, \
292NAME ## 16, 0, NAME ## 18, 0, \
293NAME ## 20, 0, NAME ## 22, 0, \
294NAME ## 24, 0, NAME ## 26, 0, \
295NAME ## 28, 0, NAME ## 30, 0, \
296}; \
297static inline void func(int n) \
298{ \
299 NAME ## _table[n](); \
300}
301
302SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
303SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
304
305SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
306SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
307
308SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
309SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
310
311DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
312DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
313
314DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
315DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
316
317DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
318DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
319
320#define FOP_CONDS(fmt) \
321static 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}; \
339static inline void gen_cmp_ ## fmt(int n) \
340{ \
341 cond_ ## fmt ## _table[n](); \
342}
343
344FOP_CONDS(d)
345FOP_CONDS(s)
346
347#endif
348
6af0bf9c
FB
349typedef 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
361enum {
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...) \
372do { \
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) \
383do { \
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) \
389do { \
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) \
398do { \
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) \
407do { \
408 if (Rn != 0) { \
409 glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
410 } \
411} while (0)
412
6ea83fed
FB
413#ifdef MIPS_USES_FPU
414
415# define GEN_LOAD_FREG_FTN(FTn, Fn) \
416do { \
417 glue(gen_op_load_fpr_, FTn)(Fn); \
418} while (0)
419
420#define GEN_STORE_FTN_FREG(Fn, FTn) \
421do { \
422 glue(gen_op_store_fpr_, FTn)(Fn); \
423} while (0)
424
425#endif
426
6af0bf9c
FB
427static 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
4ad40f36 453static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
6af0bf9c
FB
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);
4ad40f36
FB
460 if (err == 0)
461 gen_op_raise_exception(excp);
462 else
463 gen_op_raise_exception_err(excp, err);
6af0bf9c
FB
464 ctx->bstate = BS_EXCP;
465}
466
4ad40f36
FB
467static inline void generate_exception (DisasContext *ctx, int excp)
468{
469 generate_exception_err (ctx, excp, 0);
470}
471
6af0bf9c
FB
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) \
479static GenOpFunc *gen_op_l##width[] = { \
480 &gen_op_l##width##_user, \
481 &gen_op_l##width##_kernel, \
482}
483#define OP_ST_TABLE(width) \
484static 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
491OP_LD_TABLE(d);
492OP_LD_TABLE(dl);
493OP_LD_TABLE(dr);
494OP_ST_TABLE(d);
495OP_ST_TABLE(dl);
496OP_ST_TABLE(dr);
497#endif
498OP_LD_TABLE(w);
d796321b 499OP_LD_TABLE(wu);
6af0bf9c
FB
500OP_LD_TABLE(wl);
501OP_LD_TABLE(wr);
502OP_ST_TABLE(w);
503OP_ST_TABLE(wl);
504OP_ST_TABLE(wr);
505OP_LD_TABLE(h);
506OP_LD_TABLE(hu);
507OP_ST_TABLE(h);
508OP_LD_TABLE(b);
509OP_LD_TABLE(bu);
510OP_ST_TABLE(b);
511OP_LD_TABLE(l);
512OP_ST_TABLE(c);
6ea83fed
FB
513#ifdef MIPS_USES_FPU
514OP_LD_TABLE(wc1);
515OP_ST_TABLE(wc1);
516OP_LD_TABLE(dc1);
517OP_ST_TABLE(dc1);
518#endif
6af0bf9c
FB
519
520/* Load and store */
521static 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;
d796321b
FB
585 case OPC_LWU:
586 op_ldst(lwu);
587 GEN_STORE_TN_REG(rt, T0);
588 opn = "lwu";
589 break;
6af0bf9c
FB
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:
9d1d106a 638 GEN_LOAD_REG_TN(T1, rt);
6af0bf9c
FB
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:
9d1d106a 649 GEN_LOAD_REG_TN(T1, rt);
6af0bf9c
FB
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
6ea83fed
FB
678#ifdef MIPS_USES_FPU
679
680/* Load and store */
681static 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
6af0bf9c
FB
728/* Arithmetic with immediate operand */
729static 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 */
809static 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 */
901static 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
939static 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
987static 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 */
1018static 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
6e256c93 1113static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
c53be334 1114{
6e256c93
FB
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 }
c53be334
FB
1130}
1131
6af0bf9c
FB
1132/* Branches (before delay slot) */
1133static 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 */
bc9ed47b 1178 btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
6af0bf9c
FB
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 */
4ad40f36 1205 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
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;
4ad40f36 1212 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
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 */
6af0bf9c
FB
1218 /* Treated as NOP */
1219 MIPS_DEBUG("bnever (NOP)");
1220 return;
eeef26cd
FB
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;
6af0bf9c
FB
1230 case OPC_BNEL: /* rx != rx likely */
1231 case OPC_BGTZL: /* 0 > 0 likely */
6af0bf9c
FB
1232 case OPC_BLTZL: /* 0 < 0 likely */
1233 /* Skip the instruction in the delay slot */
1234 MIPS_DEBUG("bnever and skip");
6e256c93 1235 gen_goto_tb(ctx, 0, ctx->pc + 4);
6af0bf9c
FB
1236 return;
1237 case OPC_J:
4ad40f36 1238 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1239 MIPS_DEBUG("j %08x", btarget);
1240 break;
1241 case OPC_JAL:
1242 blink = 31;
4ad40f36 1243 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1244 MIPS_DEBUG("jal %08x", btarget);
1245 break;
1246 case OPC_JR:
4ad40f36 1247 ctx->hflags |= MIPS_HFLAG_BR;
6af0bf9c
FB
1248 MIPS_DEBUG("jr %s", regnames[rs]);
1249 break;
1250 case OPC_JALR:
1251 blink = rt;
4ad40f36 1252 ctx->hflags |= MIPS_HFLAG_BR;
6af0bf9c
FB
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:
4ad40f36 1329 ctx->hflags |= MIPS_HFLAG_BC;
6af0bf9c
FB
1330 break;
1331 case OPC_BLTZALL:
1332 gen_op_ltz();
1333 blink = 31;
1334 MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1335 likely:
4ad40f36 1336 ctx->hflags |= MIPS_HFLAG_BL;
6af0bf9c
FB
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) */
1352static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1353{
1354 const unsigned char *opn = "unk";
1355
bc2c3909 1356 if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
cd7dd10f 1357 (ctx->hflags & MIPS_HFLAG_UM) &&
bc2c3909
FB
1358 !(ctx->hflags & MIPS_HFLAG_ERL) &&
1359 !(ctx->hflags & MIPS_HFLAG_EXL)) {
6af0bf9c
FB
1360 if (loglevel & CPU_LOG_TB_IN_ASM) {
1361 fprintf(logfile, "CP0 is not usable\n");
1362 }
4ad40f36 1363 generate_exception_err (ctx, EXCP_CpU, 0);
6af0bf9c
FB
1364 return;
1365 }
d796321b 1366
6af0bf9c
FB
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;
4ad40f36
FB
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;
6af0bf9c
FB
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
6ea83fed
FB
1443#ifdef MIPS_USES_FPU
1444/* CP1 Branches (before delay slot) */
1445static 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
6af0bf9c 1487/* Coprocessor 1 (FPU) */
6ea83fed
FB
1488static 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
1558static 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
6af0bf9c
FB
1843
1844/* ISA extensions */
1845/* MIPS16 extension to MIPS32 */
1846/* SmartMIPS extension to MIPS32 */
1847
1848#ifdef TARGET_MIPS64
1849static 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
c53be334
FB
1880static void gen_blikely(DisasContext *ctx)
1881{
eeef26cd
FB
1882 int l1;
1883 l1 = gen_new_label();
1884 gen_op_jnz_T2(l1);
4ad40f36 1885 gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
eeef26cd
FB
1886 gen_goto_tb(ctx, 1, ctx->pc + 4);
1887 gen_set_label(l1);
c53be334
FB
1888}
1889
6af0bf9c
FB
1890static 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
d796321b
FB
1897 /* make sure instructions are on a word boundary */
1898 if (ctx->pc & 0x3) {
1899 generate_exception(ctx, EXCP_AdEL);
1900 return;
1901 }
1902
4ad40f36 1903 if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
6af0bf9c
FB
1904 /* Handle blikely not taken case */
1905 MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
c53be334 1906 gen_blikely(ctx);
6af0bf9c
FB
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;
4ad40f36 1959
6af0bf9c 1960 case 0x01: /* MOVCI */
4ad40f36
FB
1961#if defined (MIPS_HAS_MOVCI)
1962 /* XXX */
1963#else
1964 /* Not implemented */
1965 generate_exception_err (ctx, EXCP_CpU, 1);
6af0bf9c 1966#endif
4ad40f36
FB
1967 break;
1968
6af0bf9c
FB
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:
4ad40f36 2043 gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
6af0bf9c
FB
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;
d796321b 2058 case 0x20 ... 0x2E: /* Load and stores */
6af0bf9c
FB
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;
4ad40f36
FB
2071
2072 /* Floating point. */
2073 case 0x31: /* LWC1 */
2074 case 0x35: /* LDC1 */
2075 case 0x39: /* SWC1 */
2076 case 0x3D: /* SDC1 */
6ea83fed
FB
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
4ad40f36 2085 case 0x11: /* CP1 opcode */
6af0bf9c 2086#if defined(MIPS_USES_FPU)
6ea83fed
FB
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;
4ad40f36
FB
2110#else
2111 generate_exception_err(ctx, EXCP_CpU, 1);
6af0bf9c 2112#endif
4ad40f36
FB
2113 break;
2114
2115 /* COP2. */
2116 case 0x32: /* LWC2 */
2117 case 0x36: /* LDC2 */
2118 case 0x3A: /* SWC2 */
2119 case 0x3E: /* SDC2 */
6af0bf9c
FB
2120 case 0x12: /* CP2 opcode */
2121 /* Not implemented */
4ad40f36
FB
2122 generate_exception_err(ctx, EXCP_CpU, 2);
2123 break;
2124
6af0bf9c
FB
2125 case 0x13: /* CP3 opcode */
2126 /* Not implemented */
4ad40f36
FB
2127 generate_exception_err(ctx, EXCP_CpU, 3);
2128 break;
2129
6af0bf9c
FB
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 */
6af0bf9c
FB
2143 default: /* Invalid */
2144 MIPS_INVAL("");
2145 generate_exception(ctx, EXCP_RI);
2146 break;
2147 }
4ad40f36 2148 if (ctx->hflags & MIPS_HFLAG_BMASK) {
6af0bf9c
FB
2149 int hflags = ctx->hflags;
2150 /* Branches completion */
4ad40f36 2151 ctx->hflags &= ~MIPS_HFLAG_BMASK;
6af0bf9c
FB
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");
6e256c93 2158 gen_goto_tb(ctx, 0, ctx->btarget);
6af0bf9c
FB
2159 break;
2160 case MIPS_HFLAG_BL:
2161 /* blikely taken case */
2162 MIPS_DEBUG("blikely branch taken");
6e256c93 2163 gen_goto_tb(ctx, 0, ctx->btarget);
6af0bf9c
FB
2164 break;
2165 case MIPS_HFLAG_BC:
2166 /* Conditional branch */
2167 MIPS_DEBUG("conditional branch");
c53be334
FB
2168 {
2169 int l1;
2170 l1 = gen_new_label();
2171 gen_op_jnz_T2(l1);
6e256c93 2172 gen_goto_tb(ctx, 1, ctx->pc + 4);
eeef26cd
FB
2173 gen_set_label(l1);
2174 gen_goto_tb(ctx, 0, ctx->btarget);
c53be334 2175 }
6af0bf9c
FB
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
2189int 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
4ad40f36 2197 if (search_pc && loglevel)
6ea83fed 2198 fprintf (logfile, "search pc %d\n", search_pc);
4ad40f36 2199
6af0bf9c
FB
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;
c53be334 2204 nb_gen_labels = 0;
6af0bf9c 2205 ctx.pc = pc_start;
4ad40f36 2206 ctx.saved_pc = -1;
6af0bf9c
FB
2207 ctx.tb = tb;
2208 ctx.bstate = BS_NONE;
4ad40f36
FB
2209 /* Restore delay slot state from the tb context. */
2210 ctx.hflags = tb->flags;
6af0bf9c
FB
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
3d9fb9fe 2226 ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
6af0bf9c
FB
2227#endif
2228 ctx.CP0_Status = env->CP0_Status;
2229#ifdef DEBUG_DISAS
2230 if (loglevel & CPU_LOG_TB_CPU) {
2231 fprintf(logfile, "------------------------------------------------\n");
4ad40f36 2232 /* FIXME: This may print out stale hflags from env... */
6af0bf9c
FB
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)
4ad40f36
FB
2238 fprintf(logfile, "\ntb %p super %d cond %04x\n",
2239 tb, ctx.mem_idx, ctx.hflags);
6af0bf9c
FB
2240#endif
2241 while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
4ad40f36
FB
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
6af0bf9c
FB
2253 if (search_pc) {
2254 j = gen_opc_ptr - gen_opc_buf;
6af0bf9c
FB
2255 if (lj < j) {
2256 lj++;
2257 while (lj < j)
2258 gen_opc_instr_start[lj++] = 0;
6af0bf9c 2259 }
4ad40f36
FB
2260 gen_opc_pc[lj] = ctx.pc;
2261 gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
2262 gen_opc_instr_start[lj] = 1;
6af0bf9c
FB
2263 }
2264 ctx.opcode = ldl_code(ctx.pc);
2265 decode_opc(&ctx);
2266 ctx.pc += 4;
4ad40f36
FB
2267
2268 if (env->singlestep_enabled)
2269 break;
2270
6af0bf9c
FB
2271 if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
2272 break;
4ad40f36 2273
6af0bf9c
FB
2274#if defined (MIPS_SINGLE_STEP)
2275 break;
2276#endif
2277 }
4ad40f36
FB
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) {
6af0bf9c 2284 save_cpu_state(ctxp, 0);
6e256c93 2285 gen_goto_tb(&ctx, 0, ctx.pc);
6af0bf9c
FB
2286 }
2287 gen_op_reset_T0();
2288 /* Generate the return instruction */
2289 gen_op_exit_tb();
4ad40f36 2290done_generating:
6af0bf9c
FB
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));
6ea83fed 2308 target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
6af0bf9c
FB
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
2324int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
2325{
2326 return gen_intermediate_code_internal(env, tb, 0);
2327}
2328
2329int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
2330{
2331 return gen_intermediate_code_internal(env, tb, 1);
2332}
2333
6ea83fed
FB
2334#ifdef MIPS_USES_FPU
2335void 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
2360void 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
6af0bf9c
FB
2370void cpu_dump_state (CPUState *env, FILE *f,
2371 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2372 int flags)
2373{
568b600d 2374 uint32_t c0_status;
6af0bf9c
FB
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 }
568b600d
FB
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
6af0bf9c 2395 cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
568b600d 2396 c0_status, env->CP0_Cause, env->CP0_EPC);
6af0bf9c
FB
2397 cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
2398 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
6ea83fed
FB
2399#ifdef MIPS_USES_FPU
2400 fpu_dump_state(env, f, cpu_fprintf, flags);
2401#endif
6af0bf9c
FB
2402}
2403
2404CPUMIPSState *cpu_mips_init (void)
2405{
2406 CPUMIPSState *env;
2407
6af0bf9c
FB
2408 env = qemu_mallocz(sizeof(CPUMIPSState));
2409 if (!env)
2410 return NULL;
173d6cfe 2411 cpu_exec_init(env);
6af0bf9c
FB
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;
eeef26cd
FB
2436#if defined(CONFIG_USER_ONLY)
2437 env->hflags |= MIPS_HFLAG_UM;
6ea83fed
FB
2438#endif
2439#ifdef MIPS_USES_FPU
2440 env->fcr0 = MIPS_FCR0;
eeef26cd 2441#endif
6af0bf9c
FB
2442 return env;
2443}