Statistics
| Branch: | Revision:

root / target-mips / translate.c @ dfae6487

History | View | Annotate | Download (42.5 kB)

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