Statistics
| Branch: | Revision:

root / target-mips / translate.c @ 173d6cfe

History | View | Annotate | Download (48.6 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 (DisasContext *ctx, int excp)
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
    gen_op_raise_exception(excp);
349
    ctx->bstate = BS_EXCP;
350
}
351

    
352
#if defined(CONFIG_USER_ONLY)
353
#define op_ldst(name)        gen_op_##name##_raw()
354
#define OP_LD_TABLE(width)
355
#define OP_ST_TABLE(width)
356
#else
357
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
358
#define OP_LD_TABLE(width)                                                    \
359
static GenOpFunc *gen_op_l##width[] = {                                       \
360
    &gen_op_l##width##_user,                                                  \
361
    &gen_op_l##width##_kernel,                                                \
362
}
363
#define OP_ST_TABLE(width)                                                    \
364
static GenOpFunc *gen_op_s##width[] = {                                       \
365
    &gen_op_s##width##_user,                                                  \
366
    &gen_op_s##width##_kernel,                                                \
367
}
368
#endif
369

    
370
#ifdef TARGET_MIPS64
371
OP_LD_TABLE(d);
372
OP_LD_TABLE(dl);
373
OP_LD_TABLE(dr);
374
OP_ST_TABLE(d);
375
OP_ST_TABLE(dl);
376
OP_ST_TABLE(dr);
377
#endif
378
OP_LD_TABLE(w);
379
OP_LD_TABLE(wl);
380
OP_LD_TABLE(wr);
381
OP_ST_TABLE(w);
382
OP_ST_TABLE(wl);
383
OP_ST_TABLE(wr);
384
OP_LD_TABLE(h);
385
OP_LD_TABLE(hu);
386
OP_ST_TABLE(h);
387
OP_LD_TABLE(b);
388
OP_LD_TABLE(bu);
389
OP_ST_TABLE(b);
390
OP_LD_TABLE(l);
391
OP_ST_TABLE(c);
392

    
393
/* Load and store */
394
static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
395
                      int base, int16_t offset)
396
{
397
    const unsigned char *opn = "unk";
398

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

    
546
/* Arithmetic with immediate operand */
547
static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
548
                           int rs, int16_t imm)
549
{
550
    uint32_t uimm;
551
    const unsigned char *opn = "unk";
552

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

    
626
/* Arithmetic */
627
static void gen_arith (DisasContext *ctx, uint16_t opc,
628
                       int rd, int rs, int rt)
629
{
630
    const unsigned char *opn = "unk";
631

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

    
718
/* Arithmetic on HI/LO registers */
719
static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
720
{
721
    const unsigned char *opn = "unk";
722

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

    
757
static void gen_muldiv (DisasContext *ctx, uint16_t opc,
758
                        int rs, int rt)
759
{
760
    const unsigned char *opn = "unk";
761

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

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

    
835
/* Traps */
836
static void gen_trap (DisasContext *ctx, uint16_t opc,
837
                      int rs, int rt, int16_t imm)
838
{
839
    int cond;
840

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

    
931
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
932
{
933
    TranslationBlock *tb;
934
    tb = ctx->tb;
935
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
936
        if (n == 0)
937
            gen_op_goto_tb0(TBPARAM(tb));
938
        else
939
            gen_op_goto_tb1(TBPARAM(tb));
940
        gen_op_save_pc(dest);
941
        gen_op_set_T0((long)tb + n);
942
        gen_op_exit_tb();
943
    } else {
944
        gen_op_save_pc(dest);
945
        gen_op_set_T0(0);
946
        gen_op_exit_tb();
947
    }
948
}
949

    
950
/* Branches (before delay slot) */
951
static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
952
                                int rs, int rt, int32_t offset)
953
{
954
    target_ulong btarget;
955
    int blink, bcond;
956

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

    
1162
/* CP0 (MMU and control) */
1163
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
1164
{
1165
    const unsigned char *opn = "unk";
1166

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

    
1245
/* Coprocessor 1 (FPU) */
1246

    
1247
/* ISA extensions */
1248
/* MIPS16 extension to MIPS32 */
1249
/* SmartMIPS extension to MIPS32 */
1250

    
1251
#ifdef TARGET_MIPS64
1252
static void gen_arith64 (DisasContext *ctx, uint16_t opc)
1253
{
1254
    if (func == 0x02 && rd == 0) {
1255
        /* NOP */
1256
        return;
1257
    }
1258
    if (rs == 0 || rt == 0) {
1259
        gen_op_reset_T0();
1260
        gen_op_save64();
1261
    } else {
1262
        gen_op_load_gpr_T0(rs);
1263
        gen_op_load_gpr_T1(rt);
1264
        gen_op_save64();
1265
        if (func & 0x01)
1266
            gen_op_mul64u();
1267
        else
1268
            gen_op_mul64s();
1269
    }
1270
    if (func & 0x02)
1271
        gen_op_add64();
1272
    else
1273
        gen_op_sub64();
1274
}
1275

    
1276
/* Coprocessor 3 (FPU) */
1277

    
1278
/* MDMX extension to MIPS64 */
1279
/* MIPS-3D extension to MIPS64 */
1280

    
1281
#endif
1282

    
1283
static void gen_blikely(DisasContext *ctx)
1284
{
1285
  int l1;
1286
  l1 = gen_new_label();
1287
  gen_op_jnz_T2(l1);
1288
  gen_op_save_state(ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
1289
  gen_goto_tb(ctx, 1, ctx->pc + 4);
1290
}
1291

    
1292
static void decode_opc (DisasContext *ctx)
1293
{
1294
    int32_t offset;
1295
    int rs, rt, rd, sa;
1296
    uint16_t op, op1;
1297
    int16_t imm;
1298

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

    
1544
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
1545
                                    int search_pc)
1546
{
1547
    DisasContext ctx, *ctxp = &ctx;
1548
    target_ulong pc_start;
1549
    uint16_t *gen_opc_end;
1550
    int j, lj = -1;
1551

    
1552
    pc_start = tb->pc;
1553
    gen_opc_ptr = gen_opc_buf;
1554
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
1555
    gen_opparam_ptr = gen_opparam_buf;
1556
    nb_gen_labels = 0;
1557
    ctx.pc = pc_start;
1558
    ctx.tb = tb;
1559
    ctx.bstate = BS_NONE;
1560
    /* Restore delay slot state */
1561
    ctx.hflags = env->hflags;
1562
    ctx.saved_hflags = ctx.hflags;
1563
    if (ctx.hflags & MIPS_HFLAG_BR) {
1564
        gen_op_restore_breg_target();
1565
    } else if (ctx.hflags & MIPS_HFLAG_B) {
1566
        ctx.btarget = env->btarget;
1567
    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
1568
        /* If we are in the delay slot of a conditional branch,
1569
         * restore the branch condition from env->bcond to T2
1570
         */
1571
        ctx.btarget = env->btarget;
1572
        gen_op_restore_bcond();
1573
    }
1574
#if defined(CONFIG_USER_ONLY)
1575
    ctx.mem_idx = 0;
1576
#else
1577
    ctx.mem_idx = (ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 0 : 1;
1578
#endif
1579
    ctx.CP0_Status = env->CP0_Status;
1580
#ifdef DEBUG_DISAS
1581
    if (loglevel & CPU_LOG_TB_CPU) {
1582
        fprintf(logfile, "------------------------------------------------\n");
1583
        cpu_dump_state(env, logfile, fprintf, 0);
1584
    }
1585
#endif
1586
#if defined MIPS_DEBUG_DISAS
1587
    if (loglevel & CPU_LOG_TB_IN_ASM)
1588
        fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
1589
                tb, ctx.mem_idx, ctx.hflags, env->hflags);
1590
#endif
1591
    while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1592
        if (search_pc) {
1593
            j = gen_opc_ptr - gen_opc_buf;
1594
            save_cpu_state(ctxp, 1);
1595
            if (lj < j) {
1596
                lj++;
1597
                while (lj < j)
1598
                    gen_opc_instr_start[lj++] = 0;
1599
                gen_opc_pc[lj] = ctx.pc;
1600
                gen_opc_instr_start[lj] = 1;
1601
            }
1602
        }
1603
        ctx.opcode = ldl_code(ctx.pc);
1604
        decode_opc(&ctx);
1605
        ctx.pc += 4;
1606
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
1607
            break;
1608
#if defined (MIPS_SINGLE_STEP)
1609
        break;
1610
#endif
1611
    }
1612
    if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
1613
        save_cpu_state(ctxp, 0);
1614
        gen_goto_tb(&ctx, 0, ctx.pc);
1615
    }
1616
    gen_op_reset_T0();
1617
    /* Generate the return instruction */
1618
    gen_op_exit_tb();
1619
    *gen_opc_ptr = INDEX_op_end;
1620
    if (search_pc) {
1621
        j = gen_opc_ptr - gen_opc_buf;
1622
        lj++;
1623
        while (lj <= j)
1624
            gen_opc_instr_start[lj++] = 0;
1625
        tb->size = 0;
1626
    } else {
1627
        tb->size = ctx.pc - pc_start;
1628
    }
1629
#ifdef DEBUG_DISAS
1630
#if defined MIPS_DEBUG_DISAS
1631
    if (loglevel & CPU_LOG_TB_IN_ASM)
1632
        fprintf(logfile, "\n");
1633
#endif
1634
    if (loglevel & CPU_LOG_TB_IN_ASM) {
1635
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
1636
        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
1637
        fprintf(logfile, "\n");
1638
    }
1639
    if (loglevel & CPU_LOG_TB_OP) {
1640
        fprintf(logfile, "OP:\n");
1641
        dump_ops(gen_opc_buf, gen_opparam_buf);
1642
        fprintf(logfile, "\n");
1643
    }
1644
    if (loglevel & CPU_LOG_TB_CPU) {
1645
        fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
1646
    }
1647
#endif
1648
    
1649
    return 0;
1650
}
1651

    
1652
int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
1653
{
1654
    return gen_intermediate_code_internal(env, tb, 0);
1655
}
1656

    
1657
int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
1658
{
1659
    return gen_intermediate_code_internal(env, tb, 1);
1660
}
1661

    
1662
void cpu_dump_state (CPUState *env, FILE *f, 
1663
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1664
                     int flags)
1665
{
1666
    uint32_t c0_status;
1667
    int i;
1668
    
1669
    cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
1670
                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
1671
    for (i = 0; i < 32; i++) {
1672
        if ((i & 3) == 0)
1673
            cpu_fprintf(f, "GPR%02d:", i);
1674
        cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
1675
        if ((i & 3) == 3)
1676
            cpu_fprintf(f, "\n");
1677
    }
1678

    
1679
    c0_status = env->CP0_Status;
1680
    if (env->hflags & MIPS_HFLAG_UM)
1681
        c0_status |= (1 << CP0St_UM);
1682
    if (env->hflags & MIPS_HFLAG_ERL)
1683
        c0_status |= (1 << CP0St_ERL);
1684
    if (env->hflags & MIPS_HFLAG_EXL)
1685
        c0_status |= (1 << CP0St_EXL);
1686

    
1687
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x%08x\n",
1688
                c0_status, env->CP0_Cause, env->CP0_EPC);
1689
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
1690
                env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
1691
}
1692

    
1693
CPUMIPSState *cpu_mips_init (void)
1694
{
1695
    CPUMIPSState *env;
1696

    
1697
    env = qemu_mallocz(sizeof(CPUMIPSState));
1698
    if (!env)
1699
        return NULL;
1700
    cpu_exec_init(env);
1701
    tlb_flush(env, 1);
1702
    /* Minimal init */
1703
    env->PC = 0xBFC00000;
1704
#if defined (MIPS_USES_R4K_TLB)
1705
    env->CP0_random = MIPS_TLB_NB - 1;
1706
#endif
1707
    env->CP0_Wired = 0;
1708
    env->CP0_Config0 = MIPS_CONFIG0;
1709
#if defined (MIPS_CONFIG1)
1710
        env->CP0_Config1 = MIPS_CONFIG1;
1711
#endif
1712
#if defined (MIPS_CONFIG2)
1713
        env->CP0_Config2 = MIPS_CONFIG2;
1714
#endif
1715
#if defined (MIPS_CONFIG3)
1716
        env->CP0_Config3 = MIPS_CONFIG3;
1717
#endif
1718
    env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
1719
    env->CP0_WatchLo = 0;
1720
    env->hflags = MIPS_HFLAG_ERL;
1721
    /* Count register increments in debug mode, EJTAG version 1 */
1722
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
1723
    env->CP0_PRid = MIPS_CPU;
1724
    env->exception_index = EXCP_NONE;
1725
    return env;
1726
}