Statistics
| Branch: | Revision:

root / target-mips / translate.c @ 9d1d106a

History | View | Annotate | Download (42.6 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 9d1d106a bellard
        GEN_LOAD_REG_TN(T1, rt);
333 6af0bf9c bellard
        op_ldst(lwl);
334 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
335 6af0bf9c bellard
        opn = "lwl";
336 6af0bf9c bellard
        break;
337 6af0bf9c bellard
    case OPC_SWL:
338 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
339 6af0bf9c bellard
        op_ldst(swl);
340 6af0bf9c bellard
        opn = "swr";
341 6af0bf9c bellard
        break;
342 6af0bf9c bellard
    case OPC_LWR:
343 9d1d106a bellard
        GEN_LOAD_REG_TN(T1, rt);
344 6af0bf9c bellard
        op_ldst(lwr);
345 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
346 6af0bf9c bellard
        opn = "lwr";
347 6af0bf9c bellard
        break;
348 6af0bf9c bellard
    case OPC_SWR:
349 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
350 6af0bf9c bellard
        op_ldst(swr);
351 6af0bf9c bellard
        opn = "swr";
352 6af0bf9c bellard
        break;
353 6af0bf9c bellard
    case OPC_LL:
354 6af0bf9c bellard
        op_ldst(ll);
355 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
356 6af0bf9c bellard
        opn = "ll";
357 6af0bf9c bellard
        break;
358 6af0bf9c bellard
    case OPC_SC:
359 6af0bf9c bellard
        GEN_LOAD_REG_TN(T1, rt);
360 6af0bf9c bellard
        op_ldst(sc);
361 6af0bf9c bellard
        GEN_STORE_TN_REG(rt, T0);
362 6af0bf9c bellard
        opn = "sc";
363 6af0bf9c bellard
        break;
364 6af0bf9c bellard
    default:
365 6af0bf9c bellard
        MIPS_INVAL("load/store");
366 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
367 6af0bf9c bellard
        return;
368 6af0bf9c bellard
    }
369 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
370 6af0bf9c bellard
}
371 6af0bf9c bellard
372 6af0bf9c bellard
/* Arithmetic with immediate operand */
373 6af0bf9c bellard
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
374 6af0bf9c bellard
                           int rs, int16_t imm)
375 6af0bf9c bellard
{
376 6af0bf9c bellard
    uint32_t uimm;
377 6af0bf9c bellard
    const unsigned char *opn = "unk";
378 6af0bf9c bellard
379 6af0bf9c bellard
    if (rt == 0 && opc != OPC_ADDI) {
380 6af0bf9c bellard
        /* if no destination, treat it as a NOP 
381 6af0bf9c bellard
         * For addi, we must generate the overflow exception when needed.
382 6af0bf9c bellard
         */
383 6af0bf9c bellard
        MIPS_DEBUG("NOP");
384 6af0bf9c bellard
        return;
385 6af0bf9c bellard
    }
386 6af0bf9c bellard
    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
387 6af0bf9c bellard
        opc == OPC_SLTI || opc == OPC_SLTIU)
388 6af0bf9c bellard
        uimm = (int32_t)imm; /* Sign extent to 32 bits */
389 6af0bf9c bellard
    else
390 6af0bf9c bellard
        uimm = (uint16_t)imm;
391 6af0bf9c bellard
    if (opc != OPC_LUI) {
392 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, rs);
393 6af0bf9c bellard
        GEN_LOAD_IMM_TN(T1, uimm);
394 6af0bf9c bellard
    } else {
395 6af0bf9c bellard
        uimm = uimm << 16;
396 6af0bf9c bellard
        GEN_LOAD_IMM_TN(T0, uimm);
397 6af0bf9c bellard
    }
398 6af0bf9c bellard
    switch (opc) {
399 6af0bf9c bellard
    case OPC_ADDI:
400 6af0bf9c bellard
        save_cpu_state(ctx, 1);
401 6af0bf9c bellard
        gen_op_addo();
402 6af0bf9c bellard
        opn = "addi";
403 6af0bf9c bellard
        break;
404 6af0bf9c bellard
    case OPC_ADDIU:
405 6af0bf9c bellard
        gen_op_add();
406 6af0bf9c bellard
        opn = "addiu";
407 6af0bf9c bellard
        break;
408 6af0bf9c bellard
    case OPC_SLTI:
409 6af0bf9c bellard
        gen_op_lt();
410 6af0bf9c bellard
        opn = "slti";
411 6af0bf9c bellard
        break;
412 6af0bf9c bellard
    case OPC_SLTIU:
413 6af0bf9c bellard
        gen_op_ltu();
414 6af0bf9c bellard
        opn = "sltiu";
415 6af0bf9c bellard
        break;
416 6af0bf9c bellard
    case OPC_ANDI:
417 6af0bf9c bellard
        gen_op_and();
418 6af0bf9c bellard
        opn = "andi";
419 6af0bf9c bellard
        break;
420 6af0bf9c bellard
    case OPC_ORI:
421 6af0bf9c bellard
        gen_op_or();
422 6af0bf9c bellard
        opn = "ori";
423 6af0bf9c bellard
        break;
424 6af0bf9c bellard
    case OPC_XORI:
425 6af0bf9c bellard
        gen_op_xor();
426 6af0bf9c bellard
        opn = "xori";
427 6af0bf9c bellard
        break;
428 6af0bf9c bellard
    case OPC_LUI:
429 6af0bf9c bellard
        opn = "lui";
430 6af0bf9c bellard
        break;
431 6af0bf9c bellard
    case OPC_SLL:
432 6af0bf9c bellard
        gen_op_sll();
433 6af0bf9c bellard
        opn = "sll";
434 6af0bf9c bellard
        break;
435 6af0bf9c bellard
    case OPC_SRA:
436 6af0bf9c bellard
        gen_op_sra();
437 6af0bf9c bellard
        opn = "sra";
438 6af0bf9c bellard
        break;
439 6af0bf9c bellard
    case OPC_SRL:
440 6af0bf9c bellard
        gen_op_srl();
441 6af0bf9c bellard
        opn = "srl";
442 6af0bf9c bellard
        break;
443 6af0bf9c bellard
    default:
444 6af0bf9c bellard
        MIPS_INVAL("imm arith");
445 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
446 6af0bf9c bellard
        return;
447 6af0bf9c bellard
    }
448 6af0bf9c bellard
    GEN_STORE_TN_REG(rt, T0);
449 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
450 6af0bf9c bellard
}
451 6af0bf9c bellard
452 6af0bf9c bellard
/* Arithmetic */
453 6af0bf9c bellard
static void gen_arith (DisasContext *ctx, uint16_t opc,
454 6af0bf9c bellard
                       int rd, int rs, int rt)
455 6af0bf9c bellard
{
456 6af0bf9c bellard
    const unsigned char *opn = "unk";
457 6af0bf9c bellard
458 6af0bf9c bellard
    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
459 6af0bf9c bellard
        /* if no destination, treat it as a NOP 
460 6af0bf9c bellard
         * For add & sub, we must generate the overflow exception when needed.
461 6af0bf9c bellard
         */
462 6af0bf9c bellard
        MIPS_DEBUG("NOP");
463 6af0bf9c bellard
        return;
464 6af0bf9c bellard
    }
465 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
466 6af0bf9c bellard
    GEN_LOAD_REG_TN(T1, rt);
467 6af0bf9c bellard
    switch (opc) {
468 6af0bf9c bellard
    case OPC_ADD:
469 6af0bf9c bellard
        save_cpu_state(ctx, 1);
470 6af0bf9c bellard
        gen_op_addo();
471 6af0bf9c bellard
        opn = "add";
472 6af0bf9c bellard
        break;
473 6af0bf9c bellard
    case OPC_ADDU:
474 6af0bf9c bellard
        gen_op_add();
475 6af0bf9c bellard
        opn = "addu";
476 6af0bf9c bellard
        break;
477 6af0bf9c bellard
    case OPC_SUB:
478 6af0bf9c bellard
        save_cpu_state(ctx, 1);
479 6af0bf9c bellard
        gen_op_subo();
480 6af0bf9c bellard
        opn = "sub";
481 6af0bf9c bellard
        break;
482 6af0bf9c bellard
    case OPC_SUBU:
483 6af0bf9c bellard
        gen_op_sub();
484 6af0bf9c bellard
        opn = "subu";
485 6af0bf9c bellard
        break;
486 6af0bf9c bellard
    case OPC_SLT:
487 6af0bf9c bellard
        gen_op_lt();
488 6af0bf9c bellard
        opn = "slt";
489 6af0bf9c bellard
        break;
490 6af0bf9c bellard
    case OPC_SLTU:
491 6af0bf9c bellard
        gen_op_ltu();
492 6af0bf9c bellard
        opn = "sltu";
493 6af0bf9c bellard
        break;
494 6af0bf9c bellard
    case OPC_AND:
495 6af0bf9c bellard
        gen_op_and();
496 6af0bf9c bellard
        opn = "and";
497 6af0bf9c bellard
        break;
498 6af0bf9c bellard
    case OPC_NOR:
499 6af0bf9c bellard
        gen_op_nor();
500 6af0bf9c bellard
        opn = "nor";
501 6af0bf9c bellard
        break;
502 6af0bf9c bellard
    case OPC_OR:
503 6af0bf9c bellard
        gen_op_or();
504 6af0bf9c bellard
        opn = "or";
505 6af0bf9c bellard
        break;
506 6af0bf9c bellard
    case OPC_XOR:
507 6af0bf9c bellard
        gen_op_xor();
508 6af0bf9c bellard
        opn = "xor";
509 6af0bf9c bellard
        break;
510 6af0bf9c bellard
    case OPC_MUL:
511 6af0bf9c bellard
        gen_op_mul();
512 6af0bf9c bellard
        opn = "mul";
513 6af0bf9c bellard
        break;
514 6af0bf9c bellard
    case OPC_MOVN:
515 6af0bf9c bellard
        gen_op_movn(rd);
516 6af0bf9c bellard
        opn = "movn";
517 6af0bf9c bellard
        goto print;
518 6af0bf9c bellard
    case OPC_MOVZ:
519 6af0bf9c bellard
        gen_op_movz(rd);
520 6af0bf9c bellard
        opn = "movz";
521 6af0bf9c bellard
        goto print;
522 6af0bf9c bellard
    case OPC_SLLV:
523 6af0bf9c bellard
        gen_op_sllv();
524 6af0bf9c bellard
        opn = "sllv";
525 6af0bf9c bellard
        break;
526 6af0bf9c bellard
    case OPC_SRAV:
527 6af0bf9c bellard
        gen_op_srav();
528 6af0bf9c bellard
        opn = "srav";
529 6af0bf9c bellard
        break;
530 6af0bf9c bellard
    case OPC_SRLV:
531 6af0bf9c bellard
        gen_op_srlv();
532 6af0bf9c bellard
        opn = "srlv";
533 6af0bf9c bellard
        break;
534 6af0bf9c bellard
    default:
535 6af0bf9c bellard
        MIPS_INVAL("arith");
536 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
537 6af0bf9c bellard
        return;
538 6af0bf9c bellard
    }
539 6af0bf9c bellard
    GEN_STORE_TN_REG(rd, T0);
540 6af0bf9c bellard
 print:
541 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
542 6af0bf9c bellard
}
543 6af0bf9c bellard
544 6af0bf9c bellard
/* Arithmetic on HI/LO registers */
545 6af0bf9c bellard
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
546 6af0bf9c bellard
{
547 6af0bf9c bellard
    const unsigned char *opn = "unk";
548 6af0bf9c bellard
549 6af0bf9c bellard
    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
550 6af0bf9c bellard
        /* Treat as a NOP */
551 6af0bf9c bellard
        MIPS_DEBUG("NOP");
552 6af0bf9c bellard
        return;
553 6af0bf9c bellard
    }
554 6af0bf9c bellard
    switch (opc) {
555 6af0bf9c bellard
    case OPC_MFHI:
556 6af0bf9c bellard
        gen_op_load_HI();
557 6af0bf9c bellard
        GEN_STORE_TN_REG(reg, T0);
558 6af0bf9c bellard
        opn = "mfhi";
559 6af0bf9c bellard
        break;
560 6af0bf9c bellard
    case OPC_MFLO:
561 6af0bf9c bellard
        gen_op_load_LO();
562 6af0bf9c bellard
        GEN_STORE_TN_REG(reg, T0);
563 6af0bf9c bellard
        opn = "mflo";
564 6af0bf9c bellard
        break;
565 6af0bf9c bellard
    case OPC_MTHI:
566 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, reg);
567 6af0bf9c bellard
        gen_op_store_HI();
568 6af0bf9c bellard
        opn = "mthi";
569 6af0bf9c bellard
        break;
570 6af0bf9c bellard
    case OPC_MTLO:
571 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, reg);
572 6af0bf9c bellard
        gen_op_store_LO();
573 6af0bf9c bellard
        opn = "mtlo";
574 6af0bf9c bellard
        break;
575 6af0bf9c bellard
    default:
576 6af0bf9c bellard
        MIPS_INVAL("HILO");
577 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
578 6af0bf9c bellard
        return;
579 6af0bf9c bellard
    }
580 6af0bf9c bellard
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
581 6af0bf9c bellard
}
582 6af0bf9c bellard
583 6af0bf9c bellard
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
584 6af0bf9c bellard
                        int rs, int rt)
585 6af0bf9c bellard
{
586 6af0bf9c bellard
    const unsigned char *opn = "unk";
587 6af0bf9c bellard
588 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
589 6af0bf9c bellard
    GEN_LOAD_REG_TN(T1, rt);
590 6af0bf9c bellard
    switch (opc) {
591 6af0bf9c bellard
    case OPC_DIV:
592 6af0bf9c bellard
        gen_op_div();
593 6af0bf9c bellard
        opn = "div";
594 6af0bf9c bellard
        break;
595 6af0bf9c bellard
    case OPC_DIVU:
596 6af0bf9c bellard
        gen_op_divu();
597 6af0bf9c bellard
        opn = "divu";
598 6af0bf9c bellard
        break;
599 6af0bf9c bellard
    case OPC_MULT:
600 6af0bf9c bellard
        gen_op_mult();
601 6af0bf9c bellard
        opn = "mult";
602 6af0bf9c bellard
        break;
603 6af0bf9c bellard
    case OPC_MULTU:
604 6af0bf9c bellard
        gen_op_multu();
605 6af0bf9c bellard
        opn = "multu";
606 6af0bf9c bellard
        break;
607 6af0bf9c bellard
    case OPC_MADD:
608 6af0bf9c bellard
        gen_op_madd();
609 6af0bf9c bellard
        opn = "madd";
610 6af0bf9c bellard
        break;
611 6af0bf9c bellard
    case OPC_MADDU:
612 6af0bf9c bellard
        gen_op_maddu();
613 6af0bf9c bellard
        opn = "maddu";
614 6af0bf9c bellard
        break;
615 6af0bf9c bellard
    case OPC_MSUB:
616 6af0bf9c bellard
        gen_op_msub();
617 6af0bf9c bellard
        opn = "msub";
618 6af0bf9c bellard
        break;
619 6af0bf9c bellard
    case OPC_MSUBU:
620 6af0bf9c bellard
        gen_op_msubu();
621 6af0bf9c bellard
        opn = "msubu";
622 6af0bf9c bellard
        break;
623 6af0bf9c bellard
    default:
624 6af0bf9c bellard
        MIPS_INVAL("mul/div");
625 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
626 6af0bf9c bellard
        return;
627 6af0bf9c bellard
    }
628 6af0bf9c bellard
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
629 6af0bf9c bellard
}
630 6af0bf9c bellard
631 6af0bf9c bellard
static void gen_cl (DisasContext *ctx, uint16_t opc,
632 6af0bf9c bellard
                    int rd, int rs)
633 6af0bf9c bellard
{
634 6af0bf9c bellard
    const unsigned char *opn = "unk";
635 6af0bf9c bellard
    if (rd == 0) {
636 6af0bf9c bellard
        /* Treat as a NOP */
637 6af0bf9c bellard
        MIPS_DEBUG("NOP");
638 6af0bf9c bellard
        return;
639 6af0bf9c bellard
    }
640 6af0bf9c bellard
    GEN_LOAD_REG_TN(T0, rs);
641 6af0bf9c bellard
    switch (opc) {
642 6af0bf9c bellard
    case OPC_CLO:
643 6af0bf9c bellard
        /* CLO */
644 6af0bf9c bellard
        gen_op_clo();
645 6af0bf9c bellard
        opn = "clo";
646 6af0bf9c bellard
        break;
647 6af0bf9c bellard
    case OPC_CLZ:
648 6af0bf9c bellard
        /* CLZ */
649 6af0bf9c bellard
        gen_op_clz();
650 6af0bf9c bellard
        opn = "clz";
651 6af0bf9c bellard
        break;
652 6af0bf9c bellard
    default:
653 6af0bf9c bellard
        MIPS_INVAL("CLx");
654 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
655 6af0bf9c bellard
        return;
656 6af0bf9c bellard
    }
657 6af0bf9c bellard
    gen_op_store_T0_gpr(rd);
658 6af0bf9c bellard
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
659 6af0bf9c bellard
}
660 6af0bf9c bellard
661 6af0bf9c bellard
/* Traps */
662 6af0bf9c bellard
static void gen_trap (DisasContext *ctx, uint16_t opc,
663 6af0bf9c bellard
                      int rs, int rt, int16_t imm)
664 6af0bf9c bellard
{
665 6af0bf9c bellard
    int cond;
666 6af0bf9c bellard
667 6af0bf9c bellard
    cond = 0;
668 6af0bf9c bellard
    /* Load needed operands */
669 6af0bf9c bellard
    switch (opc) {
670 6af0bf9c bellard
    case OPC_TEQ:
671 6af0bf9c bellard
    case OPC_TGE:
672 6af0bf9c bellard
    case OPC_TGEU:
673 6af0bf9c bellard
    case OPC_TLT:
674 6af0bf9c bellard
    case OPC_TLTU:
675 6af0bf9c bellard
    case OPC_TNE:
676 6af0bf9c bellard
        /* Compare two registers */
677 6af0bf9c bellard
        if (rs != rt) {
678 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
679 6af0bf9c bellard
            GEN_LOAD_REG_TN(T1, rt);
680 6af0bf9c bellard
            cond = 1;
681 6af0bf9c bellard
        }
682 6af0bf9c bellard
    case OPC_TEQI:
683 6af0bf9c bellard
    case OPC_TGEI:
684 6af0bf9c bellard
    case OPC_TGEIU:
685 6af0bf9c bellard
    case OPC_TLTI:
686 6af0bf9c bellard
    case OPC_TLTIU:
687 6af0bf9c bellard
    case OPC_TNEI:
688 6af0bf9c bellard
        /* Compare register to immediate */
689 6af0bf9c bellard
        if (rs != 0 || imm != 0) {
690 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
691 6af0bf9c bellard
            GEN_LOAD_IMM_TN(T1, (int32_t)imm);
692 6af0bf9c bellard
            cond = 1;
693 6af0bf9c bellard
        }
694 6af0bf9c bellard
        break;
695 6af0bf9c bellard
    }
696 6af0bf9c bellard
    if (cond == 0) {
697 6af0bf9c bellard
        switch (opc) {
698 6af0bf9c bellard
        case OPC_TEQ:   /* rs == rs */
699 6af0bf9c bellard
        case OPC_TEQI:  /* r0 == 0  */
700 6af0bf9c bellard
        case OPC_TGE:   /* rs >= rs */
701 6af0bf9c bellard
        case OPC_TGEI:  /* r0 >= 0  */
702 6af0bf9c bellard
        case OPC_TGEU:  /* rs >= rs unsigned */
703 6af0bf9c bellard
        case OPC_TGEIU: /* r0 >= 0  unsigned */
704 6af0bf9c bellard
            /* Always trap */
705 6af0bf9c bellard
            gen_op_set_T0(1);
706 6af0bf9c bellard
            break;
707 6af0bf9c bellard
        case OPC_TLT:   /* rs < rs           */
708 6af0bf9c bellard
        case OPC_TLTI:  /* r0 < 0            */
709 6af0bf9c bellard
        case OPC_TLTU:  /* rs < rs unsigned  */
710 6af0bf9c bellard
        case OPC_TLTIU: /* r0 < 0  unsigned  */
711 6af0bf9c bellard
        case OPC_TNE:   /* rs != rs          */
712 6af0bf9c bellard
        case OPC_TNEI:  /* r0 != 0           */
713 6af0bf9c bellard
            /* Never trap: treat as NOP */
714 6af0bf9c bellard
            return;
715 6af0bf9c bellard
        default:
716 6af0bf9c bellard
            MIPS_INVAL("TRAP");
717 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
718 6af0bf9c bellard
            return;
719 6af0bf9c bellard
        }
720 6af0bf9c bellard
    } else {
721 6af0bf9c bellard
        switch (opc) {
722 6af0bf9c bellard
        case OPC_TEQ:
723 6af0bf9c bellard
        case OPC_TEQI:
724 6af0bf9c bellard
            gen_op_eq();
725 6af0bf9c bellard
            break;
726 6af0bf9c bellard
        case OPC_TGE:
727 6af0bf9c bellard
        case OPC_TGEI:
728 6af0bf9c bellard
            gen_op_ge();
729 6af0bf9c bellard
            break;
730 6af0bf9c bellard
        case OPC_TGEU:
731 6af0bf9c bellard
        case OPC_TGEIU:
732 6af0bf9c bellard
            gen_op_geu();
733 6af0bf9c bellard
            break;
734 6af0bf9c bellard
        case OPC_TLT:
735 6af0bf9c bellard
        case OPC_TLTI:
736 6af0bf9c bellard
            gen_op_lt();
737 6af0bf9c bellard
            break;
738 6af0bf9c bellard
        case OPC_TLTU:
739 6af0bf9c bellard
        case OPC_TLTIU:
740 6af0bf9c bellard
            gen_op_ltu();
741 6af0bf9c bellard
            break;
742 6af0bf9c bellard
        case OPC_TNE:
743 6af0bf9c bellard
        case OPC_TNEI:
744 6af0bf9c bellard
            gen_op_ne();
745 6af0bf9c bellard
            break;
746 6af0bf9c bellard
        default:
747 6af0bf9c bellard
            MIPS_INVAL("TRAP");
748 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
749 6af0bf9c bellard
            return;
750 6af0bf9c bellard
        }
751 6af0bf9c bellard
    }
752 6af0bf9c bellard
    save_cpu_state(ctx, 1);
753 6af0bf9c bellard
    gen_op_trap();
754 6af0bf9c bellard
    ctx->bstate = BS_STOP;
755 6af0bf9c bellard
}
756 6af0bf9c bellard
757 6af0bf9c bellard
/* Branches (before delay slot) */
758 6af0bf9c bellard
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
759 6af0bf9c bellard
                                int rs, int rt, int32_t offset)
760 6af0bf9c bellard
{
761 6af0bf9c bellard
    target_ulong btarget;
762 6af0bf9c bellard
    int blink, bcond;
763 6af0bf9c bellard
764 6af0bf9c bellard
    btarget = -1;
765 6af0bf9c bellard
    blink = 0;
766 6af0bf9c bellard
    bcond = 0;
767 6af0bf9c bellard
    /* Load needed operands */
768 6af0bf9c bellard
    switch (opc) {
769 6af0bf9c bellard
    case OPC_BEQ:
770 6af0bf9c bellard
    case OPC_BEQL:
771 6af0bf9c bellard
    case OPC_BNE:
772 6af0bf9c bellard
    case OPC_BNEL:
773 6af0bf9c bellard
        /* Compare two registers */
774 6af0bf9c bellard
        if (rs != rt) {
775 6af0bf9c bellard
            GEN_LOAD_REG_TN(T0, rs);
776 6af0bf9c bellard
            GEN_LOAD_REG_TN(T1, rt);
777 6af0bf9c bellard
            bcond = 1;
778 6af0bf9c bellard
        }
779 6af0bf9c bellard
        btarget = ctx->pc + 4 + offset;
780 6af0bf9c bellard
        break;
781 6af0bf9c bellard
    case OPC_BGEZ:
782 6af0bf9c bellard
    case OPC_BGEZAL:
783 6af0bf9c bellard
    case OPC_BGEZALL:
784 6af0bf9c bellard
    case OPC_BGEZL:
785 6af0bf9c bellard
    case OPC_BGTZ:
786 6af0bf9c bellard
    case OPC_BGTZL:
787 6af0bf9c bellard
    case OPC_BLEZ:
788 6af0bf9c bellard
    case OPC_BLEZL:
789 6af0bf9c bellard
    case OPC_BLTZ:
790 6af0bf9c bellard
    case OPC_BLTZAL:
791 6af0bf9c bellard
    case OPC_BLTZALL:
792 6af0bf9c bellard
    case OPC_BLTZL:
793 6af0bf9c bellard
        /* Compare to zero */
794 6af0bf9c bellard
        if (rs != 0) {
795 6af0bf9c bellard
            gen_op_load_gpr_T0(rs);
796 6af0bf9c bellard
            bcond = 1;
797 6af0bf9c bellard
        }
798 6af0bf9c bellard
        btarget = ctx->pc + 4 + offset;
799 6af0bf9c bellard
        break;
800 6af0bf9c bellard
    case OPC_J:
801 6af0bf9c bellard
    case OPC_JAL:
802 6af0bf9c bellard
        /* Jump to immediate */
803 bc9ed47b bellard
        btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
804 6af0bf9c bellard
        break;
805 6af0bf9c bellard
    case OPC_JR:
806 6af0bf9c bellard
    case OPC_JALR:
807 6af0bf9c bellard
        /* Jump to register */
808 6af0bf9c bellard
        if (offset != 0) {
809 6af0bf9c bellard
            /* Only hint = 0 is valid */
810 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
811 6af0bf9c bellard
            return;
812 6af0bf9c bellard
        }
813 6af0bf9c bellard
        GEN_LOAD_REG_TN(T2, rs);
814 6af0bf9c bellard
        break;
815 6af0bf9c bellard
    default:
816 6af0bf9c bellard
        MIPS_INVAL("branch/jump");
817 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
818 6af0bf9c bellard
        return;
819 6af0bf9c bellard
    }
820 6af0bf9c bellard
    if (bcond == 0) {
821 6af0bf9c bellard
        /* No condition to be computed */
822 6af0bf9c bellard
        switch (opc) {
823 6af0bf9c bellard
        case OPC_BEQ:     /* rx == rx        */
824 6af0bf9c bellard
        case OPC_BEQL:    /* rx == rx likely */
825 6af0bf9c bellard
        case OPC_BGEZ:    /* 0 >= 0          */
826 6af0bf9c bellard
        case OPC_BGEZL:   /* 0 >= 0 likely   */
827 6af0bf9c bellard
        case OPC_BLEZ:    /* 0 <= 0          */
828 6af0bf9c bellard
        case OPC_BLEZL:   /* 0 <= 0 likely   */
829 6af0bf9c bellard
            /* Always take */
830 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
831 6af0bf9c bellard
            MIPS_DEBUG("balways");
832 6af0bf9c bellard
            break;
833 6af0bf9c bellard
        case OPC_BGEZAL:  /* 0 >= 0          */
834 6af0bf9c bellard
        case OPC_BGEZALL: /* 0 >= 0 likely   */
835 6af0bf9c bellard
            /* Always take and link */
836 6af0bf9c bellard
            blink = 31;
837 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
838 6af0bf9c bellard
            MIPS_DEBUG("balways and link");
839 6af0bf9c bellard
            break;
840 6af0bf9c bellard
        case OPC_BNE:     /* rx != rx        */
841 6af0bf9c bellard
        case OPC_BGTZ:    /* 0 > 0           */
842 6af0bf9c bellard
        case OPC_BLTZ:    /* 0 < 0           */
843 6af0bf9c bellard
        case OPC_BLTZAL:  /* 0 < 0           */
844 6af0bf9c bellard
            /* Treated as NOP */
845 6af0bf9c bellard
            MIPS_DEBUG("bnever (NOP)");
846 6af0bf9c bellard
            return;
847 6af0bf9c bellard
        case OPC_BNEL:    /* rx != rx likely */
848 6af0bf9c bellard
        case OPC_BGTZL:   /* 0 > 0 likely */
849 6af0bf9c bellard
        case OPC_BLTZALL: /* 0 < 0 likely */
850 6af0bf9c bellard
        case OPC_BLTZL:   /* 0 < 0 likely */
851 6af0bf9c bellard
            /* Skip the instruction in the delay slot */
852 6af0bf9c bellard
            MIPS_DEBUG("bnever and skip");
853 6af0bf9c bellard
            gen_op_branch((long)ctx->tb, ctx->pc + 4);
854 6af0bf9c bellard
            return;
855 6af0bf9c bellard
        case OPC_J:
856 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
857 6af0bf9c bellard
            MIPS_DEBUG("j %08x", btarget);
858 6af0bf9c bellard
            break;
859 6af0bf9c bellard
        case OPC_JAL:
860 6af0bf9c bellard
            blink = 31;
861 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
862 6af0bf9c bellard
            MIPS_DEBUG("jal %08x", btarget);
863 6af0bf9c bellard
            break;
864 6af0bf9c bellard
        case OPC_JR:
865 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
866 6af0bf9c bellard
            MIPS_DEBUG("jr %s", regnames[rs]);
867 6af0bf9c bellard
            break;
868 6af0bf9c bellard
        case OPC_JALR:
869 6af0bf9c bellard
            blink = rt;
870 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
871 6af0bf9c bellard
            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
872 6af0bf9c bellard
            break;
873 6af0bf9c bellard
        default:
874 6af0bf9c bellard
            MIPS_INVAL("branch/jump");
875 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
876 6af0bf9c bellard
            return;
877 6af0bf9c bellard
        }
878 6af0bf9c bellard
    } else {
879 6af0bf9c bellard
        switch (opc) {
880 6af0bf9c bellard
        case OPC_BEQ:
881 6af0bf9c bellard
            gen_op_eq();
882 6af0bf9c bellard
            MIPS_DEBUG("beq %s, %s, %08x",
883 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
884 6af0bf9c bellard
            goto not_likely;
885 6af0bf9c bellard
        case OPC_BEQL:
886 6af0bf9c bellard
            gen_op_eq();
887 6af0bf9c bellard
            MIPS_DEBUG("beql %s, %s, %08x",
888 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
889 6af0bf9c bellard
            goto likely;
890 6af0bf9c bellard
        case OPC_BNE:
891 6af0bf9c bellard
            gen_op_ne();
892 6af0bf9c bellard
            MIPS_DEBUG("bne %s, %s, %08x",
893 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
894 6af0bf9c bellard
            goto not_likely;
895 6af0bf9c bellard
        case OPC_BNEL:
896 6af0bf9c bellard
            gen_op_ne();
897 6af0bf9c bellard
            MIPS_DEBUG("bnel %s, %s, %08x",
898 6af0bf9c bellard
                       regnames[rs], regnames[rt], btarget);
899 6af0bf9c bellard
            goto likely;
900 6af0bf9c bellard
        case OPC_BGEZ:
901 6af0bf9c bellard
            gen_op_gez();
902 6af0bf9c bellard
            MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
903 6af0bf9c bellard
            goto not_likely;
904 6af0bf9c bellard
        case OPC_BGEZL:
905 6af0bf9c bellard
            gen_op_gez();
906 6af0bf9c bellard
            MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
907 6af0bf9c bellard
            goto likely;
908 6af0bf9c bellard
        case OPC_BGEZAL:
909 6af0bf9c bellard
            gen_op_gez();
910 6af0bf9c bellard
            MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
911 6af0bf9c bellard
            blink = 31;
912 6af0bf9c bellard
            goto not_likely;
913 6af0bf9c bellard
        case OPC_BGEZALL:
914 6af0bf9c bellard
            gen_op_gez();
915 6af0bf9c bellard
            blink = 31;
916 6af0bf9c bellard
            MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
917 6af0bf9c bellard
            goto likely;
918 6af0bf9c bellard
        case OPC_BGTZ:
919 6af0bf9c bellard
            gen_op_gtz();
920 6af0bf9c bellard
            MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
921 6af0bf9c bellard
            goto not_likely;
922 6af0bf9c bellard
        case OPC_BGTZL:
923 6af0bf9c bellard
            gen_op_gtz();
924 6af0bf9c bellard
            MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
925 6af0bf9c bellard
            goto likely;
926 6af0bf9c bellard
        case OPC_BLEZ:
927 6af0bf9c bellard
            gen_op_lez();
928 6af0bf9c bellard
            MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
929 6af0bf9c bellard
            goto not_likely;
930 6af0bf9c bellard
        case OPC_BLEZL:
931 6af0bf9c bellard
            gen_op_lez();
932 6af0bf9c bellard
            MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
933 6af0bf9c bellard
            goto likely;
934 6af0bf9c bellard
        case OPC_BLTZ:
935 6af0bf9c bellard
            gen_op_ltz();
936 6af0bf9c bellard
            MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
937 6af0bf9c bellard
            goto not_likely;
938 6af0bf9c bellard
        case OPC_BLTZL:
939 6af0bf9c bellard
            gen_op_ltz();
940 6af0bf9c bellard
            MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
941 6af0bf9c bellard
            goto likely;
942 6af0bf9c bellard
        case OPC_BLTZAL:
943 6af0bf9c bellard
            gen_op_ltz();
944 6af0bf9c bellard
            blink = 31;
945 6af0bf9c bellard
            MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
946 6af0bf9c bellard
        not_likely:
947 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC;
948 6af0bf9c bellard
            break;
949 6af0bf9c bellard
        case OPC_BLTZALL:
950 6af0bf9c bellard
            gen_op_ltz();
951 6af0bf9c bellard
            blink = 31;
952 6af0bf9c bellard
            MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
953 6af0bf9c bellard
        likely:
954 6af0bf9c bellard
            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL;
955 6af0bf9c bellard
            break;
956 6af0bf9c bellard
        }
957 6af0bf9c bellard
        gen_op_set_bcond();
958 6af0bf9c bellard
    }
959 6af0bf9c bellard
    MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
960 6af0bf9c bellard
               blink, ctx->hflags, btarget);
961 6af0bf9c bellard
    ctx->btarget = btarget;
962 6af0bf9c bellard
    if (blink > 0) {
963 6af0bf9c bellard
        gen_op_set_T0(ctx->pc + 8);
964 6af0bf9c bellard
        gen_op_store_T0_gpr(blink);
965 6af0bf9c bellard
    }
966 6af0bf9c bellard
    return;
967 6af0bf9c bellard
}
968 6af0bf9c bellard
969 6af0bf9c bellard
/* CP0 (MMU and control) */
970 6af0bf9c bellard
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
971 6af0bf9c bellard
{
972 6af0bf9c bellard
    const unsigned char *opn = "unk";
973 6af0bf9c bellard
974 6af0bf9c bellard
    if (!(ctx->CP0_Status & (1 << CP0St_CU0))) {
975 6af0bf9c bellard
        if (loglevel & CPU_LOG_TB_IN_ASM) {
976 6af0bf9c bellard
            fprintf(logfile, "CP0 is not usable\n");
977 6af0bf9c bellard
        }
978 6af0bf9c bellard
        gen_op_raise_exception_err(EXCP_CpU, 0);
979 6af0bf9c bellard
        return;
980 6af0bf9c bellard
    }
981 6af0bf9c bellard
    switch (opc) {
982 6af0bf9c bellard
    case OPC_MFC0:
983 6af0bf9c bellard
        if (rt == 0) {
984 6af0bf9c bellard
            /* Treat as NOP */
985 6af0bf9c bellard
            return;
986 6af0bf9c bellard
        }
987 6af0bf9c bellard
        gen_op_mfc0(rd, ctx->opcode & 0x7);
988 6af0bf9c bellard
        gen_op_store_T0_gpr(rt);
989 6af0bf9c bellard
        opn = "mfc0";
990 6af0bf9c bellard
        break;
991 6af0bf9c bellard
    case OPC_MTC0:
992 6af0bf9c bellard
        /* If we get an exception, we want to restart at next instruction */
993 6af0bf9c bellard
        ctx->pc += 4;
994 6af0bf9c bellard
        save_cpu_state(ctx, 1);
995 6af0bf9c bellard
        ctx->pc -= 4;
996 6af0bf9c bellard
        GEN_LOAD_REG_TN(T0, rt);
997 6af0bf9c bellard
        gen_op_mtc0(rd, ctx->opcode & 0x7);
998 6af0bf9c bellard
        /* Stop translation as we may have switched the execution mode */
999 6af0bf9c bellard
        ctx->bstate = BS_STOP;
1000 6af0bf9c bellard
        opn = "mtc0";
1001 6af0bf9c bellard
        break;
1002 6af0bf9c bellard
#if defined(MIPS_USES_R4K_TLB)
1003 6af0bf9c bellard
    case OPC_TLBWI:
1004 6af0bf9c bellard
        gen_op_tlbwi();
1005 6af0bf9c bellard
        opn = "tlbwi";
1006 6af0bf9c bellard
        break;
1007 6af0bf9c bellard
    case OPC_TLBWR:
1008 6af0bf9c bellard
        gen_op_tlbwr();
1009 6af0bf9c bellard
        opn = "tlbwr";
1010 6af0bf9c bellard
        break;
1011 6af0bf9c bellard
    case OPC_TLBP:
1012 6af0bf9c bellard
        gen_op_tlbp();
1013 6af0bf9c bellard
        opn = "tlbp";
1014 6af0bf9c bellard
        break;
1015 6af0bf9c bellard
    case OPC_TLBR:
1016 6af0bf9c bellard
        gen_op_tlbr();
1017 6af0bf9c bellard
        opn = "tlbr";
1018 6af0bf9c bellard
        break;
1019 6af0bf9c bellard
#endif
1020 6af0bf9c bellard
    case OPC_ERET:
1021 6af0bf9c bellard
        opn = "eret";
1022 6af0bf9c bellard
        save_cpu_state(ctx, 0);
1023 6af0bf9c bellard
        gen_op_eret();
1024 6af0bf9c bellard
        ctx->bstate = BS_EXCP;
1025 6af0bf9c bellard
        break;
1026 6af0bf9c bellard
    case OPC_DERET:
1027 6af0bf9c bellard
        opn = "deret";
1028 6af0bf9c bellard
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1029 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1030 6af0bf9c bellard
        } else {
1031 6af0bf9c bellard
            save_cpu_state(ctx, 0);
1032 6af0bf9c bellard
            gen_op_deret();
1033 6af0bf9c bellard
            ctx->bstate = BS_EXCP;
1034 6af0bf9c bellard
        }
1035 6af0bf9c bellard
        break;
1036 6af0bf9c bellard
    /* XXX: TODO: WAIT */
1037 6af0bf9c bellard
    default:
1038 6af0bf9c bellard
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1039 6af0bf9c bellard
            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1040 6af0bf9c bellard
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1041 6af0bf9c bellard
                    ((ctx->opcode >> 16) & 0x1F));
1042 6af0bf9c bellard
        }
1043 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
1044 6af0bf9c bellard
        return;
1045 6af0bf9c bellard
    }
1046 6af0bf9c bellard
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1047 6af0bf9c bellard
}
1048 6af0bf9c bellard
1049 6af0bf9c bellard
/* Coprocessor 1 (FPU) */
1050 6af0bf9c bellard
1051 6af0bf9c bellard
/* ISA extensions */
1052 6af0bf9c bellard
/* MIPS16 extension to MIPS32 */
1053 6af0bf9c bellard
/* SmartMIPS extension to MIPS32 */
1054 6af0bf9c bellard
1055 6af0bf9c bellard
#ifdef TARGET_MIPS64
1056 6af0bf9c bellard
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1057 6af0bf9c bellard
{
1058 6af0bf9c bellard
    if (func == 0x02 && rd == 0) {
1059 6af0bf9c bellard
        /* NOP */
1060 6af0bf9c bellard
        return;
1061 6af0bf9c bellard
    }
1062 6af0bf9c bellard
    if (rs == 0 || rt == 0) {
1063 6af0bf9c bellard
        gen_op_reset_T0();
1064 6af0bf9c bellard
        gen_op_save64();
1065 6af0bf9c bellard
    } else {
1066 6af0bf9c bellard
        gen_op_load_gpr_T0(rs);
1067 6af0bf9c bellard
        gen_op_load_gpr_T1(rt);
1068 6af0bf9c bellard
        gen_op_save64();
1069 6af0bf9c bellard
        if (func & 0x01)
1070 6af0bf9c bellard
            gen_op_mul64u();
1071 6af0bf9c bellard
        else
1072 6af0bf9c bellard
            gen_op_mul64s();
1073 6af0bf9c bellard
    }
1074 6af0bf9c bellard
    if (func & 0x02)
1075 6af0bf9c bellard
        gen_op_add64();
1076 6af0bf9c bellard
    else
1077 6af0bf9c bellard
        gen_op_sub64();
1078 6af0bf9c bellard
}
1079 6af0bf9c bellard
1080 6af0bf9c bellard
/* Coprocessor 3 (FPU) */
1081 6af0bf9c bellard
1082 6af0bf9c bellard
/* MDMX extension to MIPS64 */
1083 6af0bf9c bellard
/* MIPS-3D extension to MIPS64 */
1084 6af0bf9c bellard
1085 6af0bf9c bellard
#endif
1086 6af0bf9c bellard
1087 6af0bf9c bellard
static void decode_opc (DisasContext *ctx)
1088 6af0bf9c bellard
{
1089 6af0bf9c bellard
    int32_t offset;
1090 6af0bf9c bellard
    int rs, rt, rd, sa;
1091 6af0bf9c bellard
    uint16_t op, op1;
1092 6af0bf9c bellard
    int16_t imm;
1093 6af0bf9c bellard
1094 6af0bf9c bellard
    if ((ctx->hflags & MIPS_HFLAG_DS) &&
1095 6af0bf9c bellard
        (ctx->hflags & MIPS_HFLAG_BL)) {
1096 6af0bf9c bellard
        /* Handle blikely not taken case */
1097 6af0bf9c bellard
        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1098 6af0bf9c bellard
        gen_op_blikely((long)ctx->tb, ctx->pc + 4,
1099 6af0bf9c bellard
                       ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
1100 6af0bf9c bellard
    }
1101 6af0bf9c bellard
    op = ctx->opcode >> 26;
1102 6af0bf9c bellard
    rs = ((ctx->opcode >> 21) & 0x1F);
1103 6af0bf9c bellard
    rt = ((ctx->opcode >> 16) & 0x1F);
1104 6af0bf9c bellard
    rd = ((ctx->opcode >> 11) & 0x1F);
1105 6af0bf9c bellard
    sa = ((ctx->opcode >> 6) & 0x1F);
1106 6af0bf9c bellard
    imm = (int16_t)ctx->opcode;
1107 6af0bf9c bellard
    switch (op) {
1108 6af0bf9c bellard
    case 0x00:          /* Special opcode */
1109 6af0bf9c bellard
        op1 = ctx->opcode & 0x3F;
1110 6af0bf9c bellard
        switch (op1) {
1111 6af0bf9c bellard
        case 0x00:          /* Arithmetic with immediate */
1112 6af0bf9c bellard
        case 0x02 ... 0x03:
1113 6af0bf9c bellard
            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1114 6af0bf9c bellard
            break;
1115 6af0bf9c bellard
        case 0x04:          /* Arithmetic */
1116 6af0bf9c bellard
        case 0x06 ... 0x07:
1117 6af0bf9c bellard
        case 0x0A ... 0x0B:
1118 6af0bf9c bellard
        case 0x20 ... 0x27:
1119 6af0bf9c bellard
        case 0x2A ... 0x2B:
1120 6af0bf9c bellard
            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1121 6af0bf9c bellard
            break;
1122 6af0bf9c bellard
        case 0x18 ... 0x1B: /* MULT / DIV */
1123 6af0bf9c bellard
            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1124 6af0bf9c bellard
            break;
1125 6af0bf9c bellard
        case 0x08 ... 0x09: /* Jumps */
1126 6af0bf9c bellard
            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1127 6af0bf9c bellard
            return;
1128 6af0bf9c bellard
        case 0x30 ... 0x34: /* Traps */
1129 6af0bf9c bellard
        case 0x36:
1130 6af0bf9c bellard
            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1131 6af0bf9c bellard
            break;
1132 6af0bf9c bellard
        case 0x10:          /* Move from HI/LO */
1133 6af0bf9c bellard
        case 0x12:
1134 6af0bf9c bellard
            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1135 6af0bf9c bellard
            break;
1136 6af0bf9c bellard
        case 0x11:
1137 6af0bf9c bellard
        case 0x13:          /* Move to HI/LO */
1138 6af0bf9c bellard
            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1139 6af0bf9c bellard
            break;
1140 6af0bf9c bellard
        case 0x0C:          /* SYSCALL */
1141 6af0bf9c bellard
            generate_exception(ctx, EXCP_SYSCALL);
1142 6af0bf9c bellard
            break;
1143 6af0bf9c bellard
        case 0x0D:          /* BREAK */
1144 6af0bf9c bellard
            generate_exception(ctx, EXCP_BREAK);
1145 6af0bf9c bellard
            break;
1146 6af0bf9c bellard
        case 0x0F:          /* SYNC */
1147 6af0bf9c bellard
            /* Treat as a noop */
1148 6af0bf9c bellard
            break;
1149 6af0bf9c bellard
        case 0x05:          /* Pmon entry point */
1150 6af0bf9c bellard
            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1151 6af0bf9c bellard
            break;
1152 6af0bf9c bellard
#if defined (MIPS_HAS_MOVCI)
1153 6af0bf9c bellard
        case 0x01:          /* MOVCI */
1154 6af0bf9c bellard
#endif
1155 6af0bf9c bellard
#if defined (TARGET_MIPS64)
1156 6af0bf9c bellard
        case 0x14: /* MIPS64 specific opcodes */
1157 6af0bf9c bellard
        case 0x16:
1158 6af0bf9c bellard
        case 0x17:
1159 6af0bf9c bellard
        case 0x1C ... 0x1F:
1160 6af0bf9c bellard
        case 0x2C ... 0x2F:
1161 6af0bf9c bellard
        case 0x37:
1162 6af0bf9c bellard
        case 0x39 ... 0x3B:
1163 6af0bf9c bellard
        case 0x3E ... 0x3F:
1164 6af0bf9c bellard
#endif
1165 6af0bf9c bellard
        default:            /* Invalid */
1166 6af0bf9c bellard
            MIPS_INVAL("special");
1167 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1168 6af0bf9c bellard
            break;
1169 6af0bf9c bellard
        }
1170 6af0bf9c bellard
        break;
1171 6af0bf9c bellard
    case 0x1C:          /* Special2 opcode */
1172 6af0bf9c bellard
        op1 = ctx->opcode & 0x3F;
1173 6af0bf9c bellard
        switch (op1) {
1174 6af0bf9c bellard
#if defined (MIPS_USES_R4K_EXT)
1175 6af0bf9c bellard
        /* Those instructions are not part of MIPS32 core */
1176 6af0bf9c bellard
        case 0x00 ... 0x01: /* Multiply and add/sub */
1177 6af0bf9c bellard
        case 0x04 ... 0x05:
1178 6af0bf9c bellard
            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1179 6af0bf9c bellard
            break;
1180 6af0bf9c bellard
        case 0x02:          /* MUL */
1181 6af0bf9c bellard
            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1182 6af0bf9c bellard
            break;
1183 6af0bf9c bellard
        case 0x20 ... 0x21: /* CLO / CLZ */
1184 6af0bf9c bellard
            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1185 6af0bf9c bellard
            break;
1186 6af0bf9c bellard
#endif
1187 6af0bf9c bellard
        case 0x3F:          /* SDBBP */
1188 6af0bf9c bellard
            /* XXX: not clear which exception should be raised
1189 6af0bf9c bellard
             *      when in debug mode...
1190 6af0bf9c bellard
             */
1191 6af0bf9c bellard
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1192 6af0bf9c bellard
                generate_exception(ctx, EXCP_DBp);
1193 6af0bf9c bellard
            } else {
1194 6af0bf9c bellard
                generate_exception(ctx, EXCP_DBp);
1195 6af0bf9c bellard
            }
1196 6af0bf9c bellard
            /* Treat as a noop */
1197 6af0bf9c bellard
            break;
1198 6af0bf9c bellard
        default:            /* Invalid */
1199 6af0bf9c bellard
            MIPS_INVAL("special2");
1200 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1201 6af0bf9c bellard
            break;
1202 6af0bf9c bellard
        }
1203 6af0bf9c bellard
        break;
1204 6af0bf9c bellard
    case 0x01:          /* B REGIMM opcode */
1205 6af0bf9c bellard
        op1 = ((ctx->opcode >> 16) & 0x1F);
1206 6af0bf9c bellard
        switch (op1) {
1207 6af0bf9c bellard
        case 0x00 ... 0x03: /* REGIMM branches */
1208 6af0bf9c bellard
        case 0x10 ... 0x13:
1209 6af0bf9c bellard
            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
1210 6af0bf9c bellard
            return;
1211 6af0bf9c bellard
        case 0x08 ... 0x0C: /* Traps */
1212 6af0bf9c bellard
        case 0x0E:
1213 6af0bf9c bellard
            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
1214 6af0bf9c bellard
            break;
1215 6af0bf9c bellard
        default:            /* Invalid */
1216 6af0bf9c bellard
            MIPS_INVAL("REGIMM");
1217 6af0bf9c bellard
            generate_exception(ctx, EXCP_RI);
1218 6af0bf9c bellard
            break;
1219 6af0bf9c bellard
        }
1220 6af0bf9c bellard
        break;
1221 6af0bf9c bellard
    case 0x10:          /* CP0 opcode */
1222 6af0bf9c bellard
        op1 = ((ctx->opcode >> 21) & 0x1F);
1223 6af0bf9c bellard
        switch (op1) {
1224 6af0bf9c bellard
        case 0x00:
1225 6af0bf9c bellard
        case 0x04:
1226 6af0bf9c bellard
            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
1227 6af0bf9c bellard
            break;
1228 6af0bf9c bellard
        default:
1229 6af0bf9c bellard
            gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd);
1230 6af0bf9c bellard
            break;
1231 6af0bf9c bellard
        }
1232 6af0bf9c bellard
        break;
1233 6af0bf9c bellard
    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
1234 6af0bf9c bellard
        gen_arith_imm(ctx, op, rt, rs, imm);
1235 6af0bf9c bellard
        break;
1236 6af0bf9c bellard
    case 0x02 ... 0x03: /* Jump */
1237 6af0bf9c bellard
        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
1238 6af0bf9c bellard
        gen_compute_branch(ctx, op, rs, rt, offset);
1239 6af0bf9c bellard
        return;
1240 6af0bf9c bellard
    case 0x04 ... 0x07: /* Branch */
1241 6af0bf9c bellard
    case 0x14 ... 0x17:
1242 6af0bf9c bellard
        gen_compute_branch(ctx, op, rs, rt, imm << 2);
1243 6af0bf9c bellard
        return;
1244 6af0bf9c bellard
    case 0x20 ... 0x26: /* Load and stores */
1245 6af0bf9c bellard
    case 0x28 ... 0x2E:
1246 6af0bf9c bellard
    case 0x30:
1247 6af0bf9c bellard
    case 0x38:
1248 6af0bf9c bellard
        gen_ldst(ctx, op, rt, rs, imm);
1249 6af0bf9c bellard
        break;
1250 6af0bf9c bellard
    case 0x2F:          /* Cache operation */
1251 6af0bf9c bellard
        /* Treat as a noop */
1252 6af0bf9c bellard
        break;
1253 6af0bf9c bellard
    case 0x33:          /* Prefetch */
1254 6af0bf9c bellard
        /* Treat as a noop */
1255 6af0bf9c bellard
        break;
1256 6af0bf9c bellard
    case 0x3F: /* HACK */
1257 6af0bf9c bellard
        break;
1258 6af0bf9c bellard
#if defined(MIPS_USES_FPU)
1259 6af0bf9c bellard
    case 0x31 ... 0x32: /* Floating point load/store */
1260 6af0bf9c bellard
    case 0x35 ... 0x36:
1261 6af0bf9c bellard
    case 0x3A ... 0x3B:
1262 6af0bf9c bellard
    case 0x3D ... 0x3E:
1263 6af0bf9c bellard
        /* Not implemented */
1264 6af0bf9c bellard
        /* XXX: not correct */
1265 6af0bf9c bellard
#endif
1266 6af0bf9c bellard
    case 0x11:          /* CP1 opcode */
1267 6af0bf9c bellard
        /* Not implemented */
1268 6af0bf9c bellard
        /* XXX: not correct */
1269 6af0bf9c bellard
    case 0x12:          /* CP2 opcode */
1270 6af0bf9c bellard
        /* Not implemented */
1271 6af0bf9c bellard
        /* XXX: not correct */
1272 6af0bf9c bellard
    case 0x13:          /* CP3 opcode */
1273 6af0bf9c bellard
        /* Not implemented */
1274 6af0bf9c bellard
        /* XXX: not correct */
1275 6af0bf9c bellard
#if defined (TARGET_MIPS64)
1276 6af0bf9c bellard
    case 0x18 ... 0x1B:
1277 6af0bf9c bellard
    case 0x27:
1278 6af0bf9c bellard
    case 0x34:
1279 6af0bf9c bellard
    case 0x37:
1280 6af0bf9c bellard
        /* MIPS64 opcodes */
1281 6af0bf9c bellard
#endif
1282 6af0bf9c bellard
#if defined (MIPS_HAS_JALX)
1283 6af0bf9c bellard
    case 0x1D:
1284 6af0bf9c bellard
        /* JALX: not implemented */
1285 6af0bf9c bellard
#endif
1286 6af0bf9c bellard
    case 0x1E:
1287 6af0bf9c bellard
        /* ASE specific */
1288 6af0bf9c bellard
#if defined (MIPS_HAS_LSC)
1289 6af0bf9c bellard
    case 0x31: /* LWC1 */
1290 6af0bf9c bellard
    case 0x32: /* LWC2 */
1291 6af0bf9c bellard
    case 0x35: /* SDC1 */
1292 6af0bf9c bellard
    case 0x36: /* SDC2 */
1293 6af0bf9c bellard
#endif
1294 6af0bf9c bellard
    default:            /* Invalid */
1295 6af0bf9c bellard
        MIPS_INVAL("");
1296 6af0bf9c bellard
        generate_exception(ctx, EXCP_RI);
1297 6af0bf9c bellard
        break;
1298 6af0bf9c bellard
    }
1299 6af0bf9c bellard
    if (ctx->hflags & MIPS_HFLAG_DS) {
1300 6af0bf9c bellard
        int hflags = ctx->hflags;
1301 6af0bf9c bellard
        /* Branches completion */
1302 6af0bf9c bellard
        ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS);
1303 6af0bf9c bellard
        ctx->bstate = BS_BRANCH;
1304 6af0bf9c bellard
        save_cpu_state(ctx, 0);
1305 6af0bf9c bellard
        switch (hflags & MIPS_HFLAG_BMASK) {
1306 6af0bf9c bellard
        case MIPS_HFLAG_B:
1307 6af0bf9c bellard
            /* unconditional branch */
1308 6af0bf9c bellard
            MIPS_DEBUG("unconditional branch");
1309 6af0bf9c bellard
            gen_op_branch((long)ctx->tb, ctx->btarget);
1310 6af0bf9c bellard
            break;
1311 6af0bf9c bellard
        case MIPS_HFLAG_BL:
1312 6af0bf9c bellard
            /* blikely taken case */
1313 6af0bf9c bellard
            MIPS_DEBUG("blikely branch taken");
1314 6af0bf9c bellard
            gen_op_branch((long)ctx->tb, ctx->btarget);
1315 6af0bf9c bellard
            break;
1316 6af0bf9c bellard
        case MIPS_HFLAG_BC:
1317 6af0bf9c bellard
            /* Conditional branch */
1318 6af0bf9c bellard
            MIPS_DEBUG("conditional branch");
1319 6af0bf9c bellard
            gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4);
1320 6af0bf9c bellard
            break;
1321 6af0bf9c bellard
        case MIPS_HFLAG_BR:
1322 6af0bf9c bellard
            /* unconditional branch to register */
1323 6af0bf9c bellard
            MIPS_DEBUG("branch to register");
1324 6af0bf9c bellard
            gen_op_breg();
1325 6af0bf9c bellard
            break;
1326 6af0bf9c bellard
        default:
1327 6af0bf9c bellard
            MIPS_DEBUG("unknown branch");
1328 6af0bf9c bellard
            break;
1329 6af0bf9c bellard
        }
1330 6af0bf9c bellard
    }
1331 6af0bf9c bellard
}
1332 6af0bf9c bellard
1333 6af0bf9c bellard
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1334 6af0bf9c bellard
                                    int search_pc)
1335 6af0bf9c bellard
{
1336 6af0bf9c bellard
    DisasContext ctx, *ctxp = &ctx;
1337 6af0bf9c bellard
    target_ulong pc_start;
1338 6af0bf9c bellard
    uint16_t *gen_opc_end;
1339 6af0bf9c bellard
    int j, lj = -1;
1340 6af0bf9c bellard
1341 6af0bf9c bellard
    pc_start = tb->pc;
1342 6af0bf9c bellard
    gen_opc_ptr = gen_opc_buf;
1343 6af0bf9c bellard
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1344 6af0bf9c bellard
    gen_opparam_ptr = gen_opparam_buf;
1345 6af0bf9c bellard
    ctx.pc = pc_start;
1346 6af0bf9c bellard
    ctx.tb = tb;
1347 6af0bf9c bellard
    ctx.bstate = BS_NONE;
1348 6af0bf9c bellard
    /* Restore delay slot state */
1349 6af0bf9c bellard
    ctx.hflags = env->hflags;
1350 6af0bf9c bellard
    ctx.saved_hflags = ctx.hflags;
1351 6af0bf9c bellard
    if (ctx.hflags & MIPS_HFLAG_BR) {
1352 6af0bf9c bellard
        gen_op_restore_breg_target();
1353 6af0bf9c bellard
    } else if (ctx.hflags & MIPS_HFLAG_B) {
1354 6af0bf9c bellard
        ctx.btarget = env->btarget;
1355 6af0bf9c bellard
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1356 6af0bf9c bellard
        /* If we are in the delay slot of a conditional branch,
1357 6af0bf9c bellard
         * restore the branch condition from env->bcond to T2
1358 6af0bf9c bellard
         */
1359 6af0bf9c bellard
        ctx.btarget = env->btarget;
1360 6af0bf9c bellard
        gen_op_restore_bcond();
1361 6af0bf9c bellard
    }
1362 6af0bf9c bellard
#if defined(CONFIG_USER_ONLY)
1363 6af0bf9c bellard
    ctx.mem_idx = 0;
1364 6af0bf9c bellard
#else
1365 6af0bf9c bellard
    ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
1366 6af0bf9c bellard
#endif
1367 6af0bf9c bellard
    ctx.CP0_Status = env->CP0_Status;
1368 6af0bf9c bellard
#ifdef DEBUG_DISAS
1369 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_CPU) {
1370 6af0bf9c bellard
        fprintf(logfile, "------------------------------------------------\n");
1371 6af0bf9c bellard
        cpu_dump_state(env, logfile, fprintf, 0);
1372 6af0bf9c bellard
    }
1373 6af0bf9c bellard
#endif
1374 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
1375 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM)
1376 6af0bf9c bellard
        fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
1377 6af0bf9c bellard
                tb, ctx.mem_idx, ctx.hflags, env->hflags);
1378 6af0bf9c bellard
#endif
1379 6af0bf9c bellard
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1380 6af0bf9c bellard
        if (search_pc) {
1381 6af0bf9c bellard
            j = gen_opc_ptr - gen_opc_buf;
1382 6af0bf9c bellard
            save_cpu_state(ctxp, 1);
1383 6af0bf9c bellard
            if (lj < j) {
1384 6af0bf9c bellard
                lj++;
1385 6af0bf9c bellard
                while (lj < j)
1386 6af0bf9c bellard
                    gen_opc_instr_start[lj++] = 0;
1387 6af0bf9c bellard
                gen_opc_pc[lj] = ctx.pc;
1388 6af0bf9c bellard
                gen_opc_instr_start[lj] = 1;
1389 6af0bf9c bellard
            }
1390 6af0bf9c bellard
        }
1391 6af0bf9c bellard
        ctx.opcode = ldl_code(ctx.pc);
1392 6af0bf9c bellard
        decode_opc(&ctx);
1393 6af0bf9c bellard
        ctx.pc += 4;
1394 6af0bf9c bellard
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1395 6af0bf9c bellard
            break;
1396 6af0bf9c bellard
#if defined (MIPS_SINGLE_STEP)
1397 6af0bf9c bellard
        break;
1398 6af0bf9c bellard
#endif
1399 6af0bf9c bellard
    }
1400 6af0bf9c bellard
    if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1401 6af0bf9c bellard
        save_cpu_state(ctxp, 0);
1402 6af0bf9c bellard
        gen_op_branch((long)ctx.tb, ctx.pc);
1403 6af0bf9c bellard
    }
1404 6af0bf9c bellard
    gen_op_reset_T0();
1405 6af0bf9c bellard
    /* Generate the return instruction */
1406 6af0bf9c bellard
    gen_op_exit_tb();
1407 6af0bf9c bellard
    *gen_opc_ptr = INDEX_op_end;
1408 6af0bf9c bellard
    if (search_pc) {
1409 6af0bf9c bellard
        j = gen_opc_ptr - gen_opc_buf;
1410 6af0bf9c bellard
        lj++;
1411 6af0bf9c bellard
        while (lj <= j)
1412 6af0bf9c bellard
            gen_opc_instr_start[lj++] = 0;
1413 6af0bf9c bellard
        tb->size = 0;
1414 6af0bf9c bellard
    } else {
1415 6af0bf9c bellard
        tb->size = ctx.pc - pc_start;
1416 6af0bf9c bellard
    }
1417 6af0bf9c bellard
#ifdef DEBUG_DISAS
1418 6af0bf9c bellard
#if defined MIPS_DEBUG_DISAS
1419 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM)
1420 6af0bf9c bellard
        fprintf(logfile, "\n");
1421 6af0bf9c bellard
#endif
1422 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_IN_ASM) {
1423 6af0bf9c bellard
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1424 6af0bf9c bellard
        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1425 6af0bf9c bellard
        fprintf(logfile, "\n");
1426 6af0bf9c bellard
    }
1427 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_OP) {
1428 6af0bf9c bellard
        fprintf(logfile, "OP:\n");
1429 6af0bf9c bellard
        dump_ops(gen_opc_buf, gen_opparam_buf);
1430 6af0bf9c bellard
        fprintf(logfile, "\n");
1431 6af0bf9c bellard
    }
1432 6af0bf9c bellard
    if (loglevel & CPU_LOG_TB_CPU) {
1433 6af0bf9c bellard
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1434 6af0bf9c bellard
    }
1435 6af0bf9c bellard
#endif
1436 6af0bf9c bellard
    
1437 6af0bf9c bellard
    return 0;
1438 6af0bf9c bellard
}
1439 6af0bf9c bellard
1440 6af0bf9c bellard
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1441 6af0bf9c bellard
{
1442 6af0bf9c bellard
    return gen_intermediate_code_internal(env, tb, 0);
1443 6af0bf9c bellard
}
1444 6af0bf9c bellard
1445 6af0bf9c bellard
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1446 6af0bf9c bellard
{
1447 6af0bf9c bellard
    return gen_intermediate_code_internal(env, tb, 1);
1448 6af0bf9c bellard
}
1449 6af0bf9c bellard
1450 6af0bf9c bellard
void cpu_dump_state (CPUState *env, FILE *f, 
1451 6af0bf9c bellard
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1452 6af0bf9c bellard
                     int flags)
1453 6af0bf9c bellard
{
1454 6af0bf9c bellard
    int i;
1455 6af0bf9c bellard
    
1456 6af0bf9c bellard
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1457 6af0bf9c bellard
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1458 6af0bf9c bellard
    for (i = 0; i < 32; i++) {
1459 6af0bf9c bellard
        if ((i & 3) == 0)
1460 6af0bf9c bellard
            cpu_fprintf(f, "GPR%02d:", i);
1461 6af0bf9c bellard
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1462 6af0bf9c bellard
        if ((i & 3) == 3)
1463 6af0bf9c bellard
            cpu_fprintf(f, "\n");
1464 6af0bf9c bellard
    }
1465 6af0bf9c bellard
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
1466 6af0bf9c bellard
                env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
1467 6af0bf9c bellard
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1468 6af0bf9c bellard
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1469 6af0bf9c bellard
}
1470 6af0bf9c bellard
1471 6af0bf9c bellard
CPUMIPSState *cpu_mips_init (void)
1472 6af0bf9c bellard
{
1473 6af0bf9c bellard
    CPUMIPSState *env;
1474 6af0bf9c bellard
1475 6af0bf9c bellard
    cpu_exec_init();
1476 6af0bf9c bellard
    env = qemu_mallocz(sizeof(CPUMIPSState));
1477 6af0bf9c bellard
    if (!env)
1478 6af0bf9c bellard
        return NULL;
1479 6af0bf9c bellard
    tlb_flush(env, 1);
1480 6af0bf9c bellard
    /* Minimal init */
1481 6af0bf9c bellard
    env->PC = 0xBFC00000;
1482 6af0bf9c bellard
#if defined (MIPS_USES_R4K_TLB)
1483 6af0bf9c bellard
    env->CP0_random = MIPS_TLB_NB - 1;
1484 6af0bf9c bellard
#endif
1485 6af0bf9c bellard
    env->CP0_Wired = 0;
1486 6af0bf9c bellard
    env->CP0_Config0 = MIPS_CONFIG0;
1487 6af0bf9c bellard
#if defined (MIPS_CONFIG1)
1488 6af0bf9c bellard
        env->CP0_Config1 = MIPS_CONFIG1;
1489 6af0bf9c bellard
#endif
1490 6af0bf9c bellard
#if defined (MIPS_CONFIG2)
1491 6af0bf9c bellard
        env->CP0_Config2 = MIPS_CONFIG2;
1492 6af0bf9c bellard
#endif
1493 6af0bf9c bellard
#if defined (MIPS_CONFIG3)
1494 6af0bf9c bellard
        env->CP0_Config3 = MIPS_CONFIG3;
1495 6af0bf9c bellard
#endif
1496 6af0bf9c bellard
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1497 6af0bf9c bellard
    env->CP0_WatchLo = 0;
1498 6af0bf9c bellard
    env->hflags = MIPS_HFLAG_ERL;
1499 6af0bf9c bellard
    /* Count register increments in debug mode, EJTAG version 1 */
1500 6af0bf9c bellard
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1501 6af0bf9c bellard
    env->CP0_PRid = MIPS_CPU;
1502 6af0bf9c bellard
    env->exception_index = EXCP_NONE;
1503 6af0bf9c bellard
1504 6af0bf9c bellard
    cpu_single_env = env;
1505 6af0bf9c bellard
1506 6af0bf9c bellard
    return env;
1507 6af0bf9c bellard
}