Statistics
| Branch: | Revision:

root / target-mips / translate.c @ 3d9fb9fe

History | View | Annotate | Download (50.1 kB)

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

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

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

    
31
//#define MIPS_DEBUG_DISAS
32
//#define MIPS_SINGLE_STEP
33

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

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

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

    
50
#include "gen-op.h"
51

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

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

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

    
166
    OPC_MOVCI    = 0x01 | EXT_SPECIAL,
167

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

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

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

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

    
220
const unsigned char *regnames[] =
221
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
222
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
223
      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
224
      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
225

    
226
/* Warning: no function for r0 register (hard wired to zero) */
227
#define GEN32(func, NAME) \
228
static GenOpFunc *NAME ## _table [32] = {                                     \
229
NULL,       NAME ## 1, NAME ## 2, NAME ## 3,                                  \
230
NAME ## 4,  NAME ## 5, NAME ## 6, NAME ## 7,                                  \
231
NAME ## 8,  NAME ## 9, NAME ## 10, NAME ## 11,                                \
232
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
233
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
234
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
235
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
236
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
237
};                                                                            \
238
static inline void func(int n)                                                \
239
{                                                                             \
240
    NAME ## _table[n]();                                                      \
241
}
242

    
243
/* General purpose registers moves */
244
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
245
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
246
GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
247

    
248
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
249
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
250

    
251
typedef struct DisasContext {
252
    struct TranslationBlock *tb;
253
    target_ulong pc, saved_pc;
254
    uint32_t opcode;
255
    /* Routine used to access memory */
256
    int mem_idx;
257
    uint32_t hflags, saved_hflags;
258
    uint32_t CP0_Status;
259
    int bstate;
260
    target_ulong btarget;
261
} DisasContext;
262

    
263
enum {
264
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
265
                      * exception condition
266
                      */
267
    BS_STOP     = 1, /* We want to stop translation for any reason */
268
    BS_BRANCH   = 2, /* We reached a branch condition     */
269
    BS_EXCP     = 3, /* We reached an exception condition */
270
};
271

    
272
#if defined MIPS_DEBUG_DISAS
273
#define MIPS_DEBUG(fmt, args...)                                              \
274
do {                                                                          \
275
    if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
276
        fprintf(logfile, "%08x: %08x " fmt "\n",                              \
277
                ctx->pc, ctx->opcode , ##args);                               \
278
    }                                                                         \
279
} while (0)
280
#else
281
#define MIPS_DEBUG(fmt, args...) do { } while(0)
282
#endif
283

    
284
#define MIPS_INVAL(op)                                                        \
285
do {                                                                          \
286
    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
287
               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
288
} while (0)
289

    
290
#define GEN_LOAD_REG_TN(Tn, Rn)                                               \
291
do {                                                                          \
292
    if (Rn == 0) {                                                            \
293
        glue(gen_op_reset_, Tn)();                                            \
294
    } else {                                                                  \
295
        glue(gen_op_load_gpr_, Tn)(Rn);                                       \
296
    }                                                                         \
297
} while (0)
298

    
299
#define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
300
do {                                                                          \
301
    if (Imm == 0) {                                                           \
302
        glue(gen_op_reset_, Tn)();                                            \
303
    } else {                                                                  \
304
        glue(gen_op_set_, Tn)(Imm);                                           \
305
    }                                                                         \
306
} while (0)
307

    
308
#define GEN_STORE_TN_REG(Rn, Tn)                                              \
309
do {                                                                          \
310
    if (Rn != 0) {                                                            \
311
        glue(glue(gen_op_store_, Tn),_gpr)(Rn);                               \
312
    }                                                                         \
313
} while (0)
314

    
315
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
316
{
317
#if defined MIPS_DEBUG_DISAS
318
    if (loglevel & CPU_LOG_TB_IN_ASM) {
319
            fprintf(logfile, "hflags %08x saved %08x\n",
320
                    ctx->hflags, ctx->saved_hflags);
321
    }
322
#endif
323
    if (do_save_pc && ctx->pc != ctx->saved_pc) {
324
        gen_op_save_pc(ctx->pc);
325
        ctx->saved_pc = ctx->pc;
326
    }
327
    if (ctx->hflags != ctx->saved_hflags) {
328
        gen_op_save_state(ctx->hflags);
329
        ctx->saved_hflags = ctx->hflags;
330
        if (ctx->hflags & MIPS_HFLAG_BR) {
331
            gen_op_save_breg_target();
332
        } else if (ctx->hflags & MIPS_HFLAG_B) {
333
            gen_op_save_btarget(ctx->btarget);
334
        } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
335
            gen_op_save_bcond();
336
            gen_op_save_btarget(ctx->btarget);
337
        }
338
    }
339
}
340

    
341
static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
342
{
343
#if defined MIPS_DEBUG_DISAS
344
    if (loglevel & CPU_LOG_TB_IN_ASM)
345
            fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
346
#endif
347
    save_cpu_state(ctx, 1);
348
    if (err == 0)
349
        gen_op_raise_exception(excp);
350
    else
351
        gen_op_raise_exception_err(excp, err);
352
    ctx->bstate = BS_EXCP;
353
}
354

    
355
static inline void generate_exception (DisasContext *ctx, int excp)
356
{
357
    generate_exception_err (ctx, excp, 0);
358
}
359

    
360
#if defined(CONFIG_USER_ONLY)
361
#define op_ldst(name)        gen_op_##name##_raw()
362
#define OP_LD_TABLE(width)
363
#define OP_ST_TABLE(width)
364
#else
365
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
366
#define OP_LD_TABLE(width)                                                    \
367
static GenOpFunc *gen_op_l##width[] = {                                       \
368
    &gen_op_l##width##_user,                                                  \
369
    &gen_op_l##width##_kernel,                                                \
370
}
371
#define OP_ST_TABLE(width)                                                    \
372
static GenOpFunc *gen_op_s##width[] = {                                       \
373
    &gen_op_s##width##_user,                                                  \
374
    &gen_op_s##width##_kernel,                                                \
375
}
376
#endif
377

    
378
#ifdef TARGET_MIPS64
379
OP_LD_TABLE(d);
380
OP_LD_TABLE(dl);
381
OP_LD_TABLE(dr);
382
OP_ST_TABLE(d);
383
OP_ST_TABLE(dl);
384
OP_ST_TABLE(dr);
385
#endif
386
OP_LD_TABLE(w);
387
OP_LD_TABLE(wl);
388
OP_LD_TABLE(wr);
389
OP_ST_TABLE(w);
390
OP_ST_TABLE(wl);
391
OP_ST_TABLE(wr);
392
OP_LD_TABLE(h);
393
OP_LD_TABLE(hu);
394
OP_ST_TABLE(h);
395
OP_LD_TABLE(b);
396
OP_LD_TABLE(bu);
397
OP_ST_TABLE(b);
398
OP_LD_TABLE(l);
399
OP_ST_TABLE(c);
400

    
401
/* Load and store */
402
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
403
                      int base, int16_t offset)
404
{
405
    const unsigned char *opn = "unk";
406

    
407
    if (base == 0) {
408
        GEN_LOAD_IMM_TN(T0, offset);
409
    } else if (offset == 0) {
410
        gen_op_load_gpr_T0(base);
411
    } else {
412
        gen_op_load_gpr_T0(base);
413
        gen_op_set_T1(offset);
414
        gen_op_add();
415
    }
416
    /* Don't do NOP if destination is zero: we must perform the actual
417
     * memory access
418
     */
419
    switch (opc) {
420
#if defined(TARGET_MIPS64)
421
    case OPC_LD:
422
#if defined (MIPS_HAS_UNALIGNED_LS)
423
    case OPC_ULD:
424
#endif
425
        op_ldst(ld);
426
        GEN_STORE_TN_REG(rt, T0);
427
        opn = "ld";
428
        break;
429
    case OPC_SD:
430
#if defined (MIPS_HAS_UNALIGNED_LS)
431
    case OPC_USD:
432
#endif
433
        GEN_LOAD_REG_TN(T1, rt);
434
        op_ldst(sd);
435
        opn = "sd";
436
        break;
437
    case OPC_LDL:
438
        op_ldst(ldl);
439
        GEN_STORE_TN_REG(rt, T0);
440
        opn = "ldl";
441
        break;
442
    case OPC_SDL:
443
        GEN_LOAD_REG_TN(T1, rt);
444
        op_ldst(sdl);
445
        opn = "sdl";
446
        break;
447
    case OPC_LDR:
448
        op_ldst(ldr);
449
        GEN_STORE_TN_REG(rt, T0);
450
        opn = "ldr";
451
        break;
452
    case OPC_SDR:
453
        GEN_LOAD_REG_TN(T1, rt);
454
        op_ldst(sdr);
455
        opn = "sdr";
456
        break;
457
#endif
458
    case OPC_LW:
459
#if defined (MIPS_HAS_UNALIGNED_LS)
460
    case OPC_ULW:
461
#endif
462
        op_ldst(lw);
463
        GEN_STORE_TN_REG(rt, T0);
464
        opn = "lw";
465
        break;
466
    case OPC_SW:
467
#if defined (MIPS_HAS_UNALIGNED_LS)
468
    case OPC_USW:
469
#endif
470
        GEN_LOAD_REG_TN(T1, rt);
471
        op_ldst(sw);
472
        opn = "sw";
473
        break;
474
    case OPC_LH:
475
#if defined (MIPS_HAS_UNALIGNED_LS)
476
    case OPC_ULH:
477
#endif
478
        op_ldst(lh);
479
        GEN_STORE_TN_REG(rt, T0);
480
        opn = "lh";
481
        break;
482
    case OPC_SH:
483
#if defined (MIPS_HAS_UNALIGNED_LS)
484
    case OPC_USH:
485
#endif
486
        GEN_LOAD_REG_TN(T1, rt);
487
        op_ldst(sh);
488
        opn = "sh";
489
        break;
490
    case OPC_LHU:
491
#if defined (MIPS_HAS_UNALIGNED_LS)
492
    case OPC_ULHU:
493
#endif
494
        op_ldst(lhu);
495
        GEN_STORE_TN_REG(rt, T0);
496
        opn = "lhu";
497
        break;
498
    case OPC_LB:
499
        op_ldst(lb);
500
        GEN_STORE_TN_REG(rt, T0);
501
        opn = "lb";
502
        break;
503
    case OPC_SB:
504
        GEN_LOAD_REG_TN(T1, rt);
505
        op_ldst(sb);
506
        opn = "sb";
507
        break;
508
    case OPC_LBU:
509
        op_ldst(lbu);
510
        GEN_STORE_TN_REG(rt, T0);
511
        opn = "lbu";
512
        break;
513
    case OPC_LWL:
514
        GEN_LOAD_REG_TN(T1, rt);
515
        op_ldst(lwl);
516
        GEN_STORE_TN_REG(rt, T0);
517
        opn = "lwl";
518
        break;
519
    case OPC_SWL:
520
        GEN_LOAD_REG_TN(T1, rt);
521
        op_ldst(swl);
522
        opn = "swr";
523
        break;
524
    case OPC_LWR:
525
        GEN_LOAD_REG_TN(T1, rt);
526
        op_ldst(lwr);
527
        GEN_STORE_TN_REG(rt, T0);
528
        opn = "lwr";
529
        break;
530
    case OPC_SWR:
531
        GEN_LOAD_REG_TN(T1, rt);
532
        op_ldst(swr);
533
        opn = "swr";
534
        break;
535
    case OPC_LL:
536
        op_ldst(ll);
537
        GEN_STORE_TN_REG(rt, T0);
538
        opn = "ll";
539
        break;
540
    case OPC_SC:
541
        GEN_LOAD_REG_TN(T1, rt);
542
        op_ldst(sc);
543
        GEN_STORE_TN_REG(rt, T0);
544
        opn = "sc";
545
        break;
546
    default:
547
        MIPS_INVAL("load/store");
548
        generate_exception(ctx, EXCP_RI);
549
        return;
550
    }
551
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
552
}
553

    
554
/* Arithmetic with immediate operand */
555
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
556
                           int rs, int16_t imm)
557
{
558
    uint32_t uimm;
559
    const unsigned char *opn = "unk";
560

    
561
    if (rt == 0 && opc != OPC_ADDI) {
562
        /* if no destination, treat it as a NOP 
563
         * For addi, we must generate the overflow exception when needed.
564
         */
565
        MIPS_DEBUG("NOP");
566
        return;
567
    }
568
    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
569
        opc == OPC_SLTI || opc == OPC_SLTIU)
570
        uimm = (int32_t)imm; /* Sign extent to 32 bits */
571
    else
572
        uimm = (uint16_t)imm;
573
    if (opc != OPC_LUI) {
574
        GEN_LOAD_REG_TN(T0, rs);
575
        GEN_LOAD_IMM_TN(T1, uimm);
576
    } else {
577
        uimm = uimm << 16;
578
        GEN_LOAD_IMM_TN(T0, uimm);
579
    }
580
    switch (opc) {
581
    case OPC_ADDI:
582
        save_cpu_state(ctx, 1);
583
        gen_op_addo();
584
        opn = "addi";
585
        break;
586
    case OPC_ADDIU:
587
        gen_op_add();
588
        opn = "addiu";
589
        break;
590
    case OPC_SLTI:
591
        gen_op_lt();
592
        opn = "slti";
593
        break;
594
    case OPC_SLTIU:
595
        gen_op_ltu();
596
        opn = "sltiu";
597
        break;
598
    case OPC_ANDI:
599
        gen_op_and();
600
        opn = "andi";
601
        break;
602
    case OPC_ORI:
603
        gen_op_or();
604
        opn = "ori";
605
        break;
606
    case OPC_XORI:
607
        gen_op_xor();
608
        opn = "xori";
609
        break;
610
    case OPC_LUI:
611
        opn = "lui";
612
        break;
613
    case OPC_SLL:
614
        gen_op_sll();
615
        opn = "sll";
616
        break;
617
    case OPC_SRA:
618
        gen_op_sra();
619
        opn = "sra";
620
        break;
621
    case OPC_SRL:
622
        gen_op_srl();
623
        opn = "srl";
624
        break;
625
    default:
626
        MIPS_INVAL("imm arith");
627
        generate_exception(ctx, EXCP_RI);
628
        return;
629
    }
630
    GEN_STORE_TN_REG(rt, T0);
631
    MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
632
}
633

    
634
/* Arithmetic */
635
static void gen_arith (DisasContext *ctx, uint16_t opc,
636
                       int rd, int rs, int rt)
637
{
638
    const unsigned char *opn = "unk";
639

    
640
    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
641
        /* if no destination, treat it as a NOP 
642
         * For add & sub, we must generate the overflow exception when needed.
643
         */
644
        MIPS_DEBUG("NOP");
645
        return;
646
    }
647
    GEN_LOAD_REG_TN(T0, rs);
648
    GEN_LOAD_REG_TN(T1, rt);
649
    switch (opc) {
650
    case OPC_ADD:
651
        save_cpu_state(ctx, 1);
652
        gen_op_addo();
653
        opn = "add";
654
        break;
655
    case OPC_ADDU:
656
        gen_op_add();
657
        opn = "addu";
658
        break;
659
    case OPC_SUB:
660
        save_cpu_state(ctx, 1);
661
        gen_op_subo();
662
        opn = "sub";
663
        break;
664
    case OPC_SUBU:
665
        gen_op_sub();
666
        opn = "subu";
667
        break;
668
    case OPC_SLT:
669
        gen_op_lt();
670
        opn = "slt";
671
        break;
672
    case OPC_SLTU:
673
        gen_op_ltu();
674
        opn = "sltu";
675
        break;
676
    case OPC_AND:
677
        gen_op_and();
678
        opn = "and";
679
        break;
680
    case OPC_NOR:
681
        gen_op_nor();
682
        opn = "nor";
683
        break;
684
    case OPC_OR:
685
        gen_op_or();
686
        opn = "or";
687
        break;
688
    case OPC_XOR:
689
        gen_op_xor();
690
        opn = "xor";
691
        break;
692
    case OPC_MUL:
693
        gen_op_mul();
694
        opn = "mul";
695
        break;
696
    case OPC_MOVN:
697
        gen_op_movn(rd);
698
        opn = "movn";
699
        goto print;
700
    case OPC_MOVZ:
701
        gen_op_movz(rd);
702
        opn = "movz";
703
        goto print;
704
    case OPC_SLLV:
705
        gen_op_sllv();
706
        opn = "sllv";
707
        break;
708
    case OPC_SRAV:
709
        gen_op_srav();
710
        opn = "srav";
711
        break;
712
    case OPC_SRLV:
713
        gen_op_srlv();
714
        opn = "srlv";
715
        break;
716
    default:
717
        MIPS_INVAL("arith");
718
        generate_exception(ctx, EXCP_RI);
719
        return;
720
    }
721
    GEN_STORE_TN_REG(rd, T0);
722
 print:
723
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
724
}
725

    
726
/* Arithmetic on HI/LO registers */
727
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
728
{
729
    const unsigned char *opn = "unk";
730

    
731
    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
732
        /* Treat as a NOP */
733
        MIPS_DEBUG("NOP");
734
        return;
735
    }
736
    switch (opc) {
737
    case OPC_MFHI:
738
        gen_op_load_HI();
739
        GEN_STORE_TN_REG(reg, T0);
740
        opn = "mfhi";
741
        break;
742
    case OPC_MFLO:
743
        gen_op_load_LO();
744
        GEN_STORE_TN_REG(reg, T0);
745
        opn = "mflo";
746
        break;
747
    case OPC_MTHI:
748
        GEN_LOAD_REG_TN(T0, reg);
749
        gen_op_store_HI();
750
        opn = "mthi";
751
        break;
752
    case OPC_MTLO:
753
        GEN_LOAD_REG_TN(T0, reg);
754
        gen_op_store_LO();
755
        opn = "mtlo";
756
        break;
757
    default:
758
        MIPS_INVAL("HILO");
759
        generate_exception(ctx, EXCP_RI);
760
        return;
761
    }
762
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
763
}
764

    
765
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
766
                        int rs, int rt)
767
{
768
    const unsigned char *opn = "unk";
769

    
770
    GEN_LOAD_REG_TN(T0, rs);
771
    GEN_LOAD_REG_TN(T1, rt);
772
    switch (opc) {
773
    case OPC_DIV:
774
        gen_op_div();
775
        opn = "div";
776
        break;
777
    case OPC_DIVU:
778
        gen_op_divu();
779
        opn = "divu";
780
        break;
781
    case OPC_MULT:
782
        gen_op_mult();
783
        opn = "mult";
784
        break;
785
    case OPC_MULTU:
786
        gen_op_multu();
787
        opn = "multu";
788
        break;
789
    case OPC_MADD:
790
        gen_op_madd();
791
        opn = "madd";
792
        break;
793
    case OPC_MADDU:
794
        gen_op_maddu();
795
        opn = "maddu";
796
        break;
797
    case OPC_MSUB:
798
        gen_op_msub();
799
        opn = "msub";
800
        break;
801
    case OPC_MSUBU:
802
        gen_op_msubu();
803
        opn = "msubu";
804
        break;
805
    default:
806
        MIPS_INVAL("mul/div");
807
        generate_exception(ctx, EXCP_RI);
808
        return;
809
    }
810
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
811
}
812

    
813
static void gen_cl (DisasContext *ctx, uint16_t opc,
814
                    int rd, int rs)
815
{
816
    const unsigned char *opn = "unk";
817
    if (rd == 0) {
818
        /* Treat as a NOP */
819
        MIPS_DEBUG("NOP");
820
        return;
821
    }
822
    GEN_LOAD_REG_TN(T0, rs);
823
    switch (opc) {
824
    case OPC_CLO:
825
        /* CLO */
826
        gen_op_clo();
827
        opn = "clo";
828
        break;
829
    case OPC_CLZ:
830
        /* CLZ */
831
        gen_op_clz();
832
        opn = "clz";
833
        break;
834
    default:
835
        MIPS_INVAL("CLx");
836
        generate_exception(ctx, EXCP_RI);
837
        return;
838
    }
839
    gen_op_store_T0_gpr(rd);
840
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
841
}
842

    
843
/* Traps */
844
static void gen_trap (DisasContext *ctx, uint16_t opc,
845
                      int rs, int rt, int16_t imm)
846
{
847
    int cond;
848

    
849
    cond = 0;
850
    /* Load needed operands */
851
    switch (opc) {
852
    case OPC_TEQ:
853
    case OPC_TGE:
854
    case OPC_TGEU:
855
    case OPC_TLT:
856
    case OPC_TLTU:
857
    case OPC_TNE:
858
        /* Compare two registers */
859
        if (rs != rt) {
860
            GEN_LOAD_REG_TN(T0, rs);
861
            GEN_LOAD_REG_TN(T1, rt);
862
            cond = 1;
863
        }
864
    case OPC_TEQI:
865
    case OPC_TGEI:
866
    case OPC_TGEIU:
867
    case OPC_TLTI:
868
    case OPC_TLTIU:
869
    case OPC_TNEI:
870
        /* Compare register to immediate */
871
        if (rs != 0 || imm != 0) {
872
            GEN_LOAD_REG_TN(T0, rs);
873
            GEN_LOAD_IMM_TN(T1, (int32_t)imm);
874
            cond = 1;
875
        }
876
        break;
877
    }
878
    if (cond == 0) {
879
        switch (opc) {
880
        case OPC_TEQ:   /* rs == rs */
881
        case OPC_TEQI:  /* r0 == 0  */
882
        case OPC_TGE:   /* rs >= rs */
883
        case OPC_TGEI:  /* r0 >= 0  */
884
        case OPC_TGEU:  /* rs >= rs unsigned */
885
        case OPC_TGEIU: /* r0 >= 0  unsigned */
886
            /* Always trap */
887
            gen_op_set_T0(1);
888
            break;
889
        case OPC_TLT:   /* rs < rs           */
890
        case OPC_TLTI:  /* r0 < 0            */
891
        case OPC_TLTU:  /* rs < rs unsigned  */
892
        case OPC_TLTIU: /* r0 < 0  unsigned  */
893
        case OPC_TNE:   /* rs != rs          */
894
        case OPC_TNEI:  /* r0 != 0           */
895
            /* Never trap: treat as NOP */
896
            return;
897
        default:
898
            MIPS_INVAL("TRAP");
899
            generate_exception(ctx, EXCP_RI);
900
            return;
901
        }
902
    } else {
903
        switch (opc) {
904
        case OPC_TEQ:
905
        case OPC_TEQI:
906
            gen_op_eq();
907
            break;
908
        case OPC_TGE:
909
        case OPC_TGEI:
910
            gen_op_ge();
911
            break;
912
        case OPC_TGEU:
913
        case OPC_TGEIU:
914
            gen_op_geu();
915
            break;
916
        case OPC_TLT:
917
        case OPC_TLTI:
918
            gen_op_lt();
919
            break;
920
        case OPC_TLTU:
921
        case OPC_TLTIU:
922
            gen_op_ltu();
923
            break;
924
        case OPC_TNE:
925
        case OPC_TNEI:
926
            gen_op_ne();
927
            break;
928
        default:
929
            MIPS_INVAL("TRAP");
930
            generate_exception(ctx, EXCP_RI);
931
            return;
932
        }
933
    }
934
    save_cpu_state(ctx, 1);
935
    gen_op_trap();
936
    ctx->bstate = BS_STOP;
937
}
938

    
939
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
940
{
941
    TranslationBlock *tb;
942
    tb = ctx->tb;
943
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
944
        if (n == 0)
945
            gen_op_goto_tb0(TBPARAM(tb));
946
        else
947
            gen_op_goto_tb1(TBPARAM(tb));
948
        gen_op_save_pc(dest);
949
        gen_op_set_T0((long)tb + n);
950
        gen_op_exit_tb();
951
    } else {
952
        gen_op_save_pc(dest);
953
        gen_op_set_T0(0);
954
        gen_op_exit_tb();
955
    }
956
}
957

    
958
/* Branches (before delay slot) */
959
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
960
                                int rs, int rt, int32_t offset)
961
{
962
    target_ulong btarget;
963
    int blink, bcond;
964

    
965
    btarget = -1;
966
    blink = 0;
967
    bcond = 0;
968
    /* Load needed operands */
969
    switch (opc) {
970
    case OPC_BEQ:
971
    case OPC_BEQL:
972
    case OPC_BNE:
973
    case OPC_BNEL:
974
        /* Compare two registers */
975
        if (rs != rt) {
976
            GEN_LOAD_REG_TN(T0, rs);
977
            GEN_LOAD_REG_TN(T1, rt);
978
            bcond = 1;
979
        }
980
        btarget = ctx->pc + 4 + offset;
981
        break;
982
    case OPC_BGEZ:
983
    case OPC_BGEZAL:
984
    case OPC_BGEZALL:
985
    case OPC_BGEZL:
986
    case OPC_BGTZ:
987
    case OPC_BGTZL:
988
    case OPC_BLEZ:
989
    case OPC_BLEZL:
990
    case OPC_BLTZ:
991
    case OPC_BLTZAL:
992
    case OPC_BLTZALL:
993
    case OPC_BLTZL:
994
        /* Compare to zero */
995
        if (rs != 0) {
996
            gen_op_load_gpr_T0(rs);
997
            bcond = 1;
998
        }
999
        btarget = ctx->pc + 4 + offset;
1000
        break;
1001
    case OPC_J:
1002
    case OPC_JAL:
1003
        /* Jump to immediate */
1004
        btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
1005
        break;
1006
    case OPC_JR:
1007
    case OPC_JALR:
1008
        /* Jump to register */
1009
        if (offset != 0) {
1010
            /* Only hint = 0 is valid */
1011
            generate_exception(ctx, EXCP_RI);
1012
            return;
1013
        }
1014
        GEN_LOAD_REG_TN(T2, rs);
1015
        break;
1016
    default:
1017
        MIPS_INVAL("branch/jump");
1018
        generate_exception(ctx, EXCP_RI);
1019
        return;
1020
    }
1021
    if (bcond == 0) {
1022
        /* No condition to be computed */
1023
        switch (opc) {
1024
        case OPC_BEQ:     /* rx == rx        */
1025
        case OPC_BEQL:    /* rx == rx likely */
1026
        case OPC_BGEZ:    /* 0 >= 0          */
1027
        case OPC_BGEZL:   /* 0 >= 0 likely   */
1028
        case OPC_BLEZ:    /* 0 <= 0          */
1029
        case OPC_BLEZL:   /* 0 <= 0 likely   */
1030
            /* Always take */
1031
            ctx->hflags |= MIPS_HFLAG_B;
1032
            MIPS_DEBUG("balways");
1033
            break;
1034
        case OPC_BGEZAL:  /* 0 >= 0          */
1035
        case OPC_BGEZALL: /* 0 >= 0 likely   */
1036
            /* Always take and link */
1037
            blink = 31;
1038
            ctx->hflags |= MIPS_HFLAG_B;
1039
            MIPS_DEBUG("balways and link");
1040
            break;
1041
        case OPC_BNE:     /* rx != rx        */
1042
        case OPC_BGTZ:    /* 0 > 0           */
1043
        case OPC_BLTZ:    /* 0 < 0           */
1044
            /* Treated as NOP */
1045
            MIPS_DEBUG("bnever (NOP)");
1046
            return;
1047
        case OPC_BLTZAL:  /* 0 < 0           */
1048
            gen_op_set_T0(ctx->pc + 8);
1049
            gen_op_store_T0_gpr(31);
1050
            return;
1051
        case OPC_BLTZALL: /* 0 < 0 likely */
1052
            gen_op_set_T0(ctx->pc + 8);
1053
            gen_op_store_T0_gpr(31);
1054
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1055
            return;
1056
        case OPC_BNEL:    /* rx != rx likely */
1057
        case OPC_BGTZL:   /* 0 > 0 likely */
1058
        case OPC_BLTZL:   /* 0 < 0 likely */
1059
            /* Skip the instruction in the delay slot */
1060
            MIPS_DEBUG("bnever and skip");
1061
            gen_goto_tb(ctx, 0, ctx->pc + 4);
1062
            return;
1063
        case OPC_J:
1064
            ctx->hflags |= MIPS_HFLAG_B;
1065
            MIPS_DEBUG("j %08x", btarget);
1066
            break;
1067
        case OPC_JAL:
1068
            blink = 31;
1069
            ctx->hflags |= MIPS_HFLAG_B;
1070
            MIPS_DEBUG("jal %08x", btarget);
1071
            break;
1072
        case OPC_JR:
1073
            ctx->hflags |= MIPS_HFLAG_BR;
1074
            MIPS_DEBUG("jr %s", regnames[rs]);
1075
            break;
1076
        case OPC_JALR:
1077
            blink = rt;
1078
            ctx->hflags |= MIPS_HFLAG_BR;
1079
            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1080
            break;
1081
        default:
1082
            MIPS_INVAL("branch/jump");
1083
            generate_exception(ctx, EXCP_RI);
1084
            return;
1085
        }
1086
    } else {
1087
        switch (opc) {
1088
        case OPC_BEQ:
1089
            gen_op_eq();
1090
            MIPS_DEBUG("beq %s, %s, %08x",
1091
                       regnames[rs], regnames[rt], btarget);
1092
            goto not_likely;
1093
        case OPC_BEQL:
1094
            gen_op_eq();
1095
            MIPS_DEBUG("beql %s, %s, %08x",
1096
                       regnames[rs], regnames[rt], btarget);
1097
            goto likely;
1098
        case OPC_BNE:
1099
            gen_op_ne();
1100
            MIPS_DEBUG("bne %s, %s, %08x",
1101
                       regnames[rs], regnames[rt], btarget);
1102
            goto not_likely;
1103
        case OPC_BNEL:
1104
            gen_op_ne();
1105
            MIPS_DEBUG("bnel %s, %s, %08x",
1106
                       regnames[rs], regnames[rt], btarget);
1107
            goto likely;
1108
        case OPC_BGEZ:
1109
            gen_op_gez();
1110
            MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1111
            goto not_likely;
1112
        case OPC_BGEZL:
1113
            gen_op_gez();
1114
            MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1115
            goto likely;
1116
        case OPC_BGEZAL:
1117
            gen_op_gez();
1118
            MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1119
            blink = 31;
1120
            goto not_likely;
1121
        case OPC_BGEZALL:
1122
            gen_op_gez();
1123
            blink = 31;
1124
            MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1125
            goto likely;
1126
        case OPC_BGTZ:
1127
            gen_op_gtz();
1128
            MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1129
            goto not_likely;
1130
        case OPC_BGTZL:
1131
            gen_op_gtz();
1132
            MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1133
            goto likely;
1134
        case OPC_BLEZ:
1135
            gen_op_lez();
1136
            MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1137
            goto not_likely;
1138
        case OPC_BLEZL:
1139
            gen_op_lez();
1140
            MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1141
            goto likely;
1142
        case OPC_BLTZ:
1143
            gen_op_ltz();
1144
            MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1145
            goto not_likely;
1146
        case OPC_BLTZL:
1147
            gen_op_ltz();
1148
            MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1149
            goto likely;
1150
        case OPC_BLTZAL:
1151
            gen_op_ltz();
1152
            blink = 31;
1153
            MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1154
        not_likely:
1155
            ctx->hflags |= MIPS_HFLAG_BC;
1156
            break;
1157
        case OPC_BLTZALL:
1158
            gen_op_ltz();
1159
            blink = 31;
1160
            MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1161
        likely:
1162
            ctx->hflags |= MIPS_HFLAG_BL;
1163
            break;
1164
        }
1165
        gen_op_set_bcond();
1166
    }
1167
    MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1168
               blink, ctx->hflags, btarget);
1169
    ctx->btarget = btarget;
1170
    if (blink > 0) {
1171
        gen_op_set_T0(ctx->pc + 8);
1172
        gen_op_store_T0_gpr(blink);
1173
    }
1174
    return;
1175
}
1176

    
1177
/* CP0 (MMU and control) */
1178
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1179
{
1180
    const unsigned char *opn = "unk";
1181

    
1182
    if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1183
        (ctx->hflags & MIPS_HFLAG_UM) &&
1184
        !(ctx->hflags & MIPS_HFLAG_ERL) &&
1185
        !(ctx->hflags & MIPS_HFLAG_EXL)) {
1186
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1187
            fprintf(logfile, "CP0 is not usable\n");
1188
        }
1189
        generate_exception_err (ctx, EXCP_CpU, 0);
1190
        return;
1191
    }
1192
    switch (opc) {
1193
    case OPC_MFC0:
1194
        if (rt == 0) {
1195
            /* Treat as NOP */
1196
            return;
1197
        }
1198
        gen_op_mfc0(rd, ctx->opcode & 0x7);
1199
        gen_op_store_T0_gpr(rt);
1200
        opn = "mfc0";
1201
        break;
1202
    case OPC_MTC0:
1203
        /* If we get an exception, we want to restart at next instruction */
1204
        ctx->pc += 4;
1205
        save_cpu_state(ctx, 1);
1206
        ctx->pc -= 4;
1207
        GEN_LOAD_REG_TN(T0, rt);
1208
        gen_op_mtc0(rd, ctx->opcode & 0x7);
1209
        /* Stop translation as we may have switched the execution mode */
1210
        ctx->bstate = BS_STOP;
1211
        opn = "mtc0";
1212
        break;
1213
#if defined(MIPS_USES_R4K_TLB)
1214
    case OPC_TLBWI:
1215
        gen_op_tlbwi();
1216
        opn = "tlbwi";
1217
        break;
1218
    case OPC_TLBWR:
1219
        gen_op_tlbwr();
1220
        opn = "tlbwr";
1221
        break;
1222
    case OPC_TLBP:
1223
        gen_op_tlbp();
1224
        opn = "tlbp";
1225
        break;
1226
    case OPC_TLBR:
1227
        gen_op_tlbr();
1228
        opn = "tlbr";
1229
        break;
1230
#endif
1231
    case OPC_ERET:
1232
        opn = "eret";
1233
        save_cpu_state(ctx, 0);
1234
        gen_op_eret();
1235
        ctx->bstate = BS_EXCP;
1236
        break;
1237
    case OPC_DERET:
1238
        opn = "deret";
1239
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1240
            generate_exception(ctx, EXCP_RI);
1241
        } else {
1242
            save_cpu_state(ctx, 0);
1243
            gen_op_deret();
1244
            ctx->bstate = BS_EXCP;
1245
        }
1246
        break;
1247
    case OPC_WAIT:
1248
        opn = "wait";
1249
        /* If we get an exception, we want to restart at next instruction */
1250
        ctx->pc += 4;
1251
        save_cpu_state(ctx, 1);
1252
        ctx->pc -= 4;
1253
        gen_op_wait();
1254
        ctx->bstate = BS_EXCP;
1255
        break;
1256
    default:
1257
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1258
            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1259
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1260
                    ((ctx->opcode >> 16) & 0x1F));
1261
        }
1262
        generate_exception(ctx, EXCP_RI);
1263
        return;
1264
    }
1265
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1266
}
1267

    
1268
/* Coprocessor 1 (FPU) */
1269

    
1270
/* ISA extensions */
1271
/* MIPS16 extension to MIPS32 */
1272
/* SmartMIPS extension to MIPS32 */
1273

    
1274
#ifdef TARGET_MIPS64
1275
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1276
{
1277
    if (func == 0x02 && rd == 0) {
1278
        /* NOP */
1279
        return;
1280
    }
1281
    if (rs == 0 || rt == 0) {
1282
        gen_op_reset_T0();
1283
        gen_op_save64();
1284
    } else {
1285
        gen_op_load_gpr_T0(rs);
1286
        gen_op_load_gpr_T1(rt);
1287
        gen_op_save64();
1288
        if (func & 0x01)
1289
            gen_op_mul64u();
1290
        else
1291
            gen_op_mul64s();
1292
    }
1293
    if (func & 0x02)
1294
        gen_op_add64();
1295
    else
1296
        gen_op_sub64();
1297
}
1298

    
1299
/* Coprocessor 3 (FPU) */
1300

    
1301
/* MDMX extension to MIPS64 */
1302
/* MIPS-3D extension to MIPS64 */
1303

    
1304
#endif
1305

    
1306
static void gen_blikely(DisasContext *ctx)
1307
{
1308
    int l1;
1309
    l1 = gen_new_label();
1310
    gen_op_jnz_T2(l1);
1311
    gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
1312
    gen_goto_tb(ctx, 1, ctx->pc + 4);
1313
    gen_set_label(l1);
1314
}
1315

    
1316
static void decode_opc (DisasContext *ctx)
1317
{
1318
    int32_t offset;
1319
    int rs, rt, rd, sa;
1320
    uint16_t op, op1;
1321
    int16_t imm;
1322

    
1323
    if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
1324
        /* Handle blikely not taken case */
1325
        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1326
        gen_blikely(ctx);
1327
    }
1328
    op = ctx->opcode >> 26;
1329
    rs = ((ctx->opcode >> 21) & 0x1F);
1330
    rt = ((ctx->opcode >> 16) & 0x1F);
1331
    rd = ((ctx->opcode >> 11) & 0x1F);
1332
    sa = ((ctx->opcode >> 6) & 0x1F);
1333
    imm = (int16_t)ctx->opcode;
1334
    switch (op) {
1335
    case 0x00:          /* Special opcode */
1336
        op1 = ctx->opcode & 0x3F;
1337
        switch (op1) {
1338
        case 0x00:          /* Arithmetic with immediate */
1339
        case 0x02 ... 0x03:
1340
            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1341
            break;
1342
        case 0x04:          /* Arithmetic */
1343
        case 0x06 ... 0x07:
1344
        case 0x0A ... 0x0B:
1345
        case 0x20 ... 0x27:
1346
        case 0x2A ... 0x2B:
1347
            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1348
            break;
1349
        case 0x18 ... 0x1B: /* MULT / DIV */
1350
            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1351
            break;
1352
        case 0x08 ... 0x09: /* Jumps */
1353
            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1354
            return;
1355
        case 0x30 ... 0x34: /* Traps */
1356
        case 0x36:
1357
            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1358
            break;
1359
        case 0x10:          /* Move from HI/LO */
1360
        case 0x12:
1361
            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1362
            break;
1363
        case 0x11:
1364
        case 0x13:          /* Move to HI/LO */
1365
            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1366
            break;
1367
        case 0x0C:          /* SYSCALL */
1368
            generate_exception(ctx, EXCP_SYSCALL);
1369
            break;
1370
        case 0x0D:          /* BREAK */
1371
            generate_exception(ctx, EXCP_BREAK);
1372
            break;
1373
        case 0x0F:          /* SYNC */
1374
            /* Treat as a noop */
1375
            break;
1376
        case 0x05:          /* Pmon entry point */
1377
            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1378
            break;
1379

    
1380
        case 0x01:          /* MOVCI */
1381
#if defined (MIPS_HAS_MOVCI)
1382
            /* XXX */
1383
#else
1384
            /* Not implemented */
1385
            generate_exception_err (ctx, EXCP_CpU, 1);
1386
#endif
1387
            break;
1388

    
1389
#if defined (TARGET_MIPS64)
1390
        case 0x14: /* MIPS64 specific opcodes */
1391
        case 0x16:
1392
        case 0x17:
1393
        case 0x1C ... 0x1F:
1394
        case 0x2C ... 0x2F:
1395
        case 0x37:
1396
        case 0x39 ... 0x3B:
1397
        case 0x3E ... 0x3F:
1398
#endif
1399
        default:            /* Invalid */
1400
            MIPS_INVAL("special");
1401
            generate_exception(ctx, EXCP_RI);
1402
            break;
1403
        }
1404
        break;
1405
    case 0x1C:          /* Special2 opcode */
1406
        op1 = ctx->opcode & 0x3F;
1407
        switch (op1) {
1408
#if defined (MIPS_USES_R4K_EXT)
1409
        /* Those instructions are not part of MIPS32 core */
1410
        case 0x00 ... 0x01: /* Multiply and add/sub */
1411
        case 0x04 ... 0x05:
1412
            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1413
            break;
1414
        case 0x02:          /* MUL */
1415
            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1416
            break;
1417
        case 0x20 ... 0x21: /* CLO / CLZ */
1418
            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1419
            break;
1420
#endif
1421
        case 0x3F:          /* SDBBP */
1422
            /* XXX: not clear which exception should be raised
1423
             *      when in debug mode...
1424
             */
1425
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1426
                generate_exception(ctx, EXCP_DBp);
1427
            } else {
1428
                generate_exception(ctx, EXCP_DBp);
1429
            }
1430
            /* Treat as a noop */
1431
            break;
1432
        default:            /* Invalid */
1433
            MIPS_INVAL("special2");
1434
            generate_exception(ctx, EXCP_RI);
1435
            break;
1436
        }
1437
        break;
1438
    case 0x01:          /* B REGIMM opcode */
1439
        op1 = ((ctx->opcode >> 16) & 0x1F);
1440
        switch (op1) {
1441
        case 0x00 ... 0x03: /* REGIMM branches */
1442
        case 0x10 ... 0x13:
1443
            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
1444
            return;
1445
        case 0x08 ... 0x0C: /* Traps */
1446
        case 0x0E:
1447
            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
1448
            break;
1449
        default:            /* Invalid */
1450
            MIPS_INVAL("REGIMM");
1451
            generate_exception(ctx, EXCP_RI);
1452
            break;
1453
        }
1454
        break;
1455
    case 0x10:          /* CP0 opcode */
1456
        op1 = ((ctx->opcode >> 21) & 0x1F);
1457
        switch (op1) {
1458
        case 0x00:
1459
        case 0x04:
1460
            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
1461
            break;
1462
        default:
1463
            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
1464
            break;
1465
        }
1466
        break;
1467
    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
1468
        gen_arith_imm(ctx, op, rt, rs, imm);
1469
        break;
1470
    case 0x02 ... 0x03: /* Jump */
1471
        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
1472
        gen_compute_branch(ctx, op, rs, rt, offset);
1473
        return;
1474
    case 0x04 ... 0x07: /* Branch */
1475
    case 0x14 ... 0x17:
1476
        gen_compute_branch(ctx, op, rs, rt, imm << 2);
1477
        return;
1478
    case 0x20 ... 0x26: /* Load and stores */
1479
    case 0x28 ... 0x2E:
1480
    case 0x30:
1481
    case 0x38:
1482
        gen_ldst(ctx, op, rt, rs, imm);
1483
        break;
1484
    case 0x2F:          /* Cache operation */
1485
        /* Treat as a noop */
1486
        break;
1487
    case 0x33:          /* Prefetch */
1488
        /* Treat as a noop */
1489
        break;
1490
    case 0x3F: /* HACK */
1491
        break;
1492

    
1493
    /* Floating point.  */
1494
    case 0x31: /* LWC1 */
1495
    case 0x35: /* LDC1 */
1496
    case 0x39: /* SWC1 */
1497
    case 0x3D: /* SDC1 */
1498
    case 0x11:          /* CP1 opcode */
1499
#if defined(MIPS_USES_FPU)
1500
        /* XXX: not correct */
1501
#else
1502
        generate_exception_err(ctx, EXCP_CpU, 1);
1503
#endif
1504
        break;
1505

    
1506
    /* COP2.  */
1507
    case 0x32: /* LWC2 */
1508
    case 0x36: /* LDC2 */
1509
    case 0x3A: /* SWC2 */
1510
    case 0x3E: /* SDC2 */
1511
    case 0x12:          /* CP2 opcode */
1512
        /* Not implemented */
1513
        generate_exception_err(ctx, EXCP_CpU, 2);
1514
        break;
1515

    
1516
    case 0x13:          /* CP3 opcode */
1517
        /* Not implemented */
1518
        generate_exception_err(ctx, EXCP_CpU, 3);
1519
        break;
1520

    
1521
#if defined (TARGET_MIPS64)
1522
    case 0x18 ... 0x1B:
1523
    case 0x27:
1524
    case 0x34:
1525
    case 0x37:
1526
        /* MIPS64 opcodes */
1527
#endif
1528
#if defined (MIPS_HAS_JALX)
1529
    case 0x1D:
1530
        /* JALX: not implemented */
1531
#endif
1532
    case 0x1E:
1533
        /* ASE specific */
1534
    default:            /* Invalid */
1535
        MIPS_INVAL("");
1536
        generate_exception(ctx, EXCP_RI);
1537
        break;
1538
    }
1539
    if (ctx->hflags & MIPS_HFLAG_BMASK) {
1540
        int hflags = ctx->hflags;
1541
        /* Branches completion */
1542
        ctx->hflags &= ~MIPS_HFLAG_BMASK;
1543
        ctx->bstate = BS_BRANCH;
1544
        save_cpu_state(ctx, 0);
1545
        switch (hflags & MIPS_HFLAG_BMASK) {
1546
        case MIPS_HFLAG_B:
1547
            /* unconditional branch */
1548
            MIPS_DEBUG("unconditional branch");
1549
            gen_goto_tb(ctx, 0, ctx->btarget);
1550
            break;
1551
        case MIPS_HFLAG_BL:
1552
            /* blikely taken case */
1553
            MIPS_DEBUG("blikely branch taken");
1554
            gen_goto_tb(ctx, 0, ctx->btarget);
1555
            break;
1556
        case MIPS_HFLAG_BC:
1557
            /* Conditional branch */
1558
            MIPS_DEBUG("conditional branch");
1559
            {
1560
              int l1;
1561
              l1 = gen_new_label();
1562
              gen_op_jnz_T2(l1);
1563
              gen_goto_tb(ctx, 1, ctx->pc + 4);
1564
              gen_set_label(l1);
1565
              gen_goto_tb(ctx, 0, ctx->btarget);
1566
            }
1567
            break;
1568
        case MIPS_HFLAG_BR:
1569
            /* unconditional branch to register */
1570
            MIPS_DEBUG("branch to register");
1571
            gen_op_breg();
1572
            break;
1573
        default:
1574
            MIPS_DEBUG("unknown branch");
1575
            break;
1576
        }
1577
    }
1578
}
1579

    
1580
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1581
                                    int search_pc)
1582
{
1583
    DisasContext ctx, *ctxp = &ctx;
1584
    target_ulong pc_start;
1585
    uint16_t *gen_opc_end;
1586
    int j, lj = -1;
1587

    
1588
    if (search_pc && loglevel)
1589
        fprintf (logfile, "search pc %d\n", search_pc);
1590

    
1591
    pc_start = tb->pc;
1592
    gen_opc_ptr = gen_opc_buf;
1593
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1594
    gen_opparam_ptr = gen_opparam_buf;
1595
    nb_gen_labels = 0;
1596
    ctx.pc = pc_start;
1597
    ctx.saved_pc = -1;
1598
    ctx.tb = tb;
1599
    ctx.bstate = BS_NONE;
1600
    /* Restore delay slot state from the tb context.  */
1601
    ctx.hflags = tb->flags;
1602
    ctx.saved_hflags = ctx.hflags;
1603
    if (ctx.hflags & MIPS_HFLAG_BR) {
1604
        gen_op_restore_breg_target();
1605
    } else if (ctx.hflags & MIPS_HFLAG_B) {
1606
        ctx.btarget = env->btarget;
1607
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1608
        /* If we are in the delay slot of a conditional branch,
1609
         * restore the branch condition from env->bcond to T2
1610
         */
1611
        ctx.btarget = env->btarget;
1612
        gen_op_restore_bcond();
1613
    }
1614
#if defined(CONFIG_USER_ONLY)
1615
    ctx.mem_idx = 0;
1616
#else
1617
    ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
1618
#endif
1619
    ctx.CP0_Status = env->CP0_Status;
1620
#ifdef DEBUG_DISAS
1621
    if (loglevel & CPU_LOG_TB_CPU) {
1622
        fprintf(logfile, "------------------------------------------------\n");
1623
        /* FIXME: This may print out stale hflags from env... */
1624
        cpu_dump_state(env, logfile, fprintf, 0);
1625
    }
1626
#endif
1627
#if defined MIPS_DEBUG_DISAS
1628
    if (loglevel & CPU_LOG_TB_IN_ASM)
1629
        fprintf(logfile, "\ntb %p super %d cond %04x\n",
1630
                tb, ctx.mem_idx, ctx.hflags);
1631
#endif
1632
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1633
        if (env->nb_breakpoints > 0) {
1634
            for(j = 0; j < env->nb_breakpoints; j++) {
1635
                if (env->breakpoints[j] == ctx.pc) {
1636
                    save_cpu_state(ctxp, 1);
1637
                    ctx.bstate = BS_BRANCH;
1638
                    gen_op_debug();
1639
                    goto done_generating;
1640
                }
1641
            }
1642
        }
1643

    
1644
        if (search_pc) {
1645
            j = gen_opc_ptr - gen_opc_buf;
1646
            if (lj < j) {
1647
                lj++;
1648
                while (lj < j)
1649
                    gen_opc_instr_start[lj++] = 0;
1650
            }
1651
            gen_opc_pc[lj] = ctx.pc;
1652
            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
1653
            gen_opc_instr_start[lj] = 1;
1654
        }
1655
        ctx.opcode = ldl_code(ctx.pc);
1656
        decode_opc(&ctx);
1657
        ctx.pc += 4;
1658

    
1659
        if (env->singlestep_enabled)
1660
            break;
1661

    
1662
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1663
            break;
1664

    
1665
#if defined (MIPS_SINGLE_STEP)
1666
        break;
1667
#endif
1668
    }
1669
    if (env->singlestep_enabled) {
1670
        save_cpu_state(ctxp, ctx.bstate == BS_NONE);
1671
        gen_op_debug();
1672
        goto done_generating;
1673
    }
1674
    else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1675
        save_cpu_state(ctxp, 0);
1676
        gen_goto_tb(&ctx, 0, ctx.pc);
1677
    }
1678
    gen_op_reset_T0();
1679
    /* Generate the return instruction */
1680
    gen_op_exit_tb();
1681
done_generating:
1682
    *gen_opc_ptr = INDEX_op_end;
1683
    if (search_pc) {
1684
        j = gen_opc_ptr - gen_opc_buf;
1685
        lj++;
1686
        while (lj <= j)
1687
            gen_opc_instr_start[lj++] = 0;
1688
        tb->size = 0;
1689
    } else {
1690
        tb->size = ctx.pc - pc_start;
1691
    }
1692
#ifdef DEBUG_DISAS
1693
#if defined MIPS_DEBUG_DISAS
1694
    if (loglevel & CPU_LOG_TB_IN_ASM)
1695
        fprintf(logfile, "\n");
1696
#endif
1697
    if (loglevel & CPU_LOG_TB_IN_ASM) {
1698
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1699
        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1700
        fprintf(logfile, "\n");
1701
    }
1702
    if (loglevel & CPU_LOG_TB_OP) {
1703
        fprintf(logfile, "OP:\n");
1704
        dump_ops(gen_opc_buf, gen_opparam_buf);
1705
        fprintf(logfile, "\n");
1706
    }
1707
    if (loglevel & CPU_LOG_TB_CPU) {
1708
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1709
    }
1710
#endif
1711
    
1712
    return 0;
1713
}
1714

    
1715
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1716
{
1717
    return gen_intermediate_code_internal(env, tb, 0);
1718
}
1719

    
1720
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1721
{
1722
    return gen_intermediate_code_internal(env, tb, 1);
1723
}
1724

    
1725
void cpu_dump_state (CPUState *env, FILE *f, 
1726
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1727
                     int flags)
1728
{
1729
    uint32_t c0_status;
1730
    int i;
1731
    
1732
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1733
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1734
    for (i = 0; i < 32; i++) {
1735
        if ((i & 3) == 0)
1736
            cpu_fprintf(f, "GPR%02d:", i);
1737
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1738
        if ((i & 3) == 3)
1739
            cpu_fprintf(f, "\n");
1740
    }
1741

    
1742
    c0_status = env->CP0_Status;
1743
    if (env->hflags & MIPS_HFLAG_UM)
1744
        c0_status |= (1 << CP0St_UM);
1745
    if (env->hflags & MIPS_HFLAG_ERL)
1746
        c0_status |= (1 << CP0St_ERL);
1747
    if (env->hflags & MIPS_HFLAG_EXL)
1748
        c0_status |= (1 << CP0St_EXL);
1749

    
1750
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
1751
                c0_status, env->CP0_Cause, env->CP0_EPC);
1752
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1753
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1754
}
1755

    
1756
CPUMIPSState *cpu_mips_init (void)
1757
{
1758
    CPUMIPSState *env;
1759

    
1760
    env = qemu_mallocz(sizeof(CPUMIPSState));
1761
    if (!env)
1762
        return NULL;
1763
    cpu_exec_init(env);
1764
    tlb_flush(env, 1);
1765
    /* Minimal init */
1766
    env->PC = 0xBFC00000;
1767
#if defined (MIPS_USES_R4K_TLB)
1768
    env->CP0_random = MIPS_TLB_NB - 1;
1769
#endif
1770
    env->CP0_Wired = 0;
1771
    env->CP0_Config0 = MIPS_CONFIG0;
1772
#if defined (MIPS_CONFIG1)
1773
        env->CP0_Config1 = MIPS_CONFIG1;
1774
#endif
1775
#if defined (MIPS_CONFIG2)
1776
        env->CP0_Config2 = MIPS_CONFIG2;
1777
#endif
1778
#if defined (MIPS_CONFIG3)
1779
        env->CP0_Config3 = MIPS_CONFIG3;
1780
#endif
1781
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1782
    env->CP0_WatchLo = 0;
1783
    env->hflags = MIPS_HFLAG_ERL;
1784
    /* Count register increments in debug mode, EJTAG version 1 */
1785
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1786
    env->CP0_PRid = MIPS_CPU;
1787
    env->exception_index = EXCP_NONE;
1788
#if defined(CONFIG_USER_ONLY)
1789
    env->hflags |= MIPS_HFLAG_UM;
1790
#endif
1791
    return env;
1792
}