translate.c 364.6 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  MIPS32 emulation for qemu: main translation routines.
3
 *
B
bellard 已提交
4
 *  Copyright (c) 2004-2005 Jocelyn Mayer
B
bellard 已提交
5
 *  Copyright (c) 2006 Marius Groeger (FPU operations)
T
ths 已提交
6
 *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
7
 *  Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
B
bellard 已提交
8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
21 22 23 24
 */

#include "cpu.h"
#include "disas.h"
B
bellard 已提交
25
#include "tcg-op.h"
B
bellard 已提交
26

P
pbrook 已提交
27 28 29 30
#include "helper.h"
#define GEN_HELPER 1
#include "helper.h"

31
//#define MIPS_DEBUG_DISAS
32
//#define MIPS_DEBUG_SIGN_EXTENSIONS
B
bellard 已提交
33

34 35
/* MIPS major opcodes */
#define MASK_OP_MAJOR(op)  (op & (0x3F << 26))
36 37 38

enum {
    /* indirect opcode tables */
39 40 41 42 43 44 45 46
    OPC_SPECIAL  = (0x00 << 26),
    OPC_REGIMM   = (0x01 << 26),
    OPC_CP0      = (0x10 << 26),
    OPC_CP1      = (0x11 << 26),
    OPC_CP2      = (0x12 << 26),
    OPC_CP3      = (0x13 << 26),
    OPC_SPECIAL2 = (0x1C << 26),
    OPC_SPECIAL3 = (0x1F << 26),
47
    /* arithmetic with immediate */
48 49 50 51
    OPC_ADDI     = (0x08 << 26),
    OPC_ADDIU    = (0x09 << 26),
    OPC_SLTI     = (0x0A << 26),
    OPC_SLTIU    = (0x0B << 26),
A
aurel32 已提交
52
    /* logic with immediate */
53 54 55 56
    OPC_ANDI     = (0x0C << 26),
    OPC_ORI      = (0x0D << 26),
    OPC_XORI     = (0x0E << 26),
    OPC_LUI      = (0x0F << 26),
A
aurel32 已提交
57
    /* arithmetic with immediate */
58 59
    OPC_DADDI    = (0x18 << 26),
    OPC_DADDIU   = (0x19 << 26),
60
    /* Jump and branches */
61 62
    OPC_J        = (0x02 << 26),
    OPC_JAL      = (0x03 << 26),
N
Nathan Froyd 已提交
63
    OPC_JALS     = OPC_JAL | 0x5,
64 65 66 67 68 69 70 71 72
    OPC_BEQ      = (0x04 << 26),  /* Unconditional if rs = rt = 0 (B) */
    OPC_BEQL     = (0x14 << 26),
    OPC_BNE      = (0x05 << 26),
    OPC_BNEL     = (0x15 << 26),
    OPC_BLEZ     = (0x06 << 26),
    OPC_BLEZL    = (0x16 << 26),
    OPC_BGTZ     = (0x07 << 26),
    OPC_BGTZL    = (0x17 << 26),
    OPC_JALX     = (0x1D << 26),  /* MIPS 16 only */
N
Nathan Froyd 已提交
73
    OPC_JALXS    = OPC_JALX | 0x5,
74
    /* Load and stores */
75 76 77 78 79 80
    OPC_LDL      = (0x1A << 26),
    OPC_LDR      = (0x1B << 26),
    OPC_LB       = (0x20 << 26),
    OPC_LH       = (0x21 << 26),
    OPC_LWL      = (0x22 << 26),
    OPC_LW       = (0x23 << 26),
81
    OPC_LWPC     = OPC_LW | 0x5,
82 83 84 85 86 87 88 89 90 91 92 93 94 95
    OPC_LBU      = (0x24 << 26),
    OPC_LHU      = (0x25 << 26),
    OPC_LWR      = (0x26 << 26),
    OPC_LWU      = (0x27 << 26),
    OPC_SB       = (0x28 << 26),
    OPC_SH       = (0x29 << 26),
    OPC_SWL      = (0x2A << 26),
    OPC_SW       = (0x2B << 26),
    OPC_SDL      = (0x2C << 26),
    OPC_SDR      = (0x2D << 26),
    OPC_SWR      = (0x2E << 26),
    OPC_LL       = (0x30 << 26),
    OPC_LLD      = (0x34 << 26),
    OPC_LD       = (0x37 << 26),
96
    OPC_LDPC     = OPC_LD | 0x5,
97 98 99
    OPC_SC       = (0x38 << 26),
    OPC_SCD      = (0x3C << 26),
    OPC_SD       = (0x3F << 26),
100
    /* Floating point load/store */
101 102 103 104 105 106 107 108 109 110
    OPC_LWC1     = (0x31 << 26),
    OPC_LWC2     = (0x32 << 26),
    OPC_LDC1     = (0x35 << 26),
    OPC_LDC2     = (0x36 << 26),
    OPC_SWC1     = (0x39 << 26),
    OPC_SWC2     = (0x3A << 26),
    OPC_SDC1     = (0x3D << 26),
    OPC_SDC2     = (0x3E << 26),
    /* MDMX ASE specific */
    OPC_MDMX     = (0x1E << 26),
111
    /* Cache and prefetch */
112 113 114 115
    OPC_CACHE    = (0x2F << 26),
    OPC_PREF     = (0x33 << 26),
    /* Reserved major opcode */
    OPC_MAJOR3B_RESERVED = (0x3B << 26),
116 117 118
};

/* MIPS special opcodes */
119 120
#define MASK_SPECIAL(op)   MASK_OP_MAJOR(op) | (op & 0x3F)

121 122
enum {
    /* Shifts */
123
    OPC_SLL      = 0x00 | OPC_SPECIAL,
124 125
    /* NOP is SLL r0, r0, 0   */
    /* SSNOP is SLL r0, r0, 1 */
126 127
    /* EHB is SLL r0, r0, 3 */
    OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
128
    OPC_ROTR     = OPC_SRL | (1 << 21),
129 130
    OPC_SRA      = 0x03 | OPC_SPECIAL,
    OPC_SLLV     = 0x04 | OPC_SPECIAL,
131
    OPC_SRLV     = 0x06 | OPC_SPECIAL, /* also ROTRV */
132
    OPC_ROTRV    = OPC_SRLV | (1 << 6),
133 134 135
    OPC_SRAV     = 0x07 | OPC_SPECIAL,
    OPC_DSLLV    = 0x14 | OPC_SPECIAL,
    OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
136
    OPC_DROTRV   = OPC_DSRLV | (1 << 6),
137 138 139
    OPC_DSRAV    = 0x17 | OPC_SPECIAL,
    OPC_DSLL     = 0x38 | OPC_SPECIAL,
    OPC_DSRL     = 0x3A | OPC_SPECIAL, /* also DROTR */
140
    OPC_DROTR    = OPC_DSRL | (1 << 21),
141 142 143
    OPC_DSRA     = 0x3B | OPC_SPECIAL,
    OPC_DSLL32   = 0x3C | OPC_SPECIAL,
    OPC_DSRL32   = 0x3E | OPC_SPECIAL, /* also DROTR32 */
144
    OPC_DROTR32  = OPC_DSRL32 | (1 << 21),
145
    OPC_DSRA32   = 0x3F | OPC_SPECIAL,
146
    /* Multiplication / division */
147 148 149 150 151 152 153 154
    OPC_MULT     = 0x18 | OPC_SPECIAL,
    OPC_MULTU    = 0x19 | OPC_SPECIAL,
    OPC_DIV      = 0x1A | OPC_SPECIAL,
    OPC_DIVU     = 0x1B | OPC_SPECIAL,
    OPC_DMULT    = 0x1C | OPC_SPECIAL,
    OPC_DMULTU   = 0x1D | OPC_SPECIAL,
    OPC_DDIV     = 0x1E | OPC_SPECIAL,
    OPC_DDIVU    = 0x1F | OPC_SPECIAL,
155
    /* 2 registers arithmetic / logic */
156 157 158 159 160 161 162 163 164 165 166 167 168 169
    OPC_ADD      = 0x20 | OPC_SPECIAL,
    OPC_ADDU     = 0x21 | OPC_SPECIAL,
    OPC_SUB      = 0x22 | OPC_SPECIAL,
    OPC_SUBU     = 0x23 | OPC_SPECIAL,
    OPC_AND      = 0x24 | OPC_SPECIAL,
    OPC_OR       = 0x25 | OPC_SPECIAL,
    OPC_XOR      = 0x26 | OPC_SPECIAL,
    OPC_NOR      = 0x27 | OPC_SPECIAL,
    OPC_SLT      = 0x2A | OPC_SPECIAL,
    OPC_SLTU     = 0x2B | OPC_SPECIAL,
    OPC_DADD     = 0x2C | OPC_SPECIAL,
    OPC_DADDU    = 0x2D | OPC_SPECIAL,
    OPC_DSUB     = 0x2E | OPC_SPECIAL,
    OPC_DSUBU    = 0x2F | OPC_SPECIAL,
170
    /* Jumps */
171 172
    OPC_JR       = 0x08 | OPC_SPECIAL, /* Also JR.HB */
    OPC_JALR     = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
173
    OPC_JALRC    = OPC_JALR | (0x5 << 6),
N
Nathan Froyd 已提交
174
    OPC_JALRS    = 0x10 | OPC_SPECIAL | (0x5 << 6),
175
    /* Traps */
176 177 178 179 180 181
    OPC_TGE      = 0x30 | OPC_SPECIAL,
    OPC_TGEU     = 0x31 | OPC_SPECIAL,
    OPC_TLT      = 0x32 | OPC_SPECIAL,
    OPC_TLTU     = 0x33 | OPC_SPECIAL,
    OPC_TEQ      = 0x34 | OPC_SPECIAL,
    OPC_TNE      = 0x36 | OPC_SPECIAL,
182
    /* HI / LO registers load & stores */
183 184 185 186
    OPC_MFHI     = 0x10 | OPC_SPECIAL,
    OPC_MTHI     = 0x11 | OPC_SPECIAL,
    OPC_MFLO     = 0x12 | OPC_SPECIAL,
    OPC_MTLO     = 0x13 | OPC_SPECIAL,
187
    /* Conditional moves */
188 189
    OPC_MOVZ     = 0x0A | OPC_SPECIAL,
    OPC_MOVN     = 0x0B | OPC_SPECIAL,
190

191
    OPC_MOVCI    = 0x01 | OPC_SPECIAL,
192 193

    /* Special */
S
Stefan Weil 已提交
194
    OPC_PMON     = 0x05 | OPC_SPECIAL, /* unofficial */
195 196
    OPC_SYSCALL  = 0x0C | OPC_SPECIAL,
    OPC_BREAK    = 0x0D | OPC_SPECIAL,
S
Stefan Weil 已提交
197
    OPC_SPIM     = 0x0E | OPC_SPECIAL, /* unofficial */
198 199 200 201 202 203 204 205 206 207 208
    OPC_SYNC     = 0x0F | OPC_SPECIAL,

    OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
    OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
    OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
    OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
    OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
    OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
    OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
};

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
/* Multiplication variants of the vr54xx. */
#define MASK_MUL_VR54XX(op)   MASK_SPECIAL(op) | (op & (0x1F << 6))

enum {
    OPC_VR54XX_MULS    = (0x03 << 6) | OPC_MULT,
    OPC_VR54XX_MULSU   = (0x03 << 6) | OPC_MULTU,
    OPC_VR54XX_MACC    = (0x05 << 6) | OPC_MULT,
    OPC_VR54XX_MACCU   = (0x05 << 6) | OPC_MULTU,
    OPC_VR54XX_MSAC    = (0x07 << 6) | OPC_MULT,
    OPC_VR54XX_MSACU   = (0x07 << 6) | OPC_MULTU,
    OPC_VR54XX_MULHI   = (0x09 << 6) | OPC_MULT,
    OPC_VR54XX_MULHIU  = (0x09 << 6) | OPC_MULTU,
    OPC_VR54XX_MULSHI  = (0x0B << 6) | OPC_MULT,
    OPC_VR54XX_MULSHIU = (0x0B << 6) | OPC_MULTU,
    OPC_VR54XX_MACCHI  = (0x0D << 6) | OPC_MULT,
    OPC_VR54XX_MACCHIU = (0x0D << 6) | OPC_MULTU,
    OPC_VR54XX_MSACHI  = (0x0F << 6) | OPC_MULT,
    OPC_VR54XX_MSACHIU = (0x0F << 6) | OPC_MULTU,
};

229 230 231 232 233 234 235 236 237
/* REGIMM (rt field) opcodes */
#define MASK_REGIMM(op)    MASK_OP_MAJOR(op) | (op & (0x1F << 16))

enum {
    OPC_BLTZ     = (0x00 << 16) | OPC_REGIMM,
    OPC_BLTZL    = (0x02 << 16) | OPC_REGIMM,
    OPC_BGEZ     = (0x01 << 16) | OPC_REGIMM,
    OPC_BGEZL    = (0x03 << 16) | OPC_REGIMM,
    OPC_BLTZAL   = (0x10 << 16) | OPC_REGIMM,
238
    OPC_BLTZALS  = OPC_BLTZAL | 0x5, /* microMIPS */
239 240
    OPC_BLTZALL  = (0x12 << 16) | OPC_REGIMM,
    OPC_BGEZAL   = (0x11 << 16) | OPC_REGIMM,
241
    OPC_BGEZALS  = OPC_BGEZAL | 0x5, /* microMIPS */
242 243 244 245 246 247 248 249
    OPC_BGEZALL  = (0x13 << 16) | OPC_REGIMM,
    OPC_TGEI     = (0x08 << 16) | OPC_REGIMM,
    OPC_TGEIU    = (0x09 << 16) | OPC_REGIMM,
    OPC_TLTI     = (0x0A << 16) | OPC_REGIMM,
    OPC_TLTIU    = (0x0B << 16) | OPC_REGIMM,
    OPC_TEQI     = (0x0C << 16) | OPC_REGIMM,
    OPC_TNEI     = (0x0E << 16) | OPC_REGIMM,
    OPC_SYNCI    = (0x1F << 16) | OPC_REGIMM,
250 251
};

252 253 254
/* Special2 opcodes */
#define MASK_SPECIAL2(op)  MASK_OP_MAJOR(op) | (op & 0x3F)

255
enum {
256 257 258 259 260 261
    /* Multiply & xxx operations */
    OPC_MADD     = 0x00 | OPC_SPECIAL2,
    OPC_MADDU    = 0x01 | OPC_SPECIAL2,
    OPC_MUL      = 0x02 | OPC_SPECIAL2,
    OPC_MSUB     = 0x04 | OPC_SPECIAL2,
    OPC_MSUBU    = 0x05 | OPC_SPECIAL2,
262 263 264 265 266 267 268 269 270 271 272 273 274
    /* Loongson 2F */
    OPC_MULT_G_2F   = 0x10 | OPC_SPECIAL2,
    OPC_DMULT_G_2F  = 0x11 | OPC_SPECIAL2,
    OPC_MULTU_G_2F  = 0x12 | OPC_SPECIAL2,
    OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2,
    OPC_DIV_G_2F    = 0x14 | OPC_SPECIAL2,
    OPC_DDIV_G_2F   = 0x15 | OPC_SPECIAL2,
    OPC_DIVU_G_2F   = 0x16 | OPC_SPECIAL2,
    OPC_DDIVU_G_2F  = 0x17 | OPC_SPECIAL2,
    OPC_MOD_G_2F    = 0x1c | OPC_SPECIAL2,
    OPC_DMOD_G_2F   = 0x1d | OPC_SPECIAL2,
    OPC_MODU_G_2F   = 0x1e | OPC_SPECIAL2,
    OPC_DMODU_G_2F  = 0x1f | OPC_SPECIAL2,
275
    /* Misc */
276 277 278 279
    OPC_CLZ      = 0x20 | OPC_SPECIAL2,
    OPC_CLO      = 0x21 | OPC_SPECIAL2,
    OPC_DCLZ     = 0x24 | OPC_SPECIAL2,
    OPC_DCLO     = 0x25 | OPC_SPECIAL2,
280
    /* Special */
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    OPC_SDBBP    = 0x3F | OPC_SPECIAL2,
};

/* Special3 opcodes */
#define MASK_SPECIAL3(op)  MASK_OP_MAJOR(op) | (op & 0x3F)

enum {
    OPC_EXT      = 0x00 | OPC_SPECIAL3,
    OPC_DEXTM    = 0x01 | OPC_SPECIAL3,
    OPC_DEXTU    = 0x02 | OPC_SPECIAL3,
    OPC_DEXT     = 0x03 | OPC_SPECIAL3,
    OPC_INS      = 0x04 | OPC_SPECIAL3,
    OPC_DINSM    = 0x05 | OPC_SPECIAL3,
    OPC_DINSU    = 0x06 | OPC_SPECIAL3,
    OPC_DINS     = 0x07 | OPC_SPECIAL3,
296 297
    OPC_FORK     = 0x08 | OPC_SPECIAL3,
    OPC_YIELD    = 0x09 | OPC_SPECIAL3,
298 299 300
    OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
    OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
    OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
301 302 303 304 305 306 307 308 309 310 311 312 313 314

    /* Loongson 2E */
    OPC_MULT_G_2E   = 0x18 | OPC_SPECIAL3,
    OPC_MULTU_G_2E  = 0x19 | OPC_SPECIAL3,
    OPC_DIV_G_2E    = 0x1A | OPC_SPECIAL3,
    OPC_DIVU_G_2E   = 0x1B | OPC_SPECIAL3,
    OPC_DMULT_G_2E  = 0x1C | OPC_SPECIAL3,
    OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3,
    OPC_DDIV_G_2E   = 0x1E | OPC_SPECIAL3,
    OPC_DDIVU_G_2E  = 0x1F | OPC_SPECIAL3,
    OPC_MOD_G_2E    = 0x22 | OPC_SPECIAL3,
    OPC_MODU_G_2E   = 0x23 | OPC_SPECIAL3,
    OPC_DMOD_G_2E   = 0x26 | OPC_SPECIAL3,
    OPC_DMODU_G_2E  = 0x27 | OPC_SPECIAL3,
315 316
};

317 318 319
/* BSHFL opcodes */
#define MASK_BSHFL(op)     MASK_SPECIAL3(op) | (op & (0x1F << 6))

320
enum {
321 322 323
    OPC_WSBH     = (0x02 << 6) | OPC_BSHFL,
    OPC_SEB      = (0x10 << 6) | OPC_BSHFL,
    OPC_SEH      = (0x18 << 6) | OPC_BSHFL,
324 325
};

326 327 328
/* DBSHFL opcodes */
#define MASK_DBSHFL(op)    MASK_SPECIAL3(op) | (op & (0x1F << 6))

329
enum {
330 331
    OPC_DSBH     = (0x02 << 6) | OPC_DBSHFL,
    OPC_DSHD     = (0x05 << 6) | OPC_DBSHFL,
332 333
};

334 335 336
/* Coprocessor 0 (rs field) */
#define MASK_CP0(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))

B
bellard 已提交
337
enum {
338 339 340 341
    OPC_MFC0     = (0x00 << 21) | OPC_CP0,
    OPC_DMFC0    = (0x01 << 21) | OPC_CP0,
    OPC_MTC0     = (0x04 << 21) | OPC_CP0,
    OPC_DMTC0    = (0x05 << 21) | OPC_CP0,
342
    OPC_MFTR     = (0x08 << 21) | OPC_CP0,
343 344
    OPC_RDPGPR   = (0x0A << 21) | OPC_CP0,
    OPC_MFMC0    = (0x0B << 21) | OPC_CP0,
345
    OPC_MTTR     = (0x0C << 21) | OPC_CP0,
346 347 348 349
    OPC_WRPGPR   = (0x0E << 21) | OPC_CP0,
    OPC_C0       = (0x10 << 21) | OPC_CP0,
    OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
    OPC_C0_LAST  = (0x1F << 21) | OPC_CP0,
B
bellard 已提交
350
};
351 352

/* MFMC0 opcodes */
353
#define MASK_MFMC0(op)     MASK_CP0(op) | (op & 0xFFFF)
354 355

enum {
356 357 358 359
    OPC_DMT      = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
    OPC_EMT      = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
    OPC_DVPE     = 0x01 | (0 << 5) | OPC_MFMC0,
    OPC_EVPE     = 0x01 | (1 << 5) | OPC_MFMC0,
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
    OPC_DI       = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
    OPC_EI       = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
};

/* Coprocessor 0 (with rs == C0) */
#define MASK_C0(op)        MASK_CP0(op) | (op & 0x3F)

enum {
    OPC_TLBR     = 0x01 | OPC_C0,
    OPC_TLBWI    = 0x02 | OPC_C0,
    OPC_TLBWR    = 0x06 | OPC_C0,
    OPC_TLBP     = 0x08 | OPC_C0,
    OPC_RFE      = 0x10 | OPC_C0,
    OPC_ERET     = 0x18 | OPC_C0,
    OPC_DERET    = 0x1F | OPC_C0,
    OPC_WAIT     = 0x20 | OPC_C0,
};

/* Coprocessor 1 (rs field) */
#define MASK_CP1(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))

381 382 383
/* Values for the fmt field in FP instructions */
enum {
    /* 0 - 15 are reserved */
384 385 386 387 388 389 390
    FMT_S = 16,          /* single fp */
    FMT_D = 17,          /* double fp */
    FMT_E = 18,          /* extended fp */
    FMT_Q = 19,          /* quad fp */
    FMT_W = 20,          /* 32-bit fixed */
    FMT_L = 21,          /* 64-bit fixed */
    FMT_PS = 22,         /* paired single fp */
391 392 393
    /* 23 - 31 are reserved */
};

394 395 396 397
enum {
    OPC_MFC1     = (0x00 << 21) | OPC_CP1,
    OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
    OPC_CFC1     = (0x02 << 21) | OPC_CP1,
398
    OPC_MFHC1    = (0x03 << 21) | OPC_CP1,
399 400 401
    OPC_MTC1     = (0x04 << 21) | OPC_CP1,
    OPC_DMTC1    = (0x05 << 21) | OPC_CP1,
    OPC_CTC1     = (0x06 << 21) | OPC_CP1,
402
    OPC_MTHC1    = (0x07 << 21) | OPC_CP1,
403
    OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
404 405
    OPC_BC1ANY2  = (0x09 << 21) | OPC_CP1,
    OPC_BC1ANY4  = (0x0A << 21) | OPC_CP1,
406 407 408 409 410 411 412
    OPC_S_FMT    = (FMT_S << 21) | OPC_CP1,
    OPC_D_FMT    = (FMT_D << 21) | OPC_CP1,
    OPC_E_FMT    = (FMT_E << 21) | OPC_CP1,
    OPC_Q_FMT    = (FMT_Q << 21) | OPC_CP1,
    OPC_W_FMT    = (FMT_W << 21) | OPC_CP1,
    OPC_L_FMT    = (FMT_L << 21) | OPC_CP1,
    OPC_PS_FMT   = (FMT_PS << 21) | OPC_CP1,
413 414
};

415 416 417
#define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
#define MASK_BC1(op)            MASK_CP1(op) | (op & (0x3 << 16))

418 419 420 421 422 423 424
enum {
    OPC_BC1F     = (0x00 << 16) | OPC_BC1,
    OPC_BC1T     = (0x01 << 16) | OPC_BC1,
    OPC_BC1FL    = (0x02 << 16) | OPC_BC1,
    OPC_BC1TL    = (0x03 << 16) | OPC_BC1,
};

425 426 427 428 429 430 431 432 433
enum {
    OPC_BC1FANY2     = (0x00 << 16) | OPC_BC1ANY2,
    OPC_BC1TANY2     = (0x01 << 16) | OPC_BC1ANY2,
};

enum {
    OPC_BC1FANY4     = (0x00 << 16) | OPC_BC1ANY4,
    OPC_BC1TANY4     = (0x01 << 16) | OPC_BC1ANY4,
};
434 435

#define MASK_CP2(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
T
ths 已提交
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466

enum {
    OPC_MFC2    = (0x00 << 21) | OPC_CP2,
    OPC_DMFC2   = (0x01 << 21) | OPC_CP2,
    OPC_CFC2    = (0x02 << 21) | OPC_CP2,
    OPC_MFHC2   = (0x03 << 21) | OPC_CP2,
    OPC_MTC2    = (0x04 << 21) | OPC_CP2,
    OPC_DMTC2   = (0x05 << 21) | OPC_CP2,
    OPC_CTC2    = (0x06 << 21) | OPC_CP2,
    OPC_MTHC2   = (0x07 << 21) | OPC_CP2,
    OPC_BC2     = (0x08 << 21) | OPC_CP2,
};

#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & 0x3F)

enum {
    OPC_LWXC1   = 0x00 | OPC_CP3,
    OPC_LDXC1   = 0x01 | OPC_CP3,
    OPC_LUXC1   = 0x05 | OPC_CP3,
    OPC_SWXC1   = 0x08 | OPC_CP3,
    OPC_SDXC1   = 0x09 | OPC_CP3,
    OPC_SUXC1   = 0x0D | OPC_CP3,
    OPC_PREFX   = 0x0F | OPC_CP3,
    OPC_ALNV_PS = 0x1E | OPC_CP3,
    OPC_MADD_S  = 0x20 | OPC_CP3,
    OPC_MADD_D  = 0x21 | OPC_CP3,
    OPC_MADD_PS = 0x26 | OPC_CP3,
    OPC_MSUB_S  = 0x28 | OPC_CP3,
    OPC_MSUB_D  = 0x29 | OPC_CP3,
    OPC_MSUB_PS = 0x2E | OPC_CP3,
    OPC_NMADD_S = 0x30 | OPC_CP3,
467
    OPC_NMADD_D = 0x31 | OPC_CP3,
T
ths 已提交
468 469 470 471 472 473
    OPC_NMADD_PS= 0x36 | OPC_CP3,
    OPC_NMSUB_S = 0x38 | OPC_CP3,
    OPC_NMSUB_D = 0x39 | OPC_CP3,
    OPC_NMSUB_PS= 0x3E | OPC_CP3,
};

474
/* global register indices */
P
pbrook 已提交
475 476
static TCGv_ptr cpu_env;
static TCGv cpu_gpr[32], cpu_PC;
477
static TCGv cpu_HI[MIPS_DSP_ACC], cpu_LO[MIPS_DSP_ACC], cpu_ACX[MIPS_DSP_ACC];
478 479
static TCGv cpu_dspctrl, btarget, bcond;
static TCGv_i32 hflags;
P
pbrook 已提交
480
static TCGv_i32 fpu_fcr0, fpu_fcr31;
T
ths 已提交
481

482 483
static uint32_t gen_opc_hflags[OPC_BUF_SIZE];

P
pbrook 已提交
484 485
#include "gen-icount.h"

P
pbrook 已提交
486 487 488 489 490
#define gen_helper_0i(name, arg) do {                             \
    TCGv_i32 helper_tmp = tcg_const_i32(arg);                     \
    gen_helper_##name(helper_tmp);                                \
    tcg_temp_free_i32(helper_tmp);                                \
    } while(0)
491

P
pbrook 已提交
492 493 494 495 496
#define gen_helper_1i(name, arg1, arg2) do {                      \
    TCGv_i32 helper_tmp = tcg_const_i32(arg2);                    \
    gen_helper_##name(arg1, helper_tmp);                          \
    tcg_temp_free_i32(helper_tmp);                                \
    } while(0)
497

P
pbrook 已提交
498 499 500 501 502
#define gen_helper_2i(name, arg1, arg2, arg3) do {                \
    TCGv_i32 helper_tmp = tcg_const_i32(arg3);                    \
    gen_helper_##name(arg1, arg2, helper_tmp);                    \
    tcg_temp_free_i32(helper_tmp);                                \
    } while(0)
503

P
pbrook 已提交
504 505 506 507 508
#define gen_helper_3i(name, arg1, arg2, arg3, arg4) do {          \
    TCGv_i32 helper_tmp = tcg_const_i32(arg4);                    \
    gen_helper_##name(arg1, arg2, arg3, helper_tmp);              \
    tcg_temp_free_i32(helper_tmp);                                \
    } while(0)
T
ths 已提交
509

510 511 512 513
typedef struct DisasContext {
    struct TranslationBlock *tb;
    target_ulong pc, saved_pc;
    uint32_t opcode;
N
Nathan Froyd 已提交
514
    int singlestep_enabled;
515 516 517 518 519 520 521 522 523
    /* Routine used to access memory */
    int mem_idx;
    uint32_t hflags, saved_hflags;
    int bstate;
    target_ulong btarget;
} DisasContext;

enum {
    BS_NONE     = 0, /* We go out of the TB without reaching a branch or an
T
ths 已提交
524
                      * exception condition */
525 526 527 528 529 530
    BS_STOP     = 1, /* We want to stop translation for any reason */
    BS_BRANCH   = 2, /* We reached a branch condition     */
    BS_EXCP     = 3, /* We reached an exception condition */
};

static const char *regnames[] =
B
bellard 已提交
531 532 533 534 535
    { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
      "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
      "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };

536 537 538 539 540 541 542 543 544
static const char *regnames_HI[] =
    { "HI0", "HI1", "HI2", "HI3", };

static const char *regnames_LO[] =
    { "LO0", "LO1", "LO2", "LO3", };

static const char *regnames_ACX[] =
    { "ACX0", "ACX1", "ACX2", "ACX3", };

545 546 547 548 549
static const char *fregnames[] =
    { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
      "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
      "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
      "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
T
ths 已提交
550

551
#ifdef MIPS_DEBUG_DISAS
552
#define MIPS_DEBUG(fmt, ...)                         \
553 554
        qemu_log_mask(CPU_LOG_TB_IN_ASM,                \
                       TARGET_FMT_lx ": %08x " fmt "\n", \
555
                       ctx->pc, ctx->opcode , ## __VA_ARGS__)
556
#define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
557
#else
558
#define MIPS_DEBUG(fmt, ...) do { } while(0)
559
#define LOG_DISAS(...) do { } while (0)
560
#endif
T
ths 已提交
561

562 563 564 565 566
#define MIPS_INVAL(op)                                                        \
do {                                                                          \
    MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26,            \
               ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F));             \
} while (0)
567

568 569
/* General purpose registers moves. */
static inline void gen_load_gpr (TCGv t, int reg)
570
{
571 572 573
    if (reg == 0)
        tcg_gen_movi_tl(t, 0);
    else
574
        tcg_gen_mov_tl(t, cpu_gpr[reg]);
575 576
}

577
static inline void gen_store_gpr (TCGv t, int reg)
578
{
579
    if (reg != 0)
580
        tcg_gen_mov_tl(cpu_gpr[reg], t);
581 582
}

A
aurel32 已提交
583
/* Moves to/from ACX register.  */
584
static inline void gen_load_ACX (TCGv t, int reg)
585
{
586
    tcg_gen_mov_tl(t, cpu_ACX[reg]);
587 588
}

589
static inline void gen_store_ACX (TCGv t, int reg)
590
{
591
    tcg_gen_mov_tl(cpu_ACX[reg], t);
592 593
}

594
/* Moves to/from shadow registers. */
595
static inline void gen_load_srsgpr (int from, int to)
596
{
597
    TCGv t0 = tcg_temp_new();
598 599

    if (from == 0)
600
        tcg_gen_movi_tl(t0, 0);
601
    else {
602
        TCGv_i32 t2 = tcg_temp_new_i32();
P
pbrook 已提交
603
        TCGv_ptr addr = tcg_temp_new_ptr();
604

605
        tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl));
606 607 608 609
        tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS);
        tcg_gen_andi_i32(t2, t2, 0xf);
        tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32);
        tcg_gen_ext_i32_ptr(addr, t2);
P
pbrook 已提交
610
        tcg_gen_add_ptr(addr, cpu_env, addr);
611

612
        tcg_gen_ld_tl(t0, addr, sizeof(target_ulong) * from);
P
pbrook 已提交
613
        tcg_temp_free_ptr(addr);
614
        tcg_temp_free_i32(t2);
615
    }
616 617
    gen_store_gpr(t0, to);
    tcg_temp_free(t0);
618 619
}

620
static inline void gen_store_srsgpr (int from, int to)
621
{
622
    if (to != 0) {
623 624
        TCGv t0 = tcg_temp_new();
        TCGv_i32 t2 = tcg_temp_new_i32();
P
pbrook 已提交
625
        TCGv_ptr addr = tcg_temp_new_ptr();
626

627
        gen_load_gpr(t0, from);
628
        tcg_gen_ld_i32(t2, cpu_env, offsetof(CPUMIPSState, CP0_SRSCtl));
629 630 631 632
        tcg_gen_shri_i32(t2, t2, CP0SRSCtl_PSS);
        tcg_gen_andi_i32(t2, t2, 0xf);
        tcg_gen_muli_i32(t2, t2, sizeof(target_ulong) * 32);
        tcg_gen_ext_i32_ptr(addr, t2);
P
pbrook 已提交
633
        tcg_gen_add_ptr(addr, cpu_env, addr);
634

635
        tcg_gen_st_tl(t0, addr, sizeof(target_ulong) * to);
P
pbrook 已提交
636
        tcg_temp_free_ptr(addr);
637 638
        tcg_temp_free_i32(t2);
        tcg_temp_free(t0);
639
    }
640 641 642
}

/* Floating point register moves. */
P
pbrook 已提交
643
static inline void gen_load_fpr32 (TCGv_i32 t, int reg)
T
ths 已提交
644
{
645
    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX]));
B
bellard 已提交
646 647
}

P
pbrook 已提交
648
static inline void gen_store_fpr32 (TCGv_i32 t, int reg)
T
ths 已提交
649
{
650
    tcg_gen_st_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[FP_ENDIAN_IDX]));
651 652 653 654
}

static inline void gen_load_fpr32h (TCGv_i32 t, int reg)
{
655
    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX]));
656 657 658 659
}

static inline void gen_store_fpr32h (TCGv_i32 t, int reg)
{
660
    tcg_gen_st_i32(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].w[!FP_ENDIAN_IDX]));
T
ths 已提交
661
}
B
bellard 已提交
662

P
pbrook 已提交
663
static inline void gen_load_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg)
T
ths 已提交
664
{
A
aurel32 已提交
665
    if (ctx->hflags & MIPS_HFLAG_F64) {
666
        tcg_gen_ld_i64(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].d));
A
aurel32 已提交
667
    } else {
668 669 670 671 672 673 674
        TCGv_i32 t0 = tcg_temp_new_i32();
        TCGv_i32 t1 = tcg_temp_new_i32();
        gen_load_fpr32(t0, reg & ~1);
        gen_load_fpr32(t1, reg | 1);
        tcg_gen_concat_i32_i64(t, t0, t1);
        tcg_temp_free_i32(t0);
        tcg_temp_free_i32(t1);
T
ths 已提交
675 676
    }
}
B
bellard 已提交
677

P
pbrook 已提交
678
static inline void gen_store_fpr64 (DisasContext *ctx, TCGv_i64 t, int reg)
T
ths 已提交
679
{
A
aurel32 已提交
680
    if (ctx->hflags & MIPS_HFLAG_F64) {
681
        tcg_gen_st_i64(t, cpu_env, offsetof(CPUMIPSState, active_fpu.fpr[reg].d));
A
aurel32 已提交
682
    } else {
683 684 685 686 687 688 689 690 691
        TCGv_i64 t0 = tcg_temp_new_i64();
        TCGv_i32 t1 = tcg_temp_new_i32();
        tcg_gen_trunc_i64_i32(t1, t);
        gen_store_fpr32(t1, reg & ~1);
        tcg_gen_shri_i64(t0, t, 32);
        tcg_gen_trunc_i64_i32(t1, t0);
        gen_store_fpr32(t1, reg | 1);
        tcg_temp_free_i32(t1);
        tcg_temp_free_i64(t0);
T
ths 已提交
692 693
    }
}
B
bellard 已提交
694

695
static inline int get_fp_bit (int cc)
696
{
697 698 699 700
    if (cc)
        return 24 + cc;
    else
        return 23;
701 702
}

703
/* Tests */
704 705
static inline void gen_save_pc(target_ulong pc)
{
A
aurel32 已提交
706
    tcg_gen_movi_tl(cpu_PC, pc);
707
}
708

709
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
B
bellard 已提交
710
{
711
    LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags);
B
bellard 已提交
712
    if (do_save_pc && ctx->pc != ctx->saved_pc) {
713
        gen_save_pc(ctx->pc);
B
bellard 已提交
714 715 716
        ctx->saved_pc = ctx->pc;
    }
    if (ctx->hflags != ctx->saved_hflags) {
717
        tcg_gen_movi_i32(hflags, ctx->hflags);
B
bellard 已提交
718
        ctx->saved_hflags = ctx->hflags;
719
        switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) {
720 721 722 723 724
        case MIPS_HFLAG_BR:
            break;
        case MIPS_HFLAG_BC:
        case MIPS_HFLAG_BL:
        case MIPS_HFLAG_B:
T
ths 已提交
725
            tcg_gen_movi_tl(btarget, ctx->btarget);
726
            break;
B
bellard 已提交
727 728 729 730
        }
    }
}

731
static inline void restore_cpu_state (CPUMIPSState *env, DisasContext *ctx)
732
{
733
    ctx->saved_hflags = ctx->hflags;
734
    switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) {
735 736 737 738
    case MIPS_HFLAG_BR:
        break;
    case MIPS_HFLAG_BC:
    case MIPS_HFLAG_BL:
739
    case MIPS_HFLAG_B:
740 741
        ctx->btarget = env->btarget;
        break;
742 743 744
    }
}

745
static inline void
746
generate_exception_err (DisasContext *ctx, int excp, int err)
747
{
P
pbrook 已提交
748 749
    TCGv_i32 texcp = tcg_const_i32(excp);
    TCGv_i32 terr = tcg_const_i32(err);
750
    save_cpu_state(ctx, 1);
P
pbrook 已提交
751 752 753
    gen_helper_raise_exception_err(texcp, terr);
    tcg_temp_free_i32(terr);
    tcg_temp_free_i32(texcp);
754 755
}

756
static inline void
757
generate_exception (DisasContext *ctx, int excp)
758
{
B
bellard 已提交
759
    save_cpu_state(ctx, 1);
P
pbrook 已提交
760
    gen_helper_0i(raise_exception, excp);
B
bellard 已提交
761 762
}

763
/* Addresses computation */
764
static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1)
B
bellard 已提交
765
{
766
    tcg_gen_add_tl(ret, arg0, arg1);
767 768 769 770 771

#if defined(TARGET_MIPS64)
    /* For compatibility with 32-bit code, data reference in user mode
       with Status_UX = 0 should be casted to 32-bit and sign extended.
       See the MIPS64 PRA manual, section 4.10. */
772 773
    if (((ctx->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
        !(ctx->hflags & MIPS_HFLAG_UX)) {
774
        tcg_gen_ext32s_i64(ret, ret);
775 776
    }
#endif
B
bellard 已提交
777 778
}

779
static inline void check_cp0_enabled(DisasContext *ctx)
780
{
781
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
782
        generate_exception_err(ctx, EXCP_CpU, 0);
783 784
}

785
static inline void check_cp1_enabled(DisasContext *ctx)
786
{
787
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU)))
788 789 790
        generate_exception_err(ctx, EXCP_CpU, 1);
}

791 792 793 794
/* Verify that the processor is running with COP1X instructions enabled.
   This is associated with the nabla symbol in the MIPS32 and MIPS64
   opcode tables.  */

795
static inline void check_cop1x(DisasContext *ctx)
796 797 798 799 800 801 802 803
{
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_COP1X)))
        generate_exception(ctx, EXCP_RI);
}

/* Verify that the processor is running with 64-bit floating-point
   operations enabled.  */

804
static inline void check_cp1_64bitmode(DisasContext *ctx)
805
{
806
    if (unlikely(~ctx->hflags & (MIPS_HFLAG_F64 | MIPS_HFLAG_COP1X)))
807 808 809 810 811 812 813 814 815 816 817 818 819 820
        generate_exception(ctx, EXCP_RI);
}

/*
 * Verify if floating point register is valid; an operation is not defined
 * if bit 0 of any register specification is set and the FR bit in the
 * Status register equals zero, since the register numbers specify an
 * even-odd pair of adjacent coprocessor general registers. When the FR bit
 * in the Status register equals one, both even and odd register numbers
 * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers.
 *
 * Multiple 64 bit wide registers can be checked by calling
 * gen_op_cp1_registers(freg1 | freg2 | ... | fregN);
 */
821
static inline void check_cp1_registers(DisasContext *ctx, int regs)
822
{
823
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)))
824 825 826
        generate_exception(ctx, EXCP_RI);
}

827
/* This code generates a "reserved instruction" exception if the
828
   CPU does not support the instruction set corresponding to flags. */
829
static inline void check_insn(CPUMIPSState *env, DisasContext *ctx, int flags)
830
{
831
    if (unlikely(!(env->insn_flags & flags)))
832 833 834
        generate_exception(ctx, EXCP_RI);
}

835 836
/* This code generates a "reserved instruction" exception if 64-bit
   instructions are not enabled. */
837
static inline void check_mips_64(DisasContext *ctx)
838
{
839
    if (unlikely(!(ctx->hflags & MIPS_HFLAG_64)))
840 841 842
        generate_exception(ctx, EXCP_RI);
}

843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
/* Define small wrappers for gen_load_fpr* so that we have a uniform
   calling interface for 32 and 64-bit FPRs.  No sense in changing
   all callers for gen_load_fpr32 when we need the CTX parameter for
   this one use.  */
#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y)
#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y)
#define FOP_CONDS(type, abs, fmt, ifmt, bits)                                 \
static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n,      \
                                               int ft, int fs, int cc)        \
{                                                                             \
    TCGv_i##bits fp0 = tcg_temp_new_i##bits ();                               \
    TCGv_i##bits fp1 = tcg_temp_new_i##bits ();                               \
    switch (ifmt) {                                                           \
    case FMT_PS:                                                              \
        check_cp1_64bitmode(ctx);                                             \
        break;                                                                \
    case FMT_D:                                                               \
        if (abs) {                                                            \
            check_cop1x(ctx);                                                 \
        }                                                                     \
        check_cp1_registers(ctx, fs | ft);                                    \
        break;                                                                \
    case FMT_S:                                                               \
        if (abs) {                                                            \
            check_cop1x(ctx);                                                 \
        }                                                                     \
        break;                                                                \
    }                                                                         \
    gen_ldcmp_fpr##bits (ctx, fp0, fs);                                       \
    gen_ldcmp_fpr##bits (ctx, fp1, ft);                                       \
    switch (n) {                                                              \
    case  0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc);    break;\
    case  1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc);   break;\
    case  2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc);   break;\
    case  3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc);  break;\
    case  4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc);  break;\
    case  5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc);  break;\
    case  6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc);  break;\
    case  7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc);  break;\
    case  8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc);   break;\
    case  9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\
    case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc);  break;\
    case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc);  break;\
    case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc);   break;\
    case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc);  break;\
    case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc);   break;\
    case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc);  break;\
    default: abort();                                                         \
    }                                                                         \
    tcg_temp_free_i##bits (fp0);                                              \
    tcg_temp_free_i##bits (fp1);                                              \
}

FOP_CONDS(, 0, d, FMT_D, 64)
FOP_CONDS(abs, 1, d, FMT_D, 64)
FOP_CONDS(, 0, s, FMT_S, 32)
FOP_CONDS(abs, 1, s, FMT_S, 32)
FOP_CONDS(, 0, ps, FMT_PS, 64)
FOP_CONDS(abs, 1, ps, FMT_PS, 64)
#undef FOP_CONDS
#undef gen_ldcmp_fpr32
#undef gen_ldcmp_fpr64

T
ths 已提交
906
/* load/store instructions. */
907
#define OP_LD(insn,fname)                                                 \
908
static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)   \
909 910
{                                                                         \
    tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                        \
911 912 913 914 915 916 917 918 919 920 921 922
}
OP_LD(lb,ld8s);
OP_LD(lbu,ld8u);
OP_LD(lh,ld16s);
OP_LD(lhu,ld16u);
OP_LD(lw,ld32s);
#if defined(TARGET_MIPS64)
OP_LD(lwu,ld32u);
OP_LD(ld,ld64);
#endif
#undef OP_LD

923
#define OP_ST(insn,fname)                                                  \
924
static inline void op_st_##insn(TCGv arg1, TCGv arg2, DisasContext *ctx)   \
925 926
{                                                                          \
    tcg_gen_qemu_##fname(arg1, arg2, ctx->mem_idx);                        \
927 928 929 930 931 932 933 934 935
}
OP_ST(sb,st8);
OP_ST(sh,st16);
OP_ST(sw,st32);
#if defined(TARGET_MIPS64)
OP_ST(sd,st64);
#endif
#undef OP_ST

936
#ifdef CONFIG_USER_ONLY
937
#define OP_LD_ATOMIC(insn,fname)                                           \
938
static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
939 940 941 942
{                                                                          \
    TCGv t0 = tcg_temp_new();                                              \
    tcg_gen_mov_tl(t0, arg1);                                              \
    tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx);                         \
943 944
    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, lladdr));                \
    tcg_gen_st_tl(ret, cpu_env, offsetof(CPUMIPSState, llval));                \
945
    tcg_temp_free(t0);                                                     \
946
}
947 948
#else
#define OP_LD_ATOMIC(insn,fname)                                           \
949
static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx)    \
950 951 952 953
{                                                                          \
    gen_helper_2i(insn, ret, arg1, ctx->mem_idx);                          \
}
#endif
954 955 956 957 958 959
OP_LD_ATOMIC(ll,ld32s);
#if defined(TARGET_MIPS64)
OP_LD_ATOMIC(lld,ld64);
#endif
#undef OP_LD_ATOMIC

P
Paul Brook 已提交
960 961
#ifdef CONFIG_USER_ONLY
#define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
962
static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
P
Paul Brook 已提交
963 964 965 966 967 968 969
{                                                                            \
    TCGv t0 = tcg_temp_new();                                                \
    int l1 = gen_new_label();                                                \
    int l2 = gen_new_label();                                                \
                                                                             \
    tcg_gen_andi_tl(t0, arg2, almask);                                       \
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);                              \
970
    tcg_gen_st_tl(arg2, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));          \
P
Paul Brook 已提交
971 972
    generate_exception(ctx, EXCP_AdES);                                      \
    gen_set_label(l1);                                                       \
973
    tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, lladdr));                  \
P
Paul Brook 已提交
974 975
    tcg_gen_brcond_tl(TCG_COND_NE, arg2, t0, l2);                            \
    tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20));                        \
976 977
    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, llreg));                   \
    tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUMIPSState, llnewval));              \
P
Paul Brook 已提交
978 979 980 981 982 983 984 985
    gen_helper_0i(raise_exception, EXCP_SC);                                 \
    gen_set_label(l2);                                                       \
    tcg_gen_movi_tl(t0, 0);                                                  \
    gen_store_gpr(t0, rt);                                                   \
    tcg_temp_free(t0);                                                       \
}
#else
#define OP_ST_ATOMIC(insn,fname,ldname,almask)                               \
986
static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \
P
Paul Brook 已提交
987 988
{                                                                            \
    TCGv t0 = tcg_temp_new();                                                \
989
    gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx);                       \
P
Paul Brook 已提交
990 991 992 993 994
    gen_store_gpr(t0, rt);                                                   \
    tcg_temp_free(t0);                                                       \
}
#endif
OP_ST_ATOMIC(sc,st32,ld32s,0x3);
995
#if defined(TARGET_MIPS64)
P
Paul Brook 已提交
996
OP_ST_ATOMIC(scd,st64,ld64,0x7);
997 998 999
#endif
#undef OP_ST_ATOMIC

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
static void gen_base_offset_addr (DisasContext *ctx, TCGv addr,
                                  int base, int16_t offset)
{
    if (base == 0) {
        tcg_gen_movi_tl(addr, offset);
    } else if (offset == 0) {
        gen_load_gpr(addr, base);
    } else {
        tcg_gen_movi_tl(addr, offset);
        gen_op_addr_add(ctx, addr, cpu_gpr[base], addr);
    }
}

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
static target_ulong pc_relative_pc (DisasContext *ctx)
{
    target_ulong pc = ctx->pc;

    if (ctx->hflags & MIPS_HFLAG_BMASK) {
        int branch_bytes = ctx->hflags & MIPS_HFLAG_BDS16 ? 2 : 4;

        pc -= branch_bytes;
    }

    pc &= ~(target_ulong)3;
    return pc;
}

1027
/* Load */
1028
static void gen_ld (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
1029
                    int rt, int base, int16_t offset)
B
bellard 已提交
1030
{
1031
    const char *opn = "ld";
1032 1033 1034 1035 1036 1037 1038 1039 1040
    TCGv t0, t1;

    if (rt == 0 && env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) {
        /* Loongson CPU uses a load to zero register for prefetch.
           We emulate it as a NOP. On other CPU we must perform the
           actual memory access. */
        MIPS_DEBUG("NOP");
        return;
    }
B
bellard 已提交
1041

1042 1043
    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
1044
    gen_base_offset_addr(ctx, t0, base, offset);
1045

B
bellard 已提交
1046
    switch (opc) {
1047
#if defined(TARGET_MIPS64)
1048
    case OPC_LWU:
A
aurel32 已提交
1049
        save_cpu_state(ctx, 0);
1050
        op_ld_lwu(t0, t0, ctx);
T
ths 已提交
1051
        gen_store_gpr(t0, rt);
1052 1053
        opn = "lwu";
        break;
B
bellard 已提交
1054
    case OPC_LD:
A
aurel32 已提交
1055
        save_cpu_state(ctx, 0);
1056
        op_ld_ld(t0, t0, ctx);
T
ths 已提交
1057
        gen_store_gpr(t0, rt);
B
bellard 已提交
1058 1059
        opn = "ld";
        break;
1060
    case OPC_LLD:
1061
        save_cpu_state(ctx, 1);
1062
        op_ld_lld(t0, t0, ctx);
T
ths 已提交
1063
        gen_store_gpr(t0, rt);
1064 1065
        opn = "lld";
        break;
B
bellard 已提交
1066
    case OPC_LDL:
T
ths 已提交
1067
        save_cpu_state(ctx, 1);
T
ths 已提交
1068
        gen_load_gpr(t1, rt);
1069
        gen_helper_3i(ldl, t1, t1, t0, ctx->mem_idx);
T
ths 已提交
1070
        gen_store_gpr(t1, rt);
B
bellard 已提交
1071 1072 1073
        opn = "ldl";
        break;
    case OPC_LDR:
T
ths 已提交
1074
        save_cpu_state(ctx, 1);
T
ths 已提交
1075
        gen_load_gpr(t1, rt);
1076
        gen_helper_3i(ldr, t1, t1, t0, ctx->mem_idx);
T
ths 已提交
1077
        gen_store_gpr(t1, rt);
B
bellard 已提交
1078 1079
        opn = "ldr";
        break;
1080
    case OPC_LDPC:
1081
        save_cpu_state(ctx, 0);
1082 1083
        tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
        gen_op_addr_add(ctx, t0, t0, t1);
1084
        op_ld_ld(t0, t0, ctx);
1085
        gen_store_gpr(t0, rt);
1086
        opn = "ldpc";
1087
        break;
B
bellard 已提交
1088
#endif
1089
    case OPC_LWPC:
1090
        save_cpu_state(ctx, 0);
1091 1092
        tcg_gen_movi_tl(t1, pc_relative_pc(ctx));
        gen_op_addr_add(ctx, t0, t0, t1);
1093
        op_ld_lw(t0, t0, ctx);
1094
        gen_store_gpr(t0, rt);
1095
        opn = "lwpc";
1096
        break;
B
bellard 已提交
1097
    case OPC_LW:
A
aurel32 已提交
1098
        save_cpu_state(ctx, 0);
1099
        op_ld_lw(t0, t0, ctx);
T
ths 已提交
1100
        gen_store_gpr(t0, rt);
B
bellard 已提交
1101 1102 1103
        opn = "lw";
        break;
    case OPC_LH:
A
aurel32 已提交
1104
        save_cpu_state(ctx, 0);
1105
        op_ld_lh(t0, t0, ctx);
T
ths 已提交
1106
        gen_store_gpr(t0, rt);
B
bellard 已提交
1107 1108 1109
        opn = "lh";
        break;
    case OPC_LHU:
A
aurel32 已提交
1110
        save_cpu_state(ctx, 0);
1111
        op_ld_lhu(t0, t0, ctx);
T
ths 已提交
1112
        gen_store_gpr(t0, rt);
B
bellard 已提交
1113 1114 1115
        opn = "lhu";
        break;
    case OPC_LB:
A
aurel32 已提交
1116
        save_cpu_state(ctx, 0);
1117
        op_ld_lb(t0, t0, ctx);
T
ths 已提交
1118
        gen_store_gpr(t0, rt);
B
bellard 已提交
1119 1120 1121
        opn = "lb";
        break;
    case OPC_LBU:
A
aurel32 已提交
1122
        save_cpu_state(ctx, 0);
1123
        op_ld_lbu(t0, t0, ctx);
T
ths 已提交
1124
        gen_store_gpr(t0, rt);
B
bellard 已提交
1125 1126 1127
        opn = "lbu";
        break;
    case OPC_LWL:
T
ths 已提交
1128
        save_cpu_state(ctx, 1);
A
aurel32 已提交
1129
        gen_load_gpr(t1, rt);
1130
        gen_helper_3i(lwl, t1, t1, t0, ctx->mem_idx);
T
ths 已提交
1131
        gen_store_gpr(t1, rt);
B
bellard 已提交
1132 1133 1134
        opn = "lwl";
        break;
    case OPC_LWR:
T
ths 已提交
1135
        save_cpu_state(ctx, 1);
A
aurel32 已提交
1136
        gen_load_gpr(t1, rt);
1137
        gen_helper_3i(lwr, t1, t1, t0, ctx->mem_idx);
T
ths 已提交
1138
        gen_store_gpr(t1, rt);
B
bellard 已提交
1139 1140 1141
        opn = "lwr";
        break;
    case OPC_LL:
1142
        save_cpu_state(ctx, 1);
1143
        op_ld_ll(t0, t0, ctx);
T
ths 已提交
1144
        gen_store_gpr(t0, rt);
B
bellard 已提交
1145 1146
        opn = "ll";
        break;
A
aurel32 已提交
1147
    }
B
Blue Swirl 已提交
1148
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1149 1150 1151 1152 1153
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}

1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
/* Store */
static void gen_st (DisasContext *ctx, uint32_t opc, int rt,
                    int base, int16_t offset)
{
    const char *opn = "st";
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();

    gen_base_offset_addr(ctx, t0, base, offset);
    gen_load_gpr(t1, rt);
    switch (opc) {
#if defined(TARGET_MIPS64)
    case OPC_SD:
        save_cpu_state(ctx, 0);
        op_st_sd(t1, t0, ctx);
        opn = "sd";
        break;
    case OPC_SDL:
        save_cpu_state(ctx, 1);
        gen_helper_2i(sdl, t1, t0, ctx->mem_idx);
        opn = "sdl";
        break;
    case OPC_SDR:
        save_cpu_state(ctx, 1);
        gen_helper_2i(sdr, t1, t0, ctx->mem_idx);
        opn = "sdr";
        break;
#endif
    case OPC_SW:
        save_cpu_state(ctx, 0);
        op_st_sw(t1, t0, ctx);
        opn = "sw";
        break;
    case OPC_SH:
        save_cpu_state(ctx, 0);
        op_st_sh(t1, t0, ctx);
        opn = "sh";
        break;
    case OPC_SB:
        save_cpu_state(ctx, 0);
        op_st_sb(t1, t0, ctx);
        opn = "sb";
        break;
    case OPC_SWL:
        save_cpu_state(ctx, 1);
        gen_helper_2i(swl, t1, t0, ctx->mem_idx);
        opn = "swl";
        break;
    case OPC_SWR:
        save_cpu_state(ctx, 1);
        gen_helper_2i(swr, t1, t0, ctx->mem_idx);
        opn = "swr";
        break;
    }
B
Blue Swirl 已提交
1208
    (void)opn; /* avoid a compiler warning */
1209 1210 1211 1212 1213 1214
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}


A
aurel32 已提交
1215 1216 1217 1218 1219 1220 1221 1222 1223
/* Store conditional */
static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt,
                         int base, int16_t offset)
{
    const char *opn = "st_cond";
    TCGv t0, t1;

    t0 = tcg_temp_local_new();

1224
    gen_base_offset_addr(ctx, t0, base, offset);
A
aurel32 已提交
1225 1226 1227 1228 1229 1230 1231 1232
    /* Don't do NOP if destination is zero: we must perform the actual
       memory access. */

    t1 = tcg_temp_local_new();
    gen_load_gpr(t1, rt);
    switch (opc) {
#if defined(TARGET_MIPS64)
    case OPC_SCD:
1233
        save_cpu_state(ctx, 1);
1234
        op_st_scd(t1, t0, rt, ctx);
A
aurel32 已提交
1235 1236 1237
        opn = "scd";
        break;
#endif
B
bellard 已提交
1238
    case OPC_SC:
1239
        save_cpu_state(ctx, 1);
1240
        op_st_sc(t1, t0, rt, ctx);
B
bellard 已提交
1241 1242 1243
        opn = "sc";
        break;
    }
B
Blue Swirl 已提交
1244
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
1245
    MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
T
ths 已提交
1246
    tcg_temp_free(t1);
A
aurel32 已提交
1247
    tcg_temp_free(t0);
B
bellard 已提交
1248 1249
}

B
bellard 已提交
1250
/* Load and store */
1251
static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
1252
                          int base, int16_t offset)
B
bellard 已提交
1253
{
1254
    const char *opn = "flt_ldst";
A
aurel32 已提交
1255
    TCGv t0 = tcg_temp_new();
B
bellard 已提交
1256

1257
    gen_base_offset_addr(ctx, t0, base, offset);
B
bellard 已提交
1258
    /* Don't do NOP if destination is zero: we must perform the actual
1259
       memory access. */
B
bellard 已提交
1260 1261
    switch (opc) {
    case OPC_LWC1:
1262
        {
P
pbrook 已提交
1263
            TCGv_i32 fp0 = tcg_temp_new_i32();
1264

A
aurel32 已提交
1265 1266
            tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx);
            tcg_gen_trunc_tl_i32(fp0, t0);
1267
            gen_store_fpr32(fp0, ft);
P
pbrook 已提交
1268
            tcg_temp_free_i32(fp0);
1269
        }
B
bellard 已提交
1270 1271 1272
        opn = "lwc1";
        break;
    case OPC_SWC1:
1273
        {
P
pbrook 已提交
1274 1275
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv t1 = tcg_temp_new();
1276 1277

            gen_load_fpr32(fp0, ft);
P
pbrook 已提交
1278 1279 1280 1281
            tcg_gen_extu_i32_tl(t1, fp0);
            tcg_gen_qemu_st32(t1, t0, ctx->mem_idx);
            tcg_temp_free(t1);
            tcg_temp_free_i32(fp0);
1282
        }
B
bellard 已提交
1283 1284 1285
        opn = "swc1";
        break;
    case OPC_LDC1:
1286
        {
P
pbrook 已提交
1287
            TCGv_i64 fp0 = tcg_temp_new_i64();
1288 1289 1290

            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
            gen_store_fpr64(ctx, fp0, ft);
P
pbrook 已提交
1291
            tcg_temp_free_i64(fp0);
1292
        }
B
bellard 已提交
1293 1294 1295
        opn = "ldc1";
        break;
    case OPC_SDC1:
1296
        {
P
pbrook 已提交
1297
            TCGv_i64 fp0 = tcg_temp_new_i64();
1298 1299 1300

            gen_load_fpr64(ctx, fp0, ft);
            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
P
pbrook 已提交
1301
            tcg_temp_free_i64(fp0);
1302
        }
B
bellard 已提交
1303 1304 1305
        opn = "sdc1";
        break;
    default:
1306
        MIPS_INVAL(opn);
1307
        generate_exception(ctx, EXCP_RI);
T
ths 已提交
1308
        goto out;
B
bellard 已提交
1309
    }
B
Blue Swirl 已提交
1310
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
1311
    MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
T
ths 已提交
1312 1313
 out:
    tcg_temp_free(t0);
B
bellard 已提交
1314 1315
}

1316
static void gen_cop1_ldst(CPUMIPSState *env, DisasContext *ctx,
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
                          uint32_t op, int rt, int rs, int16_t imm)
{
    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
        check_cp1_enabled(ctx);
        gen_flt_ldst(ctx, op, rt, rs, imm);
    } else {
        generate_exception_err(ctx, EXCP_CpU, 1);
    }
}

B
bellard 已提交
1327
/* Arithmetic with immediate operand */
1328
static void gen_arith_imm (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
1329
                           int rt, int rs, int16_t imm)
B
bellard 已提交
1330
{
A
aurel32 已提交
1331
    target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */
1332
    const char *opn = "imm arith";
B
bellard 已提交
1333

1334
    if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
1335 1336
        /* If no destination, treat it as a NOP.
           For addi, we must generate the overflow exception when needed. */
B
bellard 已提交
1337
        MIPS_DEBUG("NOP");
A
aurel32 已提交
1338
        return;
B
bellard 已提交
1339 1340 1341
    }
    switch (opc) {
    case OPC_ADDI:
1342
        {
A
aurel32 已提交
1343 1344 1345
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1346 1347
            int l1 = gen_new_label();

A
aurel32 已提交
1348 1349 1350
            gen_load_gpr(t1, rs);
            tcg_gen_addi_tl(t0, t1, uimm);
            tcg_gen_ext32s_tl(t0, t0);
1351

A
aurel32 已提交
1352 1353 1354 1355 1356 1357
            tcg_gen_xori_tl(t1, t1, ~uimm);
            tcg_gen_xori_tl(t2, t0, uimm);
            tcg_gen_and_tl(t1, t1, t2);
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
1358 1359 1360
            /* operands of same sign, result different sign */
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
T
ths 已提交
1361
            tcg_gen_ext32s_tl(t0, t0);
A
aurel32 已提交
1362 1363
            gen_store_gpr(t0, rt);
            tcg_temp_free(t0);
1364
        }
B
bellard 已提交
1365 1366 1367
        opn = "addi";
        break;
    case OPC_ADDIU:
A
aurel32 已提交
1368 1369 1370 1371 1372 1373
        if (rs != 0) {
            tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
            tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
        }
B
bellard 已提交
1374 1375
        opn = "addiu";
        break;
1376
#if defined(TARGET_MIPS64)
1377
    case OPC_DADDI:
1378
        {
A
aurel32 已提交
1379 1380 1381
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1382 1383
            int l1 = gen_new_label();

A
aurel32 已提交
1384 1385
            gen_load_gpr(t1, rs);
            tcg_gen_addi_tl(t0, t1, uimm);
1386

A
aurel32 已提交
1387 1388 1389 1390 1391 1392
            tcg_gen_xori_tl(t1, t1, ~uimm);
            tcg_gen_xori_tl(t2, t0, uimm);
            tcg_gen_and_tl(t1, t1, t2);
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
1393 1394 1395
            /* operands of same sign, result different sign */
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
A
aurel32 已提交
1396 1397
            gen_store_gpr(t0, rt);
            tcg_temp_free(t0);
1398
        }
1399 1400 1401
        opn = "daddi";
        break;
    case OPC_DADDIU:
A
aurel32 已提交
1402 1403 1404 1405 1406
        if (rs != 0) {
            tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
        }
1407 1408 1409
        opn = "daddiu";
        break;
#endif
A
aurel32 已提交
1410
    }
B
Blue Swirl 已提交
1411
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1412 1413 1414 1415
    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
}

/* Logic with immediate operand */
1416
static void gen_logic_imm (CPUMIPSState *env, uint32_t opc, int rt, int rs, int16_t imm)
A
aurel32 已提交
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
{
    target_ulong uimm;
    const char *opn = "imm logic";

    if (rt == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }
    uimm = (uint16_t)imm;
    switch (opc) {
B
bellard 已提交
1428
    case OPC_ANDI:
A
aurel32 已提交
1429 1430 1431 1432
        if (likely(rs != 0))
            tcg_gen_andi_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
        else
            tcg_gen_movi_tl(cpu_gpr[rt], 0);
B
bellard 已提交
1433 1434 1435
        opn = "andi";
        break;
    case OPC_ORI:
A
aurel32 已提交
1436 1437 1438 1439
        if (rs != 0)
            tcg_gen_ori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
        else
            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
B
bellard 已提交
1440 1441 1442
        opn = "ori";
        break;
    case OPC_XORI:
A
aurel32 已提交
1443 1444 1445 1446
        if (likely(rs != 0))
            tcg_gen_xori_tl(cpu_gpr[rt], cpu_gpr[rs], uimm);
        else
            tcg_gen_movi_tl(cpu_gpr[rt], uimm);
B
bellard 已提交
1447 1448 1449
        opn = "xori";
        break;
    case OPC_LUI:
A
aurel32 已提交
1450
        tcg_gen_movi_tl(cpu_gpr[rt], imm << 16);
B
bellard 已提交
1451 1452
        opn = "lui";
        break;
A
aurel32 已提交
1453
    }
B
Blue Swirl 已提交
1454
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1455 1456 1457 1458
    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
}

/* Set on less than with immediate operand */
1459
static void gen_slt_imm (CPUMIPSState *env, uint32_t opc, int rt, int rs, int16_t imm)
A
aurel32 已提交
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
{
    target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */
    const char *opn = "imm arith";
    TCGv t0;

    if (rt == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }
    t0 = tcg_temp_new();
    gen_load_gpr(t0, rs);
    switch (opc) {
    case OPC_SLTI:
1474
        tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rt], t0, uimm);
A
aurel32 已提交
1475 1476 1477
        opn = "slti";
        break;
    case OPC_SLTIU:
1478
        tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rt], t0, uimm);
A
aurel32 已提交
1479 1480 1481
        opn = "sltiu";
        break;
    }
B
Blue Swirl 已提交
1482
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1483 1484 1485 1486 1487
    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
    tcg_temp_free(t0);
}

/* Shifts with immediate operand */
1488
static void gen_shift_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
A
aurel32 已提交
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
                          int rt, int rs, int16_t imm)
{
    target_ulong uimm = ((uint16_t)imm) & 0x1f;
    const char *opn = "imm shift";
    TCGv t0;

    if (rt == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    t0 = tcg_temp_new();
    gen_load_gpr(t0, rs);
    switch (opc) {
B
bellard 已提交
1504
    case OPC_SLL:
T
ths 已提交
1505
        tcg_gen_shli_tl(t0, t0, uimm);
A
aurel32 已提交
1506
        tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
B
bellard 已提交
1507 1508 1509
        opn = "sll";
        break;
    case OPC_SRA:
A
aurel32 已提交
1510
        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm);
B
bellard 已提交
1511 1512 1513
        opn = "sra";
        break;
    case OPC_SRL:
1514 1515 1516 1517 1518
        if (uimm != 0) {
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
        } else {
            tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
1519
        }
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
        opn = "srl";
        break;
    case OPC_ROTR:
        if (uimm != 0) {
            TCGv_i32 t1 = tcg_temp_new_i32();

            tcg_gen_trunc_tl_i32(t1, t0);
            tcg_gen_rotri_i32(t1, t1, uimm);
            tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
            tcg_temp_free_i32(t1);
1530 1531
        } else {
            tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
1532 1533
        }
        opn = "rotr";
1534
        break;
1535
#if defined(TARGET_MIPS64)
1536
    case OPC_DSLL:
A
aurel32 已提交
1537
        tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm);
1538 1539 1540
        opn = "dsll";
        break;
    case OPC_DSRA:
A
aurel32 已提交
1541
        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm);
1542 1543 1544
        opn = "dsra";
        break;
    case OPC_DSRL:
1545 1546 1547 1548 1549 1550
        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm);
        opn = "dsrl";
        break;
    case OPC_DROTR:
        if (uimm != 0) {
            tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
1551 1552
        } else {
            tcg_gen_mov_tl(cpu_gpr[rt], t0);
1553
        }
1554
        opn = "drotr";
1555 1556
        break;
    case OPC_DSLL32:
A
aurel32 已提交
1557
        tcg_gen_shli_tl(cpu_gpr[rt], t0, uimm + 32);
1558 1559 1560
        opn = "dsll32";
        break;
    case OPC_DSRA32:
A
aurel32 已提交
1561
        tcg_gen_sari_tl(cpu_gpr[rt], t0, uimm + 32);
1562 1563 1564
        opn = "dsra32";
        break;
    case OPC_DSRL32:
1565 1566 1567 1568 1569 1570
        tcg_gen_shri_tl(cpu_gpr[rt], t0, uimm + 32);
        opn = "dsrl32";
        break;
    case OPC_DROTR32:
        tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm + 32);
        opn = "drotr32";
B
bellard 已提交
1571
        break;
1572
#endif
B
bellard 已提交
1573
    }
B
Blue Swirl 已提交
1574
    (void)opn; /* avoid a compiler warning */
T
ths 已提交
1575
    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
T
ths 已提交
1576
    tcg_temp_free(t0);
B
bellard 已提交
1577 1578 1579
}

/* Arithmetic */
1580
static void gen_arith (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
B
bellard 已提交
1581 1582
                       int rd, int rs, int rt)
{
1583
    const char *opn = "arith";
B
bellard 已提交
1584

1585 1586
    if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
       && opc != OPC_DADD && opc != OPC_DSUB) {
1587 1588
        /* If no destination, treat it as a NOP.
           For add & sub, we must generate the overflow exception when needed. */
B
bellard 已提交
1589
        MIPS_DEBUG("NOP");
A
aurel32 已提交
1590
        return;
T
ths 已提交
1591
    }
A
aurel32 已提交
1592

B
bellard 已提交
1593 1594
    switch (opc) {
    case OPC_ADD:
1595
        {
A
aurel32 已提交
1596 1597 1598
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1599 1600
            int l1 = gen_new_label();

A
aurel32 已提交
1601 1602 1603 1604 1605 1606
            gen_load_gpr(t1, rs);
            gen_load_gpr(t2, rt);
            tcg_gen_add_tl(t0, t1, t2);
            tcg_gen_ext32s_tl(t0, t0);
            tcg_gen_xor_tl(t1, t1, t2);
            tcg_gen_xor_tl(t2, t0, t2);
1607
            tcg_gen_andc_tl(t1, t2, t1);
A
aurel32 已提交
1608 1609 1610
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
1611 1612 1613
            /* operands of same sign, result different sign */
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
A
aurel32 已提交
1614 1615
            gen_store_gpr(t0, rd);
            tcg_temp_free(t0);
1616
        }
B
bellard 已提交
1617 1618 1619
        opn = "add";
        break;
    case OPC_ADDU:
A
aurel32 已提交
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
        if (rs != 0 && rt != 0) {
            tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
B
bellard 已提交
1630 1631 1632
        opn = "addu";
        break;
    case OPC_SUB:
1633
        {
A
aurel32 已提交
1634 1635 1636
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1637 1638
            int l1 = gen_new_label();

A
aurel32 已提交
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
            gen_load_gpr(t1, rs);
            gen_load_gpr(t2, rt);
            tcg_gen_sub_tl(t0, t1, t2);
            tcg_gen_ext32s_tl(t0, t0);
            tcg_gen_xor_tl(t2, t1, t2);
            tcg_gen_xor_tl(t1, t0, t1);
            tcg_gen_and_tl(t1, t1, t2);
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
A
Aurelien Jarno 已提交
1649
            /* operands of different sign, first operand and result different sign */
1650 1651
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
A
aurel32 已提交
1652 1653
            gen_store_gpr(t0, rd);
            tcg_temp_free(t0);
1654
        }
B
bellard 已提交
1655 1656 1657
        opn = "sub";
        break;
    case OPC_SUBU:
A
aurel32 已提交
1658 1659 1660 1661 1662
        if (rs != 0 && rt != 0) {
            tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
1663
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
A
aurel32 已提交
1664 1665 1666 1667 1668
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
B
bellard 已提交
1669 1670
        opn = "subu";
        break;
1671
#if defined(TARGET_MIPS64)
1672
    case OPC_DADD:
1673
        {
A
aurel32 已提交
1674 1675 1676
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1677 1678
            int l1 = gen_new_label();

A
aurel32 已提交
1679 1680 1681 1682 1683
            gen_load_gpr(t1, rs);
            gen_load_gpr(t2, rt);
            tcg_gen_add_tl(t0, t1, t2);
            tcg_gen_xor_tl(t1, t1, t2);
            tcg_gen_xor_tl(t2, t0, t2);
1684
            tcg_gen_andc_tl(t1, t2, t1);
A
aurel32 已提交
1685 1686 1687
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
1688 1689 1690
            /* operands of same sign, result different sign */
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
A
aurel32 已提交
1691 1692
            gen_store_gpr(t0, rd);
            tcg_temp_free(t0);
1693
        }
1694 1695 1696
        opn = "dadd";
        break;
    case OPC_DADDU:
A
aurel32 已提交
1697 1698 1699 1700 1701 1702 1703 1704 1705
        if (rs != 0 && rt != 0) {
            tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
1706 1707 1708
        opn = "daddu";
        break;
    case OPC_DSUB:
1709
        {
A
aurel32 已提交
1710 1711 1712
            TCGv t0 = tcg_temp_local_new();
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
1713 1714
            int l1 = gen_new_label();

A
aurel32 已提交
1715 1716 1717 1718 1719 1720 1721 1722 1723
            gen_load_gpr(t1, rs);
            gen_load_gpr(t2, rt);
            tcg_gen_sub_tl(t0, t1, t2);
            tcg_gen_xor_tl(t2, t1, t2);
            tcg_gen_xor_tl(t1, t0, t1);
            tcg_gen_and_tl(t1, t1, t2);
            tcg_temp_free(t2);
            tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
            tcg_temp_free(t1);
A
Aurelien Jarno 已提交
1724
            /* operands of different sign, first operand and result different sign */
1725 1726
            generate_exception(ctx, EXCP_OVERFLOW);
            gen_set_label(l1);
A
aurel32 已提交
1727 1728
            gen_store_gpr(t0, rd);
            tcg_temp_free(t0);
1729
        }
1730 1731 1732
        opn = "dsub";
        break;
    case OPC_DSUBU:
A
aurel32 已提交
1733 1734 1735 1736 1737 1738 1739 1740 1741
        if (rs != 0 && rt != 0) {
            tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
1742 1743 1744
        opn = "dsubu";
        break;
#endif
A
aurel32 已提交
1745 1746 1747 1748 1749 1750 1751 1752
    case OPC_MUL:
        if (likely(rs != 0 && rt != 0)) {
            tcg_gen_mul_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
        opn = "mul";
B
bellard 已提交
1753
        break;
A
aurel32 已提交
1754
    }
B
Blue Swirl 已提交
1755
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1756 1757 1758 1759
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}

/* Conditional move */
1760
static void gen_cond_move (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt)
A
aurel32 已提交
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779
{
    const char *opn = "cond move";
    int l1;

    if (rd == 0) {
        /* If no destination, treat it as a NOP.
           For add & sub, we must generate the overflow exception when needed. */
        MIPS_DEBUG("NOP");
        return;
    }

    l1 = gen_new_label();
    switch (opc) {
    case OPC_MOVN:
        if (likely(rt != 0))
            tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rt], 0, l1);
        else
            tcg_gen_br(l1);
        opn = "movn";
B
bellard 已提交
1780
        break;
A
aurel32 已提交
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
    case OPC_MOVZ:
        if (likely(rt != 0))
            tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rt], 0, l1);
        opn = "movz";
        break;
    }
    if (rs != 0)
        tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
    else
        tcg_gen_movi_tl(cpu_gpr[rd], 0);
    gen_set_label(l1);

B
Blue Swirl 已提交
1793
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1794 1795 1796 1797
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}

/* Logic */
1798
static void gen_logic (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt)
A
aurel32 已提交
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
{
    const char *opn = "logic";

    if (rd == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    switch (opc) {
B
bellard 已提交
1809
    case OPC_AND:
A
aurel32 已提交
1810 1811 1812 1813 1814
        if (likely(rs != 0 && rt != 0)) {
            tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
B
bellard 已提交
1815 1816 1817
        opn = "and";
        break;
    case OPC_NOR:
A
aurel32 已提交
1818 1819 1820 1821 1822 1823 1824 1825 1826
        if (rs != 0 && rt != 0) {
            tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0));
        }
B
bellard 已提交
1827 1828 1829
        opn = "nor";
        break;
    case OPC_OR:
A
aurel32 已提交
1830 1831 1832 1833 1834 1835 1836 1837 1838
        if (likely(rs != 0 && rt != 0)) {
            tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
B
bellard 已提交
1839 1840 1841
        opn = "or";
        break;
    case OPC_XOR:
A
aurel32 已提交
1842 1843 1844 1845 1846 1847 1848 1849 1850
        if (likely(rs != 0 && rt != 0)) {
            tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rs], cpu_gpr[rt]);
        } else if (rs == 0 && rt != 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rt]);
        } else if (rs != 0 && rt == 0) {
            tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
        } else {
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
        }
B
bellard 已提交
1851 1852
        opn = "xor";
        break;
A
aurel32 已提交
1853
    }
B
Blue Swirl 已提交
1854
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1855 1856 1857 1858
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
}

/* Set on lower than */
1859
static void gen_slt (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt)
A
aurel32 已提交
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
{
    const char *opn = "slt";
    TCGv t0, t1;

    if (rd == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
    gen_load_gpr(t0, rs);
    gen_load_gpr(t1, rt);
    switch (opc) {
    case OPC_SLT:
1876
        tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1);
A
aurel32 已提交
1877
        opn = "slt";
B
bellard 已提交
1878
        break;
A
aurel32 已提交
1879
    case OPC_SLTU:
1880
        tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1);
A
aurel32 已提交
1881 1882 1883
        opn = "sltu";
        break;
    }
B
Blue Swirl 已提交
1884
    (void)opn; /* avoid a compiler warning */
A
aurel32 已提交
1885 1886 1887 1888
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}
T
ths 已提交
1889

A
aurel32 已提交
1890
/* Shifts */
1891
static void gen_shift (CPUMIPSState *env, DisasContext *ctx, uint32_t opc,
A
aurel32 已提交
1892 1893 1894 1895
                       int rd, int rs, int rt)
{
    const char *opn = "shifts";
    TCGv t0, t1;
T
ths 已提交
1896

A
aurel32 已提交
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
    if (rd == 0) {
        /* If no destination, treat it as a NOP.
           For add & sub, we must generate the overflow exception when needed. */
        MIPS_DEBUG("NOP");
        return;
    }

    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
    gen_load_gpr(t0, rs);
    gen_load_gpr(t1, rt);
    switch (opc) {
B
bellard 已提交
1909
    case OPC_SLLV:
T
ths 已提交
1910 1911
        tcg_gen_andi_tl(t0, t0, 0x1f);
        tcg_gen_shl_tl(t0, t1, t0);
A
aurel32 已提交
1912
        tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
B
bellard 已提交
1913 1914 1915
        opn = "sllv";
        break;
    case OPC_SRAV:
T
ths 已提交
1916
        tcg_gen_andi_tl(t0, t0, 0x1f);
A
aurel32 已提交
1917
        tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
B
bellard 已提交
1918 1919 1920
        opn = "srav";
        break;
    case OPC_SRLV:
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
        tcg_gen_ext32u_tl(t1, t1);
        tcg_gen_andi_tl(t0, t0, 0x1f);
        tcg_gen_shr_tl(t0, t1, t0);
        tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
        opn = "srlv";
        break;
    case OPC_ROTRV:
        {
            TCGv_i32 t2 = tcg_temp_new_i32();
            TCGv_i32 t3 = tcg_temp_new_i32();

            tcg_gen_trunc_tl_i32(t2, t0);
            tcg_gen_trunc_tl_i32(t3, t1);
            tcg_gen_andi_i32(t2, t2, 0x1f);
            tcg_gen_rotr_i32(t2, t3, t2);
            tcg_gen_ext_i32_tl(cpu_gpr[rd], t2);
            tcg_temp_free_i32(t2);
            tcg_temp_free_i32(t3);
            opn = "rotrv";
1940
        }
1941
        break;
1942
#if defined(TARGET_MIPS64)
1943
    case OPC_DSLLV:
T
ths 已提交
1944
        tcg_gen_andi_tl(t0, t0, 0x3f);
A
aurel32 已提交
1945
        tcg_gen_shl_tl(cpu_gpr[rd], t1, t0);
1946 1947 1948
        opn = "dsllv";
        break;
    case OPC_DSRAV:
T
ths 已提交
1949
        tcg_gen_andi_tl(t0, t0, 0x3f);
A
aurel32 已提交
1950
        tcg_gen_sar_tl(cpu_gpr[rd], t1, t0);
1951 1952 1953
        opn = "dsrav";
        break;
    case OPC_DSRLV:
1954 1955 1956 1957 1958 1959 1960 1961
        tcg_gen_andi_tl(t0, t0, 0x3f);
        tcg_gen_shr_tl(cpu_gpr[rd], t1, t0);
        opn = "dsrlv";
        break;
    case OPC_DROTRV:
        tcg_gen_andi_tl(t0, t0, 0x3f);
        tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0);
        opn = "drotrv";
B
bellard 已提交
1962
        break;
1963
#endif
B
bellard 已提交
1964
    }
B
Blue Swirl 已提交
1965
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
1966
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
T
ths 已提交
1967 1968
    tcg_temp_free(t0);
    tcg_temp_free(t1);
B
bellard 已提交
1969 1970 1971
}

/* Arithmetic on HI/LO registers */
1972
static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
B
bellard 已提交
1973
{
1974
    const char *opn = "hilo";
B
bellard 已提交
1975 1976

    if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
1977
        /* Treat as NOP. */
B
bellard 已提交
1978
        MIPS_DEBUG("NOP");
A
aurel32 已提交
1979
        return;
B
bellard 已提交
1980 1981 1982
    }
    switch (opc) {
    case OPC_MFHI:
A
aurel32 已提交
1983
        tcg_gen_mov_tl(cpu_gpr[reg], cpu_HI[0]);
B
bellard 已提交
1984 1985 1986
        opn = "mfhi";
        break;
    case OPC_MFLO:
A
aurel32 已提交
1987
        tcg_gen_mov_tl(cpu_gpr[reg], cpu_LO[0]);
B
bellard 已提交
1988 1989 1990
        opn = "mflo";
        break;
    case OPC_MTHI:
A
aurel32 已提交
1991 1992 1993 1994
        if (reg != 0)
            tcg_gen_mov_tl(cpu_HI[0], cpu_gpr[reg]);
        else
            tcg_gen_movi_tl(cpu_HI[0], 0);
B
bellard 已提交
1995 1996 1997
        opn = "mthi";
        break;
    case OPC_MTLO:
A
aurel32 已提交
1998 1999 2000 2001
        if (reg != 0)
            tcg_gen_mov_tl(cpu_LO[0], cpu_gpr[reg]);
        else
            tcg_gen_movi_tl(cpu_LO[0], 0);
B
bellard 已提交
2002 2003 2004
        opn = "mtlo";
        break;
    }
B
Blue Swirl 已提交
2005
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
2006 2007 2008
    MIPS_DEBUG("%s %s", opn, regnames[reg]);
}

2009
static void gen_muldiv (DisasContext *ctx, uint32_t opc,
B
bellard 已提交
2010 2011
                        int rs, int rt)
{
2012
    const char *opn = "mul/div";
A
aurel32 已提交
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029
    TCGv t0, t1;

    switch (opc) {
    case OPC_DIV:
    case OPC_DIVU:
#if defined(TARGET_MIPS64)
    case OPC_DDIV:
    case OPC_DDIVU:
#endif
        t0 = tcg_temp_local_new();
        t1 = tcg_temp_local_new();
        break;
    default:
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
        break;
    }
B
bellard 已提交
2030

T
ths 已提交
2031 2032
    gen_load_gpr(t0, rs);
    gen_load_gpr(t1, rt);
B
bellard 已提交
2033 2034
    switch (opc) {
    case OPC_DIV:
2035 2036
        {
            int l1 = gen_new_label();
A
aurel32 已提交
2037
            int l2 = gen_new_label();
2038

A
aurel32 已提交
2039 2040
            tcg_gen_ext32s_tl(t0, t0);
            tcg_gen_ext32s_tl(t1, t1);
T
ths 已提交
2041
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
A
aurel32 已提交
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);

            tcg_gen_mov_tl(cpu_LO[0], t0);
            tcg_gen_movi_tl(cpu_HI[0], 0);
            tcg_gen_br(l1);
            gen_set_label(l2);
            tcg_gen_div_tl(cpu_LO[0], t0, t1);
            tcg_gen_rem_tl(cpu_HI[0], t0, t1);
            tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
            tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
2053 2054
            gen_set_label(l1);
        }
B
bellard 已提交
2055 2056 2057
        opn = "div";
        break;
    case OPC_DIVU:
2058 2059 2060
        {
            int l1 = gen_new_label();

A
aurel32 已提交
2061 2062
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
T
ths 已提交
2063
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
A
aurel32 已提交
2064 2065 2066 2067
            tcg_gen_divu_tl(cpu_LO[0], t0, t1);
            tcg_gen_remu_tl(cpu_HI[0], t0, t1);
            tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]);
            tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]);
2068 2069
            gen_set_label(l1);
        }
B
bellard 已提交
2070 2071 2072
        opn = "divu";
        break;
    case OPC_MULT:
2073
        {
A
aurel32 已提交
2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();

            tcg_gen_ext_tl_i64(t2, t0);
            tcg_gen_ext_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2085 2086
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2087
        }
B
bellard 已提交
2088 2089 2090
        opn = "mult";
        break;
    case OPC_MULTU:
2091
        {
A
aurel32 已提交
2092 2093
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();
2094

T
ths 已提交
2095 2096
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
A
aurel32 已提交
2097 2098 2099 2100 2101 2102 2103 2104
            tcg_gen_extu_tl_i64(t2, t0);
            tcg_gen_extu_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2105 2106
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2107
        }
B
bellard 已提交
2108 2109
        opn = "multu";
        break;
2110
#if defined(TARGET_MIPS64)
2111
    case OPC_DDIV:
2112 2113
        {
            int l1 = gen_new_label();
A
aurel32 已提交
2114
            int l2 = gen_new_label();
2115

T
ths 已提交
2116
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
A
aurel32 已提交
2117 2118 2119 2120 2121 2122 2123 2124
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
            tcg_gen_mov_tl(cpu_LO[0], t0);
            tcg_gen_movi_tl(cpu_HI[0], 0);
            tcg_gen_br(l1);
            gen_set_label(l2);
            tcg_gen_div_i64(cpu_LO[0], t0, t1);
            tcg_gen_rem_i64(cpu_HI[0], t0, t1);
2125 2126
            gen_set_label(l1);
        }
2127 2128 2129
        opn = "ddiv";
        break;
    case OPC_DDIVU:
2130 2131 2132
        {
            int l1 = gen_new_label();

T
ths 已提交
2133
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
A
aurel32 已提交
2134 2135
            tcg_gen_divu_i64(cpu_LO[0], t0, t1);
            tcg_gen_remu_i64(cpu_HI[0], t0, t1);
2136 2137
            gen_set_label(l1);
        }
2138 2139 2140
        opn = "ddivu";
        break;
    case OPC_DMULT:
P
pbrook 已提交
2141
        gen_helper_dmult(t0, t1);
2142 2143 2144
        opn = "dmult";
        break;
    case OPC_DMULTU:
P
pbrook 已提交
2145
        gen_helper_dmultu(t0, t1);
2146 2147 2148
        opn = "dmultu";
        break;
#endif
B
bellard 已提交
2149
    case OPC_MADD:
2150
        {
A
aurel32 已提交
2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();

            tcg_gen_ext_tl_i64(t2, t0);
            tcg_gen_ext_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
            tcg_gen_add_i64(t2, t2, t3);
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2164
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
2165
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2166
        }
B
bellard 已提交
2167 2168 2169
        opn = "madd";
        break;
    case OPC_MADDU:
2170
       {
A
aurel32 已提交
2171 2172
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();
2173

T
ths 已提交
2174 2175
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
A
aurel32 已提交
2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
            tcg_gen_extu_tl_i64(t2, t0);
            tcg_gen_extu_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
            tcg_gen_add_i64(t2, t2, t3);
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2186 2187
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2188
        }
B
bellard 已提交
2189 2190 2191
        opn = "maddu";
        break;
    case OPC_MSUB:
2192
        {
A
aurel32 已提交
2193 2194 2195 2196 2197 2198 2199
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();

            tcg_gen_ext_tl_i64(t2, t0);
            tcg_gen_ext_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
2200
            tcg_gen_sub_i64(t2, t3, t2);
A
aurel32 已提交
2201 2202 2203 2204 2205
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2206 2207
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2208
        }
B
bellard 已提交
2209 2210 2211
        opn = "msub";
        break;
    case OPC_MSUBU:
2212
        {
A
aurel32 已提交
2213 2214
            TCGv_i64 t2 = tcg_temp_new_i64();
            TCGv_i64 t3 = tcg_temp_new_i64();
2215

T
ths 已提交
2216 2217
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
A
aurel32 已提交
2218 2219 2220 2221
            tcg_gen_extu_tl_i64(t2, t0);
            tcg_gen_extu_tl_i64(t3, t1);
            tcg_gen_mul_i64(t2, t2, t3);
            tcg_gen_concat_tl_i64(t3, cpu_LO[0], cpu_HI[0]);
2222
            tcg_gen_sub_i64(t2, t3, t2);
A
aurel32 已提交
2223 2224 2225 2226 2227
            tcg_temp_free_i64(t3);
            tcg_gen_trunc_i64_tl(t0, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_tl(t1, t2);
            tcg_temp_free_i64(t2);
A
aurel32 已提交
2228 2229
            tcg_gen_ext32s_tl(cpu_LO[0], t0);
            tcg_gen_ext32s_tl(cpu_HI[0], t1);
2230
        }
B
bellard 已提交
2231 2232 2233
        opn = "msubu";
        break;
    default:
2234
        MIPS_INVAL(opn);
B
bellard 已提交
2235
        generate_exception(ctx, EXCP_RI);
T
ths 已提交
2236
        goto out;
B
bellard 已提交
2237
    }
B
Blue Swirl 已提交
2238
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
2239
    MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
T
ths 已提交
2240 2241 2242
 out:
    tcg_temp_free(t0);
    tcg_temp_free(t1);
B
bellard 已提交
2243 2244
}

2245 2246 2247 2248
static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc,
                            int rd, int rs, int rt)
{
    const char *opn = "mul vr54xx";
A
aurel32 已提交
2249 2250
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
2251

2252 2253
    gen_load_gpr(t0, rs);
    gen_load_gpr(t1, rt);
2254 2255 2256

    switch (opc) {
    case OPC_VR54XX_MULS:
P
pbrook 已提交
2257
        gen_helper_muls(t0, t0, t1);
2258
        opn = "muls";
A
aurel32 已提交
2259
        break;
2260
    case OPC_VR54XX_MULSU:
P
pbrook 已提交
2261
        gen_helper_mulsu(t0, t0, t1);
2262
        opn = "mulsu";
A
aurel32 已提交
2263
        break;
2264
    case OPC_VR54XX_MACC:
P
pbrook 已提交
2265
        gen_helper_macc(t0, t0, t1);
2266
        opn = "macc";
A
aurel32 已提交
2267
        break;
2268
    case OPC_VR54XX_MACCU:
P
pbrook 已提交
2269
        gen_helper_maccu(t0, t0, t1);
2270
        opn = "maccu";
A
aurel32 已提交
2271
        break;
2272
    case OPC_VR54XX_MSAC:
P
pbrook 已提交
2273
        gen_helper_msac(t0, t0, t1);
2274
        opn = "msac";
A
aurel32 已提交
2275
        break;
2276
    case OPC_VR54XX_MSACU:
P
pbrook 已提交
2277
        gen_helper_msacu(t0, t0, t1);
2278
        opn = "msacu";
A
aurel32 已提交
2279
        break;
2280
    case OPC_VR54XX_MULHI:
P
pbrook 已提交
2281
        gen_helper_mulhi(t0, t0, t1);
2282
        opn = "mulhi";
A
aurel32 已提交
2283
        break;
2284
    case OPC_VR54XX_MULHIU:
P
pbrook 已提交
2285
        gen_helper_mulhiu(t0, t0, t1);
2286
        opn = "mulhiu";
A
aurel32 已提交
2287
        break;
2288
    case OPC_VR54XX_MULSHI:
P
pbrook 已提交
2289
        gen_helper_mulshi(t0, t0, t1);
2290
        opn = "mulshi";
A
aurel32 已提交
2291
        break;
2292
    case OPC_VR54XX_MULSHIU:
P
pbrook 已提交
2293
        gen_helper_mulshiu(t0, t0, t1);
2294
        opn = "mulshiu";
A
aurel32 已提交
2295
        break;
2296
    case OPC_VR54XX_MACCHI:
P
pbrook 已提交
2297
        gen_helper_macchi(t0, t0, t1);
2298
        opn = "macchi";
A
aurel32 已提交
2299
        break;
2300
    case OPC_VR54XX_MACCHIU:
P
pbrook 已提交
2301
        gen_helper_macchiu(t0, t0, t1);
2302
        opn = "macchiu";
A
aurel32 已提交
2303
        break;
2304
    case OPC_VR54XX_MSACHI:
P
pbrook 已提交
2305
        gen_helper_msachi(t0, t0, t1);
2306
        opn = "msachi";
A
aurel32 已提交
2307
        break;
2308
    case OPC_VR54XX_MSACHIU:
P
pbrook 已提交
2309
        gen_helper_msachiu(t0, t0, t1);
2310
        opn = "msachiu";
A
aurel32 已提交
2311
        break;
2312 2313 2314
    default:
        MIPS_INVAL("mul vr54xx");
        generate_exception(ctx, EXCP_RI);
2315
        goto out;
2316
    }
2317
    gen_store_gpr(t0, rd);
B
Blue Swirl 已提交
2318
    (void)opn; /* avoid a compiler warning */
2319
    MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
2320 2321 2322 2323

 out:
    tcg_temp_free(t0);
    tcg_temp_free(t1);
2324 2325
}

2326
static void gen_cl (DisasContext *ctx, uint32_t opc,
B
bellard 已提交
2327 2328
                    int rd, int rs)
{
2329
    const char *opn = "CLx";
A
aurel32 已提交
2330
    TCGv t0;
2331

B
bellard 已提交
2332
    if (rd == 0) {
2333
        /* Treat as NOP. */
B
bellard 已提交
2334
        MIPS_DEBUG("NOP");
A
aurel32 已提交
2335
        return;
B
bellard 已提交
2336
    }
A
aurel32 已提交
2337
    t0 = tcg_temp_new();
2338
    gen_load_gpr(t0, rs);
B
bellard 已提交
2339 2340
    switch (opc) {
    case OPC_CLO:
A
aurel32 已提交
2341
        gen_helper_clo(cpu_gpr[rd], t0);
B
bellard 已提交
2342 2343 2344
        opn = "clo";
        break;
    case OPC_CLZ:
A
aurel32 已提交
2345
        gen_helper_clz(cpu_gpr[rd], t0);
B
bellard 已提交
2346 2347
        opn = "clz";
        break;
2348
#if defined(TARGET_MIPS64)
2349
    case OPC_DCLO:
A
aurel32 已提交
2350
        gen_helper_dclo(cpu_gpr[rd], t0);
2351 2352 2353
        opn = "dclo";
        break;
    case OPC_DCLZ:
A
aurel32 已提交
2354
        gen_helper_dclz(cpu_gpr[rd], t0);
2355 2356 2357
        opn = "dclz";
        break;
#endif
B
bellard 已提交
2358
    }
B
Blue Swirl 已提交
2359
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
2360
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
2361
    tcg_temp_free(t0);
B
bellard 已提交
2362 2363
}

2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572
/* Godson integer instructions */
static void gen_loongson_integer (DisasContext *ctx, uint32_t opc,
                                int rd, int rs, int rt)
{
    const char *opn = "loongson";
    TCGv t0, t1;

    if (rd == 0) {
        /* Treat as NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    switch (opc) {
    case OPC_MULT_G_2E:
    case OPC_MULT_G_2F:
    case OPC_MULTU_G_2E:
    case OPC_MULTU_G_2F:
#if defined(TARGET_MIPS64)
    case OPC_DMULT_G_2E:
    case OPC_DMULT_G_2F:
    case OPC_DMULTU_G_2E:
    case OPC_DMULTU_G_2F:
#endif
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
        break;
    default:
        t0 = tcg_temp_local_new();
        t1 = tcg_temp_local_new();
        break;
    }

    gen_load_gpr(t0, rs);
    gen_load_gpr(t1, rt);

    switch (opc) {
    case OPC_MULT_G_2E:
    case OPC_MULT_G_2F:
        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
        opn = "mult.g";
        break;
    case OPC_MULTU_G_2E:
    case OPC_MULTU_G_2F:
        tcg_gen_ext32u_tl(t0, t0);
        tcg_gen_ext32u_tl(t1, t1);
        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
        tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
        opn = "multu.g";
        break;
    case OPC_DIV_G_2E:
    case OPC_DIV_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            int l3 = gen_new_label();
            tcg_gen_ext32s_tl(t0, t0);
            tcg_gen_ext32s_tl(t1, t1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l3);
            gen_set_label(l1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
            tcg_gen_mov_tl(cpu_gpr[rd], t0);
            tcg_gen_br(l3);
            gen_set_label(l2);
            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
            gen_set_label(l3);
        }
        opn = "div.g";
        break;
    case OPC_DIVU_G_2E:
    case OPC_DIVU_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l2);
            gen_set_label(l1);
            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
            gen_set_label(l2);
        }
        opn = "divu.g";
        break;
    case OPC_MOD_G_2E:
    case OPC_MOD_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            int l3 = gen_new_label();
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, INT_MIN, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1, l2);
            gen_set_label(l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l3);
            gen_set_label(l2);
            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
            gen_set_label(l3);
        }
        opn = "mod.g";
        break;
    case OPC_MODU_G_2E:
    case OPC_MODU_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            tcg_gen_ext32u_tl(t0, t0);
            tcg_gen_ext32u_tl(t1, t1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l2);
            gen_set_label(l1);
            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
            tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
            gen_set_label(l2);
        }
        opn = "modu.g";
        break;
#if defined(TARGET_MIPS64)
    case OPC_DMULT_G_2E:
    case OPC_DMULT_G_2F:
        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
        opn = "dmult.g";
        break;
    case OPC_DMULTU_G_2E:
    case OPC_DMULTU_G_2F:
        tcg_gen_mul_tl(cpu_gpr[rd], t0, t1);
        opn = "dmultu.g";
        break;
    case OPC_DDIV_G_2E:
    case OPC_DDIV_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            int l3 = gen_new_label();
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l3);
            gen_set_label(l1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
            tcg_gen_mov_tl(cpu_gpr[rd], t0);
            tcg_gen_br(l3);
            gen_set_label(l2);
            tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
            gen_set_label(l3);
        }
        opn = "ddiv.g";
        break;
    case OPC_DDIVU_G_2E:
    case OPC_DDIVU_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l2);
            gen_set_label(l1);
            tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
            gen_set_label(l2);
        }
        opn = "ddivu.g";
        break;
    case OPC_DMOD_G_2E:
    case OPC_DMOD_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            int l3 = gen_new_label();
            tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, -1LL << 63, l2);
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, -1LL, l2);
            gen_set_label(l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l3);
            gen_set_label(l2);
            tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
            gen_set_label(l3);
        }
        opn = "dmod.g";
        break;
    case OPC_DMODU_G_2E:
    case OPC_DMODU_G_2F:
        {
            int l1 = gen_new_label();
            int l2 = gen_new_label();
            tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
            tcg_gen_movi_tl(cpu_gpr[rd], 0);
            tcg_gen_br(l2);
            gen_set_label(l1);
            tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
            gen_set_label(l2);
        }
        opn = "dmodu.g";
        break;
#endif
    }

B
Blue Swirl 已提交
2573
    (void)opn; /* avoid a compiler warning */
2574 2575 2576 2577 2578
    MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}

B
bellard 已提交
2579
/* Traps */
2580
static void gen_trap (DisasContext *ctx, uint32_t opc,
B
bellard 已提交
2581 2582 2583
                      int rs, int rt, int16_t imm)
{
    int cond;
A
aurel32 已提交
2584
    TCGv t0 = tcg_temp_new();
2585
    TCGv t1 = tcg_temp_new();
B
bellard 已提交
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597

    cond = 0;
    /* Load needed operands */
    switch (opc) {
    case OPC_TEQ:
    case OPC_TGE:
    case OPC_TGEU:
    case OPC_TLT:
    case OPC_TLTU:
    case OPC_TNE:
        /* Compare two registers */
        if (rs != rt) {
2598 2599
            gen_load_gpr(t0, rs);
            gen_load_gpr(t1, rt);
B
bellard 已提交
2600 2601
            cond = 1;
        }
2602
        break;
B
bellard 已提交
2603 2604 2605 2606 2607 2608 2609 2610
    case OPC_TEQI:
    case OPC_TGEI:
    case OPC_TGEIU:
    case OPC_TLTI:
    case OPC_TLTIU:
    case OPC_TNEI:
        /* Compare register to immediate */
        if (rs != 0 || imm != 0) {
2611 2612
            gen_load_gpr(t0, rs);
            tcg_gen_movi_tl(t1, (int32_t)imm);
B
bellard 已提交
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
            cond = 1;
        }
        break;
    }
    if (cond == 0) {
        switch (opc) {
        case OPC_TEQ:   /* rs == rs */
        case OPC_TEQI:  /* r0 == 0  */
        case OPC_TGE:   /* rs >= rs */
        case OPC_TGEI:  /* r0 >= 0  */
        case OPC_TGEU:  /* rs >= rs unsigned */
        case OPC_TGEIU: /* r0 >= 0  unsigned */
            /* Always trap */
A
aurel32 已提交
2626
            generate_exception(ctx, EXCP_TRAP);
B
bellard 已提交
2627 2628 2629 2630 2631 2632 2633
            break;
        case OPC_TLT:   /* rs < rs           */
        case OPC_TLTI:  /* r0 < 0            */
        case OPC_TLTU:  /* rs < rs unsigned  */
        case OPC_TLTIU: /* r0 < 0  unsigned  */
        case OPC_TNE:   /* rs != rs          */
        case OPC_TNEI:  /* r0 != 0           */
2634
            /* Never trap: treat as NOP. */
A
aurel32 已提交
2635
            break;
B
bellard 已提交
2636 2637
        }
    } else {
A
aurel32 已提交
2638 2639
        int l1 = gen_new_label();

B
bellard 已提交
2640 2641 2642
        switch (opc) {
        case OPC_TEQ:
        case OPC_TEQI:
A
aurel32 已提交
2643
            tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1);
B
bellard 已提交
2644 2645 2646
            break;
        case OPC_TGE:
        case OPC_TGEI:
A
aurel32 已提交
2647
            tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1);
B
bellard 已提交
2648 2649 2650
            break;
        case OPC_TGEU:
        case OPC_TGEIU:
A
aurel32 已提交
2651
            tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1);
B
bellard 已提交
2652 2653 2654
            break;
        case OPC_TLT:
        case OPC_TLTI:
A
aurel32 已提交
2655
            tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
B
bellard 已提交
2656 2657 2658
            break;
        case OPC_TLTU:
        case OPC_TLTIU:
A
aurel32 已提交
2659
            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
B
bellard 已提交
2660 2661 2662
            break;
        case OPC_TNE:
        case OPC_TNEI:
A
aurel32 已提交
2663
            tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1);
B
bellard 已提交
2664 2665
            break;
        }
A
aurel32 已提交
2666
        generate_exception(ctx, EXCP_TRAP);
T
ths 已提交
2667 2668
        gen_set_label(l1);
    }
2669 2670
    tcg_temp_free(t0);
    tcg_temp_free(t1);
B
bellard 已提交
2671 2672
}

2673
static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
B
bellard 已提交
2674
{
2675 2676
    TranslationBlock *tb;
    tb = ctx->tb;
N
Nathan Froyd 已提交
2677 2678
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
        likely(!ctx->singlestep_enabled)) {
B
bellard 已提交
2679
        tcg_gen_goto_tb(n);
2680
        gen_save_pc(dest);
2681
        tcg_gen_exit_tb((tcg_target_long)tb + n);
2682
    } else {
2683
        gen_save_pc(dest);
N
Nathan Froyd 已提交
2684 2685 2686 2687
        if (ctx->singlestep_enabled) {
            save_cpu_state(ctx, 0);
            gen_helper_0i(raise_exception, EXCP_DEBUG);
        }
B
bellard 已提交
2688
        tcg_gen_exit_tb(0);
2689
    }
B
bellard 已提交
2690 2691
}

B
bellard 已提交
2692
/* Branches (before delay slot) */
2693
static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
2694
                                int insn_bytes,
B
bellard 已提交
2695 2696
                                int rs, int rt, int32_t offset)
{
T
ths 已提交
2697
    target_ulong btgt = -1;
2698
    int blink = 0;
A
aurel32 已提交
2699
    int bcond_compute = 0;
2700 2701
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
2702 2703

    if (ctx->hflags & MIPS_HFLAG_BMASK) {
2704
#ifdef MIPS_DEBUG_DISAS
2705
        LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc);
2706
#endif
2707
        generate_exception(ctx, EXCP_RI);
2708
        goto out;
2709
    }
B
bellard 已提交
2710 2711 2712 2713 2714 2715 2716 2717 2718

    /* Load needed operands */
    switch (opc) {
    case OPC_BEQ:
    case OPC_BEQL:
    case OPC_BNE:
    case OPC_BNEL:
        /* Compare two registers */
        if (rs != rt) {
2719 2720
            gen_load_gpr(t0, rs);
            gen_load_gpr(t1, rt);
A
aurel32 已提交
2721
            bcond_compute = 1;
B
bellard 已提交
2722
        }
2723
        btgt = ctx->pc + insn_bytes + offset;
B
bellard 已提交
2724 2725 2726
        break;
    case OPC_BGEZ:
    case OPC_BGEZAL:
2727
    case OPC_BGEZALS:
B
bellard 已提交
2728 2729 2730 2731 2732 2733 2734 2735
    case OPC_BGEZALL:
    case OPC_BGEZL:
    case OPC_BGTZ:
    case OPC_BGTZL:
    case OPC_BLEZ:
    case OPC_BLEZL:
    case OPC_BLTZ:
    case OPC_BLTZAL:
2736
    case OPC_BLTZALS:
B
bellard 已提交
2737 2738 2739 2740
    case OPC_BLTZALL:
    case OPC_BLTZL:
        /* Compare to zero */
        if (rs != 0) {
2741
            gen_load_gpr(t0, rs);
A
aurel32 已提交
2742
            bcond_compute = 1;
B
bellard 已提交
2743
        }
2744
        btgt = ctx->pc + insn_bytes + offset;
B
bellard 已提交
2745 2746 2747
        break;
    case OPC_J:
    case OPC_JAL:
2748
    case OPC_JALX:
N
Nathan Froyd 已提交
2749 2750
    case OPC_JALS:
    case OPC_JALXS:
B
bellard 已提交
2751
        /* Jump to immediate */
2752
        btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
B
bellard 已提交
2753 2754 2755
        break;
    case OPC_JR:
    case OPC_JALR:
2756
    case OPC_JALRC:
N
Nathan Froyd 已提交
2757
    case OPC_JALRS:
B
bellard 已提交
2758
        /* Jump to register */
2759 2760
        if (offset != 0 && offset != 16) {
            /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
2761
               others are reserved. */
2762
            MIPS_INVAL("jump hint");
B
bellard 已提交
2763
            generate_exception(ctx, EXCP_RI);
2764
            goto out;
B
bellard 已提交
2765
        }
T
ths 已提交
2766
        gen_load_gpr(btarget, rs);
B
bellard 已提交
2767 2768 2769 2770
        break;
    default:
        MIPS_INVAL("branch/jump");
        generate_exception(ctx, EXCP_RI);
2771
        goto out;
B
bellard 已提交
2772
    }
A
aurel32 已提交
2773
    if (bcond_compute == 0) {
B
bellard 已提交
2774 2775 2776 2777 2778 2779 2780 2781 2782
        /* No condition to be computed */
        switch (opc) {
        case OPC_BEQ:     /* rx == rx        */
        case OPC_BEQL:    /* rx == rx likely */
        case OPC_BGEZ:    /* 0 >= 0          */
        case OPC_BGEZL:   /* 0 >= 0 likely   */
        case OPC_BLEZ:    /* 0 <= 0          */
        case OPC_BLEZL:   /* 0 <= 0 likely   */
            /* Always take */
B
bellard 已提交
2783
            ctx->hflags |= MIPS_HFLAG_B;
B
bellard 已提交
2784 2785
            MIPS_DEBUG("balways");
            break;
2786
        case OPC_BGEZALS:
B
bellard 已提交
2787 2788
        case OPC_BGEZAL:  /* 0 >= 0          */
        case OPC_BGEZALL: /* 0 >= 0 likely   */
2789 2790 2791
            ctx->hflags |= (opc == OPC_BGEZALS
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
B
bellard 已提交
2792 2793
            /* Always take and link */
            blink = 31;
B
bellard 已提交
2794
            ctx->hflags |= MIPS_HFLAG_B;
B
bellard 已提交
2795 2796 2797 2798 2799
            MIPS_DEBUG("balways and link");
            break;
        case OPC_BNE:     /* rx != rx        */
        case OPC_BGTZ:    /* 0 > 0           */
        case OPC_BLTZ:    /* 0 < 0           */
2800
            /* Treat as NOP. */
B
bellard 已提交
2801
            MIPS_DEBUG("bnever (NOP)");
2802
            goto out;
2803
        case OPC_BLTZALS:
2804
        case OPC_BLTZAL:  /* 0 < 0           */
2805 2806 2807 2808 2809 2810 2811 2812
            ctx->hflags |= (opc == OPC_BLTZALS
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
            /* Handle as an unconditional branch to get correct delay
               slot checking.  */
            blink = 31;
            btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8);
            ctx->hflags |= MIPS_HFLAG_B;
T
ths 已提交
2813
            MIPS_DEBUG("bnever and link");
2814
            break;
2815
        case OPC_BLTZALL: /* 0 < 0 likely */
2816
            tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
T
ths 已提交
2817 2818 2819
            /* Skip the instruction in the delay slot */
            MIPS_DEBUG("bnever, link and skip");
            ctx->pc += 4;
2820
            goto out;
B
bellard 已提交
2821 2822 2823 2824 2825
        case OPC_BNEL:    /* rx != rx likely */
        case OPC_BGTZL:   /* 0 > 0 likely */
        case OPC_BLTZL:   /* 0 < 0 likely */
            /* Skip the instruction in the delay slot */
            MIPS_DEBUG("bnever and skip");
T
ths 已提交
2826
            ctx->pc += 4;
2827
            goto out;
B
bellard 已提交
2828
        case OPC_J:
B
bellard 已提交
2829
            ctx->hflags |= MIPS_HFLAG_B;
T
ths 已提交
2830
            MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
B
bellard 已提交
2831
            break;
N
Nathan Froyd 已提交
2832
        case OPC_JALXS:
2833 2834 2835
        case OPC_JALX:
            ctx->hflags |= MIPS_HFLAG_BX;
            /* Fallthrough */
N
Nathan Froyd 已提交
2836
        case OPC_JALS:
B
bellard 已提交
2837 2838
        case OPC_JAL:
            blink = 31;
B
bellard 已提交
2839
            ctx->hflags |= MIPS_HFLAG_B;
N
Nathan Froyd 已提交
2840
            ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS)
2841 2842
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
T
ths 已提交
2843
            MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
B
bellard 已提交
2844 2845
            break;
        case OPC_JR:
B
bellard 已提交
2846
            ctx->hflags |= MIPS_HFLAG_BR;
N
Nathan Froyd 已提交
2847 2848
            if (insn_bytes == 4)
                ctx->hflags |= MIPS_HFLAG_BDS32;
B
bellard 已提交
2849 2850
            MIPS_DEBUG("jr %s", regnames[rs]);
            break;
N
Nathan Froyd 已提交
2851
        case OPC_JALRS:
B
bellard 已提交
2852
        case OPC_JALR:
2853
        case OPC_JALRC:
B
bellard 已提交
2854
            blink = rt;
B
bellard 已提交
2855
            ctx->hflags |= MIPS_HFLAG_BR;
N
Nathan Froyd 已提交
2856 2857 2858
            ctx->hflags |= (opc == OPC_JALRS
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
B
bellard 已提交
2859 2860 2861 2862 2863
            MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
            break;
        default:
            MIPS_INVAL("branch/jump");
            generate_exception(ctx, EXCP_RI);
2864
            goto out;
B
bellard 已提交
2865 2866 2867 2868
        }
    } else {
        switch (opc) {
        case OPC_BEQ:
2869
            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
2870
            MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx,
T
ths 已提交
2871
                       regnames[rs], regnames[rt], btgt);
B
bellard 已提交
2872 2873
            goto not_likely;
        case OPC_BEQL:
2874
            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
2875
            MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx,
T
ths 已提交
2876
                       regnames[rs], regnames[rt], btgt);
B
bellard 已提交
2877 2878
            goto likely;
        case OPC_BNE:
2879
            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
2880
            MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx,
T
ths 已提交
2881
                       regnames[rs], regnames[rt], btgt);
B
bellard 已提交
2882 2883
            goto not_likely;
        case OPC_BNEL:
2884
            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
2885
            MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
T
ths 已提交
2886
                       regnames[rs], regnames[rt], btgt);
B
bellard 已提交
2887 2888
            goto likely;
        case OPC_BGEZ:
2889
            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
T
ths 已提交
2890
            MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2891 2892
            goto not_likely;
        case OPC_BGEZL:
2893
            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
T
ths 已提交
2894
            MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2895
            goto likely;
2896
        case OPC_BGEZALS:
B
bellard 已提交
2897
        case OPC_BGEZAL:
2898 2899 2900
            ctx->hflags |= (opc == OPC_BGEZALS
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
2901
            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
T
ths 已提交
2902
            MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2903 2904 2905
            blink = 31;
            goto not_likely;
        case OPC_BGEZALL:
2906
            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
B
bellard 已提交
2907
            blink = 31;
T
ths 已提交
2908
            MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2909 2910
            goto likely;
        case OPC_BGTZ:
2911
            tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0);
T
ths 已提交
2912
            MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2913 2914
            goto not_likely;
        case OPC_BGTZL:
2915
            tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t0, 0);
T
ths 已提交
2916
            MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2917 2918
            goto likely;
        case OPC_BLEZ:
2919
            tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0);
T
ths 已提交
2920
            MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2921 2922
            goto not_likely;
        case OPC_BLEZL:
2923
            tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t0, 0);
T
ths 已提交
2924
            MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2925 2926
            goto likely;
        case OPC_BLTZ:
2927
            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
T
ths 已提交
2928
            MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2929 2930
            goto not_likely;
        case OPC_BLTZL:
2931
            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
T
ths 已提交
2932
            MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2933
            goto likely;
2934
        case OPC_BLTZALS:
B
bellard 已提交
2935
        case OPC_BLTZAL:
2936 2937 2938
            ctx->hflags |= (opc == OPC_BLTZALS
                            ? MIPS_HFLAG_BDS16
                            : MIPS_HFLAG_BDS32);
2939
            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
B
bellard 已提交
2940
            blink = 31;
T
ths 已提交
2941
            MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2942
        not_likely:
B
bellard 已提交
2943
            ctx->hflags |= MIPS_HFLAG_BC;
B
bellard 已提交
2944 2945
            break;
        case OPC_BLTZALL:
2946
            tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
B
bellard 已提交
2947
            blink = 31;
T
ths 已提交
2948
            MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btgt);
B
bellard 已提交
2949
        likely:
B
bellard 已提交
2950
            ctx->hflags |= MIPS_HFLAG_BL;
B
bellard 已提交
2951
            break;
T
ths 已提交
2952 2953 2954
        default:
            MIPS_INVAL("conditional branch/jump");
            generate_exception(ctx, EXCP_RI);
2955
            goto out;
B
bellard 已提交
2956 2957
        }
    }
2958
    MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
T
ths 已提交
2959
               blink, ctx->hflags, btgt);
2960

T
ths 已提交
2961
    ctx->btarget = btgt;
B
bellard 已提交
2962
    if (blink > 0) {
2963 2964 2965 2966 2967 2968 2969
        int post_delay = insn_bytes;
        int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);

        if (opc != OPC_JALRC)
            post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);

        tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
B
bellard 已提交
2970
    }
2971 2972

 out:
2973 2974
    if (insn_bytes == 2)
        ctx->hflags |= MIPS_HFLAG_B16;
2975 2976
    tcg_temp_free(t0);
    tcg_temp_free(t1);
B
bellard 已提交
2977 2978
}

2979 2980
/* special3 bitfield operations */
static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
2981
                        int rs, int lsb, int msb)
2982
{
P
pbrook 已提交
2983 2984
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
A
aurel32 已提交
2985
    target_ulong mask;
2986 2987

    gen_load_gpr(t1, rs);
2988 2989 2990 2991
    switch (opc) {
    case OPC_EXT:
        if (lsb + msb > 31)
            goto fail;
A
aurel32 已提交
2992 2993 2994 2995 2996 2997
        tcg_gen_shri_tl(t0, t1, lsb);
        if (msb != 31) {
            tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1);
        } else {
            tcg_gen_ext32s_tl(t0, t0);
        }
2998
        break;
T
ths 已提交
2999
#if defined(TARGET_MIPS64)
3000
    case OPC_DEXTM:
A
aurel32 已提交
3001 3002 3003 3004
        tcg_gen_shri_tl(t0, t1, lsb);
        if (msb != 31) {
            tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1);
        }
3005 3006
        break;
    case OPC_DEXTU:
A
aurel32 已提交
3007 3008
        tcg_gen_shri_tl(t0, t1, lsb + 32);
        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
3009 3010
        break;
    case OPC_DEXT:
A
aurel32 已提交
3011 3012
        tcg_gen_shri_tl(t0, t1, lsb);
        tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
3013
        break;
T
ths 已提交
3014
#endif
3015 3016 3017
    case OPC_INS:
        if (lsb > msb)
            goto fail;
A
aurel32 已提交
3018
        mask = ((msb - lsb + 1 < 32) ? ((1 << (msb - lsb + 1)) - 1) : ~0) << lsb;
3019
        gen_load_gpr(t0, rt);
A
aurel32 已提交
3020 3021 3022 3023 3024
        tcg_gen_andi_tl(t0, t0, ~mask);
        tcg_gen_shli_tl(t1, t1, lsb);
        tcg_gen_andi_tl(t1, t1, mask);
        tcg_gen_or_tl(t0, t0, t1);
        tcg_gen_ext32s_tl(t0, t0);
3025
        break;
T
ths 已提交
3026
#if defined(TARGET_MIPS64)
3027 3028 3029
    case OPC_DINSM:
        if (lsb > msb)
            goto fail;
A
aurel32 已提交
3030
        mask = ((msb - lsb + 1 + 32 < 64) ? ((1ULL << (msb - lsb + 1 + 32)) - 1) : ~0ULL) << lsb;
3031
        gen_load_gpr(t0, rt);
A
aurel32 已提交
3032 3033 3034 3035
        tcg_gen_andi_tl(t0, t0, ~mask);
        tcg_gen_shli_tl(t1, t1, lsb);
        tcg_gen_andi_tl(t1, t1, mask);
        tcg_gen_or_tl(t0, t0, t1);
3036 3037 3038 3039
        break;
    case OPC_DINSU:
        if (lsb > msb)
            goto fail;
3040
        mask = ((1ULL << (msb - lsb + 1)) - 1) << (lsb + 32);
3041
        gen_load_gpr(t0, rt);
A
aurel32 已提交
3042 3043 3044 3045
        tcg_gen_andi_tl(t0, t0, ~mask);
        tcg_gen_shli_tl(t1, t1, lsb + 32);
        tcg_gen_andi_tl(t1, t1, mask);
        tcg_gen_or_tl(t0, t0, t1);
3046 3047 3048 3049
        break;
    case OPC_DINS:
        if (lsb > msb)
            goto fail;
3050
        gen_load_gpr(t0, rt);
A
aurel32 已提交
3051 3052 3053 3054 3055 3056
        mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb;
        gen_load_gpr(t0, rt);
        tcg_gen_andi_tl(t0, t0, ~mask);
        tcg_gen_shli_tl(t1, t1, lsb);
        tcg_gen_andi_tl(t1, t1, mask);
        tcg_gen_or_tl(t0, t0, t1);
3057
        break;
T
ths 已提交
3058
#endif
3059 3060 3061 3062
    default:
fail:
        MIPS_INVAL("bitops");
        generate_exception(ctx, EXCP_RI);
3063 3064
        tcg_temp_free(t0);
        tcg_temp_free(t1);
3065 3066
        return;
    }
3067 3068 3069
    gen_store_gpr(t0, rt);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
3070 3071
}

3072 3073
static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd)
{
A
aurel32 已提交
3074
    TCGv t0;
3075

A
aurel32 已提交
3076 3077 3078 3079 3080 3081 3082 3083
    if (rd == 0) {
        /* If no destination, treat it as a NOP. */
        MIPS_DEBUG("NOP");
        return;
    }

    t0 = tcg_temp_new();
    gen_load_gpr(t0, rt);
3084 3085
    switch (op2) {
    case OPC_WSBH:
A
aurel32 已提交
3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096
        {
            TCGv t1 = tcg_temp_new();

            tcg_gen_shri_tl(t1, t0, 8);
            tcg_gen_andi_tl(t1, t1, 0x00FF00FF);
            tcg_gen_shli_tl(t0, t0, 8);
            tcg_gen_andi_tl(t0, t0, ~0x00FF00FF);
            tcg_gen_or_tl(t0, t0, t1);
            tcg_temp_free(t1);
            tcg_gen_ext32s_tl(cpu_gpr[rd], t0);
        }
3097 3098
        break;
    case OPC_SEB:
A
aurel32 已提交
3099
        tcg_gen_ext8s_tl(cpu_gpr[rd], t0);
3100 3101
        break;
    case OPC_SEH:
A
aurel32 已提交
3102
        tcg_gen_ext16s_tl(cpu_gpr[rd], t0);
3103 3104 3105
        break;
#if defined(TARGET_MIPS64)
    case OPC_DSBH:
A
aurel32 已提交
3106 3107 3108 3109 3110 3111 3112 3113 3114 3115
        {
            TCGv t1 = tcg_temp_new();

            tcg_gen_shri_tl(t1, t0, 8);
            tcg_gen_andi_tl(t1, t1, 0x00FF00FF00FF00FFULL);
            tcg_gen_shli_tl(t0, t0, 8);
            tcg_gen_andi_tl(t0, t0, ~0x00FF00FF00FF00FFULL);
            tcg_gen_or_tl(cpu_gpr[rd], t0, t1);
            tcg_temp_free(t1);
        }
3116 3117
        break;
    case OPC_DSHD:
A
aurel32 已提交
3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130
        {
            TCGv t1 = tcg_temp_new();

            tcg_gen_shri_tl(t1, t0, 16);
            tcg_gen_andi_tl(t1, t1, 0x0000FFFF0000FFFFULL);
            tcg_gen_shli_tl(t0, t0, 16);
            tcg_gen_andi_tl(t0, t0, ~0x0000FFFF0000FFFFULL);
            tcg_gen_or_tl(t0, t0, t1);
            tcg_gen_shri_tl(t1, t0, 32);
            tcg_gen_shli_tl(t0, t0, 32);
            tcg_gen_or_tl(cpu_gpr[rd], t0, t1);
            tcg_temp_free(t1);
        }
3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141
        break;
#endif
    default:
        MIPS_INVAL("bsfhl");
        generate_exception(ctx, EXCP_RI);
        tcg_temp_free(t0);
        return;
    }
    tcg_temp_free(t0);
}

3142
#ifndef CONFIG_USER_ONLY
T
ths 已提交
3143
/* CP0 (MMU and control) */
3144
static inline void gen_mfc0_load32 (TCGv arg, target_ulong off)
T
ths 已提交
3145
{
3146
    TCGv_i32 t0 = tcg_temp_new_i32();
T
ths 已提交
3147

3148 3149 3150
    tcg_gen_ld_i32(t0, cpu_env, off);
    tcg_gen_ext_i32_tl(arg, t0);
    tcg_temp_free_i32(t0);
T
ths 已提交
3151 3152
}

3153
static inline void gen_mfc0_load64 (TCGv arg, target_ulong off)
T
ths 已提交
3154
{
3155 3156
    tcg_gen_ld_tl(arg, cpu_env, off);
    tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3157 3158
}

3159
static inline void gen_mtc0_store32 (TCGv arg, target_ulong off)
3160
{
3161
    TCGv_i32 t0 = tcg_temp_new_i32();
3162

3163 3164 3165
    tcg_gen_trunc_tl_i32(t0, arg);
    tcg_gen_st_i32(t0, cpu_env, off);
    tcg_temp_free_i32(t0);
3166 3167
}

3168
static inline void gen_mtc0_store64 (TCGv arg, target_ulong off)
3169
{
3170 3171
    tcg_gen_ext32s_tl(arg, arg);
    tcg_gen_st_tl(arg, cpu_env, off);
3172 3173
}

3174
static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
3175
{
3176
    const char *rn = "invalid";
3177

3178 3179 3180
    if (sel != 0)
        check_insn(env, ctx, ISA_MIPS32);

3181 3182
    switch (reg) {
    case 0:
3183 3184
        switch (sel) {
        case 0:
3185
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
3186 3187 3188
            rn = "Index";
            break;
        case 1:
3189
            check_insn(env, ctx, ASE_MT);
3190
            gen_helper_mfc0_mvpcontrol(arg);
3191
            rn = "MVPControl";
3192
            break;
3193
        case 2:
3194
            check_insn(env, ctx, ASE_MT);
3195
            gen_helper_mfc0_mvpconf0(arg);
3196
            rn = "MVPConf0";
3197
            break;
3198
        case 3:
3199
            check_insn(env, ctx, ASE_MT);
3200
            gen_helper_mfc0_mvpconf1(arg);
3201
            rn = "MVPConf1";
3202
            break;
3203 3204 3205
        default:
            goto die;
        }
3206 3207
        break;
    case 1:
3208 3209
        switch (sel) {
        case 0:
3210
            gen_helper_mfc0_random(arg);
3211
            rn = "Random";
T
ths 已提交
3212
            break;
3213
        case 1:
3214
            check_insn(env, ctx, ASE_MT);
3215
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
3216
            rn = "VPEControl";
3217
            break;
3218
        case 2:
3219
            check_insn(env, ctx, ASE_MT);
3220
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
3221
            rn = "VPEConf0";
3222
            break;
3223
        case 3:
3224
            check_insn(env, ctx, ASE_MT);
3225
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
3226
            rn = "VPEConf1";
3227
            break;
3228
        case 4:
3229
            check_insn(env, ctx, ASE_MT);
3230
            gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask));
3231
            rn = "YQMask";
3232
            break;
3233
        case 5:
3234
            check_insn(env, ctx, ASE_MT);
3235
            gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule));
3236
            rn = "VPESchedule";
3237
            break;
3238
        case 6:
3239
            check_insn(env, ctx, ASE_MT);
3240
            gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack));
3241
            rn = "VPEScheFBack";
3242
            break;
3243
        case 7:
3244
            check_insn(env, ctx, ASE_MT);
3245
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
3246
            rn = "VPEOpt";
3247
            break;
3248 3249 3250
        default:
            goto die;
        }
3251 3252
        break;
    case 2:
3253 3254
        switch (sel) {
        case 0:
3255
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0));
3256
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3257 3258
            rn = "EntryLo0";
            break;
3259
        case 1:
3260
            check_insn(env, ctx, ASE_MT);
3261
            gen_helper_mfc0_tcstatus(arg);
T
ths 已提交
3262
            rn = "TCStatus";
3263
            break;
3264
        case 2:
3265
            check_insn(env, ctx, ASE_MT);
3266
            gen_helper_mfc0_tcbind(arg);
T
ths 已提交
3267
            rn = "TCBind";
3268
            break;
3269
        case 3:
3270
            check_insn(env, ctx, ASE_MT);
3271
            gen_helper_mfc0_tcrestart(arg);
T
ths 已提交
3272
            rn = "TCRestart";
3273
            break;
3274
        case 4:
3275
            check_insn(env, ctx, ASE_MT);
3276
            gen_helper_mfc0_tchalt(arg);
T
ths 已提交
3277
            rn = "TCHalt";
3278
            break;
3279
        case 5:
3280
            check_insn(env, ctx, ASE_MT);
3281
            gen_helper_mfc0_tccontext(arg);
T
ths 已提交
3282
            rn = "TCContext";
3283
            break;
3284
        case 6:
3285
            check_insn(env, ctx, ASE_MT);
3286
            gen_helper_mfc0_tcschedule(arg);
T
ths 已提交
3287
            rn = "TCSchedule";
3288
            break;
3289
        case 7:
3290
            check_insn(env, ctx, ASE_MT);
3291
            gen_helper_mfc0_tcschefback(arg);
T
ths 已提交
3292
            rn = "TCScheFBack";
3293
            break;
3294 3295 3296
        default:
            goto die;
        }
3297 3298
        break;
    case 3:
3299 3300
        switch (sel) {
        case 0:
3301
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1));
3302
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3303 3304
            rn = "EntryLo1";
            break;
3305 3306
        default:
            goto die;
3307
        }
3308 3309
        break;
    case 4:
3310 3311
        switch (sel) {
        case 0:
3312
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
3313
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3314 3315
            rn = "Context";
            break;
3316
        case 1:
3317
//            gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
T
ths 已提交
3318 3319
            rn = "ContextConfig";
//            break;
3320 3321
        default:
            goto die;
3322
        }
3323 3324
        break;
    case 5:
3325 3326
        switch (sel) {
        case 0:
3327
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
T
ths 已提交
3328 3329
            rn = "PageMask";
            break;
3330
        case 1:
3331
            check_insn(env, ctx, ISA_MIPS32R2);
3332
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
T
ths 已提交
3333 3334
            rn = "PageGrain";
            break;
3335 3336
        default:
            goto die;
3337
        }
3338 3339
        break;
    case 6:
3340 3341
        switch (sel) {
        case 0:
3342
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
T
ths 已提交
3343 3344
            rn = "Wired";
            break;
3345
        case 1:
3346
            check_insn(env, ctx, ISA_MIPS32R2);
3347
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
T
ths 已提交
3348
            rn = "SRSConf0";
3349
            break;
3350
        case 2:
3351
            check_insn(env, ctx, ISA_MIPS32R2);
3352
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
T
ths 已提交
3353
            rn = "SRSConf1";
3354
            break;
3355
        case 3:
3356
            check_insn(env, ctx, ISA_MIPS32R2);
3357
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
T
ths 已提交
3358
            rn = "SRSConf2";
3359
            break;
3360
        case 4:
3361
            check_insn(env, ctx, ISA_MIPS32R2);
3362
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
T
ths 已提交
3363
            rn = "SRSConf3";
3364
            break;
3365
        case 5:
3366
            check_insn(env, ctx, ISA_MIPS32R2);
3367
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
T
ths 已提交
3368
            rn = "SRSConf4";
3369
            break;
3370 3371
        default:
            goto die;
3372
        }
3373
        break;
3374
    case 7:
3375 3376
        switch (sel) {
        case 0:
3377
            check_insn(env, ctx, ISA_MIPS32R2);
3378
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
T
ths 已提交
3379 3380
            rn = "HWREna";
            break;
3381 3382
        default:
            goto die;
3383
        }
3384
        break;
3385
    case 8:
3386 3387
        switch (sel) {
        case 0:
3388
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
3389
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3390
            rn = "BadVAddr";
T
ths 已提交
3391
            break;
3392 3393 3394
        default:
            goto die;
       }
3395 3396
        break;
    case 9:
3397 3398
        switch (sel) {
        case 0:
P
pbrook 已提交
3399 3400 3401
            /* Mark as an IO operation because we read the time.  */
            if (use_icount)
                gen_io_start();
3402
            gen_helper_mfc0_count(arg);
P
pbrook 已提交
3403 3404 3405
            if (use_icount) {
                gen_io_end();
            }
3406 3407 3408
            /* Break the TB to be able to take timer interrupts immediately
               after reading count.  */
            ctx->bstate = BS_STOP;
T
ths 已提交
3409 3410 3411
            rn = "Count";
            break;
        /* 6,7 are implementation dependent */
3412 3413
        default:
            goto die;
T
ths 已提交
3414
        }
3415 3416
        break;
    case 10:
3417 3418
        switch (sel) {
        case 0:
3419
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
3420
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3421 3422
            rn = "EntryHi";
            break;
3423 3424
        default:
            goto die;
3425
        }
3426 3427
        break;
    case 11:
3428 3429
        switch (sel) {
        case 0:
3430
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
T
ths 已提交
3431 3432 3433
            rn = "Compare";
            break;
        /* 6,7 are implementation dependent */
3434 3435
        default:
            goto die;
T
ths 已提交
3436
        }
3437 3438
        break;
    case 12:
3439 3440
        switch (sel) {
        case 0:
3441
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
T
ths 已提交
3442 3443
            rn = "Status";
            break;
3444
        case 1:
3445
            check_insn(env, ctx, ISA_MIPS32R2);
3446
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
T
ths 已提交
3447 3448
            rn = "IntCtl";
            break;
3449
        case 2:
3450
            check_insn(env, ctx, ISA_MIPS32R2);
3451
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
T
ths 已提交
3452 3453
            rn = "SRSCtl";
            break;
3454
        case 3:
3455
            check_insn(env, ctx, ISA_MIPS32R2);
3456
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
T
ths 已提交
3457
            rn = "SRSMap";
3458
            break;
3459 3460 3461
        default:
            goto die;
       }
3462 3463
        break;
    case 13:
3464 3465
        switch (sel) {
        case 0:
3466
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
T
ths 已提交
3467 3468
            rn = "Cause";
            break;
3469 3470 3471
        default:
            goto die;
       }
3472 3473
        break;
    case 14:
3474 3475
        switch (sel) {
        case 0:
3476
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
3477
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3478 3479
            rn = "EPC";
            break;
3480 3481
        default:
            goto die;
3482
        }
3483 3484
        break;
    case 15:
3485 3486
        switch (sel) {
        case 0:
3487
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
T
ths 已提交
3488 3489
            rn = "PRid";
            break;
3490
        case 1:
3491
            check_insn(env, ctx, ISA_MIPS32R2);
3492
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase));
T
ths 已提交
3493 3494
            rn = "EBase";
            break;
3495 3496 3497
        default:
            goto die;
       }
3498 3499 3500 3501
        break;
    case 16:
        switch (sel) {
        case 0:
3502
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
3503 3504 3505
            rn = "Config";
            break;
        case 1:
3506
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
3507 3508
            rn = "Config1";
            break;
3509
        case 2:
3510
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
3511 3512 3513
            rn = "Config2";
            break;
        case 3:
3514
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
3515 3516
            rn = "Config3";
            break;
3517 3518 3519
        /* 4,5 are reserved */
        /* 6,7 are implementation dependent */
        case 6:
3520
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
3521 3522 3523
            rn = "Config6";
            break;
        case 7:
3524
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
3525 3526
            rn = "Config7";
            break;
3527 3528 3529 3530 3531
        default:
            goto die;
        }
        break;
    case 17:
3532 3533
        switch (sel) {
        case 0:
3534
            gen_helper_mfc0_lladdr(arg);
T
ths 已提交
3535 3536
            rn = "LLAddr";
            break;
3537 3538 3539
        default:
            goto die;
        }
3540 3541
        break;
    case 18:
3542
        switch (sel) {
3543
        case 0 ... 7:
3544
            gen_helper_1i(mfc0_watchlo, arg, sel);
T
ths 已提交
3545 3546
            rn = "WatchLo";
            break;
3547 3548 3549
        default:
            goto die;
        }
3550 3551
        break;
    case 19:
3552
        switch (sel) {
3553
        case 0 ...7:
3554
            gen_helper_1i(mfc0_watchhi, arg, sel);
T
ths 已提交
3555 3556
            rn = "WatchHi";
            break;
3557 3558 3559
        default:
            goto die;
        }
3560
        break;
3561
    case 20:
3562 3563
        switch (sel) {
        case 0:
3564
#if defined(TARGET_MIPS64)
3565
            check_insn(env, ctx, ISA_MIPS3);
3566
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
3567
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3568 3569
            rn = "XContext";
            break;
T
ths 已提交
3570
#endif
3571 3572 3573
        default:
            goto die;
        }
3574 3575
        break;
    case 21:
3576 3577 3578
       /* Officially reserved, but sel 0 is used for R1x000 framemask */
        switch (sel) {
        case 0:
3579
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask));
T
ths 已提交
3580 3581
            rn = "Framemask";
            break;
3582 3583 3584
        default:
            goto die;
        }
3585 3586
        break;
    case 22:
3587
        tcg_gen_movi_tl(arg, 0); /* unimplemented */
T
ths 已提交
3588 3589
        rn = "'Diagnostic"; /* implementation dependent */
        break;
3590
    case 23:
3591 3592
        switch (sel) {
        case 0:
3593
            gen_helper_mfc0_debug(arg); /* EJTAG support */
T
ths 已提交
3594 3595
            rn = "Debug";
            break;
3596
        case 1:
3597
//            gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */
T
ths 已提交
3598 3599
            rn = "TraceControl";
//            break;
3600
        case 2:
3601
//            gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */
T
ths 已提交
3602 3603
            rn = "TraceControl2";
//            break;
3604
        case 3:
3605
//            gen_helper_mfc0_usertracedata(arg); /* PDtrace support */
T
ths 已提交
3606 3607
            rn = "UserTraceData";
//            break;
3608
        case 4:
3609
//            gen_helper_mfc0_tracebpc(arg); /* PDtrace support */
T
ths 已提交
3610 3611
            rn = "TraceBPC";
//            break;
3612 3613 3614
        default:
            goto die;
        }
3615 3616
        break;
    case 24:
3617 3618
        switch (sel) {
        case 0:
T
ths 已提交
3619
            /* EJTAG support */
3620
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
3621
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3622 3623
            rn = "DEPC";
            break;
3624 3625 3626
        default:
            goto die;
        }
3627
        break;
3628
    case 25:
3629 3630
        switch (sel) {
        case 0:
3631
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
T
ths 已提交
3632
            rn = "Performance0";
3633 3634
            break;
        case 1:
3635
//            gen_helper_mfc0_performance1(arg);
T
ths 已提交
3636 3637
            rn = "Performance1";
//            break;
3638
        case 2:
3639
//            gen_helper_mfc0_performance2(arg);
T
ths 已提交
3640 3641
            rn = "Performance2";
//            break;
3642
        case 3:
3643
//            gen_helper_mfc0_performance3(arg);
T
ths 已提交
3644 3645
            rn = "Performance3";
//            break;
3646
        case 4:
3647
//            gen_helper_mfc0_performance4(arg);
T
ths 已提交
3648 3649
            rn = "Performance4";
//            break;
3650
        case 5:
3651
//            gen_helper_mfc0_performance5(arg);
T
ths 已提交
3652 3653
            rn = "Performance5";
//            break;
3654
        case 6:
3655
//            gen_helper_mfc0_performance6(arg);
T
ths 已提交
3656 3657
            rn = "Performance6";
//            break;
3658
        case 7:
3659
//            gen_helper_mfc0_performance7(arg);
T
ths 已提交
3660 3661
            rn = "Performance7";
//            break;
3662 3663 3664
        default:
            goto die;
        }
3665 3666
        break;
    case 26:
3667
        tcg_gen_movi_tl(arg, 0); /* unimplemented */
3668 3669
        rn = "ECC";
        break;
3670
    case 27:
3671 3672
        switch (sel) {
        case 0 ... 3:
3673
            tcg_gen_movi_tl(arg, 0); /* unimplemented */
T
ths 已提交
3674 3675
            rn = "CacheErr";
            break;
3676 3677 3678
        default:
            goto die;
        }
3679
        break;
3680 3681 3682
    case 28:
        switch (sel) {
        case 0:
3683 3684 3685
        case 2:
        case 4:
        case 6:
3686
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo));
3687 3688 3689
            rn = "TagLo";
            break;
        case 1:
3690 3691 3692
        case 3:
        case 5:
        case 7:
3693
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
3694 3695 3696 3697 3698 3699
            rn = "DataLo";
            break;
        default:
            goto die;
        }
        break;
3700
    case 29:
3701 3702 3703 3704 3705
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
3706
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
3707 3708 3709 3710 3711 3712
            rn = "TagHi";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
3713
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
3714 3715 3716 3717 3718
            rn = "DataHi";
            break;
        default:
            goto die;
        }
3719
        break;
3720
    case 30:
3721 3722
        switch (sel) {
        case 0:
3723
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
3724
            tcg_gen_ext32s_tl(arg, arg);
T
ths 已提交
3725 3726
            rn = "ErrorEPC";
            break;
3727 3728 3729
        default:
            goto die;
        }
3730 3731
        break;
    case 31:
3732 3733
        switch (sel) {
        case 0:
T
ths 已提交
3734
            /* EJTAG support */
3735
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
T
ths 已提交
3736 3737
            rn = "DESAVE";
            break;
3738 3739 3740
        default:
            goto die;
        }
3741 3742 3743 3744
        break;
    default:
       goto die;
    }
B
Blue Swirl 已提交
3745
    (void)rn; /* avoid a compiler warning */
3746
    LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
3747 3748 3749
    return;

die:
3750
    LOG_DISAS("mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
3751 3752 3753
    generate_exception(ctx, EXCP_RI);
}

3754
static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
3755
{
3756 3757
    const char *rn = "invalid";

3758 3759 3760
    if (sel != 0)
        check_insn(env, ctx, ISA_MIPS32);

P
pbrook 已提交
3761 3762 3763
    if (use_icount)
        gen_io_start();

3764 3765
    switch (reg) {
    case 0:
3766 3767
        switch (sel) {
        case 0:
3768
            gen_helper_mtc0_index(arg);
3769 3770 3771
            rn = "Index";
            break;
        case 1:
3772
            check_insn(env, ctx, ASE_MT);
3773
            gen_helper_mtc0_mvpcontrol(arg);
3774
            rn = "MVPControl";
3775
            break;
3776
        case 2:
3777
            check_insn(env, ctx, ASE_MT);
3778
            /* ignored */
3779
            rn = "MVPConf0";
3780
            break;
3781
        case 3:
3782
            check_insn(env, ctx, ASE_MT);
3783
            /* ignored */
3784
            rn = "MVPConf1";
3785
            break;
3786 3787 3788
        default:
            goto die;
        }
3789 3790
        break;
    case 1:
3791 3792
        switch (sel) {
        case 0:
T
ths 已提交
3793
            /* ignored */
3794
            rn = "Random";
T
ths 已提交
3795
            break;
3796
        case 1:
3797
            check_insn(env, ctx, ASE_MT);
3798
            gen_helper_mtc0_vpecontrol(arg);
3799
            rn = "VPEControl";
3800
            break;
3801
        case 2:
3802
            check_insn(env, ctx, ASE_MT);
3803
            gen_helper_mtc0_vpeconf0(arg);
3804
            rn = "VPEConf0";
3805
            break;
3806
        case 3:
3807
            check_insn(env, ctx, ASE_MT);
3808
            gen_helper_mtc0_vpeconf1(arg);
3809
            rn = "VPEConf1";
3810
            break;
3811
        case 4:
3812
            check_insn(env, ctx, ASE_MT);
3813
            gen_helper_mtc0_yqmask(arg);
3814
            rn = "YQMask";
3815
            break;
3816
        case 5:
3817
            check_insn(env, ctx, ASE_MT);
3818
            gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPESchedule));
3819
            rn = "VPESchedule";
3820
            break;
3821
        case 6:
3822
            check_insn(env, ctx, ASE_MT);
3823
            gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack));
3824
            rn = "VPEScheFBack";
3825
            break;
3826
        case 7:
3827
            check_insn(env, ctx, ASE_MT);
3828
            gen_helper_mtc0_vpeopt(arg);
3829
            rn = "VPEOpt";
3830
            break;
3831 3832 3833
        default:
            goto die;
        }
3834 3835
        break;
    case 2:
3836 3837
        switch (sel) {
        case 0:
3838
            gen_helper_mtc0_entrylo0(arg);
T
ths 已提交
3839 3840
            rn = "EntryLo0";
            break;
3841
        case 1:
3842
            check_insn(env, ctx, ASE_MT);
3843
            gen_helper_mtc0_tcstatus(arg);
T
ths 已提交
3844
            rn = "TCStatus";
3845
            break;
3846
        case 2:
3847
            check_insn(env, ctx, ASE_MT);
3848
            gen_helper_mtc0_tcbind(arg);
T
ths 已提交
3849
            rn = "TCBind";
3850
            break;
3851
        case 3:
3852
            check_insn(env, ctx, ASE_MT);
3853
            gen_helper_mtc0_tcrestart(arg);
T
ths 已提交
3854
            rn = "TCRestart";
3855
            break;
3856
        case 4:
3857
            check_insn(env, ctx, ASE_MT);
3858
            gen_helper_mtc0_tchalt(arg);
T
ths 已提交
3859
            rn = "TCHalt";
3860
            break;
3861
        case 5:
3862
            check_insn(env, ctx, ASE_MT);
3863
            gen_helper_mtc0_tccontext(arg);
T
ths 已提交
3864
            rn = "TCContext";
3865
            break;
3866
        case 6:
3867
            check_insn(env, ctx, ASE_MT);
3868
            gen_helper_mtc0_tcschedule(arg);
T
ths 已提交
3869
            rn = "TCSchedule";
3870
            break;
3871
        case 7:
3872
            check_insn(env, ctx, ASE_MT);
3873
            gen_helper_mtc0_tcschefback(arg);
T
ths 已提交
3874
            rn = "TCScheFBack";
3875
            break;
3876 3877 3878
        default:
            goto die;
        }
3879 3880
        break;
    case 3:
3881 3882
        switch (sel) {
        case 0:
3883
            gen_helper_mtc0_entrylo1(arg);
T
ths 已提交
3884 3885
            rn = "EntryLo1";
            break;
3886 3887
        default:
            goto die;
T
ths 已提交
3888
        }
3889 3890
        break;
    case 4:
3891 3892
        switch (sel) {
        case 0:
3893
            gen_helper_mtc0_context(arg);
T
ths 已提交
3894 3895
            rn = "Context";
            break;
3896
        case 1:
3897
//            gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */
T
ths 已提交
3898 3899
            rn = "ContextConfig";
//            break;
3900 3901
        default:
            goto die;
T
ths 已提交
3902
        }
3903 3904
        break;
    case 5:
3905 3906
        switch (sel) {
        case 0:
3907
            gen_helper_mtc0_pagemask(arg);
T
ths 已提交
3908 3909
            rn = "PageMask";
            break;
3910
        case 1:
3911
            check_insn(env, ctx, ISA_MIPS32R2);
3912
            gen_helper_mtc0_pagegrain(arg);
T
ths 已提交
3913 3914
            rn = "PageGrain";
            break;
3915 3916
        default:
            goto die;
T
ths 已提交
3917
        }
3918 3919
        break;
    case 6:
3920 3921
        switch (sel) {
        case 0:
3922
            gen_helper_mtc0_wired(arg);
T
ths 已提交
3923 3924
            rn = "Wired";
            break;
3925
        case 1:
3926
            check_insn(env, ctx, ISA_MIPS32R2);
3927
            gen_helper_mtc0_srsconf0(arg);
T
ths 已提交
3928
            rn = "SRSConf0";
3929
            break;
3930
        case 2:
3931
            check_insn(env, ctx, ISA_MIPS32R2);
3932
            gen_helper_mtc0_srsconf1(arg);
T
ths 已提交
3933
            rn = "SRSConf1";
3934
            break;
3935
        case 3:
3936
            check_insn(env, ctx, ISA_MIPS32R2);
3937
            gen_helper_mtc0_srsconf2(arg);
T
ths 已提交
3938
            rn = "SRSConf2";
3939
            break;
3940
        case 4:
3941
            check_insn(env, ctx, ISA_MIPS32R2);
3942
            gen_helper_mtc0_srsconf3(arg);
T
ths 已提交
3943
            rn = "SRSConf3";
3944
            break;
3945
        case 5:
3946
            check_insn(env, ctx, ISA_MIPS32R2);
3947
            gen_helper_mtc0_srsconf4(arg);
T
ths 已提交
3948
            rn = "SRSConf4";
3949
            break;
3950 3951
        default:
            goto die;
T
ths 已提交
3952
        }
3953 3954
        break;
    case 7:
3955 3956
        switch (sel) {
        case 0:
3957
            check_insn(env, ctx, ISA_MIPS32R2);
3958
            gen_helper_mtc0_hwrena(arg);
T
ths 已提交
3959 3960
            rn = "HWREna";
            break;
3961 3962
        default:
            goto die;
T
ths 已提交
3963
        }
3964 3965
        break;
    case 8:
3966
        /* ignored */
T
ths 已提交
3967
        rn = "BadVAddr";
3968 3969
        break;
    case 9:
3970 3971
        switch (sel) {
        case 0:
3972
            gen_helper_mtc0_count(arg);
T
ths 已提交
3973 3974
            rn = "Count";
            break;
T
ths 已提交
3975
        /* 6,7 are implementation dependent */
3976 3977
        default:
            goto die;
T
ths 已提交
3978
        }
3979 3980
        break;
    case 10:
3981 3982
        switch (sel) {
        case 0:
3983
            gen_helper_mtc0_entryhi(arg);
T
ths 已提交
3984 3985
            rn = "EntryHi";
            break;
3986 3987
        default:
            goto die;
T
ths 已提交
3988
        }
3989 3990
        break;
    case 11:
3991 3992
        switch (sel) {
        case 0:
3993
            gen_helper_mtc0_compare(arg);
T
ths 已提交
3994 3995 3996
            rn = "Compare";
            break;
        /* 6,7 are implementation dependent */
3997 3998
        default:
            goto die;
T
ths 已提交
3999
        }
4000 4001
        break;
    case 12:
4002 4003
        switch (sel) {
        case 0:
A
aurel32 已提交
4004
            save_cpu_state(ctx, 1);
4005
            gen_helper_mtc0_status(arg);
4006 4007 4008
            /* BS_STOP isn't good enough here, hflags may have changed. */
            gen_save_pc(ctx->pc + 4);
            ctx->bstate = BS_EXCP;
T
ths 已提交
4009 4010
            rn = "Status";
            break;
4011
        case 1:
4012
            check_insn(env, ctx, ISA_MIPS32R2);
4013
            gen_helper_mtc0_intctl(arg);
4014 4015
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4016 4017
            rn = "IntCtl";
            break;
4018
        case 2:
4019
            check_insn(env, ctx, ISA_MIPS32R2);
4020
            gen_helper_mtc0_srsctl(arg);
4021 4022
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4023 4024
            rn = "SRSCtl";
            break;
4025
        case 3:
4026
            check_insn(env, ctx, ISA_MIPS32R2);
4027
            gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
4028 4029
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4030
            rn = "SRSMap";
4031
            break;
4032 4033
        default:
            goto die;
T
ths 已提交
4034
        }
4035 4036
        break;
    case 13:
4037 4038
        switch (sel) {
        case 0:
A
aurel32 已提交
4039
            save_cpu_state(ctx, 1);
4040
            gen_helper_mtc0_cause(arg);
T
ths 已提交
4041 4042
            rn = "Cause";
            break;
4043 4044
        default:
            goto die;
T
ths 已提交
4045
        }
4046 4047
        break;
    case 14:
4048 4049
        switch (sel) {
        case 0:
4050
            gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_EPC));
T
ths 已提交
4051 4052
            rn = "EPC";
            break;
4053 4054
        default:
            goto die;
T
ths 已提交
4055
        }
4056 4057
        break;
    case 15:
4058 4059
        switch (sel) {
        case 0:
T
ths 已提交
4060 4061 4062
            /* ignored */
            rn = "PRid";
            break;
4063
        case 1:
4064
            check_insn(env, ctx, ISA_MIPS32R2);
4065
            gen_helper_mtc0_ebase(arg);
T
ths 已提交
4066 4067
            rn = "EBase";
            break;
4068 4069
        default:
            goto die;
4070
        }
4071 4072 4073 4074
        break;
    case 16:
        switch (sel) {
        case 0:
4075
            gen_helper_mtc0_config0(arg);
4076
            rn = "Config";
T
ths 已提交
4077 4078
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
4079 4080
            break;
        case 1:
4081
            /* ignored, read only */
4082 4083 4084
            rn = "Config1";
            break;
        case 2:
4085
            gen_helper_mtc0_config2(arg);
4086
            rn = "Config2";
T
ths 已提交
4087 4088
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
4089
            break;
4090
        case 3:
4091
            /* ignored, read only */
4092 4093
            rn = "Config3";
            break;
4094 4095 4096 4097 4098 4099 4100 4101 4102 4103
        /* 4,5 are reserved */
        /* 6,7 are implementation dependent */
        case 6:
            /* ignored */
            rn = "Config6";
            break;
        case 7:
            /* ignored */
            rn = "Config7";
            break;
4104 4105 4106 4107 4108 4109
        default:
            rn = "Invalid config selector";
            goto die;
        }
        break;
    case 17:
4110 4111
        switch (sel) {
        case 0:
4112
            gen_helper_mtc0_lladdr(arg);
T
ths 已提交
4113 4114
            rn = "LLAddr";
            break;
4115 4116 4117
        default:
            goto die;
        }
4118 4119
        break;
    case 18:
4120
        switch (sel) {
4121
        case 0 ... 7:
4122
            gen_helper_1i(mtc0_watchlo, arg, sel);
T
ths 已提交
4123 4124
            rn = "WatchLo";
            break;
4125 4126 4127
        default:
            goto die;
        }
4128 4129
        break;
    case 19:
4130
        switch (sel) {
4131
        case 0 ... 7:
4132
            gen_helper_1i(mtc0_watchhi, arg, sel);
T
ths 已提交
4133 4134
            rn = "WatchHi";
            break;
4135 4136 4137
        default:
            goto die;
        }
4138 4139
        break;
    case 20:
4140 4141
        switch (sel) {
        case 0:
4142
#if defined(TARGET_MIPS64)
4143
            check_insn(env, ctx, ISA_MIPS3);
4144
            gen_helper_mtc0_xcontext(arg);
T
ths 已提交
4145 4146
            rn = "XContext";
            break;
T
ths 已提交
4147
#endif
4148 4149 4150
        default:
            goto die;
        }
4151 4152
        break;
    case 21:
4153 4154 4155
       /* Officially reserved, but sel 0 is used for R1x000 framemask */
        switch (sel) {
        case 0:
4156
            gen_helper_mtc0_framemask(arg);
T
ths 已提交
4157 4158
            rn = "Framemask";
            break;
4159 4160 4161 4162
        default:
            goto die;
        }
        break;
4163
    case 22:
4164 4165
        /* ignored */
        rn = "Diagnostic"; /* implementation dependent */
T
ths 已提交
4166
        break;
4167
    case 23:
4168 4169
        switch (sel) {
        case 0:
4170
            gen_helper_mtc0_debug(arg); /* EJTAG support */
4171 4172 4173
            /* BS_STOP isn't good enough here, hflags may have changed. */
            gen_save_pc(ctx->pc + 4);
            ctx->bstate = BS_EXCP;
T
ths 已提交
4174 4175
            rn = "Debug";
            break;
4176
        case 1:
4177
//            gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */
T
ths 已提交
4178
            rn = "TraceControl";
4179 4180
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4181
//            break;
4182
        case 2:
4183
//            gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */
T
ths 已提交
4184
            rn = "TraceControl2";
4185 4186
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4187
//            break;
4188
        case 3:
4189 4190
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
4191
//            gen_helper_mtc0_usertracedata(arg); /* PDtrace support */
T
ths 已提交
4192
            rn = "UserTraceData";
4193 4194
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4195
//            break;
4196
        case 4:
4197
//            gen_helper_mtc0_tracebpc(arg); /* PDtrace support */
4198 4199
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
4200 4201
            rn = "TraceBPC";
//            break;
4202 4203 4204
        default:
            goto die;
        }
4205 4206
        break;
    case 24:
4207 4208
        switch (sel) {
        case 0:
4209
            /* EJTAG support */
4210
            gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_DEPC));
T
ths 已提交
4211 4212
            rn = "DEPC";
            break;
4213 4214 4215
        default:
            goto die;
        }
4216 4217
        break;
    case 25:
4218 4219
        switch (sel) {
        case 0:
4220
            gen_helper_mtc0_performance0(arg);
T
ths 已提交
4221 4222
            rn = "Performance0";
            break;
4223
        case 1:
4224
//            gen_helper_mtc0_performance1(arg);
T
ths 已提交
4225 4226
            rn = "Performance1";
//            break;
4227
        case 2:
4228
//            gen_helper_mtc0_performance2(arg);
T
ths 已提交
4229 4230
            rn = "Performance2";
//            break;
4231
        case 3:
4232
//            gen_helper_mtc0_performance3(arg);
T
ths 已提交
4233 4234
            rn = "Performance3";
//            break;
4235
        case 4:
4236
//            gen_helper_mtc0_performance4(arg);
T
ths 已提交
4237 4238
            rn = "Performance4";
//            break;
4239
        case 5:
4240
//            gen_helper_mtc0_performance5(arg);
T
ths 已提交
4241 4242
            rn = "Performance5";
//            break;
4243
        case 6:
4244
//            gen_helper_mtc0_performance6(arg);
T
ths 已提交
4245 4246
            rn = "Performance6";
//            break;
4247
        case 7:
4248
//            gen_helper_mtc0_performance7(arg);
T
ths 已提交
4249 4250
            rn = "Performance7";
//            break;
4251 4252 4253
        default:
            goto die;
        }
4254 4255
       break;
    case 26:
T
ths 已提交
4256
        /* ignored */
4257
        rn = "ECC";
T
ths 已提交
4258
        break;
4259
    case 27:
4260 4261
        switch (sel) {
        case 0 ... 3:
T
ths 已提交
4262 4263 4264
            /* ignored */
            rn = "CacheErr";
            break;
4265 4266 4267
        default:
            goto die;
        }
4268 4269 4270 4271
       break;
    case 28:
        switch (sel) {
        case 0:
4272 4273 4274
        case 2:
        case 4:
        case 6:
4275
            gen_helper_mtc0_taglo(arg);
4276 4277
            rn = "TagLo";
            break;
4278 4279 4280 4281
        case 1:
        case 3:
        case 5:
        case 7:
4282
            gen_helper_mtc0_datalo(arg);
4283 4284
            rn = "DataLo";
            break;
4285 4286 4287 4288 4289
        default:
            goto die;
        }
        break;
    case 29:
4290 4291 4292 4293 4294
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
4295
            gen_helper_mtc0_taghi(arg);
4296 4297 4298 4299 4300 4301
            rn = "TagHi";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
4302
            gen_helper_mtc0_datahi(arg);
4303 4304 4305 4306 4307 4308
            rn = "DataHi";
            break;
        default:
            rn = "invalid sel";
            goto die;
        }
4309 4310
       break;
    case 30:
4311 4312
        switch (sel) {
        case 0:
4313
            gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_ErrorEPC));
T
ths 已提交
4314 4315
            rn = "ErrorEPC";
            break;
4316 4317 4318
        default:
            goto die;
        }
4319 4320
        break;
    case 31:
4321 4322
        switch (sel) {
        case 0:
4323
            /* EJTAG support */
4324
            gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
T
ths 已提交
4325 4326
            rn = "DESAVE";
            break;
4327 4328 4329
        default:
            goto die;
        }
T
ths 已提交
4330 4331
        /* Stop translation as we may have switched the execution mode */
        ctx->bstate = BS_STOP;
4332 4333 4334 4335
        break;
    default:
       goto die;
    }
B
Blue Swirl 已提交
4336
    (void)rn; /* avoid a compiler warning */
4337
    LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
T
ths 已提交
4338
    /* For simplicity assume that all writes can cause interrupts.  */
P
pbrook 已提交
4339 4340 4341 4342
    if (use_icount) {
        gen_io_end();
        ctx->bstate = BS_STOP;
    }
4343 4344 4345
    return;

die:
4346
    LOG_DISAS("mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
4347 4348 4349
    generate_exception(ctx, EXCP_RI);
}

4350
#if defined(TARGET_MIPS64)
4351
static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
T
ths 已提交
4352 4353 4354
{
    const char *rn = "invalid";

4355 4356 4357
    if (sel != 0)
        check_insn(env, ctx, ISA_MIPS64);

T
ths 已提交
4358 4359 4360 4361
    switch (reg) {
    case 0:
        switch (sel) {
        case 0:
4362
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
T
ths 已提交
4363 4364 4365
            rn = "Index";
            break;
        case 1:
4366
            check_insn(env, ctx, ASE_MT);
4367
            gen_helper_mfc0_mvpcontrol(arg);
T
ths 已提交
4368
            rn = "MVPControl";
4369
            break;
T
ths 已提交
4370
        case 2:
4371
            check_insn(env, ctx, ASE_MT);
4372
            gen_helper_mfc0_mvpconf0(arg);
T
ths 已提交
4373
            rn = "MVPConf0";
4374
            break;
T
ths 已提交
4375
        case 3:
4376
            check_insn(env, ctx, ASE_MT);
4377
            gen_helper_mfc0_mvpconf1(arg);
T
ths 已提交
4378
            rn = "MVPConf1";
4379
            break;
T
ths 已提交
4380 4381 4382 4383 4384 4385 4386
        default:
            goto die;
        }
        break;
    case 1:
        switch (sel) {
        case 0:
4387
            gen_helper_mfc0_random(arg);
T
ths 已提交
4388
            rn = "Random";
T
ths 已提交
4389
            break;
T
ths 已提交
4390
        case 1:
4391
            check_insn(env, ctx, ASE_MT);
4392
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
T
ths 已提交
4393
            rn = "VPEControl";
4394
            break;
T
ths 已提交
4395
        case 2:
4396
            check_insn(env, ctx, ASE_MT);
4397
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
T
ths 已提交
4398
            rn = "VPEConf0";
4399
            break;
T
ths 已提交
4400
        case 3:
4401
            check_insn(env, ctx, ASE_MT);
4402
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
T
ths 已提交
4403
            rn = "VPEConf1";
4404
            break;
T
ths 已提交
4405
        case 4:
4406
            check_insn(env, ctx, ASE_MT);
4407
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask));
T
ths 已提交
4408
            rn = "YQMask";
4409
            break;
T
ths 已提交
4410
        case 5:
4411
            check_insn(env, ctx, ASE_MT);
4412
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
T
ths 已提交
4413
            rn = "VPESchedule";
4414
            break;
T
ths 已提交
4415
        case 6:
4416
            check_insn(env, ctx, ASE_MT);
4417
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
T
ths 已提交
4418
            rn = "VPEScheFBack";
4419
            break;
T
ths 已提交
4420
        case 7:
4421
            check_insn(env, ctx, ASE_MT);
4422
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
T
ths 已提交
4423
            rn = "VPEOpt";
4424
            break;
T
ths 已提交
4425 4426 4427 4428 4429 4430 4431
        default:
            goto die;
        }
        break;
    case 2:
        switch (sel) {
        case 0:
4432
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0));
T
ths 已提交
4433 4434
            rn = "EntryLo0";
            break;
T
ths 已提交
4435
        case 1:
4436
            check_insn(env, ctx, ASE_MT);
4437
            gen_helper_mfc0_tcstatus(arg);
T
ths 已提交
4438
            rn = "TCStatus";
4439
            break;
T
ths 已提交
4440
        case 2:
4441
            check_insn(env, ctx, ASE_MT);
4442
            gen_helper_mfc0_tcbind(arg);
T
ths 已提交
4443
            rn = "TCBind";
4444
            break;
T
ths 已提交
4445
        case 3:
4446
            check_insn(env, ctx, ASE_MT);
4447
            gen_helper_dmfc0_tcrestart(arg);
T
ths 已提交
4448
            rn = "TCRestart";
4449
            break;
T
ths 已提交
4450
        case 4:
4451
            check_insn(env, ctx, ASE_MT);
4452
            gen_helper_dmfc0_tchalt(arg);
T
ths 已提交
4453
            rn = "TCHalt";
4454
            break;
T
ths 已提交
4455
        case 5:
4456
            check_insn(env, ctx, ASE_MT);
4457
            gen_helper_dmfc0_tccontext(arg);
T
ths 已提交
4458
            rn = "TCContext";
4459
            break;
T
ths 已提交
4460
        case 6:
4461
            check_insn(env, ctx, ASE_MT);
4462
            gen_helper_dmfc0_tcschedule(arg);
T
ths 已提交
4463
            rn = "TCSchedule";
4464
            break;
T
ths 已提交
4465
        case 7:
4466
            check_insn(env, ctx, ASE_MT);
4467
            gen_helper_dmfc0_tcschefback(arg);
T
ths 已提交
4468
            rn = "TCScheFBack";
4469
            break;
T
ths 已提交
4470 4471 4472 4473 4474 4475 4476
        default:
            goto die;
        }
        break;
    case 3:
        switch (sel) {
        case 0:
4477
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1));
T
ths 已提交
4478 4479
            rn = "EntryLo1";
            break;
T
ths 已提交
4480 4481
        default:
            goto die;
4482
        }
T
ths 已提交
4483 4484 4485 4486
        break;
    case 4:
        switch (sel) {
        case 0:
4487
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
T
ths 已提交
4488 4489
            rn = "Context";
            break;
T
ths 已提交
4490
        case 1:
4491
//            gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
T
ths 已提交
4492 4493
            rn = "ContextConfig";
//            break;
T
ths 已提交
4494 4495
        default:
            goto die;
T
ths 已提交
4496
        }
T
ths 已提交
4497 4498 4499 4500
        break;
    case 5:
        switch (sel) {
        case 0:
4501
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
T
ths 已提交
4502 4503
            rn = "PageMask";
            break;
T
ths 已提交
4504
        case 1:
4505
            check_insn(env, ctx, ISA_MIPS32R2);
4506
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
T
ths 已提交
4507 4508
            rn = "PageGrain";
            break;
T
ths 已提交
4509 4510
        default:
            goto die;
T
ths 已提交
4511
        }
T
ths 已提交
4512 4513 4514 4515
        break;
    case 6:
        switch (sel) {
        case 0:
4516
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
T
ths 已提交
4517 4518
            rn = "Wired";
            break;
T
ths 已提交
4519
        case 1:
4520
            check_insn(env, ctx, ISA_MIPS32R2);
4521
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
T
ths 已提交
4522
            rn = "SRSConf0";
4523
            break;
T
ths 已提交
4524
        case 2:
4525
            check_insn(env, ctx, ISA_MIPS32R2);
4526
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
T
ths 已提交
4527
            rn = "SRSConf1";
4528
            break;
T
ths 已提交
4529
        case 3:
4530
            check_insn(env, ctx, ISA_MIPS32R2);
4531
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
T
ths 已提交
4532
            rn = "SRSConf2";
4533
            break;
T
ths 已提交
4534
        case 4:
4535
            check_insn(env, ctx, ISA_MIPS32R2);
4536
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
T
ths 已提交
4537
            rn = "SRSConf3";
4538
            break;
T
ths 已提交
4539
        case 5:
4540
            check_insn(env, ctx, ISA_MIPS32R2);
4541
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
T
ths 已提交
4542
            rn = "SRSConf4";
4543
            break;
T
ths 已提交
4544 4545
        default:
            goto die;
T
ths 已提交
4546
        }
T
ths 已提交
4547 4548 4549 4550
        break;
    case 7:
        switch (sel) {
        case 0:
4551
            check_insn(env, ctx, ISA_MIPS32R2);
4552
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
T
ths 已提交
4553 4554
            rn = "HWREna";
            break;
T
ths 已提交
4555 4556
        default:
            goto die;
T
ths 已提交
4557
        }
T
ths 已提交
4558 4559 4560 4561
        break;
    case 8:
        switch (sel) {
        case 0:
4562
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
T
ths 已提交
4563
            rn = "BadVAddr";
T
ths 已提交
4564
            break;
T
ths 已提交
4565 4566
        default:
            goto die;
T
ths 已提交
4567
        }
T
ths 已提交
4568 4569 4570 4571
        break;
    case 9:
        switch (sel) {
        case 0:
P
pbrook 已提交
4572 4573 4574
            /* Mark as an IO operation because we read the time.  */
            if (use_icount)
                gen_io_start();
4575
            gen_helper_mfc0_count(arg);
P
pbrook 已提交
4576 4577 4578
            if (use_icount) {
                gen_io_end();
            }
4579 4580 4581
            /* Break the TB to be able to take timer interrupts immediately
               after reading count.  */
            ctx->bstate = BS_STOP;
T
ths 已提交
4582 4583 4584
            rn = "Count";
            break;
        /* 6,7 are implementation dependent */
T
ths 已提交
4585 4586
        default:
            goto die;
T
ths 已提交
4587
        }
T
ths 已提交
4588 4589 4590 4591
        break;
    case 10:
        switch (sel) {
        case 0:
4592
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
T
ths 已提交
4593 4594
            rn = "EntryHi";
            break;
T
ths 已提交
4595 4596
        default:
            goto die;
T
ths 已提交
4597
        }
T
ths 已提交
4598 4599 4600 4601
        break;
    case 11:
        switch (sel) {
        case 0:
4602
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
T
ths 已提交
4603 4604
            rn = "Compare";
            break;
T
ths 已提交
4605
        /* 6,7 are implementation dependent */
T
ths 已提交
4606 4607
        default:
            goto die;
T
ths 已提交
4608
        }
T
ths 已提交
4609 4610 4611 4612
        break;
    case 12:
        switch (sel) {
        case 0:
4613
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
T
ths 已提交
4614 4615
            rn = "Status";
            break;
T
ths 已提交
4616
        case 1:
4617
            check_insn(env, ctx, ISA_MIPS32R2);
4618
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
T
ths 已提交
4619 4620
            rn = "IntCtl";
            break;
T
ths 已提交
4621
        case 2:
4622
            check_insn(env, ctx, ISA_MIPS32R2);
4623
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
T
ths 已提交
4624 4625
            rn = "SRSCtl";
            break;
T
ths 已提交
4626
        case 3:
4627
            check_insn(env, ctx, ISA_MIPS32R2);
4628
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
T
ths 已提交
4629 4630
            rn = "SRSMap";
            break;
T
ths 已提交
4631 4632
        default:
            goto die;
T
ths 已提交
4633
        }
T
ths 已提交
4634 4635 4636 4637
        break;
    case 13:
        switch (sel) {
        case 0:
4638
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
T
ths 已提交
4639 4640
            rn = "Cause";
            break;
T
ths 已提交
4641 4642
        default:
            goto die;
T
ths 已提交
4643
        }
T
ths 已提交
4644 4645 4646 4647
        break;
    case 14:
        switch (sel) {
        case 0:
4648
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
T
ths 已提交
4649 4650
            rn = "EPC";
            break;
T
ths 已提交
4651 4652
        default:
            goto die;
T
ths 已提交
4653
        }
T
ths 已提交
4654 4655 4656 4657
        break;
    case 15:
        switch (sel) {
        case 0:
4658
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
T
ths 已提交
4659 4660
            rn = "PRid";
            break;
T
ths 已提交
4661
        case 1:
4662
            check_insn(env, ctx, ISA_MIPS32R2);
4663
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase));
T
ths 已提交
4664 4665
            rn = "EBase";
            break;
T
ths 已提交
4666 4667
        default:
            goto die;
T
ths 已提交
4668
        }
T
ths 已提交
4669 4670 4671 4672
        break;
    case 16:
        switch (sel) {
        case 0:
4673
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
T
ths 已提交
4674 4675 4676
            rn = "Config";
            break;
        case 1:
4677
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
T
ths 已提交
4678 4679 4680
            rn = "Config1";
            break;
        case 2:
4681
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
T
ths 已提交
4682 4683 4684
            rn = "Config2";
            break;
        case 3:
4685
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
T
ths 已提交
4686 4687 4688
            rn = "Config3";
            break;
       /* 6,7 are implementation dependent */
T
ths 已提交
4689
        case 6:
4690
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
T
ths 已提交
4691 4692 4693
            rn = "Config6";
            break;
        case 7:
4694
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
T
ths 已提交
4695 4696
            rn = "Config7";
            break;
T
ths 已提交
4697 4698 4699 4700 4701 4702 4703
        default:
            goto die;
        }
        break;
    case 17:
        switch (sel) {
        case 0:
4704
            gen_helper_dmfc0_lladdr(arg);
T
ths 已提交
4705 4706
            rn = "LLAddr";
            break;
T
ths 已提交
4707 4708 4709 4710 4711 4712
        default:
            goto die;
        }
        break;
    case 18:
        switch (sel) {
4713
        case 0 ... 7:
4714
            gen_helper_1i(dmfc0_watchlo, arg, sel);
T
ths 已提交
4715 4716
            rn = "WatchLo";
            break;
T
ths 已提交
4717 4718 4719 4720 4721 4722
        default:
            goto die;
        }
        break;
    case 19:
        switch (sel) {
4723
        case 0 ... 7:
4724
            gen_helper_1i(mfc0_watchhi, arg, sel);
T
ths 已提交
4725 4726
            rn = "WatchHi";
            break;
T
ths 已提交
4727 4728 4729 4730 4731 4732 4733
        default:
            goto die;
        }
        break;
    case 20:
        switch (sel) {
        case 0:
4734
            check_insn(env, ctx, ISA_MIPS3);
4735
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
T
ths 已提交
4736 4737
            rn = "XContext";
            break;
T
ths 已提交
4738 4739 4740 4741 4742 4743 4744 4745
        default:
            goto die;
        }
        break;
    case 21:
       /* Officially reserved, but sel 0 is used for R1x000 framemask */
        switch (sel) {
        case 0:
4746
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask));
T
ths 已提交
4747 4748
            rn = "Framemask";
            break;
T
ths 已提交
4749 4750 4751 4752 4753
        default:
            goto die;
        }
        break;
    case 22:
4754
        tcg_gen_movi_tl(arg, 0); /* unimplemented */
T
ths 已提交
4755 4756
        rn = "'Diagnostic"; /* implementation dependent */
        break;
T
ths 已提交
4757 4758 4759
    case 23:
        switch (sel) {
        case 0:
4760
            gen_helper_mfc0_debug(arg); /* EJTAG support */
T
ths 已提交
4761 4762
            rn = "Debug";
            break;
T
ths 已提交
4763
        case 1:
4764
//            gen_helper_dmfc0_tracecontrol(arg); /* PDtrace support */
T
ths 已提交
4765 4766
            rn = "TraceControl";
//            break;
T
ths 已提交
4767
        case 2:
4768
//            gen_helper_dmfc0_tracecontrol2(arg); /* PDtrace support */
T
ths 已提交
4769 4770
            rn = "TraceControl2";
//            break;
T
ths 已提交
4771
        case 3:
4772
//            gen_helper_dmfc0_usertracedata(arg); /* PDtrace support */
T
ths 已提交
4773 4774
            rn = "UserTraceData";
//            break;
T
ths 已提交
4775
        case 4:
4776
//            gen_helper_dmfc0_tracebpc(arg); /* PDtrace support */
T
ths 已提交
4777 4778
            rn = "TraceBPC";
//            break;
T
ths 已提交
4779 4780 4781 4782 4783 4784 4785
        default:
            goto die;
        }
        break;
    case 24:
        switch (sel) {
        case 0:
T
ths 已提交
4786
            /* EJTAG support */
4787
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
T
ths 已提交
4788 4789
            rn = "DEPC";
            break;
T
ths 已提交
4790 4791 4792 4793 4794 4795 4796
        default:
            goto die;
        }
        break;
    case 25:
        switch (sel) {
        case 0:
4797
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
T
ths 已提交
4798
            rn = "Performance0";
T
ths 已提交
4799 4800
            break;
        case 1:
4801
//            gen_helper_dmfc0_performance1(arg);
T
ths 已提交
4802 4803
            rn = "Performance1";
//            break;
T
ths 已提交
4804
        case 2:
4805
//            gen_helper_dmfc0_performance2(arg);
T
ths 已提交
4806 4807
            rn = "Performance2";
//            break;
T
ths 已提交
4808
        case 3:
4809
//            gen_helper_dmfc0_performance3(arg);
T
ths 已提交
4810 4811
            rn = "Performance3";
//            break;
T
ths 已提交
4812
        case 4:
4813
//            gen_helper_dmfc0_performance4(arg);
T
ths 已提交
4814 4815
            rn = "Performance4";
//            break;
T
ths 已提交
4816
        case 5:
4817
//            gen_helper_dmfc0_performance5(arg);
T
ths 已提交
4818 4819
            rn = "Performance5";
//            break;
T
ths 已提交
4820
        case 6:
4821
//            gen_helper_dmfc0_performance6(arg);
T
ths 已提交
4822 4823
            rn = "Performance6";
//            break;
T
ths 已提交
4824
        case 7:
4825
//            gen_helper_dmfc0_performance7(arg);
T
ths 已提交
4826 4827
            rn = "Performance7";
//            break;
T
ths 已提交
4828 4829 4830 4831 4832
        default:
            goto die;
        }
        break;
    case 26:
4833
        tcg_gen_movi_tl(arg, 0); /* unimplemented */
4834 4835
        rn = "ECC";
        break;
T
ths 已提交
4836 4837 4838 4839
    case 27:
        switch (sel) {
        /* ignored */
        case 0 ... 3:
4840
            tcg_gen_movi_tl(arg, 0); /* unimplemented */
T
ths 已提交
4841 4842
            rn = "CacheErr";
            break;
T
ths 已提交
4843 4844 4845 4846 4847 4848 4849 4850 4851 4852
        default:
            goto die;
        }
        break;
    case 28:
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
4853
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo));
T
ths 已提交
4854 4855 4856 4857 4858 4859
            rn = "TagLo";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
4860
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
T
ths 已提交
4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872
            rn = "DataLo";
            break;
        default:
            goto die;
        }
        break;
    case 29:
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
4873
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
T
ths 已提交
4874 4875 4876 4877 4878 4879
            rn = "TagHi";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
4880
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
T
ths 已提交
4881 4882 4883 4884 4885 4886 4887 4888 4889
            rn = "DataHi";
            break;
        default:
            goto die;
        }
        break;
    case 30:
        switch (sel) {
        case 0:
4890
            tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
T
ths 已提交
4891 4892
            rn = "ErrorEPC";
            break;
T
ths 已提交
4893 4894 4895 4896 4897 4898 4899
        default:
            goto die;
        }
        break;
    case 31:
        switch (sel) {
        case 0:
T
ths 已提交
4900
            /* EJTAG support */
4901
            gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
T
ths 已提交
4902 4903
            rn = "DESAVE";
            break;
T
ths 已提交
4904 4905 4906 4907 4908
        default:
            goto die;
        }
        break;
    default:
T
ths 已提交
4909
        goto die;
T
ths 已提交
4910
    }
B
Blue Swirl 已提交
4911
    (void)rn; /* avoid a compiler warning */
4912
    LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
T
ths 已提交
4913 4914 4915
    return;

die:
4916
    LOG_DISAS("dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
T
ths 已提交
4917 4918 4919
    generate_exception(ctx, EXCP_RI);
}

4920
static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel)
T
ths 已提交
4921 4922 4923
{
    const char *rn = "invalid";

4924 4925 4926
    if (sel != 0)
        check_insn(env, ctx, ISA_MIPS64);

P
pbrook 已提交
4927 4928 4929
    if (use_icount)
        gen_io_start();

T
ths 已提交
4930 4931 4932 4933
    switch (reg) {
    case 0:
        switch (sel) {
        case 0:
4934
            gen_helper_mtc0_index(arg);
T
ths 已提交
4935 4936 4937
            rn = "Index";
            break;
        case 1:
4938
            check_insn(env, ctx, ASE_MT);
4939
            gen_helper_mtc0_mvpcontrol(arg);
T
ths 已提交
4940
            rn = "MVPControl";
4941
            break;
T
ths 已提交
4942
        case 2:
4943
            check_insn(env, ctx, ASE_MT);
4944
            /* ignored */
T
ths 已提交
4945
            rn = "MVPConf0";
4946
            break;
T
ths 已提交
4947
        case 3:
4948
            check_insn(env, ctx, ASE_MT);
4949
            /* ignored */
T
ths 已提交
4950
            rn = "MVPConf1";
4951
            break;
T
ths 已提交
4952 4953 4954 4955 4956 4957 4958
        default:
            goto die;
        }
        break;
    case 1:
        switch (sel) {
        case 0:
T
ths 已提交
4959
            /* ignored */
T
ths 已提交
4960
            rn = "Random";
T
ths 已提交
4961
            break;
T
ths 已提交
4962
        case 1:
4963
            check_insn(env, ctx, ASE_MT);
4964
            gen_helper_mtc0_vpecontrol(arg);
T
ths 已提交
4965
            rn = "VPEControl";
4966
            break;
T
ths 已提交
4967
        case 2:
4968
            check_insn(env, ctx, ASE_MT);
4969
            gen_helper_mtc0_vpeconf0(arg);
T
ths 已提交
4970
            rn = "VPEConf0";
4971
            break;
T
ths 已提交
4972
        case 3:
4973
            check_insn(env, ctx, ASE_MT);
4974
            gen_helper_mtc0_vpeconf1(arg);
T
ths 已提交
4975
            rn = "VPEConf1";
4976
            break;
T
ths 已提交
4977
        case 4:
4978
            check_insn(env, ctx, ASE_MT);
4979
            gen_helper_mtc0_yqmask(arg);
T
ths 已提交
4980
            rn = "YQMask";
4981
            break;
T
ths 已提交
4982
        case 5:
4983
            check_insn(env, ctx, ASE_MT);
4984
            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
T
ths 已提交
4985
            rn = "VPESchedule";
4986
            break;
T
ths 已提交
4987
        case 6:
4988
            check_insn(env, ctx, ASE_MT);
4989
            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
T
ths 已提交
4990
            rn = "VPEScheFBack";
4991
            break;
T
ths 已提交
4992
        case 7:
4993
            check_insn(env, ctx, ASE_MT);
4994
            gen_helper_mtc0_vpeopt(arg);
T
ths 已提交
4995
            rn = "VPEOpt";
4996
            break;
T
ths 已提交
4997 4998 4999 5000 5001 5002 5003
        default:
            goto die;
        }
        break;
    case 2:
        switch (sel) {
        case 0:
5004
            gen_helper_mtc0_entrylo0(arg);
T
ths 已提交
5005 5006
            rn = "EntryLo0";
            break;
T
ths 已提交
5007
        case 1:
5008
            check_insn(env, ctx, ASE_MT);
5009
            gen_helper_mtc0_tcstatus(arg);
T
ths 已提交
5010
            rn = "TCStatus";
5011
            break;
T
ths 已提交
5012
        case 2:
5013
            check_insn(env, ctx, ASE_MT);
5014
            gen_helper_mtc0_tcbind(arg);
T
ths 已提交
5015
            rn = "TCBind";
5016
            break;
T
ths 已提交
5017
        case 3:
5018
            check_insn(env, ctx, ASE_MT);
5019
            gen_helper_mtc0_tcrestart(arg);
T
ths 已提交
5020
            rn = "TCRestart";
5021
            break;
T
ths 已提交
5022
        case 4:
5023
            check_insn(env, ctx, ASE_MT);
5024
            gen_helper_mtc0_tchalt(arg);
T
ths 已提交
5025
            rn = "TCHalt";
5026
            break;
T
ths 已提交
5027
        case 5:
5028
            check_insn(env, ctx, ASE_MT);
5029
            gen_helper_mtc0_tccontext(arg);
T
ths 已提交
5030
            rn = "TCContext";
5031
            break;
T
ths 已提交
5032
        case 6:
5033
            check_insn(env, ctx, ASE_MT);
5034
            gen_helper_mtc0_tcschedule(arg);
T
ths 已提交
5035
            rn = "TCSchedule";
5036
            break;
T
ths 已提交
5037
        case 7:
5038
            check_insn(env, ctx, ASE_MT);
5039
            gen_helper_mtc0_tcschefback(arg);
T
ths 已提交
5040
            rn = "TCScheFBack";
5041
            break;
T
ths 已提交
5042 5043 5044 5045 5046 5047 5048
        default:
            goto die;
        }
        break;
    case 3:
        switch (sel) {
        case 0:
5049
            gen_helper_mtc0_entrylo1(arg);
T
ths 已提交
5050 5051
            rn = "EntryLo1";
            break;
T
ths 已提交
5052 5053
        default:
            goto die;
T
ths 已提交
5054
        }
T
ths 已提交
5055 5056 5057 5058
        break;
    case 4:
        switch (sel) {
        case 0:
5059
            gen_helper_mtc0_context(arg);
T
ths 已提交
5060 5061
            rn = "Context";
            break;
T
ths 已提交
5062
        case 1:
5063
//           gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */
T
ths 已提交
5064 5065
            rn = "ContextConfig";
//           break;
T
ths 已提交
5066 5067
        default:
            goto die;
T
ths 已提交
5068
        }
T
ths 已提交
5069 5070 5071 5072
        break;
    case 5:
        switch (sel) {
        case 0:
5073
            gen_helper_mtc0_pagemask(arg);
T
ths 已提交
5074 5075
            rn = "PageMask";
            break;
T
ths 已提交
5076
        case 1:
5077
            check_insn(env, ctx, ISA_MIPS32R2);
5078
            gen_helper_mtc0_pagegrain(arg);
T
ths 已提交
5079 5080
            rn = "PageGrain";
            break;
T
ths 已提交
5081 5082
        default:
            goto die;
T
ths 已提交
5083
        }
T
ths 已提交
5084 5085 5086 5087
        break;
    case 6:
        switch (sel) {
        case 0:
5088
            gen_helper_mtc0_wired(arg);
T
ths 已提交
5089 5090
            rn = "Wired";
            break;
T
ths 已提交
5091
        case 1:
5092
            check_insn(env, ctx, ISA_MIPS32R2);
5093
            gen_helper_mtc0_srsconf0(arg);
T
ths 已提交
5094
            rn = "SRSConf0";
5095
            break;
T
ths 已提交
5096
        case 2:
5097
            check_insn(env, ctx, ISA_MIPS32R2);
5098
            gen_helper_mtc0_srsconf1(arg);
T
ths 已提交
5099
            rn = "SRSConf1";
5100
            break;
T
ths 已提交
5101
        case 3:
5102
            check_insn(env, ctx, ISA_MIPS32R2);
5103
            gen_helper_mtc0_srsconf2(arg);
T
ths 已提交
5104
            rn = "SRSConf2";
5105
            break;
T
ths 已提交
5106
        case 4:
5107
            check_insn(env, ctx, ISA_MIPS32R2);
5108
            gen_helper_mtc0_srsconf3(arg);
T
ths 已提交
5109
            rn = "SRSConf3";
5110
            break;
T
ths 已提交
5111
        case 5:
5112
            check_insn(env, ctx, ISA_MIPS32R2);
5113
            gen_helper_mtc0_srsconf4(arg);
T
ths 已提交
5114
            rn = "SRSConf4";
5115
            break;
T
ths 已提交
5116 5117
        default:
            goto die;
T
ths 已提交
5118
        }
T
ths 已提交
5119 5120 5121 5122
        break;
    case 7:
        switch (sel) {
        case 0:
5123
            check_insn(env, ctx, ISA_MIPS32R2);
5124
            gen_helper_mtc0_hwrena(arg);
T
ths 已提交
5125 5126
            rn = "HWREna";
            break;
T
ths 已提交
5127 5128
        default:
            goto die;
T
ths 已提交
5129
        }
T
ths 已提交
5130 5131 5132
        break;
    case 8:
        /* ignored */
T
ths 已提交
5133
        rn = "BadVAddr";
T
ths 已提交
5134 5135 5136 5137
        break;
    case 9:
        switch (sel) {
        case 0:
5138
            gen_helper_mtc0_count(arg);
T
ths 已提交
5139 5140
            rn = "Count";
            break;
T
ths 已提交
5141
        /* 6,7 are implementation dependent */
T
ths 已提交
5142 5143
        default:
            goto die;
T
ths 已提交
5144 5145 5146
        }
        /* Stop translation as we may have switched the execution mode */
        ctx->bstate = BS_STOP;
T
ths 已提交
5147 5148 5149 5150
        break;
    case 10:
        switch (sel) {
        case 0:
5151
            gen_helper_mtc0_entryhi(arg);
T
ths 已提交
5152 5153
            rn = "EntryHi";
            break;
T
ths 已提交
5154 5155
        default:
            goto die;
T
ths 已提交
5156
        }
T
ths 已提交
5157 5158 5159 5160
        break;
    case 11:
        switch (sel) {
        case 0:
5161
            gen_helper_mtc0_compare(arg);
T
ths 已提交
5162 5163
            rn = "Compare";
            break;
T
ths 已提交
5164
        /* 6,7 are implementation dependent */
T
ths 已提交
5165 5166
        default:
            goto die;
T
ths 已提交
5167
        }
5168 5169
        /* Stop translation as we may have switched the execution mode */
        ctx->bstate = BS_STOP;
T
ths 已提交
5170 5171 5172 5173
        break;
    case 12:
        switch (sel) {
        case 0:
A
aurel32 已提交
5174
            save_cpu_state(ctx, 1);
5175
            gen_helper_mtc0_status(arg);
5176 5177 5178
            /* BS_STOP isn't good enough here, hflags may have changed. */
            gen_save_pc(ctx->pc + 4);
            ctx->bstate = BS_EXCP;
T
ths 已提交
5179 5180
            rn = "Status";
            break;
T
ths 已提交
5181
        case 1:
5182
            check_insn(env, ctx, ISA_MIPS32R2);
5183
            gen_helper_mtc0_intctl(arg);
5184 5185
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5186 5187
            rn = "IntCtl";
            break;
T
ths 已提交
5188
        case 2:
5189
            check_insn(env, ctx, ISA_MIPS32R2);
5190
            gen_helper_mtc0_srsctl(arg);
5191 5192
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5193 5194
            rn = "SRSCtl";
            break;
T
ths 已提交
5195
        case 3:
5196
            check_insn(env, ctx, ISA_MIPS32R2);
5197
            gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
5198 5199
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5200 5201 5202
            rn = "SRSMap";
            break;
        default:
T
ths 已提交
5203
            goto die;
T
ths 已提交
5204
        }
T
ths 已提交
5205 5206 5207 5208
        break;
    case 13:
        switch (sel) {
        case 0:
A
aurel32 已提交
5209
            save_cpu_state(ctx, 1);
5210 5211 5212 5213 5214
            /* Mark as an IO operation because we may trigger a software
               interrupt.  */
            if (use_icount) {
                gen_io_start();
            }
5215
            gen_helper_mtc0_cause(arg);
5216 5217 5218 5219 5220
            if (use_icount) {
                gen_io_end();
            }
            /* Stop translation as we may have triggered an intetrupt */
            ctx->bstate = BS_STOP;
T
ths 已提交
5221 5222
            rn = "Cause";
            break;
T
ths 已提交
5223 5224
        default:
            goto die;
T
ths 已提交
5225
        }
T
ths 已提交
5226 5227 5228 5229
        break;
    case 14:
        switch (sel) {
        case 0:
5230
            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
T
ths 已提交
5231 5232
            rn = "EPC";
            break;
T
ths 已提交
5233 5234
        default:
            goto die;
T
ths 已提交
5235
        }
T
ths 已提交
5236 5237 5238 5239
        break;
    case 15:
        switch (sel) {
        case 0:
T
ths 已提交
5240 5241 5242
            /* ignored */
            rn = "PRid";
            break;
T
ths 已提交
5243
        case 1:
5244
            check_insn(env, ctx, ISA_MIPS32R2);
5245
            gen_helper_mtc0_ebase(arg);
T
ths 已提交
5246 5247
            rn = "EBase";
            break;
T
ths 已提交
5248 5249
        default:
            goto die;
T
ths 已提交
5250
        }
T
ths 已提交
5251 5252 5253 5254
        break;
    case 16:
        switch (sel) {
        case 0:
5255
            gen_helper_mtc0_config0(arg);
T
ths 已提交
5256
            rn = "Config";
T
ths 已提交
5257 5258
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5259 5260
            break;
        case 1:
A
aurel32 已提交
5261
            /* ignored, read only */
T
ths 已提交
5262 5263 5264
            rn = "Config1";
            break;
        case 2:
5265
            gen_helper_mtc0_config2(arg);
T
ths 已提交
5266
            rn = "Config2";
T
ths 已提交
5267 5268
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5269 5270
            break;
        case 3:
T
ths 已提交
5271
            /* ignored */
T
ths 已提交
5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282
            rn = "Config3";
            break;
        /* 6,7 are implementation dependent */
        default:
            rn = "Invalid config selector";
            goto die;
        }
        break;
    case 17:
        switch (sel) {
        case 0:
5283
            gen_helper_mtc0_lladdr(arg);
T
ths 已提交
5284 5285
            rn = "LLAddr";
            break;
T
ths 已提交
5286 5287 5288 5289 5290 5291
        default:
            goto die;
        }
        break;
    case 18:
        switch (sel) {
5292
        case 0 ... 7:
5293
            gen_helper_1i(mtc0_watchlo, arg, sel);
T
ths 已提交
5294 5295
            rn = "WatchLo";
            break;
T
ths 已提交
5296 5297 5298 5299 5300 5301
        default:
            goto die;
        }
        break;
    case 19:
        switch (sel) {
5302
        case 0 ... 7:
5303
            gen_helper_1i(mtc0_watchhi, arg, sel);
T
ths 已提交
5304 5305
            rn = "WatchHi";
            break;
T
ths 已提交
5306 5307 5308 5309 5310 5311 5312
        default:
            goto die;
        }
        break;
    case 20:
        switch (sel) {
        case 0:
5313
            check_insn(env, ctx, ISA_MIPS3);
5314
            gen_helper_mtc0_xcontext(arg);
T
ths 已提交
5315 5316
            rn = "XContext";
            break;
T
ths 已提交
5317 5318 5319 5320 5321 5322 5323 5324
        default:
            goto die;
        }
        break;
    case 21:
       /* Officially reserved, but sel 0 is used for R1x000 framemask */
        switch (sel) {
        case 0:
5325
            gen_helper_mtc0_framemask(arg);
T
ths 已提交
5326 5327
            rn = "Framemask";
            break;
T
ths 已提交
5328 5329 5330 5331 5332 5333 5334
        default:
            goto die;
        }
        break;
    case 22:
        /* ignored */
        rn = "Diagnostic"; /* implementation dependent */
T
ths 已提交
5335
        break;
T
ths 已提交
5336 5337 5338
    case 23:
        switch (sel) {
        case 0:
5339
            gen_helper_mtc0_debug(arg); /* EJTAG support */
5340 5341 5342
            /* BS_STOP isn't good enough here, hflags may have changed. */
            gen_save_pc(ctx->pc + 4);
            ctx->bstate = BS_EXCP;
T
ths 已提交
5343 5344
            rn = "Debug";
            break;
T
ths 已提交
5345
        case 1:
5346
//            gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */
5347 5348
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5349 5350
            rn = "TraceControl";
//            break;
T
ths 已提交
5351
        case 2:
5352
//            gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */
5353 5354
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5355 5356
            rn = "TraceControl2";
//            break;
T
ths 已提交
5357
        case 3:
5358
//            gen_helper_mtc0_usertracedata(arg); /* PDtrace support */
5359 5360
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5361 5362
            rn = "UserTraceData";
//            break;
T
ths 已提交
5363
        case 4:
5364
//            gen_helper_mtc0_tracebpc(arg); /* PDtrace support */
5365 5366
            /* Stop translation as we may have switched the execution mode */
            ctx->bstate = BS_STOP;
T
ths 已提交
5367 5368
            rn = "TraceBPC";
//            break;
T
ths 已提交
5369 5370 5371 5372 5373 5374 5375
        default:
            goto die;
        }
        break;
    case 24:
        switch (sel) {
        case 0:
5376
            /* EJTAG support */
5377
            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
T
ths 已提交
5378 5379
            rn = "DEPC";
            break;
T
ths 已提交
5380 5381 5382 5383 5384 5385 5386
        default:
            goto die;
        }
        break;
    case 25:
        switch (sel) {
        case 0:
5387
            gen_helper_mtc0_performance0(arg);
T
ths 已提交
5388 5389
            rn = "Performance0";
            break;
T
ths 已提交
5390
        case 1:
5391
//            gen_helper_mtc0_performance1(arg);
T
ths 已提交
5392 5393
            rn = "Performance1";
//            break;
T
ths 已提交
5394
        case 2:
5395
//            gen_helper_mtc0_performance2(arg);
T
ths 已提交
5396 5397
            rn = "Performance2";
//            break;
T
ths 已提交
5398
        case 3:
5399
//            gen_helper_mtc0_performance3(arg);
T
ths 已提交
5400 5401
            rn = "Performance3";
//            break;
T
ths 已提交
5402
        case 4:
5403
//            gen_helper_mtc0_performance4(arg);
T
ths 已提交
5404 5405
            rn = "Performance4";
//            break;
T
ths 已提交
5406
        case 5:
5407
//            gen_helper_mtc0_performance5(arg);
T
ths 已提交
5408 5409
            rn = "Performance5";
//            break;
T
ths 已提交
5410
        case 6:
5411
//            gen_helper_mtc0_performance6(arg);
T
ths 已提交
5412 5413
            rn = "Performance6";
//            break;
T
ths 已提交
5414
        case 7:
5415
//            gen_helper_mtc0_performance7(arg);
T
ths 已提交
5416 5417
            rn = "Performance7";
//            break;
T
ths 已提交
5418 5419 5420
        default:
            goto die;
        }
T
ths 已提交
5421
        break;
T
ths 已提交
5422
    case 26:
T
ths 已提交
5423
        /* ignored */
T
ths 已提交
5424
        rn = "ECC";
T
ths 已提交
5425
        break;
T
ths 已提交
5426 5427 5428
    case 27:
        switch (sel) {
        case 0 ... 3:
T
ths 已提交
5429 5430 5431
            /* ignored */
            rn = "CacheErr";
            break;
T
ths 已提交
5432 5433 5434
        default:
            goto die;
        }
T
ths 已提交
5435
        break;
T
ths 已提交
5436 5437 5438 5439 5440 5441
    case 28:
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
5442
            gen_helper_mtc0_taglo(arg);
T
ths 已提交
5443 5444 5445 5446 5447 5448
            rn = "TagLo";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
5449
            gen_helper_mtc0_datalo(arg);
T
ths 已提交
5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461
            rn = "DataLo";
            break;
        default:
            goto die;
        }
        break;
    case 29:
        switch (sel) {
        case 0:
        case 2:
        case 4:
        case 6:
5462
            gen_helper_mtc0_taghi(arg);
T
ths 已提交
5463 5464 5465 5466 5467 5468
            rn = "TagHi";
            break;
        case 1:
        case 3:
        case 5:
        case 7:
5469
            gen_helper_mtc0_datahi(arg);
T
ths 已提交
5470 5471 5472 5473 5474 5475
            rn = "DataHi";
            break;
        default:
            rn = "invalid sel";
            goto die;
        }
T
ths 已提交
5476
        break;
T
ths 已提交
5477 5478 5479
    case 30:
        switch (sel) {
        case 0:
5480
            tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
T
ths 已提交
5481 5482
            rn = "ErrorEPC";
            break;
T
ths 已提交
5483 5484 5485 5486 5487 5488 5489
        default:
            goto die;
        }
        break;
    case 31:
        switch (sel) {
        case 0:
5490
            /* EJTAG support */
5491
            gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
T
ths 已提交
5492 5493
            rn = "DESAVE";
            break;
T
ths 已提交
5494 5495 5496
        default:
            goto die;
        }
T
ths 已提交
5497 5498
        /* Stop translation as we may have switched the execution mode */
        ctx->bstate = BS_STOP;
T
ths 已提交
5499 5500
        break;
    default:
T
ths 已提交
5501
        goto die;
T
ths 已提交
5502
    }
B
Blue Swirl 已提交
5503
    (void)rn; /* avoid a compiler warning */
5504
    LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
T
ths 已提交
5505
    /* For simplicity assume that all writes can cause interrupts.  */
P
pbrook 已提交
5506 5507 5508 5509
    if (use_icount) {
        gen_io_end();
        ctx->bstate = BS_STOP;
    }
T
ths 已提交
5510 5511 5512
    return;

die:
5513
    LOG_DISAS("dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
T
ths 已提交
5514 5515
    generate_exception(ctx, EXCP_RI);
}
5516
#endif /* TARGET_MIPS64 */
T
ths 已提交
5517

5518
static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd,
5519 5520 5521
                     int u, int sel, int h)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
P
pbrook 已提交
5522
    TCGv t0 = tcg_temp_local_new();
5523 5524

    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
5525 5526
        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
5527
        tcg_gen_movi_tl(t0, -1);
5528 5529
    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
5530
        tcg_gen_movi_tl(t0, -1);
5531 5532
    else if (u == 0) {
        switch (rt) {
5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545
        case 1:
            switch (sel) {
            case 1:
                gen_helper_mftc0_vpecontrol(t0);
                break;
            case 2:
                gen_helper_mftc0_vpeconf0(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
5546 5547 5548
        case 2:
            switch (sel) {
            case 1:
P
pbrook 已提交
5549
                gen_helper_mftc0_tcstatus(t0);
5550 5551
                break;
            case 2:
P
pbrook 已提交
5552
                gen_helper_mftc0_tcbind(t0);
5553 5554
                break;
            case 3:
P
pbrook 已提交
5555
                gen_helper_mftc0_tcrestart(t0);
5556 5557
                break;
            case 4:
P
pbrook 已提交
5558
                gen_helper_mftc0_tchalt(t0);
5559 5560
                break;
            case 5:
P
pbrook 已提交
5561
                gen_helper_mftc0_tccontext(t0);
5562 5563
                break;
            case 6:
P
pbrook 已提交
5564
                gen_helper_mftc0_tcschedule(t0);
5565 5566
                break;
            case 7:
P
pbrook 已提交
5567
                gen_helper_mftc0_tcschefback(t0);
5568 5569
                break;
            default:
5570
                gen_mfc0(env, ctx, t0, rt, sel);
5571 5572 5573 5574 5575 5576
                break;
            }
            break;
        case 10:
            switch (sel) {
            case 0:
P
pbrook 已提交
5577
                gen_helper_mftc0_entryhi(t0);
5578 5579
                break;
            default:
5580
                gen_mfc0(env, ctx, t0, rt, sel);
5581 5582 5583 5584 5585
                break;
            }
        case 12:
            switch (sel) {
            case 0:
P
pbrook 已提交
5586
                gen_helper_mftc0_status(t0);
5587 5588
                break;
            default:
5589
                gen_mfc0(env, ctx, t0, rt, sel);
5590 5591
                break;
            }
5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631
        case 13:
            switch (sel) {
            case 0:
                gen_helper_mftc0_cause(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
        case 14:
            switch (sel) {
            case 0:
                gen_helper_mftc0_epc(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
        case 15:
            switch (sel) {
            case 1:
                gen_helper_mftc0_ebase(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
        case 16:
            switch (sel) {
            case 0 ... 7:
                gen_helper_mftc0_configx(t0, tcg_const_tl(sel));
                break;
            default:
                goto die;
                break;
            }
            break;
5632 5633 5634
        case 23:
            switch (sel) {
            case 0:
P
pbrook 已提交
5635
                gen_helper_mftc0_debug(t0);
5636 5637
                break;
            default:
5638
                gen_mfc0(env, ctx, t0, rt, sel);
5639 5640 5641 5642
                break;
            }
            break;
        default:
5643
            gen_mfc0(env, ctx, t0, rt, sel);
5644 5645 5646 5647
        }
    } else switch (sel) {
    /* GPR registers. */
    case 0:
P
pbrook 已提交
5648
        gen_helper_1i(mftgpr, t0, rt);
5649 5650 5651 5652 5653
        break;
    /* Auxiliary CPU registers */
    case 1:
        switch (rt) {
        case 0:
P
pbrook 已提交
5654
            gen_helper_1i(mftlo, t0, 0);
5655 5656
            break;
        case 1:
P
pbrook 已提交
5657
            gen_helper_1i(mfthi, t0, 0);
5658 5659
            break;
        case 2:
P
pbrook 已提交
5660
            gen_helper_1i(mftacx, t0, 0);
5661 5662
            break;
        case 4:
P
pbrook 已提交
5663
            gen_helper_1i(mftlo, t0, 1);
5664 5665
            break;
        case 5:
P
pbrook 已提交
5666
            gen_helper_1i(mfthi, t0, 1);
5667 5668
            break;
        case 6:
P
pbrook 已提交
5669
            gen_helper_1i(mftacx, t0, 1);
5670 5671
            break;
        case 8:
P
pbrook 已提交
5672
            gen_helper_1i(mftlo, t0, 2);
5673 5674
            break;
        case 9:
P
pbrook 已提交
5675
            gen_helper_1i(mfthi, t0, 2);
5676 5677
            break;
        case 10:
P
pbrook 已提交
5678
            gen_helper_1i(mftacx, t0, 2);
5679 5680
            break;
        case 12:
P
pbrook 已提交
5681
            gen_helper_1i(mftlo, t0, 3);
5682 5683
            break;
        case 13:
P
pbrook 已提交
5684
            gen_helper_1i(mfthi, t0, 3);
5685 5686
            break;
        case 14:
P
pbrook 已提交
5687
            gen_helper_1i(mftacx, t0, 3);
5688 5689
            break;
        case 16:
P
pbrook 已提交
5690
            gen_helper_mftdsp(t0);
5691 5692 5693 5694 5695 5696 5697 5698 5699
            break;
        default:
            goto die;
        }
        break;
    /* Floating point (COP1). */
    case 2:
        /* XXX: For now we support only a single FPU context. */
        if (h == 0) {
P
pbrook 已提交
5700
            TCGv_i32 fp0 = tcg_temp_new_i32();
5701 5702 5703

            gen_load_fpr32(fp0, rt);
            tcg_gen_ext_i32_tl(t0, fp0);
P
pbrook 已提交
5704
            tcg_temp_free_i32(fp0);
5705
        } else {
P
pbrook 已提交
5706
            TCGv_i32 fp0 = tcg_temp_new_i32();
5707 5708 5709

            gen_load_fpr32h(fp0, rt);
            tcg_gen_ext_i32_tl(t0, fp0);
P
pbrook 已提交
5710
            tcg_temp_free_i32(fp0);
5711 5712 5713 5714
        }
        break;
    case 3:
        /* XXX: For now we support only a single FPU context. */
P
pbrook 已提交
5715
        gen_helper_1i(cfc1, t0, rt);
5716 5717 5718 5719 5720 5721 5722 5723
        break;
    /* COP2: Not implemented. */
    case 4:
    case 5:
        /* fall through */
    default:
        goto die;
    }
5724
    LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h);
5725 5726
    gen_store_gpr(t0, rd);
    tcg_temp_free(t0);
5727 5728 5729
    return;

die:
5730
    tcg_temp_free(t0);
5731
    LOG_DISAS("mftr (reg %d u %d sel %d h %d)\n", rt, u, sel, h);
5732 5733 5734
    generate_exception(ctx, EXCP_RI);
}

5735
static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt,
5736 5737 5738
                     int u, int sel, int h)
{
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
P
pbrook 已提交
5739
    TCGv t0 = tcg_temp_local_new();
5740

5741
    gen_load_gpr(t0, rt);
5742
    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
5743 5744
        ((env->tcs[other_tc].CP0_TCBind & (0xf << CP0TCBd_CurVPE)) !=
         (env->active_tc.CP0_TCBind & (0xf << CP0TCBd_CurVPE))))
5745 5746 5747 5748 5749 5750
        /* NOP */ ;
    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
        /* NOP */ ;
    else if (u == 0) {
        switch (rd) {
5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
        case 1:
            switch (sel) {
            case 1:
                gen_helper_mttc0_vpecontrol(t0);
                break;
            case 2:
                gen_helper_mttc0_vpeconf0(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
5764 5765 5766
        case 2:
            switch (sel) {
            case 1:
P
pbrook 已提交
5767
                gen_helper_mttc0_tcstatus(t0);
5768 5769
                break;
            case 2:
P
pbrook 已提交
5770
                gen_helper_mttc0_tcbind(t0);
5771 5772
                break;
            case 3:
P
pbrook 已提交
5773
                gen_helper_mttc0_tcrestart(t0);
5774 5775
                break;
            case 4:
P
pbrook 已提交
5776
                gen_helper_mttc0_tchalt(t0);
5777 5778
                break;
            case 5:
P
pbrook 已提交
5779
                gen_helper_mttc0_tccontext(t0);
5780 5781
                break;
            case 6:
P
pbrook 已提交
5782
                gen_helper_mttc0_tcschedule(t0);
5783 5784
                break;
            case 7:
P
pbrook 已提交
5785
                gen_helper_mttc0_tcschefback(t0);
5786 5787
                break;
            default:
5788
                gen_mtc0(env, ctx, t0, rd, sel);
5789 5790 5791 5792 5793 5794
                break;
            }
            break;
        case 10:
            switch (sel) {
            case 0:
P
pbrook 已提交
5795
                gen_helper_mttc0_entryhi(t0);
5796 5797
                break;
            default:
5798
                gen_mtc0(env, ctx, t0, rd, sel);
5799 5800 5801 5802 5803
                break;
            }
        case 12:
            switch (sel) {
            case 0:
P
pbrook 已提交
5804
                gen_helper_mttc0_status(t0);
5805 5806
                break;
            default:
5807
                gen_mtc0(env, ctx, t0, rd, sel);
5808 5809
                break;
            }
5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829
        case 13:
            switch (sel) {
            case 0:
                gen_helper_mttc0_cause(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
        case 15:
            switch (sel) {
            case 1:
                gen_helper_mttc0_ebase(t0);
                break;
            default:
                goto die;
                break;
            }
            break;
5830 5831 5832
        case 23:
            switch (sel) {
            case 0:
P
pbrook 已提交
5833
                gen_helper_mttc0_debug(t0);
5834 5835
                break;
            default:
5836
                gen_mtc0(env, ctx, t0, rd, sel);
5837 5838 5839 5840
                break;
            }
            break;
        default:
5841
            gen_mtc0(env, ctx, t0, rd, sel);
5842 5843 5844 5845
        }
    } else switch (sel) {
    /* GPR registers. */
    case 0:
P
pbrook 已提交
5846
        gen_helper_1i(mttgpr, t0, rd);
5847 5848 5849 5850 5851
        break;
    /* Auxiliary CPU registers */
    case 1:
        switch (rd) {
        case 0:
P
pbrook 已提交
5852
            gen_helper_1i(mttlo, t0, 0);
5853 5854
            break;
        case 1:
P
pbrook 已提交
5855
            gen_helper_1i(mtthi, t0, 0);
5856 5857
            break;
        case 2:
P
pbrook 已提交
5858
            gen_helper_1i(mttacx, t0, 0);
5859 5860
            break;
        case 4:
P
pbrook 已提交
5861
            gen_helper_1i(mttlo, t0, 1);
5862 5863
            break;
        case 5:
P
pbrook 已提交
5864
            gen_helper_1i(mtthi, t0, 1);
5865 5866
            break;
        case 6:
P
pbrook 已提交
5867
            gen_helper_1i(mttacx, t0, 1);
5868 5869
            break;
        case 8:
P
pbrook 已提交
5870
            gen_helper_1i(mttlo, t0, 2);
5871 5872
            break;
        case 9:
P
pbrook 已提交
5873
            gen_helper_1i(mtthi, t0, 2);
5874 5875
            break;
        case 10:
P
pbrook 已提交
5876
            gen_helper_1i(mttacx, t0, 2);
5877 5878
            break;
        case 12:
P
pbrook 已提交
5879
            gen_helper_1i(mttlo, t0, 3);
5880 5881
            break;
        case 13:
P
pbrook 已提交
5882
            gen_helper_1i(mtthi, t0, 3);
5883 5884
            break;
        case 14:
P
pbrook 已提交
5885
            gen_helper_1i(mttacx, t0, 3);
5886 5887
            break;
        case 16:
P
pbrook 已提交
5888
            gen_helper_mttdsp(t0);
5889 5890 5891 5892 5893 5894 5895 5896 5897
            break;
        default:
            goto die;
        }
        break;
    /* Floating point (COP1). */
    case 2:
        /* XXX: For now we support only a single FPU context. */
        if (h == 0) {
P
pbrook 已提交
5898
            TCGv_i32 fp0 = tcg_temp_new_i32();
5899 5900 5901

            tcg_gen_trunc_tl_i32(fp0, t0);
            gen_store_fpr32(fp0, rd);
P
pbrook 已提交
5902
            tcg_temp_free_i32(fp0);
5903
        } else {
P
pbrook 已提交
5904
            TCGv_i32 fp0 = tcg_temp_new_i32();
5905 5906 5907

            tcg_gen_trunc_tl_i32(fp0, t0);
            gen_store_fpr32h(fp0, rd);
P
pbrook 已提交
5908
            tcg_temp_free_i32(fp0);
5909 5910 5911 5912
        }
        break;
    case 3:
        /* XXX: For now we support only a single FPU context. */
P
pbrook 已提交
5913
        gen_helper_1i(ctc1, t0, rd);
5914 5915 5916 5917 5918 5919 5920 5921
        break;
    /* COP2: Not implemented. */
    case 4:
    case 5:
        /* fall through */
    default:
        goto die;
    }
5922
    LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h);
5923
    tcg_temp_free(t0);
5924 5925 5926
    return;

die:
5927
    tcg_temp_free(t0);
5928
    LOG_DISAS("mttr (reg %d u %d sel %d h %d)\n", rd, u, sel, h);
5929 5930 5931
    generate_exception(ctx, EXCP_RI);
}

5932
static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, int rd)
B
bellard 已提交
5933
{
T
ths 已提交
5934
    const char *opn = "ldst";
B
bellard 已提交
5935 5936 5937 5938

    switch (opc) {
    case OPC_MFC0:
        if (rt == 0) {
5939
            /* Treat as NOP. */
B
bellard 已提交
5940 5941
            return;
        }
A
aurel32 已提交
5942
        gen_mfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7);
B
bellard 已提交
5943 5944 5945
        opn = "mfc0";
        break;
    case OPC_MTC0:
5946
        {
A
aurel32 已提交
5947
            TCGv t0 = tcg_temp_new();
5948 5949 5950 5951 5952

            gen_load_gpr(t0, rt);
            gen_mtc0(env, ctx, t0, rd, ctx->opcode & 0x7);
            tcg_temp_free(t0);
        }
B
bellard 已提交
5953 5954
        opn = "mtc0";
        break;
5955
#if defined(TARGET_MIPS64)
T
ths 已提交
5956
    case OPC_DMFC0:
5957
        check_insn(env, ctx, ISA_MIPS3);
T
ths 已提交
5958
        if (rt == 0) {
5959
            /* Treat as NOP. */
T
ths 已提交
5960 5961
            return;
        }
A
aurel32 已提交
5962
        gen_dmfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7);
T
ths 已提交
5963 5964 5965
        opn = "dmfc0";
        break;
    case OPC_DMTC0:
5966
        check_insn(env, ctx, ISA_MIPS3);
5967
        {
A
aurel32 已提交
5968
            TCGv t0 = tcg_temp_new();
5969 5970 5971 5972 5973

            gen_load_gpr(t0, rt);
            gen_dmtc0(env, ctx, t0, rd, ctx->opcode & 0x7);
            tcg_temp_free(t0);
        }
T
ths 已提交
5974 5975
        opn = "dmtc0";
        break;
5976
#endif
5977
    case OPC_MFTR:
5978
        check_insn(env, ctx, ASE_MT);
5979 5980 5981 5982
        if (rd == 0) {
            /* Treat as NOP. */
            return;
        }
5983
        gen_mftr(env, ctx, rt, rd, (ctx->opcode >> 5) & 1,
5984 5985 5986 5987
                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
        opn = "mftr";
        break;
    case OPC_MTTR:
5988
        check_insn(env, ctx, ASE_MT);
5989
        gen_mttr(env, ctx, rd, rt, (ctx->opcode >> 5) & 1,
5990 5991 5992
                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
        opn = "mttr";
        break;
B
bellard 已提交
5993 5994
    case OPC_TLBWI:
        opn = "tlbwi";
5995
        if (!env->tlb->helper_tlbwi)
5996
            goto die;
P
pbrook 已提交
5997
        gen_helper_tlbwi();
B
bellard 已提交
5998 5999 6000
        break;
    case OPC_TLBWR:
        opn = "tlbwr";
6001
        if (!env->tlb->helper_tlbwr)
6002
            goto die;
P
pbrook 已提交
6003
        gen_helper_tlbwr();
B
bellard 已提交
6004 6005 6006
        break;
    case OPC_TLBP:
        opn = "tlbp";
6007
        if (!env->tlb->helper_tlbp)
6008
            goto die;
P
pbrook 已提交
6009
        gen_helper_tlbp();
B
bellard 已提交
6010 6011 6012
        break;
    case OPC_TLBR:
        opn = "tlbr";
6013
        if (!env->tlb->helper_tlbr)
6014
            goto die;
P
pbrook 已提交
6015
        gen_helper_tlbr();
B
bellard 已提交
6016 6017 6018
        break;
    case OPC_ERET:
        opn = "eret";
6019
        check_insn(env, ctx, ISA_MIPS2);
P
pbrook 已提交
6020
        gen_helper_eret();
B
bellard 已提交
6021 6022 6023 6024
        ctx->bstate = BS_EXCP;
        break;
    case OPC_DERET:
        opn = "deret";
6025
        check_insn(env, ctx, ISA_MIPS32);
B
bellard 已提交
6026
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
6027
            MIPS_INVAL(opn);
B
bellard 已提交
6028 6029
            generate_exception(ctx, EXCP_RI);
        } else {
P
pbrook 已提交
6030
            gen_helper_deret();
B
bellard 已提交
6031 6032 6033
            ctx->bstate = BS_EXCP;
        }
        break;
B
bellard 已提交
6034 6035
    case OPC_WAIT:
        opn = "wait";
6036
        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
B
bellard 已提交
6037 6038 6039 6040
        /* If we get an exception, we want to restart at next instruction */
        ctx->pc += 4;
        save_cpu_state(ctx, 1);
        ctx->pc -= 4;
P
pbrook 已提交
6041
        gen_helper_wait();
B
bellard 已提交
6042 6043
        ctx->bstate = BS_EXCP;
        break;
B
bellard 已提交
6044
    default:
6045
 die:
6046
        MIPS_INVAL(opn);
B
bellard 已提交
6047 6048 6049
        generate_exception(ctx, EXCP_RI);
        return;
    }
B
Blue Swirl 已提交
6050
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
6051 6052
    MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
}
6053
#endif /* !CONFIG_USER_ONLY */
B
bellard 已提交
6054

B
bellard 已提交
6055
/* CP1 Branches (before delay slot) */
6056
static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t op,
6057
                                 int32_t cc, int32_t offset)
B
bellard 已提交
6058 6059
{
    target_ulong btarget;
6060
    const char *opn = "cp1 cond branch";
P
pbrook 已提交
6061
    TCGv_i32 t0 = tcg_temp_new_i32();
B
bellard 已提交
6062

6063 6064 6065
    if (cc != 0)
        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);

B
bellard 已提交
6066 6067
    btarget = ctx->pc + 4 + offset;

6068 6069
    switch (op) {
    case OPC_BC1F:
6070 6071 6072 6073
        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
        tcg_gen_not_i32(t0, t0);
        tcg_gen_andi_i32(t0, t0, 1);
        tcg_gen_extu_i32_tl(bcond, t0);
6074
        opn = "bc1f";
B
bellard 已提交
6075
        goto not_likely;
6076
    case OPC_BC1FL:
6077 6078 6079 6080
        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
        tcg_gen_not_i32(t0, t0);
        tcg_gen_andi_i32(t0, t0, 1);
        tcg_gen_extu_i32_tl(bcond, t0);
6081
        opn = "bc1fl";
B
bellard 已提交
6082
        goto likely;
6083
    case OPC_BC1T:
6084 6085 6086
        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
        tcg_gen_andi_i32(t0, t0, 1);
        tcg_gen_extu_i32_tl(bcond, t0);
6087
        opn = "bc1t";
6088
        goto not_likely;
6089
    case OPC_BC1TL:
6090 6091 6092
        tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
        tcg_gen_andi_i32(t0, t0, 1);
        tcg_gen_extu_i32_tl(bcond, t0);
6093
        opn = "bc1tl";
B
bellard 已提交
6094 6095 6096
    likely:
        ctx->hflags |= MIPS_HFLAG_BL;
        break;
6097
    case OPC_BC1FANY2:
6098
        {
6099 6100 6101
            TCGv_i32 t1 = tcg_temp_new_i32();
            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
6102
            tcg_gen_nor_i32(t0, t0, t1);
6103 6104 6105
            tcg_temp_free_i32(t1);
            tcg_gen_andi_i32(t0, t0, 1);
            tcg_gen_extu_i32_tl(bcond, t0);
6106
        }
6107
        opn = "bc1any2f";
6108 6109
        goto not_likely;
    case OPC_BC1TANY2:
6110
        {
6111 6112 6113 6114 6115 6116 6117
            TCGv_i32 t1 = tcg_temp_new_i32();
            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_temp_free_i32(t1);
            tcg_gen_andi_i32(t0, t0, 1);
            tcg_gen_extu_i32_tl(bcond, t0);
6118
        }
6119
        opn = "bc1any2t";
6120 6121
        goto not_likely;
    case OPC_BC1FANY4:
6122
        {
6123 6124 6125 6126 6127 6128 6129
            TCGv_i32 t1 = tcg_temp_new_i32();
            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3));
6130
            tcg_gen_nor_i32(t0, t0, t1);
6131 6132 6133
            tcg_temp_free_i32(t1);
            tcg_gen_andi_i32(t0, t0, 1);
            tcg_gen_extu_i32_tl(bcond, t0);
6134
        }
6135
        opn = "bc1any4f";
6136 6137
        goto not_likely;
    case OPC_BC1TANY4:
6138
        {
6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149
            TCGv_i32 t1 = tcg_temp_new_i32();
            tcg_gen_shri_i32(t0, fpu_fcr31, get_fp_bit(cc));
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+1));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+2));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_gen_shri_i32(t1, fpu_fcr31, get_fp_bit(cc+3));
            tcg_gen_or_i32(t0, t0, t1);
            tcg_temp_free_i32(t1);
            tcg_gen_andi_i32(t0, t0, 1);
            tcg_gen_extu_i32_tl(bcond, t0);
6150
        }
6151
        opn = "bc1any4t";
6152 6153 6154 6155
    not_likely:
        ctx->hflags |= MIPS_HFLAG_BC;
        break;
    default:
6156
        MIPS_INVAL(opn);
6157
        generate_exception (ctx, EXCP_RI);
6158
        goto out;
B
bellard 已提交
6159
    }
B
Blue Swirl 已提交
6160
    (void)opn; /* avoid a compiler warning */
6161
    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
B
bellard 已提交
6162 6163
               ctx->hflags, btarget);
    ctx->btarget = btarget;
6164 6165

 out:
P
pbrook 已提交
6166
    tcg_temp_free_i32(t0);
B
bellard 已提交
6167 6168
}

B
bellard 已提交
6169
/* Coprocessor 1 (FPU) */
6170 6171 6172

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

6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312
enum fopcode {
    OPC_ADD_S = FOP(0, FMT_S),
    OPC_SUB_S = FOP(1, FMT_S),
    OPC_MUL_S = FOP(2, FMT_S),
    OPC_DIV_S = FOP(3, FMT_S),
    OPC_SQRT_S = FOP(4, FMT_S),
    OPC_ABS_S = FOP(5, FMT_S),
    OPC_MOV_S = FOP(6, FMT_S),
    OPC_NEG_S = FOP(7, FMT_S),
    OPC_ROUND_L_S = FOP(8, FMT_S),
    OPC_TRUNC_L_S = FOP(9, FMT_S),
    OPC_CEIL_L_S = FOP(10, FMT_S),
    OPC_FLOOR_L_S = FOP(11, FMT_S),
    OPC_ROUND_W_S = FOP(12, FMT_S),
    OPC_TRUNC_W_S = FOP(13, FMT_S),
    OPC_CEIL_W_S = FOP(14, FMT_S),
    OPC_FLOOR_W_S = FOP(15, FMT_S),
    OPC_MOVCF_S = FOP(17, FMT_S),
    OPC_MOVZ_S = FOP(18, FMT_S),
    OPC_MOVN_S = FOP(19, FMT_S),
    OPC_RECIP_S = FOP(21, FMT_S),
    OPC_RSQRT_S = FOP(22, FMT_S),
    OPC_RECIP2_S = FOP(28, FMT_S),
    OPC_RECIP1_S = FOP(29, FMT_S),
    OPC_RSQRT1_S = FOP(30, FMT_S),
    OPC_RSQRT2_S = FOP(31, FMT_S),
    OPC_CVT_D_S = FOP(33, FMT_S),
    OPC_CVT_W_S = FOP(36, FMT_S),
    OPC_CVT_L_S = FOP(37, FMT_S),
    OPC_CVT_PS_S = FOP(38, FMT_S),
    OPC_CMP_F_S = FOP (48, FMT_S),
    OPC_CMP_UN_S = FOP (49, FMT_S),
    OPC_CMP_EQ_S = FOP (50, FMT_S),
    OPC_CMP_UEQ_S = FOP (51, FMT_S),
    OPC_CMP_OLT_S = FOP (52, FMT_S),
    OPC_CMP_ULT_S = FOP (53, FMT_S),
    OPC_CMP_OLE_S = FOP (54, FMT_S),
    OPC_CMP_ULE_S = FOP (55, FMT_S),
    OPC_CMP_SF_S = FOP (56, FMT_S),
    OPC_CMP_NGLE_S = FOP (57, FMT_S),
    OPC_CMP_SEQ_S = FOP (58, FMT_S),
    OPC_CMP_NGL_S = FOP (59, FMT_S),
    OPC_CMP_LT_S = FOP (60, FMT_S),
    OPC_CMP_NGE_S = FOP (61, FMT_S),
    OPC_CMP_LE_S = FOP (62, FMT_S),
    OPC_CMP_NGT_S = FOP (63, FMT_S),

    OPC_ADD_D = FOP(0, FMT_D),
    OPC_SUB_D = FOP(1, FMT_D),
    OPC_MUL_D = FOP(2, FMT_D),
    OPC_DIV_D = FOP(3, FMT_D),
    OPC_SQRT_D = FOP(4, FMT_D),
    OPC_ABS_D = FOP(5, FMT_D),
    OPC_MOV_D = FOP(6, FMT_D),
    OPC_NEG_D = FOP(7, FMT_D),
    OPC_ROUND_L_D = FOP(8, FMT_D),
    OPC_TRUNC_L_D = FOP(9, FMT_D),
    OPC_CEIL_L_D = FOP(10, FMT_D),
    OPC_FLOOR_L_D = FOP(11, FMT_D),
    OPC_ROUND_W_D = FOP(12, FMT_D),
    OPC_TRUNC_W_D = FOP(13, FMT_D),
    OPC_CEIL_W_D = FOP(14, FMT_D),
    OPC_FLOOR_W_D = FOP(15, FMT_D),
    OPC_MOVCF_D = FOP(17, FMT_D),
    OPC_MOVZ_D = FOP(18, FMT_D),
    OPC_MOVN_D = FOP(19, FMT_D),
    OPC_RECIP_D = FOP(21, FMT_D),
    OPC_RSQRT_D = FOP(22, FMT_D),
    OPC_RECIP2_D = FOP(28, FMT_D),
    OPC_RECIP1_D = FOP(29, FMT_D),
    OPC_RSQRT1_D = FOP(30, FMT_D),
    OPC_RSQRT2_D = FOP(31, FMT_D),
    OPC_CVT_S_D = FOP(32, FMT_D),
    OPC_CVT_W_D = FOP(36, FMT_D),
    OPC_CVT_L_D = FOP(37, FMT_D),
    OPC_CMP_F_D = FOP (48, FMT_D),
    OPC_CMP_UN_D = FOP (49, FMT_D),
    OPC_CMP_EQ_D = FOP (50, FMT_D),
    OPC_CMP_UEQ_D = FOP (51, FMT_D),
    OPC_CMP_OLT_D = FOP (52, FMT_D),
    OPC_CMP_ULT_D = FOP (53, FMT_D),
    OPC_CMP_OLE_D = FOP (54, FMT_D),
    OPC_CMP_ULE_D = FOP (55, FMT_D),
    OPC_CMP_SF_D = FOP (56, FMT_D),
    OPC_CMP_NGLE_D = FOP (57, FMT_D),
    OPC_CMP_SEQ_D = FOP (58, FMT_D),
    OPC_CMP_NGL_D = FOP (59, FMT_D),
    OPC_CMP_LT_D = FOP (60, FMT_D),
    OPC_CMP_NGE_D = FOP (61, FMT_D),
    OPC_CMP_LE_D = FOP (62, FMT_D),
    OPC_CMP_NGT_D = FOP (63, FMT_D),

    OPC_CVT_S_W = FOP(32, FMT_W),
    OPC_CVT_D_W = FOP(33, FMT_W),
    OPC_CVT_S_L = FOP(32, FMT_L),
    OPC_CVT_D_L = FOP(33, FMT_L),
    OPC_CVT_PS_PW = FOP(38, FMT_W),

    OPC_ADD_PS = FOP(0, FMT_PS),
    OPC_SUB_PS = FOP(1, FMT_PS),
    OPC_MUL_PS = FOP(2, FMT_PS),
    OPC_DIV_PS = FOP(3, FMT_PS),
    OPC_ABS_PS = FOP(5, FMT_PS),
    OPC_MOV_PS = FOP(6, FMT_PS),
    OPC_NEG_PS = FOP(7, FMT_PS),
    OPC_MOVCF_PS = FOP(17, FMT_PS),
    OPC_MOVZ_PS = FOP(18, FMT_PS),
    OPC_MOVN_PS = FOP(19, FMT_PS),
    OPC_ADDR_PS = FOP(24, FMT_PS),
    OPC_MULR_PS = FOP(26, FMT_PS),
    OPC_RECIP2_PS = FOP(28, FMT_PS),
    OPC_RECIP1_PS = FOP(29, FMT_PS),
    OPC_RSQRT1_PS = FOP(30, FMT_PS),
    OPC_RSQRT2_PS = FOP(31, FMT_PS),

    OPC_CVT_S_PU = FOP(32, FMT_PS),
    OPC_CVT_PW_PS = FOP(36, FMT_PS),
    OPC_CVT_S_PL = FOP(40, FMT_PS),
    OPC_PLL_PS = FOP(44, FMT_PS),
    OPC_PLU_PS = FOP(45, FMT_PS),
    OPC_PUL_PS = FOP(46, FMT_PS),
    OPC_PUU_PS = FOP(47, FMT_PS),
    OPC_CMP_F_PS = FOP (48, FMT_PS),
    OPC_CMP_UN_PS = FOP (49, FMT_PS),
    OPC_CMP_EQ_PS = FOP (50, FMT_PS),
    OPC_CMP_UEQ_PS = FOP (51, FMT_PS),
    OPC_CMP_OLT_PS = FOP (52, FMT_PS),
    OPC_CMP_ULT_PS = FOP (53, FMT_PS),
    OPC_CMP_OLE_PS = FOP (54, FMT_PS),
    OPC_CMP_ULE_PS = FOP (55, FMT_PS),
    OPC_CMP_SF_PS = FOP (56, FMT_PS),
    OPC_CMP_NGLE_PS = FOP (57, FMT_PS),
    OPC_CMP_SEQ_PS = FOP (58, FMT_PS),
    OPC_CMP_NGL_PS = FOP (59, FMT_PS),
    OPC_CMP_LT_PS = FOP (60, FMT_PS),
    OPC_CMP_NGE_PS = FOP (61, FMT_PS),
    OPC_CMP_LE_PS = FOP (62, FMT_PS),
    OPC_CMP_NGT_PS = FOP (63, FMT_PS),
};

6313
static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
B
bellard 已提交
6314
{
6315
    const char *opn = "cp1 move";
A
aurel32 已提交
6316
    TCGv t0 = tcg_temp_new();
B
bellard 已提交
6317 6318 6319

    switch (opc) {
    case OPC_MFC1:
6320
        {
P
pbrook 已提交
6321
            TCGv_i32 fp0 = tcg_temp_new_i32();
6322 6323 6324

            gen_load_fpr32(fp0, fs);
            tcg_gen_ext_i32_tl(t0, fp0);
P
pbrook 已提交
6325
            tcg_temp_free_i32(fp0);
A
aurel32 已提交
6326
        }
6327
        gen_store_gpr(t0, rt);
B
bellard 已提交
6328 6329 6330
        opn = "mfc1";
        break;
    case OPC_MTC1:
6331
        gen_load_gpr(t0, rt);
6332
        {
P
pbrook 已提交
6333
            TCGv_i32 fp0 = tcg_temp_new_i32();
6334 6335 6336

            tcg_gen_trunc_tl_i32(fp0, t0);
            gen_store_fpr32(fp0, fs);
P
pbrook 已提交
6337
            tcg_temp_free_i32(fp0);
A
aurel32 已提交
6338
        }
B
bellard 已提交
6339 6340 6341
        opn = "mtc1";
        break;
    case OPC_CFC1:
P
pbrook 已提交
6342
        gen_helper_1i(cfc1, t0, fs);
6343
        gen_store_gpr(t0, rt);
B
bellard 已提交
6344 6345 6346
        opn = "cfc1";
        break;
    case OPC_CTC1:
6347
        gen_load_gpr(t0, rt);
P
pbrook 已提交
6348
        gen_helper_1i(ctc1, t0, fs);
B
bellard 已提交
6349 6350
        opn = "ctc1";
        break;
A
aurel32 已提交
6351
#if defined(TARGET_MIPS64)
T
ths 已提交
6352
    case OPC_DMFC1:
A
aurel32 已提交
6353
        gen_load_fpr64(ctx, t0, fs);
6354
        gen_store_gpr(t0, rt);
6355 6356
        opn = "dmfc1";
        break;
T
ths 已提交
6357
    case OPC_DMTC1:
6358
        gen_load_gpr(t0, rt);
A
aurel32 已提交
6359
        gen_store_fpr64(ctx, t0, fs);
6360 6361
        opn = "dmtc1";
        break;
A
aurel32 已提交
6362
#endif
6363
    case OPC_MFHC1:
6364
        {
P
pbrook 已提交
6365
            TCGv_i32 fp0 = tcg_temp_new_i32();
6366 6367 6368

            gen_load_fpr32h(fp0, fs);
            tcg_gen_ext_i32_tl(t0, fp0);
P
pbrook 已提交
6369
            tcg_temp_free_i32(fp0);
A
aurel32 已提交
6370
        }
6371
        gen_store_gpr(t0, rt);
6372 6373 6374
        opn = "mfhc1";
        break;
    case OPC_MTHC1:
6375
        gen_load_gpr(t0, rt);
6376
        {
P
pbrook 已提交
6377
            TCGv_i32 fp0 = tcg_temp_new_i32();
6378 6379 6380

            tcg_gen_trunc_tl_i32(fp0, t0);
            gen_store_fpr32h(fp0, fs);
P
pbrook 已提交
6381
            tcg_temp_free_i32(fp0);
A
aurel32 已提交
6382
        }
6383 6384
        opn = "mthc1";
        break;
B
bellard 已提交
6385
    default:
6386
        MIPS_INVAL(opn);
6387
        generate_exception (ctx, EXCP_RI);
6388
        goto out;
B
bellard 已提交
6389
    }
B
Blue Swirl 已提交
6390
    (void)opn; /* avoid a compiler warning */
B
bellard 已提交
6391
    MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
6392 6393 6394

 out:
    tcg_temp_free(t0);
B
bellard 已提交
6395 6396
}

6397 6398
static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
{
A
aurel32 已提交
6399
    int l1;
T
ths 已提交
6400
    TCGCond cond;
A
aurel32 已提交
6401 6402 6403 6404 6405 6406
    TCGv_i32 t0;

    if (rd == 0) {
        /* Treat as NOP. */
        return;
    }
B
bellard 已提交
6407

T
ths 已提交
6408 6409
    if (tf)
        cond = TCG_COND_EQ;
6410 6411 6412
    else
        cond = TCG_COND_NE;

A
aurel32 已提交
6413 6414
    l1 = gen_new_label();
    t0 = tcg_temp_new_i32();
6415
    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
A
aurel32 已提交
6416
    tcg_gen_brcondi_i32(cond, t0, 0, l1);
6417
    tcg_temp_free_i32(t0);
A
aurel32 已提交
6418 6419 6420 6421 6422
    if (rs == 0) {
        tcg_gen_movi_tl(cpu_gpr[rd], 0);
    } else {
        tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rs]);
    }
T
ths 已提交
6423
    gen_set_label(l1);
6424 6425
}

6426
static inline void gen_movcf_s (int fs, int fd, int cc, int tf)
6427 6428
{
    int cond;
A
aurel32 已提交
6429
    TCGv_i32 t0 = tcg_temp_new_i32();
6430 6431 6432 6433 6434 6435 6436
    int l1 = gen_new_label();

    if (tf)
        cond = TCG_COND_EQ;
    else
        cond = TCG_COND_NE;

6437
    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
A
aurel32 已提交
6438 6439 6440
    tcg_gen_brcondi_i32(cond, t0, 0, l1);
    gen_load_fpr32(t0, fs);
    gen_store_fpr32(t0, fd);
6441
    gen_set_label(l1);
A
aurel32 已提交
6442
    tcg_temp_free_i32(t0);
6443
}
6444

6445
static inline void gen_movcf_d (DisasContext *ctx, int fs, int fd, int cc, int tf)
6446 6447
{
    int cond;
A
aurel32 已提交
6448 6449
    TCGv_i32 t0 = tcg_temp_new_i32();
    TCGv_i64 fp0;
6450 6451 6452 6453 6454 6455 6456
    int l1 = gen_new_label();

    if (tf)
        cond = TCG_COND_EQ;
    else
        cond = TCG_COND_NE;

6457
    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
A
aurel32 已提交
6458
    tcg_gen_brcondi_i32(cond, t0, 0, l1);
6459
    tcg_temp_free_i32(t0);
A
aurel32 已提交
6460
    fp0 = tcg_temp_new_i64();
A
aurel32 已提交
6461 6462
    gen_load_fpr64(ctx, fp0, fs);
    gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
6463
    tcg_temp_free_i64(fp0);
A
aurel32 已提交
6464
    gen_set_label(l1);
6465 6466
}

6467
static inline void gen_movcf_ps (int fs, int fd, int cc, int tf)
6468 6469
{
    int cond;
A
aurel32 已提交
6470
    TCGv_i32 t0 = tcg_temp_new_i32();
6471 6472 6473 6474 6475 6476 6477 6478
    int l1 = gen_new_label();
    int l2 = gen_new_label();

    if (tf)
        cond = TCG_COND_EQ;
    else
        cond = TCG_COND_NE;

6479
    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc));
A
aurel32 已提交
6480 6481 6482
    tcg_gen_brcondi_i32(cond, t0, 0, l1);
    gen_load_fpr32(t0, fs);
    gen_store_fpr32(t0, fd);
6483
    gen_set_label(l1);
A
aurel32 已提交
6484

6485
    tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc+1));
A
aurel32 已提交
6486 6487 6488
    tcg_gen_brcondi_i32(cond, t0, 0, l2);
    gen_load_fpr32h(t0, fs);
    gen_store_fpr32h(t0, fd);
A
aurel32 已提交
6489
    tcg_temp_free_i32(t0);
6490 6491 6492
    gen_set_label(l2);
}

B
bellard 已提交
6493

6494
static void gen_farith (DisasContext *ctx, enum fopcode op1,
6495
                        int ft, int fs, int fd, int cc)
B
bellard 已提交
6496
{
6497
    const char *opn = "farith";
B
bellard 已提交
6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515
    const char *condnames[] = {
            "c.f",
            "c.un",
            "c.eq",
            "c.ueq",
            "c.olt",
            "c.ult",
            "c.ole",
            "c.ule",
            "c.sf",
            "c.ngle",
            "c.seq",
            "c.ngl",
            "c.lt",
            "c.nge",
            "c.le",
            "c.ngt",
    };
6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534
    const char *condnames_abs[] = {
            "cabs.f",
            "cabs.un",
            "cabs.eq",
            "cabs.ueq",
            "cabs.olt",
            "cabs.ult",
            "cabs.ole",
            "cabs.ule",
            "cabs.sf",
            "cabs.ngle",
            "cabs.seq",
            "cabs.ngl",
            "cabs.lt",
            "cabs.nge",
            "cabs.le",
            "cabs.ngt",
    };
    enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
6535 6536
    uint32_t func = ctx->opcode & 0x3f;

6537 6538
    switch (op1) {
    case OPC_ADD_S:
6539
        {
P
pbrook 已提交
6540 6541
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6542 6543 6544

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
P
pbrook 已提交
6545 6546
            gen_helper_float_add_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6547
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6548
            tcg_temp_free_i32(fp0);
6549
        }
6550
        opn = "add.s";
6551
        optype = BINOP;
6552
        break;
6553
    case OPC_SUB_S:
6554
        {
P
pbrook 已提交
6555 6556
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6557 6558 6559

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
P
pbrook 已提交
6560 6561
            gen_helper_float_sub_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6562
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6563
            tcg_temp_free_i32(fp0);
6564
        }
6565
        opn = "sub.s";
6566
        optype = BINOP;
6567
        break;
6568
    case OPC_MUL_S:
6569
        {
P
pbrook 已提交
6570 6571
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6572 6573 6574

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
P
pbrook 已提交
6575 6576
            gen_helper_float_mul_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6577
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6578
            tcg_temp_free_i32(fp0);
6579
        }
6580
        opn = "mul.s";
6581
        optype = BINOP;
6582
        break;
6583
    case OPC_DIV_S:
6584
        {
P
pbrook 已提交
6585 6586
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6587 6588 6589

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
P
pbrook 已提交
6590 6591
            gen_helper_float_div_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6592
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6593
            tcg_temp_free_i32(fp0);
6594
        }
6595
        opn = "div.s";
6596
        optype = BINOP;
6597
        break;
6598
    case OPC_SQRT_S:
6599
        {
P
pbrook 已提交
6600
            TCGv_i32 fp0 = tcg_temp_new_i32();
6601 6602

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6603
            gen_helper_float_sqrt_s(fp0, fp0);
6604
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6605
            tcg_temp_free_i32(fp0);
6606
        }
6607 6608
        opn = "sqrt.s";
        break;
6609
    case OPC_ABS_S:
6610
        {
P
pbrook 已提交
6611
            TCGv_i32 fp0 = tcg_temp_new_i32();
6612 6613

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6614
            gen_helper_float_abs_s(fp0, fp0);
6615
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6616
            tcg_temp_free_i32(fp0);
6617
        }
6618 6619
        opn = "abs.s";
        break;
6620
    case OPC_MOV_S:
6621
        {
P
pbrook 已提交
6622
            TCGv_i32 fp0 = tcg_temp_new_i32();
6623 6624 6625

            gen_load_fpr32(fp0, fs);
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6626
            tcg_temp_free_i32(fp0);
6627
        }
6628 6629
        opn = "mov.s";
        break;
6630
    case OPC_NEG_S:
6631
        {
P
pbrook 已提交
6632
            TCGv_i32 fp0 = tcg_temp_new_i32();
6633 6634

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6635
            gen_helper_float_chs_s(fp0, fp0);
6636
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6637
            tcg_temp_free_i32(fp0);
6638
        }
6639 6640
        opn = "neg.s";
        break;
6641
    case OPC_ROUND_L_S:
6642
        check_cp1_64bitmode(ctx);
6643
        {
P
pbrook 已提交
6644 6645
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6646 6647

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6648 6649
            gen_helper_float_roundl_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6650
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6651
            tcg_temp_free_i64(fp64);
6652
        }
6653 6654
        opn = "round.l.s";
        break;
6655
    case OPC_TRUNC_L_S:
6656
        check_cp1_64bitmode(ctx);
6657
        {
P
pbrook 已提交
6658 6659
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6660 6661

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6662 6663
            gen_helper_float_truncl_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6664
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6665
            tcg_temp_free_i64(fp64);
6666
        }
6667 6668
        opn = "trunc.l.s";
        break;
6669
    case OPC_CEIL_L_S:
6670
        check_cp1_64bitmode(ctx);
6671
        {
P
pbrook 已提交
6672 6673
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6674 6675

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6676 6677
            gen_helper_float_ceill_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6678
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6679
            tcg_temp_free_i64(fp64);
6680
        }
6681 6682
        opn = "ceil.l.s";
        break;
6683
    case OPC_FLOOR_L_S:
6684
        check_cp1_64bitmode(ctx);
6685
        {
P
pbrook 已提交
6686 6687
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6688 6689

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6690 6691
            gen_helper_float_floorl_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6692
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6693
            tcg_temp_free_i64(fp64);
6694
        }
6695 6696
        opn = "floor.l.s";
        break;
6697
    case OPC_ROUND_W_S:
6698
        {
P
pbrook 已提交
6699
            TCGv_i32 fp0 = tcg_temp_new_i32();
6700 6701

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6702
            gen_helper_float_roundw_s(fp0, fp0);
6703
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6704
            tcg_temp_free_i32(fp0);
6705
        }
6706 6707
        opn = "round.w.s";
        break;
6708
    case OPC_TRUNC_W_S:
6709
        {
P
pbrook 已提交
6710
            TCGv_i32 fp0 = tcg_temp_new_i32();
6711 6712

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6713
            gen_helper_float_truncw_s(fp0, fp0);
6714
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6715
            tcg_temp_free_i32(fp0);
6716
        }
6717 6718
        opn = "trunc.w.s";
        break;
6719
    case OPC_CEIL_W_S:
6720
        {
P
pbrook 已提交
6721
            TCGv_i32 fp0 = tcg_temp_new_i32();
6722 6723

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6724
            gen_helper_float_ceilw_s(fp0, fp0);
6725
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6726
            tcg_temp_free_i32(fp0);
6727
        }
6728 6729
        opn = "ceil.w.s";
        break;
6730
    case OPC_FLOOR_W_S:
6731
        {
P
pbrook 已提交
6732
            TCGv_i32 fp0 = tcg_temp_new_i32();
6733 6734

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6735
            gen_helper_float_floorw_s(fp0, fp0);
6736
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6737
            tcg_temp_free_i32(fp0);
6738
        }
6739 6740
        opn = "floor.w.s";
        break;
6741
    case OPC_MOVCF_S:
6742
        gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
6743 6744
        opn = "movcf.s";
        break;
6745
    case OPC_MOVZ_S:
6746 6747
        {
            int l1 = gen_new_label();
A
aurel32 已提交
6748
            TCGv_i32 fp0;
6749

A
aurel32 已提交
6750 6751 6752 6753
            if (ft != 0) {
                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
            }
            fp0 = tcg_temp_new_i32();
6754 6755
            gen_load_fpr32(fp0, fs);
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6756
            tcg_temp_free_i32(fp0);
6757 6758
            gen_set_label(l1);
        }
6759 6760
        opn = "movz.s";
        break;
6761
    case OPC_MOVN_S:
6762 6763
        {
            int l1 = gen_new_label();
A
aurel32 已提交
6764 6765 6766 6767 6768 6769 6770 6771 6772 6773
            TCGv_i32 fp0;

            if (ft != 0) {
                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
                fp0 = tcg_temp_new_i32();
                gen_load_fpr32(fp0, fs);
                gen_store_fpr32(fp0, fd);
                tcg_temp_free_i32(fp0);
                gen_set_label(l1);
            }
6774
        }
6775 6776
        opn = "movn.s";
        break;
6777
    case OPC_RECIP_S:
6778
        check_cop1x(ctx);
6779
        {
P
pbrook 已提交
6780
            TCGv_i32 fp0 = tcg_temp_new_i32();
6781 6782

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6783
            gen_helper_float_recip_s(fp0, fp0);
6784
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6785
            tcg_temp_free_i32(fp0);
6786
        }
T
ths 已提交
6787 6788
        opn = "recip.s";
        break;
6789
    case OPC_RSQRT_S:
6790
        check_cop1x(ctx);
6791
        {
P
pbrook 已提交
6792
            TCGv_i32 fp0 = tcg_temp_new_i32();
6793 6794

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6795
            gen_helper_float_rsqrt_s(fp0, fp0);
6796
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6797
            tcg_temp_free_i32(fp0);
6798
        }
T
ths 已提交
6799 6800
        opn = "rsqrt.s";
        break;
6801
    case OPC_RECIP2_S:
6802
        check_cp1_64bitmode(ctx);
6803
        {
P
pbrook 已提交
6804 6805
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6806 6807 6808

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, fd);
P
pbrook 已提交
6809 6810
            gen_helper_float_recip2_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6811
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6812
            tcg_temp_free_i32(fp0);
6813
        }
T
ths 已提交
6814 6815
        opn = "recip2.s";
        break;
6816
    case OPC_RECIP1_S:
6817
        check_cp1_64bitmode(ctx);
6818
        {
P
pbrook 已提交
6819
            TCGv_i32 fp0 = tcg_temp_new_i32();
6820 6821

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6822
            gen_helper_float_recip1_s(fp0, fp0);
6823
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6824
            tcg_temp_free_i32(fp0);
6825
        }
T
ths 已提交
6826 6827
        opn = "recip1.s";
        break;
6828
    case OPC_RSQRT1_S:
6829
        check_cp1_64bitmode(ctx);
6830
        {
P
pbrook 已提交
6831
            TCGv_i32 fp0 = tcg_temp_new_i32();
6832 6833

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6834
            gen_helper_float_rsqrt1_s(fp0, fp0);
6835
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6836
            tcg_temp_free_i32(fp0);
6837
        }
T
ths 已提交
6838 6839
        opn = "rsqrt1.s";
        break;
6840
    case OPC_RSQRT2_S:
6841
        check_cp1_64bitmode(ctx);
6842
        {
P
pbrook 已提交
6843 6844
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
6845 6846 6847

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
P
pbrook 已提交
6848 6849
            gen_helper_float_rsqrt2_s(fp0, fp0, fp1);
            tcg_temp_free_i32(fp1);
6850
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6851
            tcg_temp_free_i32(fp0);
6852
        }
T
ths 已提交
6853 6854
        opn = "rsqrt2.s";
        break;
6855
    case OPC_CVT_D_S:
6856
        check_cp1_registers(ctx, fd);
6857
        {
P
pbrook 已提交
6858 6859
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6860 6861

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6862 6863
            gen_helper_float_cvtd_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6864
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6865
            tcg_temp_free_i64(fp64);
6866
        }
6867 6868
        opn = "cvt.d.s";
        break;
6869
    case OPC_CVT_W_S:
6870
        {
P
pbrook 已提交
6871
            TCGv_i32 fp0 = tcg_temp_new_i32();
6872 6873

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
6874
            gen_helper_float_cvtw_s(fp0, fp0);
6875
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
6876
            tcg_temp_free_i32(fp0);
6877
        }
6878 6879
        opn = "cvt.w.s";
        break;
6880
    case OPC_CVT_L_S:
6881
        check_cp1_64bitmode(ctx);
6882
        {
P
pbrook 已提交
6883 6884
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
6885 6886

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
6887 6888
            gen_helper_float_cvtl_s(fp64, fp32);
            tcg_temp_free_i32(fp32);
6889
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6890
            tcg_temp_free_i64(fp64);
6891
        }
6892 6893
        opn = "cvt.l.s";
        break;
6894
    case OPC_CVT_PS_S:
6895
        check_cp1_64bitmode(ctx);
6896
        {
P
pbrook 已提交
6897 6898 6899
            TCGv_i64 fp64 = tcg_temp_new_i64();
            TCGv_i32 fp32_0 = tcg_temp_new_i32();
            TCGv_i32 fp32_1 = tcg_temp_new_i32();
6900 6901 6902

            gen_load_fpr32(fp32_0, fs);
            gen_load_fpr32(fp32_1, ft);
P
pbrook 已提交
6903
            tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1);
P
pbrook 已提交
6904 6905
            tcg_temp_free_i32(fp32_1);
            tcg_temp_free_i32(fp32_0);
P
pbrook 已提交
6906
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
6907
            tcg_temp_free_i64(fp64);
6908
        }
6909 6910
        opn = "cvt.ps.s";
        break;
6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926
    case OPC_CMP_F_S:
    case OPC_CMP_UN_S:
    case OPC_CMP_EQ_S:
    case OPC_CMP_UEQ_S:
    case OPC_CMP_OLT_S:
    case OPC_CMP_ULT_S:
    case OPC_CMP_OLE_S:
    case OPC_CMP_ULE_S:
    case OPC_CMP_SF_S:
    case OPC_CMP_NGLE_S:
    case OPC_CMP_SEQ_S:
    case OPC_CMP_NGL_S:
    case OPC_CMP_LT_S:
    case OPC_CMP_NGE_S:
    case OPC_CMP_LE_S:
    case OPC_CMP_NGT_S:
6927 6928 6929 6930 6931 6932
        if (ctx->opcode & (1 << 6)) {
            gen_cmpabs_s(ctx, func-48, ft, fs, cc);
            opn = condnames_abs[func-48];
        } else {
            gen_cmp_s(ctx, func-48, ft, fs, cc);
            opn = condnames[func-48];
6933
        }
6934
        break;
6935
    case OPC_ADD_D:
6936
        check_cp1_registers(ctx, fs | ft | fd);
6937
        {
P
pbrook 已提交
6938 6939
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
6940 6941 6942

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
6943 6944
            gen_helper_float_add_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
6945
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
6946
            tcg_temp_free_i64(fp0);
6947
        }
B
bellard 已提交
6948
        opn = "add.d";
6949
        optype = BINOP;
B
bellard 已提交
6950
        break;
6951
    case OPC_SUB_D:
6952
        check_cp1_registers(ctx, fs | ft | fd);
6953
        {
P
pbrook 已提交
6954 6955
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
6956 6957 6958

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
6959 6960
            gen_helper_float_sub_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
6961
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
6962
            tcg_temp_free_i64(fp0);
6963
        }
B
bellard 已提交
6964
        opn = "sub.d";
6965
        optype = BINOP;
B
bellard 已提交
6966
        break;
6967
    case OPC_MUL_D:
6968
        check_cp1_registers(ctx, fs | ft | fd);
6969
        {
P
pbrook 已提交
6970 6971
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
6972 6973 6974

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
6975 6976
            gen_helper_float_mul_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
6977
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
6978
            tcg_temp_free_i64(fp0);
6979
        }
B
bellard 已提交
6980
        opn = "mul.d";
6981
        optype = BINOP;
B
bellard 已提交
6982
        break;
6983
    case OPC_DIV_D:
6984
        check_cp1_registers(ctx, fs | ft | fd);
6985
        {
P
pbrook 已提交
6986 6987
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
6988 6989 6990

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
6991 6992
            gen_helper_float_div_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
6993
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
6994
            tcg_temp_free_i64(fp0);
6995
        }
B
bellard 已提交
6996
        opn = "div.d";
6997
        optype = BINOP;
B
bellard 已提交
6998
        break;
6999
    case OPC_SQRT_D:
7000
        check_cp1_registers(ctx, fs | fd);
7001
        {
P
pbrook 已提交
7002
            TCGv_i64 fp0 = tcg_temp_new_i64();
7003 7004

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7005
            gen_helper_float_sqrt_d(fp0, fp0);
7006
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7007
            tcg_temp_free_i64(fp0);
7008
        }
B
bellard 已提交
7009 7010
        opn = "sqrt.d";
        break;
7011
    case OPC_ABS_D:
7012
        check_cp1_registers(ctx, fs | fd);
7013
        {
P
pbrook 已提交
7014
            TCGv_i64 fp0 = tcg_temp_new_i64();
7015 7016

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7017
            gen_helper_float_abs_d(fp0, fp0);
7018
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7019
            tcg_temp_free_i64(fp0);
7020
        }
B
bellard 已提交
7021 7022
        opn = "abs.d";
        break;
7023
    case OPC_MOV_D:
7024
        check_cp1_registers(ctx, fs | fd);
7025
        {
P
pbrook 已提交
7026
            TCGv_i64 fp0 = tcg_temp_new_i64();
7027 7028 7029

            gen_load_fpr64(ctx, fp0, fs);
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7030
            tcg_temp_free_i64(fp0);
7031
        }
B
bellard 已提交
7032 7033
        opn = "mov.d";
        break;
7034
    case OPC_NEG_D:
7035
        check_cp1_registers(ctx, fs | fd);
7036
        {
P
pbrook 已提交
7037
            TCGv_i64 fp0 = tcg_temp_new_i64();
7038 7039

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7040
            gen_helper_float_chs_d(fp0, fp0);
7041
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7042
            tcg_temp_free_i64(fp0);
7043
        }
B
bellard 已提交
7044 7045
        opn = "neg.d";
        break;
7046
    case OPC_ROUND_L_D:
7047
        check_cp1_64bitmode(ctx);
7048
        {
P
pbrook 已提交
7049
            TCGv_i64 fp0 = tcg_temp_new_i64();
7050 7051

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7052
            gen_helper_float_roundl_d(fp0, fp0);
7053
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7054
            tcg_temp_free_i64(fp0);
7055
        }
7056 7057
        opn = "round.l.d";
        break;
7058
    case OPC_TRUNC_L_D:
7059
        check_cp1_64bitmode(ctx);
7060
        {
P
pbrook 已提交
7061
            TCGv_i64 fp0 = tcg_temp_new_i64();
7062 7063

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7064
            gen_helper_float_truncl_d(fp0, fp0);
7065
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7066
            tcg_temp_free_i64(fp0);
7067
        }
7068 7069
        opn = "trunc.l.d";
        break;
7070
    case OPC_CEIL_L_D:
7071
        check_cp1_64bitmode(ctx);
7072
        {
P
pbrook 已提交
7073
            TCGv_i64 fp0 = tcg_temp_new_i64();
7074 7075

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7076
            gen_helper_float_ceill_d(fp0, fp0);
7077
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7078
            tcg_temp_free_i64(fp0);
7079
        }
7080 7081
        opn = "ceil.l.d";
        break;
7082
    case OPC_FLOOR_L_D:
7083
        check_cp1_64bitmode(ctx);
7084
        {
P
pbrook 已提交
7085
            TCGv_i64 fp0 = tcg_temp_new_i64();
7086 7087

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7088
            gen_helper_float_floorl_d(fp0, fp0);
7089
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7090
            tcg_temp_free_i64(fp0);
7091
        }
7092 7093
        opn = "floor.l.d";
        break;
7094
    case OPC_ROUND_W_D:
7095
        check_cp1_registers(ctx, fs);
7096
        {
P
pbrook 已提交
7097 7098
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7099 7100

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7101 7102
            gen_helper_float_roundw_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7103
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7104
            tcg_temp_free_i32(fp32);
7105
        }
B
bellard 已提交
7106 7107
        opn = "round.w.d";
        break;
7108
    case OPC_TRUNC_W_D:
7109
        check_cp1_registers(ctx, fs);
7110
        {
P
pbrook 已提交
7111 7112
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7113 7114

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7115 7116
            gen_helper_float_truncw_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7117
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7118
            tcg_temp_free_i32(fp32);
7119
        }
B
bellard 已提交
7120 7121
        opn = "trunc.w.d";
        break;
7122
    case OPC_CEIL_W_D:
7123
        check_cp1_registers(ctx, fs);
7124
        {
P
pbrook 已提交
7125 7126
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7127 7128

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7129 7130
            gen_helper_float_ceilw_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7131
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7132
            tcg_temp_free_i32(fp32);
7133
        }
B
bellard 已提交
7134 7135
        opn = "ceil.w.d";
        break;
7136
    case OPC_FLOOR_W_D:
7137
        check_cp1_registers(ctx, fs);
7138
        {
P
pbrook 已提交
7139 7140
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7141 7142

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7143 7144
            gen_helper_float_floorw_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7145
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7146
            tcg_temp_free_i32(fp32);
7147
        }
7148
        opn = "floor.w.d";
B
bellard 已提交
7149
        break;
7150
    case OPC_MOVCF_D:
7151
        gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
7152
        opn = "movcf.d";
7153
        break;
7154
    case OPC_MOVZ_D:
7155 7156
        {
            int l1 = gen_new_label();
A
aurel32 已提交
7157
            TCGv_i64 fp0;
7158

A
aurel32 已提交
7159 7160 7161 7162
            if (ft != 0) {
                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
            }
            fp0 = tcg_temp_new_i64();
7163 7164
            gen_load_fpr64(ctx, fp0, fs);
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7165
            tcg_temp_free_i64(fp0);
7166 7167
            gen_set_label(l1);
        }
7168 7169
        opn = "movz.d";
        break;
7170
    case OPC_MOVN_D:
7171 7172
        {
            int l1 = gen_new_label();
A
aurel32 已提交
7173 7174 7175 7176 7177 7178 7179 7180 7181 7182
            TCGv_i64 fp0;

            if (ft != 0) {
                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
                fp0 = tcg_temp_new_i64();
                gen_load_fpr64(ctx, fp0, fs);
                gen_store_fpr64(ctx, fp0, fd);
                tcg_temp_free_i64(fp0);
                gen_set_label(l1);
            }
7183
        }
7184
        opn = "movn.d";
B
bellard 已提交
7185
        break;
7186
    case OPC_RECIP_D:
7187
        check_cp1_64bitmode(ctx);
7188
        {
P
pbrook 已提交
7189
            TCGv_i64 fp0 = tcg_temp_new_i64();
7190 7191

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7192
            gen_helper_float_recip_d(fp0, fp0);
7193
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7194
            tcg_temp_free_i64(fp0);
7195
        }
T
ths 已提交
7196 7197
        opn = "recip.d";
        break;
7198
    case OPC_RSQRT_D:
7199
        check_cp1_64bitmode(ctx);
7200
        {
P
pbrook 已提交
7201
            TCGv_i64 fp0 = tcg_temp_new_i64();
7202 7203

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7204
            gen_helper_float_rsqrt_d(fp0, fp0);
7205
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7206
            tcg_temp_free_i64(fp0);
7207
        }
T
ths 已提交
7208 7209
        opn = "rsqrt.d";
        break;
7210
    case OPC_RECIP2_D:
7211
        check_cp1_64bitmode(ctx);
7212
        {
P
pbrook 已提交
7213 7214
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7215 7216 7217

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7218 7219
            gen_helper_float_recip2_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7220
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7221
            tcg_temp_free_i64(fp0);
7222
        }
T
ths 已提交
7223 7224
        opn = "recip2.d";
        break;
7225
    case OPC_RECIP1_D:
7226
        check_cp1_64bitmode(ctx);
7227
        {
P
pbrook 已提交
7228
            TCGv_i64 fp0 = tcg_temp_new_i64();
7229 7230

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7231
            gen_helper_float_recip1_d(fp0, fp0);
7232
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7233
            tcg_temp_free_i64(fp0);
7234
        }
T
ths 已提交
7235 7236
        opn = "recip1.d";
        break;
7237
    case OPC_RSQRT1_D:
7238
        check_cp1_64bitmode(ctx);
7239
        {
P
pbrook 已提交
7240
            TCGv_i64 fp0 = tcg_temp_new_i64();
7241 7242

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7243
            gen_helper_float_rsqrt1_d(fp0, fp0);
7244
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7245
            tcg_temp_free_i64(fp0);
7246
        }
T
ths 已提交
7247 7248
        opn = "rsqrt1.d";
        break;
7249
    case OPC_RSQRT2_D:
7250
        check_cp1_64bitmode(ctx);
7251
        {
P
pbrook 已提交
7252 7253
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7254 7255 7256

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7257 7258
            gen_helper_float_rsqrt2_d(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7259
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7260
            tcg_temp_free_i64(fp0);
7261
        }
T
ths 已提交
7262 7263
        opn = "rsqrt2.d";
        break;
7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279
    case OPC_CMP_F_D:
    case OPC_CMP_UN_D:
    case OPC_CMP_EQ_D:
    case OPC_CMP_UEQ_D:
    case OPC_CMP_OLT_D:
    case OPC_CMP_ULT_D:
    case OPC_CMP_OLE_D:
    case OPC_CMP_ULE_D:
    case OPC_CMP_SF_D:
    case OPC_CMP_NGLE_D:
    case OPC_CMP_SEQ_D:
    case OPC_CMP_NGL_D:
    case OPC_CMP_LT_D:
    case OPC_CMP_NGE_D:
    case OPC_CMP_LE_D:
    case OPC_CMP_NGT_D:
7280 7281 7282 7283 7284 7285
        if (ctx->opcode & (1 << 6)) {
            gen_cmpabs_d(ctx, func-48, ft, fs, cc);
            opn = condnames_abs[func-48];
        } else {
            gen_cmp_d(ctx, func-48, ft, fs, cc);
            opn = condnames[func-48];
7286
        }
B
bellard 已提交
7287
        break;
7288
    case OPC_CVT_S_D:
7289
        check_cp1_registers(ctx, fs);
7290
        {
P
pbrook 已提交
7291 7292
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7293 7294

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7295 7296
            gen_helper_float_cvts_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7297
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7298
            tcg_temp_free_i32(fp32);
7299
        }
7300 7301
        opn = "cvt.s.d";
        break;
7302
    case OPC_CVT_W_D:
7303
        check_cp1_registers(ctx, fs);
7304
        {
P
pbrook 已提交
7305 7306
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7307 7308

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7309 7310
            gen_helper_float_cvtw_d(fp32, fp64);
            tcg_temp_free_i64(fp64);
7311
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7312
            tcg_temp_free_i32(fp32);
7313
        }
7314 7315
        opn = "cvt.w.d";
        break;
7316
    case OPC_CVT_L_D:
7317
        check_cp1_64bitmode(ctx);
7318
        {
P
pbrook 已提交
7319
            TCGv_i64 fp0 = tcg_temp_new_i64();
7320 7321

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7322
            gen_helper_float_cvtl_d(fp0, fp0);
7323
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7324
            tcg_temp_free_i64(fp0);
7325
        }
7326 7327
        opn = "cvt.l.d";
        break;
7328
    case OPC_CVT_S_W:
7329
        {
P
pbrook 已提交
7330
            TCGv_i32 fp0 = tcg_temp_new_i32();
7331 7332

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
7333
            gen_helper_float_cvts_w(fp0, fp0);
7334
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
7335
            tcg_temp_free_i32(fp0);
7336
        }
7337
        opn = "cvt.s.w";
B
bellard 已提交
7338
        break;
7339
    case OPC_CVT_D_W:
7340
        check_cp1_registers(ctx, fd);
7341
        {
P
pbrook 已提交
7342 7343
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7344 7345

            gen_load_fpr32(fp32, fs);
P
pbrook 已提交
7346 7347
            gen_helper_float_cvtd_w(fp64, fp32);
            tcg_temp_free_i32(fp32);
7348
            gen_store_fpr64(ctx, fp64, fd);
P
pbrook 已提交
7349
            tcg_temp_free_i64(fp64);
7350
        }
7351 7352
        opn = "cvt.d.w";
        break;
7353
    case OPC_CVT_S_L:
7354
        check_cp1_64bitmode(ctx);
7355
        {
P
pbrook 已提交
7356 7357
            TCGv_i32 fp32 = tcg_temp_new_i32();
            TCGv_i64 fp64 = tcg_temp_new_i64();
7358 7359

            gen_load_fpr64(ctx, fp64, fs);
P
pbrook 已提交
7360 7361
            gen_helper_float_cvts_l(fp32, fp64);
            tcg_temp_free_i64(fp64);
7362
            gen_store_fpr32(fp32, fd);
P
pbrook 已提交
7363
            tcg_temp_free_i32(fp32);
7364
        }
7365 7366
        opn = "cvt.s.l";
        break;
7367
    case OPC_CVT_D_L:
7368
        check_cp1_64bitmode(ctx);
7369
        {
P
pbrook 已提交
7370
            TCGv_i64 fp0 = tcg_temp_new_i64();
7371 7372

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7373
            gen_helper_float_cvtd_l(fp0, fp0);
7374
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7375
            tcg_temp_free_i64(fp0);
7376
        }
7377 7378
        opn = "cvt.d.l";
        break;
7379
    case OPC_CVT_PS_PW:
7380
        check_cp1_64bitmode(ctx);
7381
        {
P
pbrook 已提交
7382
            TCGv_i64 fp0 = tcg_temp_new_i64();
7383 7384

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7385
            gen_helper_float_cvtps_pw(fp0, fp0);
7386
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7387
            tcg_temp_free_i64(fp0);
7388
        }
7389 7390
        opn = "cvt.ps.pw";
        break;
7391
    case OPC_ADD_PS:
7392
        check_cp1_64bitmode(ctx);
7393
        {
P
pbrook 已提交
7394 7395
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7396 7397 7398

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7399 7400
            gen_helper_float_add_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7401
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7402
            tcg_temp_free_i64(fp0);
7403
        }
7404
        opn = "add.ps";
B
bellard 已提交
7405
        break;
7406
    case OPC_SUB_PS:
7407
        check_cp1_64bitmode(ctx);
7408
        {
P
pbrook 已提交
7409 7410
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7411 7412 7413

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7414 7415
            gen_helper_float_sub_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7416
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7417
            tcg_temp_free_i64(fp0);
7418
        }
7419
        opn = "sub.ps";
B
bellard 已提交
7420
        break;
7421
    case OPC_MUL_PS:
7422
        check_cp1_64bitmode(ctx);
7423
        {
P
pbrook 已提交
7424 7425
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7426 7427 7428

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7429 7430
            gen_helper_float_mul_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7431
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7432
            tcg_temp_free_i64(fp0);
7433
        }
7434
        opn = "mul.ps";
B
bellard 已提交
7435
        break;
7436
    case OPC_ABS_PS:
7437
        check_cp1_64bitmode(ctx);
7438
        {
P
pbrook 已提交
7439
            TCGv_i64 fp0 = tcg_temp_new_i64();
7440 7441

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7442
            gen_helper_float_abs_ps(fp0, fp0);
7443
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7444
            tcg_temp_free_i64(fp0);
7445
        }
7446
        opn = "abs.ps";
B
bellard 已提交
7447
        break;
7448
    case OPC_MOV_PS:
7449
        check_cp1_64bitmode(ctx);
7450
        {
P
pbrook 已提交
7451
            TCGv_i64 fp0 = tcg_temp_new_i64();
7452 7453 7454

            gen_load_fpr64(ctx, fp0, fs);
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7455
            tcg_temp_free_i64(fp0);
7456
        }
7457
        opn = "mov.ps";
B
bellard 已提交
7458
        break;
7459
    case OPC_NEG_PS:
7460
        check_cp1_64bitmode(ctx);
7461
        {
P
pbrook 已提交
7462
            TCGv_i64 fp0 = tcg_temp_new_i64();
7463 7464

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7465
            gen_helper_float_chs_ps(fp0, fp0);
7466
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7467
            tcg_temp_free_i64(fp0);
7468
        }
7469
        opn = "neg.ps";
B
bellard 已提交
7470
        break;
7471
    case OPC_MOVCF_PS:
7472
        check_cp1_64bitmode(ctx);
7473
        gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
7474
        opn = "movcf.ps";
B
bellard 已提交
7475
        break;
7476
    case OPC_MOVZ_PS:
7477
        check_cp1_64bitmode(ctx);
7478 7479
        {
            int l1 = gen_new_label();
A
aurel32 已提交
7480
            TCGv_i64 fp0;
7481

A
aurel32 已提交
7482 7483 7484 7485 7486 7487
            if (ft != 0)
                tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1);
            fp0 = tcg_temp_new_i64();
            gen_load_fpr64(ctx, fp0, fs);
            gen_store_fpr64(ctx, fp0, fd);
            tcg_temp_free_i64(fp0);
7488 7489
            gen_set_label(l1);
        }
7490
        opn = "movz.ps";
B
bellard 已提交
7491
        break;
7492
    case OPC_MOVN_PS:
7493
        check_cp1_64bitmode(ctx);
7494 7495
        {
            int l1 = gen_new_label();
A
aurel32 已提交
7496
            TCGv_i64 fp0;
A
aurel32 已提交
7497 7498 7499 7500 7501 7502 7503 7504 7505

            if (ft != 0) {
                tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1);
                fp0 = tcg_temp_new_i64();
                gen_load_fpr64(ctx, fp0, fs);
                gen_store_fpr64(ctx, fp0, fd);
                tcg_temp_free_i64(fp0);
                gen_set_label(l1);
            }
7506
        }
7507
        opn = "movn.ps";
B
bellard 已提交
7508
        break;
7509
    case OPC_ADDR_PS:
7510
        check_cp1_64bitmode(ctx);
7511
        {
P
pbrook 已提交
7512 7513
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7514 7515 7516

            gen_load_fpr64(ctx, fp0, ft);
            gen_load_fpr64(ctx, fp1, fs);
P
pbrook 已提交
7517 7518
            gen_helper_float_addr_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7519
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7520
            tcg_temp_free_i64(fp0);
7521
        }
7522 7523
        opn = "addr.ps";
        break;
7524
    case OPC_MULR_PS:
7525
        check_cp1_64bitmode(ctx);
7526
        {
P
pbrook 已提交
7527 7528
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7529 7530 7531

            gen_load_fpr64(ctx, fp0, ft);
            gen_load_fpr64(ctx, fp1, fs);
P
pbrook 已提交
7532 7533
            gen_helper_float_mulr_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7534
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7535
            tcg_temp_free_i64(fp0);
7536
        }
T
ths 已提交
7537 7538
        opn = "mulr.ps";
        break;
7539
    case OPC_RECIP2_PS:
7540
        check_cp1_64bitmode(ctx);
7541
        {
P
pbrook 已提交
7542 7543
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7544 7545 7546

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, fd);
P
pbrook 已提交
7547 7548
            gen_helper_float_recip2_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7549
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7550
            tcg_temp_free_i64(fp0);
7551
        }
T
ths 已提交
7552 7553
        opn = "recip2.ps";
        break;
7554
    case OPC_RECIP1_PS:
7555
        check_cp1_64bitmode(ctx);
7556
        {
P
pbrook 已提交
7557
            TCGv_i64 fp0 = tcg_temp_new_i64();
7558 7559

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7560
            gen_helper_float_recip1_ps(fp0, fp0);
7561
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7562
            tcg_temp_free_i64(fp0);
7563
        }
T
ths 已提交
7564 7565
        opn = "recip1.ps";
        break;
7566
    case OPC_RSQRT1_PS:
7567
        check_cp1_64bitmode(ctx);
7568
        {
P
pbrook 已提交
7569
            TCGv_i64 fp0 = tcg_temp_new_i64();
7570 7571

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7572
            gen_helper_float_rsqrt1_ps(fp0, fp0);
7573
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7574
            tcg_temp_free_i64(fp0);
7575
        }
T
ths 已提交
7576 7577
        opn = "rsqrt1.ps";
        break;
7578
    case OPC_RSQRT2_PS:
7579
        check_cp1_64bitmode(ctx);
7580
        {
P
pbrook 已提交
7581 7582
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
7583 7584 7585

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
P
pbrook 已提交
7586 7587
            gen_helper_float_rsqrt2_ps(fp0, fp0, fp1);
            tcg_temp_free_i64(fp1);
7588
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7589
            tcg_temp_free_i64(fp0);
7590
        }
T
ths 已提交
7591 7592
        opn = "rsqrt2.ps";
        break;
7593
    case OPC_CVT_S_PU:
7594
        check_cp1_64bitmode(ctx);
7595
        {
P
pbrook 已提交
7596
            TCGv_i32 fp0 = tcg_temp_new_i32();
7597 7598

            gen_load_fpr32h(fp0, fs);
P
pbrook 已提交
7599
            gen_helper_float_cvts_pu(fp0, fp0);
7600
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
7601
            tcg_temp_free_i32(fp0);
7602
        }
7603
        opn = "cvt.s.pu";
7604
        break;
7605
    case OPC_CVT_PW_PS:
7606
        check_cp1_64bitmode(ctx);
7607
        {
P
pbrook 已提交
7608
            TCGv_i64 fp0 = tcg_temp_new_i64();
7609 7610

            gen_load_fpr64(ctx, fp0, fs);
P
pbrook 已提交
7611
            gen_helper_float_cvtpw_ps(fp0, fp0);
7612
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7613
            tcg_temp_free_i64(fp0);
7614
        }
7615
        opn = "cvt.pw.ps";
B
bellard 已提交
7616
        break;
7617
    case OPC_CVT_S_PL:
7618
        check_cp1_64bitmode(ctx);
7619
        {
P
pbrook 已提交
7620
            TCGv_i32 fp0 = tcg_temp_new_i32();
7621 7622

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
7623
            gen_helper_float_cvts_pl(fp0, fp0);
7624
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
7625
            tcg_temp_free_i32(fp0);
7626
        }
7627
        opn = "cvt.s.pl";
B
bellard 已提交
7628
        break;
7629
    case OPC_PLL_PS:
7630
        check_cp1_64bitmode(ctx);
7631
        {
P
pbrook 已提交
7632 7633
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
7634 7635 7636 7637 7638

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_store_fpr32h(fp0, fd);
            gen_store_fpr32(fp1, fd);
P
pbrook 已提交
7639 7640
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7641
        }
7642
        opn = "pll.ps";
B
bellard 已提交
7643
        break;
7644
    case OPC_PLU_PS:
7645
        check_cp1_64bitmode(ctx);
7646
        {
P
pbrook 已提交
7647 7648
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
7649 7650 7651 7652 7653

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32h(fp1, ft);
            gen_store_fpr32(fp1, fd);
            gen_store_fpr32h(fp0, fd);
P
pbrook 已提交
7654 7655
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7656
        }
7657 7658
        opn = "plu.ps";
        break;
7659
    case OPC_PUL_PS:
7660
        check_cp1_64bitmode(ctx);
7661
        {
P
pbrook 已提交
7662 7663
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
7664 7665 7666 7667 7668

            gen_load_fpr32h(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_store_fpr32(fp1, fd);
            gen_store_fpr32h(fp0, fd);
P
pbrook 已提交
7669 7670
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7671
        }
7672 7673
        opn = "pul.ps";
        break;
7674
    case OPC_PUU_PS:
7675
        check_cp1_64bitmode(ctx);
7676
        {
P
pbrook 已提交
7677 7678
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
7679 7680 7681 7682 7683

            gen_load_fpr32h(fp0, fs);
            gen_load_fpr32h(fp1, ft);
            gen_store_fpr32(fp1, fd);
            gen_store_fpr32h(fp0, fd);
P
pbrook 已提交
7684 7685
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7686
        }
7687 7688
        opn = "puu.ps";
        break;
7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704
    case OPC_CMP_F_PS:
    case OPC_CMP_UN_PS:
    case OPC_CMP_EQ_PS:
    case OPC_CMP_UEQ_PS:
    case OPC_CMP_OLT_PS:
    case OPC_CMP_ULT_PS:
    case OPC_CMP_OLE_PS:
    case OPC_CMP_ULE_PS:
    case OPC_CMP_SF_PS:
    case OPC_CMP_NGLE_PS:
    case OPC_CMP_SEQ_PS:
    case OPC_CMP_NGL_PS:
    case OPC_CMP_LT_PS:
    case OPC_CMP_NGE_PS:
    case OPC_CMP_LE_PS:
    case OPC_CMP_NGT_PS:
7705 7706 7707 7708 7709 7710
        if (ctx->opcode & (1 << 6)) {
            gen_cmpabs_ps(ctx, func-48, ft, fs, cc);
            opn = condnames_abs[func-48];
        } else {
            gen_cmp_ps(ctx, func-48, ft, fs, cc);
            opn = condnames[func-48];
7711
        }
B
bellard 已提交
7712
        break;
7713
    default:
7714
        MIPS_INVAL(opn);
7715
        generate_exception (ctx, EXCP_RI);
B
bellard 已提交
7716 7717
        return;
    }
B
Blue Swirl 已提交
7718
    (void)opn; /* avoid a compiler warning */
7719 7720
    switch (optype) {
    case BINOP:
B
bellard 已提交
7721
        MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
7722 7723 7724 7725 7726
        break;
    case CMPOP:
        MIPS_DEBUG("%s %s,%s", opn, fregnames[fs], fregnames[ft]);
        break;
    default:
B
bellard 已提交
7727
        MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
7728 7729
        break;
    }
B
bellard 已提交
7730
}
B
bellard 已提交
7731

7732
/* Coprocessor 3 (FPU) */
7733 7734
static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
                           int fd, int fs, int base, int index)
7735
{
7736
    const char *opn = "extended float load/store";
T
ths 已提交
7737
    int store = 0;
A
aurel32 已提交
7738
    TCGv t0 = tcg_temp_new();
7739

T
ths 已提交
7740
    if (base == 0) {
7741
        gen_load_gpr(t0, index);
T
ths 已提交
7742
    } else if (index == 0) {
7743
        gen_load_gpr(t0, base);
T
ths 已提交
7744
    } else {
7745
        gen_load_gpr(t0, index);
7746
        gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
T
ths 已提交
7747
    }
7748
    /* Don't do NOP if destination is zero: we must perform the actual
7749
       memory access. */
A
aurel32 已提交
7750
    save_cpu_state(ctx, 0);
7751 7752
    switch (opc) {
    case OPC_LWXC1:
7753
        check_cop1x(ctx);
7754
        {
P
pbrook 已提交
7755
            TCGv_i32 fp0 = tcg_temp_new_i32();
7756

A
aurel32 已提交
7757 7758
            tcg_gen_qemu_ld32s(t0, t0, ctx->mem_idx);
            tcg_gen_trunc_tl_i32(fp0, t0);
7759
            gen_store_fpr32(fp0, fd);
P
pbrook 已提交
7760
            tcg_temp_free_i32(fp0);
7761
        }
7762 7763 7764
        opn = "lwxc1";
        break;
    case OPC_LDXC1:
7765 7766
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd);
7767
        {
P
pbrook 已提交
7768
            TCGv_i64 fp0 = tcg_temp_new_i64();
7769 7770 7771

            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7772
            tcg_temp_free_i64(fp0);
7773
        }
7774 7775 7776
        opn = "ldxc1";
        break;
    case OPC_LUXC1:
7777
        check_cp1_64bitmode(ctx);
7778
        tcg_gen_andi_tl(t0, t0, ~0x7);
7779
        {
P
pbrook 已提交
7780
            TCGv_i64 fp0 = tcg_temp_new_i64();
7781 7782 7783

            tcg_gen_qemu_ld64(fp0, t0, ctx->mem_idx);
            gen_store_fpr64(ctx, fp0, fd);
P
pbrook 已提交
7784
            tcg_temp_free_i64(fp0);
7785
        }
7786 7787 7788
        opn = "luxc1";
        break;
    case OPC_SWXC1:
7789
        check_cop1x(ctx);
7790
        {
P
pbrook 已提交
7791
            TCGv_i32 fp0 = tcg_temp_new_i32();
A
aurel32 已提交
7792
            TCGv t1 = tcg_temp_new();
7793 7794

            gen_load_fpr32(fp0, fs);
P
pbrook 已提交
7795 7796 7797
            tcg_gen_extu_i32_tl(t1, fp0);
            tcg_gen_qemu_st32(t1, t0, ctx->mem_idx);
            tcg_temp_free_i32(fp0);
A
aurel32 已提交
7798
            tcg_temp_free(t1);
7799
        }
7800
        opn = "swxc1";
T
ths 已提交
7801
        store = 1;
7802 7803
        break;
    case OPC_SDXC1:
7804 7805
        check_cop1x(ctx);
        check_cp1_registers(ctx, fs);
7806
        {
P
pbrook 已提交
7807
            TCGv_i64 fp0 = tcg_temp_new_i64();
7808 7809 7810

            gen_load_fpr64(ctx, fp0, fs);
            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
P
pbrook 已提交
7811
            tcg_temp_free_i64(fp0);
7812
        }
7813
        opn = "sdxc1";
T
ths 已提交
7814
        store = 1;
7815 7816
        break;
    case OPC_SUXC1:
7817
        check_cp1_64bitmode(ctx);
7818
        tcg_gen_andi_tl(t0, t0, ~0x7);
7819
        {
P
pbrook 已提交
7820
            TCGv_i64 fp0 = tcg_temp_new_i64();
7821 7822 7823

            gen_load_fpr64(ctx, fp0, fs);
            tcg_gen_qemu_st64(fp0, t0, ctx->mem_idx);
P
pbrook 已提交
7824
            tcg_temp_free_i64(fp0);
7825
        }
7826
        opn = "suxc1";
T
ths 已提交
7827
        store = 1;
7828 7829
        break;
    }
7830
    tcg_temp_free(t0);
B
Blue Swirl 已提交
7831
    (void)opn; (void)store; /* avoid compiler warnings */
T
ths 已提交
7832 7833
    MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
               regnames[index], regnames[base]);
7834 7835
}

7836 7837
static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
                            int fd, int fr, int fs, int ft)
7838
{
7839
    const char *opn = "flt3_arith";
7840 7841 7842

    switch (opc) {
    case OPC_ALNV_PS:
7843
        check_cp1_64bitmode(ctx);
7844
        {
P
pbrook 已提交
7845
            TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
7846 7847
            TCGv_i32 fp = tcg_temp_new_i32();
            TCGv_i32 fph = tcg_temp_new_i32();
7848 7849 7850
            int l1 = gen_new_label();
            int l2 = gen_new_label();

7851 7852 7853 7854
            gen_load_gpr(t0, fr);
            tcg_gen_andi_tl(t0, t0, 0x7);

            tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1);
A
aurel32 已提交
7855 7856 7857 7858
            gen_load_fpr32(fp, fs);
            gen_load_fpr32h(fph, fs);
            gen_store_fpr32(fp, fd);
            gen_store_fpr32h(fph, fd);
7859 7860
            tcg_gen_br(l2);
            gen_set_label(l1);
7861 7862
            tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2);
            tcg_temp_free(t0);
7863
#ifdef TARGET_WORDS_BIGENDIAN
A
aurel32 已提交
7864 7865 7866 7867
            gen_load_fpr32(fp, fs);
            gen_load_fpr32h(fph, ft);
            gen_store_fpr32h(fp, fd);
            gen_store_fpr32(fph, fd);
7868
#else
A
aurel32 已提交
7869 7870 7871 7872
            gen_load_fpr32h(fph, fs);
            gen_load_fpr32(fp, ft);
            gen_store_fpr32(fph, fd);
            gen_store_fpr32h(fp, fd);
7873 7874
#endif
            gen_set_label(l2);
A
aurel32 已提交
7875 7876
            tcg_temp_free_i32(fp);
            tcg_temp_free_i32(fph);
7877
        }
7878 7879 7880
        opn = "alnv.ps";
        break;
    case OPC_MADD_S:
7881
        check_cop1x(ctx);
7882
        {
P
pbrook 已提交
7883 7884 7885
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
            TCGv_i32 fp2 = tcg_temp_new_i32();
7886 7887 7888 7889

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_load_fpr32(fp2, fr);
P
pbrook 已提交
7890 7891 7892
            gen_helper_float_muladd_s(fp2, fp0, fp1, fp2);
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7893
            gen_store_fpr32(fp2, fd);
P
pbrook 已提交
7894
            tcg_temp_free_i32(fp2);
7895
        }
7896 7897 7898
        opn = "madd.s";
        break;
    case OPC_MADD_D:
7899 7900
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
7901
        {
P
pbrook 已提交
7902 7903 7904
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
7905 7906 7907 7908

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
7909 7910 7911
            gen_helper_float_muladd_d(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
7912
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
7913
            tcg_temp_free_i64(fp2);
7914
        }
7915 7916 7917
        opn = "madd.d";
        break;
    case OPC_MADD_PS:
7918
        check_cp1_64bitmode(ctx);
7919
        {
P
pbrook 已提交
7920 7921 7922
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
7923 7924 7925 7926

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
7927 7928 7929
            gen_helper_float_muladd_ps(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
7930
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
7931
            tcg_temp_free_i64(fp2);
7932
        }
7933 7934 7935
        opn = "madd.ps";
        break;
    case OPC_MSUB_S:
7936
        check_cop1x(ctx);
7937
        {
P
pbrook 已提交
7938 7939 7940
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
            TCGv_i32 fp2 = tcg_temp_new_i32();
7941 7942 7943 7944

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_load_fpr32(fp2, fr);
P
pbrook 已提交
7945 7946 7947
            gen_helper_float_mulsub_s(fp2, fp0, fp1, fp2);
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
7948
            gen_store_fpr32(fp2, fd);
P
pbrook 已提交
7949
            tcg_temp_free_i32(fp2);
7950
        }
7951 7952 7953
        opn = "msub.s";
        break;
    case OPC_MSUB_D:
7954 7955
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
7956
        {
P
pbrook 已提交
7957 7958 7959
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
7960 7961 7962 7963

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
7964 7965 7966
            gen_helper_float_mulsub_d(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
7967
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
7968
            tcg_temp_free_i64(fp2);
7969
        }
7970 7971 7972
        opn = "msub.d";
        break;
    case OPC_MSUB_PS:
7973
        check_cp1_64bitmode(ctx);
7974
        {
P
pbrook 已提交
7975 7976 7977
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
7978 7979 7980 7981

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
7982 7983 7984
            gen_helper_float_mulsub_ps(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
7985
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
7986
            tcg_temp_free_i64(fp2);
7987
        }
7988 7989 7990
        opn = "msub.ps";
        break;
    case OPC_NMADD_S:
7991
        check_cop1x(ctx);
7992
        {
P
pbrook 已提交
7993 7994 7995
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
            TCGv_i32 fp2 = tcg_temp_new_i32();
7996 7997 7998 7999

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_load_fpr32(fp2, fr);
P
pbrook 已提交
8000 8001 8002
            gen_helper_float_nmuladd_s(fp2, fp0, fp1, fp2);
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
8003
            gen_store_fpr32(fp2, fd);
P
pbrook 已提交
8004
            tcg_temp_free_i32(fp2);
8005
        }
8006 8007 8008
        opn = "nmadd.s";
        break;
    case OPC_NMADD_D:
8009 8010
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
8011
        {
P
pbrook 已提交
8012 8013 8014
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
8015 8016 8017 8018

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
8019 8020 8021
            gen_helper_float_nmuladd_d(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
8022
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
8023
            tcg_temp_free_i64(fp2);
8024
        }
8025 8026 8027
        opn = "nmadd.d";
        break;
    case OPC_NMADD_PS:
8028
        check_cp1_64bitmode(ctx);
8029
        {
P
pbrook 已提交
8030 8031 8032
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
8033 8034 8035 8036

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
8037 8038 8039
            gen_helper_float_nmuladd_ps(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
8040
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
8041
            tcg_temp_free_i64(fp2);
8042
        }
8043 8044 8045
        opn = "nmadd.ps";
        break;
    case OPC_NMSUB_S:
8046
        check_cop1x(ctx);
8047
        {
P
pbrook 已提交
8048 8049 8050
            TCGv_i32 fp0 = tcg_temp_new_i32();
            TCGv_i32 fp1 = tcg_temp_new_i32();
            TCGv_i32 fp2 = tcg_temp_new_i32();
8051 8052 8053 8054

            gen_load_fpr32(fp0, fs);
            gen_load_fpr32(fp1, ft);
            gen_load_fpr32(fp2, fr);
P
pbrook 已提交
8055 8056 8057
            gen_helper_float_nmulsub_s(fp2, fp0, fp1, fp2);
            tcg_temp_free_i32(fp0);
            tcg_temp_free_i32(fp1);
8058
            gen_store_fpr32(fp2, fd);
P
pbrook 已提交
8059
            tcg_temp_free_i32(fp2);
8060
        }
8061 8062 8063
        opn = "nmsub.s";
        break;
    case OPC_NMSUB_D:
8064 8065
        check_cop1x(ctx);
        check_cp1_registers(ctx, fd | fs | ft | fr);
8066
        {
P
pbrook 已提交
8067 8068 8069
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
8070 8071 8072 8073

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
8074 8075 8076
            gen_helper_float_nmulsub_d(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
8077
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
8078
            tcg_temp_free_i64(fp2);
8079
        }
8080 8081 8082
        opn = "nmsub.d";
        break;
    case OPC_NMSUB_PS:
8083
        check_cp1_64bitmode(ctx);
8084
        {
P
pbrook 已提交
8085 8086 8087
            TCGv_i64 fp0 = tcg_temp_new_i64();
            TCGv_i64 fp1 = tcg_temp_new_i64();
            TCGv_i64 fp2 = tcg_temp_new_i64();
8088 8089 8090 8091

            gen_load_fpr64(ctx, fp0, fs);
            gen_load_fpr64(ctx, fp1, ft);
            gen_load_fpr64(ctx, fp2, fr);
P
pbrook 已提交
8092 8093 8094
            gen_helper_float_nmulsub_ps(fp2, fp0, fp1, fp2);
            tcg_temp_free_i64(fp0);
            tcg_temp_free_i64(fp1);
8095
            gen_store_fpr64(ctx, fp2, fd);
P
pbrook 已提交
8096
            tcg_temp_free_i64(fp2);
8097
        }
8098 8099
        opn = "nmsub.ps";
        break;
8100 8101
    default:
        MIPS_INVAL(opn);
8102 8103 8104
        generate_exception (ctx, EXCP_RI);
        return;
    }
B
Blue Swirl 已提交
8105
    (void)opn; /* avoid a compiler warning */
8106 8107
    MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
               fregnames[fs], fregnames[ft]);
8108 8109
}

8110
static void
8111
gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd)
8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140
{
    TCGv t0;

    check_insn(env, ctx, ISA_MIPS32R2);
    t0 = tcg_temp_new();

    switch (rd) {
    case 0:
        save_cpu_state(ctx, 1);
        gen_helper_rdhwr_cpunum(t0);
        gen_store_gpr(t0, rt);
        break;
    case 1:
        save_cpu_state(ctx, 1);
        gen_helper_rdhwr_synci_step(t0);
        gen_store_gpr(t0, rt);
        break;
    case 2:
        save_cpu_state(ctx, 1);
        gen_helper_rdhwr_cc(t0);
        gen_store_gpr(t0, rt);
        break;
    case 3:
        save_cpu_state(ctx, 1);
        gen_helper_rdhwr_ccres(t0);
        gen_store_gpr(t0, rt);
        break;
    case 29:
#if defined(CONFIG_USER_ONLY)
8141
        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, tls_value));
8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155
        gen_store_gpr(t0, rt);
        break;
#else
        /* XXX: Some CPUs implement this in hardware.
           Not supported yet. */
#endif
    default:            /* Invalid */
        MIPS_INVAL("rdhwr");
        generate_exception(ctx, EXCP_RI);
        break;
    }
    tcg_temp_free(t0);
}

8156
static void handle_delay_slot (CPUMIPSState *env, DisasContext *ctx,
8157 8158 8159
                               int insn_bytes)
{
    if (ctx->hflags & MIPS_HFLAG_BMASK) {
8160
        int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
8161 8162 8163 8164 8165
        /* Branches completion */
        ctx->hflags &= ~MIPS_HFLAG_BMASK;
        ctx->bstate = BS_BRANCH;
        save_cpu_state(ctx, 0);
        /* FIXME: Need to clear can_do_io.  */
8166
        switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) {
8167 8168 8169
        case MIPS_HFLAG_B:
            /* unconditional branch */
            MIPS_DEBUG("unconditional branch");
8170 8171 8172
            if (proc_hflags & MIPS_HFLAG_BX) {
                tcg_gen_xori_i32(hflags, hflags, MIPS_HFLAG_M16);
            }
8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194
            gen_goto_tb(ctx, 0, ctx->btarget);
            break;
        case MIPS_HFLAG_BL:
            /* blikely taken case */
            MIPS_DEBUG("blikely branch taken");
            gen_goto_tb(ctx, 0, ctx->btarget);
            break;
        case MIPS_HFLAG_BC:
            /* Conditional branch */
            MIPS_DEBUG("conditional branch");
            {
                int l1 = gen_new_label();

                tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
                gen_goto_tb(ctx, 1, ctx->pc + insn_bytes);
                gen_set_label(l1);
                gen_goto_tb(ctx, 0, ctx->btarget);
            }
            break;
        case MIPS_HFLAG_BR:
            /* unconditional branch to register */
            MIPS_DEBUG("branch to register");
8195
            if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210
                TCGv t0 = tcg_temp_new();
                TCGv_i32 t1 = tcg_temp_new_i32();

                tcg_gen_andi_tl(t0, btarget, 0x1);
                tcg_gen_trunc_tl_i32(t1, t0);
                tcg_temp_free(t0);
                tcg_gen_andi_i32(hflags, hflags, ~(uint32_t)MIPS_HFLAG_M16);
                tcg_gen_shli_i32(t1, t1, MIPS_HFLAG_M16_SHIFT);
                tcg_gen_or_i32(hflags, hflags, t1);
                tcg_temp_free_i32(t1);

                tcg_gen_andi_tl(cpu_PC, btarget, ~(target_ulong)0x1);
            } else {
                tcg_gen_mov_tl(cpu_PC, btarget);
            }
8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223
            if (ctx->singlestep_enabled) {
                save_cpu_state(ctx, 0);
                gen_helper_0i(raise_exception, EXCP_DEBUG);
            }
            tcg_gen_exit_tb(0);
            break;
        default:
            MIPS_DEBUG("unknown branch");
            break;
        }
    }
}

8224
/* ISA extensions (ASEs) */
B
bellard 已提交
8225
/* MIPS16 extension to MIPS32 */
8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322

/* MIPS16 major opcodes */
enum {
  M16_OPC_ADDIUSP = 0x00,
  M16_OPC_ADDIUPC = 0x01,
  M16_OPC_B = 0x02,
  M16_OPC_JAL = 0x03,
  M16_OPC_BEQZ = 0x04,
  M16_OPC_BNEQZ = 0x05,
  M16_OPC_SHIFT = 0x06,
  M16_OPC_LD = 0x07,
  M16_OPC_RRIA = 0x08,
  M16_OPC_ADDIU8 = 0x09,
  M16_OPC_SLTI = 0x0a,
  M16_OPC_SLTIU = 0x0b,
  M16_OPC_I8 = 0x0c,
  M16_OPC_LI = 0x0d,
  M16_OPC_CMPI = 0x0e,
  M16_OPC_SD = 0x0f,
  M16_OPC_LB = 0x10,
  M16_OPC_LH = 0x11,
  M16_OPC_LWSP = 0x12,
  M16_OPC_LW = 0x13,
  M16_OPC_LBU = 0x14,
  M16_OPC_LHU = 0x15,
  M16_OPC_LWPC = 0x16,
  M16_OPC_LWU = 0x17,
  M16_OPC_SB = 0x18,
  M16_OPC_SH = 0x19,
  M16_OPC_SWSP = 0x1a,
  M16_OPC_SW = 0x1b,
  M16_OPC_RRR = 0x1c,
  M16_OPC_RR = 0x1d,
  M16_OPC_EXTEND = 0x1e,
  M16_OPC_I64 = 0x1f
};

/* I8 funct field */
enum {
  I8_BTEQZ = 0x0,
  I8_BTNEZ = 0x1,
  I8_SWRASP = 0x2,
  I8_ADJSP = 0x3,
  I8_SVRS = 0x4,
  I8_MOV32R = 0x5,
  I8_MOVR32 = 0x7
};

/* RRR f field */
enum {
  RRR_DADDU = 0x0,
  RRR_ADDU = 0x1,
  RRR_DSUBU = 0x2,
  RRR_SUBU = 0x3
};

/* RR funct field */
enum {
  RR_JR = 0x00,
  RR_SDBBP = 0x01,
  RR_SLT = 0x02,
  RR_SLTU = 0x03,
  RR_SLLV = 0x04,
  RR_BREAK = 0x05,
  RR_SRLV = 0x06,
  RR_SRAV = 0x07,
  RR_DSRL = 0x08,
  RR_CMP = 0x0a,
  RR_NEG = 0x0b,
  RR_AND = 0x0c,
  RR_OR = 0x0d,
  RR_XOR = 0x0e,
  RR_NOT = 0x0f,
  RR_MFHI = 0x10,
  RR_CNVT = 0x11,
  RR_MFLO = 0x12,
  RR_DSRA = 0x13,
  RR_DSLLV = 0x14,
  RR_DSRLV = 0x16,
  RR_DSRAV = 0x17,
  RR_MULT = 0x18,
  RR_MULTU = 0x19,
  RR_DIV = 0x1a,
  RR_DIVU = 0x1b,
  RR_DMULT = 0x1c,
  RR_DMULTU = 0x1d,
  RR_DDIV = 0x1e,
  RR_DDIVU = 0x1f
};

/* I64 funct field */
enum {
  I64_LDSP = 0x0,
  I64_SDSP = 0x1,
  I64_SDRASP = 0x2,
  I64_DADJSP = 0x3,
  I64_LDPC = 0x4,
8323
  I64_DADDIU5 = 0x5,
8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337
  I64_DADDIUPC = 0x6,
  I64_DADDIUSP = 0x7
};

/* RR ry field for CNVT */
enum {
  RR_RY_CNVT_ZEB = 0x0,
  RR_RY_CNVT_ZEH = 0x1,
  RR_RY_CNVT_ZEW = 0x2,
  RR_RY_CNVT_SEB = 0x4,
  RR_RY_CNVT_SEH = 0x5,
  RR_RY_CNVT_SEW = 0x6,
};

8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388
static int xlat (int r)
{
  static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };

  return map[r];
}

static void gen_mips16_save (DisasContext *ctx,
                             int xsregs, int aregs,
                             int do_ra, int do_s0, int do_s1,
                             int framesize)
{
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    int args, astatic;

    switch (aregs) {
    case 0:
    case 1:
    case 2:
    case 3:
    case 11:
        args = 0;
        break;
    case 4:
    case 5:
    case 6:
    case 7:
        args = 1;
        break;
    case 8:
    case 9:
    case 10:
        args = 2;
        break;
    case 12:
    case 13:
        args = 3;
        break;
    case 14:
        args = 4;
        break;
    default:
        generate_exception(ctx, EXCP_RI);
        return;
    }

    switch (args) {
    case 4:
        gen_base_offset_addr(ctx, t0, 29, 12);
        gen_load_gpr(t1, 7);
8389
        op_st_sw(t1, t0, ctx);
8390 8391 8392 8393
        /* Fall through */
    case 3:
        gen_base_offset_addr(ctx, t0, 29, 8);
        gen_load_gpr(t1, 6);
8394
        op_st_sw(t1, t0, ctx);
8395 8396 8397 8398
        /* Fall through */
    case 2:
        gen_base_offset_addr(ctx, t0, 29, 4);
        gen_load_gpr(t1, 5);
8399
        op_st_sw(t1, t0, ctx);
8400 8401 8402 8403
        /* Fall through */
    case 1:
        gen_base_offset_addr(ctx, t0, 29, 0);
        gen_load_gpr(t1, 4);
8404
        op_st_sw(t1, t0, ctx);
8405 8406 8407 8408 8409 8410 8411
    }

    gen_load_gpr(t0, 29);

#define DECR_AND_STORE(reg) do {                \
        tcg_gen_subi_tl(t0, t0, 4);             \
        gen_load_gpr(t1, reg);                  \
8412
        op_st_sw(t1, t0, ctx);                  \
8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511
    } while (0)

    if (do_ra) {
        DECR_AND_STORE(31);
    }

    switch (xsregs) {
    case 7:
        DECR_AND_STORE(30);
        /* Fall through */
    case 6:
        DECR_AND_STORE(23);
        /* Fall through */
    case 5:
        DECR_AND_STORE(22);
        /* Fall through */
    case 4:
        DECR_AND_STORE(21);
        /* Fall through */
    case 3:
        DECR_AND_STORE(20);
        /* Fall through */
    case 2:
        DECR_AND_STORE(19);
        /* Fall through */
    case 1:
        DECR_AND_STORE(18);
    }

    if (do_s1) {
        DECR_AND_STORE(17);
    }
    if (do_s0) {
        DECR_AND_STORE(16);
    }

    switch (aregs) {
    case 0:
    case 4:
    case 8:
    case 12:
    case 14:
        astatic = 0;
        break;
    case 1:
    case 5:
    case 9:
    case 13:
        astatic = 1;
        break;
    case 2:
    case 6:
    case 10:
        astatic = 2;
        break;
    case 3:
    case 7:
        astatic = 3;
        break;
    case 11:
        astatic = 4;
        break;
    default:
        generate_exception(ctx, EXCP_RI);
        return;
    }

    if (astatic > 0) {
        DECR_AND_STORE(7);
        if (astatic > 1) {
            DECR_AND_STORE(6);
            if (astatic > 2) {
                DECR_AND_STORE(5);
                if (astatic > 3) {
                    DECR_AND_STORE(4);
                }
            }
        }
    }
#undef DECR_AND_STORE

    tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}

static void gen_mips16_restore (DisasContext *ctx,
                                int xsregs, int aregs,
                                int do_ra, int do_s0, int do_s1,
                                int framesize)
{
    int astatic;
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();

    tcg_gen_addi_tl(t0, cpu_gpr[29], framesize);

#define DECR_AND_LOAD(reg) do {                 \
        tcg_gen_subi_tl(t0, t0, 4);             \
8512
        op_ld_lw(t1, t0, ctx);                  \
8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621
        gen_store_gpr(t1, reg);                 \
    } while (0)

    if (do_ra) {
        DECR_AND_LOAD(31);
    }

    switch (xsregs) {
    case 7:
        DECR_AND_LOAD(30);
        /* Fall through */
    case 6:
        DECR_AND_LOAD(23);
        /* Fall through */
    case 5:
        DECR_AND_LOAD(22);
        /* Fall through */
    case 4:
        DECR_AND_LOAD(21);
        /* Fall through */
    case 3:
        DECR_AND_LOAD(20);
        /* Fall through */
    case 2:
        DECR_AND_LOAD(19);
        /* Fall through */
    case 1:
        DECR_AND_LOAD(18);
    }

    if (do_s1) {
        DECR_AND_LOAD(17);
    }
    if (do_s0) {
        DECR_AND_LOAD(16);
    }

    switch (aregs) {
    case 0:
    case 4:
    case 8:
    case 12:
    case 14:
        astatic = 0;
        break;
    case 1:
    case 5:
    case 9:
    case 13:
        astatic = 1;
        break;
    case 2:
    case 6:
    case 10:
        astatic = 2;
        break;
    case 3:
    case 7:
        astatic = 3;
        break;
    case 11:
        astatic = 4;
        break;
    default:
        generate_exception(ctx, EXCP_RI);
        return;
    }

    if (astatic > 0) {
        DECR_AND_LOAD(7);
        if (astatic > 1) {
            DECR_AND_LOAD(6);
            if (astatic > 2) {
                DECR_AND_LOAD(5);
                if (astatic > 3) {
                    DECR_AND_LOAD(4);
                }
            }
        }
    }
#undef DECR_AND_LOAD

    tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}

static void gen_addiupc (DisasContext *ctx, int rx, int imm,
                         int is_64_bit, int extended)
{
    TCGv t0;

    if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) {
        generate_exception(ctx, EXCP_RI);
        return;
    }

    t0 = tcg_temp_new();

    tcg_gen_movi_tl(t0, pc_relative_pc(ctx));
    tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
    if (!is_64_bit) {
        tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
    }

    tcg_temp_free(t0);
}

#if defined(TARGET_MIPS64)
8622
static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx,
8623 8624 8625 8626 8627 8628 8629
                               int ry, int funct, int16_t offset,
                               int extended)
{
    switch (funct) {
    case I64_LDSP:
        check_mips_64(ctx);
        offset = extended ? offset : offset << 3;
8630
        gen_ld(env, ctx, OPC_LD, ry, 29, offset);
8631 8632 8633 8634
        break;
    case I64_SDSP:
        check_mips_64(ctx);
        offset = extended ? offset : offset << 3;
8635
        gen_st(ctx, OPC_SD, ry, 29, offset);
8636 8637 8638 8639
        break;
    case I64_SDRASP:
        check_mips_64(ctx);
        offset = extended ? offset : (ctx->opcode & 0xff) << 3;
8640
        gen_st(ctx, OPC_SD, 31, 29, offset);
8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651
        break;
    case I64_DADJSP:
        check_mips_64(ctx);
        offset = extended ? offset : ((int8_t)ctx->opcode) << 3;
        gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29, offset);
        break;
    case I64_LDPC:
        if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) {
            generate_exception(ctx, EXCP_RI);
        } else {
            offset = extended ? offset : offset << 3;
8652
            gen_ld(env, ctx, OPC_LDPC, ry, 0, offset);
8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673
        }
        break;
    case I64_DADDIU5:
        check_mips_64(ctx);
        offset = extended ? offset : ((int8_t)(offset << 3)) >> 3;
        gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry, offset);
        break;
    case I64_DADDIUPC:
        check_mips_64(ctx);
        offset = extended ? offset : offset << 2;
        gen_addiupc(ctx, ry, offset, 1, extended);
        break;
    case I64_DADDIUSP:
        check_mips_64(ctx);
        offset = extended ? offset : offset << 2;
        gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29, offset);
        break;
    }
}
#endif

8674
static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx,
8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735
                                       int *is_branch)
{
    int extend = lduw_code(ctx->pc + 2);
    int op, rx, ry, funct, sa;
    int16_t imm, offset;

    ctx->opcode = (ctx->opcode << 16) | extend;
    op = (ctx->opcode >> 11) & 0x1f;
    sa = (ctx->opcode >> 22) & 0x1f;
    funct = (ctx->opcode >> 8) & 0x7;
    rx = xlat((ctx->opcode >> 8) & 0x7);
    ry = xlat((ctx->opcode >> 5) & 0x7);
    offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11
                              | ((ctx->opcode >> 21) & 0x3f) << 5
                              | (ctx->opcode & 0x1f));

    /* The extended opcodes cleverly reuse the opcodes from their 16-bit
       counterparts.  */
    switch (op) {
    case M16_OPC_ADDIUSP:
        gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
        break;
    case M16_OPC_ADDIUPC:
        gen_addiupc(ctx, rx, imm, 0, 1);
        break;
    case M16_OPC_B:
        gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_BEQZ:
        gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_BNEQZ:
        gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_SHIFT:
        switch (ctx->opcode & 0x3) {
        case 0x0:
            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
            break;
        case 0x1:
#if defined(TARGET_MIPS64)
            check_mips_64(ctx);
            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
#else
            generate_exception(ctx, EXCP_RI);
#endif
            break;
        case 0x2:
            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
            break;
        case 0x3:
            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
            break;
        }
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_LD:
            check_mips_64(ctx);
8736
        gen_ld(env, ctx, OPC_LD, ry, rx, offset);
8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772
        break;
#endif
    case M16_OPC_RRIA:
        imm = ctx->opcode & 0xf;
        imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4;
        imm = imm | ((ctx->opcode >> 16) & 0xf) << 11;
        imm = (int16_t) (imm << 1) >> 1;
        if ((ctx->opcode >> 4) & 0x1) {
#if defined(TARGET_MIPS64)
            check_mips_64(ctx);
            gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
#else
            generate_exception(ctx, EXCP_RI);
#endif
        } else {
            gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
        }
        break;
    case M16_OPC_ADDIU8:
        gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
        break;
    case M16_OPC_SLTI:
        gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
        break;
    case M16_OPC_SLTIU:
        gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
        break;
    case M16_OPC_I8:
        switch (funct) {
        case I8_BTEQZ:
            gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1);
            break;
        case I8_BTNEZ:
            gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1);
            break;
        case I8_SWRASP:
8773
            gen_st(ctx, OPC_SW, 31, 29, imm);
8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811
            break;
        case I8_ADJSP:
            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm);
            break;
        case I8_SVRS:
            {
                int xsregs = (ctx->opcode >> 24) & 0x7;
                int aregs = (ctx->opcode >> 16) & 0xf;
                int do_ra = (ctx->opcode >> 6) & 0x1;
                int do_s0 = (ctx->opcode >> 5) & 0x1;
                int do_s1 = (ctx->opcode >> 4) & 0x1;
                int framesize = (((ctx->opcode >> 20) & 0xf) << 4
                                 | (ctx->opcode & 0xf)) << 3;

                if (ctx->opcode & (1 << 7)) {
                    gen_mips16_save(ctx, xsregs, aregs,
                                    do_ra, do_s0, do_s1,
                                    framesize);
                } else {
                    gen_mips16_restore(ctx, xsregs, aregs,
                                       do_ra, do_s0, do_s1,
                                       framesize);
                }
            }
            break;
        default:
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case M16_OPC_LI:
        tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm);
        break;
    case M16_OPC_CMPI:
        tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm);
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_SD:
8812
        gen_st(ctx, OPC_SD, ry, rx, offset);
8813 8814 8815
        break;
#endif
    case M16_OPC_LB:
8816
        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
8817 8818
        break;
    case M16_OPC_LH:
8819
        gen_ld(env, ctx, OPC_LH, ry, rx, offset);
8820 8821
        break;
    case M16_OPC_LWSP:
8822
        gen_ld(env, ctx, OPC_LW, rx, 29, offset);
8823 8824
        break;
    case M16_OPC_LW:
8825
        gen_ld(env, ctx, OPC_LW, ry, rx, offset);
8826 8827
        break;
    case M16_OPC_LBU:
8828
        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
8829 8830
        break;
    case M16_OPC_LHU:
8831
        gen_ld(env, ctx, OPC_LHU, ry, rx, offset);
8832 8833
        break;
    case M16_OPC_LWPC:
8834
        gen_ld(env, ctx, OPC_LWPC, rx, 0, offset);
8835 8836 8837
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_LWU:
8838
        gen_ld(env, ctx, OPC_LWU, ry, rx, offset);
8839 8840 8841
        break;
#endif
    case M16_OPC_SB:
8842
        gen_st(ctx, OPC_SB, ry, rx, offset);
8843 8844
        break;
    case M16_OPC_SH:
8845
        gen_st(ctx, OPC_SH, ry, rx, offset);
8846 8847
        break;
    case M16_OPC_SWSP:
8848
        gen_st(ctx, OPC_SW, rx, 29, offset);
8849 8850
        break;
    case M16_OPC_SW:
8851
        gen_st(ctx, OPC_SW, ry, rx, offset);
8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_I64:
        decode_i64_mips16(env, ctx, ry, funct, offset, 1);
        break;
#endif
    default:
        generate_exception(ctx, EXCP_RI);
        break;
    }

    return 4;
}

8866
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx,
8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906
                              int *is_branch)
{
    int rx, ry;
    int sa;
    int op, cnvt_op, op1, offset;
    int funct;
    int n_bytes;

    op = (ctx->opcode >> 11) & 0x1f;
    sa = (ctx->opcode >> 2) & 0x7;
    sa = sa == 0 ? 8 : sa;
    rx = xlat((ctx->opcode >> 8) & 0x7);
    cnvt_op = (ctx->opcode >> 5) & 0x7;
    ry = xlat((ctx->opcode >> 5) & 0x7);
    op1 = offset = ctx->opcode & 0x1f;

    n_bytes = 2;

    switch (op) {
    case M16_OPC_ADDIUSP:
        {
            int16_t imm = ((uint8_t) ctx->opcode) << 2;

            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm);
        }
        break;
    case M16_OPC_ADDIUPC:
        gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2, 0, 0);
        break;
    case M16_OPC_B:
        offset = (ctx->opcode & 0x7ff) << 1;
        offset = (int16_t)(offset << 4) >> 4;
        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_JAL:
        offset = lduw_code(ctx->pc + 2);
        offset = (((ctx->opcode & 0x1f) << 21)
                  | ((ctx->opcode >> 5) & 0x1f) << 16
                  | offset) << 2;
N
Nathan Froyd 已提交
8907
        op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS;
8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943
        gen_compute_branch(ctx, op, 4, rx, ry, offset);
        n_bytes = 4;
        *is_branch = 1;
        break;
    case M16_OPC_BEQZ:
        gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_BNEQZ:
        gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1);
        /* No delay slot, so just process as a normal instruction */
        break;
    case M16_OPC_SHIFT:
        switch (ctx->opcode & 0x3) {
        case 0x0:
            gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa);
            break;
        case 0x1:
#if defined(TARGET_MIPS64)
            check_mips_64(ctx);
            gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa);
#else
            generate_exception(ctx, EXCP_RI);
#endif
            break;
        case 0x2:
            gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa);
            break;
        case 0x3:
            gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa);
            break;
        }
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_LD:
        check_mips_64(ctx);
8944
        gen_ld(env, ctx, OPC_LD, ry, rx, offset << 3);
8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998
        break;
#endif
    case M16_OPC_RRIA:
        {
            int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4;

            if ((ctx->opcode >> 4) & 1) {
#if defined(TARGET_MIPS64)
                check_mips_64(ctx);
                gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm);
#else
                generate_exception(ctx, EXCP_RI);
#endif
            } else {
                gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm);
            }
        }
        break;
    case M16_OPC_ADDIU8:
        {
            int16_t imm = (int8_t) ctx->opcode;

            gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm);
        }
        break;
    case M16_OPC_SLTI:
        {
            int16_t imm = (uint8_t) ctx->opcode;

            gen_slt_imm(env, OPC_SLTI, 24, rx, imm);
        }
        break;
    case M16_OPC_SLTIU:
        {
            int16_t imm = (uint8_t) ctx->opcode;

            gen_slt_imm(env, OPC_SLTIU, 24, rx, imm);
        }
        break;
    case M16_OPC_I8:
        {
            int reg32;

            funct = (ctx->opcode >> 8) & 0x7;
            switch (funct) {
            case I8_BTEQZ:
                gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
                                   ((int8_t)ctx->opcode) << 1);
                break;
            case I8_BTNEZ:
                gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
                                   ((int8_t)ctx->opcode) << 1);
                break;
            case I8_SWRASP:
8999
                gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062
                break;
            case I8_ADJSP:
                gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29,
                              ((int8_t)ctx->opcode) << 3);
                break;
            case I8_SVRS:
                {
                    int do_ra = ctx->opcode & (1 << 6);
                    int do_s0 = ctx->opcode & (1 << 5);
                    int do_s1 = ctx->opcode & (1 << 4);
                    int framesize = ctx->opcode & 0xf;

                    if (framesize == 0) {
                        framesize = 128;
                    } else {
                        framesize = framesize << 3;
                    }

                    if (ctx->opcode & (1 << 7)) {
                        gen_mips16_save(ctx, 0, 0,
                                        do_ra, do_s0, do_s1, framesize);
                    } else {
                        gen_mips16_restore(ctx, 0, 0,
                                           do_ra, do_s0, do_s1, framesize);
                    }
                }
                break;
            case I8_MOV32R:
                {
                    int rz = xlat(ctx->opcode & 0x7);

                    reg32 = (((ctx->opcode >> 3) & 0x3) << 3) |
                        ((ctx->opcode >> 5) & 0x7);
                    gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0);
                }
                break;
            case I8_MOVR32:
                reg32 = ctx->opcode & 0x1f;
                gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
        }
        break;
    case M16_OPC_LI:
        {
            int16_t imm = (uint8_t) ctx->opcode;

            gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm);
        }
        break;
    case M16_OPC_CMPI:
        {
            int16_t imm = (uint8_t) ctx->opcode;

            gen_logic_imm(env, OPC_XORI, 24, rx, imm);
        }
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_SD:
        check_mips_64(ctx);
9063
        gen_st(ctx, OPC_SD, ry, rx, offset << 3);
9064 9065 9066
        break;
#endif
    case M16_OPC_LB:
9067
        gen_ld(env, ctx, OPC_LB, ry, rx, offset);
9068 9069
        break;
    case M16_OPC_LH:
9070
        gen_ld(env, ctx, OPC_LH, ry, rx, offset << 1);
9071 9072
        break;
    case M16_OPC_LWSP:
9073
        gen_ld(env, ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2);
9074 9075
        break;
    case M16_OPC_LW:
9076
        gen_ld(env, ctx, OPC_LW, ry, rx, offset << 2);
9077 9078
        break;
    case M16_OPC_LBU:
9079
        gen_ld(env, ctx, OPC_LBU, ry, rx, offset);
9080 9081
        break;
    case M16_OPC_LHU:
9082
        gen_ld(env, ctx, OPC_LHU, ry, rx, offset << 1);
9083 9084
        break;
    case M16_OPC_LWPC:
9085
        gen_ld(env, ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2);
9086 9087 9088 9089
        break;
#if defined (TARGET_MIPS64)
    case M16_OPC_LWU:
        check_mips_64(ctx);
9090
        gen_ld(env, ctx, OPC_LWU, ry, rx, offset << 2);
9091 9092 9093
        break;
#endif
    case M16_OPC_SB:
9094
        gen_st(ctx, OPC_SB, ry, rx, offset);
9095 9096
        break;
    case M16_OPC_SH:
9097
        gen_st(ctx, OPC_SH, ry, rx, offset << 1);
9098 9099
        break;
    case M16_OPC_SWSP:
9100
        gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2);
9101 9102
        break;
    case M16_OPC_SW:
9103
        gen_st(ctx, OPC_SW, ry, rx, offset << 2);
9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145
        break;
    case M16_OPC_RRR:
        {
            int rz = xlat((ctx->opcode >> 2) & 0x7);
            int mips32_op;

            switch (ctx->opcode & 0x3) {
            case RRR_ADDU:
                mips32_op = OPC_ADDU;
                break;
            case RRR_SUBU:
                mips32_op = OPC_SUBU;
                break;
#if defined(TARGET_MIPS64)
            case RRR_DADDU:
                mips32_op = OPC_DADDU;
                check_mips_64(ctx);
                break;
            case RRR_DSUBU:
                mips32_op = OPC_DSUBU;
                check_mips_64(ctx);
                break;
#endif
            default:
                generate_exception(ctx, EXCP_RI);
                goto done;
            }

            gen_arith(env, ctx, mips32_op, rz, rx, ry);
        done:
            ;
        }
        break;
    case M16_OPC_RR:
        switch (op1) {
        case RR_JR:
            {
                int nd = (ctx->opcode >> 7) & 0x1;
                int link = (ctx->opcode >> 6) & 0x1;
                int ra = (ctx->opcode >> 5) & 0x1;

                if (link) {
N
Nathan Froyd 已提交
9146
                    op = nd ? OPC_JALRC : OPC_JALRS;
9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315
                } else {
                    op = OPC_JR;
                }

                gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0);
                if (!nd) {
                    *is_branch = 1;
                }
            }
            break;
        case RR_SDBBP:
            /* XXX: not clear which exception should be raised
             *      when in debug mode...
             */
            check_insn(env, ctx, ISA_MIPS32);
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
                generate_exception(ctx, EXCP_DBp);
            } else {
                generate_exception(ctx, EXCP_DBp);
            }
            break;
        case RR_SLT:
            gen_slt(env, OPC_SLT, 24, rx, ry);
            break;
        case RR_SLTU:
            gen_slt(env, OPC_SLTU, 24, rx, ry);
            break;
        case RR_BREAK:
            generate_exception(ctx, EXCP_BREAK);
            break;
        case RR_SLLV:
            gen_shift(env, ctx, OPC_SLLV, ry, rx, ry);
            break;
        case RR_SRLV:
            gen_shift(env, ctx, OPC_SRLV, ry, rx, ry);
            break;
        case RR_SRAV:
            gen_shift(env, ctx, OPC_SRAV, ry, rx, ry);
            break;
#if defined (TARGET_MIPS64)
        case RR_DSRL:
            check_mips_64(ctx);
            gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa);
            break;
#endif
        case RR_CMP:
            gen_logic(env, OPC_XOR, 24, rx, ry);
            break;
        case RR_NEG:
            gen_arith(env, ctx, OPC_SUBU, rx, 0, ry);
            break;
        case RR_AND:
            gen_logic(env, OPC_AND, rx, rx, ry);
            break;
        case RR_OR:
            gen_logic(env, OPC_OR, rx, rx, ry);
            break;
        case RR_XOR:
            gen_logic(env, OPC_XOR, rx, rx, ry);
            break;
        case RR_NOT:
            gen_logic(env, OPC_NOR, rx, ry, 0);
            break;
        case RR_MFHI:
            gen_HILO(ctx, OPC_MFHI, rx);
            break;
        case RR_CNVT:
            switch (cnvt_op) {
            case RR_RY_CNVT_ZEB:
                tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
            case RR_RY_CNVT_ZEH:
                tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
            case RR_RY_CNVT_SEB:
                tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
            case RR_RY_CNVT_SEH:
                tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
#if defined (TARGET_MIPS64)
            case RR_RY_CNVT_ZEW:
                check_mips_64(ctx);
                tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
            case RR_RY_CNVT_SEW:
                check_mips_64(ctx);
                tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
                break;
#endif
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
        case RR_MFLO:
            gen_HILO(ctx, OPC_MFLO, rx);
            break;
#if defined (TARGET_MIPS64)
        case RR_DSRA:
            check_mips_64(ctx);
            gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa);
            break;
        case RR_DSLLV:
            check_mips_64(ctx);
            gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry);
            break;
        case RR_DSRLV:
            check_mips_64(ctx);
            gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry);
            break;
        case RR_DSRAV:
            check_mips_64(ctx);
            gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry);
            break;
#endif
        case RR_MULT:
            gen_muldiv(ctx, OPC_MULT, rx, ry);
            break;
        case RR_MULTU:
            gen_muldiv(ctx, OPC_MULTU, rx, ry);
            break;
        case RR_DIV:
            gen_muldiv(ctx, OPC_DIV, rx, ry);
            break;
        case RR_DIVU:
            gen_muldiv(ctx, OPC_DIVU, rx, ry);
            break;
#if defined (TARGET_MIPS64)
        case RR_DMULT:
            check_mips_64(ctx);
            gen_muldiv(ctx, OPC_DMULT, rx, ry);
            break;
        case RR_DMULTU:
            check_mips_64(ctx);
            gen_muldiv(ctx, OPC_DMULTU, rx, ry);
            break;
        case RR_DDIV:
            check_mips_64(ctx);
            gen_muldiv(ctx, OPC_DDIV, rx, ry);
            break;
        case RR_DDIVU:
            check_mips_64(ctx);
            gen_muldiv(ctx, OPC_DDIVU, rx, ry);
            break;
#endif
        default:
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case M16_OPC_EXTEND:
        decode_extended_mips16_opc(env, ctx, is_branch);
        n_bytes = 4;
        break;
#if defined(TARGET_MIPS64)
    case M16_OPC_I64:
        funct = (ctx->opcode >> 8) & 0x7;
        decode_i64_mips16(env, ctx, ry, funct, offset, 0);
        break;
#endif
    default:
        generate_exception(ctx, EXCP_RI);
        break;
    }

    return n_bytes;
}

9316
/* microMIPS extension to MIPS32 */
B
bellard 已提交
9317

9318
/* microMIPS32 major opcodes */
B
bellard 已提交
9319

9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779
enum {
    POOL32A = 0x00,
    POOL16A = 0x01,
    LBU16 = 0x02,
    MOVE16 = 0x03,
    ADDI32 = 0x04,
    LBU32 = 0x05,
    SB32 = 0x06,
    LB32 = 0x07,

    POOL32B = 0x08,
    POOL16B = 0x09,
    LHU16 = 0x0a,
    ANDI16 = 0x0b,
    ADDIU32 = 0x0c,
    LHU32 = 0x0d,
    SH32 = 0x0e,
    LH32 = 0x0f,

    POOL32I = 0x10,
    POOL16C = 0x11,
    LWSP16 = 0x12,
    POOL16D = 0x13,
    ORI32 = 0x14,
    POOL32F = 0x15,
    POOL32S = 0x16,
    DADDIU32 = 0x17,

    POOL32C = 0x18,
    LWGP16 = 0x19,
    LW16 = 0x1a,
    POOL16E = 0x1b,
    XORI32 = 0x1c,
    JALS32 = 0x1d,
    ADDIUPC = 0x1e,
    POOL48A = 0x1f,

    /* 0x20 is reserved */
    RES_20 = 0x20,
    POOL16F = 0x21,
    SB16 = 0x22,
    BEQZ16 = 0x23,
    SLTI32 = 0x24,
    BEQ32 = 0x25,
    SWC132 = 0x26,
    LWC132 = 0x27,

    /* 0x28 and 0x29 are reserved */
    RES_28 = 0x28,
    RES_29 = 0x29,
    SH16 = 0x2a,
    BNEZ16 = 0x2b,
    SLTIU32 = 0x2c,
    BNE32 = 0x2d,
    SDC132 = 0x2e,
    LDC132 = 0x2f,

    /* 0x30 and 0x31 are reserved */
    RES_30 = 0x30,
    RES_31 = 0x31,
    SWSP16 = 0x32,
    B16 = 0x33,
    ANDI32 = 0x34,
    J32 = 0x35,
    SD32 = 0x36,
    LD32 = 0x37,

    /* 0x38 and 0x39 are reserved */
    RES_38 = 0x38,
    RES_39 = 0x39,
    SW16 = 0x3a,
    LI16 = 0x3b,
    JALX32 = 0x3c,
    JAL32 = 0x3d,
    SW32 = 0x3e,
    LW32 = 0x3f
};

/* POOL32A encoding of minor opcode field */

enum {
    /* These opcodes are distinguished only by bits 9..6; those bits are
     * what are recorded below. */
    SLL32 = 0x0,
    SRL32 = 0x1,
    SRA = 0x2,
    ROTR = 0x3,

    SLLV = 0x0,
    SRLV = 0x1,
    SRAV = 0x2,
    ROTRV = 0x3,
    ADD = 0x4,
    ADDU32 = 0x5,
    SUB = 0x6,
    SUBU32 = 0x7,
    MUL = 0x8,
    AND = 0x9,
    OR32 = 0xa,
    NOR = 0xb,
    XOR32 = 0xc,
    SLT = 0xd,
    SLTU = 0xe,

    MOVN = 0x0,
    MOVZ = 0x1,
    LWXS = 0x4,

    /* The following can be distinguished by their lower 6 bits. */
    INS = 0x0c,
    EXT = 0x2c,
    POOL32AXF = 0x3c
};

/* POOL32AXF encoding of minor opcode field extension */

enum {
    /* bits 11..6 */
    TEQ = 0x00,
    TGE = 0x08,
    TGEU = 0x10,
    TLT = 0x20,
    TLTU = 0x28,
    TNE = 0x30,

    MFC0 = 0x03,
    MTC0 = 0x0b,

    /* bits 13..12 for 0x01 */
    MFHI_ACC = 0x0,
    MFLO_ACC = 0x1,
    MTHI_ACC = 0x2,
    MTLO_ACC = 0x3,

    /* bits 13..12 for 0x2a */
    MADD_ACC = 0x0,
    MADDU_ACC = 0x1,
    MSUB_ACC = 0x2,
    MSUBU_ACC = 0x3,

    /* bits 13..12 for 0x32 */
    MULT_ACC = 0x0,
    MULTU_ACC = 0x0,

    /* bits 15..12 for 0x2c */
    SEB = 0x2,
    SEH = 0x3,
    CLO = 0x4,
    CLZ = 0x5,
    RDHWR = 0x6,
    WSBH = 0x7,
    MULT = 0x8,
    MULTU = 0x9,
    DIV = 0xa,
    DIVU = 0xb,
    MADD = 0xc,
    MADDU = 0xd,
    MSUB = 0xe,
    MSUBU = 0xf,

    /* bits 15..12 for 0x34 */
    MFC2 = 0x4,
    MTC2 = 0x5,
    MFHC2 = 0x8,
    MTHC2 = 0x9,
    CFC2 = 0xc,
    CTC2 = 0xd,

    /* bits 15..12 for 0x3c */
    JALR = 0x0,
    JR = 0x0,                   /* alias */
    JALR_HB = 0x1,
    JALRS = 0x4,
    JALRS_HB = 0x5,

    /* bits 15..12 for 0x05 */
    RDPGPR = 0xe,
    WRPGPR = 0xf,

    /* bits 15..12 for 0x0d */
    TLBP = 0x0,
    TLBR = 0x1,
    TLBWI = 0x2,
    TLBWR = 0x3,
    WAIT = 0x9,
    IRET = 0xd,
    DERET = 0xe,
    ERET = 0xf,

    /* bits 15..12 for 0x15 */
    DMT = 0x0,
    DVPE = 0x1,
    EMT = 0x2,
    EVPE = 0x3,

    /* bits 15..12 for 0x1d */
    DI = 0x4,
    EI = 0x5,

    /* bits 15..12 for 0x2d */
    SYNC = 0x6,
    SYSCALL = 0x8,
    SDBBP = 0xd,

    /* bits 15..12 for 0x35 */
    MFHI32 = 0x0,
    MFLO32 = 0x1,
    MTHI32 = 0x2,
    MTLO32 = 0x3,
};

/* POOL32B encoding of minor opcode field (bits 15..12) */

enum {
    LWC2 = 0x0,
    LWP = 0x1,
    LDP = 0x4,
    LWM32 = 0x5,
    CACHE = 0x6,
    LDM = 0x7,
    SWC2 = 0x8,
    SWP = 0x9,
    SDP = 0xc,
    SWM32 = 0xd,
    SDM = 0xf
};

/* POOL32C encoding of minor opcode field (bits 15..12) */

enum {
    LWL = 0x0,
    SWL = 0x8,
    LWR = 0x1,
    SWR = 0x9,
    PREF = 0x2,
    /* 0xa is reserved */
    LL = 0x3,
    SC = 0xb,
    LDL = 0x4,
    SDL = 0xc,
    LDR = 0x5,
    SDR = 0xd,
    /* 0x6 is reserved */
    LWU = 0xe,
    LLD = 0x7,
    SCD = 0xf
};

/* POOL32F encoding of minor opcode field (bits 5..0) */

enum {
    /* These are the bit 7..6 values */
    ADD_FMT = 0x0,
    MOVN_FMT = 0x0,

    SUB_FMT = 0x1,
    MOVZ_FMT = 0x1,

    MUL_FMT = 0x2,

    DIV_FMT = 0x3,

    /* These are the bit 8..6 values */
    RSQRT2_FMT = 0x0,
    MOVF_FMT = 0x0,

    LWXC1 = 0x1,
    MOVT_FMT = 0x1,

    PLL_PS = 0x2,
    SWXC1 = 0x2,

    PLU_PS = 0x3,
    LDXC1 = 0x3,

    PUL_PS = 0x4,
    SDXC1 = 0x4,
    RECIP2_FMT = 0x4,

    PUU_PS = 0x5,
    LUXC1 = 0x5,

    CVT_PS_S = 0x6,
    SUXC1 = 0x6,
    ADDR_PS = 0x6,
    PREFX = 0x6,

    MULR_PS = 0x7,

    MADD_S = 0x01,
    MADD_D = 0x09,
    MADD_PS = 0x11,
    ALNV_PS = 0x19,
    MSUB_S = 0x21,
    MSUB_D = 0x29,
    MSUB_PS = 0x31,

    NMADD_S = 0x02,
    NMADD_D = 0x0a,
    NMADD_PS = 0x12,
    NMSUB_S = 0x22,
    NMSUB_D = 0x2a,
    NMSUB_PS = 0x32,

    POOL32FXF = 0x3b,

    CABS_COND_FMT = 0x1c,              /* MIPS3D */
    C_COND_FMT = 0x3c
};

/* POOL32Fxf encoding of minor opcode extension field */

enum {
    CVT_L = 0x04,
    RSQRT_FMT = 0x08,
    FLOOR_L = 0x0c,
    CVT_PW_PS = 0x1c,
    CVT_W = 0x24,
    SQRT_FMT = 0x28,
    FLOOR_W = 0x2c,
    CVT_PS_PW = 0x3c,
    CFC1 = 0x40,
    RECIP_FMT = 0x48,
    CEIL_L = 0x4c,
    CTC1 = 0x60,
    CEIL_W = 0x6c,
    MFC1 = 0x80,
    CVT_S_PL = 0x84,
    TRUNC_L = 0x8c,
    MTC1 = 0xa0,
    CVT_S_PU = 0xa4,
    TRUNC_W = 0xac,
    MFHC1 = 0xc0,
    ROUND_L = 0xcc,
    MTHC1 = 0xe0,
    ROUND_W = 0xec,

    MOV_FMT = 0x01,
    MOVF = 0x05,
    ABS_FMT = 0x0d,
    RSQRT1_FMT = 0x1d,
    MOVT = 0x25,
    NEG_FMT = 0x2d,
    CVT_D = 0x4d,
    RECIP1_FMT = 0x5d,
    CVT_S = 0x6d
};

/* POOL32I encoding of minor opcode field (bits 25..21) */

enum {
    BLTZ = 0x00,
    BLTZAL = 0x01,
    BGEZ = 0x02,
    BGEZAL = 0x03,
    BLEZ = 0x04,
    BNEZC = 0x05,
    BGTZ = 0x06,
    BEQZC = 0x07,
    TLTI = 0x08,
    TGEI = 0x09,
    TLTIU = 0x0a,
    TGEIU = 0x0b,
    TNEI = 0x0c,
    LUI = 0x0d,
    TEQI = 0x0e,
    SYNCI = 0x10,
    BLTZALS = 0x11,
    BGEZALS = 0x13,
    BC2F = 0x14,
    BC2T = 0x15,
    BPOSGE64 = 0x1a,
    BPOSGE32 = 0x1b,
    /* These overlap and are distinguished by bit16 of the instruction */
    BC1F = 0x1c,
    BC1T = 0x1d,
    BC1ANY2F = 0x1c,
    BC1ANY2T = 0x1d,
    BC1ANY4F = 0x1e,
    BC1ANY4T = 0x1f
};

/* POOL16A encoding of minor opcode field */

enum {
    ADDU16 = 0x0,
    SUBU16 = 0x1
};

/* POOL16B encoding of minor opcode field */

enum {
    SLL16 = 0x0,
    SRL16 = 0x1
};

/* POOL16C encoding of minor opcode field */

enum {
    NOT16 = 0x00,
    XOR16 = 0x04,
    AND16 = 0x08,
    OR16 = 0x0c,
    LWM16 = 0x10,
    SWM16 = 0x14,
    JR16 = 0x18,
    JRC16 = 0x1a,
    JALR16 = 0x1c,
    JALR16S = 0x1e,
    MFHI16 = 0x20,
    MFLO16 = 0x24,
    BREAK16 = 0x28,
    SDBBP16 = 0x2c,
    JRADDIUSP = 0x30
};

/* POOL16D encoding of minor opcode field */

enum {
    ADDIUS5 = 0x0,
    ADDIUSP = 0x1
};

/* POOL16E encoding of minor opcode field */

enum {
    ADDIUR2 = 0x0,
    ADDIUR1SP = 0x1
};

static int mmreg (int r)
{
    static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };

    return map[r];
}

/* Used for 16-bit store instructions.  */
static int mmreg2 (int r)
{
    static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 };

    return map[r];
}

#define uMIPS_RD(op) ((op >> 7) & 0x7)
#define uMIPS_RS(op) ((op >> 4) & 0x7)
#define uMIPS_RS2(op) uMIPS_RS(op)
#define uMIPS_RS1(op) ((op >> 1) & 0x7)
#define uMIPS_RD5(op) ((op >> 5) & 0x1f)
#define uMIPS_RS5(op) (op & 0x1f)

/* Signed immediate */
#define SIMM(op, start, width)                                          \
    ((int32_t)(((op >> start) & ((~0U) >> (32-width)))                 \
               << (32-width))                                           \
     >> (32-width))
/* Zero-extended immediate */
#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width)))

9780
static void gen_addiur1sp (CPUMIPSState *env, DisasContext *ctx)
9781 9782 9783 9784 9785 9786
{
    int rd = mmreg(uMIPS_RD(ctx->opcode));

    gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2);
}

9787
static void gen_addiur2 (CPUMIPSState *env, DisasContext *ctx)
9788 9789 9790 9791 9792 9793 9794 9795
{
    static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 };
    int rd = mmreg(uMIPS_RD(ctx->opcode));
    int rs = mmreg(uMIPS_RS(ctx->opcode));

    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]);
}

9796
static void gen_addiusp (CPUMIPSState *env, DisasContext *ctx)
9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813
{
    int encoded = ZIMM(ctx->opcode, 1, 9);
    int decoded;

    if (encoded <= 1) {
        decoded = 256 + encoded;
    } else if (encoded <= 255) {
        decoded = encoded;
    } else if (encoded <= 509) {
        decoded = encoded - 512;
    } else {
        decoded = encoded - 768;
    }

    gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2);
}

9814
static void gen_addius5 (CPUMIPSState *env, DisasContext *ctx)
9815 9816 9817 9818 9819 9820 9821
{
    int imm = SIMM(ctx->opcode, 1, 4);
    int rd = (ctx->opcode >> 5) & 0x1f;

    gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm);
}

9822
static void gen_andi16 (CPUMIPSState *env, DisasContext *ctx)
9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849
{
    static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16,
                                 31, 32, 63, 64, 255, 32768, 65535 };
    int rd = mmreg(uMIPS_RD(ctx->opcode));
    int rs = mmreg(uMIPS_RS(ctx->opcode));
    int encoded = ZIMM(ctx->opcode, 0, 4);

    gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]);
}

static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist,
                               int base, int16_t offset)
{
    TCGv t0, t1;
    TCGv_i32 t2;

    if (ctx->hflags & MIPS_HFLAG_BMASK) {
        generate_exception(ctx, EXCP_RI);
        return;
    }

    t0 = tcg_temp_new();

    gen_base_offset_addr(ctx, t0, base, offset);

    t1 = tcg_const_tl(reglist);
    t2 = tcg_const_i32(ctx->mem_idx);
B
bellard 已提交
9850

9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865
    save_cpu_state(ctx, 1);
    switch (opc) {
    case LWM32:
        gen_helper_lwm(t0, t1, t2);
        break;
    case SWM32:
        gen_helper_swm(t0, t1, t2);
        break;
#ifdef TARGET_MIPS64
    case LDM:
        gen_helper_ldm(t0, t1, t2);
        break;
    case SDM:
        gen_helper_sdm(t0, t1, t2);
        break;
B
bellard 已提交
9866
#endif
9867 9868 9869
    }
    MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]);
    tcg_temp_free(t0);
S
Stefan Weil 已提交
9870
    tcg_temp_free(t1);
9871 9872
    tcg_temp_free_i32(t2);
}
B
bellard 已提交
9873

9874

9875
static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
B
bellard 已提交
9876
{
9877 9878 9879
    int rd = mmreg((ctx->opcode >> 3) & 0x7);
    int rs = mmreg(ctx->opcode & 0x7);
    int opc;
B
bellard 已提交
9880

9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016
    switch (((ctx->opcode) >> 4) & 0x3f) {
    case NOT16 + 0:
    case NOT16 + 1:
    case NOT16 + 2:
    case NOT16 + 3:
        gen_logic(env, OPC_NOR, rd, rs, 0);
        break;
    case XOR16 + 0:
    case XOR16 + 1:
    case XOR16 + 2:
    case XOR16 + 3:
        gen_logic(env, OPC_XOR, rd, rd, rs);
        break;
    case AND16 + 0:
    case AND16 + 1:
    case AND16 + 2:
    case AND16 + 3:
        gen_logic(env, OPC_AND, rd, rd, rs);
        break;
    case OR16 + 0:
    case OR16 + 1:
    case OR16 + 2:
    case OR16 + 3:
        gen_logic(env, OPC_OR, rd, rd, rs);
        break;
    case LWM16 + 0:
    case LWM16 + 1:
    case LWM16 + 2:
    case LWM16 + 3:
        {
            static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
            int offset = ZIMM(ctx->opcode, 0, 4);

            gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3],
                              29, offset << 2);
        }
        break;
    case SWM16 + 0:
    case SWM16 + 1:
    case SWM16 + 2:
    case SWM16 + 3:
        {
            static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
            int offset = ZIMM(ctx->opcode, 0, 4);

            gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3],
                              29, offset << 2);
        }
        break;
    case JR16 + 0:
    case JR16 + 1:
        {
            int reg = ctx->opcode & 0x1f;

            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
        }
        *is_branch = 1;
        break;
    case JRC16 + 0:
    case JRC16 + 1:
        {
            int reg = ctx->opcode & 0x1f;

            gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
            /* Let normal delay slot handling in our caller take us
               to the branch target.  */
        }
        break;
    case JALR16 + 0:
    case JALR16 + 1:
        opc = OPC_JALR;
        goto do_jalr;
    case JALR16S + 0:
    case JALR16S + 1:
        opc = OPC_JALRS;
    do_jalr:
        {
            int reg = ctx->opcode & 0x1f;

            gen_compute_branch(ctx, opc, 2, reg, 31, 0);
        }
        *is_branch = 1;
        break;
    case MFHI16 + 0:
    case MFHI16 + 1:
        gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode));
        break;
    case MFLO16 + 0:
    case MFLO16 + 1:
        gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode));
        break;
    case BREAK16:
        generate_exception(ctx, EXCP_BREAK);
        break;
    case SDBBP16:
        /* XXX: not clear which exception should be raised
         *      when in debug mode...
         */
        check_insn(env, ctx, ISA_MIPS32);
        if (!(ctx->hflags & MIPS_HFLAG_DM)) {
            generate_exception(ctx, EXCP_DBp);
        } else {
            generate_exception(ctx, EXCP_DBp);
        }
        break;
    case JRADDIUSP + 0:
    case JRADDIUSP + 1:
        {
            int imm = ZIMM(ctx->opcode, 0, 5);

            gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
            gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2);
            /* Let normal delay slot handling in our caller take us
               to the branch target.  */
        }
        break;
    default:
        generate_exception(ctx, EXCP_RI);
        break;
    }
}

static void gen_ldxs (DisasContext *ctx, int base, int index, int rd)
{
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();

    gen_load_gpr(t0, base);

    if (index != 0) {
        gen_load_gpr(t1, index);
        tcg_gen_shli_tl(t1, t1, 2);
        gen_op_addr_add(ctx, t0, t1, t0);
    }

    save_cpu_state(ctx, 0);
10017
    op_ld_lw(t1, t0, ctx);
10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031
    gen_store_gpr(t1, rd);

    tcg_temp_free(t0);
    tcg_temp_free(t1);
}

static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
                           int base, int16_t offset)
{
    const char *opn = "ldst_pair";
    TCGv t0, t1;

    if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
        generate_exception(ctx, EXCP_RI);
10032 10033 10034
        return;
    }

10035 10036
    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
10037

10038 10039 10040 10041 10042
    gen_base_offset_addr(ctx, t0, base, offset);

    switch (opc) {
    case LWP:
        save_cpu_state(ctx, 0);
10043
        op_ld_lw(t1, t0, ctx);
10044 10045 10046
        gen_store_gpr(t1, rd);
        tcg_gen_movi_tl(t1, 4);
        gen_op_addr_add(ctx, t0, t0, t1);
10047
        op_ld_lw(t1, t0, ctx);
10048 10049 10050 10051
        gen_store_gpr(t1, rd+1);
        opn = "lwp";
        break;
    case SWP:
10052
        save_cpu_state(ctx, 0);
10053
        gen_load_gpr(t1, rd);
10054
        op_st_sw(t1, t0, ctx);
10055 10056 10057
        tcg_gen_movi_tl(t1, 4);
        gen_op_addr_add(ctx, t0, t0, t1);
        gen_load_gpr(t1, rd+1);
10058
        op_st_sw(t1, t0, ctx);
10059 10060 10061 10062 10063
        opn = "swp";
        break;
#ifdef TARGET_MIPS64
    case LDP:
        save_cpu_state(ctx, 0);
10064
        op_ld_ld(t1, t0, ctx);
10065 10066 10067
        gen_store_gpr(t1, rd);
        tcg_gen_movi_tl(t1, 8);
        gen_op_addr_add(ctx, t0, t0, t1);
10068
        op_ld_ld(t1, t0, ctx);
10069 10070 10071 10072
        gen_store_gpr(t1, rd+1);
        opn = "ldp";
        break;
    case SDP:
10073
        save_cpu_state(ctx, 0);
10074
        gen_load_gpr(t1, rd);
10075
        op_st_sd(t1, t0, ctx);
10076 10077 10078
        tcg_gen_movi_tl(t1, 8);
        gen_op_addr_add(ctx, t0, t0, t1);
        gen_load_gpr(t1, rd+1);
10079
        op_st_sd(t1, t0, ctx);
10080 10081 10082
        opn = "sdp";
        break;
#endif
B
bellard 已提交
10083
    }
B
Blue Swirl 已提交
10084
    (void)opn; /* avoid a compiler warning */
10085 10086 10087 10088
    MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
}
10089

10090
static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130
                           int *is_branch)
{
    int extension = (ctx->opcode >> 6) & 0x3f;
    int minor = (ctx->opcode >> 12) & 0xf;
    uint32_t mips32_op;

    switch (extension) {
    case TEQ:
        mips32_op = OPC_TEQ;
        goto do_trap;
    case TGE:
        mips32_op = OPC_TGE;
        goto do_trap;
    case TGEU:
        mips32_op = OPC_TGEU;
        goto do_trap;
    case TLT:
        mips32_op = OPC_TLT;
        goto do_trap;
    case TLTU:
        mips32_op = OPC_TLTU;
        goto do_trap;
    case TNE:
        mips32_op = OPC_TNE;
    do_trap:
        gen_trap(ctx, mips32_op, rs, rt, -1);
        break;
#ifndef CONFIG_USER_ONLY
    case MFC0:
    case MFC0 + 32:
        if (rt == 0) {
            /* Treat as NOP. */
            break;
        }
        gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
        break;
    case MTC0:
    case MTC0 + 32:
        {
            TCGv t0 = tcg_temp_new();
10131

10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363
            gen_load_gpr(t0, rt);
            gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
            tcg_temp_free(t0);
        }
        break;
#endif
    case 0x2c:
        switch (minor) {
        case SEB:
            gen_bshfl(ctx, OPC_SEB, rs, rt);
            break;
        case SEH:
            gen_bshfl(ctx, OPC_SEH, rs, rt);
            break;
        case CLO:
            mips32_op = OPC_CLO;
            goto do_cl;
        case CLZ:
            mips32_op = OPC_CLZ;
        do_cl:
            check_insn(env, ctx, ISA_MIPS32);
            gen_cl(ctx, mips32_op, rt, rs);
            break;
        case RDHWR:
            gen_rdhwr(env, ctx, rt, rs);
            break;
        case WSBH:
            gen_bshfl(ctx, OPC_WSBH, rs, rt);
            break;
        case MULT:
            mips32_op = OPC_MULT;
            goto do_muldiv;
        case MULTU:
            mips32_op = OPC_MULTU;
            goto do_muldiv;
        case DIV:
            mips32_op = OPC_DIV;
            goto do_muldiv;
        case DIVU:
            mips32_op = OPC_DIVU;
            goto do_muldiv;
        case MADD:
            mips32_op = OPC_MADD;
            goto do_muldiv;
        case MADDU:
            mips32_op = OPC_MADDU;
            goto do_muldiv;
        case MSUB:
            mips32_op = OPC_MSUB;
            goto do_muldiv;
        case MSUBU:
            mips32_op = OPC_MSUBU;
        do_muldiv:
            check_insn(env, ctx, ISA_MIPS32);
            gen_muldiv(ctx, mips32_op, rs, rt);
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    case 0x34:
        switch (minor) {
        case MFC2:
        case MTC2:
        case MFHC2:
        case MTHC2:
        case CFC2:
        case CTC2:
            generate_exception_err(ctx, EXCP_CpU, 2);
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    case 0x3c:
        switch (minor) {
        case JALR:
        case JALR_HB:
            gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0);
            *is_branch = 1;
            break;
        case JALRS:
        case JALRS_HB:
            gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0);
            *is_branch = 1;
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    case 0x05:
        switch (minor) {
        case RDPGPR:
            check_insn(env, ctx, ISA_MIPS32R2);
            gen_load_srsgpr(rt, rs);
            break;
        case WRPGPR:
            check_insn(env, ctx, ISA_MIPS32R2);
            gen_store_srsgpr(rt, rs);
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
#ifndef CONFIG_USER_ONLY
    case 0x0d:
        switch (minor) {
        case TLBP:
            mips32_op = OPC_TLBP;
            goto do_cp0;
        case TLBR:
            mips32_op = OPC_TLBR;
            goto do_cp0;
        case TLBWI:
            mips32_op = OPC_TLBWI;
            goto do_cp0;
        case TLBWR:
            mips32_op = OPC_TLBWR;
            goto do_cp0;
        case WAIT:
            mips32_op = OPC_WAIT;
            goto do_cp0;
        case DERET:
            mips32_op = OPC_DERET;
            goto do_cp0;
        case ERET:
            mips32_op = OPC_ERET;
        do_cp0:
            gen_cp0(env, ctx, mips32_op, rt, rs);
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    case 0x1d:
        switch (minor) {
        case DI:
            {
                TCGv t0 = tcg_temp_new();

                save_cpu_state(ctx, 1);
                gen_helper_di(t0);
                gen_store_gpr(t0, rs);
                /* Stop translation as we may have switched the execution mode */
                ctx->bstate = BS_STOP;
                tcg_temp_free(t0);
            }
            break;
        case EI:
            {
                TCGv t0 = tcg_temp_new();

                save_cpu_state(ctx, 1);
                gen_helper_ei(t0);
                gen_store_gpr(t0, rs);
                /* Stop translation as we may have switched the execution mode */
                ctx->bstate = BS_STOP;
                tcg_temp_free(t0);
            }
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
#endif
    case 0x2d:
        switch (minor) {
        case SYNC:
            /* NOP */
            break;
        case SYSCALL:
            generate_exception(ctx, EXCP_SYSCALL);
            ctx->bstate = BS_STOP;
            break;
        case SDBBP:
            check_insn(env, ctx, ISA_MIPS32);
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
                generate_exception(ctx, EXCP_DBp);
            } else {
                generate_exception(ctx, EXCP_DBp);
            }
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    case 0x35:
        switch (minor) {
        case MFHI32:
            gen_HILO(ctx, OPC_MFHI, rs);
            break;
        case MFLO32:
            gen_HILO(ctx, OPC_MFLO, rs);
            break;
        case MTHI32:
            gen_HILO(ctx, OPC_MTHI, rs);
            break;
        case MTLO32:
            gen_HILO(ctx, OPC_MTLO, rs);
            break;
        default:
            goto pool32axf_invalid;
        }
        break;
    default:
    pool32axf_invalid:
        MIPS_INVAL("pool32axf");
        generate_exception(ctx, EXCP_RI);
        break;
    }
}

/* Values for microMIPS fmt field.  Variable-width, depending on which
   formats the instruction supports.  */

enum {
    FMT_SD_S = 0,
    FMT_SD_D = 1,

    FMT_SDPS_S = 0,
    FMT_SDPS_D = 1,
    FMT_SDPS_PS = 2,

    FMT_SWL_S = 0,
    FMT_SWL_W = 1,
    FMT_SWL_L = 2,

    FMT_DWL_D = 0,
    FMT_DWL_W = 1,
    FMT_DWL_L = 2
};

10364
static void gen_pool32fxf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609
{
    int extension = (ctx->opcode >> 6) & 0x3ff;
    uint32_t mips32_op;

#define FLOAT_1BIT_FMT(opc, fmt) (fmt << 8) | opc
#define FLOAT_2BIT_FMT(opc, fmt) (fmt << 7) | opc
#define COND_FLOAT_MOV(opc, cond) (cond << 7) | opc

    switch (extension) {
    case FLOAT_1BIT_FMT(CFC1, 0):
        mips32_op = OPC_CFC1;
        goto do_cp1;
    case FLOAT_1BIT_FMT(CTC1, 0):
        mips32_op = OPC_CTC1;
        goto do_cp1;
    case FLOAT_1BIT_FMT(MFC1, 0):
        mips32_op = OPC_MFC1;
        goto do_cp1;
    case FLOAT_1BIT_FMT(MTC1, 0):
        mips32_op = OPC_MTC1;
        goto do_cp1;
    case FLOAT_1BIT_FMT(MFHC1, 0):
        mips32_op = OPC_MFHC1;
        goto do_cp1;
    case FLOAT_1BIT_FMT(MTHC1, 0):
        mips32_op = OPC_MTHC1;
    do_cp1:
        gen_cp1(ctx, mips32_op, rt, rs);
        break;

        /* Reciprocal square root */
    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S):
        mips32_op = OPC_RSQRT_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D):
        mips32_op = OPC_RSQRT_D;
        goto do_unaryfp;

        /* Square root */
    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S):
        mips32_op = OPC_SQRT_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D):
        mips32_op = OPC_SQRT_D;
        goto do_unaryfp;

        /* Reciprocal */
    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S):
        mips32_op = OPC_RECIP_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D):
        mips32_op = OPC_RECIP_D;
        goto do_unaryfp;

        /* Floor */
    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S):
        mips32_op = OPC_FLOOR_L_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D):
        mips32_op = OPC_FLOOR_L_D;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S):
        mips32_op = OPC_FLOOR_W_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D):
        mips32_op = OPC_FLOOR_W_D;
        goto do_unaryfp;

        /* Ceiling */
    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S):
        mips32_op = OPC_CEIL_L_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D):
        mips32_op = OPC_CEIL_L_D;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S):
        mips32_op = OPC_CEIL_W_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D):
        mips32_op = OPC_CEIL_W_D;
        goto do_unaryfp;

        /* Truncation */
    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S):
        mips32_op = OPC_TRUNC_L_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D):
        mips32_op = OPC_TRUNC_L_D;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S):
        mips32_op = OPC_TRUNC_W_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D):
        mips32_op = OPC_TRUNC_W_D;
        goto do_unaryfp;

        /* Round */
    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S):
        mips32_op = OPC_ROUND_L_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D):
        mips32_op = OPC_ROUND_L_D;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S):
        mips32_op = OPC_ROUND_W_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D):
        mips32_op = OPC_ROUND_W_D;
        goto do_unaryfp;

        /* Integer to floating-point conversion */
    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S):
        mips32_op = OPC_CVT_L_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D):
        mips32_op = OPC_CVT_L_D;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S):
        mips32_op = OPC_CVT_W_S;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D):
        mips32_op = OPC_CVT_W_D;
        goto do_unaryfp;

        /* Paired-foo conversions */
    case FLOAT_1BIT_FMT(CVT_S_PL, 0):
        mips32_op = OPC_CVT_S_PL;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_S_PU, 0):
        mips32_op = OPC_CVT_S_PU;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_PW_PS, 0):
        mips32_op = OPC_CVT_PW_PS;
        goto do_unaryfp;
    case FLOAT_1BIT_FMT(CVT_PS_PW, 0):
        mips32_op = OPC_CVT_PS_PW;
        goto do_unaryfp;

        /* Floating-point moves */
    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S):
        mips32_op = OPC_MOV_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D):
        mips32_op = OPC_MOV_D;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS):
        mips32_op = OPC_MOV_PS;
        goto do_unaryfp;

        /* Absolute value */
    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S):
        mips32_op = OPC_ABS_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D):
        mips32_op = OPC_ABS_D;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS):
        mips32_op = OPC_ABS_PS;
        goto do_unaryfp;

        /* Negation */
    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S):
        mips32_op = OPC_NEG_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D):
        mips32_op = OPC_NEG_D;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS):
        mips32_op = OPC_NEG_PS;
        goto do_unaryfp;

        /* Reciprocal square root step */
    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S):
        mips32_op = OPC_RSQRT1_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D):
        mips32_op = OPC_RSQRT1_D;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS):
        mips32_op = OPC_RSQRT1_PS;
        goto do_unaryfp;

        /* Reciprocal step */
    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S):
        mips32_op = OPC_RECIP1_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D):
        mips32_op = OPC_RECIP1_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS):
        mips32_op = OPC_RECIP1_PS;
        goto do_unaryfp;

        /* Conversions from double */
    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S):
        mips32_op = OPC_CVT_D_S;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W):
        mips32_op = OPC_CVT_D_W;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L):
        mips32_op = OPC_CVT_D_L;
        goto do_unaryfp;

        /* Conversions from single */
    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D):
        mips32_op = OPC_CVT_S_D;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W):
        mips32_op = OPC_CVT_S_W;
        goto do_unaryfp;
    case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L):
        mips32_op = OPC_CVT_S_L;
    do_unaryfp:
        gen_farith(ctx, mips32_op, -1, rs, rt, 0);
        break;

        /* Conditional moves on floating-point codes */
    case COND_FLOAT_MOV(MOVT, 0):
    case COND_FLOAT_MOV(MOVT, 1):
    case COND_FLOAT_MOV(MOVT, 2):
    case COND_FLOAT_MOV(MOVT, 3):
    case COND_FLOAT_MOV(MOVT, 4):
    case COND_FLOAT_MOV(MOVT, 5):
    case COND_FLOAT_MOV(MOVT, 6):
    case COND_FLOAT_MOV(MOVT, 7):
        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1);
        break;
    case COND_FLOAT_MOV(MOVF, 0):
    case COND_FLOAT_MOV(MOVF, 1):
    case COND_FLOAT_MOV(MOVF, 2):
    case COND_FLOAT_MOV(MOVF, 3):
    case COND_FLOAT_MOV(MOVF, 4):
    case COND_FLOAT_MOV(MOVF, 5):
    case COND_FLOAT_MOV(MOVF, 6):
    case COND_FLOAT_MOV(MOVF, 7):
        gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0);
        break;
    default:
        MIPS_INVAL("pool32fxf");
        generate_exception(ctx, EXCP_RI);
        break;
    }
}

10610
static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184
                                    uint16_t insn_hw1, int *is_branch)
{
    int32_t offset;
    uint16_t insn;
    int rt, rs, rd, rr;
    int16_t imm;
    uint32_t op, minor, mips32_op;
    uint32_t cond, fmt, cc;

    insn = lduw_code(ctx->pc + 2);
    ctx->opcode = (ctx->opcode << 16) | insn;

    rt = (ctx->opcode >> 21) & 0x1f;
    rs = (ctx->opcode >> 16) & 0x1f;
    rd = (ctx->opcode >> 11) & 0x1f;
    rr = (ctx->opcode >> 6) & 0x1f;
    imm = (int16_t) ctx->opcode;

    op = (ctx->opcode >> 26) & 0x3f;
    switch (op) {
    case POOL32A:
        minor = ctx->opcode & 0x3f;
        switch (minor) {
        case 0x00:
            minor = (ctx->opcode >> 6) & 0xf;
            switch (minor) {
            case SLL32:
                mips32_op = OPC_SLL;
                goto do_shifti;
            case SRA:
                mips32_op = OPC_SRA;
                goto do_shifti;
            case SRL32:
                mips32_op = OPC_SRL;
                goto do_shifti;
            case ROTR:
                mips32_op = OPC_ROTR;
            do_shifti:
                gen_shift_imm(env, ctx, mips32_op, rt, rs, rd);
                break;
            default:
                goto pool32a_invalid;
            }
            break;
        case 0x10:
            minor = (ctx->opcode >> 6) & 0xf;
            switch (minor) {
                /* Arithmetic */
            case ADD:
                mips32_op = OPC_ADD;
                goto do_arith;
            case ADDU32:
                mips32_op = OPC_ADDU;
                goto do_arith;
            case SUB:
                mips32_op = OPC_SUB;
                goto do_arith;
            case SUBU32:
                mips32_op = OPC_SUBU;
                goto do_arith;
            case MUL:
                mips32_op = OPC_MUL;
            do_arith:
                gen_arith(env, ctx, mips32_op, rd, rs, rt);
                break;
                /* Shifts */
            case SLLV:
                mips32_op = OPC_SLLV;
                goto do_shift;
            case SRLV:
                mips32_op = OPC_SRLV;
                goto do_shift;
            case SRAV:
                mips32_op = OPC_SRAV;
                goto do_shift;
            case ROTRV:
                mips32_op = OPC_ROTRV;
            do_shift:
                gen_shift(env, ctx, mips32_op, rd, rs, rt);
                break;
                /* Logical operations */
            case AND:
                mips32_op = OPC_AND;
                goto do_logic;
            case OR32:
                mips32_op = OPC_OR;
                goto do_logic;
            case NOR:
                mips32_op = OPC_NOR;
                goto do_logic;
            case XOR32:
                mips32_op = OPC_XOR;
            do_logic:
                gen_logic(env, mips32_op, rd, rs, rt);
                break;
                /* Set less than */
            case SLT:
                mips32_op = OPC_SLT;
                goto do_slt;
            case SLTU:
                mips32_op = OPC_SLTU;
            do_slt:
                gen_slt(env, mips32_op, rd, rs, rt);
                break;
            default:
                goto pool32a_invalid;
            }
            break;
        case 0x18:
            minor = (ctx->opcode >> 6) & 0xf;
            switch (minor) {
                /* Conditional moves */
            case MOVN:
                mips32_op = OPC_MOVN;
                goto do_cmov;
            case MOVZ:
                mips32_op = OPC_MOVZ;
            do_cmov:
                gen_cond_move(env, mips32_op, rd, rs, rt);
                break;
            case LWXS:
                gen_ldxs(ctx, rs, rt, rd);
                break;
            default:
                goto pool32a_invalid;
            }
            break;
        case INS:
            gen_bitops(ctx, OPC_INS, rt, rs, rr, rd);
            return;
        case EXT:
            gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);
            return;
        case POOL32AXF:
            gen_pool32axf(env, ctx, rt, rs, is_branch);
            break;
        case 0x07:
            generate_exception(ctx, EXCP_BREAK);
            break;
        default:
        pool32a_invalid:
                MIPS_INVAL("pool32a");
                generate_exception(ctx, EXCP_RI);
                break;
        }
        break;
    case POOL32B:
        minor = (ctx->opcode >> 12) & 0xf;
        switch (minor) {
        case CACHE:
            /* Treat as no-op. */
            break;
        case LWC2:
        case SWC2:
            /* COP2: Not implemented. */
            generate_exception_err(ctx, EXCP_CpU, 2);
            break;
        case LWP:
        case SWP:
#ifdef TARGET_MIPS64
        case LDP:
        case SDP:
#endif
            gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
            break;
        case LWM32:
        case SWM32:
#ifdef TARGET_MIPS64
        case LDM:
        case SDM:
#endif
            gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
            break;
        default:
            MIPS_INVAL("pool32b");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case POOL32F:
        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
            minor = ctx->opcode & 0x3f;
            check_cp1_enabled(ctx);
            switch (minor) {
            case ALNV_PS:
                mips32_op = OPC_ALNV_PS;
                goto do_madd;
            case MADD_S:
                mips32_op = OPC_MADD_S;
                goto do_madd;
            case MADD_D:
                mips32_op = OPC_MADD_D;
                goto do_madd;
            case MADD_PS:
                mips32_op = OPC_MADD_PS;
                goto do_madd;
            case MSUB_S:
                mips32_op = OPC_MSUB_S;
                goto do_madd;
            case MSUB_D:
                mips32_op = OPC_MSUB_D;
                goto do_madd;
            case MSUB_PS:
                mips32_op = OPC_MSUB_PS;
                goto do_madd;
            case NMADD_S:
                mips32_op = OPC_NMADD_S;
                goto do_madd;
            case NMADD_D:
                mips32_op = OPC_NMADD_D;
                goto do_madd;
            case NMADD_PS:
                mips32_op = OPC_NMADD_PS;
                goto do_madd;
            case NMSUB_S:
                mips32_op = OPC_NMSUB_S;
                goto do_madd;
            case NMSUB_D:
                mips32_op = OPC_NMSUB_D;
                goto do_madd;
            case NMSUB_PS:
                mips32_op = OPC_NMSUB_PS;
            do_madd:
                gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt);
                break;
            case CABS_COND_FMT:
                cond = (ctx->opcode >> 6) & 0xf;
                cc = (ctx->opcode >> 13) & 0x7;
                fmt = (ctx->opcode >> 10) & 0x3;
                switch (fmt) {
                case 0x0:
                    gen_cmpabs_s(ctx, cond, rt, rs, cc);
                    break;
                case 0x1:
                    gen_cmpabs_d(ctx, cond, rt, rs, cc);
                    break;
                case 0x2:
                    gen_cmpabs_ps(ctx, cond, rt, rs, cc);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            case C_COND_FMT:
                cond = (ctx->opcode >> 6) & 0xf;
                cc = (ctx->opcode >> 13) & 0x7;
                fmt = (ctx->opcode >> 10) & 0x3;
                switch (fmt) {
                case 0x0:
                    gen_cmp_s(ctx, cond, rt, rs, cc);
                    break;
                case 0x1:
                    gen_cmp_d(ctx, cond, rt, rs, cc);
                    break;
                case 0x2:
                    gen_cmp_ps(ctx, cond, rt, rs, cc);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            case POOL32FXF:
                gen_pool32fxf(env, ctx, rt, rs);
                break;
            case 0x00:
                /* PLL foo */
                switch ((ctx->opcode >> 6) & 0x7) {
                case PLL_PS:
                    mips32_op = OPC_PLL_PS;
                    goto do_ps;
                case PLU_PS:
                    mips32_op = OPC_PLU_PS;
                    goto do_ps;
                case PUL_PS:
                    mips32_op = OPC_PUL_PS;
                    goto do_ps;
                case PUU_PS:
                    mips32_op = OPC_PUU_PS;
                    goto do_ps;
                case CVT_PS_S:
                    mips32_op = OPC_CVT_PS_S;
                do_ps:
                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            case 0x08:
                /* [LS][WDU]XC1 */
                switch ((ctx->opcode >> 6) & 0x7) {
                case LWXC1:
                    mips32_op = OPC_LWXC1;
                    goto do_ldst_cp1;
                case SWXC1:
                    mips32_op = OPC_SWXC1;
                    goto do_ldst_cp1;
                case LDXC1:
                    mips32_op = OPC_LDXC1;
                    goto do_ldst_cp1;
                case SDXC1:
                    mips32_op = OPC_SDXC1;
                    goto do_ldst_cp1;
                case LUXC1:
                    mips32_op = OPC_LUXC1;
                    goto do_ldst_cp1;
                case SUXC1:
                    mips32_op = OPC_SUXC1;
                do_ldst_cp1:
                    gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            case 0x18:
                /* 3D insns */
                fmt = (ctx->opcode >> 9) & 0x3;
                switch ((ctx->opcode >> 6) & 0x7) {
                case RSQRT2_FMT:
                    switch (fmt) {
                    case FMT_SDPS_S:
                        mips32_op = OPC_RSQRT2_S;
                        goto do_3d;
                    case FMT_SDPS_D:
                        mips32_op = OPC_RSQRT2_D;
                        goto do_3d;
                    case FMT_SDPS_PS:
                        mips32_op = OPC_RSQRT2_PS;
                        goto do_3d;
                    default:
                        goto pool32f_invalid;
                    }
                    break;
                case RECIP2_FMT:
                    switch (fmt) {
                    case FMT_SDPS_S:
                        mips32_op = OPC_RECIP2_S;
                        goto do_3d;
                    case FMT_SDPS_D:
                        mips32_op = OPC_RECIP2_D;
                        goto do_3d;
                    case FMT_SDPS_PS:
                        mips32_op = OPC_RECIP2_PS;
                        goto do_3d;
                    default:
                        goto pool32f_invalid;
                    }
                    break;
                case ADDR_PS:
                    mips32_op = OPC_ADDR_PS;
                    goto do_3d;
                case MULR_PS:
                    mips32_op = OPC_MULR_PS;
                do_3d:
                    gen_farith(ctx, mips32_op, rt, rs, rd, 0);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            case 0x20:
                /* MOV[FT].fmt and PREFX */
                cc = (ctx->opcode >> 13) & 0x7;
                fmt = (ctx->opcode >> 9) & 0x3;
                switch ((ctx->opcode >> 6) & 0x7) {
                case MOVF_FMT:
                    switch (fmt) {
                    case FMT_SDPS_S:
                        gen_movcf_s(rs, rt, cc, 0);
                        break;
                    case FMT_SDPS_D:
                        gen_movcf_d(ctx, rs, rt, cc, 0);
                        break;
                    case FMT_SDPS_PS:
                        gen_movcf_ps(rs, rt, cc, 0);
                        break;
                    default:
                        goto pool32f_invalid;
                    }
                    break;
                case MOVT_FMT:
                    switch (fmt) {
                    case FMT_SDPS_S:
                        gen_movcf_s(rs, rt, cc, 1);
                        break;
                    case FMT_SDPS_D:
                        gen_movcf_d(ctx, rs, rt, cc, 1);
                        break;
                    case FMT_SDPS_PS:
                        gen_movcf_ps(rs, rt, cc, 1);
                        break;
                    default:
                        goto pool32f_invalid;
                    }
                    break;
                case PREFX:
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
#define FINSN_3ARG_SDPS(prfx)                           \
                switch ((ctx->opcode >> 8) & 0x3) {     \
                case FMT_SDPS_S:                        \
                    mips32_op = OPC_##prfx##_S;         \
                    goto do_fpop;                       \
                case FMT_SDPS_D:                        \
                    mips32_op = OPC_##prfx##_D;         \
                    goto do_fpop;                       \
                case FMT_SDPS_PS:                       \
                    mips32_op = OPC_##prfx##_PS;        \
                    goto do_fpop;                       \
                default:                                \
                    goto pool32f_invalid;               \
                }
            case 0x30:
                /* regular FP ops */
                switch ((ctx->opcode >> 6) & 0x3) {
                case ADD_FMT:
                    FINSN_3ARG_SDPS(ADD);
                    break;
                case SUB_FMT:
                    FINSN_3ARG_SDPS(SUB);
                    break;
                case MUL_FMT:
                    FINSN_3ARG_SDPS(MUL);
                    break;
                case DIV_FMT:
                    fmt = (ctx->opcode >> 8) & 0x3;
                    if (fmt == 1) {
                        mips32_op = OPC_DIV_D;
                    } else if (fmt == 0) {
                        mips32_op = OPC_DIV_S;
                    } else {
                        goto pool32f_invalid;
                    }
                    goto do_fpop;
                default:
                    goto pool32f_invalid;
                }
                break;
            case 0x38:
                /* cmovs */
                switch ((ctx->opcode >> 6) & 0x3) {
                case MOVN_FMT:
                    FINSN_3ARG_SDPS(MOVN);
                    break;
                case MOVZ_FMT:
                    FINSN_3ARG_SDPS(MOVZ);
                    break;
                default:
                    goto pool32f_invalid;
                }
                break;
            do_fpop:
                gen_farith(ctx, mips32_op, rt, rs, rd, 0);
                break;
            default:
            pool32f_invalid:
                MIPS_INVAL("pool32f");
                generate_exception(ctx, EXCP_RI);
                break;
            }
        } else {
            generate_exception_err(ctx, EXCP_CpU, 1);
        }
        break;
    case POOL32I:
        minor = (ctx->opcode >> 21) & 0x1f;
        switch (minor) {
        case BLTZ:
            mips32_op = OPC_BLTZ;
            goto do_branch;
        case BLTZAL:
            mips32_op = OPC_BLTZAL;
            goto do_branch;
        case BLTZALS:
            mips32_op = OPC_BLTZALS;
            goto do_branch;
        case BGEZ:
            mips32_op = OPC_BGEZ;
            goto do_branch;
        case BGEZAL:
            mips32_op = OPC_BGEZAL;
            goto do_branch;
        case BGEZALS:
            mips32_op = OPC_BGEZALS;
            goto do_branch;
        case BLEZ:
            mips32_op = OPC_BLEZ;
            goto do_branch;
        case BGTZ:
            mips32_op = OPC_BGTZ;
        do_branch:
            gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
            *is_branch = 1;
            break;

            /* Traps */
        case TLTI:
            mips32_op = OPC_TLTI;
            goto do_trapi;
        case TGEI:
            mips32_op = OPC_TGEI;
            goto do_trapi;
        case TLTIU:
            mips32_op = OPC_TLTIU;
            goto do_trapi;
        case TGEIU:
            mips32_op = OPC_TGEIU;
            goto do_trapi;
        case TNEI:
            mips32_op = OPC_TNEI;
            goto do_trapi;
        case TEQI:
            mips32_op = OPC_TEQI;
        do_trapi:
            gen_trap(ctx, mips32_op, rs, -1, imm);
            break;

        case BNEZC:
        case BEQZC:
            gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
                               4, rs, 0, imm << 1);
            /* Compact branches don't have a delay slot, so just let
               the normal delay slot handling take us to the branch
               target. */
            break;
        case LUI:
            gen_logic_imm(env, OPC_LUI, rs, -1, imm);
            break;
        case SYNCI:
            break;
        case BC2F:
        case BC2T:
            /* COP2: Not implemented. */
            generate_exception_err(ctx, EXCP_CpU, 2);
            break;
        case BC1F:
            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F;
            goto do_cp1branch;
        case BC1T:
            mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T;
            goto do_cp1branch;
        case BC1ANY4F:
            mips32_op = OPC_BC1FANY4;
            goto do_cp1mips3d;
        case BC1ANY4T:
            mips32_op = OPC_BC1TANY4;
        do_cp1mips3d:
            check_cop1x(ctx);
            check_insn(env, ctx, ASE_MIPS3D);
            /* Fall through */
        do_cp1branch:
            gen_compute_branch1(env, ctx, mips32_op,
                                (ctx->opcode >> 18) & 0x7, imm << 1);
            *is_branch = 1;
            break;
        case BPOSGE64:
        case BPOSGE32:
            /* MIPS DSP: not implemented */
            /* Fall through */
        default:
            MIPS_INVAL("pool32i");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case POOL32C:
        minor = (ctx->opcode >> 12) & 0xf;
        switch (minor) {
        case LWL:
            mips32_op = OPC_LWL;
11185
            goto do_ld_lr;
11186 11187
        case SWL:
            mips32_op = OPC_SWL;
11188
            goto do_st_lr;
11189 11190
        case LWR:
            mips32_op = OPC_LWR;
11191
            goto do_ld_lr;
11192 11193
        case SWR:
            mips32_op = OPC_SWR;
11194
            goto do_st_lr;
11195 11196 11197
#if defined(TARGET_MIPS64)
        case LDL:
            mips32_op = OPC_LDL;
11198
            goto do_ld_lr;
11199 11200
        case SDL:
            mips32_op = OPC_SDL;
11201
            goto do_st_lr;
11202 11203
        case LDR:
            mips32_op = OPC_LDR;
11204
            goto do_ld_lr;
11205 11206
        case SDR:
            mips32_op = OPC_SDR;
11207
            goto do_st_lr;
11208 11209
        case LWU:
            mips32_op = OPC_LWU;
11210
            goto do_ld_lr;
11211 11212
        case LLD:
            mips32_op = OPC_LLD;
11213
            goto do_ld_lr;
11214 11215 11216
#endif
        case LL:
            mips32_op = OPC_LL;
11217 11218
            goto do_ld_lr;
        do_ld_lr:
11219
            gen_ld(env, ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
11220 11221 11222
            break;
        do_st_lr:
            gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325
            break;
        case SC:
            gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12));
            break;
#if defined(TARGET_MIPS64)
        case SCD:
            gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12));
            break;
#endif
        case PREF:
            /* Treat as no-op */
            break;
        default:
            MIPS_INVAL("pool32c");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case ADDI32:
        mips32_op = OPC_ADDI;
        goto do_addi;
    case ADDIU32:
        mips32_op = OPC_ADDIU;
    do_addi:
        gen_arith_imm(env, ctx, mips32_op, rt, rs, imm);
        break;

        /* Logical operations */
    case ORI32:
        mips32_op = OPC_ORI;
        goto do_logici;
    case XORI32:
        mips32_op = OPC_XORI;
        goto do_logici;
    case ANDI32:
        mips32_op = OPC_ANDI;
    do_logici:
        gen_logic_imm(env, mips32_op, rt, rs, imm);
        break;

        /* Set less than immediate */
    case SLTI32:
        mips32_op = OPC_SLTI;
        goto do_slti;
    case SLTIU32:
        mips32_op = OPC_SLTIU;
    do_slti:
        gen_slt_imm(env, mips32_op, rt, rs, imm);
        break;
    case JALX32:
        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
        gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset);
        *is_branch = 1;
        break;
    case JALS32:
        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1;
        gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset);
        *is_branch = 1;
        break;
    case BEQ32:
        gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);
        *is_branch = 1;
        break;
    case BNE32:
        gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);
        *is_branch = 1;
        break;
    case J32:
        gen_compute_branch(ctx, OPC_J, 4, rt, rs,
                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
        *is_branch = 1;
        break;
    case JAL32:
        gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,
                           (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
        *is_branch = 1;
        break;
        /* Floating point (COP1) */
    case LWC132:
        mips32_op = OPC_LWC1;
        goto do_cop1;
    case LDC132:
        mips32_op = OPC_LDC1;
        goto do_cop1;
    case SWC132:
        mips32_op = OPC_SWC1;
        goto do_cop1;
    case SDC132:
        mips32_op = OPC_SDC1;
    do_cop1:
        gen_cop1_ldst(env, ctx, mips32_op, rt, rs, imm);
        break;
    case ADDIUPC:
        {
            int reg = mmreg(ZIMM(ctx->opcode, 23, 3));
            int offset = SIMM(ctx->opcode, 0, 23) << 2;

            gen_addiupc(ctx, reg, offset, 0, 0);
        }
        break;
        /* Loads and stores */
    case LB32:
        mips32_op = OPC_LB;
11326
        goto do_ld;
11327 11328
    case LBU32:
        mips32_op = OPC_LBU;
11329
        goto do_ld;
11330 11331
    case LH32:
        mips32_op = OPC_LH;
11332
        goto do_ld;
11333 11334
    case LHU32:
        mips32_op = OPC_LHU;
11335
        goto do_ld;
11336 11337
    case LW32:
        mips32_op = OPC_LW;
11338
        goto do_ld;
11339 11340 11341
#ifdef TARGET_MIPS64
    case LD32:
        mips32_op = OPC_LD;
11342
        goto do_ld;
11343 11344
    case SD32:
        mips32_op = OPC_SD;
11345
        goto do_st;
11346 11347 11348
#endif
    case SB32:
        mips32_op = OPC_SB;
11349
        goto do_st;
11350 11351
    case SH32:
        mips32_op = OPC_SH;
11352
        goto do_st;
11353 11354
    case SW32:
        mips32_op = OPC_SW;
11355 11356
        goto do_st;
    do_ld:
11357
        gen_ld(env, ctx, mips32_op, rt, rs, imm);
11358 11359 11360
        break;
    do_st:
        gen_st(ctx, mips32_op, rt, rs, imm);
11361 11362 11363 11364 11365 11366 11367
        break;
    default:
        generate_exception(ctx, EXCP_RI);
        break;
    }
}

11368
static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509
{
    uint32_t op;

    /* make sure instructions are on a halfword boundary */
    if (ctx->pc & 0x1) {
        env->CP0_BadVAddr = ctx->pc;
        generate_exception(ctx, EXCP_AdEL);
        ctx->bstate = BS_STOP;
        return 2;
    }

    op = (ctx->opcode >> 10) & 0x3f;
    /* Enforce properly-sized instructions in a delay slot */
    if (ctx->hflags & MIPS_HFLAG_BMASK) {
        int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT;

        switch (op) {
        case POOL32A:
        case POOL32B:
        case POOL32I:
        case POOL32C:
        case ADDI32:
        case ADDIU32:
        case ORI32:
        case XORI32:
        case SLTI32:
        case SLTIU32:
        case ANDI32:
        case JALX32:
        case LBU32:
        case LHU32:
        case POOL32F:
        case JALS32:
        case BEQ32:
        case BNE32:
        case J32:
        case JAL32:
        case SB32:
        case SH32:
        case POOL32S:
        case ADDIUPC:
        case SWC132:
        case SDC132:
        case SD32:
        case SW32:
        case LB32:
        case LH32:
        case DADDIU32:
        case POOL48A:           /* ??? */
        case LWC132:
        case LDC132:
        case LD32:
        case LW32:
            if (bits & MIPS_HFLAG_BDS16) {
                generate_exception(ctx, EXCP_RI);
                /* Just stop translation; the user is confused.  */
                ctx->bstate = BS_STOP;
                return 2;
            }
            break;
        case POOL16A:
        case POOL16B:
        case POOL16C:
        case LWGP16:
        case POOL16F:
        case LBU16:
        case LHU16:
        case LWSP16:
        case LW16:
        case SB16:
        case SH16:
        case SWSP16:
        case SW16:
        case MOVE16:
        case ANDI16:
        case POOL16D:
        case POOL16E:
        case BEQZ16:
        case BNEZ16:
        case B16:
        case LI16:
            if (bits & MIPS_HFLAG_BDS32) {
                generate_exception(ctx, EXCP_RI);
                /* Just stop translation; the user is confused.  */
                ctx->bstate = BS_STOP;
                return 2;
            }
            break;
        default:
            break;
        }
    }
    switch (op) {
    case POOL16A:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rs1 = mmreg(uMIPS_RS1(ctx->opcode));
            int rs2 = mmreg(uMIPS_RS2(ctx->opcode));
            uint32_t opc = 0;

            switch (ctx->opcode & 0x1) {
            case ADDU16:
                opc = OPC_ADDU;
                break;
            case SUBU16:
                opc = OPC_SUBU;
                break;
            }

            gen_arith(env, ctx, opc, rd, rs1, rs2);
        }
        break;
    case POOL16B:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rs = mmreg(uMIPS_RS(ctx->opcode));
            int amount = (ctx->opcode >> 1) & 0x7;
            uint32_t opc = 0;
            amount = amount == 0 ? 8 : amount;

            switch (ctx->opcode & 0x1) {
            case SLL16:
                opc = OPC_SLL;
                break;
            case SRL16:
                opc = OPC_SRL;
                break;
            }

            gen_shift_imm(env, ctx, opc, rd, rs, amount);
        }
        break;
    case POOL16C:
        gen_pool16c_insn(env, ctx, is_branch);
        break;
    case LWGP16:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rb = 28;            /* GP */
            int16_t offset = SIMM(ctx->opcode, 0, 7) << 2;

11510
            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541
        }
        break;
    case POOL16F:
        if (ctx->opcode & 1) {
            generate_exception(ctx, EXCP_RI);
        } else {
            /* MOVEP */
            int enc_dest = uMIPS_RD(ctx->opcode);
            int enc_rt = uMIPS_RS2(ctx->opcode);
            int enc_rs = uMIPS_RS1(ctx->opcode);
            int rd, rs, re, rt;
            static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
            static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
            static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 };

            rd = rd_enc[enc_dest];
            re = re_enc[enc_dest];
            rs = rs_rt_enc[enc_rs];
            rt = rs_rt_enc[enc_rt];

            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
            gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0);
        }
        break;
    case LBU16:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4);
            offset = (offset == 0xf ? -1 : offset);

11542
            gen_ld(env, ctx, OPC_LBU, rd, rb, offset);
11543 11544 11545 11546 11547 11548 11549 11550
        }
        break;
    case LHU16:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;

11551
            gen_ld(env, ctx, OPC_LHU, rd, rb, offset);
11552 11553 11554 11555 11556 11557 11558 11559
        }
        break;
    case LWSP16:
        {
            int rd = (ctx->opcode >> 5) & 0x1f;
            int rb = 29;            /* SP */
            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;

11560
            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
11561 11562 11563 11564 11565 11566 11567 11568
        }
        break;
    case LW16:
        {
            int rd = mmreg(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;

11569
            gen_ld(env, ctx, OPC_LW, rd, rb, offset);
11570 11571 11572 11573 11574 11575 11576 11577
        }
        break;
    case SB16:
        {
            int rd = mmreg2(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4);

11578
            gen_st(ctx, OPC_SB, rd, rb, offset);
11579 11580 11581 11582 11583 11584 11585 11586
        }
        break;
    case SH16:
        {
            int rd = mmreg2(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;

11587
            gen_st(ctx, OPC_SH, rd, rb, offset);
11588 11589 11590 11591 11592 11593 11594 11595
        }
        break;
    case SWSP16:
        {
            int rd = (ctx->opcode >> 5) & 0x1f;
            int rb = 29;            /* SP */
            int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;

11596
            gen_st(ctx, OPC_SW, rd, rb, offset);
11597 11598 11599 11600 11601 11602 11603 11604
        }
        break;
    case SW16:
        {
            int rd = mmreg2(uMIPS_RD(ctx->opcode));
            int rb = mmreg(uMIPS_RS(ctx->opcode));
            int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;

11605
            gen_st(ctx, OPC_SW, rd, rb, offset);
11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684
        }
        break;
    case MOVE16:
        {
            int rd = uMIPS_RD5(ctx->opcode);
            int rs = uMIPS_RS5(ctx->opcode);

            gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
        }
        break;
    case ANDI16:
        gen_andi16(env, ctx);
        break;
    case POOL16D:
        switch (ctx->opcode & 0x1) {
        case ADDIUS5:
            gen_addius5(env, ctx);
            break;
        case ADDIUSP:
            gen_addiusp(env, ctx);
            break;
        }
        break;
    case POOL16E:
        switch (ctx->opcode & 0x1) {
        case ADDIUR2:
            gen_addiur2(env, ctx);
            break;
        case ADDIUR1SP:
            gen_addiur1sp(env, ctx);
            break;
        }
        break;
    case B16:
        gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
                           SIMM(ctx->opcode, 0, 10) << 1);
        *is_branch = 1;
        break;
    case BNEZ16:
    case BEQZ16:
        gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
                           mmreg(uMIPS_RD(ctx->opcode)),
                           0, SIMM(ctx->opcode, 0, 7) << 1);
        *is_branch = 1;
        break;
    case LI16:
        {
            int reg = mmreg(uMIPS_RD(ctx->opcode));
            int imm = ZIMM(ctx->opcode, 0, 7);

            imm = (imm == 0x7f ? -1 : imm);
            tcg_gen_movi_tl(cpu_gpr[reg], imm);
        }
        break;
    case RES_20:
    case RES_28:
    case RES_29:
    case RES_30:
    case RES_31:
    case RES_38:
    case RES_39:
        generate_exception(ctx, EXCP_RI);
        break;
    default:
        decode_micromips32_opc (env, ctx, op, is_branch);
        return 4;
    }

    return 2;
}

/* SmartMIPS extension to MIPS32 */

#if defined(TARGET_MIPS64)

/* MDMX extension to MIPS64 */

#endif

11685
static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719
{
    int32_t offset;
    int rs, rt, rd, sa;
    uint32_t op, op1, op2;
    int16_t imm;

    /* make sure instructions are on a word boundary */
    if (ctx->pc & 0x3) {
        env->CP0_BadVAddr = ctx->pc;
        generate_exception(ctx, EXCP_AdEL);
        return;
    }

    /* Handle blikely not taken case */
    if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
        int l1 = gen_new_label();

        MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
        tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
        tcg_gen_movi_i32(hflags, ctx->hflags & ~MIPS_HFLAG_BMASK);
        gen_goto_tb(ctx, 1, ctx->pc + 4);
        gen_set_label(l1);
    }

    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
        tcg_gen_debug_insn_start(ctx->pc);

    op = MASK_OP_MAJOR(ctx->opcode);
    rs = (ctx->opcode >> 21) & 0x1f;
    rt = (ctx->opcode >> 16) & 0x1f;
    rd = (ctx->opcode >> 11) & 0x1f;
    sa = (ctx->opcode >> 6) & 0x1f;
    imm = (int16_t)ctx->opcode;
    switch (op) {
11720 11721
    case OPC_SPECIAL:
        op1 = MASK_SPECIAL(ctx->opcode);
B
bellard 已提交
11722
        switch (op1) {
A
aurel32 已提交
11723 11724 11725
        case OPC_SLL:          /* Shift with immediate */
        case OPC_SRA:
            gen_shift_imm(env, ctx, op1, rd, rt, sa);
11726
            break;
11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742
        case OPC_SRL:
            switch ((ctx->opcode >> 21) & 0x1f) {
            case 1:
                /* rotr is decoded as srl on non-R2 CPUs */
                if (env->insn_flags & ISA_MIPS32R2) {
                    op1 = OPC_ROTR;
                }
                /* Fallthrough */
            case 0:
                gen_shift_imm(env, ctx, op1, rd, rt, sa);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
A
aurel32 已提交
11743 11744
        case OPC_MOVN:         /* Conditional move */
        case OPC_MOVZ:
11745 11746
            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 |
                                 INSN_LOONGSON2E | INSN_LOONGSON2F);
A
aurel32 已提交
11747 11748 11749
            gen_cond_move(env, op1, rd, rs, rt);
            break;
        case OPC_ADD ... OPC_SUBU:
11750
            gen_arith(env, ctx, op1, rd, rs, rt);
11751
            break;
A
aurel32 已提交
11752 11753 11754 11755
        case OPC_SLLV:         /* Shifts */
        case OPC_SRAV:
            gen_shift(env, ctx, op1, rd, rs, rt);
            break;
11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771
        case OPC_SRLV:
            switch ((ctx->opcode >> 6) & 0x1f) {
            case 1:
                /* rotrv is decoded as srlv on non-R2 CPUs */
                if (env->insn_flags & ISA_MIPS32R2) {
                    op1 = OPC_ROTRV;
                }
                /* Fallthrough */
            case 0:
                gen_shift(env, ctx, op1, rd, rs, rt);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
A
aurel32 已提交
11772 11773 11774 11775 11776 11777 11778 11779 11780 11781
        case OPC_SLT:          /* Set on less than */
        case OPC_SLTU:
            gen_slt(env, op1, rd, rs, rt);
            break;
        case OPC_AND:          /* Logic*/
        case OPC_OR:
        case OPC_NOR:
        case OPC_XOR:
            gen_logic(env, op1, rd, rs, rt);
            break;
11782
        case OPC_MULT ... OPC_DIVU:
11783 11784 11785 11786 11787 11788
            if (sa) {
                check_insn(env, ctx, INSN_VR54XX);
                op1 = MASK_MUL_VR54XX(ctx->opcode);
                gen_mul_vr54xx(ctx, op1, rd, rs, rt);
            } else
                gen_muldiv(ctx, op1, rs, rt);
11789 11790
            break;
        case OPC_JR ... OPC_JALR:
11791
            gen_compute_branch(ctx, op1, 4, rs, rd, sa);
11792 11793
            *is_branch = 1;
            break;
11794 11795 11796
        case OPC_TGE ... OPC_TEQ: /* Traps */
        case OPC_TNE:
            gen_trap(ctx, op1, rs, rt, -1);
B
bellard 已提交
11797
            break;
11798 11799 11800
        case OPC_MFHI:          /* Move from HI/LO */
        case OPC_MFLO:
            gen_HILO(ctx, op1, rd);
B
bellard 已提交
11801
            break;
11802 11803 11804
        case OPC_MTHI:
        case OPC_MTLO:          /* Move to HI/LO */
            gen_HILO(ctx, op1, rs);
B
bellard 已提交
11805
            break;
11806 11807 11808 11809 11810
        case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
#ifdef MIPS_STRICT_STANDARD
            MIPS_INVAL("PMON / selsl");
            generate_exception(ctx, EXCP_RI);
#else
P
pbrook 已提交
11811
            gen_helper_0i(pmon, sa);
11812
#endif
11813 11814
            break;
        case OPC_SYSCALL:
B
bellard 已提交
11815
            generate_exception(ctx, EXCP_SYSCALL);
11816
            ctx->bstate = BS_STOP;
B
bellard 已提交
11817
            break;
11818
        case OPC_BREAK:
B
bellard 已提交
11819 11820
            generate_exception(ctx, EXCP_BREAK);
            break;
11821 11822 11823 11824 11825
        case OPC_SPIM:
#ifdef MIPS_STRICT_STANDARD
            MIPS_INVAL("SPIM");
            generate_exception(ctx, EXCP_RI);
#else
11826 11827 11828
           /* Implemented as RI exception for now. */
            MIPS_INVAL("spim (unofficial)");
            generate_exception(ctx, EXCP_RI);
11829
#endif
B
bellard 已提交
11830
            break;
11831
        case OPC_SYNC:
11832
            /* Treat as NOP. */
B
bellard 已提交
11833
            break;
B
bellard 已提交
11834

11835
        case OPC_MOVCI:
11836
            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
11837
            if (env->CP0_Config1 & (1 << CP0C1_FP)) {
11838
                check_cp1_enabled(ctx);
11839 11840 11841
                gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
                          (ctx->opcode >> 16) & 1);
            } else {
11842
                generate_exception_err(ctx, EXCP_CpU, 1);
11843
            }
B
bellard 已提交
11844 11845
            break;

11846
#if defined(TARGET_MIPS64)
11847 11848
       /* MIPS64 specific opcodes */
        case OPC_DSLL:
A
aurel32 已提交
11849
        case OPC_DSRA:
11850
        case OPC_DSLL32:
A
aurel32 已提交
11851
        case OPC_DSRA32:
11852 11853
            check_insn(env, ctx, ISA_MIPS3);
            check_mips_64(ctx);
A
aurel32 已提交
11854
            gen_shift_imm(env, ctx, op1, rd, rt, sa);
11855
            break;
11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891
        case OPC_DSRL:
            switch ((ctx->opcode >> 21) & 0x1f) {
            case 1:
                /* drotr is decoded as dsrl on non-R2 CPUs */
                if (env->insn_flags & ISA_MIPS32R2) {
                    op1 = OPC_DROTR;
                }
                /* Fallthrough */
            case 0:
                check_insn(env, ctx, ISA_MIPS3);
                check_mips_64(ctx);
                gen_shift_imm(env, ctx, op1, rd, rt, sa);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
        case OPC_DSRL32:
            switch ((ctx->opcode >> 21) & 0x1f) {
            case 1:
                /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
                if (env->insn_flags & ISA_MIPS32R2) {
                    op1 = OPC_DROTR32;
                }
                /* Fallthrough */
            case 0:
                check_insn(env, ctx, ISA_MIPS3);
                check_mips_64(ctx);
                gen_shift_imm(env, ctx, op1, rd, rt, sa);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
11892
        case OPC_DADD ... OPC_DSUBU:
11893 11894 11895
            check_insn(env, ctx, ISA_MIPS3);
            check_mips_64(ctx);
            gen_arith(env, ctx, op1, rd, rs, rt);
11896
            break;
A
aurel32 已提交
11897 11898 11899 11900 11901 11902
        case OPC_DSLLV:
        case OPC_DSRAV:
            check_insn(env, ctx, ISA_MIPS3);
            check_mips_64(ctx);
            gen_shift(env, ctx, op1, rd, rs, rt);
            break;
11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920
        case OPC_DSRLV:
            switch ((ctx->opcode >> 6) & 0x1f) {
            case 1:
                /* drotrv is decoded as dsrlv on non-R2 CPUs */
                if (env->insn_flags & ISA_MIPS32R2) {
                    op1 = OPC_DROTRV;
                }
                /* Fallthrough */
            case 0:
                check_insn(env, ctx, ISA_MIPS3);
                check_mips_64(ctx);
                gen_shift(env, ctx, op1, rd, rs, rt);
                break;
            default:
                generate_exception(ctx, EXCP_RI);
                break;
            }
            break;
11921
        case OPC_DMULT ... OPC_DDIVU:
11922 11923
            check_insn(env, ctx, ISA_MIPS3);
            check_mips_64(ctx);
11924 11925
            gen_muldiv(ctx, op1, rs, rt);
            break;
B
bellard 已提交
11926 11927 11928 11929 11930 11931 11932
#endif
        default:            /* Invalid */
            MIPS_INVAL("special");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
11933 11934
    case OPC_SPECIAL2:
        op1 = MASK_SPECIAL2(ctx->opcode);
B
bellard 已提交
11935
        switch (op1) {
11936 11937
        case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
        case OPC_MSUB ... OPC_MSUBU:
11938
            check_insn(env, ctx, ISA_MIPS32);
11939
            gen_muldiv(ctx, op1, rs, rt);
B
bellard 已提交
11940
            break;
11941
        case OPC_MUL:
11942
            gen_arith(env, ctx, op1, rd, rs, rt);
B
bellard 已提交
11943
            break;
A
aurel32 已提交
11944 11945
        case OPC_CLO:
        case OPC_CLZ:
11946
            check_insn(env, ctx, ISA_MIPS32);
11947
            gen_cl(ctx, op1, rd, rs);
B
bellard 已提交
11948
            break;
11949
        case OPC_SDBBP:
B
bellard 已提交
11950 11951 11952
            /* XXX: not clear which exception should be raised
             *      when in debug mode...
             */
11953
            check_insn(env, ctx, ISA_MIPS32);
B
bellard 已提交
11954 11955 11956 11957 11958
            if (!(ctx->hflags & MIPS_HFLAG_DM)) {
                generate_exception(ctx, EXCP_DBp);
            } else {
                generate_exception(ctx, EXCP_DBp);
            }
11959
            /* Treat as NOP. */
B
bellard 已提交
11960
            break;
11961 11962 11963 11964 11965 11966 11967 11968 11969
        case OPC_DIV_G_2F:
        case OPC_DIVU_G_2F:
        case OPC_MULT_G_2F:
        case OPC_MULTU_G_2F:
        case OPC_MOD_G_2F:
        case OPC_MODU_G_2F:
            check_insn(env, ctx, INSN_LOONGSON2F);
            gen_loongson_integer(ctx, op1, rd, rs, rt);
            break;
11970
#if defined(TARGET_MIPS64)
A
aurel32 已提交
11971 11972
        case OPC_DCLO:
        case OPC_DCLZ:
11973 11974
            check_insn(env, ctx, ISA_MIPS64);
            check_mips_64(ctx);
11975 11976
            gen_cl(ctx, op1, rd, rs);
            break;
11977 11978 11979 11980 11981 11982 11983 11984 11985
        case OPC_DMULT_G_2F:
        case OPC_DMULTU_G_2F:
        case OPC_DDIV_G_2F:
        case OPC_DDIVU_G_2F:
        case OPC_DMOD_G_2F:
        case OPC_DMODU_G_2F:
            check_insn(env, ctx, INSN_LOONGSON2F);
            gen_loongson_integer(ctx, op1, rd, rs, rt);
            break;
11986
#endif
B
bellard 已提交
11987 11988 11989 11990 11991 11992
        default:            /* Invalid */
            MIPS_INVAL("special2");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
11993
    case OPC_SPECIAL3:
11994 11995 11996 11997 11998 11999 12000 12001 12002 12003
        op1 = MASK_SPECIAL3(ctx->opcode);
        switch (op1) {
        case OPC_EXT:
        case OPC_INS:
            check_insn(env, ctx, ISA_MIPS32R2);
            gen_bitops(ctx, op1, rt, rs, sa, rd);
            break;
        case OPC_BSHFL:
            check_insn(env, ctx, ISA_MIPS32R2);
            op2 = MASK_BSHFL(ctx->opcode);
12004
            gen_bshfl(ctx, op2, rt, rd);
12005
            break;
12006
        case OPC_RDHWR:
12007
            gen_rdhwr(env, ctx, rt, rd);
12008
            break;
12009
        case OPC_FORK:
12010
            check_insn(env, ctx, ASE_MT);
12011
            {
A
aurel32 已提交
12012 12013
                TCGv t0 = tcg_temp_new();
                TCGv t1 = tcg_temp_new();
12014 12015 12016

                gen_load_gpr(t0, rt);
                gen_load_gpr(t1, rs);
P
pbrook 已提交
12017
                gen_helper_fork(t0, t1);
12018 12019 12020
                tcg_temp_free(t0);
                tcg_temp_free(t1);
            }
12021 12022
            break;
        case OPC_YIELD:
12023
            check_insn(env, ctx, ASE_MT);
12024
            {
A
aurel32 已提交
12025
                TCGv t0 = tcg_temp_new();
12026

A
aurel32 已提交
12027
                save_cpu_state(ctx, 1);
12028
                gen_load_gpr(t0, rs);
P
pbrook 已提交
12029
                gen_helper_yield(t0, t0);
12030 12031 12032
                gen_store_gpr(t0, rd);
                tcg_temp_free(t0);
            }
12033
            break;
12034 12035 12036 12037 12038 12039
        case OPC_DIV_G_2E ... OPC_DIVU_G_2E:
        case OPC_MULT_G_2E ... OPC_MULTU_G_2E:
        case OPC_MOD_G_2E ... OPC_MODU_G_2E:
            check_insn(env, ctx, INSN_LOONGSON2E);
            gen_loongson_integer(ctx, op1, rd, rs, rt);
            break;
12040
#if defined(TARGET_MIPS64)
12041 12042
        case OPC_DEXTM ... OPC_DEXT:
        case OPC_DINSM ... OPC_DINS:
12043 12044
            check_insn(env, ctx, ISA_MIPS64R2);
            check_mips_64(ctx);
12045
            gen_bitops(ctx, op1, rt, rs, sa, rd);
12046
            break;
12047
        case OPC_DBSHFL:
12048 12049
            check_insn(env, ctx, ISA_MIPS64R2);
            check_mips_64(ctx);
12050
            op2 = MASK_DBSHFL(ctx->opcode);
12051
            gen_bshfl(ctx, op2, rt, rd);
T
ths 已提交
12052
            break;
12053 12054 12055 12056 12057 12058
        case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E:
        case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E:
        case OPC_DMOD_G_2E ... OPC_DMODU_G_2E:
            check_insn(env, ctx, INSN_LOONGSON2E);
            gen_loongson_integer(ctx, op1, rd, rs, rt);
            break;
12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070
#endif
        default:            /* Invalid */
            MIPS_INVAL("special3");
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
    case OPC_REGIMM:
        op1 = MASK_REGIMM(ctx->opcode);
        switch (op1) {
        case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
        case OPC_BLTZAL ... OPC_BGEZALL:
12071
            gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
12072 12073
            *is_branch = 1;
            break;
12074 12075 12076 12077 12078
        case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
        case OPC_TNEI:
            gen_trap(ctx, op1, rs, -1, imm);
            break;
        case OPC_SYNCI:
12079
            check_insn(env, ctx, ISA_MIPS32R2);
12080
            /* Treat as NOP. */
B
bellard 已提交
12081 12082
            break;
        default:            /* Invalid */
12083
            MIPS_INVAL("regimm");
B
bellard 已提交
12084 12085 12086 12087
            generate_exception(ctx, EXCP_RI);
            break;
        }
        break;
12088
    case OPC_CP0:
12089
        check_cp0_enabled(ctx);
12090
        op1 = MASK_CP0(ctx->opcode);
B
bellard 已提交
12091
        switch (op1) {
12092 12093
        case OPC_MFC0:
        case OPC_MTC0:
12094 12095
        case OPC_MFTR:
        case OPC_MTTR:
12096
#if defined(TARGET_MIPS64)
12097 12098 12099
        case OPC_DMFC0:
        case OPC_DMTC0:
#endif
12100
#ifndef CONFIG_USER_ONLY
12101
            gen_cp0(env, ctx, op1, rt, rd);
T
ths 已提交
12102
#endif /* !CONFIG_USER_ONLY */
12103 12104
            break;
        case OPC_C0_FIRST ... OPC_C0_LAST:
12105
#ifndef CONFIG_USER_ONLY
12106
            gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);
T
ths 已提交
12107
#endif /* !CONFIG_USER_ONLY */
12108 12109
            break;
        case OPC_MFMC0:
12110
#ifndef CONFIG_USER_ONLY
12111
            {
A
aurel32 已提交
12112
                TCGv t0 = tcg_temp_new();
12113

T
ths 已提交
12114
                op2 = MASK_MFMC0(ctx->opcode);
12115 12116 12117
                switch (op2) {
                case OPC_DMT:
                    check_insn(env, ctx, ASE_MT);
12118
                    gen_helper_dmt(t0);
A
aurel32 已提交
12119
                    gen_store_gpr(t0, rt);
12120 12121 12122
                    break;
                case OPC_EMT:
                    check_insn(env, ctx, ASE_MT);
12123
                    gen_helper_emt(t0);
A
aurel32 已提交
12124
                    gen_store_gpr(t0, rt);
12125
                    break;
12126 12127
                case OPC_DVPE:
                    check_insn(env, ctx, ASE_MT);
12128
                    gen_helper_dvpe(t0);
A
aurel32 已提交
12129
                    gen_store_gpr(t0, rt);
12130 12131 12132
                    break;
                case OPC_EVPE:
                    check_insn(env, ctx, ASE_MT);
12133
                    gen_helper_evpe(t0);
A
aurel32 已提交
12134
                    gen_store_gpr(t0, rt);
12135 12136 12137
                    break;
                case OPC_DI:
                    check_insn(env, ctx, ISA_MIPS32R2);
A
aurel32 已提交
12138
                    save_cpu_state(ctx, 1);
P
pbrook 已提交
12139
                    gen_helper_di(t0);
A
aurel32 已提交
12140
                    gen_store_gpr(t0, rt);
12141 12142 12143 12144 12145
                    /* Stop translation as we may have switched the execution mode */
                    ctx->bstate = BS_STOP;
                    break;
                case OPC_EI:
                    check_insn(env, ctx, ISA_MIPS32R2);
A
aurel32 已提交
12146
                    save_cpu_state(ctx, 1);
P
pbrook 已提交
12147
                    gen_helper_ei(t0);
A
aurel32 已提交
12148
                    gen_store_gpr(t0, rt);
12149 12150 12151 12152 12153 12154 12155 12156 12157
                    /* Stop translation as we may have switched the execution mode */
                    ctx->bstate = BS_STOP;
                    break;
                default:            /* Invalid */
                    MIPS_INVAL("mfmc0");
                    generate_exception(ctx, EXCP_RI);
                    break;
                }
                tcg_temp_free(t0);
12158
            }
T
ths 已提交
12159
#endif /* !CONFIG_USER_ONLY */
B
bellard 已提交
12160
            break;
12161
        case OPC_RDPGPR:
12162
            check_insn(env, ctx, ISA_MIPS32R2);
12163
            gen_load_srsgpr(rt, rd);
12164
            break;
12165
        case OPC_WRPGPR:
12166
            check_insn(env, ctx, ISA_MIPS32R2);
12167
            gen_store_srsgpr(rt, rd);
12168
            break;
B
bellard 已提交
12169
        default:
12170
            MIPS_INVAL("cp0");
12171
            generate_exception(ctx, EXCP_RI);
B
bellard 已提交
12172 12173 12174
            break;
        }
        break;
A
aurel32 已提交
12175 12176
    case OPC_ADDI: /* Arithmetic with immediate opcode */
    case OPC_ADDIU:
12177
         gen_arith_imm(env, ctx, op, rt, rs, imm);
12178
         break;
A
aurel32 已提交
12179 12180 12181 12182 12183 12184 12185 12186 12187 12188
    case OPC_SLTI: /* Set on less than with immediate opcode */
    case OPC_SLTIU:
         gen_slt_imm(env, op, rt, rs, imm);
         break;
    case OPC_ANDI: /* Arithmetic with immediate opcode */
    case OPC_LUI:
    case OPC_ORI:
    case OPC_XORI:
         gen_logic_imm(env, op, rt, rs, imm);
         break;
12189 12190
    case OPC_J ... OPC_JAL: /* Jump */
         offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
12191
         gen_compute_branch(ctx, op, 4, rs, rt, offset);
12192 12193
         *is_branch = 1;
         break;
12194 12195
    case OPC_BEQ ... OPC_BGTZ: /* Branch */
    case OPC_BEQL ... OPC_BGTZL:
12196
         gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
12197 12198
         *is_branch = 1;
         break;
12199
    case OPC_LB ... OPC_LWR: /* Load and stores */
12200
    case OPC_LL:
12201
         gen_ld(env, ctx, op, rt, rs, imm);
12202
         break;
12203 12204
    case OPC_SB ... OPC_SW:
    case OPC_SWR:
12205
         gen_st(ctx, op, rt, rs, imm);
12206
         break;
A
aurel32 已提交
12207 12208 12209
    case OPC_SC:
         gen_st_cond(ctx, op, rt, rs, imm);
         break;
12210
    case OPC_CACHE:
12211
        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
12212
        /* Treat as NOP. */
12213
        break;
12214
    case OPC_PREF:
12215
        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
12216
        /* Treat as NOP. */
B
bellard 已提交
12217
        break;
B
bellard 已提交
12218

12219
    /* Floating point (COP1). */
12220 12221 12222 12223
    case OPC_LWC1:
    case OPC_LDC1:
    case OPC_SWC1:
    case OPC_SDC1:
12224
        gen_cop1_ldst(env, ctx, op, rt, rs, imm);
B
bellard 已提交
12225 12226
        break;

12227
    case OPC_CP1:
12228
        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
12229
            check_cp1_enabled(ctx);
12230 12231
            op1 = MASK_CP1(ctx->opcode);
            switch (op1) {
12232 12233
            case OPC_MFHC1:
            case OPC_MTHC1:
12234
                check_insn(env, ctx, ISA_MIPS32R2);
12235 12236 12237 12238
            case OPC_MFC1:
            case OPC_CFC1:
            case OPC_MTC1:
            case OPC_CTC1:
12239 12240
                gen_cp1(ctx, op1, rt, rd);
                break;
12241
#if defined(TARGET_MIPS64)
12242 12243
            case OPC_DMFC1:
            case OPC_DMTC1:
12244
                check_insn(env, ctx, ISA_MIPS3);
12245 12246
                gen_cp1(ctx, op1, rt, rd);
                break;
12247
#endif
12248 12249
            case OPC_BC1ANY2:
            case OPC_BC1ANY4:
12250
                check_cop1x(ctx);
12251
                check_insn(env, ctx, ASE_MIPS3D);
12252 12253
                /* fall through */
            case OPC_BC1:
12254
                gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
12255
                                    (rt >> 2) & 0x7, imm << 2);
12256 12257
                *is_branch = 1;
                break;
12258 12259 12260 12261
            case OPC_S_FMT:
            case OPC_D_FMT:
            case OPC_W_FMT:
            case OPC_L_FMT:
12262
            case OPC_PS_FMT:
12263
                gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
12264
                           (imm >> 8) & 0x7);
12265 12266
                break;
            default:
12267
                MIPS_INVAL("cp1");
12268
                generate_exception (ctx, EXCP_RI);
12269 12270 12271 12272
                break;
            }
        } else {
            generate_exception_err(ctx, EXCP_CpU, 1);
B
bellard 已提交
12273
        }
B
bellard 已提交
12274 12275 12276
        break;

    /* COP2.  */
12277 12278 12279 12280 12281 12282
    case OPC_LWC2:
    case OPC_LDC2:
    case OPC_SWC2:
    case OPC_SDC2:
    case OPC_CP2:
        /* COP2: Not implemented. */
B
bellard 已提交
12283 12284 12285
        generate_exception_err(ctx, EXCP_CpU, 2);
        break;

12286
    case OPC_CP3:
12287
        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
12288
            check_cp1_enabled(ctx);
12289 12290
            op1 = MASK_CP3(ctx->opcode);
            switch (op1) {
12291 12292 12293 12294 12295 12296
            case OPC_LWXC1:
            case OPC_LDXC1:
            case OPC_LUXC1:
            case OPC_SWXC1:
            case OPC_SDXC1:
            case OPC_SUXC1:
T
ths 已提交
12297
                gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);
12298
                break;
T
ths 已提交
12299
            case OPC_PREFX:
12300
                /* Treat as NOP. */
T
ths 已提交
12301
                break;
12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316
            case OPC_ALNV_PS:
            case OPC_MADD_S:
            case OPC_MADD_D:
            case OPC_MADD_PS:
            case OPC_MSUB_S:
            case OPC_MSUB_D:
            case OPC_MSUB_PS:
            case OPC_NMADD_S:
            case OPC_NMADD_D:
            case OPC_NMADD_PS:
            case OPC_NMSUB_S:
            case OPC_NMSUB_D:
            case OPC_NMSUB_PS:
                gen_flt3_arith(ctx, op1, sa, rs, rd, rt);
                break;
12317
            default:
12318
                MIPS_INVAL("cp3");
12319
                generate_exception (ctx, EXCP_RI);
12320 12321 12322
                break;
            }
        } else {
12323
            generate_exception_err(ctx, EXCP_CpU, 1);
12324
        }
B
bellard 已提交
12325 12326
        break;

12327
#if defined(TARGET_MIPS64)
12328 12329 12330 12331 12332
    /* MIPS64 opcodes */
    case OPC_LWU:
    case OPC_LDL ... OPC_LDR:
    case OPC_LLD:
    case OPC_LD:
12333 12334
        check_insn(env, ctx, ISA_MIPS3);
        check_mips_64(ctx);
12335
        gen_ld(env, ctx, op, rt, rs, imm);
12336 12337
        break;
    case OPC_SDL ... OPC_SDR:
12338
    case OPC_SD:
12339 12340
        check_insn(env, ctx, ISA_MIPS3);
        check_mips_64(ctx);
12341
        gen_st(ctx, op, rt, rs, imm);
12342
        break;
A
aurel32 已提交
12343 12344 12345 12346 12347
    case OPC_SCD:
        check_insn(env, ctx, ISA_MIPS3);
        check_mips_64(ctx);
        gen_st_cond(ctx, op, rt, rs, imm);
        break;
A
aurel32 已提交
12348 12349
    case OPC_DADDI:
    case OPC_DADDIU:
12350 12351 12352
        check_insn(env, ctx, ISA_MIPS3);
        check_mips_64(ctx);
        gen_arith_imm(env, ctx, op, rt, rs, imm);
12353
        break;
B
bellard 已提交
12354
#endif
12355
    case OPC_JALX:
12356
        check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS);
12357 12358 12359 12360
        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
        gen_compute_branch(ctx, op, 4, rs, rt, offset);
        *is_branch = 1;
        break;
12361
    case OPC_MDMX:
12362
        check_insn(env, ctx, ASE_MDMX);
12363
        /* MDMX: Not implemented. */
B
bellard 已提交
12364
    default:            /* Invalid */
12365
        MIPS_INVAL("major opcode");
B
bellard 已提交
12366 12367 12368 12369 12370
        generate_exception(ctx, EXCP_RI);
        break;
    }
}

12371
static inline void
12372
gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb,
12373
                                int search_pc)
B
bellard 已提交
12374
{
T
ths 已提交
12375
    DisasContext ctx;
B
bellard 已提交
12376 12377
    target_ulong pc_start;
    uint16_t *gen_opc_end;
12378
    CPUBreakpoint *bp;
B
bellard 已提交
12379
    int j, lj = -1;
P
pbrook 已提交
12380 12381
    int num_insns;
    int max_insns;
12382 12383
    int insn_bytes;
    int is_branch;
B
bellard 已提交
12384

12385 12386
    if (search_pc)
        qemu_log("search pc %d\n", search_pc);
B
bellard 已提交
12387

B
bellard 已提交
12388
    pc_start = tb->pc;
12389
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
B
bellard 已提交
12390
    ctx.pc = pc_start;
B
bellard 已提交
12391
    ctx.saved_pc = -1;
N
Nathan Froyd 已提交
12392
    ctx.singlestep_enabled = env->singlestep_enabled;
B
bellard 已提交
12393 12394
    ctx.tb = tb;
    ctx.bstate = BS_NONE;
B
bellard 已提交
12395
    /* Restore delay slot state from the tb context.  */
12396
    ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
12397
    restore_cpu_state(env, &ctx);
12398
#ifdef CONFIG_USER_ONLY
T
ths 已提交
12399
        ctx.mem_idx = MIPS_HFLAG_UM;
12400
#else
T
ths 已提交
12401
        ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU;
12402
#endif
P
pbrook 已提交
12403 12404 12405 12406
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;
12407
    LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
P
pbrook 已提交
12408
    gen_icount_start();
T
ths 已提交
12409
    while (ctx.bstate == BS_NONE) {
B
Blue Swirl 已提交
12410 12411
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
12412
                if (bp->pc == ctx.pc) {
T
ths 已提交
12413
                    save_cpu_state(&ctx, 1);
B
bellard 已提交
12414
                    ctx.bstate = BS_BRANCH;
P
pbrook 已提交
12415
                    gen_helper_0i(raise_exception, EXCP_DEBUG);
12416 12417 12418
                    /* Include the breakpoint location or the tb won't
                     * be flushed when it must be.  */
                    ctx.pc += 4;
B
bellard 已提交
12419 12420 12421 12422 12423
                    goto done_generating;
                }
            }
        }

B
bellard 已提交
12424 12425 12426 12427 12428 12429 12430
        if (search_pc) {
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
            }
B
bellard 已提交
12431 12432 12433
            gen_opc_pc[lj] = ctx.pc;
            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
            gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
12434
            gen_opc_icount[lj] = num_insns;
B
bellard 已提交
12435
        }
P
pbrook 已提交
12436 12437
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
12438 12439

        is_branch = 0;
12440
        if (!(ctx.hflags & MIPS_HFLAG_M16)) {
12441 12442 12443
            ctx.opcode = ldl_code(ctx.pc);
            insn_bytes = 4;
            decode_opc(env, &ctx, &is_branch);
12444 12445 12446
        } else if (env->insn_flags & ASE_MICROMIPS) {
            ctx.opcode = lduw_code(ctx.pc);
            insn_bytes = decode_micromips_opc(env, &ctx, &is_branch);
12447 12448 12449
        } else if (env->insn_flags & ASE_MIPS16) {
            ctx.opcode = lduw_code(ctx.pc);
            insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
12450 12451
        } else {
            generate_exception(&ctx, EXCP_RI);
12452
            ctx.bstate = BS_STOP;
12453 12454 12455 12456 12457 12458 12459
            break;
        }
        if (!is_branch) {
            handle_delay_slot(env, &ctx, insn_bytes);
        }
        ctx.pc += insn_bytes;

P
pbrook 已提交
12460
        num_insns++;
B
bellard 已提交
12461

N
Nathan Froyd 已提交
12462 12463 12464 12465 12466
        /* Execute a branch and its delay slot as a single instruction.
           This is what GDB expects and is consistent with what the
           hardware does (e.g. if a delay slot instruction faults, the
           reported PC is the PC of the branch).  */
        if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0)
B
bellard 已提交
12467 12468
            break;

B
bellard 已提交
12469 12470
        if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
            break;
B
bellard 已提交
12471

T
ths 已提交
12472 12473 12474
        if (gen_opc_ptr >= gen_opc_end)
            break;

P
pbrook 已提交
12475 12476
        if (num_insns >= max_insns)
            break;
12477 12478 12479

        if (singlestep)
            break;
B
bellard 已提交
12480
    }
P
pbrook 已提交
12481 12482
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
N
Nathan Froyd 已提交
12483
    if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) {
T
ths 已提交
12484
        save_cpu_state(&ctx, ctx.bstate == BS_NONE);
P
pbrook 已提交
12485
        gen_helper_0i(raise_exception, EXCP_DEBUG);
T
ths 已提交
12486
    } else {
A
aurel32 已提交
12487
        switch (ctx.bstate) {
T
ths 已提交
12488
        case BS_STOP:
12489 12490
            gen_goto_tb(&ctx, 0, ctx.pc);
            break;
T
ths 已提交
12491
        case BS_NONE:
T
ths 已提交
12492
            save_cpu_state(&ctx, 0);
T
ths 已提交
12493 12494
            gen_goto_tb(&ctx, 0, ctx.pc);
            break;
12495
        case BS_EXCP:
B
bellard 已提交
12496
            tcg_gen_exit_tb(0);
T
ths 已提交
12497
            break;
12498 12499 12500
        case BS_BRANCH:
        default:
            break;
A
aurel32 已提交
12501
        }
B
bellard 已提交
12502
    }
B
bellard 已提交
12503
done_generating:
P
pbrook 已提交
12504
    gen_icount_end(tb, num_insns);
B
bellard 已提交
12505 12506 12507 12508 12509 12510 12511 12512
    *gen_opc_ptr = INDEX_op_end;
    if (search_pc) {
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
        tb->size = ctx.pc - pc_start;
P
pbrook 已提交
12513
        tb->icount = num_insns;
B
bellard 已提交
12514 12515
    }
#ifdef DEBUG_DISAS
12516
    LOG_DISAS("\n");
12517
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
12518 12519 12520
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(pc_start, ctx.pc - pc_start, 0);
        qemu_log("\n");
B
bellard 已提交
12521 12522 12523 12524
    }
#endif
}

12525
void gen_intermediate_code (CPUMIPSState *env, struct TranslationBlock *tb)
B
bellard 已提交
12526
{
12527
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
12528 12529
}

12530
void gen_intermediate_code_pc (CPUMIPSState *env, struct TranslationBlock *tb)
B
bellard 已提交
12531
{
12532
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
12533 12534
}

12535
static void fpu_dump_state(CPUMIPSState *env, FILE *f, fprintf_function fpu_fprintf,
12536
                           int flags)
B
bellard 已提交
12537 12538
{
    int i;
12539
    int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
12540

12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558 12559 12560
#define printfpr(fp)                                                    \
    do {                                                                \
        if (is_fpu64)                                                   \
            fpu_fprintf(f, "w:%08x d:%016" PRIx64                       \
                        " fd:%13g fs:%13g psu: %13g\n",                 \
                        (fp)->w[FP_ENDIAN_IDX], (fp)->d,                \
                        (double)(fp)->fd,                               \
                        (double)(fp)->fs[FP_ENDIAN_IDX],                \
                        (double)(fp)->fs[!FP_ENDIAN_IDX]);              \
        else {                                                          \
            fpr_t tmp;                                                  \
            tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX];              \
            tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX];       \
            fpu_fprintf(f, "w:%08x d:%016" PRIx64                       \
                        " fd:%13g fs:%13g psu:%13g\n",                  \
                        tmp.w[FP_ENDIAN_IDX], tmp.d,                    \
                        (double)tmp.fd,                                 \
                        (double)tmp.fs[FP_ENDIAN_IDX],                  \
                        (double)tmp.fs[!FP_ENDIAN_IDX]);                \
        }                                                               \
B
bellard 已提交
12561 12562
    } while(0)

12563

12564 12565
    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%02x\n",
                env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
12566
                get_float_exception_flags(&env->active_fpu.fp_status));
12567 12568
    for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
        fpu_fprintf(f, "%3s: ", fregnames[i]);
12569
        printfpr(&env->active_fpu.fpr[i]);
B
bellard 已提交
12570 12571 12572 12573 12574
    }

#undef printfpr
}

12575
#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
12576
/* Debug help: The architecture requires 32bit code to maintain proper
T
ths 已提交
12577
   sign-extended values on 64bit machines.  */
12578 12579 12580

#define SIGN_EXT_P(val) ((((val) & ~0x7fffffff) == 0) || (((val) & ~0x7fffffff) == ~0x7fffffff))

12581
static void
12582
cpu_mips_check_sign_extensions (CPUMIPSState *env, FILE *f,
12583
                                fprintf_function cpu_fprintf,
12584
                                int flags)
12585 12586 12587
{
    int i;

12588 12589 12590 12591 12592 12593
    if (!SIGN_EXT_P(env->active_tc.PC))
        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC);
    if (!SIGN_EXT_P(env->active_tc.HI[0]))
        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->active_tc.HI[0]);
    if (!SIGN_EXT_P(env->active_tc.LO[0]))
        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->active_tc.LO[0]);
12594
    if (!SIGN_EXT_P(env->btarget))
T
ths 已提交
12595
        cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
12596 12597

    for (i = 0; i < 32; i++) {
12598 12599
        if (!SIGN_EXT_P(env->active_tc.gpr[i]))
            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->active_tc.gpr[i]);
12600 12601 12602
    }

    if (!SIGN_EXT_P(env->CP0_EPC))
T
ths 已提交
12603
        cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC);
12604 12605
    if (!SIGN_EXT_P(env->lladdr))
        cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->lladdr);
12606 12607 12608
}
#endif

12609
void cpu_dump_state (CPUMIPSState *env, FILE *f, fprintf_function cpu_fprintf,
B
bellard 已提交
12610 12611 12612
                     int flags)
{
    int i;
12613

12614 12615 12616
    cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
                " LO=0x" TARGET_FMT_lx " ds %04x "
                TARGET_FMT_lx " " TARGET_FMT_ld "\n",
12617 12618
                env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
                env->hflags, env->btarget, env->bcond);
B
bellard 已提交
12619 12620 12621
    for (i = 0; i < 32; i++) {
        if ((i & 3) == 0)
            cpu_fprintf(f, "GPR%02d:", i);
12622
        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]);
B
bellard 已提交
12623 12624 12625
        if ((i & 3) == 3)
            cpu_fprintf(f, "\n");
    }
12626

T
ths 已提交
12627
    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x" TARGET_FMT_lx "\n",
12628
                env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
T
ths 已提交
12629
    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n",
12630
                env->CP0_Config0, env->CP0_Config1, env->lladdr);
12631
    if (env->hflags & MIPS_HFLAG_FPU)
12632
        fpu_dump_state(env, f, cpu_fprintf, flags);
12633
#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
12634 12635
    cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags);
#endif
B
bellard 已提交
12636 12637
}

12638 12639
static void mips_tcg_init(void)
{
12640
    int i;
12641 12642 12643 12644
    static int inited;

    /* Initialize various static tables. */
    if (inited)
A
aurel32 已提交
12645
        return;
12646

P
pbrook 已提交
12647
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
12648
    TCGV_UNUSED(cpu_gpr[0]);
12649
    for (i = 1; i < 32; i++)
P
pbrook 已提交
12650
        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
12651
                                        offsetof(CPUMIPSState, active_tc.gpr[i]),
12652
                                        regnames[i]);
P
pbrook 已提交
12653
    cpu_PC = tcg_global_mem_new(TCG_AREG0,
12654
                                offsetof(CPUMIPSState, active_tc.PC), "PC");
12655
    for (i = 0; i < MIPS_DSP_ACC; i++) {
P
pbrook 已提交
12656
        cpu_HI[i] = tcg_global_mem_new(TCG_AREG0,
12657
                                       offsetof(CPUMIPSState, active_tc.HI[i]),
12658
                                       regnames_HI[i]);
P
pbrook 已提交
12659
        cpu_LO[i] = tcg_global_mem_new(TCG_AREG0,
12660
                                       offsetof(CPUMIPSState, active_tc.LO[i]),
12661
                                       regnames_LO[i]);
P
pbrook 已提交
12662
        cpu_ACX[i] = tcg_global_mem_new(TCG_AREG0,
12663
                                        offsetof(CPUMIPSState, active_tc.ACX[i]),
12664 12665
                                        regnames_ACX[i]);
    }
P
pbrook 已提交
12666
    cpu_dspctrl = tcg_global_mem_new(TCG_AREG0,
12667
                                     offsetof(CPUMIPSState, active_tc.DSPControl),
12668
                                     "DSPControl");
12669
    bcond = tcg_global_mem_new(TCG_AREG0,
12670
                               offsetof(CPUMIPSState, bcond), "bcond");
P
pbrook 已提交
12671
    btarget = tcg_global_mem_new(TCG_AREG0,
12672
                                 offsetof(CPUMIPSState, btarget), "btarget");
12673
    hflags = tcg_global_mem_new_i32(TCG_AREG0,
12674
                                    offsetof(CPUMIPSState, hflags), "hflags");
12675

P
pbrook 已提交
12676
    fpu_fcr0 = tcg_global_mem_new_i32(TCG_AREG0,
12677
                                      offsetof(CPUMIPSState, active_fpu.fcr0),
P
pbrook 已提交
12678 12679
                                      "fcr0");
    fpu_fcr31 = tcg_global_mem_new_i32(TCG_AREG0,
12680
                                       offsetof(CPUMIPSState, active_fpu.fcr31),
P
pbrook 已提交
12681
                                       "fcr31");
12682

T
ths 已提交
12683
    /* register helpers */
P
pbrook 已提交
12684
#define GEN_HELPER 2
T
ths 已提交
12685 12686
#include "helper.h"

12687 12688 12689
    inited = 1;
}

B
bellard 已提交
12690 12691 12692
#include "translate_init.c"

CPUMIPSState *cpu_mips_init (const char *cpu_model)
B
bellard 已提交
12693
{
A
Andreas Färber 已提交
12694
    MIPSCPU *cpu;
B
bellard 已提交
12695
    CPUMIPSState *env;
A
Anthony Liguori 已提交
12696
    const mips_def_t *def;
B
bellard 已提交
12697

B
bellard 已提交
12698 12699 12700
    def = cpu_mips_find_by_name(cpu_model);
    if (!def)
        return NULL;
A
Andreas Färber 已提交
12701 12702
    cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
    env = &cpu->env;
B
bellard 已提交
12703
    env->cpu_model = def;
B
Blue Swirl 已提交
12704
    env->cpu_model_str = cpu_model;
B
bellard 已提交
12705

B
Blue Swirl 已提交
12706 12707 12708 12709 12710
#ifndef CONFIG_USER_ONLY
    mmu_init(env, def);
#endif
    fpu_init(env, def);
    mvp_init(env, def);
12711
    mips_tcg_init();
12712
    cpu_state_reset(env);
12713
    qemu_init_vcpu(env);
12714 12715 12716
    return env;
}

12717
void cpu_state_reset(CPUMIPSState *env)
12718
{
A
aliguori 已提交
12719 12720 12721 12722 12723
    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
        log_cpu_state(env, 0);
    }

12724
    memset(env, 0, offsetof(CPUMIPSState, breakpoints));
B
bellard 已提交
12725
    tlb_flush(env, 1);
12726

B
Blue Swirl 已提交
12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737
    /* Reset registers to their default values */
    env->CP0_PRid = env->cpu_model->CP0_PRid;
    env->CP0_Config0 = env->cpu_model->CP0_Config0;
#ifdef TARGET_WORDS_BIGENDIAN
    env->CP0_Config0 |= (1 << CP0C0_BE);
#endif
    env->CP0_Config1 = env->cpu_model->CP0_Config1;
    env->CP0_Config2 = env->cpu_model->CP0_Config2;
    env->CP0_Config3 = env->cpu_model->CP0_Config3;
    env->CP0_Config6 = env->cpu_model->CP0_Config6;
    env->CP0_Config7 = env->cpu_model->CP0_Config7;
12738 12739 12740
    env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
                                 << env->cpu_model->CP0_LLAddr_shift;
    env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
B
Blue Swirl 已提交
12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765 12766 12767
    env->SYNCI_Step = env->cpu_model->SYNCI_Step;
    env->CCRes = env->cpu_model->CCRes;
    env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
    env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
    env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
    env->current_tc = 0;
    env->SEGBITS = env->cpu_model->SEGBITS;
    env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
#if defined(TARGET_MIPS64)
    if (env->cpu_model->insn_flags & ISA_MIPS3) {
        env->SEGMask |= 3ULL << 62;
    }
#endif
    env->PABITS = env->cpu_model->PABITS;
    env->PAMask = (target_ulong)((1ULL << env->cpu_model->PABITS) - 1);
    env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
    env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
    env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
    env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
    env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
    env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
    env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
    env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
    env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
    env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
    env->insn_flags = env->cpu_model->insn_flags;

T
ths 已提交
12768
#if defined(CONFIG_USER_ONLY)
12769
    env->hflags = MIPS_HFLAG_UM;
12770 12771
    /* Enable access to the SYNCI_Step register.  */
    env->CP0_HWREna |= (1 << 1);
12772 12773 12774 12775 12776 12777 12778 12779
    if (env->CP0_Config1 & (1 << CP0C1_FP)) {
        env->hflags |= MIPS_HFLAG_FPU;
    }
#ifdef TARGET_MIPS64
    if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
        env->hflags |= MIPS_HFLAG_F64;
    }
#endif
12780 12781 12782 12783 12784
#else
    if (env->hflags & MIPS_HFLAG_BMASK) {
        /* If the exception was raised from a delay slot,
           come back to the jump.  */
        env->CP0_ErrorEPC = env->active_tc.PC - 4;
12785
    } else {
12786 12787 12788
        env->CP0_ErrorEPC = env->active_tc.PC;
    }
    env->active_tc.PC = (int32_t)0xBFC00000;
B
Blue Swirl 已提交
12789 12790
    env->CP0_Random = env->tlb->nb_tlb - 1;
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
12791
    env->CP0_Wired = 0;
12792
    env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF);
12793 12794 12795 12796 12797 12798 12799 12800 12801 12802
    env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
    /* vectored interrupts not implemented, timer on int 7,
       no performance counters. */
    env->CP0_IntCtl = 0xe0000000;
    {
        int i;

        for (i = 0; i < 7; i++) {
            env->CP0_WatchLo[i] = 0;
            env->CP0_WatchHi[i] = 0x80000000;
12803
        }
12804 12805
        env->CP0_WatchLo[7] = 0;
        env->CP0_WatchHi[7] = 0;
12806
    }
12807 12808 12809
    /* Count register increments in debug mode, EJTAG version 1 */
    env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
    env->hflags = MIPS_HFLAG_CP0;
12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835

    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
        int i;

        /* Only TC0 on VPE 0 starts as active.  */
        for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
            env->tcs[i].CP0_TCBind = env->cpu_index << CP0TCBd_CurVPE;
            env->tcs[i].CP0_TCHalt = 1;
        }
        env->active_tc.CP0_TCHalt = 1;
        env->halted = 1;

        if (!env->cpu_index) {
            /* VPE0 starts up enabled.  */
            env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
            env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);

            /* TC0 starts up unhalted.  */
            env->halted = 0;
            env->active_tc.CP0_TCHalt = 0;
            env->tcs[0].CP0_TCHalt = 0;
            /* With thread 0 active.  */
            env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
            env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
        }
    }
B
Blue Swirl 已提交
12836 12837 12838 12839 12840
#endif
#if defined(TARGET_MIPS64)
    if (env->cpu_model->insn_flags & ISA_MIPS3) {
        env->hflags |= MIPS_HFLAG_64;
    }
12841
#endif
B
bellard 已提交
12842 12843
    env->exception_index = EXCP_NONE;
}
A
aurel32 已提交
12844

12845
void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos)
A
aurel32 已提交
12846
{
12847
    env->active_tc.PC = gen_opc_pc[pc_pos];
A
aurel32 已提交
12848 12849 12850
    env->hflags &= ~MIPS_HFLAG_BMASK;
    env->hflags |= gen_opc_hflags[pc_pos];
}