Statistics
| Branch: | Revision:

root / target-mips / translate.c @ 417f38f0

History | View | Annotate | Download (70.5 kB)

1
/*
2
 *  MIPS32 emulation for qemu: main translation routines.
3
 * 
4
 *  Copyright (c) 2004-2005 Jocelyn Mayer
5
 *  Copyright (c) 2006 Marius Groeger (FPU operations)
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21

    
22
#include <stdarg.h>
23
#include <stdlib.h>
24
#include <stdio.h>
25
#include <string.h>
26
#include <inttypes.h>
27

    
28
#include "cpu.h"
29
#include "exec-all.h"
30
#include "disas.h"
31

    
32
//#define MIPS_DEBUG_DISAS
33
//#define MIPS_SINGLE_STEP
34

    
35
#ifdef USE_DIRECT_JUMP
36
#define TBPARAM(x)
37
#else
38
#define TBPARAM(x) (long)(x)
39
#endif
40

    
41
enum {
42
#define DEF(s, n, copy_size) INDEX_op_ ## s,
43
#include "opc.h"
44
#undef DEF
45
    NB_OPS,
46
};
47

    
48
static uint16_t *gen_opc_ptr;
49
static uint32_t *gen_opparam_ptr;
50

    
51
#include "gen-op.h"
52

    
53
/* MIPS opcodes */
54
#define EXT_SPECIAL  0x100
55
#define EXT_SPECIAL2 0x200
56
#define EXT_REGIMM   0x300
57
#define EXT_CP0      0x400
58
#define EXT_CP1      0x500
59
#define EXT_CP2      0x600
60
#define EXT_CP3      0x700
61

    
62
enum {
63
    /* indirect opcode tables */
64
    OPC_SPECIAL  = 0x00,
65
    OPC_BREGIMM  = 0x01,
66
    OPC_CP0      = 0x10,
67
    OPC_CP1      = 0x11,
68
    OPC_CP2      = 0x12,
69
    OPC_CP3      = 0x13,
70
    OPC_SPECIAL2 = 0x1C,
71
    /* arithmetic with immediate */
72
    OPC_ADDI     = 0x08,
73
    OPC_ADDIU    = 0x09,
74
    OPC_SLTI     = 0x0A,
75
    OPC_SLTIU    = 0x0B,
76
    OPC_ANDI     = 0x0C,
77
    OPC_ORI      = 0x0D,
78
    OPC_XORI     = 0x0E,
79
    OPC_LUI      = 0x0F,
80
    /* Jump and branches */
81
    OPC_J        = 0x02,
82
    OPC_JAL      = 0x03,
83
    OPC_BEQ      = 0x04,  /* Unconditional if rs = rt = 0 (B) */
84
    OPC_BEQL     = 0x14,
85
    OPC_BNE      = 0x05,
86
    OPC_BNEL     = 0x15,
87
    OPC_BLEZ     = 0x06,
88
    OPC_BLEZL    = 0x16,
89
    OPC_BGTZ     = 0x07,
90
    OPC_BGTZL    = 0x17,
91
    OPC_JALX     = 0x1D,  /* MIPS 16 only */
92
    /* Load and stores */
93
    OPC_LB       = 0x20,
94
    OPC_LH       = 0x21,
95
    OPC_LWL      = 0x22,
96
    OPC_LW       = 0x23,
97
    OPC_LBU      = 0x24,
98
    OPC_LHU      = 0x25,
99
    OPC_LWR      = 0x26,
100
    OPC_LWU      = 0x27,
101
    OPC_SB       = 0x28,
102
    OPC_SH       = 0x29,
103
    OPC_SWL      = 0x2A,
104
    OPC_SW       = 0x2B,
105
    OPC_SWR      = 0x2E,
106
    OPC_LL       = 0x30,
107
    OPC_SC       = 0x38,
108
    /* Floating point load/store */
109
    OPC_LWC1     = 0x31,
110
    OPC_LWC2     = 0x32,
111
    OPC_LDC1     = 0x35,
112
    OPC_LDC2     = 0x36,
113
    OPC_SWC1     = 0x39,
114
    OPC_SWC2     = 0x3A,
115
    OPC_SDC1     = 0x3D,
116
    OPC_SDC2     = 0x3E,
117
    /* Cache and prefetch */
118
    OPC_CACHE    = 0x2F,
119
    OPC_PREF     = 0x33,
120
};
121

    
122
/* MIPS special opcodes */
123
enum {
124
    /* Shifts */
125
    OPC_SLL      = 0x00 | EXT_SPECIAL,
126
    /* NOP is SLL r0, r0, 0   */
127
    /* SSNOP is SLL r0, r0, 1 */
128
    OPC_SRL      = 0x02 | EXT_SPECIAL,
129
    OPC_SRA      = 0x03 | EXT_SPECIAL,
130
    OPC_SLLV     = 0x04 | EXT_SPECIAL,
131
    OPC_SRLV     = 0x06 | EXT_SPECIAL,
132
    OPC_SRAV     = 0x07 | EXT_SPECIAL,
133
    /* Multiplication / division */
134
    OPC_MULT     = 0x18 | EXT_SPECIAL,
135
    OPC_MULTU    = 0x19 | EXT_SPECIAL,
136
    OPC_DIV      = 0x1A | EXT_SPECIAL,
137
    OPC_DIVU     = 0x1B | EXT_SPECIAL,
138
    /* 2 registers arithmetic / logic */
139
    OPC_ADD      = 0x20 | EXT_SPECIAL,
140
    OPC_ADDU     = 0x21 | EXT_SPECIAL,
141
    OPC_SUB      = 0x22 | EXT_SPECIAL,
142
    OPC_SUBU     = 0x23 | EXT_SPECIAL,
143
    OPC_AND      = 0x24 | EXT_SPECIAL,
144
    OPC_OR       = 0x25 | EXT_SPECIAL,
145
    OPC_XOR      = 0x26 | EXT_SPECIAL,
146
    OPC_NOR      = 0x27 | EXT_SPECIAL,
147
    OPC_SLT      = 0x2A | EXT_SPECIAL,
148
    OPC_SLTU     = 0x2B | EXT_SPECIAL,
149
    /* Jumps */
150
    OPC_JR       = 0x08 | EXT_SPECIAL,
151
    OPC_JALR     = 0x09 | EXT_SPECIAL,
152
    /* Traps */
153
    OPC_TGE      = 0x30 | EXT_SPECIAL,
154
    OPC_TGEU     = 0x31 | EXT_SPECIAL,
155
    OPC_TLT      = 0x32 | EXT_SPECIAL,
156
    OPC_TLTU     = 0x33 | EXT_SPECIAL,
157
    OPC_TEQ      = 0x34 | EXT_SPECIAL,
158
    OPC_TNE      = 0x36 | EXT_SPECIAL,
159
    /* HI / LO registers load & stores */
160
    OPC_MFHI     = 0x10 | EXT_SPECIAL,
161
    OPC_MTHI     = 0x11 | EXT_SPECIAL,
162
    OPC_MFLO     = 0x12 | EXT_SPECIAL,
163
    OPC_MTLO     = 0x13 | EXT_SPECIAL,
164
    /* Conditional moves */
165
    OPC_MOVZ     = 0x0A | EXT_SPECIAL,
166
    OPC_MOVN     = 0x0B | EXT_SPECIAL,
167

    
168
    OPC_MOVCI    = 0x01 | EXT_SPECIAL,
169

    
170
    /* Special */
171
    OPC_PMON     = 0x05 | EXT_SPECIAL,
172
    OPC_SYSCALL  = 0x0C | EXT_SPECIAL,
173
    OPC_BREAK    = 0x0D | EXT_SPECIAL,
174
    OPC_SYNC     = 0x0F | EXT_SPECIAL,
175
};
176

    
177
enum {
178
    /* Mutiply & xxx operations */
179
    OPC_MADD     = 0x00 | EXT_SPECIAL2,
180
    OPC_MADDU    = 0x01 | EXT_SPECIAL2,
181
    OPC_MUL      = 0x02 | EXT_SPECIAL2,
182
    OPC_MSUB     = 0x04 | EXT_SPECIAL2,
183
    OPC_MSUBU    = 0x05 | EXT_SPECIAL2,
184
    /* Misc */
185
    OPC_CLZ      = 0x20 | EXT_SPECIAL2,
186
    OPC_CLO      = 0x21 | EXT_SPECIAL2,
187
    /* Special */
188
    OPC_SDBBP    = 0x3F | EXT_SPECIAL2,
189
};
190

    
191
/* Branch REGIMM */
192
enum {
193
    OPC_BLTZ     = 0x00 | EXT_REGIMM,
194
    OPC_BLTZL    = 0x02 | EXT_REGIMM,
195
    OPC_BGEZ     = 0x01 | EXT_REGIMM,
196
    OPC_BGEZL    = 0x03 | EXT_REGIMM,
197
    OPC_BLTZAL   = 0x10 | EXT_REGIMM,
198
    OPC_BLTZALL  = 0x12 | EXT_REGIMM,
199
    OPC_BGEZAL   = 0x11 | EXT_REGIMM,
200
    OPC_BGEZALL  = 0x13 | EXT_REGIMM,
201
    OPC_TGEI     = 0x08 | EXT_REGIMM,
202
    OPC_TGEIU    = 0x09 | EXT_REGIMM,
203
    OPC_TLTI     = 0x0A | EXT_REGIMM,
204
    OPC_TLTIU    = 0x0B | EXT_REGIMM,
205
    OPC_TEQI     = 0x0C | EXT_REGIMM,
206
    OPC_TNEI     = 0x0E | EXT_REGIMM,
207
};
208

    
209
enum {
210
    /* Coprocessor 0 (MMU) */
211
    OPC_MFC0     = 0x00 | EXT_CP0,
212
    OPC_MTC0     = 0x04 | EXT_CP0,
213
    OPC_TLBR     = 0x01 | EXT_CP0,
214
    OPC_TLBWI    = 0x02 | EXT_CP0,
215
    OPC_TLBWR    = 0x06 | EXT_CP0,
216
    OPC_TLBP     = 0x08 | EXT_CP0,
217
    OPC_ERET     = 0x18 | EXT_CP0,
218
    OPC_DERET    = 0x1F | EXT_CP0,
219
    OPC_WAIT     = 0x20 | EXT_CP0,
220
};
221

    
222
#ifdef MIPS_USES_FPU
223
enum {
224
    /* Coprocessor 1 (FPU) */
225
    OPC_MFC1     = 0x00 | EXT_CP1,
226
    OPC_MTC1     = 0x04 | EXT_CP1,
227
    OPC_CFC1     = 0x02 | EXT_CP1,
228
    OPC_CTC1     = 0x06 | EXT_CP1,
229
};
230
#endif
231

    
232
const unsigned char *regnames[] =
233
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
234
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
235
      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
236
      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
237

    
238
/* Warning: no function for r0 register (hard wired to zero) */
239
#define GEN32(func, NAME) \
240
static GenOpFunc *NAME ## _table [32] = {                                     \
241
NULL,       NAME ## 1, NAME ## 2, NAME ## 3,                                  \
242
NAME ## 4,  NAME ## 5, NAME ## 6, NAME ## 7,                                  \
243
NAME ## 8,  NAME ## 9, NAME ## 10, NAME ## 11,                                \
244
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
245
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
246
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
247
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
248
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
249
};                                                                            \
250
static inline void func(int n)                                                \
251
{                                                                             \
252
    NAME ## _table[n]();                                                      \
253
}
254

    
255
/* General purpose registers moves */
256
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
257
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
258
GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
259

    
260
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
261
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
262

    
263
#ifdef MIPS_USES_FPU
264
const unsigned char *fregnames[] =
265
    { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
266
      "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
267
      "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
268
      "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
269

    
270
# define SFGEN32(func, NAME) \
271
static GenOpFunc *NAME ## _table [32] = {                                     \
272
NAME ## 0,  NAME ## 1,  NAME ## 2,  NAME ## 3,                                \
273
NAME ## 4,  NAME ## 5,  NAME ## 6,  NAME ## 7,                                \
274
NAME ## 8,  NAME ## 9,  NAME ## 10, NAME ## 11,                               \
275
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
276
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
277
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
278
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
279
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
280
};                                                                            \
281
static inline void func(int n)                                                \
282
{                                                                             \
283
    NAME ## _table[n]();                                                      \
284
}
285

    
286
# define DFGEN32(func, NAME) \
287
static GenOpFunc *NAME ## _table [32] = {                                     \
288
NAME ## 0,  0, NAME ## 2,  0,                                                 \
289
NAME ## 4,  0, NAME ## 6,  0,                                                 \
290
NAME ## 8,  0, NAME ## 10, 0,                                                 \
291
NAME ## 12, 0, NAME ## 14, 0,                                                 \
292
NAME ## 16, 0, NAME ## 18, 0,                                                 \
293
NAME ## 20, 0, NAME ## 22, 0,                                                 \
294
NAME ## 24, 0, NAME ## 26, 0,                                                 \
295
NAME ## 28, 0, NAME ## 30, 0,                                                 \
296
};                                                                            \
297
static inline void func(int n)                                                \
298
{                                                                             \
299
    NAME ## _table[n]();                                                      \
300
}
301

    
302
SFGEN32(gen_op_load_fpr_WT0,  gen_op_load_fpr_WT0_fpr);
303
SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
304

    
305
SFGEN32(gen_op_load_fpr_WT1,  gen_op_load_fpr_WT1_fpr);
306
SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
307

    
308
SFGEN32(gen_op_load_fpr_WT2,  gen_op_load_fpr_WT2_fpr);
309
SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
310

    
311
DFGEN32(gen_op_load_fpr_DT0,  gen_op_load_fpr_DT0_fpr);
312
DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
313

    
314
DFGEN32(gen_op_load_fpr_DT1,  gen_op_load_fpr_DT1_fpr);
315
DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
316

    
317
DFGEN32(gen_op_load_fpr_DT2,  gen_op_load_fpr_DT2_fpr);
318
DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
319

    
320
#define FOP_CONDS(fmt) \
321
static GenOpFunc * cond_ ## fmt ## _table[16] = {                       \
322
    gen_op_cmp_ ## fmt ## _f,                                           \
323
    gen_op_cmp_ ## fmt ## _un,                                          \
324
    gen_op_cmp_ ## fmt ## _eq,                                          \
325
    gen_op_cmp_ ## fmt ## _ueq,                                         \
326
    gen_op_cmp_ ## fmt ## _olt,                                         \
327
    gen_op_cmp_ ## fmt ## _ult,                                         \
328
    gen_op_cmp_ ## fmt ## _ole,                                         \
329
    gen_op_cmp_ ## fmt ## _ule,                                         \
330
    gen_op_cmp_ ## fmt ## _sf,                                          \
331
    gen_op_cmp_ ## fmt ## _ngle,                                        \
332
    gen_op_cmp_ ## fmt ## _seq,                                         \
333
    gen_op_cmp_ ## fmt ## _ngl,                                         \
334
    gen_op_cmp_ ## fmt ## _lt,                                          \
335
    gen_op_cmp_ ## fmt ## _nge,                                         \
336
    gen_op_cmp_ ## fmt ## _le,                                          \
337
    gen_op_cmp_ ## fmt ## _ngt,                                         \
338
};                                                                      \
339
static inline void gen_cmp_ ## fmt(int n)                               \
340
{                                                                       \
341
    cond_ ## fmt ## _table[n]();                                        \
342
}
343

    
344
FOP_CONDS(d)
345
FOP_CONDS(s)
346

    
347
#endif
348

    
349
typedef struct DisasContext {
350
    struct TranslationBlock *tb;
351
    target_ulong pc, saved_pc;
352
    uint32_t opcode;
353
    /* Routine used to access memory */
354
    int mem_idx;
355
    uint32_t hflags, saved_hflags;
356
    uint32_t CP0_Status;
357
    int bstate;
358
    target_ulong btarget;
359
} DisasContext;
360

    
361
enum {
362
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
363
                      * exception condition
364
                      */
365
    BS_STOP     = 1, /* We want to stop translation for any reason */
366
    BS_BRANCH   = 2, /* We reached a branch condition     */
367
    BS_EXCP     = 3, /* We reached an exception condition */
368
};
369

    
370
#if defined MIPS_DEBUG_DISAS
371
#define MIPS_DEBUG(fmt, args...)                                              \
372
do {                                                                          \
373
    if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
374
        fprintf(logfile, "%08x: %08x " fmt "\n",                              \
375
                ctx->pc, ctx->opcode , ##args);                               \
376
    }                                                                         \
377
} while (0)
378
#else
379
#define MIPS_DEBUG(fmt, args...) do { } while(0)
380
#endif
381

    
382
#define MIPS_INVAL(op)                                                        \
383
do {                                                                          \
384
    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
385
               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
386
} while (0)
387

    
388
#define GEN_LOAD_REG_TN(Tn, Rn)                                               \
389
do {                                                                          \
390
    if (Rn == 0) {                                                            \
391
        glue(gen_op_reset_, Tn)();                                            \
392
    } else {                                                                  \
393
        glue(gen_op_load_gpr_, Tn)(Rn);                                       \
394
    }                                                                         \
395
} while (0)
396

    
397
#define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
398
do {                                                                          \
399
    if (Imm == 0) {                                                           \
400
        glue(gen_op_reset_, Tn)();                                            \
401
    } else {                                                                  \
402
        glue(gen_op_set_, Tn)(Imm);                                           \
403
    }                                                                         \
404
} while (0)
405

    
406
#define GEN_STORE_TN_REG(Rn, Tn)                                              \
407
do {                                                                          \
408
    if (Rn != 0) {                                                            \
409
        glue(glue(gen_op_store_, Tn),_gpr)(Rn);                               \
410
    }                                                                         \
411
} while (0)
412

    
413
#ifdef MIPS_USES_FPU
414

    
415
# define GEN_LOAD_FREG_FTN(FTn, Fn)                                           \
416
do {                                                                          \
417
    glue(gen_op_load_fpr_, FTn)(Fn);                                          \
418
} while (0)
419

    
420
#define GEN_STORE_FTN_FREG(Fn, FTn)                                           \
421
do {                                                                          \
422
    glue(gen_op_store_fpr_, FTn)(Fn);                                         \
423
} while (0)
424

    
425
#endif
426

    
427
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
428
{
429
#if defined MIPS_DEBUG_DISAS
430
    if (loglevel & CPU_LOG_TB_IN_ASM) {
431
            fprintf(logfile, "hflags %08x saved %08x\n",
432
                    ctx->hflags, ctx->saved_hflags);
433
    }
434
#endif
435
    if (do_save_pc && ctx->pc != ctx->saved_pc) {
436
        gen_op_save_pc(ctx->pc);
437
        ctx->saved_pc = ctx->pc;
438
    }
439
    if (ctx->hflags != ctx->saved_hflags) {
440
        gen_op_save_state(ctx->hflags);
441
        ctx->saved_hflags = ctx->hflags;
442
        if (ctx->hflags & MIPS_HFLAG_BR) {
443
            gen_op_save_breg_target();
444
        } else if (ctx->hflags & MIPS_HFLAG_B) {
445
            gen_op_save_btarget(ctx->btarget);
446
        } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
447
            gen_op_save_bcond();
448
            gen_op_save_btarget(ctx->btarget);
449
        }
450
    }
451
}
452

    
453
static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
454
{
455
#if defined MIPS_DEBUG_DISAS
456
    if (loglevel & CPU_LOG_TB_IN_ASM)
457
            fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
458
#endif
459
    save_cpu_state(ctx, 1);
460
    if (err == 0)
461
        gen_op_raise_exception(excp);
462
    else
463
        gen_op_raise_exception_err(excp, err);
464
    ctx->bstate = BS_EXCP;
465
}
466

    
467
static inline void generate_exception (DisasContext *ctx, int excp)
468
{
469
    generate_exception_err (ctx, excp, 0);
470
}
471

    
472
#if defined(CONFIG_USER_ONLY)
473
#define op_ldst(name)        gen_op_##name##_raw()
474
#define OP_LD_TABLE(width)
475
#define OP_ST_TABLE(width)
476
#else
477
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
478
#define OP_LD_TABLE(width)                                                    \
479
static GenOpFunc *gen_op_l##width[] = {                                       \
480
    &gen_op_l##width##_user,                                                  \
481
    &gen_op_l##width##_kernel,                                                \
482
}
483
#define OP_ST_TABLE(width)                                                    \
484
static GenOpFunc *gen_op_s##width[] = {                                       \
485
    &gen_op_s##width##_user,                                                  \
486
    &gen_op_s##width##_kernel,                                                \
487
}
488
#endif
489

    
490
#ifdef TARGET_MIPS64
491
OP_LD_TABLE(d);
492
OP_LD_TABLE(dl);
493
OP_LD_TABLE(dr);
494
OP_ST_TABLE(d);
495
OP_ST_TABLE(dl);
496
OP_ST_TABLE(dr);
497
#endif
498
OP_LD_TABLE(w);
499
OP_LD_TABLE(wu);
500
OP_LD_TABLE(wl);
501
OP_LD_TABLE(wr);
502
OP_ST_TABLE(w);
503
OP_ST_TABLE(wl);
504
OP_ST_TABLE(wr);
505
OP_LD_TABLE(h);
506
OP_LD_TABLE(hu);
507
OP_ST_TABLE(h);
508
OP_LD_TABLE(b);
509
OP_LD_TABLE(bu);
510
OP_ST_TABLE(b);
511
OP_LD_TABLE(l);
512
OP_ST_TABLE(c);
513
#ifdef MIPS_USES_FPU
514
OP_LD_TABLE(wc1);
515
OP_ST_TABLE(wc1);
516
OP_LD_TABLE(dc1);
517
OP_ST_TABLE(dc1);
518
#endif
519

    
520
/* Load and store */
521
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
522
                      int base, int16_t offset)
523
{
524
    const unsigned char *opn = "unk";
525

    
526
    if (base == 0) {
527
        GEN_LOAD_IMM_TN(T0, offset);
528
    } else if (offset == 0) {
529
        gen_op_load_gpr_T0(base);
530
    } else {
531
        gen_op_load_gpr_T0(base);
532
        gen_op_set_T1(offset);
533
        gen_op_add();
534
    }
535
    /* Don't do NOP if destination is zero: we must perform the actual
536
     * memory access
537
     */
538
    switch (opc) {
539
#if defined(TARGET_MIPS64)
540
    case OPC_LD:
541
#if defined (MIPS_HAS_UNALIGNED_LS)
542
    case OPC_ULD:
543
#endif
544
        op_ldst(ld);
545
        GEN_STORE_TN_REG(rt, T0);
546
        opn = "ld";
547
        break;
548
    case OPC_SD:
549
#if defined (MIPS_HAS_UNALIGNED_LS)
550
    case OPC_USD:
551
#endif
552
        GEN_LOAD_REG_TN(T1, rt);
553
        op_ldst(sd);
554
        opn = "sd";
555
        break;
556
    case OPC_LDL:
557
        op_ldst(ldl);
558
        GEN_STORE_TN_REG(rt, T0);
559
        opn = "ldl";
560
        break;
561
    case OPC_SDL:
562
        GEN_LOAD_REG_TN(T1, rt);
563
        op_ldst(sdl);
564
        opn = "sdl";
565
        break;
566
    case OPC_LDR:
567
        op_ldst(ldr);
568
        GEN_STORE_TN_REG(rt, T0);
569
        opn = "ldr";
570
        break;
571
    case OPC_SDR:
572
        GEN_LOAD_REG_TN(T1, rt);
573
        op_ldst(sdr);
574
        opn = "sdr";
575
        break;
576
#endif
577
    case OPC_LW:
578
#if defined (MIPS_HAS_UNALIGNED_LS)
579
    case OPC_ULW:
580
#endif
581
        op_ldst(lw);
582
        GEN_STORE_TN_REG(rt, T0);
583
        opn = "lw";
584
        break;
585
    case OPC_LWU:
586
        op_ldst(lwu);
587
        GEN_STORE_TN_REG(rt, T0);
588
        opn = "lwu";
589
        break;
590
    case OPC_SW:
591
#if defined (MIPS_HAS_UNALIGNED_LS)
592
    case OPC_USW:
593
#endif
594
        GEN_LOAD_REG_TN(T1, rt);
595
        op_ldst(sw);
596
        opn = "sw";
597
        break;
598
    case OPC_LH:
599
#if defined (MIPS_HAS_UNALIGNED_LS)
600
    case OPC_ULH:
601
#endif
602
        op_ldst(lh);
603
        GEN_STORE_TN_REG(rt, T0);
604
        opn = "lh";
605
        break;
606
    case OPC_SH:
607
#if defined (MIPS_HAS_UNALIGNED_LS)
608
    case OPC_USH:
609
#endif
610
        GEN_LOAD_REG_TN(T1, rt);
611
        op_ldst(sh);
612
        opn = "sh";
613
        break;
614
    case OPC_LHU:
615
#if defined (MIPS_HAS_UNALIGNED_LS)
616
    case OPC_ULHU:
617
#endif
618
        op_ldst(lhu);
619
        GEN_STORE_TN_REG(rt, T0);
620
        opn = "lhu";
621
        break;
622
    case OPC_LB:
623
        op_ldst(lb);
624
        GEN_STORE_TN_REG(rt, T0);
625
        opn = "lb";
626
        break;
627
    case OPC_SB:
628
        GEN_LOAD_REG_TN(T1, rt);
629
        op_ldst(sb);
630
        opn = "sb";
631
        break;
632
    case OPC_LBU:
633
        op_ldst(lbu);
634
        GEN_STORE_TN_REG(rt, T0);
635
        opn = "lbu";
636
        break;
637
    case OPC_LWL:
638
        GEN_LOAD_REG_TN(T1, rt);
639
        op_ldst(lwl);
640
        GEN_STORE_TN_REG(rt, T0);
641
        opn = "lwl";
642
        break;
643
    case OPC_SWL:
644
        GEN_LOAD_REG_TN(T1, rt);
645
        op_ldst(swl);
646
        opn = "swr";
647
        break;
648
    case OPC_LWR:
649
        GEN_LOAD_REG_TN(T1, rt);
650
        op_ldst(lwr);
651
        GEN_STORE_TN_REG(rt, T0);
652
        opn = "lwr";
653
        break;
654
    case OPC_SWR:
655
        GEN_LOAD_REG_TN(T1, rt);
656
        op_ldst(swr);
657
        opn = "swr";
658
        break;
659
    case OPC_LL:
660
        op_ldst(ll);
661
        GEN_STORE_TN_REG(rt, T0);
662
        opn = "ll";
663
        break;
664
    case OPC_SC:
665
        GEN_LOAD_REG_TN(T1, rt);
666
        op_ldst(sc);
667
        GEN_STORE_TN_REG(rt, T0);
668
        opn = "sc";
669
        break;
670
    default:
671
        MIPS_INVAL("load/store");
672
        generate_exception(ctx, EXCP_RI);
673
        return;
674
    }
675
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
676
}
677

    
678
#ifdef MIPS_USES_FPU
679

    
680
/* Load and store */
681
static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
682
                      int base, int16_t offset)
683
{
684
    const unsigned char *opn = "unk";
685

    
686
    if (base == 0) {
687
        GEN_LOAD_IMM_TN(T0, offset);
688
    } else if (offset == 0) {
689
        gen_op_load_gpr_T0(base);
690
    } else {
691
        gen_op_load_gpr_T0(base);
692
        gen_op_set_T1(offset);
693
        gen_op_add();
694
    }
695
    /* Don't do NOP if destination is zero: we must perform the actual
696
     * memory access
697
     */
698
    switch (opc) {
699
    case OPC_LWC1:
700
        op_ldst(lwc1);
701
        GEN_STORE_FTN_FREG(ft, WT0);
702
        opn = "lwc1";
703
        break;
704
    case OPC_SWC1:
705
        GEN_LOAD_FREG_FTN(WT0, ft);
706
        op_ldst(swc1);
707
        opn = "swc1";
708
        break;
709
    case OPC_LDC1:
710
        op_ldst(ldc1);
711
        GEN_STORE_FTN_FREG(ft, DT0);
712
        opn = "ldc1";
713
        break;
714
    case OPC_SDC1:
715
        GEN_LOAD_FREG_FTN(DT0, ft);
716
        op_ldst(sdc1);
717
        opn = "sdc1";
718
        break;
719
    default:
720
        MIPS_INVAL("float load/store");
721
        generate_exception(ctx, EXCP_CpU);
722
        return;
723
    }
724
    MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
725
}
726
#endif
727

    
728
/* Arithmetic with immediate operand */
729
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
730
                           int rs, int16_t imm)
731
{
732
    uint32_t uimm;
733
    const unsigned char *opn = "unk";
734

    
735
    if (rt == 0 && opc != OPC_ADDI) {
736
        /* if no destination, treat it as a NOP 
737
         * For addi, we must generate the overflow exception when needed.
738
         */
739
        MIPS_DEBUG("NOP");
740
        return;
741
    }
742
    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
743
        opc == OPC_SLTI || opc == OPC_SLTIU)
744
        uimm = (int32_t)imm; /* Sign extent to 32 bits */
745
    else
746
        uimm = (uint16_t)imm;
747
    if (opc != OPC_LUI) {
748
        GEN_LOAD_REG_TN(T0, rs);
749
        GEN_LOAD_IMM_TN(T1, uimm);
750
    } else {
751
        uimm = uimm << 16;
752
        GEN_LOAD_IMM_TN(T0, uimm);
753
    }
754
    switch (opc) {
755
    case OPC_ADDI:
756
        save_cpu_state(ctx, 1);
757
        gen_op_addo();
758
        opn = "addi";
759
        break;
760
    case OPC_ADDIU:
761
        gen_op_add();
762
        opn = "addiu";
763
        break;
764
    case OPC_SLTI:
765
        gen_op_lt();
766
        opn = "slti";
767
        break;
768
    case OPC_SLTIU:
769
        gen_op_ltu();
770
        opn = "sltiu";
771
        break;
772
    case OPC_ANDI:
773
        gen_op_and();
774
        opn = "andi";
775
        break;
776
    case OPC_ORI:
777
        gen_op_or();
778
        opn = "ori";
779
        break;
780
    case OPC_XORI:
781
        gen_op_xor();
782
        opn = "xori";
783
        break;
784
    case OPC_LUI:
785
        opn = "lui";
786
        break;
787
    case OPC_SLL:
788
        gen_op_sll();
789
        opn = "sll";
790
        break;
791
    case OPC_SRA:
792
        gen_op_sra();
793
        opn = "sra";
794
        break;
795
    case OPC_SRL:
796
        gen_op_srl();
797
        opn = "srl";
798
        break;
799
    default:
800
        MIPS_INVAL("imm arith");
801
        generate_exception(ctx, EXCP_RI);
802
        return;
803
    }
804
    GEN_STORE_TN_REG(rt, T0);
805
    MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
806
}
807

    
808
/* Arithmetic */
809
static void gen_arith (DisasContext *ctx, uint16_t opc,
810
                       int rd, int rs, int rt)
811
{
812
    const unsigned char *opn = "unk";
813

    
814
    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
815
        /* if no destination, treat it as a NOP 
816
         * For add & sub, we must generate the overflow exception when needed.
817
         */
818
        MIPS_DEBUG("NOP");
819
        return;
820
    }
821
    GEN_LOAD_REG_TN(T0, rs);
822
    GEN_LOAD_REG_TN(T1, rt);
823
    switch (opc) {
824
    case OPC_ADD:
825
        save_cpu_state(ctx, 1);
826
        gen_op_addo();
827
        opn = "add";
828
        break;
829
    case OPC_ADDU:
830
        gen_op_add();
831
        opn = "addu";
832
        break;
833
    case OPC_SUB:
834
        save_cpu_state(ctx, 1);
835
        gen_op_subo();
836
        opn = "sub";
837
        break;
838
    case OPC_SUBU:
839
        gen_op_sub();
840
        opn = "subu";
841
        break;
842
    case OPC_SLT:
843
        gen_op_lt();
844
        opn = "slt";
845
        break;
846
    case OPC_SLTU:
847
        gen_op_ltu();
848
        opn = "sltu";
849
        break;
850
    case OPC_AND:
851
        gen_op_and();
852
        opn = "and";
853
        break;
854
    case OPC_NOR:
855
        gen_op_nor();
856
        opn = "nor";
857
        break;
858
    case OPC_OR:
859
        gen_op_or();
860
        opn = "or";
861
        break;
862
    case OPC_XOR:
863
        gen_op_xor();
864
        opn = "xor";
865
        break;
866
    case OPC_MUL:
867
        gen_op_mul();
868
        opn = "mul";
869
        break;
870
    case OPC_MOVN:
871
        gen_op_movn(rd);
872
        opn = "movn";
873
        goto print;
874
    case OPC_MOVZ:
875
        gen_op_movz(rd);
876
        opn = "movz";
877
        goto print;
878
    case OPC_SLLV:
879
        gen_op_sllv();
880
        opn = "sllv";
881
        break;
882
    case OPC_SRAV:
883
        gen_op_srav();
884
        opn = "srav";
885
        break;
886
    case OPC_SRLV:
887
        gen_op_srlv();
888
        opn = "srlv";
889
        break;
890
    default:
891
        MIPS_INVAL("arith");
892
        generate_exception(ctx, EXCP_RI);
893
        return;
894
    }
895
    GEN_STORE_TN_REG(rd, T0);
896
 print:
897
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
898
}
899

    
900
/* Arithmetic on HI/LO registers */
901
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
902
{
903
    const unsigned char *opn = "unk";
904

    
905
    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
906
        /* Treat as a NOP */
907
        MIPS_DEBUG("NOP");
908
        return;
909
    }
910
    switch (opc) {
911
    case OPC_MFHI:
912
        gen_op_load_HI();
913
        GEN_STORE_TN_REG(reg, T0);
914
        opn = "mfhi";
915
        break;
916
    case OPC_MFLO:
917
        gen_op_load_LO();
918
        GEN_STORE_TN_REG(reg, T0);
919
        opn = "mflo";
920
        break;
921
    case OPC_MTHI:
922
        GEN_LOAD_REG_TN(T0, reg);
923
        gen_op_store_HI();
924
        opn = "mthi";
925
        break;
926
    case OPC_MTLO:
927
        GEN_LOAD_REG_TN(T0, reg);
928
        gen_op_store_LO();
929
        opn = "mtlo";
930
        break;
931
    default:
932
        MIPS_INVAL("HILO");
933
        generate_exception(ctx, EXCP_RI);
934
        return;
935
    }
936
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
937
}
938

    
939
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
940
                        int rs, int rt)
941
{
942
    const unsigned char *opn = "unk";
943

    
944
    GEN_LOAD_REG_TN(T0, rs);
945
    GEN_LOAD_REG_TN(T1, rt);
946
    switch (opc) {
947
    case OPC_DIV:
948
        gen_op_div();
949
        opn = "div";
950
        break;
951
    case OPC_DIVU:
952
        gen_op_divu();
953
        opn = "divu";
954
        break;
955
    case OPC_MULT:
956
        gen_op_mult();
957
        opn = "mult";
958
        break;
959
    case OPC_MULTU:
960
        gen_op_multu();
961
        opn = "multu";
962
        break;
963
    case OPC_MADD:
964
        gen_op_madd();
965
        opn = "madd";
966
        break;
967
    case OPC_MADDU:
968
        gen_op_maddu();
969
        opn = "maddu";
970
        break;
971
    case OPC_MSUB:
972
        gen_op_msub();
973
        opn = "msub";
974
        break;
975
    case OPC_MSUBU:
976
        gen_op_msubu();
977
        opn = "msubu";
978
        break;
979
    default:
980
        MIPS_INVAL("mul/div");
981
        generate_exception(ctx, EXCP_RI);
982
        return;
983
    }
984
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
985
}
986

    
987
static void gen_cl (DisasContext *ctx, uint16_t opc,
988
                    int rd, int rs)
989
{
990
    const unsigned char *opn = "unk";
991
    if (rd == 0) {
992
        /* Treat as a NOP */
993
        MIPS_DEBUG("NOP");
994
        return;
995
    }
996
    GEN_LOAD_REG_TN(T0, rs);
997
    switch (opc) {
998
    case OPC_CLO:
999
        /* CLO */
1000
        gen_op_clo();
1001
        opn = "clo";
1002
        break;
1003
    case OPC_CLZ:
1004
        /* CLZ */
1005
        gen_op_clz();
1006
        opn = "clz";
1007
        break;
1008
    default:
1009
        MIPS_INVAL("CLx");
1010
        generate_exception(ctx, EXCP_RI);
1011
        return;
1012
    }
1013
    gen_op_store_T0_gpr(rd);
1014
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
1015
}
1016

    
1017
/* Traps */
1018
static void gen_trap (DisasContext *ctx, uint16_t opc,
1019
                      int rs, int rt, int16_t imm)
1020
{
1021
    int cond;
1022

    
1023
    cond = 0;
1024
    /* Load needed operands */
1025
    switch (opc) {
1026
    case OPC_TEQ:
1027
    case OPC_TGE:
1028
    case OPC_TGEU:
1029
    case OPC_TLT:
1030
    case OPC_TLTU:
1031
    case OPC_TNE:
1032
        /* Compare two registers */
1033
        if (rs != rt) {
1034
            GEN_LOAD_REG_TN(T0, rs);
1035
            GEN_LOAD_REG_TN(T1, rt);
1036
            cond = 1;
1037
        }
1038
    case OPC_TEQI:
1039
    case OPC_TGEI:
1040
    case OPC_TGEIU:
1041
    case OPC_TLTI:
1042
    case OPC_TLTIU:
1043
    case OPC_TNEI:
1044
        /* Compare register to immediate */
1045
        if (rs != 0 || imm != 0) {
1046
            GEN_LOAD_REG_TN(T0, rs);
1047
            GEN_LOAD_IMM_TN(T1, (int32_t)imm);
1048
            cond = 1;
1049
        }
1050
        break;
1051
    }
1052
    if (cond == 0) {
1053
        switch (opc) {
1054
        case OPC_TEQ:   /* rs == rs */
1055
        case OPC_TEQI:  /* r0 == 0  */
1056
        case OPC_TGE:   /* rs >= rs */
1057
        case OPC_TGEI:  /* r0 >= 0  */
1058
        case OPC_TGEU:  /* rs >= rs unsigned */
1059
        case OPC_TGEIU: /* r0 >= 0  unsigned */
1060
            /* Always trap */
1061
            gen_op_set_T0(1);
1062
            break;
1063
        case OPC_TLT:   /* rs < rs           */
1064
        case OPC_TLTI:  /* r0 < 0            */
1065
        case OPC_TLTU:  /* rs < rs unsigned  */
1066
        case OPC_TLTIU: /* r0 < 0  unsigned  */
1067
        case OPC_TNE:   /* rs != rs          */
1068
        case OPC_TNEI:  /* r0 != 0           */
1069
            /* Never trap: treat as NOP */
1070
            return;
1071
        default:
1072
            MIPS_INVAL("TRAP");
1073
            generate_exception(ctx, EXCP_RI);
1074
            return;
1075
        }
1076
    } else {
1077
        switch (opc) {
1078
        case OPC_TEQ:
1079
        case OPC_TEQI:
1080
            gen_op_eq();
1081
            break;
1082
        case OPC_TGE:
1083
        case OPC_TGEI:
1084
            gen_op_ge();
1085
            break;
1086
        case OPC_TGEU:
1087
        case OPC_TGEIU:
1088
            gen_op_geu();
1089
            break;
1090
        case OPC_TLT:
1091
        case OPC_TLTI:
1092
            gen_op_lt();
1093
            break;
1094
        case OPC_TLTU:
1095
        case OPC_TLTIU:
1096
            gen_op_ltu();
1097
            break;
1098
        case OPC_TNE:
1099
        case OPC_TNEI:
1100
            gen_op_ne();
1101
            break;
1102
        default:
1103
            MIPS_INVAL("TRAP");
1104
            generate_exception(ctx, EXCP_RI);
1105
            return;
1106
        }
1107
    }
1108
    save_cpu_state(ctx, 1);
1109
    gen_op_trap();
1110
    ctx->bstate = BS_STOP;
1111
}
1112

    
1113
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
1114
{
1115
    TranslationBlock *tb;
1116
    tb = ctx->tb;
1117
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1118
        if (n == 0)
1119
            gen_op_goto_tb0(TBPARAM(tb));
1120
        else
1121
            gen_op_goto_tb1(TBPARAM(tb));
1122
        gen_op_save_pc(dest);
1123
        gen_op_set_T0((long)tb + n);
1124
        gen_op_exit_tb();
1125
    } else {
1126
        gen_op_save_pc(dest);
1127
        gen_op_set_T0(0);
1128
        gen_op_exit_tb();
1129
    }
1130
}
1131

    
1132
/* Branches (before delay slot) */
1133
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
1134
                                int rs, int rt, int32_t offset)
1135
{
1136
    target_ulong btarget;
1137
    int blink, bcond;
1138

    
1139
    btarget = -1;
1140
    blink = 0;
1141
    bcond = 0;
1142
    /* Load needed operands */
1143
    switch (opc) {
1144
    case OPC_BEQ:
1145
    case OPC_BEQL:
1146
    case OPC_BNE:
1147
    case OPC_BNEL:
1148
        /* Compare two registers */
1149
        if (rs != rt) {
1150
            GEN_LOAD_REG_TN(T0, rs);
1151
            GEN_LOAD_REG_TN(T1, rt);
1152
            bcond = 1;
1153
        }
1154
        btarget = ctx->pc + 4 + offset;
1155
        break;
1156
    case OPC_BGEZ:
1157
    case OPC_BGEZAL:
1158
    case OPC_BGEZALL:
1159
    case OPC_BGEZL:
1160
    case OPC_BGTZ:
1161
    case OPC_BGTZL:
1162
    case OPC_BLEZ:
1163
    case OPC_BLEZL:
1164
    case OPC_BLTZ:
1165
    case OPC_BLTZAL:
1166
    case OPC_BLTZALL:
1167
    case OPC_BLTZL:
1168
        /* Compare to zero */
1169
        if (rs != 0) {
1170
            gen_op_load_gpr_T0(rs);
1171
            bcond = 1;
1172
        }
1173
        btarget = ctx->pc + 4 + offset;
1174
        break;
1175
    case OPC_J:
1176
    case OPC_JAL:
1177
        /* Jump to immediate */
1178
        btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
1179
        break;
1180
    case OPC_JR:
1181
    case OPC_JALR:
1182
        /* Jump to register */
1183
        if (offset != 0) {
1184
            /* Only hint = 0 is valid */
1185
            generate_exception(ctx, EXCP_RI);
1186
            return;
1187
        }
1188
        GEN_LOAD_REG_TN(T2, rs);
1189
        break;
1190
    default:
1191
        MIPS_INVAL("branch/jump");
1192
        generate_exception(ctx, EXCP_RI);
1193
        return;
1194
    }
1195
    if (bcond == 0) {
1196
        /* No condition to be computed */
1197
        switch (opc) {
1198
        case OPC_BEQ:     /* rx == rx        */
1199
        case OPC_BEQL:    /* rx == rx likely */
1200
        case OPC_BGEZ:    /* 0 >= 0          */
1201
        case OPC_BGEZL:   /* 0 >= 0 likely   */
1202
        case OPC_BLEZ:    /* 0 <= 0          */
1203
        case OPC_BLEZL:   /* 0 <= 0 likely   */
1204
            /* Always take */
1205
            ctx->hflags |= MIPS_HFLAG_B;
1206
            MIPS_DEBUG("balways");
1207
            break;
1208
        case OPC_BGEZAL:  /* 0 >= 0          */
1209
        case OPC_BGEZALL: /* 0 >= 0 likely   */
1210
            /* Always take and link */
1211
            blink = 31;
1212
            ctx->hflags |= MIPS_HFLAG_B;
1213
            MIPS_DEBUG("balways and link");
1214
            break;
1215
        case OPC_BNE:     /* rx != rx        */
1216
        case OPC_BGTZ:    /* 0 > 0           */
1217
        case OPC_BLTZ:    /* 0 < 0           */
1218
            /* Treated as NOP */
1219
            MIPS_DEBUG("bnever (NOP)");
1220
            return;
1221
        case OPC_BLTZAL:  /* 0 < 0           */
1222
            gen_op_set_T0(ctx->pc + 8);
1223
            gen_op_store_T0_gpr(31);
1224
            return;
1225
        case OPC_BLTZALL: /* 0 < 0 likely */
1226
            gen_op_set_T0(ctx->pc + 8);
1227
            gen_op_store_T0_gpr(31);
1228
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1229
            return;
1230
        case OPC_BNEL:    /* rx != rx likely */
1231
        case OPC_BGTZL:   /* 0 > 0 likely */
1232
        case OPC_BLTZL:   /* 0 < 0 likely */
1233
            /* Skip the instruction in the delay slot */
1234
            MIPS_DEBUG("bnever and skip");
1235
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1236
            return;
1237
        case OPC_J:
1238
            ctx->hflags |= MIPS_HFLAG_B;
1239
            MIPS_DEBUG("j %08x", btarget);
1240
            break;
1241
        case OPC_JAL:
1242
            blink = 31;
1243
            ctx->hflags |= MIPS_HFLAG_B;
1244
            MIPS_DEBUG("jal %08x", btarget);
1245
            break;
1246
        case OPC_JR:
1247
            ctx->hflags |= MIPS_HFLAG_BR;
1248
            MIPS_DEBUG("jr %s", regnames[rs]);
1249
            break;
1250
        case OPC_JALR:
1251
            blink = rt;
1252
            ctx->hflags |= MIPS_HFLAG_BR;
1253
            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1254
            break;
1255
        default:
1256
            MIPS_INVAL("branch/jump");
1257
            generate_exception(ctx, EXCP_RI);
1258
            return;
1259
        }
1260
    } else {
1261
        switch (opc) {
1262
        case OPC_BEQ:
1263
            gen_op_eq();
1264
            MIPS_DEBUG("beq %s, %s, %08x",
1265
                       regnames[rs], regnames[rt], btarget);
1266
            goto not_likely;
1267
        case OPC_BEQL:
1268
            gen_op_eq();
1269
            MIPS_DEBUG("beql %s, %s, %08x",
1270
                       regnames[rs], regnames[rt], btarget);
1271
            goto likely;
1272
        case OPC_BNE:
1273
            gen_op_ne();
1274
            MIPS_DEBUG("bne %s, %s, %08x",
1275
                       regnames[rs], regnames[rt], btarget);
1276
            goto not_likely;
1277
        case OPC_BNEL:
1278
            gen_op_ne();
1279
            MIPS_DEBUG("bnel %s, %s, %08x",
1280
                       regnames[rs], regnames[rt], btarget);
1281
            goto likely;
1282
        case OPC_BGEZ:
1283
            gen_op_gez();
1284
            MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1285
            goto not_likely;
1286
        case OPC_BGEZL:
1287
            gen_op_gez();
1288
            MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1289
            goto likely;
1290
        case OPC_BGEZAL:
1291
            gen_op_gez();
1292
            MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1293
            blink = 31;
1294
            goto not_likely;
1295
        case OPC_BGEZALL:
1296
            gen_op_gez();
1297
            blink = 31;
1298
            MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1299
            goto likely;
1300
        case OPC_BGTZ:
1301
            gen_op_gtz();
1302
            MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1303
            goto not_likely;
1304
        case OPC_BGTZL:
1305
            gen_op_gtz();
1306
            MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1307
            goto likely;
1308
        case OPC_BLEZ:
1309
            gen_op_lez();
1310
            MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1311
            goto not_likely;
1312
        case OPC_BLEZL:
1313
            gen_op_lez();
1314
            MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1315
            goto likely;
1316
        case OPC_BLTZ:
1317
            gen_op_ltz();
1318
            MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1319
            goto not_likely;
1320
        case OPC_BLTZL:
1321
            gen_op_ltz();
1322
            MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1323
            goto likely;
1324
        case OPC_BLTZAL:
1325
            gen_op_ltz();
1326
            blink = 31;
1327
            MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1328
        not_likely:
1329
            ctx->hflags |= MIPS_HFLAG_BC;
1330
            break;
1331
        case OPC_BLTZALL:
1332
            gen_op_ltz();
1333
            blink = 31;
1334
            MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1335
        likely:
1336
            ctx->hflags |= MIPS_HFLAG_BL;
1337
            break;
1338
        }
1339
        gen_op_set_bcond();
1340
    }
1341
    MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1342
               blink, ctx->hflags, btarget);
1343
    ctx->btarget = btarget;
1344
    if (blink > 0) {
1345
        gen_op_set_T0(ctx->pc + 8);
1346
        gen_op_store_T0_gpr(blink);
1347
    }
1348
    return;
1349
}
1350

    
1351
/* CP0 (MMU and control) */
1352
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1353
{
1354
    const unsigned char *opn = "unk";
1355

    
1356
    if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1357
        (ctx->hflags & MIPS_HFLAG_UM) &&
1358
        !(ctx->hflags & MIPS_HFLAG_ERL) &&
1359
        !(ctx->hflags & MIPS_HFLAG_EXL)) {
1360
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1361
            fprintf(logfile, "CP0 is not usable\n");
1362
        }
1363
        generate_exception_err (ctx, EXCP_CpU, 0);
1364
        return;
1365
    }
1366

    
1367
    switch (opc) {
1368
    case OPC_MFC0:
1369
        if (rt == 0) {
1370
            /* Treat as NOP */
1371
            return;
1372
        }
1373
        gen_op_mfc0(rd, ctx->opcode & 0x7);
1374
        gen_op_store_T0_gpr(rt);
1375
        opn = "mfc0";
1376
        break;
1377
    case OPC_MTC0:
1378
        /* If we get an exception, we want to restart at next instruction */
1379
        ctx->pc += 4;
1380
        save_cpu_state(ctx, 1);
1381
        ctx->pc -= 4;
1382
        GEN_LOAD_REG_TN(T0, rt);
1383
        gen_op_mtc0(rd, ctx->opcode & 0x7);
1384
        /* Stop translation as we may have switched the execution mode */
1385
        ctx->bstate = BS_STOP;
1386
        opn = "mtc0";
1387
        break;
1388
#if defined(MIPS_USES_R4K_TLB)
1389
    case OPC_TLBWI:
1390
        gen_op_tlbwi();
1391
        opn = "tlbwi";
1392
        break;
1393
    case OPC_TLBWR:
1394
        gen_op_tlbwr();
1395
        opn = "tlbwr";
1396
        break;
1397
    case OPC_TLBP:
1398
        gen_op_tlbp();
1399
        opn = "tlbp";
1400
        break;
1401
    case OPC_TLBR:
1402
        gen_op_tlbr();
1403
        opn = "tlbr";
1404
        break;
1405
#endif
1406
    case OPC_ERET:
1407
        opn = "eret";
1408
        save_cpu_state(ctx, 0);
1409
        gen_op_eret();
1410
        ctx->bstate = BS_EXCP;
1411
        break;
1412
    case OPC_DERET:
1413
        opn = "deret";
1414
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1415
            generate_exception(ctx, EXCP_RI);
1416
        } else {
1417
            save_cpu_state(ctx, 0);
1418
            gen_op_deret();
1419
            ctx->bstate = BS_EXCP;
1420
        }
1421
        break;
1422
    case OPC_WAIT:
1423
        opn = "wait";
1424
        /* If we get an exception, we want to restart at next instruction */
1425
        ctx->pc += 4;
1426
        save_cpu_state(ctx, 1);
1427
        ctx->pc -= 4;
1428
        gen_op_wait();
1429
        ctx->bstate = BS_EXCP;
1430
        break;
1431
    default:
1432
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1433
            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1434
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1435
                    ((ctx->opcode >> 16) & 0x1F));
1436
        }
1437
        generate_exception(ctx, EXCP_RI);
1438
        return;
1439
    }
1440
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1441
}
1442

    
1443
#ifdef MIPS_USES_FPU
1444
/* CP1 Branches (before delay slot) */
1445
static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
1446
                                 int32_t offset)
1447
{
1448
    target_ulong btarget;
1449

    
1450
    btarget = ctx->pc + 4 + offset;
1451

    
1452
    switch (cond) {
1453
    case 0x0000: /* bc1f */
1454
        gen_op_bc1f();
1455
        MIPS_DEBUG("bc1f %08x", btarget);
1456
        goto not_likely;
1457
    case 0x0002: /* bc1fl */
1458
        gen_op_bc1f();
1459
        MIPS_DEBUG("bc1fl %08x", btarget);
1460
        goto likely;
1461
    case 0x0001: /* bc1t */
1462
        gen_op_bc1t();
1463
        MIPS_DEBUG("bc1t %08x", btarget);
1464
    not_likely:
1465
        ctx->hflags |= MIPS_HFLAG_BC;
1466
        break;
1467
    case 0x0003: /* bc1tl */
1468
        gen_op_bc1t();
1469
        MIPS_DEBUG("bc1tl %08x", btarget);
1470
    likely:
1471
        ctx->hflags |= MIPS_HFLAG_BL;
1472
        break;
1473
    default:    
1474
        MIPS_INVAL("cp1 branch/jump");
1475
        generate_exception(ctx, EXCP_RI);
1476
        return;
1477
    }
1478
    gen_op_set_bcond();
1479

    
1480
    MIPS_DEBUG("enter ds: cond %02x target %08x",
1481
               ctx->hflags, btarget);
1482
    ctx->btarget = btarget;
1483

    
1484
    return;
1485
}
1486

    
1487
/* Coprocessor 1 (FPU) */
1488
static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
1489
{
1490
    const unsigned char *opn = "unk";
1491

    
1492
    switch (opc) {
1493
    case OPC_MFC1:
1494
        GEN_LOAD_FREG_FTN(WT0, fs);
1495
        gen_op_mfc1();
1496
        GEN_STORE_TN_REG(rt, T0);
1497
        opn = "mfc1";
1498
        break;
1499
    case OPC_MTC1:
1500
        GEN_LOAD_REG_TN(T0, rt);
1501
        gen_op_mtc1();
1502
        GEN_STORE_FTN_FREG(fs, WT0);
1503
        opn = "mtc1";
1504
        break;
1505
    case OPC_CFC1:
1506
        if (fs != 0 && fs != 31) {
1507
            MIPS_INVAL("cfc1 freg");
1508
            generate_exception(ctx, EXCP_RI);
1509
            return;
1510
        }
1511
        GEN_LOAD_IMM_TN(T1, fs);
1512
        gen_op_cfc1();
1513
        GEN_STORE_TN_REG(rt, T0);
1514
        opn = "cfc1";
1515
        break;
1516
    case OPC_CTC1:
1517
        if (fs != 0 && fs != 31) {
1518
            MIPS_INVAL("ctc1 freg");
1519
            generate_exception(ctx, EXCP_RI);
1520
            return;
1521
        }
1522
        GEN_LOAD_IMM_TN(T1, fs);
1523
        GEN_LOAD_REG_TN(T0, rt);
1524
        gen_op_ctc1();
1525
        opn = "ctc1";
1526
        break;
1527
    default:
1528
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1529
            fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
1530
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1531
                    ((ctx->opcode >> 16) & 0x1F));
1532
        }
1533
        generate_exception(ctx, EXCP_RI);
1534
        return;
1535
    }
1536
    MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
1537
}
1538

    
1539
/* verify if floating point register is valid; an operation is not defined
1540
 * if bit 0 of any register specification is set and the FR bit in the
1541
 * Status register equals zero, since the register numbers specify an
1542
 * even-odd pair of adjacent coprocessor general registers. When the FR bit
1543
 * in the Status register equals one, both even and odd register numbers
1544
 * are valid.
1545
 * 
1546
 * Multiple float registers can be checked by calling
1547
 * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
1548
 */
1549
#define CHECK_FR(ctx, freg) do { \
1550
        if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
1551
            generate_exception(ctx, EXCP_RI); \
1552
            return; \
1553
        } \
1554
    } while(0)
1555

    
1556
#define FOP(func, fmt) (((fmt) << 21) | (func))
1557

    
1558
static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
1559
{
1560
    const unsigned char *opn = "unk";
1561
    const char *condnames[] = {
1562
            "c.f",
1563
            "c.un",
1564
            "c.eq",
1565
            "c.ueq",
1566
            "c.olt",
1567
            "c.ult",
1568
            "c.ole",
1569
            "c.ule",
1570
            "c.sf",
1571
            "c.ngle",
1572
            "c.seq",
1573
            "c.ngl",
1574
            "c.lt",
1575
            "c.nge",
1576
            "c.le",
1577
            "c.ngt",
1578
    };
1579
    int binary = 0;
1580
    
1581
    switch (ctx->opcode & FOP(0x3f, 0x1f)) {
1582
    case FOP(0, 17):
1583
        CHECK_FR(ctx, fs | ft | fd);
1584
        GEN_LOAD_FREG_FTN(DT0, fs);
1585
        GEN_LOAD_FREG_FTN(DT1, ft);
1586
        gen_op_float_add_d();
1587
        GEN_STORE_FTN_FREG(fd, DT2);
1588
        opn = "add.d";
1589
        binary = 1;
1590
        break;
1591
    case FOP(1, 17):
1592
        CHECK_FR(ctx, fs | ft | fd);
1593
        GEN_LOAD_FREG_FTN(DT0, fs);
1594
        GEN_LOAD_FREG_FTN(DT1, ft);
1595
        gen_op_float_sub_d();
1596
        GEN_STORE_FTN_FREG(fd, DT2);
1597
        opn = "sub.d";
1598
        binary = 1;
1599
        break;
1600
    case FOP(2, 17):
1601
        CHECK_FR(ctx, fs | ft | fd);
1602
        GEN_LOAD_FREG_FTN(DT0, fs);
1603
        GEN_LOAD_FREG_FTN(DT1, ft);
1604
        gen_op_float_mul_d();
1605
        GEN_STORE_FTN_FREG(fd, DT2);
1606
        opn = "mul.d";
1607
        binary = 1;
1608
        break;
1609
    case FOP(3, 17):
1610
        CHECK_FR(ctx, fs | ft | fd);
1611
        GEN_LOAD_FREG_FTN(DT0, fs);
1612
        GEN_LOAD_FREG_FTN(DT1, ft);
1613
        gen_op_float_div_d();
1614
        GEN_STORE_FTN_FREG(fd, DT2);
1615
        opn = "div.d";
1616
        binary = 1;
1617
        break;
1618
    case FOP(4, 17):
1619
        CHECK_FR(ctx, fs | fd);
1620
        GEN_LOAD_FREG_FTN(DT0, fs);
1621
        gen_op_float_sqrt_d();
1622
        GEN_STORE_FTN_FREG(fd, DT2);
1623
        opn = "sqrt.d";
1624
        break;
1625
    case FOP(5, 17):
1626
        CHECK_FR(ctx, fs | fd);
1627
        GEN_LOAD_FREG_FTN(DT0, fs);
1628
        gen_op_float_abs_d();
1629
        GEN_STORE_FTN_FREG(fd, DT2);
1630
        opn = "abs.d";
1631
        break;
1632
    case FOP(6, 17):
1633
        CHECK_FR(ctx, fs | fd);
1634
        GEN_LOAD_FREG_FTN(DT0, fs);
1635
        gen_op_float_mov_d();
1636
        GEN_STORE_FTN_FREG(fd, DT2);
1637
        opn = "mov.d";
1638
        break;
1639
    case FOP(7, 17):
1640
        CHECK_FR(ctx, fs | fd);
1641
        GEN_LOAD_FREG_FTN(DT0, fs);
1642
        gen_op_float_chs_d();
1643
        GEN_STORE_FTN_FREG(fd, DT2);
1644
        opn = "neg.d";
1645
        break;
1646
    /*  8 - round.l */
1647
    /*  9 - trunc.l */
1648
    /* 10 - ceil.l  */
1649
    /* 11 - floor.l */
1650
    case FOP(12, 17):
1651
        CHECK_FR(ctx, fs | fd);
1652
        GEN_LOAD_FREG_FTN(DT0, fs);
1653
        gen_op_float_roundw_d();
1654
        GEN_STORE_FTN_FREG(fd, WT2);
1655
        opn = "round.w.d";
1656
        break;
1657
    case FOP(13, 17):
1658
        CHECK_FR(ctx, fs | fd);
1659
        GEN_LOAD_FREG_FTN(DT0, fs);
1660
        gen_op_float_truncw_d();
1661
        GEN_STORE_FTN_FREG(fd, WT2);
1662
        opn = "trunc.w.d";
1663
        break;
1664
    case FOP(14, 17):
1665
        CHECK_FR(ctx, fs | fd);
1666
        GEN_LOAD_FREG_FTN(DT0, fs);
1667
        gen_op_float_ceilw_d();
1668
        GEN_STORE_FTN_FREG(fd, WT2);
1669
        opn = "ceil.w.d";
1670
        break;
1671
    case FOP(15, 17):
1672
        CHECK_FR(ctx, fs | fd);
1673
        GEN_LOAD_FREG_FTN(DT0, fs);
1674
        gen_op_float_floorw_d();
1675
        GEN_STORE_FTN_FREG(fd, WT2);
1676
        opn = "ceil.w.d";
1677
        break;
1678
    case FOP(33, 16): /* cvt.d.s */
1679
        CHECK_FR(ctx, fs | fd);
1680
        GEN_LOAD_FREG_FTN(WT0, fs);
1681
        gen_op_float_cvtd_s();
1682
        GEN_STORE_FTN_FREG(fd, DT2);
1683
        opn = "cvt.d.s";
1684
        break;
1685
    case FOP(33, 20): /* cvt.d.w */
1686
        CHECK_FR(ctx, fs | fd);
1687
        GEN_LOAD_FREG_FTN(WT0, fs);
1688
        gen_op_float_cvtd_w();
1689
        GEN_STORE_FTN_FREG(fd, DT2);
1690
        opn = "cvt.d.w";
1691
        break;
1692
    case FOP(48, 17):
1693
    case FOP(49, 17):
1694
    case FOP(50, 17):
1695
    case FOP(51, 17):
1696
    case FOP(52, 17):
1697
    case FOP(53, 17):
1698
    case FOP(54, 17):
1699
    case FOP(55, 17):
1700
    case FOP(56, 17):
1701
    case FOP(57, 17):
1702
    case FOP(58, 17):
1703
    case FOP(59, 17):
1704
    case FOP(60, 17):
1705
    case FOP(61, 17):
1706
    case FOP(62, 17):
1707
    case FOP(63, 17):
1708
        CHECK_FR(ctx, fs | ft);
1709
        GEN_LOAD_FREG_FTN(DT0, fs);
1710
        GEN_LOAD_FREG_FTN(DT1, ft);
1711
        gen_cmp_d(func-48);
1712
        opn = condnames[func-48];
1713
        break;
1714
    case FOP(0, 16):
1715
        CHECK_FR(ctx, fs | ft | fd);
1716
        GEN_LOAD_FREG_FTN(WT0, fs);
1717
        GEN_LOAD_FREG_FTN(WT1, ft);
1718
        gen_op_float_add_s();
1719
        GEN_STORE_FTN_FREG(fd, WT2);
1720
        opn = "add.s";
1721
        binary = 1;
1722
        break;
1723
    case FOP(1, 16):
1724
        CHECK_FR(ctx, fs | ft | fd);
1725
        GEN_LOAD_FREG_FTN(WT0, fs);
1726
        GEN_LOAD_FREG_FTN(WT1, ft);
1727
        gen_op_float_sub_s();
1728
        GEN_STORE_FTN_FREG(fd, WT2);
1729
        opn = "sub.s";
1730
        binary = 1;
1731
        break;
1732
    case FOP(2, 16):
1733
        CHECK_FR(ctx, fs | ft | fd);
1734
        GEN_LOAD_FREG_FTN(WT0, fs);
1735
        GEN_LOAD_FREG_FTN(WT1, ft);
1736
        gen_op_float_mul_s();
1737
        GEN_STORE_FTN_FREG(fd, WT2);
1738
        opn = "mul.s";
1739
        binary = 1;
1740
        break;
1741
    case FOP(3, 16):
1742
        CHECK_FR(ctx, fs | ft | fd);
1743
        GEN_LOAD_FREG_FTN(WT0, fs);
1744
        GEN_LOAD_FREG_FTN(WT1, ft);
1745
        gen_op_float_div_s();
1746
        GEN_STORE_FTN_FREG(fd, WT2);
1747
        opn = "div.s";
1748
        binary = 1;
1749
        break;
1750
    case FOP(4, 16):
1751
        CHECK_FR(ctx, fs | fd);
1752
        GEN_LOAD_FREG_FTN(WT0, fs);
1753
        gen_op_float_sqrt_s();
1754
        GEN_STORE_FTN_FREG(fd, WT2);
1755
        opn = "sqrt.s";
1756
        break;
1757
    case FOP(5, 16):
1758
        CHECK_FR(ctx, fs | fd);
1759
        GEN_LOAD_FREG_FTN(WT0, fs);
1760
        gen_op_float_abs_s();
1761
        GEN_STORE_FTN_FREG(fd, WT2);
1762
        opn = "abs.s";
1763
        break;
1764
    case FOP(6, 16):
1765
        CHECK_FR(ctx, fs | fd);
1766
        GEN_LOAD_FREG_FTN(WT0, fs);
1767
        gen_op_float_mov_s();
1768
        GEN_STORE_FTN_FREG(fd, WT2);
1769
        opn = "mov.s";
1770
        break;
1771
    case FOP(7, 16):
1772
        CHECK_FR(ctx, fs | fd);
1773
        GEN_LOAD_FREG_FTN(WT0, fs);
1774
        gen_op_float_chs_s();
1775
        GEN_STORE_FTN_FREG(fd, WT2);
1776
        opn = "neg.s";
1777
        break;
1778
    case FOP(12, 16):
1779
        CHECK_FR(ctx, fs | fd);
1780
        GEN_LOAD_FREG_FTN(WT0, fs);
1781
        gen_op_float_roundw_s();
1782
        GEN_STORE_FTN_FREG(fd, WT2);
1783
        opn = "round.w.s";
1784
        break;
1785
    case FOP(13, 16):
1786
        CHECK_FR(ctx, fs | fd);
1787
        GEN_LOAD_FREG_FTN(WT0, fs);
1788
        gen_op_float_truncw_s();
1789
        GEN_STORE_FTN_FREG(fd, WT2);
1790
        opn = "trunc.w.s";
1791
        break;
1792
    case FOP(32, 17): /* cvt.s.d */
1793
        CHECK_FR(ctx, fs | fd);
1794
        GEN_LOAD_FREG_FTN(DT0, fs);
1795
        gen_op_float_cvts_d();
1796
        GEN_STORE_FTN_FREG(fd, WT2);
1797
        opn = "cvt.s.d";
1798
        break;
1799
    case FOP(32, 20): /* cvt.s.w */
1800
        CHECK_FR(ctx, fs | fd);
1801
        GEN_LOAD_FREG_FTN(WT0, fs);
1802
        gen_op_float_cvts_w();
1803
        GEN_STORE_FTN_FREG(fd, WT2);
1804
        opn = "cvt.s.w";
1805
        break;
1806
    case FOP(36, 16): /* cvt.w.s */
1807
        CHECK_FR(ctx, fs | fd);
1808
        GEN_LOAD_FREG_FTN(WT0, fs);
1809
        gen_op_float_cvtw_s();
1810
        GEN_STORE_FTN_FREG(fd, WT2);
1811
        opn = "cvt.w.s";
1812
        break;
1813
    case FOP(36, 17): /* cvt.w.d */
1814
        CHECK_FR(ctx, fs | fd);
1815
        GEN_LOAD_FREG_FTN(DT0, fs);
1816
        gen_op_float_cvtw_d();
1817
        GEN_STORE_FTN_FREG(fd, WT2);
1818
        opn = "cvt.w.d";
1819
        break;
1820
    case FOP(48, 16):
1821
    case FOP(49, 16):
1822
    case FOP(50, 16):
1823
    case FOP(51, 16):
1824
    case FOP(52, 16):
1825
    case FOP(53, 16):
1826
    case FOP(54, 16):
1827
    case FOP(55, 16):
1828
    case FOP(56, 16):
1829
    case FOP(57, 16):
1830
    case FOP(58, 16):
1831
    case FOP(59, 16):
1832
    case FOP(60, 16):
1833
    case FOP(61, 16):
1834
    case FOP(62, 16):
1835
    case FOP(63, 16):
1836
        CHECK_FR(ctx, fs | ft);
1837
        GEN_LOAD_FREG_FTN(WT0, fs);
1838
        GEN_LOAD_FREG_FTN(WT1, ft);
1839
        gen_cmp_s(func-48);
1840
        opn = condnames[func-48];
1841
        break;
1842
    default:    
1843
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1844
            fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
1845
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1846
                    ((ctx->opcode >> 16) & 0x1F));
1847
        }
1848
        generate_exception(ctx, EXCP_RI);
1849
        return;
1850
    }
1851
    if (binary)
1852
        MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
1853
    else
1854
        MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
1855
}
1856
#endif
1857

    
1858
/* ISA extensions */
1859
/* MIPS16 extension to MIPS32 */
1860
/* SmartMIPS extension to MIPS32 */
1861

    
1862
#ifdef TARGET_MIPS64
1863
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1864
{
1865
    if (func == 0x02 && rd == 0) {
1866
        /* NOP */
1867
        return;
1868
    }
1869
    if (rs == 0 || rt == 0) {
1870
        gen_op_reset_T0();
1871
        gen_op_save64();
1872
    } else {
1873
        gen_op_load_gpr_T0(rs);
1874
        gen_op_load_gpr_T1(rt);
1875
        gen_op_save64();
1876
        if (func & 0x01)
1877
            gen_op_mul64u();
1878
        else
1879
            gen_op_mul64s();
1880
    }
1881
    if (func & 0x02)
1882
        gen_op_add64();
1883
    else
1884
        gen_op_sub64();
1885
}
1886

    
1887
/* Coprocessor 3 (FPU) */
1888

    
1889
/* MDMX extension to MIPS64 */
1890
/* MIPS-3D extension to MIPS64 */
1891

    
1892
#endif
1893

    
1894
static void gen_blikely(DisasContext *ctx)
1895
{
1896
    int l1;
1897
    l1 = gen_new_label();
1898
    gen_op_jnz_T2(l1);
1899
    gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
1900
    gen_goto_tb(ctx, 1, ctx->pc + 4);
1901
    gen_set_label(l1);
1902
}
1903

    
1904
static void decode_opc (DisasContext *ctx)
1905
{
1906
    int32_t offset;
1907
    int rs, rt, rd, sa;
1908
    uint16_t op, op1;
1909
    int16_t imm;
1910

    
1911
    /* make sure instructions are on a word boundary */
1912
    if (ctx->pc & 0x3) {
1913
        generate_exception(ctx, EXCP_AdEL);
1914
        return;
1915
    }
1916

    
1917
    if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
1918
        /* Handle blikely not taken case */
1919
        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1920
        gen_blikely(ctx);
1921
    }
1922
    op = ctx->opcode >> 26;
1923
    rs = ((ctx->opcode >> 21) & 0x1F);
1924
    rt = ((ctx->opcode >> 16) & 0x1F);
1925
    rd = ((ctx->opcode >> 11) & 0x1F);
1926
    sa = ((ctx->opcode >> 6) & 0x1F);
1927
    imm = (int16_t)ctx->opcode;
1928
    switch (op) {
1929
    case 0x00:          /* Special opcode */
1930
        op1 = ctx->opcode & 0x3F;
1931
        switch (op1) {
1932
        case 0x00:          /* Arithmetic with immediate */
1933
        case 0x02 ... 0x03:
1934
            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1935
            break;
1936
        case 0x04:          /* Arithmetic */
1937
        case 0x06 ... 0x07:
1938
        case 0x0A ... 0x0B:
1939
        case 0x20 ... 0x27:
1940
        case 0x2A ... 0x2B:
1941
            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1942
            break;
1943
        case 0x18 ... 0x1B: /* MULT / DIV */
1944
            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1945
            break;
1946
        case 0x08 ... 0x09: /* Jumps */
1947
            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1948
            return;
1949
        case 0x30 ... 0x34: /* Traps */
1950
        case 0x36:
1951
            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1952
            break;
1953
        case 0x10:          /* Move from HI/LO */
1954
        case 0x12:
1955
            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1956
            break;
1957
        case 0x11:
1958
        case 0x13:          /* Move to HI/LO */
1959
            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1960
            break;
1961
        case 0x0C:          /* SYSCALL */
1962
            generate_exception(ctx, EXCP_SYSCALL);
1963
            break;
1964
        case 0x0D:          /* BREAK */
1965
            generate_exception(ctx, EXCP_BREAK);
1966
            break;
1967
        case 0x0F:          /* SYNC */
1968
            /* Treat as a noop */
1969
            break;
1970
        case 0x05:          /* Pmon entry point */
1971
            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1972
            break;
1973

    
1974
        case 0x01:          /* MOVCI */
1975
#if defined (MIPS_HAS_MOVCI)
1976
            /* XXX */
1977
#else
1978
            /* Not implemented */
1979
            generate_exception_err (ctx, EXCP_CpU, 1);
1980
#endif
1981
            break;
1982

    
1983
#if defined (TARGET_MIPS64)
1984
        case 0x14: /* MIPS64 specific opcodes */
1985
        case 0x16:
1986
        case 0x17:
1987
        case 0x1C ... 0x1F:
1988
        case 0x2C ... 0x2F:
1989
        case 0x37:
1990
        case 0x39 ... 0x3B:
1991
        case 0x3E ... 0x3F:
1992
#endif
1993
        default:            /* Invalid */
1994
            MIPS_INVAL("special");
1995
            generate_exception(ctx, EXCP_RI);
1996
            break;
1997
        }
1998
        break;
1999
    case 0x1C:          /* Special2 opcode */
2000
        op1 = ctx->opcode & 0x3F;
2001
        switch (op1) {
2002
#if defined (MIPS_USES_R4K_EXT)
2003
        /* Those instructions are not part of MIPS32 core */
2004
        case 0x00 ... 0x01: /* Multiply and add/sub */
2005
        case 0x04 ... 0x05:
2006
            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
2007
            break;
2008
        case 0x02:          /* MUL */
2009
            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
2010
            break;
2011
        case 0x20 ... 0x21: /* CLO / CLZ */
2012
            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
2013
            break;
2014
#endif
2015
        case 0x3F:          /* SDBBP */
2016
            /* XXX: not clear which exception should be raised
2017
             *      when in debug mode...
2018
             */
2019
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
2020
                generate_exception(ctx, EXCP_DBp);
2021
            } else {
2022
                generate_exception(ctx, EXCP_DBp);
2023
            }
2024
            /* Treat as a noop */
2025
            break;
2026
        default:            /* Invalid */
2027
            MIPS_INVAL("special2");
2028
            generate_exception(ctx, EXCP_RI);
2029
            break;
2030
        }
2031
        break;
2032
    case 0x01:          /* B REGIMM opcode */
2033
        op1 = ((ctx->opcode >> 16) & 0x1F);
2034
        switch (op1) {
2035
        case 0x00 ... 0x03: /* REGIMM branches */
2036
        case 0x10 ... 0x13:
2037
            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
2038
            return;
2039
        case 0x08 ... 0x0C: /* Traps */
2040
        case 0x0E:
2041
            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
2042
            break;
2043
        default:            /* Invalid */
2044
            MIPS_INVAL("REGIMM");
2045
            generate_exception(ctx, EXCP_RI);
2046
            break;
2047
        }
2048
        break;
2049
    case 0x10:          /* CP0 opcode */
2050
        op1 = ((ctx->opcode >> 21) & 0x1F);
2051
        switch (op1) {
2052
        case 0x00:
2053
        case 0x04:
2054
            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
2055
            break;
2056
        default:
2057
            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
2058
            break;
2059
        }
2060
        break;
2061
    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
2062
        gen_arith_imm(ctx, op, rt, rs, imm);
2063
        break;
2064
    case 0x02 ... 0x03: /* Jump */
2065
        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
2066
        gen_compute_branch(ctx, op, rs, rt, offset);
2067
        return;
2068
    case 0x04 ... 0x07: /* Branch */
2069
    case 0x14 ... 0x17:
2070
        gen_compute_branch(ctx, op, rs, rt, imm << 2);
2071
        return;
2072
    case 0x20 ... 0x2E: /* Load and stores */
2073
    case 0x30:
2074
    case 0x38:
2075
        gen_ldst(ctx, op, rt, rs, imm);
2076
        break;
2077
    case 0x2F:          /* Cache operation */
2078
        /* Treat as a noop */
2079
        break;
2080
    case 0x33:          /* Prefetch */
2081
        /* Treat as a noop */
2082
        break;
2083
    case 0x3F: /* HACK */
2084
        break;
2085

    
2086
    /* Floating point.  */
2087
    case 0x31: /* LWC1 */
2088
    case 0x35: /* LDC1 */
2089
    case 0x39: /* SWC1 */
2090
    case 0x3D: /* SDC1 */
2091
#if defined(MIPS_USES_FPU)
2092
        save_cpu_state(ctx, 1);
2093
        gen_op_cp1_enabled();
2094
        gen_flt_ldst(ctx, op, rt, rs, imm);
2095
#else
2096
        generate_exception_err(ctx, EXCP_CpU, 1);
2097
#endif
2098
        break;
2099

    
2100
    case 0x11:          /* CP1 opcode */
2101
#if defined(MIPS_USES_FPU)
2102
        save_cpu_state(ctx, 1);
2103
        gen_op_cp1_enabled();
2104
        op1 = ((ctx->opcode >> 21) & 0x1F);
2105
        switch (op1) {
2106
        case 0x00: /* mfc1 */
2107
        case 0x02: /* cfc1 */
2108
        case 0x04: /* mtc1 */
2109
        case 0x06: /* ctc1 */
2110
            gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
2111
            break;
2112
        case 0x08: /* bc */
2113
            gen_compute_branch1(ctx, rt, imm << 2);
2114
            return;
2115
        case 0x10: /* 16: fmt=single fp */
2116
        case 0x11: /* 17: fmt=double fp */
2117
        case 0x14: /* 20: fmt=32bit fixed */
2118
        case 0x15: /* 21: fmt=64bit fixed */
2119
            gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
2120
            break;
2121
        default:
2122
            generate_exception_err(ctx, EXCP_RI, 1);
2123
            break;
2124
        }
2125
        break;
2126
#else
2127
        generate_exception_err(ctx, EXCP_CpU, 1);
2128
#endif
2129
        break;
2130

    
2131
    /* COP2.  */
2132
    case 0x32: /* LWC2 */
2133
    case 0x36: /* LDC2 */
2134
    case 0x3A: /* SWC2 */
2135
    case 0x3E: /* SDC2 */
2136
    case 0x12:          /* CP2 opcode */
2137
        /* Not implemented */
2138
        generate_exception_err(ctx, EXCP_CpU, 2);
2139
        break;
2140

    
2141
    case 0x13:          /* CP3 opcode */
2142
        /* Not implemented */
2143
        generate_exception_err(ctx, EXCP_CpU, 3);
2144
        break;
2145

    
2146
#if defined (TARGET_MIPS64)
2147
    case 0x18 ... 0x1B:
2148
    case 0x27:
2149
    case 0x34:
2150
    case 0x37:
2151
        /* MIPS64 opcodes */
2152
#endif
2153
#if defined (MIPS_HAS_JALX)
2154
    case 0x1D:
2155
        /* JALX: not implemented */
2156
#endif
2157
    case 0x1E:
2158
        /* ASE specific */
2159
    default:            /* Invalid */
2160
        MIPS_INVAL("");
2161
        generate_exception(ctx, EXCP_RI);
2162
        break;
2163
    }
2164
    if (ctx->hflags & MIPS_HFLAG_BMASK) {
2165
        int hflags = ctx->hflags;
2166
        /* Branches completion */
2167
        ctx->hflags &= ~MIPS_HFLAG_BMASK;
2168
        ctx->bstate = BS_BRANCH;
2169
        save_cpu_state(ctx, 0);
2170
        switch (hflags & MIPS_HFLAG_BMASK) {
2171
        case MIPS_HFLAG_B:
2172
            /* unconditional branch */
2173
            MIPS_DEBUG("unconditional branch");
2174
            gen_goto_tb(ctx, 0, ctx->btarget);
2175
            break;
2176
        case MIPS_HFLAG_BL:
2177
            /* blikely taken case */
2178
            MIPS_DEBUG("blikely branch taken");
2179
            gen_goto_tb(ctx, 0, ctx->btarget);
2180
            break;
2181
        case MIPS_HFLAG_BC:
2182
            /* Conditional branch */
2183
            MIPS_DEBUG("conditional branch");
2184
            {
2185
              int l1;
2186
              l1 = gen_new_label();
2187
              gen_op_jnz_T2(l1);
2188
              gen_goto_tb(ctx, 1, ctx->pc + 4);
2189
              gen_set_label(l1);
2190
              gen_goto_tb(ctx, 0, ctx->btarget);
2191
            }
2192
            break;
2193
        case MIPS_HFLAG_BR:
2194
            /* unconditional branch to register */
2195
            MIPS_DEBUG("branch to register");
2196
            gen_op_breg();
2197
            break;
2198
        default:
2199
            MIPS_DEBUG("unknown branch");
2200
            break;
2201
        }
2202
    }
2203
}
2204

    
2205
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
2206
                                    int search_pc)
2207
{
2208
    DisasContext ctx, *ctxp = &ctx;
2209
    target_ulong pc_start;
2210
    uint16_t *gen_opc_end;
2211
    int j, lj = -1;
2212

    
2213
    if (search_pc && loglevel)
2214
        fprintf (logfile, "search pc %d\n", search_pc);
2215

    
2216
    pc_start = tb->pc;
2217
    gen_opc_ptr = gen_opc_buf;
2218
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2219
    gen_opparam_ptr = gen_opparam_buf;
2220
    nb_gen_labels = 0;
2221
    ctx.pc = pc_start;
2222
    ctx.saved_pc = -1;
2223
    ctx.tb = tb;
2224
    ctx.bstate = BS_NONE;
2225
    /* Restore delay slot state from the tb context.  */
2226
    ctx.hflags = tb->flags;
2227
    ctx.saved_hflags = ctx.hflags;
2228
    if (ctx.hflags & MIPS_HFLAG_BR) {
2229
        gen_op_restore_breg_target();
2230
    } else if (ctx.hflags & MIPS_HFLAG_B) {
2231
        ctx.btarget = env->btarget;
2232
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
2233
        /* If we are in the delay slot of a conditional branch,
2234
         * restore the branch condition from env->bcond to T2
2235
         */
2236
        ctx.btarget = env->btarget;
2237
        gen_op_restore_bcond();
2238
    }
2239
#if defined(CONFIG_USER_ONLY)
2240
    ctx.mem_idx = 0;
2241
#else
2242
    ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
2243
#endif
2244
    ctx.CP0_Status = env->CP0_Status;
2245
#ifdef DEBUG_DISAS
2246
    if (loglevel & CPU_LOG_TB_CPU) {
2247
        fprintf(logfile, "------------------------------------------------\n");
2248
        /* FIXME: This may print out stale hflags from env... */
2249
        cpu_dump_state(env, logfile, fprintf, 0);
2250
    }
2251
#endif
2252
#if defined MIPS_DEBUG_DISAS
2253
    if (loglevel & CPU_LOG_TB_IN_ASM)
2254
        fprintf(logfile, "\ntb %p super %d cond %04x\n",
2255
                tb, ctx.mem_idx, ctx.hflags);
2256
#endif
2257
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
2258
        if (env->nb_breakpoints > 0) {
2259
            for(j = 0; j < env->nb_breakpoints; j++) {
2260
                if (env->breakpoints[j] == ctx.pc) {
2261
                    save_cpu_state(ctxp, 1);
2262
                    ctx.bstate = BS_BRANCH;
2263
                    gen_op_debug();
2264
                    goto done_generating;
2265
                }
2266
            }
2267
        }
2268

    
2269
        if (search_pc) {
2270
            j = gen_opc_ptr - gen_opc_buf;
2271
            if (lj < j) {
2272
                lj++;
2273
                while (lj < j)
2274
                    gen_opc_instr_start[lj++] = 0;
2275
            }
2276
            gen_opc_pc[lj] = ctx.pc;
2277
            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
2278
            gen_opc_instr_start[lj] = 1;
2279
        }
2280
        ctx.opcode = ldl_code(ctx.pc);
2281
        decode_opc(&ctx);
2282
        ctx.pc += 4;
2283

    
2284
        if (env->singlestep_enabled)
2285
            break;
2286

    
2287
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
2288
            break;
2289

    
2290
#if defined (MIPS_SINGLE_STEP)
2291
        break;
2292
#endif
2293
    }
2294
    if (env->singlestep_enabled) {
2295
        save_cpu_state(ctxp, ctx.bstate == BS_NONE);
2296
        gen_op_debug();
2297
        goto done_generating;
2298
    }
2299
    else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
2300
        save_cpu_state(ctxp, 0);
2301
        gen_goto_tb(&ctx, 0, ctx.pc);
2302
    }
2303
    gen_op_reset_T0();
2304
    /* Generate the return instruction */
2305
    gen_op_exit_tb();
2306
done_generating:
2307
    *gen_opc_ptr = INDEX_op_end;
2308
    if (search_pc) {
2309
        j = gen_opc_ptr - gen_opc_buf;
2310
        lj++;
2311
        while (lj <= j)
2312
            gen_opc_instr_start[lj++] = 0;
2313
        tb->size = 0;
2314
    } else {
2315
        tb->size = ctx.pc - pc_start;
2316
    }
2317
#ifdef DEBUG_DISAS
2318
#if defined MIPS_DEBUG_DISAS
2319
    if (loglevel & CPU_LOG_TB_IN_ASM)
2320
        fprintf(logfile, "\n");
2321
#endif
2322
    if (loglevel & CPU_LOG_TB_IN_ASM) {
2323
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2324
    target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
2325
        fprintf(logfile, "\n");
2326
    }
2327
    if (loglevel & CPU_LOG_TB_OP) {
2328
        fprintf(logfile, "OP:\n");
2329
        dump_ops(gen_opc_buf, gen_opparam_buf);
2330
        fprintf(logfile, "\n");
2331
    }
2332
    if (loglevel & CPU_LOG_TB_CPU) {
2333
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
2334
    }
2335
#endif
2336
    
2337
    return 0;
2338
}
2339

    
2340
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
2341
{
2342
    return gen_intermediate_code_internal(env, tb, 0);
2343
}
2344

    
2345
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
2346
{
2347
    return gen_intermediate_code_internal(env, tb, 1);
2348
}
2349

    
2350
#ifdef MIPS_USES_FPU
2351
void fpu_dump_state(CPUState *env, FILE *f, 
2352
                    int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
2353
                    int flags)
2354
{
2355
    int i;
2356

    
2357
#   define printfpr(fp) do { \
2358
        fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
2359
                (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
2360
    } while(0)
2361

    
2362
    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d\n",
2363
                env->fcr0, env->fcr31,
2364
                (env->CP0_Status & (1<<CP0St_FR)) != 0);
2365
    fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
2366
    fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
2367
    fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
2368
    for(i=0; i < 32; i+=2) {
2369
        fpu_fprintf(f, "f%02d: ", i);
2370
        printfpr(FPR(env, i));
2371
    }
2372

    
2373
#undef printfpr
2374
}
2375

    
2376
void dump_fpu(CPUState *env)
2377
{
2378
    if (loglevel) { 
2379
       fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
2380
               env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
2381
       fpu_dump_state(env, logfile, fprintf, 0);
2382
    }
2383
}
2384
#endif /* MIPS_USES_FPU */
2385

    
2386
void cpu_dump_state (CPUState *env, FILE *f, 
2387
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2388
                     int flags)
2389
{
2390
    uint32_t c0_status;
2391
    int i;
2392
    
2393
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
2394
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
2395
    for (i = 0; i < 32; i++) {
2396
        if ((i & 3) == 0)
2397
            cpu_fprintf(f, "GPR%02d:", i);
2398
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
2399
        if ((i & 3) == 3)
2400
            cpu_fprintf(f, "\n");
2401
    }
2402

    
2403
    c0_status = env->CP0_Status;
2404
    if (env->hflags & MIPS_HFLAG_UM)
2405
        c0_status |= (1 << CP0St_UM);
2406
    if (env->hflags & MIPS_HFLAG_ERL)
2407
        c0_status |= (1 << CP0St_ERL);
2408
    if (env->hflags & MIPS_HFLAG_EXL)
2409
        c0_status |= (1 << CP0St_EXL);
2410

    
2411
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
2412
                c0_status, env->CP0_Cause, env->CP0_EPC);
2413
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
2414
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
2415
#ifdef MIPS_USES_FPU
2416
    fpu_dump_state(env, f, cpu_fprintf, flags);
2417
#endif
2418
}
2419

    
2420
CPUMIPSState *cpu_mips_init (void)
2421
{
2422
    CPUMIPSState *env;
2423

    
2424
    env = qemu_mallocz(sizeof(CPUMIPSState));
2425
    if (!env)
2426
        return NULL;
2427
    cpu_exec_init(env);
2428
    tlb_flush(env, 1);
2429
    /* Minimal init */
2430
    env->PC = 0xBFC00000;
2431
#if defined (MIPS_USES_R4K_TLB)
2432
    env->CP0_random = MIPS_TLB_NB - 1;
2433
#endif
2434
    env->CP0_Wired = 0;
2435
    env->CP0_Config0 = MIPS_CONFIG0;
2436
#if defined (MIPS_CONFIG1)
2437
        env->CP0_Config1 = MIPS_CONFIG1;
2438
#endif
2439
#if defined (MIPS_CONFIG2)
2440
        env->CP0_Config2 = MIPS_CONFIG2;
2441
#endif
2442
#if defined (MIPS_CONFIG3)
2443
        env->CP0_Config3 = MIPS_CONFIG3;
2444
#endif
2445
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
2446
    env->CP0_WatchLo = 0;
2447
    env->hflags = MIPS_HFLAG_ERL;
2448
    /* Count register increments in debug mode, EJTAG version 1 */
2449
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
2450
    env->CP0_PRid = MIPS_CPU;
2451
    env->exception_index = EXCP_NONE;
2452
#if defined(CONFIG_USER_ONLY)
2453
    env->hflags |= MIPS_HFLAG_UM;
2454
#endif
2455
#ifdef MIPS_USES_FPU
2456
    env->fcr0 = MIPS_FCR0;        
2457
#endif
2458
    return env;
2459
}