Statistics
| Branch: | Revision:

root / target-mips / translate.c @ e37e863f

History | View | Annotate | Download (47.7 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
enum {
35
#define DEF(s, n, copy_size) INDEX_op_ ## s,
36
#include "opc.h"
37
#undef DEF
38
    NB_OPS,
39
};
40

    
41
static uint16_t *gen_opc_ptr;
42
static uint32_t *gen_opparam_ptr;
43

    
44
#include "gen-op.h"
45

    
46
/* MIPS opcodes */
47
#define EXT_SPECIAL  0x100
48
#define EXT_SPECIAL2 0x200
49
#define EXT_REGIMM   0x300
50
#define EXT_CP0      0x400
51
#define EXT_CP1      0x500
52
#define EXT_CP2      0x600
53
#define EXT_CP3      0x700
54

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

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

    
160
    OPC_MOVCI    = 0x01 | EXT_SPECIAL,
161

    
162
    /* Special */
163
    OPC_PMON     = 0x05 | EXT_SPECIAL,
164
    OPC_SYSCALL  = 0x0C | EXT_SPECIAL,
165
    OPC_BREAK    = 0x0D | EXT_SPECIAL,
166
    OPC_SYNC     = 0x0F | EXT_SPECIAL,
167
};
168

    
169
enum {
170
    /* Mutiply & xxx operations */
171
    OPC_MADD     = 0x00 | EXT_SPECIAL2,
172
    OPC_MADDU    = 0x01 | EXT_SPECIAL2,
173
    OPC_MUL      = 0x02 | EXT_SPECIAL2,
174
    OPC_MSUB     = 0x04 | EXT_SPECIAL2,
175
    OPC_MSUBU    = 0x05 | EXT_SPECIAL2,
176
    /* Misc */
177
    OPC_CLZ      = 0x20 | EXT_SPECIAL2,
178
    OPC_CLO      = 0x21 | EXT_SPECIAL2,
179
    /* Special */
180
    OPC_SDBBP    = 0x3F | EXT_SPECIAL2,
181
};
182

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

    
201
enum {
202
    /* Coprocessor 0 (MMU) */
203
    OPC_MFC0     = 0x00 | EXT_CP0,
204
    OPC_MTC0     = 0x04 | EXT_CP0,
205
    OPC_TLBR     = 0x01 | EXT_CP0,
206
    OPC_TLBWI    = 0x02 | EXT_CP0,
207
    OPC_TLBWR    = 0x06 | EXT_CP0,
208
    OPC_TLBP     = 0x08 | EXT_CP0,
209
    OPC_ERET     = 0x18 | EXT_CP0,
210
    OPC_DERET    = 0x1F | EXT_CP0,
211
    OPC_WAIT     = 0x20 | EXT_CP0,
212
};
213

    
214
const unsigned char *regnames[] =
215
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
216
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
217
      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
218
      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
219

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

    
237
/* General purpose registers moves */
238
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
239
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
240
GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
241

    
242
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
243
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
244

    
245
typedef struct DisasContext {
246
    struct TranslationBlock *tb;
247
    target_ulong pc, saved_pc;
248
    uint32_t opcode;
249
    /* Routine used to access memory */
250
    int mem_idx;
251
    uint32_t hflags, saved_hflags;
252
    uint32_t CP0_Status;
253
    int bstate;
254
    target_ulong btarget;
255
} DisasContext;
256

    
257
enum {
258
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
259
                      * exception condition
260
                      */
261
    BS_STOP     = 1, /* We want to stop translation for any reason */
262
    BS_BRANCH   = 2, /* We reached a branch condition     */
263
    BS_EXCP     = 3, /* We reached an exception condition */
264
};
265

    
266
#if defined MIPS_DEBUG_DISAS
267
#define MIPS_DEBUG(fmt, args...)                                              \
268
do {                                                                          \
269
    if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
270
        fprintf(logfile, "%08x: %08x " fmt "\n",                              \
271
                ctx->pc, ctx->opcode , ##args);                               \
272
    }                                                                         \
273
} while (0)
274
#else
275
#define MIPS_DEBUG(fmt, args...) do { } while(0)
276
#endif
277

    
278
#define MIPS_INVAL(op)                                                        \
279
do {                                                                          \
280
    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
281
               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
282
} while (0)
283

    
284
#define GEN_LOAD_REG_TN(Tn, Rn)                                               \
285
do {                                                                          \
286
    if (Rn == 0) {                                                            \
287
        glue(gen_op_reset_, Tn)();                                            \
288
    } else {                                                                  \
289
        glue(gen_op_load_gpr_, Tn)(Rn);                                       \
290
    }                                                                         \
291
} while (0)
292

    
293
#define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
294
do {                                                                          \
295
    if (Imm == 0) {                                                           \
296
        glue(gen_op_reset_, Tn)();                                            \
297
    } else {                                                                  \
298
        glue(gen_op_set_, Tn)(Imm);                                           \
299
    }                                                                         \
300
} while (0)
301

    
302
#define GEN_STORE_TN_REG(Rn, Tn)                                              \
303
do {                                                                          \
304
    if (Rn != 0) {                                                            \
305
        glue(glue(gen_op_store_, Tn),_gpr)(Rn);                               \
306
    }                                                                         \
307
} while (0)
308

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

    
335
static inline void generate_exception (DisasContext *ctx, int excp)
336
{
337
#if defined MIPS_DEBUG_DISAS
338
    if (loglevel & CPU_LOG_TB_IN_ASM)
339
            fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
340
#endif
341
    save_cpu_state(ctx, 1);
342
    gen_op_raise_exception(excp);
343
    ctx->bstate = BS_EXCP;
344
}
345

    
346
#if defined(CONFIG_USER_ONLY)
347
#define op_ldst(name)        gen_op_##name##_raw()
348
#define OP_LD_TABLE(width)
349
#define OP_ST_TABLE(width)
350
#else
351
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
352
#define OP_LD_TABLE(width)                                                    \
353
static GenOpFunc *gen_op_l##width[] = {                                       \
354
    &gen_op_l##width##_user,                                                  \
355
    &gen_op_l##width##_kernel,                                                \
356
}
357
#define OP_ST_TABLE(width)                                                    \
358
static GenOpFunc *gen_op_s##width[] = {                                       \
359
    &gen_op_s##width##_user,                                                  \
360
    &gen_op_s##width##_kernel,                                                \
361
}
362
#endif
363

    
364
#ifdef TARGET_MIPS64
365
OP_LD_TABLE(d);
366
OP_LD_TABLE(dl);
367
OP_LD_TABLE(dr);
368
OP_ST_TABLE(d);
369
OP_ST_TABLE(dl);
370
OP_ST_TABLE(dr);
371
#endif
372
OP_LD_TABLE(w);
373
OP_LD_TABLE(wl);
374
OP_LD_TABLE(wr);
375
OP_ST_TABLE(w);
376
OP_ST_TABLE(wl);
377
OP_ST_TABLE(wr);
378
OP_LD_TABLE(h);
379
OP_LD_TABLE(hu);
380
OP_ST_TABLE(h);
381
OP_LD_TABLE(b);
382
OP_LD_TABLE(bu);
383
OP_ST_TABLE(b);
384
OP_LD_TABLE(l);
385
OP_ST_TABLE(c);
386

    
387
/* Load and store */
388
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
389
                      int base, int16_t offset)
390
{
391
    const unsigned char *opn = "unk";
392

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

    
540
/* Arithmetic with immediate operand */
541
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
542
                           int rs, int16_t imm)
543
{
544
    uint32_t uimm;
545
    const unsigned char *opn = "unk";
546

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

    
620
/* Arithmetic */
621
static void gen_arith (DisasContext *ctx, uint16_t opc,
622
                       int rd, int rs, int rt)
623
{
624
    const unsigned char *opn = "unk";
625

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

    
712
/* Arithmetic on HI/LO registers */
713
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
714
{
715
    const unsigned char *opn = "unk";
716

    
717
    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
718
        /* Treat as a NOP */
719
        MIPS_DEBUG("NOP");
720
        return;
721
    }
722
    switch (opc) {
723
    case OPC_MFHI:
724
        gen_op_load_HI();
725
        GEN_STORE_TN_REG(reg, T0);
726
        opn = "mfhi";
727
        break;
728
    case OPC_MFLO:
729
        gen_op_load_LO();
730
        GEN_STORE_TN_REG(reg, T0);
731
        opn = "mflo";
732
        break;
733
    case OPC_MTHI:
734
        GEN_LOAD_REG_TN(T0, reg);
735
        gen_op_store_HI();
736
        opn = "mthi";
737
        break;
738
    case OPC_MTLO:
739
        GEN_LOAD_REG_TN(T0, reg);
740
        gen_op_store_LO();
741
        opn = "mtlo";
742
        break;
743
    default:
744
        MIPS_INVAL("HILO");
745
        generate_exception(ctx, EXCP_RI);
746
        return;
747
    }
748
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
749
}
750

    
751
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
752
                        int rs, int rt)
753
{
754
    const unsigned char *opn = "unk";
755

    
756
    GEN_LOAD_REG_TN(T0, rs);
757
    GEN_LOAD_REG_TN(T1, rt);
758
    switch (opc) {
759
    case OPC_DIV:
760
        gen_op_div();
761
        opn = "div";
762
        break;
763
    case OPC_DIVU:
764
        gen_op_divu();
765
        opn = "divu";
766
        break;
767
    case OPC_MULT:
768
        gen_op_mult();
769
        opn = "mult";
770
        break;
771
    case OPC_MULTU:
772
        gen_op_multu();
773
        opn = "multu";
774
        break;
775
    case OPC_MADD:
776
        gen_op_madd();
777
        opn = "madd";
778
        break;
779
    case OPC_MADDU:
780
        gen_op_maddu();
781
        opn = "maddu";
782
        break;
783
    case OPC_MSUB:
784
        gen_op_msub();
785
        opn = "msub";
786
        break;
787
    case OPC_MSUBU:
788
        gen_op_msubu();
789
        opn = "msubu";
790
        break;
791
    default:
792
        MIPS_INVAL("mul/div");
793
        generate_exception(ctx, EXCP_RI);
794
        return;
795
    }
796
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
797
}
798

    
799
static void gen_cl (DisasContext *ctx, uint16_t opc,
800
                    int rd, int rs)
801
{
802
    const unsigned char *opn = "unk";
803
    if (rd == 0) {
804
        /* Treat as a NOP */
805
        MIPS_DEBUG("NOP");
806
        return;
807
    }
808
    GEN_LOAD_REG_TN(T0, rs);
809
    switch (opc) {
810
    case OPC_CLO:
811
        /* CLO */
812
        gen_op_clo();
813
        opn = "clo";
814
        break;
815
    case OPC_CLZ:
816
        /* CLZ */
817
        gen_op_clz();
818
        opn = "clz";
819
        break;
820
    default:
821
        MIPS_INVAL("CLx");
822
        generate_exception(ctx, EXCP_RI);
823
        return;
824
    }
825
    gen_op_store_T0_gpr(rd);
826
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
827
}
828

    
829
/* Traps */
830
static void gen_trap (DisasContext *ctx, uint16_t opc,
831
                      int rs, int rt, int16_t imm)
832
{
833
    int cond;
834

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

    
925
/* Branches (before delay slot) */
926
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
927
                                int rs, int rt, int32_t offset)
928
{
929
    target_ulong btarget;
930
    int blink, bcond;
931

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

    
1137
/* CP0 (MMU and control) */
1138
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1139
{
1140
    const unsigned char *opn = "unk";
1141

    
1142
    if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
1143
        !(ctx->hflags & MIPS_HFLAG_UM) &&
1144
        !(ctx->hflags & MIPS_HFLAG_ERL) &&
1145
        !(ctx->hflags & MIPS_HFLAG_EXL)) {
1146
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1147
            fprintf(logfile, "CP0 is not usable\n");
1148
        }
1149
        gen_op_raise_exception_err(EXCP_CpU, 0);
1150
        return;
1151
    }
1152
    switch (opc) {
1153
    case OPC_MFC0:
1154
        if (rt == 0) {
1155
            /* Treat as NOP */
1156
            return;
1157
        }
1158
        gen_op_mfc0(rd, ctx->opcode & 0x7);
1159
        gen_op_store_T0_gpr(rt);
1160
        opn = "mfc0";
1161
        break;
1162
    case OPC_MTC0:
1163
        /* If we get an exception, we want to restart at next instruction */
1164
        ctx->pc += 4;
1165
        save_cpu_state(ctx, 1);
1166
        ctx->pc -= 4;
1167
        GEN_LOAD_REG_TN(T0, rt);
1168
        gen_op_mtc0(rd, ctx->opcode & 0x7);
1169
        /* Stop translation as we may have switched the execution mode */
1170
        ctx->bstate = BS_STOP;
1171
        opn = "mtc0";
1172
        break;
1173
#if defined(MIPS_USES_R4K_TLB)
1174
    case OPC_TLBWI:
1175
        gen_op_tlbwi();
1176
        opn = "tlbwi";
1177
        break;
1178
    case OPC_TLBWR:
1179
        gen_op_tlbwr();
1180
        opn = "tlbwr";
1181
        break;
1182
    case OPC_TLBP:
1183
        gen_op_tlbp();
1184
        opn = "tlbp";
1185
        break;
1186
    case OPC_TLBR:
1187
        gen_op_tlbr();
1188
        opn = "tlbr";
1189
        break;
1190
#endif
1191
    case OPC_ERET:
1192
        opn = "eret";
1193
        save_cpu_state(ctx, 0);
1194
        gen_op_eret();
1195
        ctx->bstate = BS_EXCP;
1196
        break;
1197
    case OPC_DERET:
1198
        opn = "deret";
1199
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1200
            generate_exception(ctx, EXCP_RI);
1201
        } else {
1202
            save_cpu_state(ctx, 0);
1203
            gen_op_deret();
1204
            ctx->bstate = BS_EXCP;
1205
        }
1206
        break;
1207
    /* XXX: TODO: WAIT */
1208
    default:
1209
        if (loglevel & CPU_LOG_TB_IN_ASM) {
1210
            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
1211
                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
1212
                    ((ctx->opcode >> 16) & 0x1F));
1213
        }
1214
        generate_exception(ctx, EXCP_RI);
1215
        return;
1216
    }
1217
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
1218
}
1219

    
1220
/* Coprocessor 1 (FPU) */
1221

    
1222
/* ISA extensions */
1223
/* MIPS16 extension to MIPS32 */
1224
/* SmartMIPS extension to MIPS32 */
1225

    
1226
#ifdef TARGET_MIPS64
1227
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1228
{
1229
    if (func == 0x02 && rd == 0) {
1230
        /* NOP */
1231
        return;
1232
    }
1233
    if (rs == 0 || rt == 0) {
1234
        gen_op_reset_T0();
1235
        gen_op_save64();
1236
    } else {
1237
        gen_op_load_gpr_T0(rs);
1238
        gen_op_load_gpr_T1(rt);
1239
        gen_op_save64();
1240
        if (func & 0x01)
1241
            gen_op_mul64u();
1242
        else
1243
            gen_op_mul64s();
1244
    }
1245
    if (func & 0x02)
1246
        gen_op_add64();
1247
    else
1248
        gen_op_sub64();
1249
}
1250

    
1251
/* Coprocessor 3 (FPU) */
1252

    
1253
/* MDMX extension to MIPS64 */
1254
/* MIPS-3D extension to MIPS64 */
1255

    
1256
#endif
1257

    
1258
static void decode_opc (DisasContext *ctx)
1259
{
1260
    int32_t offset;
1261
    int rs, rt, rd, sa;
1262
    uint16_t op, op1;
1263
    int16_t imm;
1264

    
1265
    if ((ctx->hflags & MIPS_HFLAG_DS) &&
1266
        (ctx->hflags & MIPS_HFLAG_BL)) {
1267
        /* Handle blikely not taken case */
1268
        MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
1269
        gen_op_blikely((long)ctx->tb, ctx->pc + 4,
1270
                       ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
1271
    }
1272
    op = ctx->opcode >> 26;
1273
    rs = ((ctx->opcode >> 21) & 0x1F);
1274
    rt = ((ctx->opcode >> 16) & 0x1F);
1275
    rd = ((ctx->opcode >> 11) & 0x1F);
1276
    sa = ((ctx->opcode >> 6) & 0x1F);
1277
    imm = (int16_t)ctx->opcode;
1278
    switch (op) {
1279
    case 0x00:          /* Special opcode */
1280
        op1 = ctx->opcode & 0x3F;
1281
        switch (op1) {
1282
        case 0x00:          /* Arithmetic with immediate */
1283
        case 0x02 ... 0x03:
1284
            gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
1285
            break;
1286
        case 0x04:          /* Arithmetic */
1287
        case 0x06 ... 0x07:
1288
        case 0x0A ... 0x0B:
1289
        case 0x20 ... 0x27:
1290
        case 0x2A ... 0x2B:
1291
            gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
1292
            break;
1293
        case 0x18 ... 0x1B: /* MULT / DIV */
1294
            gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
1295
            break;
1296
        case 0x08 ... 0x09: /* Jumps */
1297
            gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
1298
            return;
1299
        case 0x30 ... 0x34: /* Traps */
1300
        case 0x36:
1301
            gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
1302
            break;
1303
        case 0x10:          /* Move from HI/LO */
1304
        case 0x12:
1305
            gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
1306
            break;
1307
        case 0x11:
1308
        case 0x13:          /* Move to HI/LO */
1309
            gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
1310
            break;
1311
        case 0x0C:          /* SYSCALL */
1312
            generate_exception(ctx, EXCP_SYSCALL);
1313
            break;
1314
        case 0x0D:          /* BREAK */
1315
            generate_exception(ctx, EXCP_BREAK);
1316
            break;
1317
        case 0x0F:          /* SYNC */
1318
            /* Treat as a noop */
1319
            break;
1320
        case 0x05:          /* Pmon entry point */
1321
            gen_op_pmon((ctx->opcode >> 6) & 0x1F);
1322
            break;
1323
#if defined (MIPS_HAS_MOVCI)
1324
        case 0x01:          /* MOVCI */
1325
#endif
1326
#if defined (TARGET_MIPS64)
1327
        case 0x14: /* MIPS64 specific opcodes */
1328
        case 0x16:
1329
        case 0x17:
1330
        case 0x1C ... 0x1F:
1331
        case 0x2C ... 0x2F:
1332
        case 0x37:
1333
        case 0x39 ... 0x3B:
1334
        case 0x3E ... 0x3F:
1335
#endif
1336
        default:            /* Invalid */
1337
            MIPS_INVAL("special");
1338
            generate_exception(ctx, EXCP_RI);
1339
            break;
1340
        }
1341
        break;
1342
    case 0x1C:          /* Special2 opcode */
1343
        op1 = ctx->opcode & 0x3F;
1344
        switch (op1) {
1345
#if defined (MIPS_USES_R4K_EXT)
1346
        /* Those instructions are not part of MIPS32 core */
1347
        case 0x00 ... 0x01: /* Multiply and add/sub */
1348
        case 0x04 ... 0x05:
1349
            gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
1350
            break;
1351
        case 0x02:          /* MUL */
1352
            gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
1353
            break;
1354
        case 0x20 ... 0x21: /* CLO / CLZ */
1355
            gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
1356
            break;
1357
#endif
1358
        case 0x3F:          /* SDBBP */
1359
            /* XXX: not clear which exception should be raised
1360
             *      when in debug mode...
1361
             */
1362
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
1363
                generate_exception(ctx, EXCP_DBp);
1364
            } else {
1365
                generate_exception(ctx, EXCP_DBp);
1366
            }
1367
            /* Treat as a noop */
1368
            break;
1369
        default:            /* Invalid */
1370
            MIPS_INVAL("special2");
1371
            generate_exception(ctx, EXCP_RI);
1372
            break;
1373
        }
1374
        break;
1375
    case 0x01:          /* B REGIMM opcode */
1376
        op1 = ((ctx->opcode >> 16) & 0x1F);
1377
        switch (op1) {
1378
        case 0x00 ... 0x03: /* REGIMM branches */
1379
        case 0x10 ... 0x13:
1380
            gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
1381
            return;
1382
        case 0x08 ... 0x0C: /* Traps */
1383
        case 0x0E:
1384
            gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
1385
            break;
1386
        default:            /* Invalid */
1387
            MIPS_INVAL("REGIMM");
1388
            generate_exception(ctx, EXCP_RI);
1389
            break;
1390
        }
1391
        break;
1392
    case 0x10:          /* CP0 opcode */
1393
        op1 = ((ctx->opcode >> 21) & 0x1F);
1394
        switch (op1) {
1395
        case 0x00:
1396
        case 0x04:
1397
            gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
1398
            break;
1399
        default:
1400
            gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd);
1401
            break;
1402
        }
1403
        break;
1404
    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
1405
        gen_arith_imm(ctx, op, rt, rs, imm);
1406
        break;
1407
    case 0x02 ... 0x03: /* Jump */
1408
        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
1409
        gen_compute_branch(ctx, op, rs, rt, offset);
1410
        return;
1411
    case 0x04 ... 0x07: /* Branch */
1412
    case 0x14 ... 0x17:
1413
        gen_compute_branch(ctx, op, rs, rt, imm << 2);
1414
        return;
1415
    case 0x20 ... 0x26: /* Load and stores */
1416
    case 0x28 ... 0x2E:
1417
    case 0x30:
1418
    case 0x38:
1419
        gen_ldst(ctx, op, rt, rs, imm);
1420
        break;
1421
    case 0x2F:          /* Cache operation */
1422
        /* Treat as a noop */
1423
        break;
1424
    case 0x33:          /* Prefetch */
1425
        /* Treat as a noop */
1426
        break;
1427
    case 0x3F: /* HACK */
1428
        break;
1429
#if defined(MIPS_USES_FPU)
1430
    case 0x31 ... 0x32: /* Floating point load/store */
1431
    case 0x35 ... 0x36:
1432
    case 0x3A ... 0x3B:
1433
    case 0x3D ... 0x3E:
1434
        /* Not implemented */
1435
        /* XXX: not correct */
1436
#endif
1437
    case 0x11:          /* CP1 opcode */
1438
        /* Not implemented */
1439
        /* XXX: not correct */
1440
    case 0x12:          /* CP2 opcode */
1441
        /* Not implemented */
1442
        /* XXX: not correct */
1443
    case 0x13:          /* CP3 opcode */
1444
        /* Not implemented */
1445
        /* XXX: not correct */
1446
#if defined (TARGET_MIPS64)
1447
    case 0x18 ... 0x1B:
1448
    case 0x27:
1449
    case 0x34:
1450
    case 0x37:
1451
        /* MIPS64 opcodes */
1452
#endif
1453
#if defined (MIPS_HAS_JALX)
1454
    case 0x1D:
1455
        /* JALX: not implemented */
1456
#endif
1457
    case 0x1E:
1458
        /* ASE specific */
1459
#if defined (MIPS_HAS_LSC)
1460
    case 0x31: /* LWC1 */
1461
    case 0x32: /* LWC2 */
1462
    case 0x35: /* SDC1 */
1463
    case 0x36: /* SDC2 */
1464
#endif
1465
    default:            /* Invalid */
1466
        MIPS_INVAL("");
1467
        generate_exception(ctx, EXCP_RI);
1468
        break;
1469
    }
1470
    if (ctx->hflags & MIPS_HFLAG_DS) {
1471
        int hflags = ctx->hflags;
1472
        /* Branches completion */
1473
        ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS);
1474
        ctx->bstate = BS_BRANCH;
1475
        save_cpu_state(ctx, 0);
1476
        switch (hflags & MIPS_HFLAG_BMASK) {
1477
        case MIPS_HFLAG_B:
1478
            /* unconditional branch */
1479
            MIPS_DEBUG("unconditional branch");
1480
            gen_op_branch((long)ctx->tb, ctx->btarget);
1481
            break;
1482
        case MIPS_HFLAG_BL:
1483
            /* blikely taken case */
1484
            MIPS_DEBUG("blikely branch taken");
1485
            gen_op_branch((long)ctx->tb, ctx->btarget);
1486
            break;
1487
        case MIPS_HFLAG_BC:
1488
            /* Conditional branch */
1489
            MIPS_DEBUG("conditional branch");
1490
            gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4);
1491
            break;
1492
        case MIPS_HFLAG_BR:
1493
            /* unconditional branch to register */
1494
            MIPS_DEBUG("branch to register");
1495
            gen_op_breg();
1496
            break;
1497
        default:
1498
            MIPS_DEBUG("unknown branch");
1499
            break;
1500
        }
1501
    }
1502
}
1503

    
1504
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1505
                                    int search_pc)
1506
{
1507
    DisasContext ctx, *ctxp = &ctx;
1508
    target_ulong pc_start;
1509
    uint16_t *gen_opc_end;
1510
    int j, lj = -1;
1511

    
1512
    pc_start = tb->pc;
1513
    gen_opc_ptr = gen_opc_buf;
1514
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1515
    gen_opparam_ptr = gen_opparam_buf;
1516
    ctx.pc = pc_start;
1517
    ctx.tb = tb;
1518
    ctx.bstate = BS_NONE;
1519
    /* Restore delay slot state */
1520
    ctx.hflags = env->hflags;
1521
    ctx.saved_hflags = ctx.hflags;
1522
    if (ctx.hflags & MIPS_HFLAG_BR) {
1523
        gen_op_restore_breg_target();
1524
    } else if (ctx.hflags & MIPS_HFLAG_B) {
1525
        ctx.btarget = env->btarget;
1526
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1527
        /* If we are in the delay slot of a conditional branch,
1528
         * restore the branch condition from env->bcond to T2
1529
         */
1530
        ctx.btarget = env->btarget;
1531
        gen_op_restore_bcond();
1532
    }
1533
#if defined(CONFIG_USER_ONLY)
1534
    ctx.mem_idx = 0;
1535
#else
1536
    ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
1537
#endif
1538
    ctx.CP0_Status = env->CP0_Status;
1539
#ifdef DEBUG_DISAS
1540
    if (loglevel & CPU_LOG_TB_CPU) {
1541
        fprintf(logfile, "------------------------------------------------\n");
1542
        cpu_dump_state(env, logfile, fprintf, 0);
1543
    }
1544
#endif
1545
#if defined MIPS_DEBUG_DISAS
1546
    if (loglevel & CPU_LOG_TB_IN_ASM)
1547
        fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
1548
                tb, ctx.mem_idx, ctx.hflags, env->hflags);
1549
#endif
1550
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1551
        if (search_pc) {
1552
            j = gen_opc_ptr - gen_opc_buf;
1553
            save_cpu_state(ctxp, 1);
1554
            if (lj < j) {
1555
                lj++;
1556
                while (lj < j)
1557
                    gen_opc_instr_start[lj++] = 0;
1558
                gen_opc_pc[lj] = ctx.pc;
1559
                gen_opc_instr_start[lj] = 1;
1560
            }
1561
        }
1562
        ctx.opcode = ldl_code(ctx.pc);
1563
        decode_opc(&ctx);
1564
        ctx.pc += 4;
1565
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1566
            break;
1567
#if defined (MIPS_SINGLE_STEP)
1568
        break;
1569
#endif
1570
    }
1571
    if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1572
        save_cpu_state(ctxp, 0);
1573
        gen_op_branch((long)ctx.tb, ctx.pc);
1574
    }
1575
    gen_op_reset_T0();
1576
    /* Generate the return instruction */
1577
    gen_op_exit_tb();
1578
    *gen_opc_ptr = INDEX_op_end;
1579
    if (search_pc) {
1580
        j = gen_opc_ptr - gen_opc_buf;
1581
        lj++;
1582
        while (lj <= j)
1583
            gen_opc_instr_start[lj++] = 0;
1584
        tb->size = 0;
1585
    } else {
1586
        tb->size = ctx.pc - pc_start;
1587
    }
1588
#ifdef DEBUG_DISAS
1589
#if defined MIPS_DEBUG_DISAS
1590
    if (loglevel & CPU_LOG_TB_IN_ASM)
1591
        fprintf(logfile, "\n");
1592
#endif
1593
    if (loglevel & CPU_LOG_TB_IN_ASM) {
1594
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1595
        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1596
        fprintf(logfile, "\n");
1597
    }
1598
    if (loglevel & CPU_LOG_TB_OP) {
1599
        fprintf(logfile, "OP:\n");
1600
        dump_ops(gen_opc_buf, gen_opparam_buf);
1601
        fprintf(logfile, "\n");
1602
    }
1603
    if (loglevel & CPU_LOG_TB_CPU) {
1604
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1605
    }
1606
#endif
1607
    
1608
    return 0;
1609
}
1610

    
1611
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1612
{
1613
    return gen_intermediate_code_internal(env, tb, 0);
1614
}
1615

    
1616
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1617
{
1618
    return gen_intermediate_code_internal(env, tb, 1);
1619
}
1620

    
1621
void cpu_dump_state (CPUState *env, FILE *f, 
1622
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1623
                     int flags)
1624
{
1625
    uint32_t c0_status;
1626
    int i;
1627
    
1628
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1629
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1630
    for (i = 0; i < 32; i++) {
1631
        if ((i & 3) == 0)
1632
            cpu_fprintf(f, "GPR%02d:", i);
1633
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1634
        if ((i & 3) == 3)
1635
            cpu_fprintf(f, "\n");
1636
    }
1637

    
1638
    c0_status = env->CP0_Status;
1639
    if (env->hflags & MIPS_HFLAG_UM)
1640
        c0_status |= (1 << CP0St_UM);
1641
    if (env->hflags & MIPS_HFLAG_ERL)
1642
        c0_status |= (1 << CP0St_ERL);
1643
    if (env->hflags & MIPS_HFLAG_EXL)
1644
        c0_status |= (1 << CP0St_EXL);
1645

    
1646
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
1647
                c0_status, env->CP0_Cause, env->CP0_EPC);
1648
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1649
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1650
}
1651

    
1652
CPUMIPSState *cpu_mips_init (void)
1653
{
1654
    CPUMIPSState *env;
1655

    
1656
    cpu_exec_init();
1657
    env = qemu_mallocz(sizeof(CPUMIPSState));
1658
    if (!env)
1659
        return NULL;
1660
    tlb_flush(env, 1);
1661
    /* Minimal init */
1662
    env->PC = 0xBFC00000;
1663
#if defined (MIPS_USES_R4K_TLB)
1664
    env->CP0_random = MIPS_TLB_NB - 1;
1665
#endif
1666
    env->CP0_Wired = 0;
1667
    env->CP0_Config0 = MIPS_CONFIG0;
1668
#if defined (MIPS_CONFIG1)
1669
        env->CP0_Config1 = MIPS_CONFIG1;
1670
#endif
1671
#if defined (MIPS_CONFIG2)
1672
        env->CP0_Config2 = MIPS_CONFIG2;
1673
#endif
1674
#if defined (MIPS_CONFIG3)
1675
        env->CP0_Config3 = MIPS_CONFIG3;
1676
#endif
1677
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1678
    env->CP0_WatchLo = 0;
1679
    env->hflags = MIPS_HFLAG_ERL;
1680
    /* Count register increments in debug mode, EJTAG version 1 */
1681
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1682
    env->CP0_PRid = MIPS_CPU;
1683
    env->exception_index = EXCP_NONE;
1684

    
1685
    cpu_single_env = env;
1686

    
1687
    return env;
1688
}