]> git.proxmox.com Git - mirror_qemu.git/blame - target-mips/translate.c
Look for gcc3 (Anthony Liguori).
[mirror_qemu.git] / target-mips / translate.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS32 emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
6ea83fed 5 * Copyright (c) 2006 Marius Groeger (FPU operations)
bb8a53ad 6 * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
6af0bf9c
FB
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <stdarg.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <inttypes.h>
28
29#include "cpu.h"
30#include "exec-all.h"
31#include "disas.h"
32
eeef26cd 33//#define MIPS_DEBUG_DISAS
6af0bf9c
FB
34//#define MIPS_SINGLE_STEP
35
c53be334
FB
36#ifdef USE_DIRECT_JUMP
37#define TBPARAM(x)
38#else
39#define TBPARAM(x) (long)(x)
40#endif
41
6af0bf9c
FB
42enum {
43#define DEF(s, n, copy_size) INDEX_op_ ## s,
44#include "opc.h"
45#undef DEF
46 NB_OPS,
47};
48
49static uint16_t *gen_opc_ptr;
50static uint32_t *gen_opparam_ptr;
51
52#include "gen-op.h"
53
7a387fff
TS
54/* MIPS major opcodes */
55#define MASK_OP_MAJOR(op) (op & (0x3F << 26))
e37e863f
FB
56
57enum {
58 /* indirect opcode tables */
7a387fff
TS
59 OPC_SPECIAL = (0x00 << 26),
60 OPC_REGIMM = (0x01 << 26),
61 OPC_CP0 = (0x10 << 26),
62 OPC_CP1 = (0x11 << 26),
63 OPC_CP2 = (0x12 << 26),
64 OPC_CP3 = (0x13 << 26),
65 OPC_SPECIAL2 = (0x1C << 26),
66 OPC_SPECIAL3 = (0x1F << 26),
e37e863f 67 /* arithmetic with immediate */
7a387fff
TS
68 OPC_ADDI = (0x08 << 26),
69 OPC_ADDIU = (0x09 << 26),
70 OPC_SLTI = (0x0A << 26),
71 OPC_SLTIU = (0x0B << 26),
72 OPC_ANDI = (0x0C << 26),
73 OPC_ORI = (0x0D << 26),
74 OPC_XORI = (0x0E << 26),
75 OPC_LUI = (0x0F << 26),
76 OPC_DADDI = (0x18 << 26),
77 OPC_DADDIU = (0x19 << 26),
e37e863f 78 /* Jump and branches */
7a387fff
TS
79 OPC_J = (0x02 << 26),
80 OPC_JAL = (0x03 << 26),
81 OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */
82 OPC_BEQL = (0x14 << 26),
83 OPC_BNE = (0x05 << 26),
84 OPC_BNEL = (0x15 << 26),
85 OPC_BLEZ = (0x06 << 26),
86 OPC_BLEZL = (0x16 << 26),
87 OPC_BGTZ = (0x07 << 26),
88 OPC_BGTZL = (0x17 << 26),
89 OPC_JALX = (0x1D << 26), /* MIPS 16 only */
e37e863f 90 /* Load and stores */
7a387fff
TS
91 OPC_LDL = (0x1A << 26),
92 OPC_LDR = (0x1B << 26),
93 OPC_LB = (0x20 << 26),
94 OPC_LH = (0x21 << 26),
95 OPC_LWL = (0x22 << 26),
96 OPC_LW = (0x23 << 26),
97 OPC_LBU = (0x24 << 26),
98 OPC_LHU = (0x25 << 26),
99 OPC_LWR = (0x26 << 26),
100 OPC_LWU = (0x27 << 26),
101 OPC_SB = (0x28 << 26),
102 OPC_SH = (0x29 << 26),
103 OPC_SWL = (0x2A << 26),
104 OPC_SW = (0x2B << 26),
105 OPC_SDL = (0x2C << 26),
106 OPC_SDR = (0x2D << 26),
107 OPC_SWR = (0x2E << 26),
108 OPC_LL = (0x30 << 26),
109 OPC_LLD = (0x34 << 26),
110 OPC_LD = (0x37 << 26),
111 OPC_SC = (0x38 << 26),
112 OPC_SCD = (0x3C << 26),
113 OPC_SD = (0x3F << 26),
e37e863f 114 /* Floating point load/store */
7a387fff
TS
115 OPC_LWC1 = (0x31 << 26),
116 OPC_LWC2 = (0x32 << 26),
117 OPC_LDC1 = (0x35 << 26),
118 OPC_LDC2 = (0x36 << 26),
119 OPC_SWC1 = (0x39 << 26),
120 OPC_SWC2 = (0x3A << 26),
121 OPC_SDC1 = (0x3D << 26),
122 OPC_SDC2 = (0x3E << 26),
123 /* MDMX ASE specific */
124 OPC_MDMX = (0x1E << 26),
e37e863f 125 /* Cache and prefetch */
7a387fff
TS
126 OPC_CACHE = (0x2F << 26),
127 OPC_PREF = (0x33 << 26),
128 /* Reserved major opcode */
129 OPC_MAJOR3B_RESERVED = (0x3B << 26),
e37e863f
FB
130};
131
132/* MIPS special opcodes */
7a387fff
TS
133#define MASK_SPECIAL(op) MASK_OP_MAJOR(op) | (op & 0x3F)
134
e37e863f
FB
135enum {
136 /* Shifts */
7a387fff 137 OPC_SLL = 0x00 | OPC_SPECIAL,
e37e863f
FB
138 /* NOP is SLL r0, r0, 0 */
139 /* SSNOP is SLL r0, r0, 1 */
7a387fff
TS
140 /* EHB is SLL r0, r0, 3 */
141 OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */
142 OPC_SRA = 0x03 | OPC_SPECIAL,
143 OPC_SLLV = 0x04 | OPC_SPECIAL,
144 OPC_SRLV = 0x06 | OPC_SPECIAL,
145 OPC_SRAV = 0x07 | OPC_SPECIAL,
146 OPC_DSLLV = 0x14 | OPC_SPECIAL,
147 OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */
148 OPC_DSRAV = 0x17 | OPC_SPECIAL,
149 OPC_DSLL = 0x38 | OPC_SPECIAL,
150 OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */
151 OPC_DSRA = 0x3B | OPC_SPECIAL,
152 OPC_DSLL32 = 0x3C | OPC_SPECIAL,
153 OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */
154 OPC_DSRA32 = 0x3F | OPC_SPECIAL,
e37e863f 155 /* Multiplication / division */
7a387fff
TS
156 OPC_MULT = 0x18 | OPC_SPECIAL,
157 OPC_MULTU = 0x19 | OPC_SPECIAL,
158 OPC_DIV = 0x1A | OPC_SPECIAL,
159 OPC_DIVU = 0x1B | OPC_SPECIAL,
160 OPC_DMULT = 0x1C | OPC_SPECIAL,
161 OPC_DMULTU = 0x1D | OPC_SPECIAL,
162 OPC_DDIV = 0x1E | OPC_SPECIAL,
163 OPC_DDIVU = 0x1F | OPC_SPECIAL,
e37e863f 164 /* 2 registers arithmetic / logic */
7a387fff
TS
165 OPC_ADD = 0x20 | OPC_SPECIAL,
166 OPC_ADDU = 0x21 | OPC_SPECIAL,
167 OPC_SUB = 0x22 | OPC_SPECIAL,
168 OPC_SUBU = 0x23 | OPC_SPECIAL,
169 OPC_AND = 0x24 | OPC_SPECIAL,
170 OPC_OR = 0x25 | OPC_SPECIAL,
171 OPC_XOR = 0x26 | OPC_SPECIAL,
172 OPC_NOR = 0x27 | OPC_SPECIAL,
173 OPC_SLT = 0x2A | OPC_SPECIAL,
174 OPC_SLTU = 0x2B | OPC_SPECIAL,
175 OPC_DADD = 0x2C | OPC_SPECIAL,
176 OPC_DADDU = 0x2D | OPC_SPECIAL,
177 OPC_DSUB = 0x2E | OPC_SPECIAL,
178 OPC_DSUBU = 0x2F | OPC_SPECIAL,
e37e863f 179 /* Jumps */
7a387fff
TS
180 OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
181 OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
e37e863f 182 /* Traps */
7a387fff
TS
183 OPC_TGE = 0x30 | OPC_SPECIAL,
184 OPC_TGEU = 0x31 | OPC_SPECIAL,
185 OPC_TLT = 0x32 | OPC_SPECIAL,
186 OPC_TLTU = 0x33 | OPC_SPECIAL,
187 OPC_TEQ = 0x34 | OPC_SPECIAL,
188 OPC_TNE = 0x36 | OPC_SPECIAL,
e37e863f 189 /* HI / LO registers load & stores */
7a387fff
TS
190 OPC_MFHI = 0x10 | OPC_SPECIAL,
191 OPC_MTHI = 0x11 | OPC_SPECIAL,
192 OPC_MFLO = 0x12 | OPC_SPECIAL,
193 OPC_MTLO = 0x13 | OPC_SPECIAL,
e37e863f 194 /* Conditional moves */
7a387fff
TS
195 OPC_MOVZ = 0x0A | OPC_SPECIAL,
196 OPC_MOVN = 0x0B | OPC_SPECIAL,
e37e863f 197
7a387fff 198 OPC_MOVCI = 0x01 | OPC_SPECIAL,
e37e863f
FB
199
200 /* Special */
7a387fff
TS
201 OPC_PMON = 0x05 | OPC_SPECIAL, /* inofficial */
202 OPC_SYSCALL = 0x0C | OPC_SPECIAL,
203 OPC_BREAK = 0x0D | OPC_SPECIAL,
204 OPC_SPIM = 0x0E | OPC_SPECIAL, /* inofficial */
205 OPC_SYNC = 0x0F | OPC_SPECIAL,
206
207 OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
208 OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
209 OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
210 OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
211 OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
212 OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
213 OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
214};
215
216/* REGIMM (rt field) opcodes */
217#define MASK_REGIMM(op) MASK_OP_MAJOR(op) | (op & (0x1F << 16))
218
219enum {
220 OPC_BLTZ = (0x00 << 16) | OPC_REGIMM,
221 OPC_BLTZL = (0x02 << 16) | OPC_REGIMM,
222 OPC_BGEZ = (0x01 << 16) | OPC_REGIMM,
223 OPC_BGEZL = (0x03 << 16) | OPC_REGIMM,
224 OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM,
225 OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM,
226 OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM,
227 OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM,
228 OPC_TGEI = (0x08 << 16) | OPC_REGIMM,
229 OPC_TGEIU = (0x09 << 16) | OPC_REGIMM,
230 OPC_TLTI = (0x0A << 16) | OPC_REGIMM,
231 OPC_TLTIU = (0x0B << 16) | OPC_REGIMM,
232 OPC_TEQI = (0x0C << 16) | OPC_REGIMM,
233 OPC_TNEI = (0x0E << 16) | OPC_REGIMM,
234 OPC_SYNCI = (0x1F << 16) | OPC_REGIMM,
e37e863f
FB
235};
236
7a387fff
TS
237/* Special2 opcodes */
238#define MASK_SPECIAL2(op) MASK_OP_MAJOR(op) | (op & 0x3F)
239
e37e863f 240enum {
7a387fff
TS
241 /* Multiply & xxx operations */
242 OPC_MADD = 0x00 | OPC_SPECIAL2,
243 OPC_MADDU = 0x01 | OPC_SPECIAL2,
244 OPC_MUL = 0x02 | OPC_SPECIAL2,
245 OPC_MSUB = 0x04 | OPC_SPECIAL2,
246 OPC_MSUBU = 0x05 | OPC_SPECIAL2,
e37e863f 247 /* Misc */
7a387fff
TS
248 OPC_CLZ = 0x20 | OPC_SPECIAL2,
249 OPC_CLO = 0x21 | OPC_SPECIAL2,
250 OPC_DCLZ = 0x24 | OPC_SPECIAL2,
251 OPC_DCLO = 0x25 | OPC_SPECIAL2,
e37e863f 252 /* Special */
7a387fff
TS
253 OPC_SDBBP = 0x3F | OPC_SPECIAL2,
254};
255
256/* Special3 opcodes */
257#define MASK_SPECIAL3(op) MASK_OP_MAJOR(op) | (op & 0x3F)
258
259enum {
260 OPC_EXT = 0x00 | OPC_SPECIAL3,
261 OPC_DEXTM = 0x01 | OPC_SPECIAL3,
262 OPC_DEXTU = 0x02 | OPC_SPECIAL3,
263 OPC_DEXT = 0x03 | OPC_SPECIAL3,
264 OPC_INS = 0x04 | OPC_SPECIAL3,
265 OPC_DINSM = 0x05 | OPC_SPECIAL3,
266 OPC_DINSU = 0x06 | OPC_SPECIAL3,
267 OPC_DINS = 0x07 | OPC_SPECIAL3,
268 OPC_BSHFL = 0x20 | OPC_SPECIAL3,
269 OPC_DBSHFL = 0x24 | OPC_SPECIAL3,
270 OPC_RDHWR = 0x3B | OPC_SPECIAL3,
e37e863f
FB
271};
272
7a387fff
TS
273/* BSHFL opcodes */
274#define MASK_BSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6))
275
e37e863f 276enum {
7a387fff
TS
277 OPC_WSBH = (0x02 << 6) | OPC_BSHFL,
278 OPC_SEB = (0x10 << 6) | OPC_BSHFL,
279 OPC_SEH = (0x18 << 6) | OPC_BSHFL,
e37e863f
FB
280};
281
7a387fff
TS
282/* DBSHFL opcodes */
283#define MASK_DBSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6))
284
e37e863f 285enum {
7a387fff
TS
286 OPC_DSBH = (0x02 << 6) | OPC_DBSHFL,
287 OPC_DSHD = (0x05 << 6) | OPC_DBSHFL,
e37e863f
FB
288};
289
7a387fff
TS
290/* Coprocessor 0 (rs field) */
291#define MASK_CP0(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
292
6ea83fed 293enum {
7a387fff
TS
294 OPC_MFC0 = (0x00 << 21) | OPC_CP0,
295 OPC_DMFC0 = (0x01 << 21) | OPC_CP0,
296 OPC_MTC0 = (0x04 << 21) | OPC_CP0,
297 OPC_DMTC0 = (0x05 << 21) | OPC_CP0,
298 OPC_RDPGPR = (0x0A << 21) | OPC_CP0,
299 OPC_MFMC0 = (0x0B << 21) | OPC_CP0,
300 OPC_WRPGPR = (0x0E << 21) | OPC_CP0,
301 OPC_C0 = (0x10 << 21) | OPC_CP0,
302 OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
303 OPC_C0_LAST = (0x1F << 21) | OPC_CP0,
6ea83fed 304};
7a387fff
TS
305
306/* MFMC0 opcodes */
307#define MASK_MFMC0(op) MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5)))
308
309enum {
310 OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
311 OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
312};
313
314/* Coprocessor 0 (with rs == C0) */
315#define MASK_C0(op) MASK_CP0(op) | (op & 0x3F)
316
317enum {
318 OPC_TLBR = 0x01 | OPC_C0,
319 OPC_TLBWI = 0x02 | OPC_C0,
320 OPC_TLBWR = 0x06 | OPC_C0,
321 OPC_TLBP = 0x08 | OPC_C0,
322 OPC_RFE = 0x10 | OPC_C0,
323 OPC_ERET = 0x18 | OPC_C0,
324 OPC_DERET = 0x1F | OPC_C0,
325 OPC_WAIT = 0x20 | OPC_C0,
326};
327
328/* Coprocessor 1 (rs field) */
329#define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
330
331enum {
332 OPC_MFC1 = (0x00 << 21) | OPC_CP1,
333 OPC_DMFC1 = (0x01 << 21) | OPC_CP1,
334 OPC_CFC1 = (0x02 << 21) | OPC_CP1,
335 OPC_MFHCI = (0x03 << 21) | OPC_CP1,
336 OPC_MTC1 = (0x04 << 21) | OPC_CP1,
337 OPC_DMTC1 = (0x05 << 21) | OPC_CP1,
338 OPC_CTC1 = (0x06 << 21) | OPC_CP1,
339 OPC_MTHCI = (0x07 << 21) | OPC_CP1,
340 OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */
341 OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
342 OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
343 OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
344 OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
345 OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
346 OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
347};
348
349enum {
350 OPC_BC1F = (0x00 << 16) | OPC_BC1,
351 OPC_BC1T = (0x01 << 16) | OPC_BC1,
352 OPC_BC1FL = (0x02 << 16) | OPC_BC1,
353 OPC_BC1TL = (0x03 << 16) | OPC_BC1,
354};
355
e1449664
TS
356#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16))
357#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
7a387fff
TS
358
359#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
360#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
6ea83fed 361
6af0bf9c
FB
362const unsigned char *regnames[] =
363 { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
364 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
365 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
366 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
367
368/* Warning: no function for r0 register (hard wired to zero) */
369#define GEN32(func, NAME) \
370static GenOpFunc *NAME ## _table [32] = { \
371NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
372NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
373NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
374NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
375NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
376NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
377NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
378NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
379}; \
380static inline void func(int n) \
381{ \
382 NAME ## _table[n](); \
383}
384
385/* General purpose registers moves */
386GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
387GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
388GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
389
390GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
391GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
392
71fb7241
TS
393#ifdef MIPS_USES_FPU
394
7a387fff 395static const char *fregnames[] =
6ea83fed
FB
396 { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
397 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
398 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
399 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
400
401# define SFGEN32(func, NAME) \
402static GenOpFunc *NAME ## _table [32] = { \
403NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
404NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
405NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
406NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
407NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
408NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
409NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
410NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
411}; \
412static inline void func(int n) \
413{ \
414 NAME ## _table[n](); \
415}
416
417# define DFGEN32(func, NAME) \
418static GenOpFunc *NAME ## _table [32] = { \
419NAME ## 0, 0, NAME ## 2, 0, \
420NAME ## 4, 0, NAME ## 6, 0, \
421NAME ## 8, 0, NAME ## 10, 0, \
422NAME ## 12, 0, NAME ## 14, 0, \
423NAME ## 16, 0, NAME ## 18, 0, \
424NAME ## 20, 0, NAME ## 22, 0, \
425NAME ## 24, 0, NAME ## 26, 0, \
426NAME ## 28, 0, NAME ## 30, 0, \
427}; \
428static inline void func(int n) \
429{ \
430 NAME ## _table[n](); \
431}
432
433SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
434SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
435
436SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
437SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
438
439SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
440SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
441
442DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
443DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
444
445DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
446DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
447
448DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
449DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
450
451#define FOP_CONDS(fmt) \
452static GenOpFunc * cond_ ## fmt ## _table[16] = { \
453 gen_op_cmp_ ## fmt ## _f, \
454 gen_op_cmp_ ## fmt ## _un, \
455 gen_op_cmp_ ## fmt ## _eq, \
456 gen_op_cmp_ ## fmt ## _ueq, \
457 gen_op_cmp_ ## fmt ## _olt, \
458 gen_op_cmp_ ## fmt ## _ult, \
459 gen_op_cmp_ ## fmt ## _ole, \
460 gen_op_cmp_ ## fmt ## _ule, \
461 gen_op_cmp_ ## fmt ## _sf, \
462 gen_op_cmp_ ## fmt ## _ngle, \
463 gen_op_cmp_ ## fmt ## _seq, \
464 gen_op_cmp_ ## fmt ## _ngl, \
465 gen_op_cmp_ ## fmt ## _lt, \
466 gen_op_cmp_ ## fmt ## _nge, \
467 gen_op_cmp_ ## fmt ## _le, \
468 gen_op_cmp_ ## fmt ## _ngt, \
469}; \
470static inline void gen_cmp_ ## fmt(int n) \
471{ \
472 cond_ ## fmt ## _table[n](); \
473}
474
475FOP_CONDS(d)
476FOP_CONDS(s)
477
71fb7241
TS
478#endif /* MIPS_USES_FPU */
479
6af0bf9c
FB
480typedef struct DisasContext {
481 struct TranslationBlock *tb;
482 target_ulong pc, saved_pc;
483 uint32_t opcode;
484 /* Routine used to access memory */
485 int mem_idx;
486 uint32_t hflags, saved_hflags;
487 uint32_t CP0_Status;
488 int bstate;
489 target_ulong btarget;
490} DisasContext;
491
492enum {
493 BS_NONE = 0, /* We go out of the TB without reaching a branch or an
494 * exception condition
495 */
496 BS_STOP = 1, /* We want to stop translation for any reason */
497 BS_BRANCH = 2, /* We reached a branch condition */
498 BS_EXCP = 3, /* We reached an exception condition */
499};
500
501#if defined MIPS_DEBUG_DISAS
502#define MIPS_DEBUG(fmt, args...) \
503do { \
504 if (loglevel & CPU_LOG_TB_IN_ASM) { \
505 fprintf(logfile, "%08x: %08x " fmt "\n", \
506 ctx->pc, ctx->opcode , ##args); \
507 } \
508} while (0)
509#else
510#define MIPS_DEBUG(fmt, args...) do { } while(0)
511#endif
512
513#define MIPS_INVAL(op) \
514do { \
515 MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \
516 ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
517} while (0)
518
519#define GEN_LOAD_REG_TN(Tn, Rn) \
520do { \
521 if (Rn == 0) { \
522 glue(gen_op_reset_, Tn)(); \
523 } else { \
524 glue(gen_op_load_gpr_, Tn)(Rn); \
525 } \
526} while (0)
527
528#define GEN_LOAD_IMM_TN(Tn, Imm) \
529do { \
530 if (Imm == 0) { \
531 glue(gen_op_reset_, Tn)(); \
532 } else { \
533 glue(gen_op_set_, Tn)(Imm); \
534 } \
535} while (0)
536
537#define GEN_STORE_TN_REG(Rn, Tn) \
538do { \
539 if (Rn != 0) { \
540 glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
541 } \
542} while (0)
543
7a387fff 544#define GEN_LOAD_FREG_FTN(FTn, Fn) \
6ea83fed
FB
545do { \
546 glue(gen_op_load_fpr_, FTn)(Fn); \
547} while (0)
548
549#define GEN_STORE_FTN_FREG(Fn, FTn) \
550do { \
551 glue(gen_op_store_fpr_, FTn)(Fn); \
552} while (0)
553
6af0bf9c
FB
554static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
555{
556#if defined MIPS_DEBUG_DISAS
557 if (loglevel & CPU_LOG_TB_IN_ASM) {
558 fprintf(logfile, "hflags %08x saved %08x\n",
559 ctx->hflags, ctx->saved_hflags);
560 }
561#endif
562 if (do_save_pc && ctx->pc != ctx->saved_pc) {
563 gen_op_save_pc(ctx->pc);
564 ctx->saved_pc = ctx->pc;
565 }
566 if (ctx->hflags != ctx->saved_hflags) {
567 gen_op_save_state(ctx->hflags);
568 ctx->saved_hflags = ctx->hflags;
569 if (ctx->hflags & MIPS_HFLAG_BR) {
570 gen_op_save_breg_target();
571 } else if (ctx->hflags & MIPS_HFLAG_B) {
572 gen_op_save_btarget(ctx->btarget);
573 } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
574 gen_op_save_bcond();
575 gen_op_save_btarget(ctx->btarget);
576 }
577 }
578}
579
4ad40f36 580static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
6af0bf9c
FB
581{
582#if defined MIPS_DEBUG_DISAS
583 if (loglevel & CPU_LOG_TB_IN_ASM)
584 fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
585#endif
586 save_cpu_state(ctx, 1);
4ad40f36
FB
587 if (err == 0)
588 gen_op_raise_exception(excp);
589 else
590 gen_op_raise_exception_err(excp, err);
6af0bf9c
FB
591 ctx->bstate = BS_EXCP;
592}
593
4ad40f36
FB
594static inline void generate_exception (DisasContext *ctx, int excp)
595{
596 generate_exception_err (ctx, excp, 0);
597}
598
6af0bf9c
FB
599#if defined(CONFIG_USER_ONLY)
600#define op_ldst(name) gen_op_##name##_raw()
601#define OP_LD_TABLE(width)
602#define OP_ST_TABLE(width)
603#else
604#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
605#define OP_LD_TABLE(width) \
606static GenOpFunc *gen_op_l##width[] = { \
607 &gen_op_l##width##_user, \
608 &gen_op_l##width##_kernel, \
609}
610#define OP_ST_TABLE(width) \
611static GenOpFunc *gen_op_s##width[] = { \
612 &gen_op_s##width##_user, \
613 &gen_op_s##width##_kernel, \
614}
615#endif
616
7a387fff 617#ifdef MIPS_HAS_MIPS64
6af0bf9c
FB
618OP_LD_TABLE(d);
619OP_LD_TABLE(dl);
620OP_LD_TABLE(dr);
621OP_ST_TABLE(d);
622OP_ST_TABLE(dl);
623OP_ST_TABLE(dr);
624#endif
625OP_LD_TABLE(w);
d796321b 626OP_LD_TABLE(wu);
6af0bf9c
FB
627OP_LD_TABLE(wl);
628OP_LD_TABLE(wr);
629OP_ST_TABLE(w);
630OP_ST_TABLE(wl);
631OP_ST_TABLE(wr);
632OP_LD_TABLE(h);
633OP_LD_TABLE(hu);
634OP_ST_TABLE(h);
635OP_LD_TABLE(b);
636OP_LD_TABLE(bu);
637OP_ST_TABLE(b);
638OP_LD_TABLE(l);
639OP_ST_TABLE(c);
71fb7241 640#ifdef MIPS_USES_FPU
6ea83fed
FB
641OP_LD_TABLE(wc1);
642OP_ST_TABLE(wc1);
643OP_LD_TABLE(dc1);
644OP_ST_TABLE(dc1);
71fb7241 645#endif
6af0bf9c
FB
646
647/* Load and store */
7a387fff 648static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
6af0bf9c
FB
649 int base, int16_t offset)
650{
7a387fff 651 const char *opn = "unk";
6af0bf9c
FB
652
653 if (base == 0) {
654 GEN_LOAD_IMM_TN(T0, offset);
655 } else if (offset == 0) {
656 gen_op_load_gpr_T0(base);
657 } else {
658 gen_op_load_gpr_T0(base);
659 gen_op_set_T1(offset);
660 gen_op_add();
661 }
662 /* Don't do NOP if destination is zero: we must perform the actual
663 * memory access
664 */
665 switch (opc) {
7a387fff 666#ifdef MIPS_HAS_MIPS64
6af0bf9c 667 case OPC_LD:
6af0bf9c
FB
668 op_ldst(ld);
669 GEN_STORE_TN_REG(rt, T0);
670 opn = "ld";
671 break;
7a387fff
TS
672 case OPC_LLD:
673 op_ldst(lld);
674 GEN_STORE_TN_REG(rt, T0);
675 opn = "lld";
676 break;
6af0bf9c 677 case OPC_SD:
6af0bf9c
FB
678 GEN_LOAD_REG_TN(T1, rt);
679 op_ldst(sd);
680 opn = "sd";
681 break;
7a387fff
TS
682 case OPC_SCD:
683 GEN_LOAD_REG_TN(T1, rt);
684 op_ldst(scd);
685 opn = "scd";
686 break;
6af0bf9c
FB
687 case OPC_LDL:
688 op_ldst(ldl);
689 GEN_STORE_TN_REG(rt, T0);
690 opn = "ldl";
691 break;
692 case OPC_SDL:
693 GEN_LOAD_REG_TN(T1, rt);
694 op_ldst(sdl);
695 opn = "sdl";
696 break;
697 case OPC_LDR:
698 op_ldst(ldr);
699 GEN_STORE_TN_REG(rt, T0);
700 opn = "ldr";
701 break;
702 case OPC_SDR:
703 GEN_LOAD_REG_TN(T1, rt);
704 op_ldst(sdr);
705 opn = "sdr";
706 break;
707#endif
708 case OPC_LW:
6af0bf9c
FB
709 op_ldst(lw);
710 GEN_STORE_TN_REG(rt, T0);
711 opn = "lw";
712 break;
d796321b
FB
713 case OPC_LWU:
714 op_ldst(lwu);
715 GEN_STORE_TN_REG(rt, T0);
716 opn = "lwu";
717 break;
6af0bf9c 718 case OPC_SW:
6af0bf9c
FB
719 GEN_LOAD_REG_TN(T1, rt);
720 op_ldst(sw);
721 opn = "sw";
722 break;
723 case OPC_LH:
6af0bf9c
FB
724 op_ldst(lh);
725 GEN_STORE_TN_REG(rt, T0);
726 opn = "lh";
727 break;
728 case OPC_SH:
6af0bf9c
FB
729 GEN_LOAD_REG_TN(T1, rt);
730 op_ldst(sh);
731 opn = "sh";
732 break;
733 case OPC_LHU:
6af0bf9c
FB
734 op_ldst(lhu);
735 GEN_STORE_TN_REG(rt, T0);
736 opn = "lhu";
737 break;
738 case OPC_LB:
739 op_ldst(lb);
740 GEN_STORE_TN_REG(rt, T0);
741 opn = "lb";
742 break;
743 case OPC_SB:
744 GEN_LOAD_REG_TN(T1, rt);
745 op_ldst(sb);
746 opn = "sb";
747 break;
748 case OPC_LBU:
749 op_ldst(lbu);
750 GEN_STORE_TN_REG(rt, T0);
751 opn = "lbu";
752 break;
753 case OPC_LWL:
9d1d106a 754 GEN_LOAD_REG_TN(T1, rt);
6af0bf9c
FB
755 op_ldst(lwl);
756 GEN_STORE_TN_REG(rt, T0);
757 opn = "lwl";
758 break;
759 case OPC_SWL:
760 GEN_LOAD_REG_TN(T1, rt);
761 op_ldst(swl);
762 opn = "swr";
763 break;
764 case OPC_LWR:
9d1d106a 765 GEN_LOAD_REG_TN(T1, rt);
6af0bf9c
FB
766 op_ldst(lwr);
767 GEN_STORE_TN_REG(rt, T0);
768 opn = "lwr";
769 break;
770 case OPC_SWR:
771 GEN_LOAD_REG_TN(T1, rt);
772 op_ldst(swr);
773 opn = "swr";
774 break;
775 case OPC_LL:
776 op_ldst(ll);
777 GEN_STORE_TN_REG(rt, T0);
778 opn = "ll";
779 break;
780 case OPC_SC:
781 GEN_LOAD_REG_TN(T1, rt);
782 op_ldst(sc);
783 GEN_STORE_TN_REG(rt, T0);
784 opn = "sc";
785 break;
786 default:
787 MIPS_INVAL("load/store");
788 generate_exception(ctx, EXCP_RI);
789 return;
790 }
791 MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
792}
793
71fb7241
TS
794#ifdef MIPS_USES_FPU
795
6ea83fed 796/* Load and store */
7a387fff 797static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
6ea83fed
FB
798 int base, int16_t offset)
799{
7a387fff 800 const char *opn = "unk";
6ea83fed
FB
801
802 if (base == 0) {
803 GEN_LOAD_IMM_TN(T0, offset);
804 } else if (offset == 0) {
805 gen_op_load_gpr_T0(base);
806 } else {
807 gen_op_load_gpr_T0(base);
808 gen_op_set_T1(offset);
809 gen_op_add();
810 }
811 /* Don't do NOP if destination is zero: we must perform the actual
812 * memory access
813 */
814 switch (opc) {
815 case OPC_LWC1:
816 op_ldst(lwc1);
817 GEN_STORE_FTN_FREG(ft, WT0);
818 opn = "lwc1";
819 break;
820 case OPC_SWC1:
821 GEN_LOAD_FREG_FTN(WT0, ft);
822 op_ldst(swc1);
823 opn = "swc1";
824 break;
825 case OPC_LDC1:
826 op_ldst(ldc1);
827 GEN_STORE_FTN_FREG(ft, DT0);
828 opn = "ldc1";
829 break;
830 case OPC_SDC1:
831 GEN_LOAD_FREG_FTN(DT0, ft);
832 op_ldst(sdc1);
833 opn = "sdc1";
834 break;
835 default:
836 MIPS_INVAL("float load/store");
7a387fff 837 generate_exception_err(ctx, EXCP_CpU, 1);
6ea83fed
FB
838 return;
839 }
840 MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
841}
6ea83fed 842
71fb7241
TS
843#endif /* MIPS_USES_FPU */
844
6af0bf9c 845/* Arithmetic with immediate operand */
7a387fff 846static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
6af0bf9c
FB
847 int rs, int16_t imm)
848{
849 uint32_t uimm;
7a387fff 850 const char *opn = "unk";
6af0bf9c 851
7a387fff 852 if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
6af0bf9c
FB
853 /* if no destination, treat it as a NOP
854 * For addi, we must generate the overflow exception when needed.
855 */
856 MIPS_DEBUG("NOP");
857 return;
858 }
859 if (opc == OPC_ADDI || opc == OPC_ADDIU ||
7a387fff 860 opc == OPC_DADDI || opc == OPC_DADDIU ||
6af0bf9c 861 opc == OPC_SLTI || opc == OPC_SLTIU)
7a387fff 862 uimm = (int32_t)imm; /* Sign extend to 32 bits */
6af0bf9c
FB
863 else
864 uimm = (uint16_t)imm;
865 if (opc != OPC_LUI) {
866 GEN_LOAD_REG_TN(T0, rs);
867 GEN_LOAD_IMM_TN(T1, uimm);
868 } else {
869 uimm = uimm << 16;
870 GEN_LOAD_IMM_TN(T0, uimm);
871 }
872 switch (opc) {
873 case OPC_ADDI:
874 save_cpu_state(ctx, 1);
875 gen_op_addo();
876 opn = "addi";
877 break;
878 case OPC_ADDIU:
879 gen_op_add();
880 opn = "addiu";
881 break;
7a387fff
TS
882#ifdef MIPS_HAS_MIPS64
883 case OPC_DADDI:
884 save_cpu_state(ctx, 1);
885 gen_op_daddo();
886 opn = "daddi";
887 break;
888 case OPC_DADDIU:
889 gen_op_dadd();
890 opn = "daddiu";
891 break;
892#endif
6af0bf9c
FB
893 case OPC_SLTI:
894 gen_op_lt();
895 opn = "slti";
896 break;
897 case OPC_SLTIU:
898 gen_op_ltu();
899 opn = "sltiu";
900 break;
901 case OPC_ANDI:
902 gen_op_and();
903 opn = "andi";
904 break;
905 case OPC_ORI:
906 gen_op_or();
907 opn = "ori";
908 break;
909 case OPC_XORI:
910 gen_op_xor();
911 opn = "xori";
912 break;
913 case OPC_LUI:
914 opn = "lui";
915 break;
916 case OPC_SLL:
917 gen_op_sll();
918 opn = "sll";
919 break;
920 case OPC_SRA:
921 gen_op_sra();
922 opn = "sra";
923 break;
924 case OPC_SRL:
7a387fff
TS
925 if ((ctx->opcode >> 21) & 1) {
926 gen_op_rotr();
927 opn = "rotr";
928 } else {
929 gen_op_srl();
930 opn = "srl";
931 }
932 break;
933#ifdef MIPS_HAS_MIPS64
934 case OPC_DSLL:
935 gen_op_dsll();
936 opn = "dsll";
937 break;
938 case OPC_DSRA:
939 gen_op_dsra();
940 opn = "dsra";
941 break;
942 case OPC_DSRL:
943 if ((ctx->opcode >> 21) & 1) {
944 gen_op_drotr();
945 opn = "drotr";
946 } else {
947 gen_op_dsrl();
948 opn = "dsrl";
949 }
950 break;
951 case OPC_DSLL32:
952 gen_op_dsll32();
953 opn = "dsll32";
954 break;
955 case OPC_DSRA32:
956 gen_op_dsra32();
957 opn = "dsra32";
958 break;
959 case OPC_DSRL32:
960 if ((ctx->opcode >> 21) & 1) {
961 gen_op_drotr32();
962 opn = "drotr32";
963 } else {
964 gen_op_dsrl32();
965 opn = "dsrl32";
966 }
6af0bf9c 967 break;
7a387fff 968#endif
6af0bf9c
FB
969 default:
970 MIPS_INVAL("imm arith");
971 generate_exception(ctx, EXCP_RI);
972 return;
973 }
974 GEN_STORE_TN_REG(rt, T0);
975 MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
976}
977
978/* Arithmetic */
7a387fff 979static void gen_arith (DisasContext *ctx, uint32_t opc,
6af0bf9c
FB
980 int rd, int rs, int rt)
981{
7a387fff 982 const char *opn = "unk";
6af0bf9c 983
7a387fff
TS
984 if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
985 && opc != OPC_DADD && opc != OPC_DSUB) {
6af0bf9c
FB
986 /* if no destination, treat it as a NOP
987 * For add & sub, we must generate the overflow exception when needed.
988 */
989 MIPS_DEBUG("NOP");
990 return;
991 }
992 GEN_LOAD_REG_TN(T0, rs);
993 GEN_LOAD_REG_TN(T1, rt);
994 switch (opc) {
995 case OPC_ADD:
996 save_cpu_state(ctx, 1);
997 gen_op_addo();
998 opn = "add";
999 break;
1000 case OPC_ADDU:
1001 gen_op_add();
1002 opn = "addu";
1003 break;
1004 case OPC_SUB:
1005 save_cpu_state(ctx, 1);
1006 gen_op_subo();
1007 opn = "sub";
1008 break;
1009 case OPC_SUBU:
1010 gen_op_sub();
1011 opn = "subu";
1012 break;
7a387fff
TS
1013#ifdef MIPS_HAS_MIPS64
1014 case OPC_DADD:
1015 save_cpu_state(ctx, 1);
1016 gen_op_daddo();
1017 opn = "dadd";
1018 break;
1019 case OPC_DADDU:
1020 gen_op_dadd();
1021 opn = "daddu";
1022 break;
1023 case OPC_DSUB:
1024 save_cpu_state(ctx, 1);
1025 gen_op_dsubo();
1026 opn = "dsub";
1027 break;
1028 case OPC_DSUBU:
1029 gen_op_dsub();
1030 opn = "dsubu";
1031 break;
1032#endif
6af0bf9c
FB
1033 case OPC_SLT:
1034 gen_op_lt();
1035 opn = "slt";
1036 break;
1037 case OPC_SLTU:
1038 gen_op_ltu();
1039 opn = "sltu";
1040 break;
1041 case OPC_AND:
1042 gen_op_and();
1043 opn = "and";
1044 break;
1045 case OPC_NOR:
1046 gen_op_nor();
1047 opn = "nor";
1048 break;
1049 case OPC_OR:
1050 gen_op_or();
1051 opn = "or";
1052 break;
1053 case OPC_XOR:
1054 gen_op_xor();
1055 opn = "xor";
1056 break;
1057 case OPC_MUL:
1058 gen_op_mul();
1059 opn = "mul";
1060 break;
1061 case OPC_MOVN:
1062 gen_op_movn(rd);
1063 opn = "movn";
1064 goto print;
1065 case OPC_MOVZ:
1066 gen_op_movz(rd);
1067 opn = "movz";
1068 goto print;
1069 case OPC_SLLV:
1070 gen_op_sllv();
1071 opn = "sllv";
1072 break;
1073 case OPC_SRAV:
1074 gen_op_srav();
1075 opn = "srav";
1076 break;
1077 case OPC_SRLV:
7a387fff
TS
1078 if ((ctx->opcode >> 6) & 1) {
1079 gen_op_rotrv();
1080 opn = "rotrv";
1081 } else {
1082 gen_op_srlv();
1083 opn = "srlv";
1084 }
1085 break;
1086#ifdef MIPS_HAS_MIPS64
1087 case OPC_DSLLV:
1088 gen_op_dsllv();
1089 opn = "dsllv";
1090 break;
1091 case OPC_DSRAV:
1092 gen_op_dsrav();
1093 opn = "dsrav";
1094 break;
1095 case OPC_DSRLV:
1096 if ((ctx->opcode >> 6) & 1) {
1097 gen_op_drotrv();
1098 opn = "drotrv";
1099 } else {
1100 gen_op_dsrlv();
1101 opn = "dsrlv";
1102 }
6af0bf9c 1103 break;
7a387fff 1104#endif
6af0bf9c
FB
1105 default:
1106 MIPS_INVAL("arith");
1107 generate_exception(ctx, EXCP_RI);
1108 return;
1109 }
1110 GEN_STORE_TN_REG(rd, T0);
1111 print:
1112 MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
1113}
1114
1115/* Arithmetic on HI/LO registers */
7a387fff 1116static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
6af0bf9c 1117{
7a387fff 1118 const char *opn = "unk";
6af0bf9c
FB
1119
1120 if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
1121 /* Treat as a NOP */
1122 MIPS_DEBUG("NOP");
1123 return;
1124 }
1125 switch (opc) {
1126 case OPC_MFHI:
1127 gen_op_load_HI();
1128 GEN_STORE_TN_REG(reg, T0);
1129 opn = "mfhi";
1130 break;
1131 case OPC_MFLO:
1132 gen_op_load_LO();
1133 GEN_STORE_TN_REG(reg, T0);
1134 opn = "mflo";
1135 break;
1136 case OPC_MTHI:
1137 GEN_LOAD_REG_TN(T0, reg);
1138 gen_op_store_HI();
1139 opn = "mthi";
1140 break;
1141 case OPC_MTLO:
1142 GEN_LOAD_REG_TN(T0, reg);
1143 gen_op_store_LO();
1144 opn = "mtlo";
1145 break;
1146 default:
1147 MIPS_INVAL("HILO");
1148 generate_exception(ctx, EXCP_RI);
1149 return;
1150 }
1151 MIPS_DEBUG("%s %s", opn, regnames[reg]);
1152}
1153
7a387fff 1154static void gen_muldiv (DisasContext *ctx, uint32_t opc,
6af0bf9c
FB
1155 int rs, int rt)
1156{
7a387fff 1157 const char *opn = "unk";
6af0bf9c
FB
1158
1159 GEN_LOAD_REG_TN(T0, rs);
1160 GEN_LOAD_REG_TN(T1, rt);
1161 switch (opc) {
1162 case OPC_DIV:
1163 gen_op_div();
1164 opn = "div";
1165 break;
1166 case OPC_DIVU:
1167 gen_op_divu();
1168 opn = "divu";
1169 break;
1170 case OPC_MULT:
1171 gen_op_mult();
1172 opn = "mult";
1173 break;
1174 case OPC_MULTU:
1175 gen_op_multu();
1176 opn = "multu";
1177 break;
7a387fff
TS
1178#ifdef MIPS_HAS_MIPS64
1179 case OPC_DDIV:
1180 gen_op_ddiv();
1181 opn = "ddiv";
1182 break;
1183 case OPC_DDIVU:
1184 gen_op_ddivu();
1185 opn = "ddivu";
1186 break;
1187 case OPC_DMULT:
1188 gen_op_dmult();
1189 opn = "dmult";
1190 break;
1191 case OPC_DMULTU:
1192 gen_op_dmultu();
1193 opn = "dmultu";
1194 break;
1195#endif
6af0bf9c
FB
1196 case OPC_MADD:
1197 gen_op_madd();
1198 opn = "madd";
1199 break;
1200 case OPC_MADDU:
1201 gen_op_maddu();
1202 opn = "maddu";
1203 break;
1204 case OPC_MSUB:
1205 gen_op_msub();
1206 opn = "msub";
1207 break;
1208 case OPC_MSUBU:
1209 gen_op_msubu();
1210 opn = "msubu";
1211 break;
1212 default:
1213 MIPS_INVAL("mul/div");
1214 generate_exception(ctx, EXCP_RI);
1215 return;
1216 }
1217 MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
1218}
1219
7a387fff 1220static void gen_cl (DisasContext *ctx, uint32_t opc,
6af0bf9c
FB
1221 int rd, int rs)
1222{
7a387fff 1223 const char *opn = "unk";
6af0bf9c
FB
1224 if (rd == 0) {
1225 /* Treat as a NOP */
1226 MIPS_DEBUG("NOP");
1227 return;
1228 }
1229 GEN_LOAD_REG_TN(T0, rs);
1230 switch (opc) {
1231 case OPC_CLO:
6af0bf9c
FB
1232 gen_op_clo();
1233 opn = "clo";
1234 break;
1235 case OPC_CLZ:
6af0bf9c
FB
1236 gen_op_clz();
1237 opn = "clz";
1238 break;
7a387fff
TS
1239#ifdef MIPS_HAS_MIPS64
1240 case OPC_DCLO:
1241 gen_op_dclo();
1242 opn = "dclo";
1243 break;
1244 case OPC_DCLZ:
1245 gen_op_dclz();
1246 opn = "dclz";
1247 break;
1248#endif
6af0bf9c
FB
1249 default:
1250 MIPS_INVAL("CLx");
1251 generate_exception(ctx, EXCP_RI);
1252 return;
1253 }
1254 gen_op_store_T0_gpr(rd);
1255 MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
1256}
1257
1258/* Traps */
7a387fff 1259static void gen_trap (DisasContext *ctx, uint32_t opc,
6af0bf9c
FB
1260 int rs, int rt, int16_t imm)
1261{
1262 int cond;
1263
1264 cond = 0;
1265 /* Load needed operands */
1266 switch (opc) {
1267 case OPC_TEQ:
1268 case OPC_TGE:
1269 case OPC_TGEU:
1270 case OPC_TLT:
1271 case OPC_TLTU:
1272 case OPC_TNE:
1273 /* Compare two registers */
1274 if (rs != rt) {
1275 GEN_LOAD_REG_TN(T0, rs);
1276 GEN_LOAD_REG_TN(T1, rt);
1277 cond = 1;
1278 }
179e32bb 1279 break;
6af0bf9c
FB
1280 case OPC_TEQI:
1281 case OPC_TGEI:
1282 case OPC_TGEIU:
1283 case OPC_TLTI:
1284 case OPC_TLTIU:
1285 case OPC_TNEI:
1286 /* Compare register to immediate */
1287 if (rs != 0 || imm != 0) {
1288 GEN_LOAD_REG_TN(T0, rs);
1289 GEN_LOAD_IMM_TN(T1, (int32_t)imm);
1290 cond = 1;
1291 }
1292 break;
1293 }
1294 if (cond == 0) {
1295 switch (opc) {
1296 case OPC_TEQ: /* rs == rs */
1297 case OPC_TEQI: /* r0 == 0 */
1298 case OPC_TGE: /* rs >= rs */
1299 case OPC_TGEI: /* r0 >= 0 */
1300 case OPC_TGEU: /* rs >= rs unsigned */
1301 case OPC_TGEIU: /* r0 >= 0 unsigned */
1302 /* Always trap */
1303 gen_op_set_T0(1);
1304 break;
1305 case OPC_TLT: /* rs < rs */
1306 case OPC_TLTI: /* r0 < 0 */
1307 case OPC_TLTU: /* rs < rs unsigned */
1308 case OPC_TLTIU: /* r0 < 0 unsigned */
1309 case OPC_TNE: /* rs != rs */
1310 case OPC_TNEI: /* r0 != 0 */
1311 /* Never trap: treat as NOP */
1312 return;
1313 default:
1314 MIPS_INVAL("TRAP");
1315 generate_exception(ctx, EXCP_RI);
1316 return;
1317 }
1318 } else {
1319 switch (opc) {
1320 case OPC_TEQ:
1321 case OPC_TEQI:
1322 gen_op_eq();
1323 break;
1324 case OPC_TGE:
1325 case OPC_TGEI:
1326 gen_op_ge();
1327 break;
1328 case OPC_TGEU:
1329 case OPC_TGEIU:
1330 gen_op_geu();
1331 break;
1332 case OPC_TLT:
1333 case OPC_TLTI:
1334 gen_op_lt();
1335 break;
1336 case OPC_TLTU:
1337 case OPC_TLTIU:
1338 gen_op_ltu();
1339 break;
1340 case OPC_TNE:
1341 case OPC_TNEI:
1342 gen_op_ne();
1343 break;
1344 default:
1345 MIPS_INVAL("TRAP");
1346 generate_exception(ctx, EXCP_RI);
1347 return;
1348 }
1349 }
1350 save_cpu_state(ctx, 1);
1351 gen_op_trap();
1352 ctx->bstate = BS_STOP;
1353}
1354
6e256c93 1355static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
c53be334 1356{
6e256c93
FB
1357 TranslationBlock *tb;
1358 tb = ctx->tb;
1359 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1360 if (n == 0)
1361 gen_op_goto_tb0(TBPARAM(tb));
1362 else
1363 gen_op_goto_tb1(TBPARAM(tb));
1364 gen_op_save_pc(dest);
1365 gen_op_set_T0((long)tb + n);
1366 gen_op_exit_tb();
1367 } else {
1368 gen_op_save_pc(dest);
1369 gen_op_set_T0(0);
1370 gen_op_exit_tb();
1371 }
c53be334
FB
1372}
1373
6af0bf9c 1374/* Branches (before delay slot) */
7a387fff 1375static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
6af0bf9c
FB
1376 int rs, int rt, int32_t offset)
1377{
1378 target_ulong btarget;
1379 int blink, bcond;
1380
1381 btarget = -1;
1382 blink = 0;
1383 bcond = 0;
1384 /* Load needed operands */
1385 switch (opc) {
1386 case OPC_BEQ:
1387 case OPC_BEQL:
1388 case OPC_BNE:
1389 case OPC_BNEL:
1390 /* Compare two registers */
1391 if (rs != rt) {
1392 GEN_LOAD_REG_TN(T0, rs);
1393 GEN_LOAD_REG_TN(T1, rt);
1394 bcond = 1;
1395 }
1396 btarget = ctx->pc + 4 + offset;
1397 break;
1398 case OPC_BGEZ:
1399 case OPC_BGEZAL:
1400 case OPC_BGEZALL:
1401 case OPC_BGEZL:
1402 case OPC_BGTZ:
1403 case OPC_BGTZL:
1404 case OPC_BLEZ:
1405 case OPC_BLEZL:
1406 case OPC_BLTZ:
1407 case OPC_BLTZAL:
1408 case OPC_BLTZALL:
1409 case OPC_BLTZL:
1410 /* Compare to zero */
1411 if (rs != 0) {
1412 gen_op_load_gpr_T0(rs);
1413 bcond = 1;
1414 }
1415 btarget = ctx->pc + 4 + offset;
1416 break;
1417 case OPC_J:
1418 case OPC_JAL:
1419 /* Jump to immediate */
bc9ed47b 1420 btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
6af0bf9c
FB
1421 break;
1422 case OPC_JR:
1423 case OPC_JALR:
1424 /* Jump to register */
7a387fff
TS
1425 if (offset != 0 && offset != 16) {
1426 /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
1427 others are reserved. */
6af0bf9c
FB
1428 generate_exception(ctx, EXCP_RI);
1429 return;
1430 }
1431 GEN_LOAD_REG_TN(T2, rs);
1432 break;
1433 default:
1434 MIPS_INVAL("branch/jump");
1435 generate_exception(ctx, EXCP_RI);
1436 return;
1437 }
1438 if (bcond == 0) {
1439 /* No condition to be computed */
1440 switch (opc) {
1441 case OPC_BEQ: /* rx == rx */
1442 case OPC_BEQL: /* rx == rx likely */
1443 case OPC_BGEZ: /* 0 >= 0 */
1444 case OPC_BGEZL: /* 0 >= 0 likely */
1445 case OPC_BLEZ: /* 0 <= 0 */
1446 case OPC_BLEZL: /* 0 <= 0 likely */
1447 /* Always take */
4ad40f36 1448 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1449 MIPS_DEBUG("balways");
1450 break;
1451 case OPC_BGEZAL: /* 0 >= 0 */
1452 case OPC_BGEZALL: /* 0 >= 0 likely */
1453 /* Always take and link */
1454 blink = 31;
4ad40f36 1455 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1456 MIPS_DEBUG("balways and link");
1457 break;
1458 case OPC_BNE: /* rx != rx */
1459 case OPC_BGTZ: /* 0 > 0 */
1460 case OPC_BLTZ: /* 0 < 0 */
6af0bf9c
FB
1461 /* Treated as NOP */
1462 MIPS_DEBUG("bnever (NOP)");
1463 return;
eeef26cd
FB
1464 case OPC_BLTZAL: /* 0 < 0 */
1465 gen_op_set_T0(ctx->pc + 8);
1466 gen_op_store_T0_gpr(31);
1467 return;
1468 case OPC_BLTZALL: /* 0 < 0 likely */
1469 gen_op_set_T0(ctx->pc + 8);
1470 gen_op_store_T0_gpr(31);
1471 gen_goto_tb(ctx, 0, ctx->pc + 4);
1472 return;
6af0bf9c
FB
1473 case OPC_BNEL: /* rx != rx likely */
1474 case OPC_BGTZL: /* 0 > 0 likely */
6af0bf9c
FB
1475 case OPC_BLTZL: /* 0 < 0 likely */
1476 /* Skip the instruction in the delay slot */
1477 MIPS_DEBUG("bnever and skip");
6e256c93 1478 gen_goto_tb(ctx, 0, ctx->pc + 4);
6af0bf9c
FB
1479 return;
1480 case OPC_J:
4ad40f36 1481 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1482 MIPS_DEBUG("j %08x", btarget);
1483 break;
1484 case OPC_JAL:
1485 blink = 31;
4ad40f36 1486 ctx->hflags |= MIPS_HFLAG_B;
6af0bf9c
FB
1487 MIPS_DEBUG("jal %08x", btarget);
1488 break;
1489 case OPC_JR:
4ad40f36 1490 ctx->hflags |= MIPS_HFLAG_BR;
6af0bf9c
FB
1491 MIPS_DEBUG("jr %s", regnames[rs]);
1492 break;
1493 case OPC_JALR:
1494 blink = rt;
4ad40f36 1495 ctx->hflags |= MIPS_HFLAG_BR;
6af0bf9c
FB
1496 MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
1497 break;
1498 default:
1499 MIPS_INVAL("branch/jump");
1500 generate_exception(ctx, EXCP_RI);
1501 return;
1502 }
1503 } else {
1504 switch (opc) {
1505 case OPC_BEQ:
1506 gen_op_eq();
1507 MIPS_DEBUG("beq %s, %s, %08x",
1508 regnames[rs], regnames[rt], btarget);
1509 goto not_likely;
1510 case OPC_BEQL:
1511 gen_op_eq();
1512 MIPS_DEBUG("beql %s, %s, %08x",
1513 regnames[rs], regnames[rt], btarget);
1514 goto likely;
1515 case OPC_BNE:
1516 gen_op_ne();
1517 MIPS_DEBUG("bne %s, %s, %08x",
1518 regnames[rs], regnames[rt], btarget);
1519 goto not_likely;
1520 case OPC_BNEL:
1521 gen_op_ne();
1522 MIPS_DEBUG("bnel %s, %s, %08x",
1523 regnames[rs], regnames[rt], btarget);
1524 goto likely;
1525 case OPC_BGEZ:
1526 gen_op_gez();
1527 MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
1528 goto not_likely;
1529 case OPC_BGEZL:
1530 gen_op_gez();
1531 MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
1532 goto likely;
1533 case OPC_BGEZAL:
1534 gen_op_gez();
1535 MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
1536 blink = 31;
1537 goto not_likely;
1538 case OPC_BGEZALL:
1539 gen_op_gez();
1540 blink = 31;
1541 MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
1542 goto likely;
1543 case OPC_BGTZ:
1544 gen_op_gtz();
1545 MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
1546 goto not_likely;
1547 case OPC_BGTZL:
1548 gen_op_gtz();
1549 MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
1550 goto likely;
1551 case OPC_BLEZ:
1552 gen_op_lez();
1553 MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
1554 goto not_likely;
1555 case OPC_BLEZL:
1556 gen_op_lez();
1557 MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
1558 goto likely;
1559 case OPC_BLTZ:
1560 gen_op_ltz();
1561 MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
1562 goto not_likely;
1563 case OPC_BLTZL:
1564 gen_op_ltz();
1565 MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
1566 goto likely;
1567 case OPC_BLTZAL:
1568 gen_op_ltz();
1569 blink = 31;
1570 MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
1571 not_likely:
4ad40f36 1572 ctx->hflags |= MIPS_HFLAG_BC;
6af0bf9c
FB
1573 break;
1574 case OPC_BLTZALL:
1575 gen_op_ltz();
1576 blink = 31;
1577 MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
1578 likely:
4ad40f36 1579 ctx->hflags |= MIPS_HFLAG_BL;
6af0bf9c
FB
1580 break;
1581 }
1582 gen_op_set_bcond();
1583 }
1584 MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
1585 blink, ctx->hflags, btarget);
1586 ctx->btarget = btarget;
1587 if (blink > 0) {
1588 gen_op_set_T0(ctx->pc + 8);
1589 gen_op_store_T0_gpr(blink);
1590 }
1591 return;
1592}
1593
7a387fff
TS
1594/* special3 bitfield operations */
1595static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
1596 int rs, int lsb, int msb)
1597{
1598 GEN_LOAD_REG_TN(T1, rs);
1599 switch (opc) {
1600 case OPC_EXT:
1601 if (lsb + msb > 31)
1602 goto fail;
1603 gen_op_ext(lsb, msb + 1);
1604 break;
1605 case OPC_DEXTM:
1606 if (lsb + msb > 63)
1607 goto fail;
1608 gen_op_ext(lsb, msb + 1 + 32);
1609 break;
1610 case OPC_DEXTU:
1611 if (lsb + msb > 63)
1612 goto fail;
1613 gen_op_ext(lsb + 32, msb + 1);
1614 break;
1615 case OPC_DEXT:
1616 gen_op_ext(lsb, msb + 1);
1617 break;
1618 case OPC_INS:
1619 if (lsb > msb)
1620 goto fail;
1621 GEN_LOAD_REG_TN(T2, rt);
1622 gen_op_ins(lsb, msb - lsb + 1);
1623 break;
1624 case OPC_DINSM:
1625 if (lsb > msb)
1626 goto fail;
1627 GEN_LOAD_REG_TN(T2, rt);
1628 gen_op_ins(lsb, msb - lsb + 1 + 32);
1629 break;
1630 case OPC_DINSU:
1631 if (lsb > msb)
1632 goto fail;
1633 GEN_LOAD_REG_TN(T2, rt);
1634 gen_op_ins(lsb + 32, msb - lsb + 1);
1635 break;
1636 case OPC_DINS:
1637 if (lsb > msb)
1638 goto fail;
1639 GEN_LOAD_REG_TN(T2, rt);
1640 gen_op_ins(lsb, msb - lsb + 1);
1641 break;
1642 default:
1643fail:
1644 MIPS_INVAL("bitops");
1645 generate_exception(ctx, EXCP_RI);
1646 return;
1647 }
1648 GEN_STORE_TN_REG(rt, T0);
1649}
1650
6af0bf9c 1651/* CP0 (MMU and control) */
873eb012
TS
1652static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
1653{
7a387fff 1654 const char *rn = "invalid";
873eb012 1655
873eb012
TS
1656 switch (reg) {
1657 case 0:
7a387fff
TS
1658 switch (sel) {
1659 case 0:
1660 gen_op_mfc0_index();
1661 rn = "Index";
1662 break;
1663 case 1:
1664// gen_op_mfc0_mvpcontrol(); /* MT ASE */
1665 rn = "MVPControl";
1666// break;
1667 case 2:
1668// gen_op_mfc0_mvpconf0(); /* MT ASE */
1669 rn = "MVPConf0";
1670// break;
1671 case 3:
1672// gen_op_mfc0_mvpconf1(); /* MT ASE */
1673 rn = "MVPConf1";
1674// break;
1675 default:
1676 goto die;
1677 }
873eb012
TS
1678 break;
1679 case 1:
7a387fff
TS
1680 switch (sel) {
1681 case 0:
1682 gen_op_mfc0_random();
1683 rn = "Random";
1684 break;
1685 case 1:
1686// gen_op_mfc0_vpecontrol(); /* MT ASE */
1687 rn = "VPEControl";
1688// break;
1689 case 2:
1690// gen_op_mfc0_vpeconf0(); /* MT ASE */
1691 rn = "VPEConf0";
1692// break;
1693 case 3:
1694// gen_op_mfc0_vpeconf1(); /* MT ASE */
1695 rn = "VPEConf1";
1696// break;
1697 case 4:
1698// gen_op_mfc0_YQMask(); /* MT ASE */
1699 rn = "YQMask";
1700// break;
1701 case 5:
1702// gen_op_mfc0_vpeschedule(); /* MT ASE */
1703 rn = "VPESchedule";
1704// break;
1705 case 6:
1706// gen_op_mfc0_vpeschefback(); /* MT ASE */
1707 rn = "VPEScheFBack";
1708// break;
1709 case 7:
1710// gen_op_mfc0_vpeopt(); /* MT ASE */
1711 rn = "VPEOpt";
1712// break;
1713 default:
1714 goto die;
1715 }
873eb012
TS
1716 break;
1717 case 2:
7a387fff
TS
1718 switch (sel) {
1719 case 0:
1720 gen_op_mfc0_entrylo0();
1721 rn = "EntryLo0";
1722 break;
1723 case 1:
1724// gen_op_mfc0_tcstatus(); /* MT ASE */
1725 rn = "TCStatus";
1726// break;
1727 case 2:
1728// gen_op_mfc0_tcbind(); /* MT ASE */
1729 rn = "TCBind";
1730// break;
1731 case 3:
1732// gen_op_mfc0_tcrestart(); /* MT ASE */
1733 rn = "TCRestart";
1734// break;
1735 case 4:
1736// gen_op_mfc0_tchalt(); /* MT ASE */
1737 rn = "TCHalt";
1738// break;
1739 case 5:
1740// gen_op_mfc0_tccontext(); /* MT ASE */
1741 rn = "TCContext";
1742// break;
1743 case 6:
1744// gen_op_mfc0_tcschedule(); /* MT ASE */
1745 rn = "TCSchedule";
1746// break;
1747 case 7:
1748// gen_op_mfc0_tcschefback(); /* MT ASE */
1749 rn = "TCScheFBack";
1750// break;
1751 default:
1752 goto die;
1753 }
873eb012
TS
1754 break;
1755 case 3:
7a387fff
TS
1756 switch (sel) {
1757 case 0:
1758 gen_op_mfc0_entrylo1();
1759 rn = "EntryLo1";
1760 break;
1761 default:
1762 goto die;
1763 }
873eb012
TS
1764 break;
1765 case 4:
7a387fff
TS
1766 switch (sel) {
1767 case 0:
1768 gen_op_mfc0_context();
1769 rn = "Context";
1770 break;
1771 case 1:
1772// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
1773 rn = "ContextConfig";
1774// break;
1775 default:
1776 goto die;
1777 }
873eb012
TS
1778 break;
1779 case 5:
7a387fff
TS
1780 switch (sel) {
1781 case 0:
1782 gen_op_mfc0_pagemask();
1783 rn = "PageMask";
1784 break;
1785 case 1:
1786 gen_op_mfc0_pagegrain();
1787 rn = "PageGrain";
1788 break;
1789 default:
1790 goto die;
1791 }
873eb012
TS
1792 break;
1793 case 6:
7a387fff
TS
1794 switch (sel) {
1795 case 0:
1796 gen_op_mfc0_wired();
1797 rn = "Wired";
1798 break;
1799 case 1:
1800// gen_op_mfc0_srsconf0(); /* shadow registers */
1801 rn = "SRSConf0";
1802// break;
1803 case 2:
1804// gen_op_mfc0_srsconf1(); /* shadow registers */
1805 rn = "SRSConf1";
1806// break;
1807 case 3:
1808// gen_op_mfc0_srsconf2(); /* shadow registers */
1809 rn = "SRSConf2";
1810// break;
1811 case 4:
1812// gen_op_mfc0_srsconf3(); /* shadow registers */
1813 rn = "SRSConf3";
1814// break;
1815 case 5:
1816// gen_op_mfc0_srsconf4(); /* shadow registers */
1817 rn = "SRSConf4";
1818// break;
1819 default:
1820 goto die;
1821 }
873eb012 1822 break;
8c0fdd85 1823 case 7:
7a387fff
TS
1824 switch (sel) {
1825 case 0:
1826 gen_op_mfc0_hwrena();
1827 rn = "HWREna";
1828 break;
1829 default:
1830 goto die;
1831 }
8c0fdd85 1832 break;
873eb012 1833 case 8:
7a387fff
TS
1834 switch (sel) {
1835 case 0:
1836 gen_op_mfc0_badvaddr();
1837 rn = "BadVaddr";
1838 break;
1839 default:
1840 goto die;
1841 }
873eb012
TS
1842 break;
1843 case 9:
7a387fff
TS
1844 switch (sel) {
1845 case 0:
1846 gen_op_mfc0_count();
1847 rn = "Count";
1848 break;
1849 /* 6,7 are implementation dependent */
1850 default:
1851 goto die;
1852 }
873eb012
TS
1853 break;
1854 case 10:
7a387fff
TS
1855 switch (sel) {
1856 case 0:
1857 gen_op_mfc0_entryhi();
1858 rn = "EntryHi";
1859 break;
1860 default:
1861 goto die;
1862 }
873eb012
TS
1863 break;
1864 case 11:
7a387fff
TS
1865 switch (sel) {
1866 case 0:
1867 gen_op_mfc0_compare();
1868 rn = "Compare";
1869 break;
1870 /* 6,7 are implementation dependent */
1871 default:
1872 goto die;
1873 }
873eb012
TS
1874 break;
1875 case 12:
7a387fff
TS
1876 switch (sel) {
1877 case 0:
1878 gen_op_mfc0_status();
1879 rn = "Status";
1880 break;
1881 case 1:
1882 gen_op_mfc0_intctl();
1883 rn = "IntCtl";
1884 break;
1885 case 2:
1886 gen_op_mfc0_srsctl();
1887 rn = "SRSCtl";
1888 break;
1889 case 3:
1890// gen_op_mfc0_srsmap(); /* shadow registers */
1891 rn = "SRSMap";
1892// break;
1893 default:
1894 goto die;
1895 }
873eb012
TS
1896 break;
1897 case 13:
7a387fff
TS
1898 switch (sel) {
1899 case 0:
1900 gen_op_mfc0_cause();
1901 rn = "Cause";
1902 break;
1903 default:
1904 goto die;
1905 }
873eb012
TS
1906 break;
1907 case 14:
7a387fff
TS
1908 switch (sel) {
1909 case 0:
1910 gen_op_mfc0_epc();
1911 rn = "EPC";
1912 break;
1913 default:
1914 goto die;
1915 }
873eb012
TS
1916 break;
1917 case 15:
7a387fff
TS
1918 switch (sel) {
1919 case 0:
1920 gen_op_mfc0_prid();
1921 rn = "PRid";
1922 break;
1923 case 1:
1924 gen_op_mfc0_ebase();
1925 rn = "EBase";
1926 break;
1927 default:
1928 goto die;
1929 }
873eb012
TS
1930 break;
1931 case 16:
1932 switch (sel) {
1933 case 0:
1934 gen_op_mfc0_config0();
1935 rn = "Config";
1936 break;
1937 case 1:
1938 gen_op_mfc0_config1();
1939 rn = "Config1";
1940 break;
7a387fff
TS
1941 case 2:
1942 gen_op_mfc0_config2();
1943 rn = "Config2";
1944 break;
1945 case 3:
1946 gen_op_mfc0_config3();
1947 rn = "Config3";
1948 break;
1949 /* 6,7 are implementation dependent */
873eb012 1950 default:
873eb012
TS
1951 goto die;
1952 }
1953 break;
1954 case 17:
7a387fff
TS
1955 switch (sel) {
1956 case 0:
1957 gen_op_mfc0_lladdr();
1958 rn = "LLAddr";
1959 break;
1960 default:
1961 goto die;
1962 }
873eb012
TS
1963 break;
1964 case 18:
7a387fff
TS
1965 switch (sel) {
1966 case 0:
1967 gen_op_mfc0_watchlo0();
1968 rn = "WatchLo";
1969 break;
1970 case 1:
1971// gen_op_mfc0_watchlo1();
1972 rn = "WatchLo1";
1973// break;
1974 case 2:
1975// gen_op_mfc0_watchlo2();
1976 rn = "WatchLo2";
1977// break;
1978 case 3:
1979// gen_op_mfc0_watchlo3();
1980 rn = "WatchLo3";
1981// break;
1982 case 4:
1983// gen_op_mfc0_watchlo4();
1984 rn = "WatchLo4";
1985// break;
1986 case 5:
1987// gen_op_mfc0_watchlo5();
1988 rn = "WatchLo5";
1989// break;
1990 case 6:
1991// gen_op_mfc0_watchlo6();
1992 rn = "WatchLo6";
1993// break;
1994 case 7:
1995// gen_op_mfc0_watchlo7();
1996 rn = "WatchLo7";
1997// break;
1998 default:
1999 goto die;
2000 }
873eb012
TS
2001 break;
2002 case 19:
7a387fff
TS
2003 switch (sel) {
2004 case 0:
2005 gen_op_mfc0_watchhi0();
2006 rn = "WatchHi";
2007 break;
2008 case 1:
2009// gen_op_mfc0_watchhi1();
2010 rn = "WatchHi1";
2011// break;
2012 case 2:
2013// gen_op_mfc0_watchhi2();
2014 rn = "WatchHi2";
2015// break;
2016 case 3:
2017// gen_op_mfc0_watchhi3();
2018 rn = "WatchHi3";
2019// break;
2020 case 4:
2021// gen_op_mfc0_watchhi4();
2022 rn = "WatchHi4";
2023// break;
2024 case 5:
2025// gen_op_mfc0_watchhi5();
2026 rn = "WatchHi5";
2027// break;
2028 case 6:
2029// gen_op_mfc0_watchhi6();
2030 rn = "WatchHi6";
2031// break;
2032 case 7:
2033// gen_op_mfc0_watchhi7();
2034 rn = "WatchHi7";
2035// break;
2036 default:
2037 goto die;
2038 }
873eb012 2039 break;
8c0fdd85 2040 case 20:
7a387fff
TS
2041 switch (sel) {
2042 case 0:
2043 /* 64 bit MMU only */
2044 gen_op_mfc0_xcontext();
2045 rn = "XContext";
2046 break;
2047 default:
2048 goto die;
2049 }
8c0fdd85
TS
2050 break;
2051 case 21:
7a387fff
TS
2052 /* Officially reserved, but sel 0 is used for R1x000 framemask */
2053 switch (sel) {
2054 case 0:
2055 gen_op_mfc0_framemask();
2056 rn = "Framemask";
2057 break;
2058 default:
2059 goto die;
2060 }
8c0fdd85
TS
2061 break;
2062 case 22:
7a387fff
TS
2063 /* ignored */
2064 rn = "'Diagnostic"; /* implementation dependent */
2065 break;
873eb012 2066 case 23:
7a387fff
TS
2067 switch (sel) {
2068 case 0:
2069 gen_op_mfc0_debug(); /* EJTAG support */
2070 rn = "Debug";
2071 break;
2072 case 1:
2073// gen_op_mfc0_tracecontrol(); /* PDtrace support */
2074 rn = "TraceControl";
2075// break;
2076 case 2:
2077// gen_op_mfc0_tracecontrol2(); /* PDtrace support */
2078 rn = "TraceControl2";
2079// break;
2080 case 3:
2081// gen_op_mfc0_usertracedata(); /* PDtrace support */
2082 rn = "UserTraceData";
2083// break;
2084 case 4:
2085// gen_op_mfc0_debug(); /* PDtrace support */
2086 rn = "TraceBPC";
2087// break;
2088 default:
2089 goto die;
2090 }
873eb012
TS
2091 break;
2092 case 24:
7a387fff
TS
2093 switch (sel) {
2094 case 0:
2095 gen_op_mfc0_depc(); /* EJTAG support */
2096 rn = "DEPC";
2097 break;
2098 default:
2099 goto die;
2100 }
873eb012 2101 break;
8c0fdd85 2102 case 25:
7a387fff
TS
2103 switch (sel) {
2104 case 0:
2105 gen_op_mfc0_performance0();
2106 rn = "Performance0";
2107 break;
2108 case 1:
2109// gen_op_mfc0_performance1();
2110 rn = "Performance1";
2111// break;
2112 case 2:
2113// gen_op_mfc0_performance2();
2114 rn = "Performance2";
2115// break;
2116 case 3:
2117// gen_op_mfc0_performance3();
2118 rn = "Performance3";
2119// break;
2120 case 4:
2121// gen_op_mfc0_performance4();
2122 rn = "Performance4";
2123// break;
2124 case 5:
2125// gen_op_mfc0_performance5();
2126 rn = "Performance5";
2127// break;
2128 case 6:
2129// gen_op_mfc0_performance6();
2130 rn = "Performance6";
2131// break;
2132 case 7:
2133// gen_op_mfc0_performance7();
2134 rn = "Performance7";
2135// break;
2136 default:
2137 goto die;
2138 }
8c0fdd85
TS
2139 break;
2140 case 26:
7a387fff
TS
2141 rn = "ECC";
2142 break;
8c0fdd85 2143 case 27:
7a387fff
TS
2144 switch (sel) {
2145 /* ignored */
2146 case 0 ... 3:
2147 rn = "CacheErr";
2148 break;
2149 default:
2150 goto die;
2151 }
8c0fdd85 2152 break;
873eb012
TS
2153 case 28:
2154 switch (sel) {
2155 case 0:
7a387fff
TS
2156 case 2:
2157 case 4:
2158 case 6:
873eb012
TS
2159 gen_op_mfc0_taglo();
2160 rn = "TagLo";
2161 break;
2162 case 1:
7a387fff
TS
2163 case 3:
2164 case 5:
2165 case 7:
873eb012
TS
2166 gen_op_mfc0_datalo();
2167 rn = "DataLo";
2168 break;
2169 default:
873eb012
TS
2170 goto die;
2171 }
2172 break;
8c0fdd85 2173 case 29:
7a387fff
TS
2174 switch (sel) {
2175 case 0:
2176 case 2:
2177 case 4:
2178 case 6:
2179 gen_op_mfc0_taghi();
2180 rn = "TagHi";
2181 break;
2182 case 1:
2183 case 3:
2184 case 5:
2185 case 7:
2186 gen_op_mfc0_datahi();
2187 rn = "DataHi";
2188 break;
2189 default:
2190 goto die;
2191 }
8c0fdd85 2192 break;
873eb012 2193 case 30:
7a387fff
TS
2194 switch (sel) {
2195 case 0:
2196 gen_op_mfc0_errorepc();
2197 rn = "ErrorEPC";
2198 break;
2199 default:
2200 goto die;
2201 }
873eb012
TS
2202 break;
2203 case 31:
7a387fff
TS
2204 switch (sel) {
2205 case 0:
2206 gen_op_mfc0_desave(); /* EJTAG support */
2207 rn = "DESAVE";
2208 break;
2209 default:
2210 goto die;
2211 }
873eb012
TS
2212 break;
2213 default:
873eb012
TS
2214 goto die;
2215 }
2216#if defined MIPS_DEBUG_DISAS
2217 if (loglevel & CPU_LOG_TB_IN_ASM) {
7a387fff
TS
2218 fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
2219 rn, reg, sel);
873eb012
TS
2220 }
2221#endif
2222 return;
2223
2224die:
2225#if defined MIPS_DEBUG_DISAS
2226 if (loglevel & CPU_LOG_TB_IN_ASM) {
7a387fff
TS
2227 fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
2228 rn, reg, sel);
873eb012
TS
2229 }
2230#endif
2231 generate_exception(ctx, EXCP_RI);
2232}
2233
8c0fdd85
TS
2234static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
2235{
7a387fff
TS
2236 const char *rn = "invalid";
2237
8c0fdd85
TS
2238 switch (reg) {
2239 case 0:
7a387fff
TS
2240 switch (sel) {
2241 case 0:
2242 gen_op_mtc0_index();
2243 rn = "Index";
2244 break;
2245 case 1:
2246// gen_op_mtc0_mvpcontrol(); /* MT ASE */
2247 rn = "MVPControl";
2248// break;
2249 case 2:
2250// gen_op_mtc0_mvpconf0(); /* MT ASE */
2251 rn = "MVPConf0";
2252// break;
2253 case 3:
2254// gen_op_mtc0_mvpconf1(); /* MT ASE */
2255 rn = "MVPConf1";
2256// break;
2257 default:
2258 goto die;
2259 }
8c0fdd85
TS
2260 break;
2261 case 1:
7a387fff
TS
2262 switch (sel) {
2263 case 0:
2264 /* ignored */
2265 rn = "Random";
2266 break;
2267 case 1:
2268// gen_op_mtc0_vpecontrol(); /* MT ASE */
2269 rn = "VPEControl";
2270// break;
2271 case 2:
2272// gen_op_mtc0_vpeconf0(); /* MT ASE */
2273 rn = "VPEConf0";
2274// break;
2275 case 3:
2276// gen_op_mtc0_vpeconf1(); /* MT ASE */
2277 rn = "VPEConf1";
2278// break;
2279 case 4:
2280// gen_op_mtc0_YQMask(); /* MT ASE */
2281 rn = "YQMask";
2282// break;
2283 case 5:
2284// gen_op_mtc0_vpeschedule(); /* MT ASE */
2285 rn = "VPESchedule";
2286// break;
2287 case 6:
2288// gen_op_mtc0_vpeschefback(); /* MT ASE */
2289 rn = "VPEScheFBack";
2290// break;
2291 case 7:
2292// gen_op_mtc0_vpeopt(); /* MT ASE */
2293 rn = "VPEOpt";
2294// break;
2295 default:
2296 goto die;
2297 }
8c0fdd85
TS
2298 break;
2299 case 2:
7a387fff
TS
2300 switch (sel) {
2301 case 0:
2302 gen_op_mtc0_entrylo0();
2303 rn = "EntryLo0";
2304 break;
2305 case 1:
2306// gen_op_mtc0_tcstatus(); /* MT ASE */
2307 rn = "TCStatus";
2308// break;
2309 case 2:
2310// gen_op_mtc0_tcbind(); /* MT ASE */
2311 rn = "TCBind";
2312// break;
2313 case 3:
2314// gen_op_mtc0_tcrestart(); /* MT ASE */
2315 rn = "TCRestart";
2316// break;
2317 case 4:
2318// gen_op_mtc0_tchalt(); /* MT ASE */
2319 rn = "TCHalt";
2320// break;
2321 case 5:
2322// gen_op_mtc0_tccontext(); /* MT ASE */
2323 rn = "TCContext";
2324// break;
2325 case 6:
2326// gen_op_mtc0_tcschedule(); /* MT ASE */
2327 rn = "TCSchedule";
2328// break;
2329 case 7:
2330// gen_op_mtc0_tcschefback(); /* MT ASE */
2331 rn = "TCScheFBack";
2332// break;
2333 default:
2334 goto die;
2335 }
8c0fdd85
TS
2336 break;
2337 case 3:
7a387fff
TS
2338 switch (sel) {
2339 case 0:
2340 gen_op_mtc0_entrylo1();
2341 rn = "EntryLo1";
2342 break;
2343 default:
2344 goto die;
2345 }
8c0fdd85
TS
2346 break;
2347 case 4:
7a387fff
TS
2348 switch (sel) {
2349 case 0:
2350 gen_op_mtc0_context();
2351 rn = "Context";
2352 break;
2353 case 1:
2354// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
2355 rn = "ContextConfig";
2356// break;
2357 default:
2358 goto die;
2359 }
8c0fdd85
TS
2360 break;
2361 case 5:
7a387fff
TS
2362 switch (sel) {
2363 case 0:
2364 gen_op_mtc0_pagemask();
2365 rn = "PageMask";
2366 break;
2367 case 1:
2368 gen_op_mtc0_pagegrain();
2369 rn = "PageGrain";
2370 break;
2371 default:
2372 goto die;
2373 }
8c0fdd85
TS
2374 break;
2375 case 6:
7a387fff
TS
2376 switch (sel) {
2377 case 0:
2378 gen_op_mtc0_wired();
2379 rn = "Wired";
2380 break;
2381 case 1:
2382// gen_op_mtc0_srsconf0(); /* shadow registers */
2383 rn = "SRSConf0";
2384// break;
2385 case 2:
2386// gen_op_mtc0_srsconf1(); /* shadow registers */
2387 rn = "SRSConf1";
2388// break;
2389 case 3:
2390// gen_op_mtc0_srsconf2(); /* shadow registers */
2391 rn = "SRSConf2";
2392// break;
2393 case 4:
2394// gen_op_mtc0_srsconf3(); /* shadow registers */
2395 rn = "SRSConf3";
2396// break;
2397 case 5:
2398// gen_op_mtc0_srsconf4(); /* shadow registers */
2399 rn = "SRSConf4";
2400// break;
2401 default:
2402 goto die;
2403 }
8c0fdd85
TS
2404 break;
2405 case 7:
7a387fff
TS
2406 switch (sel) {
2407 case 0:
2408 gen_op_mtc0_hwrena();
2409 rn = "HWREna";
2410 break;
2411 default:
2412 goto die;
2413 }
8c0fdd85
TS
2414 break;
2415 case 8:
7a387fff 2416 /* ignored */
8c0fdd85
TS
2417 rn = "BadVaddr";
2418 break;
2419 case 9:
7a387fff
TS
2420 switch (sel) {
2421 case 0:
2422 gen_op_mtc0_count();
2423 rn = "Count";
2424 break;
2425 /* 6,7 are implementation dependent */
2426 default:
2427 goto die;
2428 }
2429 /* Stop translation as we may have switched the execution mode */
2430 ctx->bstate = BS_STOP;
8c0fdd85
TS
2431 break;
2432 case 10:
7a387fff
TS
2433 switch (sel) {
2434 case 0:
2435 gen_op_mtc0_entryhi();
2436 rn = "EntryHi";
2437 break;
2438 default:
2439 goto die;
2440 }
8c0fdd85
TS
2441 break;
2442 case 11:
7a387fff
TS
2443 switch (sel) {
2444 case 0:
2445 gen_op_mtc0_compare();
2446 rn = "Compare";
2447 break;
2448 /* 6,7 are implementation dependent */
2449 default:
2450 goto die;
2451 }
2452 /* Stop translation as we may have switched the execution mode */
2453 ctx->bstate = BS_STOP;
8c0fdd85
TS
2454 break;
2455 case 12:
7a387fff
TS
2456 switch (sel) {
2457 case 0:
2458 gen_op_mtc0_status();
2459 rn = "Status";
2460 break;
2461 case 1:
2462 gen_op_mtc0_intctl();
2463 rn = "IntCtl";
2464 break;
2465 case 2:
2466 gen_op_mtc0_srsctl();
2467 rn = "SRSCtl";
2468 break;
2469 case 3:
2470// gen_op_mtc0_srsmap(); /* shadow registers */
2471 rn = "SRSMap";
2472// break;
2473 default:
2474 goto die;
2475 }
2476 /* Stop translation as we may have switched the execution mode */
2477 ctx->bstate = BS_STOP;
8c0fdd85
TS
2478 break;
2479 case 13:
7a387fff
TS
2480 switch (sel) {
2481 case 0:
2482 gen_op_mtc0_cause();
2483 rn = "Cause";
2484 break;
2485 default:
2486 goto die;
2487 }
2488 /* Stop translation as we may have switched the execution mode */
2489 ctx->bstate = BS_STOP;
8c0fdd85
TS
2490 break;
2491 case 14:
7a387fff
TS
2492 switch (sel) {
2493 case 0:
2494 gen_op_mtc0_epc();
2495 rn = "EPC";
2496 break;
2497 default:
2498 goto die;
2499 }
8c0fdd85
TS
2500 break;
2501 case 15:
7a387fff
TS
2502 switch (sel) {
2503 case 0:
2504 /* ignored */
2505 rn = "PRid";
2506 break;
2507 case 1:
2508 gen_op_mtc0_ebase();
2509 rn = "EBase";
2510 break;
2511 default:
2512 goto die;
2513 }
8c0fdd85
TS
2514 break;
2515 case 16:
2516 switch (sel) {
2517 case 0:
2518 gen_op_mtc0_config0();
7a387fff
TS
2519 rn = "Config";
2520 break;
2521 case 1:
2522 /* ignored */
2523 rn = "Config1";
2524 break;
2525 case 2:
2526 gen_op_mtc0_config2();
2527 rn = "Config2";
8c0fdd85 2528 break;
7a387fff
TS
2529 case 3:
2530 /* ignored */
2531 rn = "Config3";
2532 break;
2533 /* 6,7 are implementation dependent */
8c0fdd85
TS
2534 default:
2535 rn = "Invalid config selector";
2536 goto die;
2537 }
7a387fff
TS
2538 /* Stop translation as we may have switched the execution mode */
2539 ctx->bstate = BS_STOP;
8c0fdd85
TS
2540 break;
2541 case 17:
7a387fff
TS
2542 switch (sel) {
2543 case 0:
2544 /* ignored */
2545 rn = "LLAddr";
2546 break;
2547 default:
2548 goto die;
2549 }
8c0fdd85
TS
2550 break;
2551 case 18:
7a387fff
TS
2552 switch (sel) {
2553 case 0:
2554 gen_op_mtc0_watchlo0();
2555 rn = "WatchLo";
2556 break;
2557 case 1:
2558// gen_op_mtc0_watchlo1();
2559 rn = "WatchLo1";
2560// break;
2561 case 2:
2562// gen_op_mtc0_watchlo2();
2563 rn = "WatchLo2";
2564// break;
2565 case 3:
2566// gen_op_mtc0_watchlo3();
2567 rn = "WatchLo3";
2568// break;
2569 case 4:
2570// gen_op_mtc0_watchlo4();
2571 rn = "WatchLo4";
2572// break;
2573 case 5:
2574// gen_op_mtc0_watchlo5();
2575 rn = "WatchLo5";
2576// break;
2577 case 6:
2578// gen_op_mtc0_watchlo6();
2579 rn = "WatchLo6";
2580// break;
2581 case 7:
2582// gen_op_mtc0_watchlo7();
2583 rn = "WatchLo7";
2584// break;
2585 default:
2586 goto die;
2587 }
8c0fdd85
TS
2588 break;
2589 case 19:
7a387fff
TS
2590 switch (sel) {
2591 case 0:
2592 gen_op_mtc0_watchhi0();
2593 rn = "WatchHi";
2594 break;
2595 case 1:
2596// gen_op_mtc0_watchhi1();
2597 rn = "WatchHi1";
2598// break;
2599 case 2:
2600// gen_op_mtc0_watchhi2();
2601 rn = "WatchHi2";
2602// break;
2603 case 3:
2604// gen_op_mtc0_watchhi3();
2605 rn = "WatchHi3";
2606// break;
2607 case 4:
2608// gen_op_mtc0_watchhi4();
2609 rn = "WatchHi4";
2610// break;
2611 case 5:
2612// gen_op_mtc0_watchhi5();
2613 rn = "WatchHi5";
2614// break;
2615 case 6:
2616// gen_op_mtc0_watchhi6();
2617 rn = "WatchHi6";
2618// break;
2619 case 7:
2620// gen_op_mtc0_watchhi7();
2621 rn = "WatchHi7";
2622// break;
2623 default:
2624 goto die;
2625 }
8c0fdd85
TS
2626 break;
2627 case 20:
7a387fff
TS
2628 switch (sel) {
2629 case 0:
2630 /* 64 bit MMU only */
2631 gen_op_mtc0_xcontext();
2632 rn = "XContext";
2633 break;
2634 default:
2635 goto die;
2636 }
8c0fdd85
TS
2637 break;
2638 case 21:
7a387fff
TS
2639 /* Officially reserved, but sel 0 is used for R1x000 framemask */
2640 switch (sel) {
2641 case 0:
2642 gen_op_mtc0_framemask();
2643 rn = "Framemask";
2644 break;
2645 default:
2646 goto die;
2647 }
2648 break;
8c0fdd85 2649 case 22:
7a387fff
TS
2650 /* ignored */
2651 rn = "Diagnostic"; /* implementation dependent */
8c0fdd85
TS
2652 break;
2653 case 23:
7a387fff
TS
2654 switch (sel) {
2655 case 0:
2656 gen_op_mtc0_debug(); /* EJTAG support */
2657 rn = "Debug";
2658 break;
2659 case 1:
2660// gen_op_mtc0_tracecontrol(); /* PDtrace support */
2661 rn = "TraceControl";
2662// break;
2663 case 2:
2664// gen_op_mtc0_tracecontrol2(); /* PDtrace support */
2665 rn = "TraceControl2";
2666// break;
2667 case 3:
2668// gen_op_mtc0_usertracedata(); /* PDtrace support */
2669 rn = "UserTraceData";
2670// break;
2671 case 4:
2672// gen_op_mtc0_debug(); /* PDtrace support */
2673 rn = "TraceBPC";
2674// break;
2675 default:
2676 goto die;
2677 }
2678 /* Stop translation as we may have switched the execution mode */
2679 ctx->bstate = BS_STOP;
8c0fdd85
TS
2680 break;
2681 case 24:
7a387fff
TS
2682 switch (sel) {
2683 case 0:
2684 gen_op_mtc0_depc(); /* EJTAG support */
2685 rn = "DEPC";
2686 break;
2687 default:
2688 goto die;
2689 }
8c0fdd85
TS
2690 break;
2691 case 25:
7a387fff
TS
2692 switch (sel) {
2693 case 0:
2694 gen_op_mtc0_performance0();
2695 rn = "Performance0";
2696 break;
2697 case 1:
2698// gen_op_mtc0_performance1();
2699 rn = "Performance1";
2700// break;
2701 case 2:
2702// gen_op_mtc0_performance2();
2703 rn = "Performance2";
2704// break;
2705 case 3:
2706// gen_op_mtc0_performance3();
2707 rn = "Performance3";
2708// break;
2709 case 4:
2710// gen_op_mtc0_performance4();
2711 rn = "Performance4";
2712// break;
2713 case 5:
2714// gen_op_mtc0_performance5();
2715 rn = "Performance5";
2716// break;
2717 case 6:
2718// gen_op_mtc0_performance6();
2719 rn = "Performance6";
2720// break;
2721 case 7:
2722// gen_op_mtc0_performance7();
2723 rn = "Performance7";
2724// break;
2725 default:
2726 goto die;
2727 }
8c0fdd85
TS
2728 break;
2729 case 26:
7a387fff 2730 /* ignored */
8c0fdd85
TS
2731 rn = "ECC";
2732 break;
2733 case 27:
7a387fff
TS
2734 switch (sel) {
2735 case 0 ... 3:
2736 /* ignored */
2737 rn = "CacheErr";
2738 break;
2739 default:
2740 goto die;
2741 }
8c0fdd85
TS
2742 break;
2743 case 28:
2744 switch (sel) {
2745 case 0:
7a387fff
TS
2746 case 2:
2747 case 4:
2748 case 6:
8c0fdd85
TS
2749 gen_op_mtc0_taglo();
2750 rn = "TagLo";
2751 break;
7a387fff
TS
2752 case 1:
2753 case 3:
2754 case 5:
2755 case 7:
2756 gen_op_mtc0_datalo();
2757 rn = "DataLo";
2758 break;
8c0fdd85 2759 default:
8c0fdd85
TS
2760 goto die;
2761 }
2762 break;
2763 case 29:
7a387fff
TS
2764 switch (sel) {
2765 case 0:
2766 case 2:
2767 case 4:
2768 case 6:
2769 gen_op_mtc0_taghi();
2770 rn = "TagHi";
2771 break;
2772 case 1:
2773 case 3:
2774 case 5:
2775 case 7:
2776 gen_op_mtc0_datahi();
2777 rn = "DataHi";
2778 break;
2779 default:
2780 rn = "invalid sel";
2781 goto die;
2782 }
8c0fdd85
TS
2783 break;
2784 case 30:
7a387fff
TS
2785 switch (sel) {
2786 case 0:
2787 gen_op_mtc0_errorepc();
2788 rn = "ErrorEPC";
2789 break;
2790 default:
2791 goto die;
2792 }
8c0fdd85
TS
2793 break;
2794 case 31:
7a387fff
TS
2795 switch (sel) {
2796 case 0:
2797 gen_op_mtc0_desave(); /* EJTAG support */
2798 rn = "DESAVE";
2799 break;
2800 default:
2801 goto die;
2802 }
2803 /* Stop translation as we may have switched the execution mode */
2804 ctx->bstate = BS_STOP;
8c0fdd85
TS
2805 break;
2806 default:
8c0fdd85
TS
2807 goto die;
2808 }
2809#if defined MIPS_DEBUG_DISAS
2810 if (loglevel & CPU_LOG_TB_IN_ASM) {
7a387fff
TS
2811 fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
2812 rn, reg, sel);
8c0fdd85
TS
2813 }
2814#endif
2815 return;
2816
2817die:
2818#if defined MIPS_DEBUG_DISAS
2819 if (loglevel & CPU_LOG_TB_IN_ASM) {
7a387fff
TS
2820 fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
2821 rn, reg, sel);
8c0fdd85
TS
2822 }
2823#endif
2824 generate_exception(ctx, EXCP_RI);
2825}
2826
7a387fff 2827static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
6af0bf9c 2828{
7a387fff 2829 const char *opn = "unk";
6af0bf9c 2830
aa328add
TS
2831 if ((!ctx->CP0_Status & (1 << CP0St_CU0) &&
2832 (ctx->hflags & MIPS_HFLAG_UM)) &&
bc2c3909
FB
2833 !(ctx->hflags & MIPS_HFLAG_ERL) &&
2834 !(ctx->hflags & MIPS_HFLAG_EXL)) {
6af0bf9c
FB
2835 if (loglevel & CPU_LOG_TB_IN_ASM) {
2836 fprintf(logfile, "CP0 is not usable\n");
2837 }
7a387fff 2838 generate_exception (ctx, EXCP_CpU);
6af0bf9c
FB
2839 return;
2840 }
d796321b 2841
6af0bf9c
FB
2842 switch (opc) {
2843 case OPC_MFC0:
2844 if (rt == 0) {
2845 /* Treat as NOP */
2846 return;
2847 }
873eb012 2848 gen_mfc0(ctx, rd, ctx->opcode & 0x7);
6af0bf9c
FB
2849 gen_op_store_T0_gpr(rt);
2850 opn = "mfc0";
2851 break;
2852 case OPC_MTC0:
2853 /* If we get an exception, we want to restart at next instruction */
7a387fff 2854 /* XXX: breaks for mtc in delay slot */
6af0bf9c
FB
2855 ctx->pc += 4;
2856 save_cpu_state(ctx, 1);
2857 ctx->pc -= 4;
2858 GEN_LOAD_REG_TN(T0, rt);
8c0fdd85 2859 gen_mtc0(ctx, rd, ctx->opcode & 0x7);
6af0bf9c
FB
2860 opn = "mtc0";
2861 break;
2862#if defined(MIPS_USES_R4K_TLB)
2863 case OPC_TLBWI:
2864 gen_op_tlbwi();
2865 opn = "tlbwi";
2866 break;
2867 case OPC_TLBWR:
2868 gen_op_tlbwr();
2869 opn = "tlbwr";
2870 break;
2871 case OPC_TLBP:
2872 gen_op_tlbp();
2873 opn = "tlbp";
2874 break;
2875 case OPC_TLBR:
2876 gen_op_tlbr();
2877 opn = "tlbr";
2878 break;
2879#endif
2880 case OPC_ERET:
2881 opn = "eret";
2882 save_cpu_state(ctx, 0);
2883 gen_op_eret();
2884 ctx->bstate = BS_EXCP;
2885 break;
2886 case OPC_DERET:
2887 opn = "deret";
2888 if (!(ctx->hflags & MIPS_HFLAG_DM)) {
2889 generate_exception(ctx, EXCP_RI);
2890 } else {
2891 save_cpu_state(ctx, 0);
2892 gen_op_deret();
2893 ctx->bstate = BS_EXCP;
2894 }
2895 break;
4ad40f36
FB
2896 case OPC_WAIT:
2897 opn = "wait";
2898 /* If we get an exception, we want to restart at next instruction */
2899 ctx->pc += 4;
2900 save_cpu_state(ctx, 1);
2901 ctx->pc -= 4;
2902 gen_op_wait();
2903 ctx->bstate = BS_EXCP;
2904 break;
6af0bf9c
FB
2905 default:
2906 if (loglevel & CPU_LOG_TB_IN_ASM) {
2907 fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
2908 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
2909 ((ctx->opcode >> 16) & 0x1F));
2910 }
2911 generate_exception(ctx, EXCP_RI);
2912 return;
2913 }
2914 MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
2915}
2916
71fb7241
TS
2917#ifdef MIPS_USES_FPU
2918
6ea83fed 2919/* CP1 Branches (before delay slot) */
7a387fff 2920static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
6ea83fed
FB
2921 int32_t offset)
2922{
2923 target_ulong btarget;
2924
2925 btarget = ctx->pc + 4 + offset;
2926
7a387fff
TS
2927 switch (op) {
2928 case OPC_BC1F:
6ea83fed
FB
2929 gen_op_bc1f();
2930 MIPS_DEBUG("bc1f %08x", btarget);
2931 goto not_likely;
7a387fff 2932 case OPC_BC1FL:
6ea83fed
FB
2933 gen_op_bc1f();
2934 MIPS_DEBUG("bc1fl %08x", btarget);
2935 goto likely;
7a387fff 2936 case OPC_BC1T:
6ea83fed
FB
2937 gen_op_bc1t();
2938 MIPS_DEBUG("bc1t %08x", btarget);
2939 not_likely:
2940 ctx->hflags |= MIPS_HFLAG_BC;
2941 break;
7a387fff 2942 case OPC_BC1TL:
6ea83fed
FB
2943 gen_op_bc1t();
2944 MIPS_DEBUG("bc1tl %08x", btarget);
2945 likely:
2946 ctx->hflags |= MIPS_HFLAG_BL;
2947 break;
2948 default:
2949 MIPS_INVAL("cp1 branch/jump");
7a387fff 2950 generate_exception_err (ctx, EXCP_RI, 1);
6ea83fed
FB
2951 return;
2952 }
2953 gen_op_set_bcond();
2954
2955 MIPS_DEBUG("enter ds: cond %02x target %08x",
2956 ctx->hflags, btarget);
2957 ctx->btarget = btarget;
2958
2959 return;
2960}
2961
6af0bf9c 2962/* Coprocessor 1 (FPU) */
7a387fff 2963static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
6ea83fed 2964{
7a387fff 2965 const char *opn = "unk";
6ea83fed
FB
2966
2967 switch (opc) {
2968 case OPC_MFC1:
2969 GEN_LOAD_FREG_FTN(WT0, fs);
2970 gen_op_mfc1();
2971 GEN_STORE_TN_REG(rt, T0);
2972 opn = "mfc1";
2973 break;
2974 case OPC_MTC1:
2975 GEN_LOAD_REG_TN(T0, rt);
2976 gen_op_mtc1();
2977 GEN_STORE_FTN_FREG(fs, WT0);
2978 opn = "mtc1";
2979 break;
2980 case OPC_CFC1:
2981 if (fs != 0 && fs != 31) {
2982 MIPS_INVAL("cfc1 freg");
7a387fff 2983 generate_exception_err (ctx, EXCP_RI, 1);
6ea83fed
FB
2984 return;
2985 }
2986 GEN_LOAD_IMM_TN(T1, fs);
2987 gen_op_cfc1();
2988 GEN_STORE_TN_REG(rt, T0);
2989 opn = "cfc1";
2990 break;
2991 case OPC_CTC1:
7a387fff 2992 if (fs != 0 && fs != 31) {
6ea83fed 2993 MIPS_INVAL("ctc1 freg");
7a387fff 2994 generate_exception_err (ctx, EXCP_RI, 1);
6ea83fed
FB
2995 return;
2996 }
2997 GEN_LOAD_IMM_TN(T1, fs);
2998 GEN_LOAD_REG_TN(T0, rt);
2999 gen_op_ctc1();
3000 opn = "ctc1";
3001 break;
3002 default:
3003 if (loglevel & CPU_LOG_TB_IN_ASM) {
3004 fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
3005 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
3006 ((ctx->opcode >> 16) & 0x1F));
3007 }
7a387fff 3008 generate_exception_err (ctx, EXCP_RI, 1);
6ea83fed
FB
3009 return;
3010 }
3011 MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
3012}
3013
3014/* verify if floating point register is valid; an operation is not defined
3015 * if bit 0 of any register specification is set and the FR bit in the
3016 * Status register equals zero, since the register numbers specify an
3017 * even-odd pair of adjacent coprocessor general registers. When the FR bit
3018 * in the Status register equals one, both even and odd register numbers
3019 * are valid.
3020 *
3021 * Multiple float registers can be checked by calling
3022 * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
3023 */
3024#define CHECK_FR(ctx, freg) do { \
3025 if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
7a387fff 3026 generate_exception_err (ctx, EXCP_RI, 1); \
6ea83fed
FB
3027 return; \
3028 } \
3029 } while(0)
3030
3031#define FOP(func, fmt) (((fmt) << 21) | (func))
3032
7a387fff 3033static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd)
6ea83fed 3034{
7a387fff 3035 const char *opn = "unk";
6ea83fed
FB
3036 const char *condnames[] = {
3037 "c.f",
3038 "c.un",
3039 "c.eq",
3040 "c.ueq",
3041 "c.olt",
3042 "c.ult",
3043 "c.ole",
3044 "c.ule",
3045 "c.sf",
3046 "c.ngle",
3047 "c.seq",
3048 "c.ngl",
3049 "c.lt",
3050 "c.nge",
3051 "c.le",
3052 "c.ngt",
3053 };
3054 int binary = 0;
7a387fff
TS
3055 uint32_t func = ctx->opcode & 0x3f;
3056
6ea83fed
FB
3057 switch (ctx->opcode & FOP(0x3f, 0x1f)) {
3058 case FOP(0, 17):
3059 CHECK_FR(ctx, fs | ft | fd);
3060 GEN_LOAD_FREG_FTN(DT0, fs);
3061 GEN_LOAD_FREG_FTN(DT1, ft);
3062 gen_op_float_add_d();
3063 GEN_STORE_FTN_FREG(fd, DT2);
3064 opn = "add.d";
3065 binary = 1;
3066 break;
3067 case FOP(1, 17):
3068 CHECK_FR(ctx, fs | ft | fd);
3069 GEN_LOAD_FREG_FTN(DT0, fs);
3070 GEN_LOAD_FREG_FTN(DT1, ft);
3071 gen_op_float_sub_d();
3072 GEN_STORE_FTN_FREG(fd, DT2);
3073 opn = "sub.d";
3074 binary = 1;
3075 break;
3076 case FOP(2, 17):
3077 CHECK_FR(ctx, fs | ft | fd);
3078 GEN_LOAD_FREG_FTN(DT0, fs);
3079 GEN_LOAD_FREG_FTN(DT1, ft);
3080 gen_op_float_mul_d();
3081 GEN_STORE_FTN_FREG(fd, DT2);
3082 opn = "mul.d";
3083 binary = 1;
3084 break;
3085 case FOP(3, 17):
3086 CHECK_FR(ctx, fs | ft | fd);
3087 GEN_LOAD_FREG_FTN(DT0, fs);
3088 GEN_LOAD_FREG_FTN(DT1, ft);
3089 gen_op_float_div_d();
3090 GEN_STORE_FTN_FREG(fd, DT2);
3091 opn = "div.d";
3092 binary = 1;
3093 break;
3094 case FOP(4, 17):
3095 CHECK_FR(ctx, fs | fd);
3096 GEN_LOAD_FREG_FTN(DT0, fs);
3097 gen_op_float_sqrt_d();
3098 GEN_STORE_FTN_FREG(fd, DT2);
3099 opn = "sqrt.d";
3100 break;
3101 case FOP(5, 17):
3102 CHECK_FR(ctx, fs | fd);
3103 GEN_LOAD_FREG_FTN(DT0, fs);
3104 gen_op_float_abs_d();
3105 GEN_STORE_FTN_FREG(fd, DT2);
3106 opn = "abs.d";
3107 break;
3108 case FOP(6, 17):
3109 CHECK_FR(ctx, fs | fd);
3110 GEN_LOAD_FREG_FTN(DT0, fs);
3111 gen_op_float_mov_d();
3112 GEN_STORE_FTN_FREG(fd, DT2);
3113 opn = "mov.d";
3114 break;
3115 case FOP(7, 17):
3116 CHECK_FR(ctx, fs | fd);
3117 GEN_LOAD_FREG_FTN(DT0, fs);
3118 gen_op_float_chs_d();
3119 GEN_STORE_FTN_FREG(fd, DT2);
3120 opn = "neg.d";
3121 break;
3122 /* 8 - round.l */
3123 /* 9 - trunc.l */
3124 /* 10 - ceil.l */
3125 /* 11 - floor.l */
3126 case FOP(12, 17):
3127 CHECK_FR(ctx, fs | fd);
3128 GEN_LOAD_FREG_FTN(DT0, fs);
3129 gen_op_float_roundw_d();
3130 GEN_STORE_FTN_FREG(fd, WT2);
3131 opn = "round.w.d";
3132 break;
3133 case FOP(13, 17):
3134 CHECK_FR(ctx, fs | fd);
3135 GEN_LOAD_FREG_FTN(DT0, fs);
3136 gen_op_float_truncw_d();
3137 GEN_STORE_FTN_FREG(fd, WT2);
3138 opn = "trunc.w.d";
3139 break;
3140 case FOP(14, 17):
3141 CHECK_FR(ctx, fs | fd);
3142 GEN_LOAD_FREG_FTN(DT0, fs);
3143 gen_op_float_ceilw_d();
3144 GEN_STORE_FTN_FREG(fd, WT2);
3145 opn = "ceil.w.d";
3146 break;
3147 case FOP(15, 17):
3148 CHECK_FR(ctx, fs | fd);
3149 GEN_LOAD_FREG_FTN(DT0, fs);
3150 gen_op_float_floorw_d();
3151 GEN_STORE_FTN_FREG(fd, WT2);
7a387fff 3152 opn = "floor.w.d";
6ea83fed 3153 break;
dd016883
FB
3154 case FOP(33, 16): /* cvt.d.s */
3155 CHECK_FR(ctx, fs | fd);
3156 GEN_LOAD_FREG_FTN(WT0, fs);
3157 gen_op_float_cvtd_s();
3158 GEN_STORE_FTN_FREG(fd, DT2);
3159 opn = "cvt.d.s";
3160 break;
6ea83fed
FB
3161 case FOP(33, 20): /* cvt.d.w */
3162 CHECK_FR(ctx, fs | fd);
3163 GEN_LOAD_FREG_FTN(WT0, fs);
3164 gen_op_float_cvtd_w();
3165 GEN_STORE_FTN_FREG(fd, DT2);
3166 opn = "cvt.d.w";
3167 break;
3168 case FOP(48, 17):
3169 case FOP(49, 17):
3170 case FOP(50, 17):
3171 case FOP(51, 17):
3172 case FOP(52, 17):
3173 case FOP(53, 17):
3174 case FOP(54, 17):
3175 case FOP(55, 17):
3176 case FOP(56, 17):
3177 case FOP(57, 17):
3178 case FOP(58, 17):
3179 case FOP(59, 17):
3180 case FOP(60, 17):
3181 case FOP(61, 17):
3182 case FOP(62, 17):
3183 case FOP(63, 17):
3184 CHECK_FR(ctx, fs | ft);
3185 GEN_LOAD_FREG_FTN(DT0, fs);
3186 GEN_LOAD_FREG_FTN(DT1, ft);
3187 gen_cmp_d(func-48);
3188 opn = condnames[func-48];
3189 break;
3190 case FOP(0, 16):
3191 CHECK_FR(ctx, fs | ft | fd);
3192 GEN_LOAD_FREG_FTN(WT0, fs);
3193 GEN_LOAD_FREG_FTN(WT1, ft);
3194 gen_op_float_add_s();
3195 GEN_STORE_FTN_FREG(fd, WT2);
3196 opn = "add.s";
3197 binary = 1;
3198 break;
3199 case FOP(1, 16):
3200 CHECK_FR(ctx, fs | ft | fd);
3201 GEN_LOAD_FREG_FTN(WT0, fs);
3202 GEN_LOAD_FREG_FTN(WT1, ft);
3203 gen_op_float_sub_s();
3204 GEN_STORE_FTN_FREG(fd, WT2);
3205 opn = "sub.s";
3206 binary = 1;
3207 break;
3208 case FOP(2, 16):
3209 CHECK_FR(ctx, fs | ft | fd);
3210 GEN_LOAD_FREG_FTN(WT0, fs);
3211 GEN_LOAD_FREG_FTN(WT1, ft);
3212 gen_op_float_mul_s();
3213 GEN_STORE_FTN_FREG(fd, WT2);
3214 opn = "mul.s";
3215 binary = 1;
3216 break;
3217 case FOP(3, 16):
3218 CHECK_FR(ctx, fs | ft | fd);
3219 GEN_LOAD_FREG_FTN(WT0, fs);
3220 GEN_LOAD_FREG_FTN(WT1, ft);
3221 gen_op_float_div_s();
3222 GEN_STORE_FTN_FREG(fd, WT2);
3223 opn = "div.s";
3224 binary = 1;
3225 break;
3226 case FOP(4, 16):
3227 CHECK_FR(ctx, fs | fd);
3228 GEN_LOAD_FREG_FTN(WT0, fs);
3229 gen_op_float_sqrt_s();
3230 GEN_STORE_FTN_FREG(fd, WT2);
3231 opn = "sqrt.s";
3232 break;
3233 case FOP(5, 16):
3234 CHECK_FR(ctx, fs | fd);
3235 GEN_LOAD_FREG_FTN(WT0, fs);
3236 gen_op_float_abs_s();
3237 GEN_STORE_FTN_FREG(fd, WT2);
3238 opn = "abs.s";
3239 break;
3240 case FOP(6, 16):
3241 CHECK_FR(ctx, fs | fd);
3242 GEN_LOAD_FREG_FTN(WT0, fs);
3243 gen_op_float_mov_s();
3244 GEN_STORE_FTN_FREG(fd, WT2);
3245 opn = "mov.s";
3246 break;
3247 case FOP(7, 16):
3248 CHECK_FR(ctx, fs | fd);
3249 GEN_LOAD_FREG_FTN(WT0, fs);
3250 gen_op_float_chs_s();
3251 GEN_STORE_FTN_FREG(fd, WT2);
3252 opn = "neg.s";
3253 break;
3254 case FOP(12, 16):
3255 CHECK_FR(ctx, fs | fd);
3256 GEN_LOAD_FREG_FTN(WT0, fs);
3257 gen_op_float_roundw_s();
3258 GEN_STORE_FTN_FREG(fd, WT2);
3259 opn = "round.w.s";
3260 break;
3261 case FOP(13, 16):
3262 CHECK_FR(ctx, fs | fd);
3263 GEN_LOAD_FREG_FTN(WT0, fs);
3264 gen_op_float_truncw_s();
3265 GEN_STORE_FTN_FREG(fd, WT2);
3266 opn = "trunc.w.s";
3267 break;
dd016883
FB
3268 case FOP(32, 17): /* cvt.s.d */
3269 CHECK_FR(ctx, fs | fd);
417f38f0 3270 GEN_LOAD_FREG_FTN(DT0, fs);
dd016883
FB
3271 gen_op_float_cvts_d();
3272 GEN_STORE_FTN_FREG(fd, WT2);
3273 opn = "cvt.s.d";
3274 break;
6ea83fed
FB
3275 case FOP(32, 20): /* cvt.s.w */
3276 CHECK_FR(ctx, fs | fd);
3277 GEN_LOAD_FREG_FTN(WT0, fs);
3278 gen_op_float_cvts_w();
3279 GEN_STORE_FTN_FREG(fd, WT2);
3280 opn = "cvt.s.w";
3281 break;
3282 case FOP(36, 16): /* cvt.w.s */
3283 CHECK_FR(ctx, fs | fd);
3284 GEN_LOAD_FREG_FTN(WT0, fs);
3285 gen_op_float_cvtw_s();
3286 GEN_STORE_FTN_FREG(fd, WT2);
3287 opn = "cvt.w.s";
3288 break;
3289 case FOP(36, 17): /* cvt.w.d */
3290 CHECK_FR(ctx, fs | fd);
417f38f0 3291 GEN_LOAD_FREG_FTN(DT0, fs);
6ea83fed
FB
3292 gen_op_float_cvtw_d();
3293 GEN_STORE_FTN_FREG(fd, WT2);
3294 opn = "cvt.w.d";
3295 break;
3296 case FOP(48, 16):
3297 case FOP(49, 16):
3298 case FOP(50, 16):
3299 case FOP(51, 16):
3300 case FOP(52, 16):
3301 case FOP(53, 16):
3302 case FOP(54, 16):
3303 case FOP(55, 16):
3304 case FOP(56, 16):
3305 case FOP(57, 16):
3306 case FOP(58, 16):
3307 case FOP(59, 16):
3308 case FOP(60, 16):
3309 case FOP(61, 16):
3310 case FOP(62, 16):
3311 case FOP(63, 16):
3312 CHECK_FR(ctx, fs | ft);
3313 GEN_LOAD_FREG_FTN(WT0, fs);
3314 GEN_LOAD_FREG_FTN(WT1, ft);
3315 gen_cmp_s(func-48);
3316 opn = condnames[func-48];
3317 break;
3318 default:
3319 if (loglevel & CPU_LOG_TB_IN_ASM) {
7a387fff 3320 fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n",
6ea83fed
FB
3321 ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
3322 ((ctx->opcode >> 16) & 0x1F));
3323 }
7a387fff 3324 generate_exception_err (ctx, EXCP_RI, 1);
6ea83fed
FB
3325 return;
3326 }
3327 if (binary)
3328 MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
3329 else
3330 MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
3331}
6af0bf9c 3332
7a387fff
TS
3333static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
3334{
3335 uint32_t ccbit;
3336
3337 if (cc)
3338 ccbit = 1 << (24 + cc);
3339 else
3340 ccbit = 1 << 23;
3341 if (!tf)
3342 gen_op_movf(ccbit, rd, rs);
3343 else
3344 gen_op_movt(ccbit, rd, rs);
3345}
3346
71fb7241
TS
3347#endif /* MIPS_USES_FPU */
3348
7a387fff 3349/* ISA extensions (ASEs) */
6af0bf9c
FB
3350/* MIPS16 extension to MIPS32 */
3351/* SmartMIPS extension to MIPS32 */
3352
7a387fff
TS
3353#ifdef MIPS_HAS_MIPS64
3354static void gen_arith64 (DisasContext *ctx, uint32_t opc)
6af0bf9c
FB
3355{
3356 if (func == 0x02 && rd == 0) {
3357 /* NOP */
3358 return;
3359 }
3360 if (rs == 0 || rt == 0) {
3361 gen_op_reset_T0();
3362 gen_op_save64();
3363 } else {
3364 gen_op_load_gpr_T0(rs);
3365 gen_op_load_gpr_T1(rt);
3366 gen_op_save64();
3367 if (func & 0x01)
3368 gen_op_mul64u();
3369 else
3370 gen_op_mul64s();
3371 }
3372 if (func & 0x02)
3373 gen_op_add64();
3374 else
3375 gen_op_sub64();
3376}
3377
3378/* Coprocessor 3 (FPU) */
3379
3380/* MDMX extension to MIPS64 */
3381/* MIPS-3D extension to MIPS64 */
3382
3383#endif
3384
c53be334
FB
3385static void gen_blikely(DisasContext *ctx)
3386{
eeef26cd
FB
3387 int l1;
3388 l1 = gen_new_label();
3389 gen_op_jnz_T2(l1);
4ad40f36 3390 gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
eeef26cd
FB
3391 gen_goto_tb(ctx, 1, ctx->pc + 4);
3392 gen_set_label(l1);
c53be334
FB
3393}
3394
6af0bf9c
FB
3395static void decode_opc (DisasContext *ctx)
3396{
3397 int32_t offset;
3398 int rs, rt, rd, sa;
7a387fff 3399 uint32_t op, op1, op2;
6af0bf9c
FB
3400 int16_t imm;
3401
d796321b
FB
3402 /* make sure instructions are on a word boundary */
3403 if (ctx->pc & 0x3) {
3404 generate_exception(ctx, EXCP_AdEL);
3405 return;
3406 }
3407
4ad40f36 3408 if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
6af0bf9c
FB
3409 /* Handle blikely not taken case */
3410 MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
c53be334 3411 gen_blikely(ctx);
6af0bf9c 3412 }
7a387fff
TS
3413 op = MASK_OP_MAJOR(ctx->opcode);
3414 rs = (ctx->opcode >> 21) & 0x1f;
3415 rt = (ctx->opcode >> 16) & 0x1f;
3416 rd = (ctx->opcode >> 11) & 0x1f;
3417 sa = (ctx->opcode >> 6) & 0x1f;
6af0bf9c
FB
3418 imm = (int16_t)ctx->opcode;
3419 switch (op) {
7a387fff
TS
3420 case OPC_SPECIAL:
3421 op1 = MASK_SPECIAL(ctx->opcode);
6af0bf9c 3422 switch (op1) {
7a387fff
TS
3423 case OPC_SLL: /* Arithmetic with immediate */
3424 case OPC_SRL ... OPC_SRA:
3425 gen_arith_imm(ctx, op1, rd, rt, sa);
3426 break;
3427 case OPC_SLLV: /* Arithmetic */
3428 case OPC_SRLV ... OPC_SRAV:
3429 case OPC_MOVZ ... OPC_MOVN:
3430 case OPC_ADD ... OPC_NOR:
3431 case OPC_SLT ... OPC_SLTU:
3432 gen_arith(ctx, op1, rd, rs, rt);
3433 break;
3434 case OPC_MULT ... OPC_DIVU:
3435 gen_muldiv(ctx, op1, rs, rt);
3436 break;
3437 case OPC_JR ... OPC_JALR:
3438 gen_compute_branch(ctx, op1, rs, rd, sa);
6af0bf9c 3439 return;
7a387fff
TS
3440 case OPC_TGE ... OPC_TEQ: /* Traps */
3441 case OPC_TNE:
3442 gen_trap(ctx, op1, rs, rt, -1);
6af0bf9c 3443 break;
7a387fff
TS
3444 case OPC_MFHI: /* Move from HI/LO */
3445 case OPC_MFLO:
3446 gen_HILO(ctx, op1, rd);
6af0bf9c 3447 break;
7a387fff
TS
3448 case OPC_MTHI:
3449 case OPC_MTLO: /* Move to HI/LO */
3450 gen_HILO(ctx, op1, rs);
6af0bf9c 3451 break;
7a387fff
TS
3452 case OPC_PMON: /* Pmon entry point */
3453 gen_op_pmon(sa);
3454 break;
3455 case OPC_SYSCALL:
6af0bf9c 3456 generate_exception(ctx, EXCP_SYSCALL);
7a387fff 3457 ctx->bstate = BS_EXCP;
6af0bf9c 3458 break;
7a387fff 3459 case OPC_BREAK:
6af0bf9c
FB
3460 generate_exception(ctx, EXCP_BREAK);
3461 break;
7a387fff
TS
3462 case OPC_SPIM: /* SPIM ? */
3463 /* Implemented as RI exception for now. */
3464 MIPS_INVAL("spim (unofficial)");
3465 generate_exception(ctx, EXCP_RI);
6af0bf9c 3466 break;
7a387fff
TS
3467 case OPC_SYNC:
3468 /* Treat as a noop. */
6af0bf9c 3469 break;
4ad40f36 3470
71fb7241 3471#ifdef MIPS_USES_FPU
7a387fff
TS
3472 case OPC_MOVCI:
3473 gen_op_cp1_enabled();
3474 gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
3475 (ctx->opcode >> 16) & 1);
4ad40f36 3476 break;
71fb7241 3477#endif
4ad40f36 3478
7a387fff
TS
3479#ifdef MIPS_HAS_MIPS64
3480 /* MIPS64 specific opcodes */
3481 case OPC_DSLL:
3482 case OPC_DSRL ... OPC_DSRA:
3483 case OPC_DSLL32:
3484 case OPC_DSRL32 ... OPC_DSRA32:
3485 gen_arith_imm(ctx, op1, rd, rt, sa);
3486 break;
3487 case OPC_DSLLV:
3488 case OPC_DSRLV ... OPC_DSRAV:
3489 case OPC_DADD ... OPC_DSUBU:
3490 gen_arith(ctx, op1, rd, rs, rt);
3491 break;
3492 case OPC_DMULT ... OPC_DDIVU:
3493 gen_muldiv(ctx, op1, rs, rt);
3494 break;
6af0bf9c
FB
3495#endif
3496 default: /* Invalid */
3497 MIPS_INVAL("special");
3498 generate_exception(ctx, EXCP_RI);
3499 break;
3500 }
3501 break;
7a387fff
TS
3502 case OPC_SPECIAL2:
3503 op1 = MASK_SPECIAL2(ctx->opcode);
6af0bf9c 3504 switch (op1) {
7a387fff
TS
3505 case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
3506 case OPC_MSUB ... OPC_MSUBU:
3507 gen_muldiv(ctx, op1, rs, rt);
6af0bf9c 3508 break;
7a387fff
TS
3509 case OPC_MUL:
3510 gen_arith(ctx, op1, rd, rs, rt);
6af0bf9c 3511 break;
7a387fff
TS
3512 case OPC_CLZ ... OPC_CLO:
3513 gen_cl(ctx, op1, rd, rs);
6af0bf9c 3514 break;
7a387fff 3515 case OPC_SDBBP:
6af0bf9c
FB
3516 /* XXX: not clear which exception should be raised
3517 * when in debug mode...
3518 */
3519 if (!(ctx->hflags & MIPS_HFLAG_DM)) {
3520 generate_exception(ctx, EXCP_DBp);
3521 } else {
3522 generate_exception(ctx, EXCP_DBp);
3523 }
3524 /* Treat as a noop */
3525 break;
7a387fff
TS
3526#ifdef MIPS_HAS_MIPS64
3527 case OPC_DCLZ ... OPC_DCLO:
3528 gen_cl(ctx, op1, rd, rs);
3529 break;
3530#endif
6af0bf9c
FB
3531 default: /* Invalid */
3532 MIPS_INVAL("special2");
3533 generate_exception(ctx, EXCP_RI);
3534 break;
3535 }
3536 break;
7a387fff
TS
3537 case OPC_SPECIAL3:
3538 op1 = MASK_SPECIAL3(ctx->opcode);
6af0bf9c 3539 switch (op1) {
7a387fff
TS
3540 case OPC_EXT:
3541 case OPC_INS:
3542 gen_bitops(ctx, op1, rt, rs, sa, rd);
3543 break;
3544 case OPC_BSHFL:
3545 op2 = MASK_BSHFL(ctx->opcode);
3546 switch (op2) {
3547 case OPC_WSBH:
3548 GEN_LOAD_REG_TN(T1, rt);
3549 gen_op_wsbh();
3550 break;
3551 case OPC_SEB:
3552 GEN_LOAD_REG_TN(T1, rt);
3553 gen_op_seb();
3554 break;
3555 case OPC_SEH:
3556 GEN_LOAD_REG_TN(T1, rt);
3557 gen_op_seh();
3558 break;
3559 default: /* Invalid */
3560 MIPS_INVAL("bshfl");
3561 generate_exception(ctx, EXCP_RI);
3562 break;
3563 }
3564 GEN_STORE_TN_REG(rd, T0);
3565 break;
3566 case OPC_RDHWR:
3567 switch (rd) {
3568 case 0:
3569 gen_op_rdhwr_cpunum();
3570 break;
3571 case 1:
3572 gen_op_rdhwr_synci_step();
3573 break;
3574 case 2:
3575 gen_op_rdhwr_cc();
3576 break;
3577 case 3:
3578 gen_op_rdhwr_ccres();
3579 break;
3580 default: /* Invalid */
3581 MIPS_INVAL("rdhwr");
3582 generate_exception(ctx, EXCP_RI);
3583 break;
3584 }
3585 GEN_STORE_TN_REG(rt, T0);
3586 break;
3587#ifdef MIPS_HAS_MIPS64
3588 case OPC_DEXTM ... OPC_DEXT:
3589 case OPC_DINSM ... OPC_DINS:
3590 gen_bitops(ctx, op1, rt, rs, sa, rd);
3591 break;
3592 case OPC_DBSHFL:
3593 op2 = MASK_DBSHFL(ctx->opcode);
3594 switch (op2) {
3595 case OPC_DSBH:
3596 GEN_LOAD_REG_TN(T1, rt);
3597 gen_op_dsbh();
3598 break;
3599 case OPC_DSHD:
3600 GEN_LOAD_REG_TN(T1, rt);
3601 gen_op_dshd();
3602 break;
3603 default: /* Invalid */
3604 MIPS_INVAL("dbshfl");
3605 generate_exception(ctx, EXCP_RI);
3606 break;
3607 }
3608 GEN_STORE_TN_REG(rd, T0);
3609#endif
3610 default: /* Invalid */
3611 MIPS_INVAL("special3");
3612 generate_exception(ctx, EXCP_RI);
3613 break;
3614 }
3615 break;
3616 case OPC_REGIMM:
3617 op1 = MASK_REGIMM(ctx->opcode);
3618 switch (op1) {
3619 case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
3620 case OPC_BLTZAL ... OPC_BGEZALL:
3621 gen_compute_branch(ctx, op1, rs, -1, imm << 2);
6af0bf9c 3622 return;
7a387fff
TS
3623 case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
3624 case OPC_TNEI:
3625 gen_trap(ctx, op1, rs, -1, imm);
3626 break;
3627 case OPC_SYNCI:
3628 /* treat as noop */
6af0bf9c
FB
3629 break;
3630 default: /* Invalid */
3631 MIPS_INVAL("REGIMM");
3632 generate_exception(ctx, EXCP_RI);
3633 break;
3634 }
3635 break;
7a387fff
TS
3636 case OPC_CP0:
3637 op1 = MASK_CP0(ctx->opcode);
6af0bf9c 3638 switch (op1) {
7a387fff
TS
3639 case OPC_MFC0:
3640 case OPC_MTC0:
3641#ifdef MIPS_HAS_MIPS64
3642 case OPC_DMFC0:
3643 case OPC_DMTC0:
3644#endif
3645 gen_cp0(ctx, op1, rt, rd);
3646 break;
3647 case OPC_C0_FIRST ... OPC_C0_LAST:
3648 gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd);
3649 break;
3650 case OPC_MFMC0:
3651 op2 = MASK_MFMC0(ctx->opcode);
3652 switch (op2) {
3653 case OPC_DI:
3654 gen_op_di();
3655 /* Stop translation as we may have switched the execution mode */
3656 ctx->bstate = BS_STOP;
3657 break;
3658 case OPC_EI:
3659 gen_op_ei();
3660 /* Stop translation as we may have switched the execution mode */
3661 ctx->bstate = BS_STOP;
3662 break;
3663 default: /* Invalid */
3664 MIPS_INVAL("MFMC0");
3665 generate_exception(ctx, EXCP_RI);
3666 break;
3667 }
3668 GEN_STORE_TN_REG(rt, T0);
6af0bf9c 3669 break;
7a387fff
TS
3670 /* Shadow registers (not implemented). */
3671 case OPC_RDPGPR:
3672 case OPC_WRPGPR:
6af0bf9c 3673 default:
7a387fff 3674 generate_exception(ctx, EXCP_RI);
6af0bf9c
FB
3675 break;
3676 }
3677 break;
7a387fff
TS
3678 case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
3679 gen_arith_imm(ctx, op, rt, rs, imm);
3680 break;
3681 case OPC_J ... OPC_JAL: /* Jump */
3682 offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
3683 gen_compute_branch(ctx, op, rs, rt, offset);
3684 return;
3685 case OPC_BEQ ... OPC_BGTZ: /* Branch */
3686 case OPC_BEQL ... OPC_BGTZL:
3687 gen_compute_branch(ctx, op, rs, rt, imm << 2);
3688 return;
3689 case OPC_LB ... OPC_LWR: /* Load and stores */
3690 case OPC_SB ... OPC_SW:
3691 case OPC_SWR:
3692 case OPC_LL:
3693 case OPC_SC:
3694 gen_ldst(ctx, op, rt, rs, imm);
3695 break;
3696 case OPC_CACHE:
3697 /* Treat as a noop */
3698 break;
3699 case OPC_PREF:
6af0bf9c
FB
3700 /* Treat as a noop */
3701 break;
4ad40f36
FB
3702
3703 /* Floating point. */
7a387fff
TS
3704 case OPC_LWC1:
3705 case OPC_LDC1:
3706 case OPC_SWC1:
3707 case OPC_SDC1:
6ea83fed 3708#if defined(MIPS_USES_FPU)
417f38f0 3709 save_cpu_state(ctx, 1);
6ea83fed
FB
3710 gen_op_cp1_enabled();
3711 gen_flt_ldst(ctx, op, rt, rs, imm);
3712#else
3713 generate_exception_err(ctx, EXCP_CpU, 1);
3714#endif
3715 break;
3716
7a387fff 3717 case OPC_CP1:
6af0bf9c 3718#if defined(MIPS_USES_FPU)
417f38f0 3719 save_cpu_state(ctx, 1);
6ea83fed 3720 gen_op_cp1_enabled();
7a387fff 3721 op1 = MASK_CP1(ctx->opcode);
6ea83fed 3722 switch (op1) {
7a387fff
TS
3723 case OPC_MFC1:
3724 case OPC_CFC1:
3725 case OPC_MTC1:
3726 case OPC_CTC1:
3727 gen_cp1(ctx, op1, rt, rd);
3728 break;
3729 case OPC_BC1:
3730 gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2);
6ea83fed 3731 return;
7a387fff
TS
3732 case OPC_S_FMT:
3733 case OPC_D_FMT:
3734 case OPC_W_FMT:
3735 case OPC_L_FMT:
3736 gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa);
6ea83fed
FB
3737 break;
3738 default:
3739 generate_exception_err(ctx, EXCP_RI, 1);
3740 break;
3741 }
4ad40f36
FB
3742#else
3743 generate_exception_err(ctx, EXCP_CpU, 1);
6af0bf9c 3744#endif
4ad40f36
FB
3745 break;
3746
3747 /* COP2. */
7a387fff
TS
3748 case OPC_LWC2:
3749 case OPC_LDC2:
3750 case OPC_SWC2:
3751 case OPC_SDC2:
3752 case OPC_CP2:
3753 /* COP2: Not implemented. */
4ad40f36
FB
3754 generate_exception_err(ctx, EXCP_CpU, 2);
3755 break;
3756
71fb7241 3757#ifdef MIPS_USES_FPU
7a387fff
TS
3758 case OPC_CP3:
3759 gen_op_cp1_enabled();
3760 op1 = MASK_CP3(ctx->opcode);
3761 switch (op1) {
6af0bf9c 3762 /* Not implemented */
7a387fff
TS
3763 default:
3764 generate_exception_err(ctx, EXCP_RI, 1);
3765 break;
3766 }
4ad40f36 3767 break;
71fb7241 3768#endif
4ad40f36 3769
7a387fff
TS
3770#ifdef MIPS_HAS_MIPS64
3771 /* MIPS64 opcodes */
3772 case OPC_LWU:
3773 case OPC_LDL ... OPC_LDR:
3774 case OPC_SDL ... OPC_SDR:
3775 case OPC_LLD:
3776 case OPC_LD:
3777 case OPC_SCD:
3778 case OPC_SD:
3779 gen_ldst(ctx, op, rt, rs, imm);
3780 break;
3781 case OPC_DADDI ... OPC_DADDIU:
3782 gen_arith_imm(ctx, op, rt, rs, imm);
3783 break;
6af0bf9c 3784#endif
7a387fff
TS
3785#ifdef MIPS_HAS_MIPS16
3786 case OPC_JALX:
3787 /* MIPS16: Not implemented. */
3788#endif
3789#ifdef MIPS_HAS_MDMX
3790 case OPC_MDMX:
3791 /* MDMX: Not implemented. */
6af0bf9c 3792#endif
6af0bf9c
FB
3793 default: /* Invalid */
3794 MIPS_INVAL("");
3795 generate_exception(ctx, EXCP_RI);
3796 break;
3797 }
4ad40f36 3798 if (ctx->hflags & MIPS_HFLAG_BMASK) {
6af0bf9c
FB
3799 int hflags = ctx->hflags;
3800 /* Branches completion */
4ad40f36 3801 ctx->hflags &= ~MIPS_HFLAG_BMASK;
6af0bf9c
FB
3802 ctx->bstate = BS_BRANCH;
3803 save_cpu_state(ctx, 0);
3804 switch (hflags & MIPS_HFLAG_BMASK) {
3805 case MIPS_HFLAG_B:
3806 /* unconditional branch */
3807 MIPS_DEBUG("unconditional branch");
6e256c93 3808 gen_goto_tb(ctx, 0, ctx->btarget);
6af0bf9c
FB
3809 break;
3810 case MIPS_HFLAG_BL:
3811 /* blikely taken case */
3812 MIPS_DEBUG("blikely branch taken");
6e256c93 3813 gen_goto_tb(ctx, 0, ctx->btarget);
6af0bf9c
FB
3814 break;
3815 case MIPS_HFLAG_BC:
3816 /* Conditional branch */
3817 MIPS_DEBUG("conditional branch");
c53be334
FB
3818 {
3819 int l1;
3820 l1 = gen_new_label();
3821 gen_op_jnz_T2(l1);
6e256c93 3822 gen_goto_tb(ctx, 1, ctx->pc + 4);
eeef26cd
FB
3823 gen_set_label(l1);
3824 gen_goto_tb(ctx, 0, ctx->btarget);
c53be334 3825 }
6af0bf9c
FB
3826 break;
3827 case MIPS_HFLAG_BR:
3828 /* unconditional branch to register */
3829 MIPS_DEBUG("branch to register");
3830 gen_op_breg();
3831 break;
3832 default:
3833 MIPS_DEBUG("unknown branch");
3834 break;
3835 }
3836 }
3837}
3838
3839int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
3840 int search_pc)
3841{
3842 DisasContext ctx, *ctxp = &ctx;
3843 target_ulong pc_start;
3844 uint16_t *gen_opc_end;
3845 int j, lj = -1;
3846
4ad40f36 3847 if (search_pc && loglevel)
6ea83fed 3848 fprintf (logfile, "search pc %d\n", search_pc);
4ad40f36 3849
6af0bf9c
FB
3850 pc_start = tb->pc;
3851 gen_opc_ptr = gen_opc_buf;
3852 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3853 gen_opparam_ptr = gen_opparam_buf;
c53be334 3854 nb_gen_labels = 0;
6af0bf9c 3855 ctx.pc = pc_start;
4ad40f36 3856 ctx.saved_pc = -1;
6af0bf9c
FB
3857 ctx.tb = tb;
3858 ctx.bstate = BS_NONE;
4ad40f36
FB
3859 /* Restore delay slot state from the tb context. */
3860 ctx.hflags = tb->flags;
6af0bf9c
FB
3861 ctx.saved_hflags = ctx.hflags;
3862 if (ctx.hflags & MIPS_HFLAG_BR) {
3863 gen_op_restore_breg_target();
3864 } else if (ctx.hflags & MIPS_HFLAG_B) {
3865 ctx.btarget = env->btarget;
3866 } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
3867 /* If we are in the delay slot of a conditional branch,
3868 * restore the branch condition from env->bcond to T2
3869 */
3870 ctx.btarget = env->btarget;
3871 gen_op_restore_bcond();
3872 }
3873#if defined(CONFIG_USER_ONLY)
3874 ctx.mem_idx = 0;
3875#else
3d9fb9fe 3876 ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
6af0bf9c
FB
3877#endif
3878 ctx.CP0_Status = env->CP0_Status;
3879#ifdef DEBUG_DISAS
3880 if (loglevel & CPU_LOG_TB_CPU) {
3881 fprintf(logfile, "------------------------------------------------\n");
4ad40f36 3882 /* FIXME: This may print out stale hflags from env... */
6af0bf9c
FB
3883 cpu_dump_state(env, logfile, fprintf, 0);
3884 }
3885#endif
3886#if defined MIPS_DEBUG_DISAS
3887 if (loglevel & CPU_LOG_TB_IN_ASM)
4ad40f36
FB
3888 fprintf(logfile, "\ntb %p super %d cond %04x\n",
3889 tb, ctx.mem_idx, ctx.hflags);
6af0bf9c
FB
3890#endif
3891 while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
4ad40f36
FB
3892 if (env->nb_breakpoints > 0) {
3893 for(j = 0; j < env->nb_breakpoints; j++) {
3894 if (env->breakpoints[j] == ctx.pc) {
3895 save_cpu_state(ctxp, 1);
3896 ctx.bstate = BS_BRANCH;
3897 gen_op_debug();
3898 goto done_generating;
3899 }
3900 }
3901 }
3902
6af0bf9c
FB
3903 if (search_pc) {
3904 j = gen_opc_ptr - gen_opc_buf;
6af0bf9c
FB
3905 if (lj < j) {
3906 lj++;
3907 while (lj < j)
3908 gen_opc_instr_start[lj++] = 0;
6af0bf9c 3909 }
4ad40f36
FB
3910 gen_opc_pc[lj] = ctx.pc;
3911 gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
3912 gen_opc_instr_start[lj] = 1;
6af0bf9c
FB
3913 }
3914 ctx.opcode = ldl_code(ctx.pc);
3915 decode_opc(&ctx);
3916 ctx.pc += 4;
4ad40f36
FB
3917
3918 if (env->singlestep_enabled)
3919 break;
3920
6af0bf9c
FB
3921 if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
3922 break;
4ad40f36 3923
6af0bf9c
FB
3924#if defined (MIPS_SINGLE_STEP)
3925 break;
3926#endif
3927 }
4ad40f36
FB
3928 if (env->singlestep_enabled) {
3929 save_cpu_state(ctxp, ctx.bstate == BS_NONE);
3930 gen_op_debug();
3931 goto done_generating;
3932 }
3933 else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
6af0bf9c 3934 save_cpu_state(ctxp, 0);
6e256c93 3935 gen_goto_tb(&ctx, 0, ctx.pc);
6af0bf9c
FB
3936 }
3937 gen_op_reset_T0();
3938 /* Generate the return instruction */
3939 gen_op_exit_tb();
4ad40f36 3940done_generating:
6af0bf9c
FB
3941 *gen_opc_ptr = INDEX_op_end;
3942 if (search_pc) {
3943 j = gen_opc_ptr - gen_opc_buf;
3944 lj++;
3945 while (lj <= j)
3946 gen_opc_instr_start[lj++] = 0;
3947 tb->size = 0;
3948 } else {
3949 tb->size = ctx.pc - pc_start;
3950 }
3951#ifdef DEBUG_DISAS
3952#if defined MIPS_DEBUG_DISAS
3953 if (loglevel & CPU_LOG_TB_IN_ASM)
3954 fprintf(logfile, "\n");
3955#endif
3956 if (loglevel & CPU_LOG_TB_IN_ASM) {
3957 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
6ea83fed 3958 target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
6af0bf9c
FB
3959 fprintf(logfile, "\n");
3960 }
3961 if (loglevel & CPU_LOG_TB_OP) {
3962 fprintf(logfile, "OP:\n");
3963 dump_ops(gen_opc_buf, gen_opparam_buf);
3964 fprintf(logfile, "\n");
3965 }
3966 if (loglevel & CPU_LOG_TB_CPU) {
3967 fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
3968 }
3969#endif
3970
3971 return 0;
3972}
3973
3974int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
3975{
3976 return gen_intermediate_code_internal(env, tb, 0);
3977}
3978
3979int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
3980{
3981 return gen_intermediate_code_internal(env, tb, 1);
3982}
3983
71fb7241
TS
3984#ifdef MIPS_USES_FPU
3985
6ea83fed
FB
3986void fpu_dump_state(CPUState *env, FILE *f,
3987 int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
3988 int flags)
3989{
3990 int i;
3991
3992# define printfpr(fp) do { \
3993 fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
3994 (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
3995 } while(0)
3996
3997 fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n",
3998 env->fcr0, env->fcr31,
7a387fff 3999 (env->CP0_Status & (1 << CP0St_FR)) != 0);
6ea83fed
FB
4000 fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
4001 fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
4002 fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
7a387fff
TS
4003 for(i = 0; i < 32; i += 2) {
4004 fpu_fprintf(f, "%s: ", fregnames[i]);
6ea83fed
FB
4005 printfpr(FPR(env, i));
4006 }
4007
4008#undef printfpr
4009}
4010
7a387fff 4011void dump_fpu (CPUState *env)
6ea83fed
FB
4012{
4013 if (loglevel) {
4014 fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
4015 env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
4016 fpu_dump_state(env, logfile, fprintf, 0);
4017 }
4018}
6ea83fed 4019
71fb7241
TS
4020#endif /* MIPS_USES_FPU */
4021
6af0bf9c
FB
4022void cpu_dump_state (CPUState *env, FILE *f,
4023 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
4024 int flags)
4025{
568b600d 4026 uint32_t c0_status;
6af0bf9c
FB
4027 int i;
4028
4029 cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
4030 env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
4031 for (i = 0; i < 32; i++) {
4032 if ((i & 3) == 0)
4033 cpu_fprintf(f, "GPR%02d:", i);
4034 cpu_fprintf(f, " %s %08x", regnames[i], env->gpr[i]);
4035 if ((i & 3) == 3)
4036 cpu_fprintf(f, "\n");
4037 }
568b600d
FB
4038
4039 c0_status = env->CP0_Status;
4040 if (env->hflags & MIPS_HFLAG_UM)
4041 c0_status |= (1 << CP0St_UM);
4042 if (env->hflags & MIPS_HFLAG_ERL)
4043 c0_status |= (1 << CP0St_ERL);
4044 if (env->hflags & MIPS_HFLAG_EXL)
4045 c0_status |= (1 << CP0St_EXL);
4046
6af0bf9c 4047 cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x%08x\n",
568b600d 4048 c0_status, env->CP0_Cause, env->CP0_EPC);
6af0bf9c
FB
4049 cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
4050 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
71fb7241 4051#ifdef MIPS_USES_FPU
7a387fff
TS
4052 if (c0_status & (1 << CP0St_CU1))
4053 fpu_dump_state(env, f, cpu_fprintf, flags);
71fb7241 4054#endif
6af0bf9c
FB
4055}
4056
4057CPUMIPSState *cpu_mips_init (void)
4058{
4059 CPUMIPSState *env;
4060
6af0bf9c
FB
4061 env = qemu_mallocz(sizeof(CPUMIPSState));
4062 if (!env)
4063 return NULL;
173d6cfe 4064 cpu_exec_init(env);
6ae81775
TS
4065 cpu_reset(env);
4066 return env;
4067}
4068
4069void cpu_reset (CPUMIPSState *env)
4070{
4071 memset(env, 0, offsetof(CPUMIPSState, breakpoints));
4072
6af0bf9c 4073 tlb_flush(env, 1);
6ae81775 4074
6af0bf9c 4075 /* Minimal init */
ca7c2b1b 4076#if !defined(CONFIG_USER_ONLY)
aa328add
TS
4077 if (env->hflags & MIPS_HFLAG_BMASK) {
4078 /* If the exception was raised from a delay slot,
4079 * come back to the jump. */
4080 env->CP0_ErrorEPC = env->PC - 4;
4081 env->hflags &= ~MIPS_HFLAG_BMASK;
4082 } else {
4083 env->CP0_ErrorEPC = env->PC;
4084 }
6af0bf9c
FB
4085 env->PC = 0xBFC00000;
4086#if defined (MIPS_USES_R4K_TLB)
4087 env->CP0_random = MIPS_TLB_NB - 1;
814b9a47 4088 env->tlb_in_use = MIPS_TLB_NB;
6af0bf9c
FB
4089#endif
4090 env->CP0_Wired = 0;
7a387fff
TS
4091 /* SMP not implemented */
4092 env->CP0_EBase = 0x80000000;
6af0bf9c 4093 env->CP0_Config0 = MIPS_CONFIG0;
7a387fff
TS
4094 env->CP0_Config1 = MIPS_CONFIG1;
4095 env->CP0_Config2 = MIPS_CONFIG2;
4096 env->CP0_Config3 = MIPS_CONFIG3;
aa328add 4097 env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
6af0bf9c
FB
4098 env->CP0_WatchLo = 0;
4099 env->hflags = MIPS_HFLAG_ERL;
4100 /* Count register increments in debug mode, EJTAG version 1 */
4101 env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
4102 env->CP0_PRid = MIPS_CPU;
ca7c2b1b 4103#endif
6af0bf9c 4104 env->exception_index = EXCP_NONE;
eeef26cd
FB
4105#if defined(CONFIG_USER_ONLY)
4106 env->hflags |= MIPS_HFLAG_UM;
ca7c2b1b 4107 env->user_mode_only = 1;
6ea83fed
FB
4108#endif
4109#ifdef MIPS_USES_FPU
4110 env->fcr0 = MIPS_FCR0;
eeef26cd 4111#endif
7a387fff
TS
4112 /* XXX some guesswork here, values are CPU specific */
4113 env->SYNCI_Step = 16;
4114 env->CCRes = 2;
6af0bf9c 4115}