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