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