1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     mips3drc.c
6 
7     Universal machine language-based MIPS III/IV emulator.
8 
9 ****************************************************************************
10 
11     Future improvements/changes:
12 
13     * Add DRC option to flush PC before calling memory handlers
14 
15     * Constant tracking? (hasn't bought us much in the past)
16 
17     * Customized mapped/unmapped memory handlers
18         - create 3 sets of handlers: cached, uncached, general
19         - default to general
20         - in general case, if cached use RECALL to point to cached code
21         - (same for uncached)
22         - in cached/uncached case, fall back to general case
23 
24 ***************************************************************************/
25 
26 #include "emu.h"
27 #include "debugger.h"
28 #include "mips3com.h"
29 #include "mips3fe.h"
30 #include "mips3dsm.h"
31 #include "ps2vu.h"
32 #include "cpu/drcfe.h"
33 #include "cpu/drcuml.h"
34 #include "cpu/drcumlsh.h"
35 
36 
37 /***************************************************************************
38     MACROS
39 ***************************************************************************/
40 
41 #define IS_FR0      ((m_core->mode & 1) == 0)
42 #define IS_FR1      ((m_core->mode & 1) != 0)
43 
44 #define R32(reg)                m_regmaplo[reg]
45 #define LO32                    R32(REG_LO)
46 #define HI32                    R32(REG_HI)
47 #define CPR032(reg)             uml::mem(LOPTR(&m_core->cpr[0][reg]))
48 #define CCR032(reg)             uml::mem(LOPTR(&m_core->ccr[0][reg]))
49 #define FPR32(reg)              uml::mem((IS_FR0) ? &((float *)&m_core->cpr[1][reg & 0x1E])[BYTE_XOR_LE(reg & 1)] : (float *)&m_core->cpr[1][reg])
50 #define CCR132(reg)             uml::mem(LOPTR(&m_core->ccr[1][reg]))
51 #define CPR232(reg)             uml::mem(LOPTR(&m_core->cpr[2][reg]))
52 #define CCR232(reg)             uml::mem(LOPTR(&m_core->ccr[2][reg]))
53 
54 #define R64(reg)                m_regmap[reg]
55 #define LO64                    R64(REG_LO)
56 #define HI64                    R64(REG_HI)
57 #define CPR064(reg)             uml::mem(&m_core->cpr[0][reg])
58 #define CCR064(reg)             uml::mem(&m_core->ccr[0][reg])
59 #define FPR64(reg)              uml::mem((IS_FR0) ? (double *)&m_core->cpr[1][reg & 0x1E] : (double *)&m_core->cpr[1][reg])
60 #define CCR164(reg)             uml::mem(&m_core->ccr[1][reg])
61 #define CPR264(reg)             uml::mem(&m_core->cpr[2][reg])
62 #define CCR264(reg)             uml::mem(&m_core->ccr[2][reg])
63 
64 #define FCCSHIFT(which)         fcc_shift[(m_flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)]
65 #define FCCMASK(which)          (uint32_t(1 << FCCSHIFT(which)))
66 
67 
68 
69 /***************************************************************************
70     FUNCTION PROTOTYPES
71 ***************************************************************************/
72 
73 static void cfunc_printf_exception(void *param);
74 static void cfunc_get_cycles(void *param);
75 static void cfunc_printf_probe(void *param);
76 static void cfunc_debug_break(void *param);
77 
78 
79 /***************************************************************************
80     PRIVATE GLOBAL VARIABLES
81 ***************************************************************************/
82 
83 /* bit indexes for various FCCs */
84 static const uint8_t fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 };
85 
86 
87 /***************************************************************************
88     INLINE FUNCTIONS
89 ***************************************************************************/
90 
91 /*-------------------------------------------------
92     epc - compute the exception PC from a
93     descriptor
94 -------------------------------------------------*/
95 
epc(const opcode_desc * desc)96 static inline uint32_t epc(const opcode_desc *desc)
97 {
98 	return (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc;
99 }
100 
101 
102 /*-------------------------------------------------
103     alloc_handle - allocate a handle if not
104     already allocated
105 -------------------------------------------------*/
106 
alloc_handle(drcuml_state & drcuml,uml::code_handle * & handleptr,const char * name)107 static inline void alloc_handle(drcuml_state &drcuml, uml::code_handle *&handleptr, const char *name)
108 {
109 	if (!handleptr)
110 		handleptr = drcuml.handle_alloc(name);
111 }
112 
113 
114 /*-------------------------------------------------
115     load_fast_iregs - load any fast integer
116     registers
117 -------------------------------------------------*/
118 
load_fast_iregs(drcuml_block & block)119 inline void mips3_device::load_fast_iregs(drcuml_block &block)
120 {
121 	int regnum;
122 
123 	for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
124 		if (m_regmap[regnum].is_int_register())
125 			UML_DMOV(block, ireg(m_regmap[regnum].ireg() - REG_I0), mem(&m_core->r[regnum]));
126 }
127 
128 
129 /*-------------------------------------------------
130     save_fast_iregs - save any fast integer
131     registers
132 -------------------------------------------------*/
133 
save_fast_iregs(drcuml_block & block)134 inline void mips3_device::save_fast_iregs(drcuml_block &block)
135 {
136 	int regnum;
137 
138 	for (regnum = 0; regnum < ARRAY_LENGTH(m_regmap); regnum++)
139 		if (m_regmap[regnum].is_int_register())
140 			UML_DMOV(block, mem(&m_core->r[regnum]), ireg(m_regmap[regnum].ireg() - REG_I0));
141 }
142 
143 
144 
145 /***************************************************************************
146     CORE CALLBACKS
147 ***************************************************************************/
148 
149 /*-------------------------------------------------
150     mips3drc_set_options - configure DRC options
151 -------------------------------------------------*/
152 
mips3drc_set_options(uint32_t options)153 void mips3_device::mips3drc_set_options(uint32_t options)
154 {
155 	if (!allow_drc()) return;
156 	m_drcoptions = options;
157 }
158 
159 /*-------------------------------------------------
160     mips3drc_clears_fastram - clears fastram
161     region starting at index select_start
162 -------------------------------------------------*/
clear_fastram(uint32_t select_start)163 void mips3_device::clear_fastram(uint32_t select_start)
164 {
165 	m_fastram_select=select_start;
166 	// Set cache to dirty so that re-mapping occurs
167 	m_drc_cache_dirty = true;
168 }
169 
170 /*-------------------------------------------------
171     mips3drc_add_fastram - add a new fastram
172     region
173 -------------------------------------------------*/
174 
add_fastram(offs_t start,offs_t end,uint8_t readonly,void * base)175 void mips3_device::add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base)
176 {
177 	if (m_fastram_select < ARRAY_LENGTH(m_fastram))
178 	{
179 		m_fastram[m_fastram_select].start = start;
180 		m_fastram[m_fastram_select].end = end;
181 		m_fastram[m_fastram_select].readonly = readonly;
182 		m_fastram[m_fastram_select].base = base;
183 		m_fastram[m_fastram_select].offset_base8 = (uint8_t*)base - start;
184 		m_fastram[m_fastram_select].offset_base16 = (uint16_t*)((uint8_t*)base - start);
185 		m_fastram[m_fastram_select].offset_base32 = (uint32_t*)((uint8_t*)base - start);
186 		m_fastram_select++;
187 		// Set cache to dirty so that re-mapping occurs
188 		m_drc_cache_dirty = true;
189 	}
190 }
191 
192 
193 /*-------------------------------------------------
194     mips3drc_add_hotspot - add a new hotspot
195 -------------------------------------------------*/
196 
mips3drc_add_hotspot(offs_t pc,uint32_t opcode,uint32_t cycles)197 void mips3_device::mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles)
198 {
199 	if (!allow_drc()) return;
200 	if (m_hotspot_select < ARRAY_LENGTH(m_hotspot))
201 	{
202 		m_hotspot[m_hotspot_select].pc = pc;
203 		m_hotspot[m_hotspot_select].opcode = opcode;
204 		m_hotspot[m_hotspot_select].cycles = cycles;
205 		m_hotspot_select++;
206 	}
207 }
208 
209 
210 
211 /***************************************************************************
212     CACHE MANAGEMENT
213 ***************************************************************************/
214 
215 /*-------------------------------------------------
216     code_flush_cache - flush the cache and
217     regenerate static code
218 -------------------------------------------------*/
219 
code_flush_cache()220 void mips3_device::code_flush_cache()
221 {
222 	int mode;
223 
224 	/* empty the transient cache contents */
225 	m_drcuml->reset();
226 
227 	try
228 	{
229 		/* generate the entry point and out-of-cycles handlers */
230 		static_generate_entry_point();
231 		static_generate_nocode_handler();
232 		static_generate_out_of_cycles();
233 		static_generate_tlb_mismatch();
234 
235 		/* append exception handlers for various types */
236 		static_generate_exception(EXCEPTION_INTERRUPT,     true,  "exception_interrupt");
237 		static_generate_exception(EXCEPTION_INTERRUPT,     false, "exception_interrupt_norecover");
238 		static_generate_exception(EXCEPTION_TLBMOD,        true,  "exception_tlbmod");
239 		static_generate_exception(EXCEPTION_TLBLOAD,       true,  "exception_tlbload");
240 		static_generate_exception(EXCEPTION_TLBSTORE,      true,  "exception_tlbstore");
241 		static_generate_exception(EXCEPTION_TLBLOAD_FILL,  true,  "exception_tlbload_fill");
242 		static_generate_exception(EXCEPTION_TLBSTORE_FILL, true,  "exception_tlbstore_fill");
243 		static_generate_exception(EXCEPTION_ADDRLOAD,      true,  "exception_addrload");
244 		static_generate_exception(EXCEPTION_ADDRSTORE,     true,  "exception_addrstore");
245 		static_generate_exception(EXCEPTION_SYSCALL,       true,  "exception_syscall");
246 		static_generate_exception(EXCEPTION_BREAK,         true,  "exception_break");
247 		static_generate_exception(EXCEPTION_INVALIDOP,     true,  "exception_invalidop");
248 		static_generate_exception(EXCEPTION_BADCOP,        true,  "exception_badcop");
249 		static_generate_exception(EXCEPTION_OVERFLOW,      true,  "exception_overflow");
250 		static_generate_exception(EXCEPTION_TRAP,          true,  "exception_trap");
251 		static_generate_exception(EXCEPTION_FPE,           true,  "exception_fpe");
252 
253 		/* add subroutines for memory accesses */
254 		for (mode = 0; mode < 3; mode++)
255 		{
256 			static_generate_memory_accessor(mode, 1, false, false, "read8",       m_read8[mode]);
257 			static_generate_memory_accessor(mode, 1, true,  false, "write8",      m_write8[mode]);
258 			static_generate_memory_accessor(mode, 2, false, false, "read16",      m_read16[mode]);
259 			static_generate_memory_accessor(mode, 2, true,  false, "write16",     m_write16[mode]);
260 			static_generate_memory_accessor(mode, 4, false, false, "read32",      m_read32[mode]);
261 			static_generate_memory_accessor(mode, 4, false, true,  "read32mask",  m_read32mask[mode]);
262 			static_generate_memory_accessor(mode, 4, true,  false, "write32",     m_write32[mode]);
263 			static_generate_memory_accessor(mode, 4, true,  true,  "write32mask", m_write32mask[mode]);
264 			static_generate_memory_accessor(mode, 8, false, false, "read64",      m_read64[mode]);
265 			static_generate_memory_accessor(mode, 8, false, true,  "read64mask",  m_read64mask[mode]);
266 			static_generate_memory_accessor(mode, 8, true,  false, "write64",     m_write64[mode]);
267 			static_generate_memory_accessor(mode, 8, true,  true,  "write64mask", m_write64mask[mode]);
268 		}
269 	}
270 	catch (drcuml_block::abort_compilation &)
271 	{
272 		fatalerror("Unrecoverable error generating static code\n");
273 	}
274 }
275 
276 
277 /*-------------------------------------------------
278     code_compile_block - compile a block of the
279     given mode at the specified pc
280 -------------------------------------------------*/
281 
code_compile_block(uint8_t mode,offs_t pc)282 void mips3_device::code_compile_block(uint8_t mode, offs_t pc)
283 {
284 	compiler_state compiler = { 0 };
285 	const opcode_desc *seqhead, *seqlast;
286 	const opcode_desc *desclist;
287 	bool override = false;
288 
289 	g_profiler.start(PROFILER_DRC_COMPILE);
290 
291 	/* get a description of this sequence */
292 	desclist = m_drcfe->describe_code(pc);
293 	if (m_drcuml->logging() || m_drcuml->logging_native())
294 		log_opcode_desc(desclist, 0);
295 
296 	/* if we get an error back, flush the cache and try again */
297 	bool succeeded = false;
298 	while (!succeeded)
299 	{
300 		try
301 		{
302 			/* start the block */
303 			drcuml_block &block(m_drcuml->begin_block(4096));
304 
305 			/* loop until we get through all instruction sequences */
306 			for (seqhead = desclist; seqhead != nullptr; seqhead = seqlast->next())
307 			{
308 				const opcode_desc *curdesc;
309 				uint32_t nextpc;
310 
311 				/* add a code log entry */
312 				if (m_drcuml->logging())
313 					block.append_comment("-------------------------");                     // comment
314 
315 				/* determine the last instruction in this sequence */
316 				for (seqlast = seqhead; seqlast != nullptr; seqlast = seqlast->next())
317 					if (seqlast->flags & OPFLAG_END_SEQUENCE)
318 						break;
319 				assert(seqlast != nullptr);
320 
321 				/* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
322 				if (override || !m_drcuml->hash_exists(mode, seqhead->pc))
323 				{
324 					UML_HASH(block, mode, seqhead->pc);                                     // hash    mode,pc
325 				}
326 				/* if we already have a hash, and this is the first sequence, assume that we */
327 				/* are recompiling due to being out of sync and allow future overrides */
328 				else if (seqhead == desclist)
329 				{
330 					override = true;
331 					UML_HASH(block, mode, seqhead->pc);                                     // hash    mode,pc
332 				}
333 
334 				/* otherwise, redispatch to that fixed PC and skip the rest of the processing */
335 				else
336 				{
337 					UML_LABEL(block, seqhead->pc | 0x80000000);                             // label   seqhead->pc | 0x80000000
338 					UML_HASHJMP(block, m_core->mode, seqhead->pc, *m_nocode);               // hashjmp <mode>,seqhead->pc,nocode
339 					continue;
340 				}
341 
342 				/* validate this code block if we're not pointing into ROM */
343 				if (m_program->get_write_ptr(seqhead->physpc) != nullptr)
344 					generate_checksum_block(block, compiler, seqhead, seqlast);
345 
346 				/* label this instruction, if it may be jumped to locally */
347 				if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
348 				{
349 					UML_LABEL(block, seqhead->pc | 0x80000000);                             // label   seqhead->pc | 0x80000000
350 				}
351 
352 				/* iterate over instructions in the sequence and compile them */
353 				for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
354 				{
355 					generate_sequence_instruction(block, compiler, curdesc);
356 				}
357 
358 				/* if we need to return to the start, do it */
359 				if (seqlast->flags & OPFLAG_RETURN_TO_START)
360 					nextpc = pc;
361 
362 				/* otherwise we just go to the next instruction */
363 				else
364 					nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
365 
366 				/* count off cycles and go there */
367 				generate_update_cycles(block, compiler, nextpc, true);          // <subtract cycles>
368 
369 				/* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
370 				if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
371 				{
372 					UML_HASHJMP(block, mem(&m_core->mode), nextpc, *m_nocode);              // hashjmp <mode>,nextpc,nocode
373 				}
374 				else if (seqlast->next() == nullptr || seqlast->next()->pc != nextpc)
375 				{
376 					UML_HASHJMP(block, m_core->mode, nextpc, *m_nocode);                    // hashjmp <mode>,nextpc,nocode
377 				}
378 			}
379 
380 			/* end the sequence */
381 			block.end();
382 			g_profiler.stop();
383 			succeeded = true;
384 		}
385 		catch (drcuml_block::abort_compilation &)
386 		{
387 			code_flush_cache();
388 		}
389 	}
390 }
391 
392 
393 
394 /***************************************************************************
395     C FUNCTION CALLBACKS
396 ***************************************************************************/
397 
cfunc_mips3com_update_cycle_counting(void * param)398 static void cfunc_mips3com_update_cycle_counting(void *param)
399 {
400 	((mips3_device *)param)->mips3com_update_cycle_counting();
401 }
402 
cfunc_mips3com_asid_changed(void * param)403 static void cfunc_mips3com_asid_changed(void *param)
404 {
405 	((mips3_device *)param)->mips3com_asid_changed();
406 }
407 
cfunc_mips3com_tlbr(void * param)408 static void cfunc_mips3com_tlbr(void *param)
409 {
410 	((mips3_device *)param)->mips3com_tlbr();
411 }
412 
cfunc_mips3com_tlbwi(void * param)413 static void cfunc_mips3com_tlbwi(void *param)
414 {
415 	((mips3_device *)param)->mips3com_tlbwi();
416 }
417 
cfunc_mips3com_tlbwr(void * param)418 static void cfunc_mips3com_tlbwr(void *param)
419 {
420 	((mips3_device *)param)->mips3com_tlbwr();
421 }
422 
cfunc_mips3com_tlbp(void * param)423 static void cfunc_mips3com_tlbp(void *param)
424 {
425 	((mips3_device *)param)->mips3com_tlbp();
426 }
427 
428 /*-------------------------------------------------
429     cfunc_get_cycles - compute the total number
430     of cycles executed so far
431 -------------------------------------------------*/
432 
func_get_cycles()433 void mips3_device::func_get_cycles()
434 {
435 	m_core->numcycles = total_cycles();
436 }
437 
cfunc_get_cycles(void * param)438 static void cfunc_get_cycles(void *param)
439 {
440 	((mips3_device *)param)->func_get_cycles();
441 }
442 
443 
444 /*-------------------------------------------------
445     cfunc_printf_exception - log any exceptions that
446     aren't interrupts
447 -------------------------------------------------*/
448 
func_printf_exception()449 void mips3_device::func_printf_exception()
450 {
451 	printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", (uint32_t)m_core->cpr[0][COP0_EPC], (uint32_t)m_core->cpr[0][COP0_Cause], (uint32_t)m_core->cpr[0][COP0_BadVAddr], m_core->pc);
452 	func_printf_probe();
453 }
454 
cfunc_printf_exception(void * param)455 static void cfunc_printf_exception(void *param)
456 {
457 	((mips3_device *)param)->func_printf_exception();
458 }
459 
460 /*-------------------------------------------------
461     cfunc_printf_debug - generic printf for
462     debugging
463 -------------------------------------------------*/
464 
func_printf_debug()465 void mips3_device::func_printf_debug()
466 {
467 	printf(m_core->format, m_core->arg0, m_core->arg1);
468 }
469 
cfunc_printf_debug(void * param)470 static void cfunc_printf_debug(void *param)
471 {
472 	((mips3_device *)param)->func_printf_debug();
473 }
474 
475 
476 /*-------------------------------------------------
477     cfunc_printf_probe - print the current CPU
478     state and return
479 -------------------------------------------------*/
480 
func_printf_probe()481 void mips3_device::func_printf_probe()
482 {
483 	printf(" PC=%08X          r1=%08X%08X  r2=%08X%08X  r3=%08X%08X\n",
484 		m_core->pc,
485 		(uint32_t)(m_core->r[1] >> 32), (uint32_t)m_core->r[1],
486 		(uint32_t)(m_core->r[2] >> 32), (uint32_t)m_core->r[2],
487 		(uint32_t)(m_core->r[3] >> 32), (uint32_t)m_core->r[3]);
488 	printf(" r4=%08X%08X  r5=%08X%08X  r6=%08X%08X  r7=%08X%08X\n",
489 		(uint32_t)(m_core->r[4] >> 32), (uint32_t)m_core->r[4],
490 		(uint32_t)(m_core->r[5] >> 32), (uint32_t)m_core->r[5],
491 		(uint32_t)(m_core->r[6] >> 32), (uint32_t)m_core->r[6],
492 		(uint32_t)(m_core->r[7] >> 32), (uint32_t)m_core->r[7]);
493 	printf(" r8=%08X%08X  r9=%08X%08X r10=%08X%08X r11=%08X%08X\n",
494 		(uint32_t)(m_core->r[8] >> 32), (uint32_t)m_core->r[8],
495 		(uint32_t)(m_core->r[9] >> 32), (uint32_t)m_core->r[9],
496 		(uint32_t)(m_core->r[10] >> 32), (uint32_t)m_core->r[10],
497 		(uint32_t)(m_core->r[11] >> 32), (uint32_t)m_core->r[11]);
498 	printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n",
499 		(uint32_t)(m_core->r[12] >> 32), (uint32_t)m_core->r[12],
500 		(uint32_t)(m_core->r[13] >> 32), (uint32_t)m_core->r[13],
501 		(uint32_t)(m_core->r[14] >> 32), (uint32_t)m_core->r[14],
502 		(uint32_t)(m_core->r[15] >> 32), (uint32_t)m_core->r[15]);
503 	printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n",
504 		(uint32_t)(m_core->r[16] >> 32), (uint32_t)m_core->r[16],
505 		(uint32_t)(m_core->r[17] >> 32), (uint32_t)m_core->r[17],
506 		(uint32_t)(m_core->r[18] >> 32), (uint32_t)m_core->r[18],
507 		(uint32_t)(m_core->r[19] >> 32), (uint32_t)m_core->r[19]);
508 	printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n",
509 		(uint32_t)(m_core->r[20] >> 32), (uint32_t)m_core->r[20],
510 		(uint32_t)(m_core->r[21] >> 32), (uint32_t)m_core->r[21],
511 		(uint32_t)(m_core->r[22] >> 32), (uint32_t)m_core->r[22],
512 		(uint32_t)(m_core->r[23] >> 32), (uint32_t)m_core->r[23]);
513 	printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n",
514 		(uint32_t)(m_core->r[24] >> 32), (uint32_t)m_core->r[24],
515 		(uint32_t)(m_core->r[25] >> 32), (uint32_t)m_core->r[25],
516 		(uint32_t)(m_core->r[26] >> 32), (uint32_t)m_core->r[26],
517 		(uint32_t)(m_core->r[27] >> 32), (uint32_t)m_core->r[27]);
518 	printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n",
519 		(uint32_t)(m_core->r[28] >> 32), (uint32_t)m_core->r[28],
520 		(uint32_t)(m_core->r[29] >> 32), (uint32_t)m_core->r[29],
521 		(uint32_t)(m_core->r[30] >> 32), (uint32_t)m_core->r[30],
522 		(uint32_t)(m_core->r[31] >> 32), (uint32_t)m_core->r[31]);
523 	printf(" hi=%08X%08X  lo=%08X%08X\n",
524 		(uint32_t)(m_core->r[REG_HI] >> 32), (uint32_t)m_core->r[REG_HI],
525 		(uint32_t)(m_core->r[REG_LO] >> 32), (uint32_t)m_core->r[REG_LO]);
526 }
527 
cfunc_printf_probe(void * param)528 static void cfunc_printf_probe(void *param)
529 {
530 	((mips3_device *)param)->func_printf_probe();
531 }
532 
533 /*-------------------------------------------------
534     func_debug_break - debugger break
535 -------------------------------------------------*/
536 
func_debug_break()537 void mips3_device::func_debug_break()
538 {
539 	machine().debug_break();
540 }
541 
cfunc_debug_break(void * param)542 static void cfunc_debug_break(void *param)
543 {
544 	((mips3_device *)param)->func_debug_break();
545 }
546 
547 /*-------------------------------------------------
548     cfunc_unimplemented - handler for
549     unimplemented opcdes
550 -------------------------------------------------*/
551 
func_unimplemented()552 void mips3_device::func_unimplemented()
553 {
554 	uint32_t opcode = m_core->arg0;
555 	fatalerror("PC=%08X: Unimplemented op %08X (%02X,%02X)\n", m_core->pc, opcode, opcode >> 26, opcode & 0x3f);
556 }
557 
cfunc_unimplemented(void * param)558 static void cfunc_unimplemented(void *param)
559 {
560 	((mips3_device *)param)->func_unimplemented();
561 }
562 
563 
564 /***************************************************************************
565     STATIC CODEGEN
566 ***************************************************************************/
567 
568 /*-------------------------------------------------
569     static_generate_entry_point - generate a
570     static entry point
571 -------------------------------------------------*/
572 
static_generate_entry_point()573 void mips3_device::static_generate_entry_point()
574 {
575 	uml::code_label const skip = 1;
576 
577 	drcuml_block &block(m_drcuml->begin_block(20));
578 
579 	/* forward references */
580 	alloc_handle(*m_drcuml, m_exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover");
581 	alloc_handle(*m_drcuml, m_nocode, "nocode");
582 
583 	alloc_handle(*m_drcuml, m_entry, "entry");
584 	UML_HANDLE(block, *m_entry);                                     // handle  entry
585 
586 	/* reset the FPU mode */
587 	UML_AND(block, I0, CCR132(31), 3);                                  // and     i0,ccr1[31],3
588 	UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1);// load    i0,fpmode,i0,byte
589 	UML_SETFMOD(block, I0);                                                 // setfmod i0
590 
591 	/* load fast integer registers */
592 	load_fast_iregs(block);
593 
594 	/* check for interrupts */
595 	UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status));                // and     i0,[Cause],[Status]
596 	UML_AND(block, I0, I0, 0xfc00);                                 // and     i0,i0,0xfc00,Z
597 	UML_JMPc(block, COND_Z, skip);                                                  // jmp     skip,Z
598 	UML_TEST(block, CPR032(COP0_Status), SR_IE);                                // test    [Status],SR_IE
599 	UML_JMPc(block, COND_Z, skip);                                                  // jmp     skip,Z
600 	UML_TEST(block, CPR032(COP0_Status), SR_EXL | SR_ERL);                      // test    [Status],SR_EXL | SR_ERL
601 	UML_JMPc(block, COND_NZ, skip);                                                 // jmp     skip,NZ
602 	UML_MOV(block, I0, mem(&m_core->pc));                                        // mov     i0,pc
603 	UML_MOV(block, I1, 0);                                              // mov     i1,0
604 	UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]);   // callh   exception_norecover
605 	UML_LABEL(block, skip);                                                     // skip:
606 
607 	/* generate a hash jump via the current mode and PC */
608 	UML_HASHJMP(block, mem(&m_core->mode), mem(&m_core->pc), *m_nocode);
609 																					// hashjmp <mode>,<pc>,nocode
610 	block.end();
611 }
612 
613 
614 /*-------------------------------------------------
615     static_generate_nocode_handler - generate an
616     exception handler for "out of code"
617 -------------------------------------------------*/
618 
static_generate_nocode_handler()619 void mips3_device::static_generate_nocode_handler()
620 {
621 	/* begin generating */
622 	drcuml_block &block(m_drcuml->begin_block(10));
623 
624 	/* generate a hash jump via the current mode and PC */
625 	alloc_handle(*m_drcuml, m_nocode, "nocode");
626 	UML_HANDLE(block, *m_nocode);                                               // handle  nocode
627 	UML_GETEXP(block, I0);                                                      // getexp  i0
628 	UML_MOV(block, mem(&m_core->pc), I0);                                       // mov     [pc],i0
629 	save_fast_iregs(block);
630 	UML_EXIT(block, EXECUTE_MISSING_CODE);                                      // exit    EXECUTE_MISSING_CODE
631 
632 	block.end();
633 }
634 
635 
636 /*-------------------------------------------------
637     static_generate_out_of_cycles - generate an
638     out of cycles exception handler
639 -------------------------------------------------*/
640 
static_generate_out_of_cycles()641 void mips3_device::static_generate_out_of_cycles()
642 {
643 	/* begin generating */
644 	drcuml_block &block(m_drcuml->begin_block(10));
645 
646 	/* generate a hash jump via the current mode and PC */
647 	alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles");
648 	UML_HANDLE(block, *m_out_of_cycles);                                        // handle  out_of_cycles
649 	UML_GETEXP(block, I0);                                                      // getexp  i0
650 	UML_MOV(block, mem(&m_core->pc), I0);                                       // mov     <pc>,i0
651 	save_fast_iregs(block);
652 	UML_EXIT(block, EXECUTE_OUT_OF_CYCLES);                                     // exit    EXECUTE_OUT_OF_CYCLES
653 
654 	block.end();
655 }
656 
657 
658 /*-------------------------------------------------
659     static_generate_tlb_mismatch - generate a
660     TLB mismatch handler
661 -------------------------------------------------*/
662 
static_generate_tlb_mismatch()663 void mips3_device::static_generate_tlb_mismatch()
664 {
665 	/* forward references */
666 	alloc_handle(*m_drcuml, m_exception[EXCEPTION_TLBLOAD], "exception_tlbload");
667 	alloc_handle(*m_drcuml, m_exception[EXCEPTION_TLBLOAD_FILL], "exception_tlbload_fill");
668 
669 	/* begin generating */
670 	drcuml_block &block(m_drcuml->begin_block(20));
671 
672 	/* generate a hash jump via the current mode and PC */
673 	alloc_handle(*m_drcuml, m_tlb_mismatch, "tlb_mismatch");
674 	UML_HANDLE(block, *m_tlb_mismatch);                                         // handle  tlb_mismatch
675 	UML_RECOVER(block, I0, MAPVAR_PC);                                          // recover i0,PC
676 	// Need the current PC address for the instruction to do the TLB lookup
677 	// so need to adjust I0 so it points to the true PC address in case this is a delay slot
678 	UML_ADD(block, I0, I0, 3);                                                  // add     i1,i0,3
679 	UML_AND(block, I0, I0, ~3);                                                 // and     i0,i0,~3
680 	UML_SHR(block, I1, I0, 12);                                                 // shr     i1,i0,12
681 	UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4);        // load    i1,[vtlb_table],i1,dword
682 	if (PRINTF_MMU)
683 	{
684 		static const char text[] = "TLB mismatch @ %08X (ent=%08X)\n";
685 		UML_MOV(block, mem(&m_core->format), (uintptr_t)text);                  // mov     [format],text
686 		UML_MOV(block, mem(&m_core->arg0), I0);                                 // mov     [arg0],i0
687 		UML_MOV(block, mem(&m_core->arg1), I1);                                 // mov     [arg1],i1
688 		UML_CALLC(block, cfunc_printf_debug, this);                             // callc   printf_debug
689 	}
690 	UML_TEST(block, I1, VTLB_FETCH_ALLOWED);                                    // test    i1,VTLB_FETCH_ALLOWED
691 	UML_JMPc(block, COND_NZ, 1);                                                // jmp     1,nz
692 	UML_TEST(block, I1, VTLB_FLAG_FIXED);                                       // test    i1,VTLB_FLAG_FIXED
693 	UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBLOAD], I0);              // exh     exception[TLBLOAD],i0,nz
694 	UML_EXH(block, *m_exception[EXCEPTION_TLBLOAD_FILL], I0);                   // exh     exception[TLBLOAD_FILL],i0
695 	UML_LABEL(block, 1);                                                        // 1:
696 	save_fast_iregs(block);
697 
698 	// the saved PC may be set 1 instruction back with the low bit set to indicate
699 	// a delay slot; in this path we want the previous instruction address, so recover it
700 	UML_RECOVER(block, I0, MAPVAR_PC);                                          // recover i0,PC
701 	UML_AND(block, I0, I0, ~3);                                                 // and     i0,i0,~3
702 	UML_MOV(block, mem(&m_core->pc), I0);                                       // mov     i0,[pc]
703 
704 	UML_EXIT(block, EXECUTE_MISSING_CODE);                                      // exit    EXECUTE_MISSING_CODE
705 
706 	block.end();
707 }
708 
709 
710 /*-------------------------------------------------
711     static_generate_exception - generate a static
712     exception handler
713 -------------------------------------------------*/
714 
static_generate_exception(uint8_t exception,int recover,const char * name)715 void mips3_device::static_generate_exception(uint8_t exception, int recover, const char *name)
716 {
717 	uml::code_handle *&exception_handle = recover ? m_exception[exception] : m_exception_norecover[exception];
718 	uint32_t offset = 0x180;
719 	uml::code_label const next = 1;
720 	uml::code_label const skip = 2;
721 
722 	/* translate our fake fill exceptions into real exceptions */
723 	if (exception == EXCEPTION_TLBLOAD_FILL || exception == EXCEPTION_TLBSTORE_FILL)
724 	{
725 		offset = 0x000;
726 		exception = (exception - EXCEPTION_TLBLOAD_FILL) + EXCEPTION_TLBLOAD;
727 	}
728 
729 	/* begin generating */
730 	drcuml_block &block(m_drcuml->begin_block(1024));
731 
732 	/* add a global entry for this */
733 	alloc_handle(*m_drcuml, exception_handle, name);
734 	UML_HANDLE(block, *exception_handle);                                           // handle  name
735 
736 	/* exception parameter is expected to be the fault address in this case */
737 	if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE || exception == EXCEPTION_TLBMOD || exception == EXCEPTION_ADDRLOAD || exception == EXCEPTION_ADDRSTORE)
738 	{
739 		/* set BadVAddr to the fault address */
740 		UML_GETEXP(block, I0);                                                  // getexp  i0
741 		UML_MOV(block, CPR032(COP0_BadVAddr), I0);                              // mov     [BadVAddr],i0
742 	}
743 
744 	if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
745 	{
746 		/* set the upper bits of EntryHi and the lower bits of Context to the fault page */
747 		UML_ROLINS(block, CPR032(COP0_EntryHi), I0, 0, 0xffffe000); // rolins  [EntryHi],i0,0,0xffffe000
748 		UML_ROLINS(block, CPR032(COP0_Context), I0, 32-9, 0x7ffff0);    // rolins  [Context],i0,32-9,0x7ffff0
749 	}
750 
751 	if (exception == EXCEPTION_FPE)
752 	{
753 		/* set the flag and cause */
754 		UML_GETEXP(block, I0);                                      // getexp  i0
755 		UML_ROLINS(block, CCR132(31), I0, FCR31_FLAGS, 0x0000007c); // rolins  [CCR31],i0,FCR31_FLAGS,0x0000007c
756 		UML_ROLINS(block, CCR132(31), I0, FCR31_CAUSE, 0x0003f000); // rolins  [CCR31],i0,FCR31_CAUSE,0x0003f000
757 	}
758 
759 	/* set the EPC and Cause registers */
760 	if (recover)
761 	{
762 		UML_RECOVER(block, I0, MAPVAR_PC);                                      // recover i0,PC
763 		UML_RECOVER(block, I1, MAPVAR_CYCLES);                                  // recover i1,CYCLES
764 	}
765 
766 	UML_AND(block, I2, CPR032(COP0_Cause), ~0x800000ff);                        // and     i2,[Cause],~0x800000ff
767 	UML_TEST(block, I0, 1);                                                     // test    i0,1
768 	UML_JMPc(block, COND_Z, next);                                              // jz      <next>
769 	UML_OR(block, I2, I2, 0x80000000);                                          // or      i2,i2,0x80000000
770 	UML_SUB(block, I0, I0, 1);                                                  // sub     i0,i0,1
771 	UML_LABEL(block, next);                                                     // <next>:
772 	UML_MOV(block, I3, offset);                                                 // mov     i3,offset
773 	UML_TEST(block, CPR032(COP0_Status), SR_EXL);                               // test    [Status],SR_EXL
774 	UML_MOVc(block, COND_Z, CPR032(COP0_EPC), I0);                              // mov     [EPC],i0,Z
775 	UML_MOVc(block, COND_NZ, I3, 0x180);                                        // mov     i3,0x180,NZ
776 	UML_OR(block, CPR032(COP0_Cause), I2, exception << 2);                      // or      [Cause],i2,exception << 2
777 
778 	/* for BADCOP exceptions, we use the exception parameter to know which COP */
779 	if (exception == EXCEPTION_BADCOP)
780 	{
781 		UML_GETEXP(block, I0);                                                  // getexp  i0
782 		UML_ROLINS(block, CPR032(COP0_Cause), I0, 28, 0x30000000);              // rolins  [Cause],i0,28,0x30000000
783 	}
784 
785 	/* set EXL in the SR */
786 	UML_OR(block, I0, CPR032(COP0_Status), SR_EXL);                     // or      i0,[Status],SR_EXL
787 	UML_MOV(block, CPR032(COP0_Status), I0);                                    // mov     [Status],i0
788 	generate_update_mode(block);
789 
790 	/* optionally print exceptions */
791 	if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_INTERRUPT && exception != EXCEPTION_SYSCALL) ||
792 		(PRINTF_MMU && (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)))
793 	{
794 		UML_CALLC(block, cfunc_printf_exception, this);                            // callc   cfunc_printf_exception,nullptr
795 		//UML_CALLC(block, cfunc_debug_break, this);                            // callc   cfunc_debug_break,nullptr
796 	}
797 
798 	/* choose our target PC */
799 	UML_ADD(block, I0, I3, 0xbfc00200);                             // add     i0,i3,0xbfc00200
800 	UML_TEST(block, CPR032(COP0_Status), SR_BEV);                   // test    CPR032(COP0_Status),SR_BEV
801 	UML_JMPc(block, COND_NZ, skip);                                                 // jnz     <skip>
802 	UML_ADD(block, I0, I3, 0x80000000);                             // add     i0,i3,0x80000000,z
803 	UML_LABEL(block, skip);                                                     // <skip>:
804 
805 	/* adjust cycles */
806 	UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I1);               // sub icount,icount,cycles,S
807 	UML_EXHc(block, COND_S, *m_out_of_cycles, I0);                   // exh     out_of_cycles,i0
808 
809 	UML_HASHJMP(block, mem(&m_core->mode), I0, *m_nocode);// hashjmp <mode>,i0,nocode
810 
811 	block.end();
812 }
813 
814 
815 /*------------------------------------------------------------------
816     static_generate_memory_accessor
817 ------------------------------------------------------------------*/
818 
static_generate_memory_accessor(int mode,int size,int iswrite,int ismasked,const char * name,uml::code_handle * & handleptr)819 void mips3_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr)
820 {
821 	/* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
822 	/* on exit, read result is in I0 */
823 	/* routine trashes I0-I3 */
824 	uml::code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
825 	uml::code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL];
826 	uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
827 	int tlbmiss = 0;
828 	int label = 1;
829 	int ramnum;
830 
831 	/* begin generating */
832 	drcuml_block &block(m_drcuml->begin_block(1024));
833 
834 	/* add a global entry for this */
835 	alloc_handle(*m_drcuml, handleptr, name);
836 	UML_HANDLE(block, *handleptr);                                              // handle  handleptr
837 
838 	/* user mode? generate address exception if top bit is set */
839 	if (mode == MODE_USER)
840 	{
841 		UML_TEST(block, I0, 0x80000000);                                        // test    i0,0x80000000
842 		UML_EXHc(block, COND_NZ, exception_addrerr, I0);                        // exh     addrerr,i0,nz
843 	}
844 
845 	/* supervisor mode? generate address exception if not in user space or in $C0000000-DFFFFFFF */
846 	if (mode == MODE_SUPER)
847 	{
848 		int addrok;
849 		UML_TEST(block, I0, 0x80000000);                                    // test    i0,0x80000000
850 		UML_JMPc(block, COND_Z, addrok = label++);                                  // jz      addrok
851 		UML_SHR(block, I3, I0, 29);                                 // shr     i3,i0,29
852 		UML_CMP(block, I3, 6);                                          // cmp     i3,6
853 		UML_EXHc(block, COND_NE, exception_addrerr, I0);                            // exh     addrerr,i0,ne
854 		UML_LABEL(block, addrok);                                               // addrok:
855 	}
856 
857 	/* general case: assume paging and perform a translation */
858 	UML_SHR(block, I3, I0, 12);                                     // shr     i3,i0,12
859 	UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load    i3,[vtlb_table],i3,dword
860 	UML_TEST(block, I3, iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED);// test    i3,iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED
861 	UML_JMPc(block, COND_Z, tlbmiss = label++);                                     // jmp     tlbmiss,z
862 	UML_ROLINS(block, I0, I3, 0, 0xfffff000);                   // rolins  i0,i3,0,0xfffff000
863 
864 	if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0)
865 		for (ramnum = 0; ramnum < m_fastram_select; ramnum++)
866 			if (!(iswrite && m_fastram[ramnum].readonly))
867 			{
868 				void *fastbase = (uint8_t *)m_fastram[ramnum].base - m_fastram[ramnum].start;
869 				uint32_t skip = label++;
870 				if (m_fastram[ramnum].end != 0xffffffff)
871 				{
872 					UML_CMP(block, I0, m_fastram[ramnum].end);   // cmp     i0,end
873 					UML_JMPc(block, COND_A, skip);                                      // ja      skip
874 				}
875 				if (m_fastram[ramnum].start != 0x00000000)
876 				{
877 					UML_CMP(block, I0, m_fastram[ramnum].start);// cmp     i0,fastram_start
878 					UML_JMPc(block, COND_B, skip);                                      // jb      skip
879 				}
880 				if (!iswrite)
881 				{
882 					if (size == 1)
883 					{
884 						UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
885 																						// xor     i0,i0,bytexor
886 						UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1);             // load    i0,fastbase,i0,byte
887 					}
888 					else if (size == 2)
889 					{
890 						UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
891 																						// xor     i0,i0,wordxor
892 						UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1);         // load    i0,fastbase,i0,word_x1
893 					}
894 					else if (size == 4)
895 					{
896 						UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1);            // load    i0,fastbase,i0,dword_x1
897 					}
898 					else if (size == 8)
899 					{
900 						UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1);           // dload   i0,fastbase,i0,qword_x1
901 						UML_DROR(block, I0, I0, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
902 																						// dror    i0,i0,32*bytexor
903 					}
904 					UML_RET(block);                                                     // ret
905 				}
906 				else
907 				{
908 					if (size == 1)
909 					{
910 						UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
911 																						// xor     i0,i0,bytexor
912 						UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store   fastbase,i0,i1,byte
913 					}
914 					else if (size == 2)
915 					{
916 						UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
917 																						// xor     i0,i0,wordxor
918 						UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store   fastbase,i0,i1,word_x1
919 					}
920 					else if (size == 4)
921 					{
922 						if (ismasked)
923 						{
924 							UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1);        // load    i3,fastbase,i0,dword_x1
925 							UML_ROLINS(block, I3, I1, 0, I2);       // rolins  i3,i1,0,i2
926 							UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1);       // store   fastbase,i0,i3,dword_x1
927 						}
928 						else
929 							UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1);       // store   fastbase,i0,i1,dword_x1
930 					}
931 					else if (size == 8)
932 					{
933 						UML_DROR(block, I1, I1, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
934 																						// dror    i1,i1,32*bytexor
935 						if (ismasked)
936 						{
937 							UML_DROR(block, I2, I2, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
938 																						// dror    i2,i2,32*bytexor
939 							UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1);       // dload   i3,fastbase,i0,qword_x1
940 							UML_DROLINS(block, I3, I1, 0, I2);      // drolins i3,i1,0,i2
941 							UML_DSTORE(block, fastbase, I0, I3, SIZE_QWORD, SCALE_x1);  // dstore  fastbase,i0,i3,qword_x1
942 						}
943 						else
944 							UML_DSTORE(block, fastbase, I0, I1, SIZE_QWORD, SCALE_x1);  // dstore  fastbase,i0,i1,qword_x1
945 					}
946 					UML_RET(block);                                                     // ret
947 				}
948 
949 				UML_LABEL(block, skip);                                             // skip:
950 			}
951 
952 	switch (size)
953 	{
954 		case 1:
955 			if (iswrite)
956 				UML_WRITE(block, I0, I1, SIZE_BYTE, SPACE_PROGRAM);                 // write   i0,i1,program_byte
957 			else
958 				UML_READ(block, I0, I0, SIZE_BYTE, SPACE_PROGRAM);                  // read    i0,i0,program_byte
959 			break;
960 
961 		case 2:
962 			if (iswrite)
963 				UML_WRITE(block, I0, I1, SIZE_WORD, SPACE_PROGRAM);                 // write   i0,i1,program_word
964 			else
965 				UML_READ(block, I0, I0, SIZE_WORD, SPACE_PROGRAM);                  // read    i0,i0,program_word
966 			break;
967 
968 		case 4:
969 			if (iswrite)
970 			{
971 				if (!ismasked)
972 					UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM);                // write   i0,i1,program_dword
973 				else
974 					UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM);   // writem  i0,i1,i2,program_dword
975 			}
976 			else
977 			{
978 				if (!ismasked)
979 					UML_READ(block, I0, I0, SIZE_DWORD, SPACE_PROGRAM);             // read    i0,i0,program_dword
980 				else
981 					UML_READM(block, I0, I0, I2, SIZE_DWORD, SPACE_PROGRAM);        // readm   i0,i0,i2,program_dword
982 			}
983 			break;
984 
985 		case 8:
986 			if (iswrite)
987 			{
988 				if (!ismasked)
989 					UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM);               // dwrite  i0,i1,program_qword
990 				else
991 					UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM);  // dwritem i0,i1,i2,program_qword
992 			}
993 			else
994 			{
995 				if (!ismasked)
996 					UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM);                // dread   i0,i0,program_qword
997 				else
998 					UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM);   // dreadm  i0,i0,i2,program_qword
999 			}
1000 			break;
1001 	}
1002 	UML_RET(block);                                                                 // ret
1003 
1004 	if (tlbmiss != 0)
1005 	{
1006 		UML_LABEL(block, tlbmiss);                                              // tlbmiss:
1007 		if (iswrite)
1008 		{
1009 			UML_TEST(block, I3, VTLB_READ_ALLOWED);                     // test    i3,VTLB_READ_ALLOWED
1010 			UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0);
1011 																					// exh     tlbmod,i0,nz
1012 		}
1013 		UML_TEST(block, I3, VTLB_FLAG_FIXED);                               // test    i3,VTLB_FLAG_FIXED
1014 		UML_EXHc(block, COND_NZ, exception_tlb, I0);                                // exh     tlb,i0,nz
1015 		UML_EXH(block, exception_tlbfill, I0);                                  // exh     tlbfill,i0
1016 	}
1017 
1018 	block.end();
1019 }
1020 
1021 
1022 
1023 /***************************************************************************
1024     CODE GENERATION
1025 ***************************************************************************/
1026 
1027 /*-------------------------------------------------
1028     generate_update_mode - update the mode based
1029     on a new SR (in i0); trashes i2
1030 -------------------------------------------------*/
1031 
generate_update_mode(drcuml_block & block)1032 void mips3_device::generate_update_mode(drcuml_block &block)
1033 {
1034 	UML_ROLAND(block, I2, I0, 32-2, 0x06);                      // roland  i2,i0,32-2,0x06
1035 	UML_TEST(block, I0, SR_EXL | SR_ERL);                                   // test    i0,SR_EXL | SR_ERL
1036 	UML_MOVc(block, COND_NZ, I2, 0);                                        // mov     i2,0,nz
1037 	UML_ROLINS(block, I2, I0, 32-26, 0x01);                     // rolins  i2,i0,32-26,0x01
1038 	UML_MOV(block, mem(&m_core->mode), I2);                            // mov     [mode],i2
1039 }
1040 
1041 
1042 /*-------------------------------------------------
1043     generate_update_cycles - generate code to
1044     subtract cycles from the icount and generate
1045     an exception if out
1046 -------------------------------------------------*/
1047 
generate_update_cycles(drcuml_block & block,compiler_state & compiler,uml::parameter param,bool allow_exception)1048 void mips3_device::generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception)
1049 {
1050 	/* check software interrupts if pending */
1051 	if (compiler.checksoftints)
1052 	{
1053 		uml::code_label skip;
1054 
1055 		compiler.checksoftints = false;
1056 		UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status));            // and     i0,[Cause],[Status]
1057 		UML_AND(block, I0, I0, 0x0300);                                         // and     i0,i0,0x0300
1058 		UML_JMPc(block, COND_Z, skip = compiler.labelnum++);                    // jmp     skip,Z
1059 		UML_MOV(block, I0, param);                                              // mov     i0,nextpc
1060 		UML_MOV(block, I1, compiler.cycles);                                    // mov     i1,cycles
1061 		UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]);          // callh   interrupt_norecover
1062 		UML_LABEL(block, skip);                                                 // skip:
1063 	}
1064 
1065 	/* check full interrupts if pending */
1066 	if (compiler.checkints)
1067 	{
1068 		uml::code_label skip;
1069 
1070 		compiler.checkints = false;
1071 		UML_AND(block, I0, CPR032(COP0_Cause), CPR032(COP0_Status));            // and     i0,[Cause],[Status]
1072 		UML_AND(block, I0, I0, 0xfc00);                                         // and     i0,i0,0xfc00
1073 		UML_JMPc(block, COND_Z, skip = compiler.labelnum++);                    // jmp     skip,Z
1074 		UML_TEST(block, CPR032(COP0_Status), SR_IE);                            // test    [Status],SR_IE
1075 		UML_JMPc(block, COND_Z, skip);                                          // jmp     skip,Z
1076 		UML_TEST(block, CPR032(COP0_Status), SR_EXL | SR_ERL);                  // test    [Status],SR_EXL | SR_ERL
1077 		UML_JMPc(block, COND_NZ, skip);                                         // jmp     skip,NZ
1078 		UML_MOV(block, I0, param);                                              // mov     i0,nextpc
1079 		UML_MOV(block, I1, compiler.cycles);                                    // mov     i1,cycles
1080 		UML_CALLH(block, *m_exception_norecover[EXCEPTION_INTERRUPT]);          // callh   interrupt_norecover
1081 		UML_LABEL(block, skip);                                                 // skip:
1082 	}
1083 
1084 	/* account for cycles */
1085 	if (compiler.cycles > 0)
1086 	{
1087 		UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), MAPVAR_CYCLES);    // sub     icount,icount,cycles
1088 		UML_MAPVAR(block, MAPVAR_CYCLES, 0);                                        // mapvar  cycles,0
1089 		if (allow_exception)
1090 			UML_EXHc(block, COND_S, *m_out_of_cycles, param);
1091 																					// exh     out_of_cycles,nextpc
1092 	}
1093 	compiler.cycles = 0;
1094 }
1095 
1096 /*-------------------------------------------------
1097     generate_checksum_block - generate code to
1098     validate a sequence of opcodes
1099 -------------------------------------------------*/
1100 
generate_checksum_block(drcuml_block & block,compiler_state & compiler,const opcode_desc * seqhead,const opcode_desc * seqlast)1101 void mips3_device::generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
1102 {
1103 	const opcode_desc *curdesc;
1104 	if (m_drcuml->logging())
1105 		block.append_comment("[Validation for %08X]", seqhead->pc);                // comment
1106 
1107 	/* loose verify or single instruction: just compare and fail */
1108 	if (!(m_drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next() == nullptr)
1109 	{
1110 		if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP))
1111 		{
1112 			uint32_t sum = seqhead->opptr.l[0];
1113 			const void *base = m_prptr(seqhead->physpc);
1114 			uint32_t low_bits = (seqhead->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
1115 			UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1);         // load    i0,base,0,dword
1116 
1117 			if (seqhead->delay.first() != nullptr
1118 				&& !(seqhead->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
1119 				&& seqhead->physpc != seqhead->delay.first()->physpc)
1120 			{
1121 				uint32_t low_bits = (seqhead->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
1122 				base = m_prptr(seqhead->delay.first()->physpc);
1123 				assert(base != nullptr);
1124 				UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1);                 // load    i1,base,dword
1125 				UML_ADD(block, I0, I0, I1);                     // add     i0,i0,i1
1126 
1127 				sum += seqhead->delay.first()->opptr.l[0];
1128 			}
1129 
1130 			UML_CMP(block, I0, sum);                                    // cmp     i0,opptr[0]
1131 			UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead));       // exne    nocode,seqhead->pc
1132 		}
1133 	}
1134 
1135 	/* full verification; sum up everything */
1136 	else
1137 	{
1138 #if 0
1139 		for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
1140 			if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
1141 			{
1142 				const void *base = m_prptr(seqhead->physpc);
1143 				UML_LOAD(block, I0, base, m_dword_xor, SIZE_DWORD, SCALE_x1);     // load    i0,base,0,dword
1144 				UML_CMP(block, I0, curdesc->opptr.l[0]);                    // cmp     i0,opptr[0]
1145 				UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead));   // exne    nocode,seqhead->pc
1146 			}
1147 #else
1148 		uint32_t sum = 0;
1149 		const void *base = m_prptr(seqhead->physpc);
1150 		uint32_t low_bits = (seqhead->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
1151 		UML_LOAD(block, I0, base, low_bits, SIZE_DWORD, SCALE_x1);             // load    i0,base,0,dword
1152 		sum += seqhead->opptr.l[0];
1153 		for (curdesc = seqhead->next(); curdesc != seqlast->next(); curdesc = curdesc->next())
1154 		{
1155 			if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP))
1156 			{
1157 				base = m_prptr(curdesc->physpc);
1158 				assert(base != nullptr);
1159 				uint32_t low_bits = (curdesc->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
1160 				UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1);     // load    i1,base,dword
1161 				UML_ADD(block, I0, I0, I1);                         // add     i0,i0,i1
1162 				sum += curdesc->opptr.l[0];
1163 
1164 				if (curdesc->delay.first() != nullptr
1165 					&& !(curdesc->delay.first()->flags & OPFLAG_VIRTUAL_NOOP)
1166 					&& (curdesc == seqlast || (curdesc->next() != nullptr && curdesc->next()->physpc != curdesc->delay.first()->physpc)))
1167 				{
1168 					base = m_prptr(curdesc->delay.first()->physpc);
1169 					assert(base != nullptr);
1170 					uint32_t low_bits = (curdesc->delay.first()->physpc & (m_data_bits == 64 ? 4 : 0)) ^ m_dword_xor;
1171 					UML_LOAD(block, I1, base, low_bits, SIZE_DWORD, SCALE_x1); // load    i1,base,dword
1172 					UML_ADD(block, I0, I0, I1);                     // add     i0,i0,i1
1173 					sum += curdesc->delay.first()->opptr.l[0];
1174 				}
1175 			}
1176 		}
1177 		UML_CMP(block, I0, sum);                                            // cmp     i0,sum
1178 		UML_EXHc(block, COND_NE, *m_nocode, epc(seqhead));           // exne    nocode,seqhead->pc
1179 #endif
1180 	}
1181 }
1182 
1183 
1184 /*-------------------------------------------------
1185     generate_sequence_instruction - generate code
1186     for a single instruction in a sequence
1187 -------------------------------------------------*/
1188 
generate_sequence_instruction(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)1189 void mips3_device::generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
1190 {
1191 	offs_t expc;
1192 	int hotnum;
1193 
1194 	/* add an entry for the log */
1195 	if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
1196 		log_add_disasm_comment(block, desc->pc, desc->opptr.l[0]);
1197 
1198 	/* set the PC map variable */
1199 	expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
1200 	UML_MAPVAR(block, MAPVAR_PC, expc);                                             // mapvar  PC,expc
1201 
1202 	/* accumulate total cycles */
1203 	compiler.cycles += desc->cycles;
1204 
1205 	/* is this a hotspot? */
1206 	for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
1207 		if (m_hotspot[hotnum].pc != 0 && desc->pc == m_hotspot[hotnum].pc && desc->opptr.l[0] == m_hotspot[hotnum].opcode)
1208 		{
1209 			compiler.cycles += m_hotspot[hotnum].cycles;
1210 			break;
1211 		}
1212 
1213 	/* update the icount map variable */
1214 	UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles);                             // mapvar  CYCLES,compiler.cycles
1215 
1216 	/* if we want a probe, add it here */
1217 	if (desc->pc == PROBE_ADDRESS)
1218 	{
1219 		UML_MOV(block, mem(&m_core->pc), desc->pc);                              // mov     [pc],desc->pc
1220 		UML_CALLC(block, cfunc_printf_probe, this);                                // callc   cfunc_printf_probe,mips3
1221 	}
1222 
1223 	/* if we are debugging, call the debugger */
1224 	if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
1225 	{
1226 		UML_MOV(block, mem(&m_core->pc), desc->pc);                              // mov     [pc],desc->pc
1227 		save_fast_iregs(block);
1228 		UML_DEBUG(block, desc->pc);                                         // debug   desc->pc
1229 	}
1230 
1231 	/* if we hit an unmapped address, fatal error */
1232 	if (desc->flags & OPFLAG_COMPILER_UNMAPPED)
1233 	{
1234 		UML_MOV(block, mem(&m_core->pc), desc->pc);                              // mov     [pc],desc->pc
1235 		save_fast_iregs(block);
1236 		UML_EXIT(block, EXECUTE_UNMAPPED_CODE);                             // exit    EXECUTE_UNMAPPED_CODE
1237 	}
1238 
1239 	/* if we hit a compiler page fault, it's just like a TLB mismatch */
1240 	if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT)
1241 	{
1242 		if (PRINTF_MMU)
1243 		{
1244 			static const char text[] = "Compiler page fault @ %08X\n";
1245 			UML_MOV(block, mem(&m_core->format), (uintptr_t)text);          // mov     [format],text
1246 			UML_MOV(block, mem(&m_core->arg0), desc->pc);              // mov     [arg0],desc->pc
1247 			UML_CALLC(block, cfunc_printf_debug, this);                            // callc   printf_debug
1248 		}
1249 		UML_EXH(block, *m_tlb_mismatch, 0);                      // exh     tlb_mismatch,0
1250 		// Unconditional tlb exception, no point going further
1251 		return;
1252 	}
1253 
1254 	/* validate our TLB entry at this PC; if we fail, we need to handle it */
1255 	if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
1256 	{
1257 		const vtlb_entry *tlbtable = vtlb_table();
1258 
1259 		/* if we currently have a valid TLB read entry, we just verify */
1260 		if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
1261 		{
1262 			if (PRINTF_MMU)
1263 			{
1264 				static const char text[] = "Checking TLB at @ %08X\n";
1265 				UML_MOV(block, mem(&m_core->format), (uintptr_t)text);      // mov     [format],text
1266 				UML_MOV(block, mem(&m_core->arg0), desc->pc);          // mov     [arg0],desc->pc
1267 				UML_CALLC(block, cfunc_printf_debug, this);                        // callc   printf_debug
1268 			}
1269 			UML_LOAD(block, I0, &tlbtable[desc->pc >> 12], 0, SIZE_DWORD, SCALE_x4);        // load i0,tlbtable[desc->pc >> 12],0,dword
1270 			UML_CMP(block, I0, tlbtable[desc->pc >> 12]);                   // cmp     i0,*tlbentry
1271 			UML_EXHc(block, COND_NE, *m_tlb_mismatch, 0);            // exh     tlb_mismatch,0,NE
1272 		}
1273 
1274 		/* otherwise, we generate an unconditional exception */
1275 		else
1276 		{
1277 			if (PRINTF_MMU)
1278 			{
1279 				static const char text[] = "No valid TLB @ %08X\n";
1280 				UML_MOV(block, mem(&m_core->format), (uintptr_t)text);      // mov     [format],text
1281 				UML_MOV(block, mem(&m_core->arg0), desc->pc);          // mov     [arg0],desc->pc
1282 				UML_CALLC(block, cfunc_printf_debug, this);                        // callc   printf_debug
1283 			}
1284 			UML_EXH(block, *m_tlb_mismatch, 0);                  // exh     tlb_mismatch,0
1285 			// Unconditional tlb exception, no point going further
1286 			return;
1287 		}
1288 	}
1289 
1290 	/* if this is an invalid opcode, generate the exception now */
1291 	if (desc->flags & OPFLAG_INVALID_OPCODE)
1292 		UML_EXH(block, *m_exception[EXCEPTION_INVALIDOP], 0);    // exh     invalidop,0
1293 
1294 	/* otherwise, unless this is a virtual no-op, it's a regular instruction */
1295 	else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
1296 	{
1297 		/* compile the instruction */
1298 		if (!generate_opcode(block, compiler, desc))
1299 		{
1300 			UML_MOV(block, mem(&m_core->pc), desc->pc);                          // mov     [pc],desc->pc
1301 			UML_MOV(block, mem(&m_core->arg0), desc->opptr.l[0]);      // mov     [arg0],desc->opptr.l
1302 			UML_CALLC(block, cfunc_unimplemented, this);                           // callc   cfunc_unimplemented
1303 		}
1304 	}
1305 }
1306 
1307 
1308 /*------------------------------------------------------------------
1309     generate_delay_slot_and_branch
1310 ------------------------------------------------------------------*/
1311 
generate_delay_slot_and_branch(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc,uint8_t linkreg)1312 void mips3_device::generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg)
1313 {
1314 	compiler_state compiler_temp(compiler);
1315 	uint32_t op = desc->opptr.l[0];
1316 
1317 	/* fetch the target register if dynamic, in case it is modified by the delay slot */
1318 	if (desc->targetpc == BRANCH_TARGET_DYNAMIC)
1319 	{
1320 		UML_MOV(block, mem(&m_core->jmpdest), R32(RSREG));                 // mov     [jmpdest],<rsreg>
1321 
1322 	}
1323 
1324 	/* set the link if needed -- before the delay slot */
1325 	if (linkreg != 0)
1326 	{
1327 		UML_DMOV(block, R64(linkreg), (int32_t)(desc->pc + 8));                   // dmov    <linkreg>,desc->pc + 8
1328 	}
1329 
1330 	/* compile the delay slot using temporary compiler state */
1331 	assert(desc->delay.first() != nullptr);
1332 	generate_sequence_instruction(block, compiler_temp, desc->delay.first());       // <next instruction>
1333 
1334 	/* update the cycles and jump through the hash table to the target */
1335 	if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
1336 	{
1337 		generate_update_cycles(block, compiler_temp, desc->targetpc, true); // <subtract cycles>
1338 		if (!(m_drcoptions & MIPS3DRC_DISABLE_INTRABLOCK) && desc->flags & OPFLAG_INTRABLOCK_BRANCH)
1339 		{
1340 			UML_JMP(block, desc->targetpc | 0x80000000);                            // jmp     desc->targetpc | 0x80000000
1341 		}
1342 		else
1343 		{
1344 			UML_HASHJMP(block, m_core->mode, desc->targetpc, *m_nocode);            // hashjmp <mode>,desc->targetpc,nocode
1345 		}
1346 	}
1347 	else
1348 	{
1349 		generate_update_cycles(block, compiler_temp, uml::mem(&m_core->jmpdest), true); // <subtract cycles>
1350 		UML_HASHJMP(block, m_core->mode, mem(&m_core->jmpdest), *m_nocode);         // hashjmp <mode>,<rsreg>,nocode
1351 	}
1352 
1353 	/* update the label */
1354 	compiler.labelnum = compiler_temp.labelnum;
1355 
1356 	/* reset the mapvar to the current cycles and account for skipped slots */
1357 	compiler.cycles += desc->skipslots;
1358 	UML_MAPVAR(block, MAPVAR_CYCLES, compiler.cycles);                             // mapvar  CYCLES,compiler.cycles
1359 }
1360 
1361 
1362 /*-------------------------------------------------
1363     generate_opcode - generate code for a specific
1364     opcode
1365 -------------------------------------------------*/
1366 
generate_opcode(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)1367 bool mips3_device::generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
1368 {
1369 	int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
1370 	uint32_t op = desc->opptr.l[0];
1371 	uint8_t opswitch = op >> 26;
1372 	uml::code_label skip;
1373 
1374 	switch (opswitch)
1375 	{
1376 		/* ----- sub-groups ----- */
1377 
1378 		case 0x00:  /* SPECIAL - MIPS I */
1379 			return generate_special(block, compiler, desc);
1380 
1381 		case 0x01:  /* REGIMM - MIPS I */
1382 			return generate_regimm(block, compiler, desc);
1383 
1384 		case 0x1c:  /* IDT-specific */
1385 			return generate_idt(block, compiler, desc);
1386 
1387 
1388 		/* ----- jumps and branches ----- */
1389 
1390 		case 0x02:  /* J - MIPS I */
1391 			generate_delay_slot_and_branch(block, compiler, desc, 0);        // <next instruction + hashjmp>
1392 			return true;
1393 
1394 		case 0x03:  /* JAL - MIPS I */
1395 			generate_delay_slot_and_branch(block, compiler, desc, 31);       // <next instruction + hashjmp>
1396 			return true;
1397 
1398 		case 0x04:  /* BEQ - MIPS I */
1399 		case 0x14:  /* BEQL - MIPS II */
1400 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
1401 			UML_JMPc(block, COND_NE, skip = compiler.labelnum++);                  // jmp     skip,NE
1402 			generate_delay_slot_and_branch(block, compiler, desc, 0);        // <next instruction + hashjmp>
1403 			UML_LABEL(block, skip);                                             // skip:
1404 			return true;
1405 
1406 		case 0x05:  /* BNE - MIPS I */
1407 		case 0x15:  /* BNEL - MIPS II */
1408 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
1409 			UML_JMPc(block, COND_E, skip = compiler.labelnum++);                       // jmp     skip,E
1410 			generate_delay_slot_and_branch(block, compiler, desc, 0);        // <next instruction + hashjmp>
1411 			UML_LABEL(block, skip);                                             // skip:
1412 			return true;
1413 
1414 		case 0x06:  /* BLEZ - MIPS I */
1415 		case 0x16:  /* BLEZL - MIPS II */
1416 			if (RSREG != 0)
1417 			{
1418 				UML_DCMP(block, R64(RSREG), 0);                             // dcmp    <rsreg>,0
1419 				UML_JMPc(block, COND_G, skip = compiler.labelnum++);                   // jmp     skip,G
1420 				generate_delay_slot_and_branch(block, compiler, desc, 0);    // <next instruction + hashjmp>
1421 				UML_LABEL(block, skip);                                         // skip:
1422 			}
1423 			else
1424 				generate_delay_slot_and_branch(block, compiler, desc, 0);    // <next instruction + hashjmp>
1425 			return true;
1426 
1427 		case 0x07:  /* BGTZ - MIPS I */
1428 		case 0x17:  /* BGTZL - MIPS II */
1429 			UML_DCMP(block, R64(RSREG), 0);                                 // dcmp    <rsreg>,0
1430 			UML_JMPc(block, COND_LE, skip = compiler.labelnum++);                  // jmp     skip,LE
1431 			generate_delay_slot_and_branch(block, compiler, desc, 0);        // <next instruction + hashjmp>
1432 			UML_LABEL(block, skip);                                             // skip:
1433 			return true;
1434 
1435 
1436 		/* ----- immediate arithmetic ----- */
1437 
1438 		case 0x0f:  /* LUI - MIPS I */
1439 			if (RTREG != 0)
1440 				UML_DMOV(block, R64(RTREG), UIMMVAL << 16);                 // dmov    <rtreg>,UIMMVAL << 16
1441 			return true;
1442 
1443 		case 0x08:  /* ADDI - MIPS I */
1444 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1445 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
1446 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
1447 																					// exh    overflow,0
1448 			if (RTREG != 0)
1449 				UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD);                       // dsext   <rtreg>,i0,dword
1450 			return true;
1451 
1452 		case 0x09:  /* ADDIU - MIPS I */
1453 			if (RTREG != 0)
1454 			{
1455 				UML_ADD(block, I0, R32(RSREG), SIMMVAL);                    // add     i0,<rsreg>,SIMMVAL,V
1456 				UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD);                       // dsext   <rtreg>,i0,dword
1457 			}
1458 			return true;
1459 
1460 		case 0x18:  /* DADDI - MIPS III */
1461 			UML_DADD(block, I0, R64(RSREG), SIMMVAL);                       // dadd    i0,<rsreg>,SIMMVAL
1462 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
1463 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
1464 																					// exh    overflow,0
1465 			if (RTREG != 0)
1466 				UML_DMOV(block, R64(RTREG), I0);                                // dmov    <rtreg>,i0
1467 			return true;
1468 
1469 		case 0x19:  /* DADDIU - MIPS III */
1470 			if (RTREG != 0)
1471 				UML_DADD(block, R64(RTREG), R64(RSREG), SIMMVAL);               // dadd    <rtreg>,<rsreg>,SIMMVAL
1472 			return true;
1473 
1474 		case 0x0c:  /* ANDI - MIPS I */
1475 			if (RTREG != 0)
1476 				UML_DAND(block, R64(RTREG), R64(RSREG), UIMMVAL);               // dand    <rtreg>,<rsreg>,UIMMVAL
1477 			return true;
1478 
1479 		case 0x0d:  /* ORI - MIPS I */
1480 			if (RTREG != 0)
1481 				UML_DOR(block, R64(RTREG), R64(RSREG), UIMMVAL);                // dor     <rtreg>,<rsreg>,UIMMVAL
1482 			return true;
1483 
1484 		case 0x0e:  /* XORI - MIPS I */
1485 			if (RTREG != 0)
1486 				UML_DXOR(block, R64(RTREG), R64(RSREG), UIMMVAL);               // dxor    <rtreg>,<rsreg>,UIMMVAL
1487 			return true;
1488 
1489 		case 0x0a:  /* SLTI - MIPS I */
1490 			if (RTREG != 0)
1491 			{
1492 				UML_DCMP(block, R64(RSREG), SIMMVAL);                           // dcmp    <rsreg>,SIMMVAL
1493 				UML_DSETc(block, COND_L, R64(RTREG));                                   // dset    <rtreg>,l
1494 			}
1495 			return true;
1496 
1497 		case 0x0b:  /* SLTIU - MIPS I */
1498 			if (RTREG != 0)
1499 			{
1500 				UML_DCMP(block, R64(RSREG), SIMMVAL);                           // dcmp    <rsreg>,SIMMVAL
1501 				UML_DSETc(block, COND_B, R64(RTREG));                                   // dset    <rtreg>,b
1502 			}
1503 			return true;
1504 
1505 
1506 		/* ----- memory load operations ----- */
1507 
1508 		case 0x20:  /* LB - MIPS I */
1509 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1510 			UML_CALLH(block, *m_read8[m_core->mode >> 1]);  // callh   read8
1511 			if (RTREG != 0)
1512 				UML_DSEXT(block, R64(RTREG), I0, SIZE_BYTE);                        // dsext   <rtreg>,i0,byte
1513 			if (!in_delay_slot)
1514 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1515 			return true;
1516 
1517 		case 0x21:  /* LH - MIPS I */
1518 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1519 			UML_CALLH(block, *m_read16[m_core->mode >> 1]); // callh   read16
1520 			if (RTREG != 0)
1521 				UML_DSEXT(block, R64(RTREG), I0, SIZE_WORD);                        // dsext   <rtreg>,i0,word
1522 			if (!in_delay_slot)
1523 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1524 			return true;
1525 
1526 		case 0x23:  /* LW - MIPS I */
1527 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1528 			UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh   read32
1529 			if (RTREG != 0)
1530 				UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD);                       // dsext   <rtreg>,i0
1531 			if (!in_delay_slot)
1532 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1533 			return true;
1534 
1535 		case 0x30:  /* LL - MIPS II */
1536 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1537 			UML_MOV(block, mem(&m_core->cpr[0][COP0_LLAddr]), I0);          // mov     [LLAddr],i0
1538 			UML_CALLH(block, *m_read32[m_core->mode >> 1]);                 // callh   read32
1539 			if (RTREG != 0)
1540 				UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD);               // dsext   <rtreg>,i0
1541 			UML_MOV(block, mem(&m_core->llbit), 1);                         // mov     [llbit],1
1542 			if (!in_delay_slot)
1543 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1544 			if LL_BREAK
1545 				UML_CALLC(block, cfunc_debug_break, this);                  // callc   cfunc_debug_break,nullptr
1546 			return true;
1547 
1548 		case 0x24:  /* LBU - MIPS I */
1549 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1550 			UML_CALLH(block, *m_read8[m_core->mode >> 1]);  // callh   read8
1551 			if (RTREG != 0)
1552 				UML_DAND(block, R64(RTREG), I0, 0xff);                  // dand    <rtreg>,i0,0xff
1553 			if (!in_delay_slot)
1554 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1555 			return true;
1556 
1557 		case 0x25:  /* LHU - MIPS I */
1558 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1559 			UML_CALLH(block, *m_read16[m_core->mode >> 1]); // callh   read16
1560 			if (RTREG != 0)
1561 				UML_DAND(block, R64(RTREG), I0, 0xffff);                    // dand    <rtreg>,i0,0xffff
1562 			if (!in_delay_slot)
1563 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1564 			return true;
1565 
1566 		case 0x27:  /* LWU - MIPS III */
1567 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1568 			UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh   read32
1569 			if (RTREG != 0)
1570 				UML_DAND(block, R64(RTREG), I0, 0xffffffff);                // dand    <rtreg>,i0,0xffffffff
1571 			if (!in_delay_slot)
1572 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1573 			return true;
1574 
1575 		case 0x37:  /* LD - MIPS III */
1576 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1577 			UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh   read64
1578 			if (RTREG != 0)
1579 				UML_DMOV(block, R64(RTREG), I0);                                // dmov    <rtreg>,i0
1580 			if (!in_delay_slot)
1581 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1582 			return true;
1583 
1584 		case 0x34:  /* LLD - MIPS III */
1585 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1586 			UML_MOV(block, mem(&m_core->cpr[0][COP0_LLAddr]), I0);          // mov     [LLAddr],i0
1587 			UML_CALLH(block, *m_read64[m_core->mode >> 1]);                 // callh   read64
1588 			if (RTREG != 0)
1589 				UML_DMOV(block, R64(RTREG), I0);                            // dmov    <rtreg>,i0
1590 			UML_MOV(block, mem(&m_core->llbit), 1);                         // mov     [llbit],1
1591 			if (!in_delay_slot)
1592 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1593 			if LL_BREAK
1594 				UML_CALLC(block, cfunc_debug_break, this);                  // callc   cfunc_debug_break,nullptr
1595 			return true;
1596 
1597 		case 0x22:  /* LWL - MIPS I */
1598 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1599 			UML_SHL(block, I1, I0, 3);                              // shl     i1,i0,3
1600 			UML_AND(block, I0, I0, ~3);                             // and     i0,i0,~3
1601 			if (!m_bigendian)
1602 				UML_XOR(block, I1, I1, 0x18);                       // xor     i1,i1,0x18
1603 			UML_SHR(block, I2, ~0, I1);                             // shr     i2,~0,i1
1604 			UML_CALLH(block, *m_read32mask[m_core->mode >> 1]);
1605 																					// callh   read32mask
1606 			if (RTREG != 0)
1607 			{
1608 				UML_SHL(block, I2, ~0, I1);                         // shl     i2,~0,i1
1609 				UML_MOV(block, I3, R32(RTREG));                             // mov     i3,<rtreg>
1610 				UML_ROLINS(block, I3, I0, I1, I2);              // rolins  i3,i0,i1,i2
1611 				UML_DSEXT(block, R64(RTREG), I3, SIZE_DWORD);                       // dsext   <rtreg>,i3,dword
1612 			}
1613 			if (!in_delay_slot)
1614 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1615 			return true;
1616 
1617 		case 0x26:  /* LWR - MIPS I */
1618 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1619 			UML_SHL(block, I1, I0, 3);                              // shl     i1,i0,3
1620 			UML_AND(block, I0, I0, ~3);                             // and     i0,i0,~3
1621 			if (m_bigendian)
1622 				UML_XOR(block, I1, I1, 0x18);                       // xor     i1,i1,0x18
1623 			UML_SHL(block, I2, ~0, I1);                             // shl     i2,~0,i1
1624 			UML_CALLH(block, *m_read32mask[m_core->mode >> 1]);
1625 																					// callh   read32mask
1626 			if (RTREG != 0)
1627 			{
1628 				UML_SHR(block, I2, ~0, I1);                         // shr     i2,~0,i1
1629 				UML_SUB(block, I1, 32, I1);                         // sub     i1,32,i1
1630 				UML_MOV(block, I3, R32(RTREG));                             // mov     i3,<rtreg>
1631 				UML_ROLINS(block, I3, I0, I1, I2);              // rolins  i3,i0,i1,i2
1632 				UML_DSEXT(block, R64(RTREG), I3, SIZE_DWORD);                       // dsext   <rtreg>,i3,dword
1633 			}
1634 			if (!in_delay_slot)
1635 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1636 			return true;
1637 
1638 		case 0x1a:  /* LDL - MIPS III */
1639 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1640 			UML_SHL(block, I1, I0, 3);                              // shl     i1,i0,3
1641 			UML_AND(block, I0, I0, ~7);                             // and     i0,i0,~7
1642 			if (!m_bigendian)
1643 				UML_XOR(block, I1, I1, 0x38);                       // xor     i1,i1,0x38
1644 			UML_DSHR(block, I2, (uint64_t)~0, I1);                        // dshr    i2,~0,i1
1645 			UML_CALLH(block, *m_read64mask[m_core->mode >> 1]);
1646 																					// callh   read64mask
1647 			if (RTREG != 0)
1648 			{
1649 				UML_DSHL(block, I2, (uint64_t)~0, I1);                    // dshl    i2,~0,i1
1650 				UML_DROLINS(block, R64(RTREG), I0, I1, I2);         // drolins <rtreg>,i0,i1,i2
1651 			}
1652 			if (!in_delay_slot)
1653 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1654 			return true;
1655 
1656 		case 0x1b:  /* LDR - MIPS III */
1657 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);            // add     i0,<rsreg>,SIMMVAL
1658 			UML_SHL(block, I1, I0, 3);                          // shl     i1,i0,3
1659 			UML_AND(block, I0, I0, ~7);                         // and     i0,i0,~7
1660 			if (m_bigendian)
1661 				UML_XOR(block, I1, I1, 0x38);                   // xor     i1,i1,0x38
1662 			UML_DSHL(block, I2, (uint64_t)~0, I1);                // dshl    i2,~0,i1
1663 			UML_CALLH(block, *m_read64mask[m_core->mode >> 1]); // callh   read64mask
1664 			if (RTREG != 0)
1665 			{
1666 				UML_DSHR(block, I2, (uint64_t)~0, I1);            // dshr    i2,~0,i1
1667 				UML_SUB(block, I1, 64, I1);                     // sub     i1,64,i1
1668 				UML_DROLINS(block, R64(RTREG), I0, I1, I2);     // drolins <rtreg>,i0,i1,i2
1669 			}
1670 			if (!in_delay_slot)
1671 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1672 			return true;
1673 
1674 		case 0x31:  /* LWC1 - MIPS I */
1675 			check_cop1_access(block);
1676 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);        // add     i0,<rsreg>,SIMMVAL
1677 			UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh   read32
1678 			UML_MOV(block, FPR32(RTREG), I0);           // mov     <cpr1_rt>,i0
1679 			if (!in_delay_slot)
1680 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1681 			return true;
1682 
1683 		case 0x35:  /* LDC1 - MIPS III */
1684 			check_cop1_access(block);
1685 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);        // add     i0,<rsreg>,SIMMVAL
1686 			UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh   read64
1687 			UML_DMOV(block, FPR64(RTREG), I0);              // dmov    <cpr1_rt>,i0
1688 			if (!in_delay_slot)
1689 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1690 			return true;
1691 
1692 		case 0x32:  /* LWC2 - MIPS I */
1693 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1694 			UML_CALLH(block, *m_read32[m_core->mode >> 1]); // callh   read32
1695 			UML_DAND(block, CPR264(RTREG), I0, 0xffffffff);             // dand    <cpr2_rt>,i0,0xffffffff
1696 			if (!in_delay_slot)
1697 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1698 			return true;
1699 
1700 		case 0x36:  /* LDC2 - MIPS II */
1701 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1702 			UML_CALLH(block, *m_read64[m_core->mode >> 1]); // callh   read64
1703 			UML_DMOV(block, CPR264(RTREG), I0);                             // dmov    <cpr2_rt>,i0
1704 			if (!in_delay_slot)
1705 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1706 			return true;
1707 
1708 
1709 		/* ----- memory store operations ----- */
1710 
1711 		case 0x28:  /* SB - MIPS I */
1712 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1713 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1714 			UML_CALLH(block, *m_write8[m_core->mode >> 1]); // callh   write8
1715 			if (!in_delay_slot)
1716 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1717 			return true;
1718 
1719 		case 0x29:  /* SH - MIPS I */
1720 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1721 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1722 			UML_CALLH(block, *m_write16[m_core->mode >> 1]);    // callh   write16
1723 			if (!in_delay_slot)
1724 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1725 			return true;
1726 
1727 		case 0x2b:  /* SW - MIPS I */
1728 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1729 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1730 			UML_CALLH(block, *m_write32[m_core->mode >> 1]);    // callh   write32
1731 			if (!in_delay_slot)
1732 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1733 			return true;
1734 
1735 		case 0x38:  /* SC - MIPS II */
1736 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1737 			UML_MOV(block, R32(RTREG), 0);                                  // mov     <rtreg>, 0
1738 			UML_CMP(block, mem(&m_core->llbit), 0);                         // cmp     [llbit],0
1739 			UML_JMPc(block, COND_E, skip = compiler.labelnum++);            // je      skip
1740 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1741 			UML_CMP(block, mem(&m_core->cpr[0][COP0_LLAddr]), I0);          // cmp [LLADDR], RSREG + SIMMVAL
1742 			UML_JMPc(block, COND_NE, skip);                                 // jne      skip
1743 			UML_CALLH(block, *m_write32[m_core->mode >> 1]);                // callh   write32
1744 			UML_MOV(block, R32(RTREG), 1);                                  // mov     <rtreg>, 0
1745 			UML_LABEL(block, skip);                                         // skip:
1746 			if (!in_delay_slot)
1747 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1748 			return true;
1749 
1750 		case 0x3f:  /* SD - MIPS III */
1751 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1752 			UML_DMOV(block, I1, R64(RTREG));                                // dmov    i1,<rtreg>
1753 			UML_CALLH(block, *m_write64[m_core->mode >> 1]);    // callh   write64
1754 			if (!in_delay_slot)
1755 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1756 			return true;
1757 
1758 		case 0x3c:  /* SCD - MIPS III */
1759 			UML_DMOV(block, I1, R64(RTREG));                                    // dmov    i1,<rtreg>
1760 			UML_DMOV(block, R64(RTREG), 0);                                     // dmov   <rtreg>,0
1761 			UML_CMP(block, mem(&m_core->llbit), 0);                             // cmp     [llbit],0
1762 			UML_JMPc(block, COND_E, skip = compiler.labelnum++);                // je      skip
1763 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                            // add     i0,<rsreg>,SIMMVAL
1764 			UML_CMP(block, mem(&m_core->cpr[0][COP0_LLAddr]), I0);              // cmp [LLADDR], RSREG + SIMMVAL
1765 			UML_JMPc(block, COND_NE, skip);                                     // jne      skip
1766 			UML_CALLH(block, *m_write64[m_core->mode >> 1]);                    // callh   write64
1767 			UML_DMOV(block, R64(RTREG), 1);                                     // dmov   <rtreg>,1
1768 			UML_LABEL(block, skip);                                             // skip:
1769 			if (!in_delay_slot)
1770 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1771 			return true;
1772 
1773 		case 0x2a:  /* SWL - MIPS I */
1774 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1775 			UML_SHL(block, I3, I0, 3);                              // shl     i3,i0,3
1776 			UML_AND(block, I0, I0, ~3);                             // and     i0,i0,~3
1777 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1778 			if (!m_bigendian)
1779 				UML_XOR(block, I3, I3, 0x18);                       // xor     i3,i3,0x18
1780 			UML_SHR(block, I2, ~0, I3);                             // shr     i2,~0,i3
1781 			UML_SHR(block, I1, I1, I3);                             // shr     i1,i1,i3
1782 			UML_CALLH(block, *m_write32mask[m_core->mode >> 1]);
1783 																					// callh   write32mask
1784 			if (!in_delay_slot)
1785 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1786 			return true;
1787 
1788 		case 0x2e:  /* SWR - MIPS I */
1789 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1790 			UML_SHL(block, I3, I0, 3);                              // shl     i3,i0,3
1791 			UML_AND(block, I0, I0, ~3);                             // and     i0,i0,~3
1792 			UML_MOV(block, I1, R32(RTREG));                                 // mov     i1,<rtreg>
1793 			if (m_bigendian)
1794 				UML_XOR(block, I3, I3, 0x18);                       // xor     i3,i3,0x18
1795 			UML_SHL(block, I2, ~0, I3);                             // shl     i2,~0,i3
1796 			UML_SHL(block, I1, I1, I3);                             // shl     i1,i1,i3
1797 			UML_CALLH(block, *m_write32mask[m_core->mode >> 1]);
1798 																					// callh   write32mask
1799 			if (!in_delay_slot)
1800 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1801 			return true;
1802 
1803 		case 0x2c:  /* SDL - MIPS III */
1804 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);            // add     i0,<rsreg>,SIMMVAL
1805 			UML_SHL(block, I3, I0, 3);                          // shl     i3,i0,3
1806 			UML_AND(block, I0, I0, ~7);                         // and     i0,i0,~7
1807 			UML_DMOV(block, I1, R64(RTREG));                    // dmov    i1,<rtreg>
1808 			if (!m_bigendian)
1809 				UML_XOR(block, I3, I3, 0x38);                   // xor     i3,i3,0x38
1810 			UML_DSHR(block, I2, (uint64_t)~0, I3);                // dshr    i2,~0,i3
1811 			UML_DSHR(block, I1, I1, I3);                        // dshr    i1,i1,i3
1812 			UML_CALLH(block, *m_write64mask[m_core->mode >> 1]);// callh   write64mask
1813 
1814 			if (!in_delay_slot)
1815 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1816 			return true;
1817 
1818 		case 0x2d:  /* SDR - MIPS III */
1819 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);            // add     i0,<rsreg>,SIMMVAL
1820 			UML_SHL(block, I3, I0, 3);                          // shl     i3,i0,3
1821 			UML_AND(block, I0, I0, ~7);                         // and     i0,i0,~7
1822 			UML_DMOV(block, I1, R64(RTREG));                    // dmov    i1,<rtreg>
1823 			if (m_bigendian)
1824 				UML_XOR(block, I3, I3, 0x38);                   // xor     i3,i3,0x38
1825 			UML_DSHL(block, I2, (uint64_t)~0, I3);                // dshl    i2,~0,i3
1826 			UML_DSHL(block, I1, I1, I3);                        // dshl    i1,i1,i3
1827 			UML_CALLH(block, *m_write64mask[m_core->mode >> 1]);// callh   write64mask
1828 
1829 			if (!in_delay_slot)
1830 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1831 			return true;
1832 
1833 		case 0x39:  /* SWC1 - MIPS I */
1834 			check_cop1_access(block);
1835 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);            // add     i0,<rsreg>,SIMMVAL
1836 			UML_MOV(block, I1, FPR32(RTREG));                   // mov     i1,<cpr1_rt>
1837 			UML_CALLH(block, *m_write32[m_core->mode >> 1]);    // callh   write32
1838 			if (!in_delay_slot)
1839 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1840 			return true;
1841 
1842 		case 0x3d:  /* SDC1 - MIPS III */
1843 			check_cop1_access(block);
1844 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);            // add     i0,<rsreg>,SIMMVAL
1845 			UML_DMOV(block, I1, FPR64(RTREG));                  // dmov    i1,<cpr1_rt>
1846 			UML_CALLH(block, *m_write64[m_core->mode >> 1]);    // callh   write64
1847 			if (!in_delay_slot)
1848 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1849 			return true;
1850 
1851 		case 0x3a:  /* SWC2 - MIPS I */
1852 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1853 			UML_MOV(block, I1, CPR232(RTREG));                                  // mov     i1,<cpr2_rt>
1854 			UML_CALLH(block, *m_write32[m_core->mode >> 1]);    // callh   write32
1855 			if (!in_delay_slot)
1856 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1857 			return true;
1858 
1859 		case 0x3e:  /* SDC2 - MIPS II */
1860 			UML_ADD(block, I0, R32(RSREG), SIMMVAL);                        // add     i0,<rsreg>,SIMMVAL
1861 			UML_DMOV(block, I1, CPR264(RTREG));                             // dmov    i1,<cpr2_rt>
1862 			UML_CALLH(block, *m_write64[m_core->mode >> 1]);    // callh   write64
1863 			if (!in_delay_slot)
1864 				generate_update_cycles(block, compiler, desc->pc + 4, true);
1865 			return true;
1866 
1867 
1868 		/* ----- effective no-ops ----- */
1869 
1870 		case 0x2f:  /* CACHE - MIPS II */
1871 		case 0x33:  /* PREF - MIPS IV */
1872 			return true;
1873 
1874 
1875 		/* ----- coprocessor instructions ----- */
1876 
1877 		case 0x10:  /* COP0 - MIPS I */
1878 			return generate_cop0(block, compiler, desc);
1879 
1880 		case 0x11:  /* COP1 - MIPS I */
1881 			return generate_cop1(block, compiler, desc);
1882 
1883 		case 0x13:  /* COP1X - MIPS IV */
1884 			return generate_cop1x(block, compiler, desc);
1885 
1886 		case 0x12:  /* COP2 - MIPS I */
1887 			UML_EXH(block, *m_exception[EXCEPTION_INVALIDOP], 0);// exh     invalidop,0
1888 			return true;
1889 
1890 
1891 		/* ----- unimplemented/illegal instructions ----- */
1892 
1893 //      default:    /* ??? */       invalid_instruction(op);                                                break;
1894 	}
1895 
1896 	return false;
1897 }
1898 
1899 
1900 /*-------------------------------------------------
1901     generate_special - compile opcodes in the
1902     'SPECIAL' group
1903 -------------------------------------------------*/
1904 
generate_special(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)1905 bool mips3_device::generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
1906 {
1907 	uint32_t op = desc->opptr.l[0];
1908 	uint8_t opswitch = op & 63;
1909 
1910 	switch (opswitch)
1911 	{
1912 		/* ----- shift instructions ----- */
1913 
1914 		case 0x00:  /* SLL - MIPS I */
1915 			if (RDREG != 0)
1916 			{
1917 				UML_SHL(block, I0, R32(RTREG), SHIFT);                  // shl     i0,<rtreg>,<shift>
1918 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1919 			}
1920 			return true;
1921 
1922 		case 0x02:  /* SRL - MIPS I */
1923 			if (RDREG != 0)
1924 			{
1925 				UML_SHR(block, I0, R32(RTREG), SHIFT);                  // shr     i0,<rtreg>,<shift>
1926 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1927 			}
1928 			return true;
1929 
1930 		case 0x03:  /* SRA - MIPS I */
1931 			if (RDREG != 0)
1932 			{
1933 				UML_SAR(block, I0, R32(RTREG), SHIFT);                  // sar     i0,<rtreg>,<shift>
1934 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1935 			}
1936 			return true;
1937 
1938 		case 0x04:  /* SLLV - MIPS I */
1939 			if (RDREG != 0)
1940 			{
1941 				UML_SHL(block, I0, R32(RTREG), R32(RSREG));                 // shl     i0,<rtreg>,<rsreg>
1942 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1943 			}
1944 			return true;
1945 
1946 		case 0x06:  /* SRLV - MIPS I */
1947 			if (RDREG != 0)
1948 			{
1949 				UML_SHR(block, I0, R32(RTREG), R32(RSREG));                 // shr     i0,<rtreg>,<rsreg>
1950 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1951 			}
1952 			return true;
1953 
1954 		case 0x07:  /* SRAV - MIPS I */
1955 			if (RDREG != 0)
1956 			{
1957 				UML_SAR(block, I0, R32(RTREG), R32(RSREG));                 // sar     i0,<rtreg>,<rsreg>
1958 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
1959 			}
1960 			return true;
1961 
1962 		case 0x38:  /* DSLL - MIPS III */
1963 			if (RDREG != 0)
1964 				UML_DSHL(block, R64(RDREG), R64(RTREG), SHIFT);             // dshl    <rdreg>,<rtreg>,<shift>
1965 			return true;
1966 
1967 		case 0x3a:  /* DSRL - MIPS III */
1968 			if (RDREG != 0)
1969 				UML_DSHR(block, R64(RDREG), R64(RTREG), SHIFT);             // dshr    <rdreg>,<rtreg>,<shift>
1970 			return true;
1971 
1972 		case 0x3b:  /* DSRA - MIPS III */
1973 			if (RDREG != 0)
1974 				UML_DSAR(block, R64(RDREG), R64(RTREG), SHIFT);             // dsar    <rdreg>,<rtreg>,<shift>
1975 			return true;
1976 
1977 		case 0x3c:  /* DSLL32 - MIPS III */
1978 			if (RDREG != 0)
1979 				UML_DSHL(block, R64(RDREG), R64(RTREG), SHIFT + 32);            // dshl    <rdreg>,<rtreg>,<shift>+32
1980 			return true;
1981 
1982 		case 0x3e:  /* DSRL32 - MIPS III */
1983 			if (RDREG != 0)
1984 				UML_DSHR(block, R64(RDREG), R64(RTREG), SHIFT + 32);            // dshr    <rdreg>,<rtreg>,<shift>+32
1985 			return true;
1986 
1987 		case 0x3f:  /* DSRA32 - MIPS III */
1988 			if (RDREG != 0)
1989 				UML_DSAR(block, R64(RDREG), R64(RTREG), SHIFT + 32);            // dsar    <rdreg>,<rtreg>,<shift>+32
1990 			return true;
1991 
1992 		case 0x14:  /* DSLLV - MIPS III */
1993 			if (RDREG != 0)
1994 				UML_DSHL(block, R64(RDREG), R64(RTREG), R64(RSREG));                // dshl    <rdreg>,<rtreg>,<rsreg>
1995 			return true;
1996 
1997 		case 0x16:  /* DSRLV - MIPS III */
1998 			if (RDREG != 0)
1999 				UML_DSHR(block, R64(RDREG), R64(RTREG), R64(RSREG));                // dshr    <rdreg>,<rtreg>,<rsreg>
2000 			return true;
2001 
2002 		case 0x17:  /* DSRAV - MIPS III */
2003 			if (RDREG != 0)
2004 				UML_DSAR(block, R64(RDREG), R64(RTREG), R64(RSREG));                // dsar    <rdreg>,<rtreg>,<rsreg>
2005 			return true;
2006 
2007 
2008 		/* ----- basic arithmetic ----- */
2009 
2010 		case 0x20:  /* ADD - MIPS I */
2011 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
2012 			{
2013 				UML_ADD(block, I0, R32(RSREG), R32(RTREG));                 // add     i0,<rsreg>,<rtreg>
2014 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
2015 																					// exh     overflow,0,V
2016 				if (RDREG != 0)
2017 					UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                   // dsext   <rdreg>,i0,dword
2018 			}
2019 			else if (RDREG != 0)
2020 			{
2021 				UML_ADD(block, I0, R32(RSREG), R32(RTREG));                 // add     i0,<rsreg>,<rtreg>
2022 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
2023 			}
2024 			return true;
2025 
2026 		case 0x21:  /* ADDU - MIPS I */
2027 			if (RDREG != 0)
2028 			{
2029 				UML_ADD(block, I0, R32(RSREG), R32(RTREG));                 // add     i0,<rsreg>,<rtreg>
2030 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
2031 			}
2032 			return true;
2033 
2034 		case 0x2c:  /* DADD - MIPS III */
2035 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
2036 			{
2037 				UML_DADD(block, I0, R64(RSREG), R64(RTREG));                    // dadd    i0,<rsreg>,<rtreg>
2038 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
2039 																					// exh     overflow,0,V
2040 				if (RDREG != 0)
2041 					UML_DMOV(block, R64(RDREG), I0);                            // dmov    <rdreg>,i0
2042 			}
2043 			else if (RDREG != 0)
2044 				UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dadd    <rdreg>,<rsreg>,<rtreg>
2045 			return true;
2046 
2047 		case 0x2d:  /* DADDU - MIPS III */
2048 			if (RDREG != 0)
2049 				UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dadd    <rdreg>,<rsreg>,<rtreg>
2050 			return true;
2051 
2052 		case 0x22:  /* SUB - MIPS I */
2053 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
2054 			{
2055 				UML_SUB(block, I0, R32(RSREG), R32(RTREG));                 // sub     i0,<rsreg>,<rtreg>
2056 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
2057 																					// exh     overflow,0,V
2058 				if (RDREG != 0)
2059 					UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                   // dsext   <rdreg>,i0,dword
2060 			}
2061 			else if (RDREG != 0)
2062 			{
2063 				UML_SUB(block, I0, R32(RSREG), R32(RTREG));                 // sub     i0,<rsreg>,<rtreg>
2064 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
2065 			}
2066 			return true;
2067 
2068 		case 0x23:  /* SUBU - MIPS I */
2069 			if (RDREG != 0)
2070 			{
2071 				UML_SUB(block, I0, R32(RSREG), R32(RTREG));                 // sub     i0,<rsreg>,<rtreg>
2072 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                       // dsext   <rdreg>,i0,dword
2073 			}
2074 			return true;
2075 
2076 		case 0x2e:  /* DSUB - MIPS III */
2077 			if (m_drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
2078 			{
2079 				UML_DSUB(block, I0, R64(RSREG), R64(RTREG));                    // dsub    i0,<rsreg>,<rtreg>
2080 				UML_EXHc(block, COND_V, *m_exception[EXCEPTION_OVERFLOW], 0);
2081 																					// exh     overflow,0,V
2082 				if (RDREG != 0)
2083 					UML_DMOV(block, R64(RDREG), I0);                            // dmov    <rdreg>,i0
2084 			}
2085 			else if (RDREG != 0)
2086 				UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dsub    <rdreg>,<rsreg>,<rtreg>
2087 			return true;
2088 
2089 		case 0x2f:  /* DSUBU - MIPS III */
2090 			if (RDREG != 0)
2091 				UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dsub    <rdreg>,<rsreg>,<rtreg>
2092 			return true;
2093 
2094 		case 0x18:  /* MULT - MIPS I */
2095 			UML_MULS(block, I0, I1, R32(RSREG), R32(RTREG));                // muls    i0,i1,<rsreg>,<rtreg>
2096 			UML_DSEXT(block, LO64, I0, SIZE_DWORD);                                 // dsext   lo,i0,dword
2097 			UML_DSEXT(block, HI64, I1, SIZE_DWORD);                                 // dsext   hi,i1,dword
2098 			return true;
2099 
2100 		case 0x19:  /* MULTU - MIPS I */
2101 			UML_MULU(block, I0, I1, R32(RSREG), R32(RTREG));                // mulu    i0,i1,<rsreg>,<rtreg>
2102 			UML_DSEXT(block, LO64, I0, SIZE_DWORD);                                 // dsext   lo,i0,dword
2103 			UML_DSEXT(block, HI64, I1, SIZE_DWORD);                                 // dsext   hi,i1,dword
2104 			return true;
2105 
2106 		case 0x1c:  /* DMULT - MIPS III */
2107 			UML_DMULS(block, LO64, HI64, R64(RSREG), R64(RTREG));
2108 			return true;
2109 
2110 		case 0x1d:  /* DMULTU - MIPS III */
2111 			UML_DMULU(block, LO64, HI64, R64(RSREG), R64(RTREG));
2112 			return true;
2113 
2114 		case 0x1a:  /* DIV - MIPS I */
2115 			UML_DIVS(block, I0, I1, R32(RSREG), R32(RTREG));                    // divs    i0,i1,<rsreg>,<rtreg>
2116 			UML_DSEXT(block, LO64, I0, SIZE_DWORD);                             // dsext   lo,i0,dword
2117 			UML_DSEXT(block, HI64, I1, SIZE_DWORD);                             // dsext   hi,i1,dword
2118 			return true;
2119 
2120 		case 0x1b:  /* DIVU - MIPS I */
2121 			UML_DIVU(block, I0, I1, R32(RSREG), R32(RTREG));                    // divu    i0,i1,<rsreg>,<rtreg>
2122 			UML_DSEXT(block, LO64, I0, SIZE_DWORD);                             // dsext   lo,i0,dword
2123 			UML_DSEXT(block, HI64, I1, SIZE_DWORD);                             // dsext   hi,i1,dword
2124 			return true;
2125 
2126 		case 0x1e:  /* DDIV - MIPS III */
2127 			UML_DDIVS(block, LO64, HI64, R64(RSREG), R64(RTREG));                   // ddivs    lo,hi,<rsreg>,<rtreg>
2128 			return true;
2129 
2130 		case 0x1f:  /* DDIVU - MIPS III */
2131 			UML_DDIVU(block, LO64, HI64, R64(RSREG), R64(RTREG));                   // ddivu    lo,hi,<rsreg>,<rtreg>
2132 			return true;
2133 
2134 
2135 		/* ----- basic logical ops ----- */
2136 
2137 		case 0x24:  /* AND - MIPS I */
2138 			if (RDREG != 0)
2139 				UML_DAND(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dand     <rdreg>,<rsreg>,<rtreg>
2140 			return true;
2141 
2142 		case 0x25:  /* OR - MIPS I */
2143 			if (RDREG != 0)
2144 				UML_DOR(block, R64(RDREG), R64(RSREG), R64(RTREG));                 // dor      <rdreg>,<rsreg>,<rtreg>
2145 			return true;
2146 
2147 		case 0x26:  /* XOR - MIPS I */
2148 			if (RDREG != 0)
2149 				UML_DXOR(block, R64(RDREG), R64(RSREG), R64(RTREG));                // dxor     <rdreg>,<rsreg>,<rtreg>
2150 			return true;
2151 
2152 		case 0x27:  /* NOR - MIPS I */
2153 			if (RDREG != 0)
2154 			{
2155 				UML_DOR(block, I0, R64(RSREG), R64(RTREG));                 // dor      i0,<rsreg>,<rtreg>
2156 				UML_DXOR(block, R64(RDREG), I0, (uint64_t)~0);                // dxor     <rdreg>,i0,~0
2157 			}
2158 			return true;
2159 
2160 
2161 		/* ----- basic comparisons ----- */
2162 
2163 		case 0x2a:  /* SLT - MIPS I */
2164 			if (RDREG != 0)
2165 			{
2166 				UML_DCMP(block, R64(RSREG), R64(RTREG));                            // dcmp    <rsreg>,<rtreg>
2167 				UML_DSETc(block, COND_L, R64(RDREG));                                   // dset    <rdreg>,l
2168 			}
2169 			return true;
2170 
2171 		case 0x2b:  /* SLTU - MIPS I */
2172 			if (RDREG != 0)
2173 			{
2174 				UML_DCMP(block, R64(RSREG), R64(RTREG));                            // dcmp    <rsreg>,<rtreg>
2175 				UML_DSETc(block, COND_B, R64(RDREG));                                   // dset    <rdreg>,b
2176 			}
2177 			return true;
2178 
2179 
2180 		/* ----- conditional traps ----- */
2181 
2182 		case 0x30:  /* TGE - MIPS II */
2183 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2184 			UML_EXHc(block, COND_GE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,GE
2185 			return true;
2186 
2187 		case 0x31:  /* TGEU - MIPS II */
2188 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2189 			UML_EXHc(block, COND_AE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,AE
2190 			return true;
2191 
2192 		case 0x32:  /* TLT - MIPS II */
2193 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2194 			UML_EXHc(block, COND_L, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,LT
2195 			return true;
2196 
2197 		case 0x33:  /* TLTU - MIPS II */
2198 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2199 			UML_EXHc(block, COND_B, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,B
2200 			return true;
2201 
2202 		case 0x34:  /* TEQ - MIPS II */
2203 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2204 			UML_EXHc(block, COND_E, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,E
2205 			return true;
2206 
2207 		case 0x36:  /* TNE - MIPS II */
2208 			UML_DCMP(block, R64(RSREG), R64(RTREG));                                // dcmp    <rsreg>,<rtreg>
2209 			UML_EXHc(block, COND_NE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,NE
2210 			return true;
2211 
2212 
2213 		/* ----- conditional moves ----- */
2214 
2215 		case 0x0a:  /* MOVZ - MIPS IV */
2216 			if (RDREG != 0)
2217 			{
2218 				UML_DCMP(block, R64(RTREG), 0);                             // dcmp    <rtreg>,0
2219 				UML_DMOVc(block, COND_Z, R64(RDREG), R64(RSREG));                       // dmov    <rdreg>,<rsreg>,Z
2220 			}
2221 			return true;
2222 
2223 		case 0x0b:  /* MOVN - MIPS IV */
2224 			if (RDREG != 0)
2225 			{
2226 				UML_DCMP(block, R64(RTREG), 0);                             // dcmp    <rtreg>,0
2227 				UML_DMOVc(block, COND_NZ, R64(RDREG), R64(RSREG));                  // dmov    <rdreg>,<rsreg>,NZ
2228 			}
2229 			return true;
2230 
2231 		case 0x01:  /* MOVF/MOVT - MIPS IV */
2232 			if (RDREG != 0)
2233 			{
2234 				UML_TEST(block, CCR132(31), FCCMASK(op >> 18));             // test    ccr31,fcc_mask[x]
2235 				UML_DMOVc(block, ((op >> 16) & 1) ? COND_NZ : COND_Z, R64(RDREG), R64(RSREG));
2236 																					// dmov    <rdreg>,<rsreg>,NZ/Z
2237 			}
2238 			return true;
2239 
2240 
2241 		/* ----- jumps and branches ----- */
2242 
2243 		case 0x08:  /* JR - MIPS I */
2244 			generate_delay_slot_and_branch(block, compiler, desc, 0);        // <next instruction + hashjmp>
2245 			return true;
2246 
2247 		case 0x09:  /* JALR - MIPS I */
2248 			generate_delay_slot_and_branch(block, compiler, desc, RDREG);    // <next instruction + hashjmp>
2249 			return true;
2250 
2251 
2252 		/* ----- system calls ----- */
2253 
2254 		case 0x0c:  /* SYSCALL - MIPS I */
2255 			UML_EXH(block, *m_exception[EXCEPTION_SYSCALL], 0);  // exh     syscall,0
2256 			return true;
2257 
2258 		case 0x0d:  /* BREAK - MIPS I */
2259 			UML_EXH(block, *m_exception[EXCEPTION_BREAK], 0);    // exh     break,0
2260 			return true;
2261 
2262 
2263 		/* ----- effective no-ops ----- */
2264 
2265 		case 0x0f:  /* SYNC - MIPS II */
2266 			return true;
2267 
2268 
2269 		/* ----- hi/lo register access ----- */
2270 
2271 		case 0x10:  /* MFHI - MIPS I */
2272 			if (RDREG != 0)
2273 				UML_DMOV(block, R64(RDREG), HI64);                                  // dmov    <rdreg>,hi
2274 			return true;
2275 
2276 		case 0x11:  /* MTHI - MIPS I */
2277 			UML_DMOV(block, HI64, R64(RSREG));                                      // dmov    hi,<rsreg>
2278 			return true;
2279 
2280 		case 0x12:  /* MFLO - MIPS I */
2281 			if (RDREG != 0)
2282 				UML_DMOV(block, R64(RDREG), LO64);                                  // dmov    <rdreg>,lo
2283 			return true;
2284 
2285 		case 0x13:  /* MTLO - MIPS I */
2286 			UML_DMOV(block, LO64, R64(RSREG));                                      // dmov    lo,<rsreg>
2287 			return true;
2288 	}
2289 	return false;
2290 }
2291 
2292 
2293 /*-------------------------------------------------
2294     generate_regimm - compile opcodes in the
2295     'REGIMM' group
2296 -------------------------------------------------*/
2297 
generate_regimm(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)2298 bool mips3_device::generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
2299 {
2300 	uint32_t op = desc->opptr.l[0];
2301 	uint8_t opswitch = RTREG;
2302 	uml::code_label skip;
2303 
2304 	switch (opswitch)
2305 	{
2306 		case 0x00:  /* BLTZ */
2307 		case 0x02:  /* BLTZL */
2308 		case 0x10:  /* BLTZAL */
2309 		case 0x12:  /* BLTZALL */
2310 			if (opswitch & 0x10)
2311 			{
2312 				UML_DMOV(block, R64(31), (int32_t)(desc->pc + 8));
2313 			}
2314 			if (RSREG != 0)
2315 			{
2316 				UML_DCMP(block, R64(RSREG), 0);                             // dcmp    <rsreg>,0
2317 				UML_JMPc(block, COND_GE, skip = compiler.labelnum++);              // jmp     skip,GE
2318 				generate_delay_slot_and_branch(block, compiler, desc, 0);
2319 																					// <next instruction + hashjmp>
2320 				UML_LABEL(block, skip);                                         // skip:
2321 			}
2322 			return true;
2323 
2324 		case 0x01:  /* BGEZ */
2325 		case 0x03:  /* BGEZL */
2326 		case 0x11:  /* BGEZAL */
2327 		case 0x13:  /* BGEZALL */
2328 			if (opswitch & 0x10)
2329 			{
2330 				UML_DMOV(block, R64(31), (int32_t)(desc->pc + 8));
2331 			}
2332 
2333 			if (RSREG != 0)
2334 			{
2335 				UML_DCMP(block, R64(RSREG), 0);                             // dcmp    <rsreg>,0
2336 				UML_JMPc(block, COND_L, skip = compiler.labelnum++);       // jmp     skip,L
2337 				generate_delay_slot_and_branch(block, compiler, desc, 0);   // <next instruction + hashjmp>
2338 				UML_LABEL(block, skip);                                     // skip:
2339 			}
2340 			else
2341 			{
2342 				generate_delay_slot_and_branch(block, compiler, desc, 0);   // <next instruction + hashjmp>
2343 			}
2344 			return true;
2345 
2346 		case 0x08:  /* TGEI */
2347 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2348 			UML_EXHc(block, COND_GE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,GE
2349 			return true;
2350 
2351 		case 0x09:  /* TGEIU */
2352 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2353 			UML_EXHc(block, COND_AE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,AE
2354 			return true;
2355 
2356 		case 0x0a:  /* TLTI */
2357 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2358 			UML_EXHc(block, COND_L, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,L
2359 			return true;
2360 
2361 		case 0x0b:  /* TLTIU */
2362 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2363 			UML_EXHc(block, COND_B, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,B
2364 			return true;
2365 
2366 		case 0x0c:  /* TEQI */
2367 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2368 			UML_EXHc(block, COND_E, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,E
2369 			return true;
2370 
2371 		case 0x0e:  /* TNEI */
2372 			UML_DCMP(block, R64(RSREG), SIMMVAL);                               // dcmp    <rsreg>,SIMMVAL
2373 			UML_EXHc(block, COND_NE, *m_exception[EXCEPTION_TRAP], 0);// exh     trap,0,NE
2374 			return true;
2375 	}
2376 	return false;
2377 }
2378 
2379 
2380 /*-------------------------------------------------
2381     generate_idt - compile opcodes in the IDT-
2382     specific group
2383 -------------------------------------------------*/
2384 
generate_idt(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)2385 bool mips3_device::generate_idt(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
2386 {
2387 	uint32_t op = desc->opptr.l[0];
2388 	uint8_t opswitch = op & 0x1f;
2389 
2390 	/* only enabled on IDT processors */
2391 	if (m_flavor != MIPS3_TYPE_R4650)
2392 		return false;
2393 
2394 	switch (opswitch)
2395 	{
2396 		case 0: /* MAD */
2397 			if (RSREG != 0 && RTREG != 0)
2398 			{
2399 				UML_MULS(block, I0, I1, R32(RSREG), R32(RTREG));                // muls   i0,i1,rsreg,rtreg
2400 				UML_ADD(block, I0, I0, LO32);                                   // add    i0,i0,lo
2401 				UML_ADDC(block, I1, I1, HI32);                                  // addc   i1,i1,hi
2402 				UML_DSEXT(block, LO64, I0, SIZE_DWORD);                         // dsext   lo,i0,dword
2403 				UML_DSEXT(block, HI64, I1, SIZE_DWORD);                         // dsext   hi,i1,dword
2404 			}
2405 			return true;
2406 
2407 		case 1: /* MADU */
2408 			if (RSREG != 0 && RTREG != 0)
2409 			{
2410 				UML_MULU(block, I0, I1, R32(RSREG), R32(RTREG));                // mulu   i0,i1,rsreg,rtreg
2411 				UML_ADD(block, I0, I0, LO32);                                   // add    i0,i0,lo
2412 				UML_ADDC(block, I1, I1, HI32);                                  // addc   i1,i1,hi
2413 				UML_DSEXT(block, LO64, I0, SIZE_DWORD);                         // dsext   lo,i0,dword
2414 				UML_DSEXT(block, HI64, I1, SIZE_DWORD);                         // dsext   hi,i1,dword
2415 			}
2416 			return true;
2417 
2418 		case 2: /* MUL */
2419 			if (RDREG != 0)
2420 			{
2421 				UML_MULS(block, I0, I0, R32(RSREG), R32(RTREG));                // muls   i0,i0,rsreg,rtreg
2422 				UML_DSEXT(block, R64(RDREG), I0, SIZE_DWORD);                   // dsext  rdreg,i0,dword
2423 			}
2424 			return true;
2425 	}
2426 	return false;
2427 }
2428 
2429 
2430 /*-------------------------------------------------
2431     generate_set_cop0_reg - generate code to
2432     handle special COP0 registers
2433 -------------------------------------------------*/
2434 
generate_set_cop0_reg(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc,uint8_t reg)2435 bool mips3_device::generate_set_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg)
2436 {
2437 	int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
2438 	uml::code_label link;
2439 
2440 	switch (reg)
2441 	{
2442 		case COP0_Cause:
2443 			UML_ROLINS(block, CPR032(COP0_Cause), I0, 0, ~0xfc00);              // rolins  [Cause],i0,0,~0xfc00
2444 			compiler.checksoftints = true;
2445 			if (!in_delay_slot)
2446 				generate_update_cycles(block, compiler, desc->pc + 4, true);
2447 			return true;
2448 
2449 		case COP0_Status:
2450 			generate_update_cycles(block, compiler, desc->pc, !in_delay_slot);  // <subtract cycles>
2451 			UML_MOV(block, I1, CPR032(COP0_Status));                            // mov     i1,[Status]
2452 			UML_MOV(block, CPR032(COP0_Status), I0);                            // mov     [Status],i0
2453 			generate_update_mode(block);                                        // <update mode>
2454 			UML_XOR(block, I0, I0, I1);                                         // xor     i0,i0,i1
2455 			UML_TEST(block, I0, 0x8000);                                        // test    i0,0x8000
2456 			UML_CALLCc(block, COND_NZ, cfunc_mips3com_update_cycle_counting, this);      // callc   mips3com_update_cycle_counting,mips.core,NZ
2457 			compiler.checkints = true;
2458 			if (!in_delay_slot)
2459 				generate_update_cycles(block, compiler, desc->pc + 4, true);
2460 			return true;
2461 
2462 		case COP0_Count:
2463 			generate_update_cycles(block, compiler, desc->pc, !in_delay_slot);  // <subtract cycles>
2464 			UML_MOV(block, CPR032(COP0_Count), I0);                             // mov     [Count],i0
2465 			UML_CALLC(block, cfunc_get_cycles, this);                           // callc   cfunc_get_cycles,mips3
2466 			UML_DAND(block, I0, I0, 0xffffffff);                                // and     i0,i0,0xffffffff
2467 			UML_DADD(block, I0, I0, I0);                                        // dadd    i0,i0,i0
2468 			UML_DSUB(block, mem(&m_core->count_zero_time), mem(&m_core->numcycles), I0);
2469 																				// dsub    [count_zero_time],[m_numcycles],i0
2470 			UML_CALLC(block, cfunc_mips3com_update_cycle_counting, this);       // callc   mips3com_update_cycle_counting,mips.core
2471 			return true;
2472 
2473 		case COP0_Compare:
2474 			UML_MOV(block, mem(&m_core->compare_armed), 1);                     // mov     [compare_armed],1
2475 			generate_update_cycles(block, compiler, desc->pc, !in_delay_slot);  // <subtract cycles>
2476 			UML_MOV(block, CPR032(COP0_Compare), I0);                           // mov     [Compare],i0
2477 			UML_AND(block, CPR032(COP0_Cause), CPR032(COP0_Cause), ~0x8000);    // and     [Cause],[Cause],~0x8000
2478 			UML_CALLC(block, cfunc_mips3com_update_cycle_counting, this);       // callc   mips3com_update_cycle_counting,mips.core
2479 			return true;
2480 
2481 		case COP0_PRId:
2482 			return true;
2483 
2484 		case COP0_Config:
2485 			UML_ROLINS(block, CPR032(COP0_Config), I0, 0, 0x0007);              // rolins  [Config],i0,0,0x0007
2486 			return true;
2487 
2488 		case COP0_EntryHi:
2489 			UML_XOR(block, I1, I0, CPR032(reg));                                // xor     i1,i0,cpr0[reg]
2490 			UML_MOV(block, CPR032(reg), I0);                                    // mov     cpr0[reg],i0
2491 			UML_TEST(block, I1, 0xff);                                          // test    i1,0xff
2492 			UML_JMPc(block, COND_Z, link = compiler.labelnum++);                // jmp     link,z
2493 			UML_CALLC(block, cfunc_mips3com_asid_changed, this);                // callc   mips3com_asid_changed
2494 			UML_LABEL(block, link);                                             // link:
2495 			return true;
2496 
2497 		default:
2498 			UML_MOV(block, CPR032(reg), I0);                                    // mov     cpr0[reg],i0
2499 			return true;
2500 	}
2501 }
2502 
2503 
2504 /*-------------------------------------------------
2505     generate_get_cop0_reg - generate code to
2506     read special COP0 registers
2507 -------------------------------------------------*/
2508 
generate_get_cop0_reg(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc,uint8_t reg)2509 bool mips3_device::generate_get_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg)
2510 {
2511 	uml::code_label link1, link2;
2512 
2513 	switch (reg)
2514 	{
2515 		case COP0_Count:
2516 			generate_update_cycles(block, compiler, desc->pc, false);           // <subtract cycles>
2517 			UML_CALLC(block, cfunc_get_cycles, this);                           // callc   cfunc_get_cycles,mips3
2518 			UML_DSUB(block, I0, mem(&m_core->numcycles), mem(&m_core->count_zero_time));
2519 																				// dsub    i0,[numcycles],[count_zero_time]
2520 			UML_DSHR(block, I0, I0, 1);                                         // dshr    i0,i0,1
2521 			UML_DSEXT(block, I0, I0, SIZE_DWORD);                               // dsext   i0,i0,dword
2522 			return true;
2523 
2524 		case COP0_Random:
2525 			generate_update_cycles(block, compiler, desc->pc, false);           // <subtract cycles>
2526 			UML_CALLC(block, cfunc_get_cycles, this);                           // callc   cfunc_get_cycles,mips3
2527 			UML_DSUB(block, I0, mem(&m_core->numcycles), mem(&m_core->count_zero_time));
2528 																				// dsub    i0,[numcycles],[count_zero_time]
2529 			UML_AND(block, I1, CPR032(COP0_Wired), 0x3f);                       // and     i1,[Wired],0x3f
2530 			UML_SUB(block, I2, 48, I1);                                         // sub     i2,48,i1
2531 			UML_JMPc(block, COND_BE, link1 = compiler.labelnum++);              // jmp     link1,BE
2532 			UML_DAND(block, I2, I2, 0xffffffff);                                // dand    i2,i2,0xffffffff
2533 			UML_DDIVU(block, I0, I2, I0, I2);                                   // ddivu   i0,i2,i0,i2
2534 			UML_ADD(block, I0, I2, I1);                                         // add     i0,i2,i1
2535 			UML_DAND(block, I0, I0, 0x3f);                                      // dand    i0,i0,0x3f
2536 			UML_JMP(block, link2 = compiler.labelnum++);                        // jmp     link2
2537 			UML_LABEL(block, link1);                                            // link1:
2538 			UML_DMOV(block, I0, 47);                                            // dmov    i0,47
2539 			UML_LABEL(block, link2);                                            // link2:
2540 			return true;
2541 
2542 		default:
2543 			UML_DSEXT(block, I0, CPR032(reg), SIZE_DWORD);                      // dsext   i0,cpr0[reg],dword
2544 			return true;
2545 	}
2546 }
2547 
2548 
2549 /*-------------------------------------------------------------------------
2550     generate_badcop - raise a BADCOP exception
2551 -------------------------------------------------------------------------*/
2552 
generate_badcop(drcuml_block & block,const int cop)2553 void mips3_device::generate_badcop(drcuml_block &block, const int cop)
2554 {
2555 	UML_TEST(block, CPR032(COP0_Status), SR_COP0 << cop);               // test    [Status], SR_COP0 << cop
2556 	UML_EXHc(block, COND_Z, *m_exception[EXCEPTION_BADCOP], cop);       // exh     badcop,cop,Z
2557 }
2558 
2559 /*-------------------------------------------------------------------------
2560     check_cop0_access - raise a BADCOP exception if we're not in kernel mode
2561 -------------------------------------------------------------------------*/
2562 
check_cop0_access(drcuml_block & block)2563 void mips3_device::check_cop0_access(drcuml_block &block)
2564 {
2565 	if ((m_core->mode >> 1) != MODE_KERNEL)
2566 	{
2567 		generate_badcop(block, 0);
2568 	}
2569 }
2570 
2571 /*-------------------------------------------------
2572     generate_cop0 - compile COP0 opcodes
2573 -------------------------------------------------*/
2574 
generate_cop0(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)2575 bool mips3_device::generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
2576 {
2577 	uint32_t op = desc->opptr.l[0];
2578 	uint8_t opswitch = RSREG;
2579 	int skip;
2580 
2581 	/* generate an exception if COP0 is disabled unless we are in kernel mode */
2582 	if ((m_core->mode >> 1) != MODE_KERNEL)
2583 	{
2584 		UML_TEST(block, CPR032(COP0_Status), SR_COP0);                          // test    [Status],SR_COP0
2585 		UML_EXHc(block, COND_Z, *m_exception[EXCEPTION_BADCOP], 0);             // exh     cop,0,Z
2586 	}
2587 
2588 	switch (opswitch)
2589 	{
2590 		case 0x00:  /* MFCz */
2591 			if (RTREG != 0)
2592 			{
2593 				generate_get_cop0_reg(block, compiler, desc, RDREG);            // <get cop0 reg>
2594 				UML_DSEXT(block, R64(RTREG), I0, SIZE_DWORD);                   // dsext   <rtreg>,i0,dword
2595 			}
2596 			return true;
2597 
2598 		case 0x01:  /* DMFCz */
2599 			if (RTREG != 0)
2600 			{
2601 				generate_get_cop0_reg(block, compiler, desc, RDREG);            // <get cop0 reg>
2602 				UML_DMOV(block, R64(RTREG), I0);                                // dmov    <rtreg>,i0
2603 			}
2604 			return true;
2605 
2606 		case 0x02:  /* CFCz */
2607 			if (RTREG != 0)
2608 				UML_DSEXT(block, R64(RTREG), CCR032(RDREG), SIZE_DWORD);        // dsext   <rtreg>,ccr0[rdreg],dword
2609 			return true;
2610 
2611 		case 0x04:  /* MTCz */
2612 			UML_DSEXT(block, I0, R32(RTREG), SIZE_DWORD);                       // dsext   i0,<rtreg>,dword
2613 			generate_set_cop0_reg(block, compiler, desc, RDREG);                // <set cop0 reg>
2614 			return true;
2615 
2616 		case 0x05:  /* DMTCz */
2617 			UML_DMOV(block, I0, R64(RTREG));                                    // dmov    i0,<rtreg>
2618 			generate_set_cop0_reg(block, compiler, desc, RDREG);                // <set cop0 reg>
2619 			return true;
2620 
2621 		case 0x06:  /* CTCz */
2622 			UML_DSEXT(block, CCR064(RDREG), R32(RTREG), SIZE_DWORD);            // dsext   ccr0[rdreg],<rtreg>,dword
2623 			return true;
2624 
2625 		case 0x10:
2626 		case 0x11:
2627 		case 0x12:
2628 		case 0x13:
2629 		case 0x14:
2630 		case 0x15:
2631 		case 0x16:
2632 		case 0x17:
2633 		case 0x18:
2634 		case 0x19:
2635 		case 0x1a:
2636 		case 0x1b:
2637 		case 0x1c:
2638 		case 0x1d:
2639 		case 0x1e:
2640 		case 0x1f:  /* COP */
2641 			switch (op & 0x01ffffff)
2642 			{
2643 				case 0x01:  /* TLBR */
2644 					UML_CALLC(block, cfunc_mips3com_tlbr, this);                // callc   mips3com_tlbr,mips3
2645 					return true;
2646 
2647 				case 0x02:  /* TLBWI */
2648 					UML_CALLC(block, cfunc_mips3com_tlbwi, this);               // callc   mips3com_tlbwi,mips3
2649 					return true;
2650 
2651 				case 0x06:  /* TLBWR */
2652 					UML_CALLC(block, cfunc_mips3com_tlbwr, this);               // callc   mips3com_tlbwr,mips3
2653 					return true;
2654 
2655 				case 0x08:  /* TLBP */
2656 					UML_CALLC(block, cfunc_mips3com_tlbp, this);                // callc   mips3com_tlbp,mips3
2657 					return true;
2658 
2659 				case 0x18:  /* ERET */
2660 					UML_MOV(block, mem(&m_core->llbit), 0);                     // mov     [llbit],0
2661 					UML_MOV(block, I0, CPR032(COP0_Status));                    // mov     i0,[Status]
2662 					UML_TEST(block, I0, SR_ERL);                                // test    i0,SR_ERL
2663 					UML_JMPc(block, COND_NZ, skip = compiler.labelnum++);       // jmp     skip,nz
2664 					UML_AND(block, I0, I0, ~SR_EXL);                            // and     i0,i0,~SR_EXL
2665 					UML_MOV(block, CPR032(COP0_Status), I0);                    // mov     [Status],i0
2666 					generate_update_mode(block);
2667 					compiler.checkints = true;
2668 					generate_update_cycles(block, compiler, CPR032(COP0_EPC), true);// <subtract cycles>
2669 					UML_HASHJMP(block, mem(&m_core->mode), CPR032(COP0_EPC), *m_nocode);
2670 																				// hashjmp <mode>,[EPC],nocode
2671 					UML_LABEL(block, skip);                                     // skip:
2672 					UML_AND(block, I0, I0, ~SR_ERL);                            // and     i0,i0,~SR_ERL
2673 					UML_MOV(block, CPR032(COP0_Status), I0);                    // mov     [Status],i0
2674 					generate_update_mode(block);
2675 					compiler.checkints = true;
2676 					generate_update_cycles(block, compiler, CPR032(COP0_ErrorPC), true); // <subtract cycles>
2677 					UML_HASHJMP(block, mem(&m_core->mode), CPR032(COP0_ErrorPC), *m_nocode); // hashjmp <mode>,[EPC],nocode
2678 					return true;
2679 
2680 				case 0x20:  /* WAIT */
2681 					return true;
2682 			}
2683 			break;
2684 	}
2685 
2686 	return false;
2687 }
2688 
2689 
2690 
2691 /***************************************************************************
2692     COP1 RECOMPILATION
2693 ***************************************************************************/
2694 
2695 /*-------------------------------------------------------------------------
2696     check_cop1_access - raise a BADCOP exception if COP1 is not enabled
2697 -------------------------------------------------------------------------*/
2698 
check_cop1_access(drcuml_block & block)2699 void mips3_device::check_cop1_access(drcuml_block &block)
2700 {
2701 	if (m_drcoptions & MIPS3DRC_STRICT_COP1)
2702 	{
2703 		generate_badcop(block, 1);
2704 	}
2705 }
2706 
2707 /*-------------------------------------------------------
2708     generate_cop1 - compile COP1 opcodes
2709 ---------------------------------------------------------*/
2710 
generate_cop1(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)2711 bool mips3_device::generate_cop1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
2712 {
2713 	uint32_t op = desc->opptr.l[0];
2714 	uml::code_label skip;
2715 	uml::condition_t condition;
2716 
2717 	check_cop1_access(block);
2718 
2719 	switch (RSREG)
2720 	{
2721 		case 0x00:  /* MFC1 - MIPS I */
2722 			if (RTREG != 0)
2723 			{
2724 				UML_DSEXT(block, R64(RTREG), FPR32(RDREG), SIZE_DWORD);     // dsext   <rtreg>,fpr[rdreg],dword
2725 			}
2726 			return true;
2727 
2728 		case 0x01:  /* DMFC1 - MIPS III */
2729 			if (RTREG != 0)
2730 			{
2731 				UML_DMOV(block, R64(RTREG), FPR64(RDREG));                  // dmov    <rtreg>,fpr[rdreg]
2732 			}
2733 			return true;
2734 
2735 		case 0x02:  /* CFC1 - MIPS I */
2736 			if (RTREG != 0)
2737 				UML_DSEXT(block, R64(RTREG), CCR132(RDREG), SIZE_DWORD);        // dsext   <rtreg>,ccr132[rdreg],dword
2738 			return true;
2739 
2740 		case 0x04:  /* MTC1 - MIPS I */
2741 			UML_MOV(block, FPR32(RDREG), R32(RTREG));                       // mov     fpr[rdreg],<rtreg>
2742 			return true;
2743 
2744 		case 0x05:  /* DMTC1 - MIPS III */
2745 			UML_DMOV(block, FPR64(RDREG), R64(RTREG));                      // dmov    fpr[rdreg],<rtreg>
2746 			return true;
2747 
2748 		case 0x06:  /* CTC1 - MIPS I */
2749 			if (RDREG != 31)
2750 			{
2751 				UML_DSEXT(block, CCR164(RDREG), R32(RTREG), SIZE_DWORD);        // dsext   ccr1[rdreg],<rtreg>,dword
2752 			}
2753 			else
2754 			{
2755 				UML_XOR(block, I0, CCR132(31), R32(RTREG));                     // xor     i0,ccr1[31],<rtreg>
2756 				UML_DSEXT(block, CCR164(31), R32(RTREG), SIZE_DWORD);           // dsext   ccr1[31],<rtreg>,dword
2757 				UML_TEST(block, I0, 3);                                         // test    i0,3
2758 				UML_JMPc(block, COND_Z, skip = compiler.labelnum++);            // jmp     skip,Z
2759 				UML_AND(block, I0, CCR132(31), 3);                              // and     i0,ccr1[31],3
2760 				UML_LOAD(block, I0, &m_fpmode[0], I0, SIZE_BYTE, SCALE_x1);     // load   i0,fpmode,i0,byte
2761 				UML_SETFMOD(block, I0);                                         // setfmod i0
2762 				UML_LABEL(block, skip);                                         // skip:
2763 			}
2764 			return true;
2765 
2766 		case 0x08:  /* BC */
2767 			switch ((op >> 16) & 3)
2768 			{
2769 				case 0x00:  /* BCzF - MIPS I */
2770 				case 0x02:  /* BCzFL - MIPS II */
2771 					UML_TEST(block, CCR132(31), FCCMASK(op >> 18));             // test    ccr1[31],fccmask[which]
2772 					UML_JMPc(block, COND_NZ, skip = compiler.labelnum++);       // jmp     skip,NZ
2773 					generate_delay_slot_and_branch(block, compiler, desc, 0);   // <next instruction + hashjmp>
2774 					UML_LABEL(block, skip);                                     // skip:
2775 					return true;
2776 
2777 				case 0x01:  /* BCzT - MIPS I */
2778 				case 0x03:  /* BCzTL - MIPS II */
2779 					UML_TEST(block, CCR132(31), FCCMASK(op >> 18));             // test    ccr1[31],fccmask[which]
2780 					UML_JMPc(block, COND_Z, skip = compiler.labelnum++);        // jmp     skip,Z
2781 					generate_delay_slot_and_branch(block, compiler, desc, 0);   // <next instruction + hashjmp>
2782 					UML_LABEL(block, skip);                                     // skip:
2783 					return true;
2784 			}
2785 			break;
2786 
2787 		default:
2788 			switch (op & 0x3f)
2789 			{
2790 				case 0x00:
2791 					if (IS_SINGLE(op))  /* ADD.S - MIPS I */
2792 					{
2793 						UML_FSADD(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG));       // fsadd   <fdreg>,<fsreg>,<ftreg>
2794 					}
2795 					else                /* ADD.D - MIPS I */
2796 					{
2797 						UML_FDADD(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG));       // fdadd   <fdreg>,<fsreg>,<ftreg>
2798 					}
2799 					return true;
2800 
2801 				case 0x01:
2802 					if (IS_SINGLE(op))  /* SUB.S - MIPS I */
2803 					{
2804 						UML_FSSUB(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG));       // fssub   <fdreg>,<fsreg>,<ftreg>
2805 					}
2806 					else                /* SUB.D - MIPS I */
2807 					{
2808 						UML_FDSUB(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG));       // fdsub   <fdreg>,<fsreg>,<ftreg>
2809 					}
2810 					return true;
2811 
2812 				case 0x02:
2813 					if (IS_SINGLE(op))  /* MUL.S - MIPS I */
2814 					{
2815 						UML_FSMUL(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG));       // fsmul   <fdreg>,<fsreg>,<ftreg>
2816 					}
2817 					else                /* MUL.D - MIPS I */
2818 					{
2819 						UML_FDMUL(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG));       // fdmul    <fdreg>,<fsreg>,<ftreg>
2820 					}
2821 					return true;
2822 
2823 				case 0x03:
2824 					if (IS_SINGLE(op))  /* DIV.S - MIPS I */
2825 					{
2826 						UML_TEST(block, FPR32(FTREG), 0xffffffff);                              // test    <ftreg>,-1
2827 						UML_JMPc(block, COND_NZ, skip = compiler.labelnum++);                   // jmp     skip,NZ
2828 						UML_TEST(block, CCR132(31), 1 << (FCR31_ENABLE + FPE_DIV0));            // test    [FCR31], 1 << DIV0_EN
2829 						UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_FPE], 1 << FPE_DIV0);   // exh     FPE,cop,FPE_DIV0
2830 						UML_LABEL(block, skip);                                                 // skip:
2831 						UML_FSDIV(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG));             // fsdiv   <fdreg>,<fsreg>,<ftreg>
2832 					}
2833 					else                /* DIV.D - MIPS I */
2834 					{
2835 						UML_DTEST(block, FPR64(FTREG), 0xffffffff'ffffffffull);                 // dtest    <ftreg>,-1
2836 						UML_JMPc(block, COND_NZ, skip = compiler.labelnum++);                   // jmp     skip,NZ
2837 						UML_TEST(block, CCR132(31), 1 << (FCR31_ENABLE + FPE_DIV0));            // test    [FCR31], 1 << DIV0_EN
2838 						UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_FPE], 1 << FPE_DIV0);   // exh     FPE,cop,FPE_DIV0
2839 						UML_LABEL(block, skip);                                                 // skip:
2840 						UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG));             // fddiv   <fdreg>,<fsreg>,<ftreg>
2841 					}
2842 					return true;
2843 
2844 				case 0x04:
2845 					if (IS_SINGLE(op))  /* SQRT.S - MIPS II */
2846 					{
2847 						UML_FSSQRT(block, FPR32(FDREG), FPR32(FSREG));                  // fssqrt  <fdreg>,<fsreg>
2848 					}
2849 					else                /* SQRT.D - MIPS II */
2850 					{
2851 						UML_FDSQRT(block, FPR64(FDREG), FPR64(FSREG));                  // fdsqrt  <fdreg>,<fsreg>
2852 					}
2853 					return true;
2854 
2855 				case 0x05:
2856 					if (IS_SINGLE(op))  /* ABS.S - MIPS I */
2857 					{
2858 						UML_FSABS(block, FPR32(FDREG), FPR32(FSREG));                   // fsabs   <fdreg>,<fsreg>
2859 					}
2860 					else                /* ABS.D - MIPS I */
2861 					{
2862 						UML_FDABS(block, FPR64(FDREG), FPR64(FSREG));                   // fdabs   <fdreg>,<fsreg>
2863 					}
2864 					return true;
2865 
2866 				case 0x06:
2867 					if (IS_SINGLE(op))  /* MOV.S - MIPS I */
2868 					{
2869 						UML_FSMOV(block, FPR32(FDREG), FPR32(FSREG));                   // fsmov   <fdreg>,<fsreg>
2870 					}
2871 					else                /* MOV.D - MIPS I */
2872 					{
2873 						UML_FDMOV(block, FPR64(FDREG), FPR64(FSREG));                   // fdmov   <fdreg>,<fsreg>
2874 					}
2875 					return true;
2876 
2877 				case 0x07:
2878 					if (IS_SINGLE(op))  /* NEG.S - MIPS I */
2879 					{
2880 						UML_FSNEG(block, FPR32(FDREG), FPR32(FSREG));         // fsneg   <fdreg>,<fsreg>
2881 						UML_CMP(block, FPR32(FSREG), 0);                      // cmp     <fsreg>,0.0
2882 						UML_MOVc(block, COND_E, FPR32(FDREG), 0x80000000);    // mov     <fdreg>,-0.0,e
2883 					}
2884 					else                /* NEG.D - MIPS I */
2885 					{
2886 						UML_FDNEG(block, FPR64(FDREG), FPR64(FSREG));                         // fdneg   <fdreg>,<fsreg>
2887 						UML_DCMP(block, FPR64(FSREG), 0);                                     // cmp     <fsreg>,0.0
2888 						UML_DMOVc(block, COND_E, FPR64(FDREG), 0x8000000000000000U);          // dmov    <fdreg>,-0.0,e
2889 					}
2890 					return true;
2891 
2892 				case 0x08:
2893 					if (IS_SINGLE(op))  /* ROUND.L.S - MIPS III */
2894 					{
2895 						UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_ROUND);// fstoint <fdreg>,<fsreg>,qword,round
2896 					}
2897 					else                /* ROUND.L.D - MIPS III */
2898 					{
2899 						UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_ROUND);// fdtoint <fdreg>,<fsreg>,qword,round
2900 					}
2901 					return true;
2902 
2903 				case 0x09:
2904 					if (IS_SINGLE(op))  /* TRUNC.L.S - MIPS III */
2905 					{
2906 						UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_TRUNC);// fstoint <fdreg>,<fsreg>,qword,trunc
2907 					}
2908 					else                /* TRUNC.L.D - MIPS III */
2909 					{
2910 						UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_TRUNC);// fdtoint <fdreg>,<fsreg>,qword,trunc
2911 					}
2912 					return true;
2913 
2914 				case 0x0a:
2915 					if (IS_SINGLE(op))  /* CEIL.L.S - MIPS III */
2916 					{
2917 						UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_CEIL);// fstoint <fdreg>,<fsreg>,qword,ceil
2918 					}
2919 					else                /* CEIL.L.D - MIPS III */
2920 					{
2921 						UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_CEIL);// fdtoint <fdreg>,<fsreg>,qword,ceil
2922 					}
2923 					return true;
2924 
2925 				case 0x0b:
2926 					if (IS_SINGLE(op))  /* FLOOR.L.S - MIPS III */
2927 					{
2928 						UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_FLOOR);// fstoint <fdreg>,<fsreg>,qword,floor
2929 					}
2930 					else                /* FLOOR.L.D - MIPS III */
2931 					{
2932 						UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_FLOOR);// fdtoint <fdreg>,<fsreg>,qword,floor
2933 					}
2934 					return true;
2935 
2936 				case 0x0c:
2937 					if (IS_SINGLE(op))  /* ROUND.W.S - MIPS II */
2938 					{
2939 						UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_ROUND);// fstoint <fdreg>,<fsreg>,dword,round
2940 					}
2941 					else                /* ROUND.W.D - MIPS II */
2942 					{
2943 						UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_ROUND);// fdtoint <fdreg>,<fsreg>,dword,round
2944 					}
2945 					return true;
2946 
2947 				case 0x0d:
2948 					if (IS_SINGLE(op))  /* TRUNC.W.S - MIPS II */
2949 					{
2950 						UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_TRUNC);// fstoint <fdreg>,<fsreg>,dword,trunc
2951 					}
2952 					else                /* TRUNC.W.D - MIPS II */
2953 					{
2954 						UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_TRUNC);// fdtoint <fdreg>,<fsreg>,dword,trunc
2955 					}
2956 					return true;
2957 
2958 				case 0x0e:
2959 					if (IS_SINGLE(op))  /* CEIL.W.S - MIPS II */
2960 					{
2961 						UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_CEIL);// fstoint <fdreg>,<fsreg>,dword,ceil
2962 					}
2963 					else                /* CEIL.W.D - MIPS II */
2964 					{
2965 						UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_CEIL);// fdtoint <fdreg>,<fsreg>,dword,ceil
2966 					}
2967 					return true;
2968 
2969 				case 0x0f:
2970 					if (IS_SINGLE(op))  /* FLOOR.W.S - MIPS II */
2971 					{
2972 						UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_FLOOR);// fstoint <fdreg>,<fsreg>,dword,floor
2973 					}
2974 					else                /* FLOOR.W.D - MIPS II */
2975 					{
2976 						UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_FLOOR);// fdtoint <fdreg>,<fsreg>,dword,floor
2977 					}
2978 					return true;
2979 
2980 				case 0x11:
2981 					condition = ((op >> 16) & 1) ? uml::COND_NZ : uml::COND_Z;
2982 					UML_TEST(block, CCR132(31), FCCMASK(op >> 18));         // test    ccr31,fccmask[op]
2983 					if (IS_SINGLE(op))  /* MOVT/F.S - MIPS IV */
2984 					{
2985 						UML_FSMOVc(block, condition, FPR32(FDREG), FPR32(FSREG));   // fsmov   <fdreg>,<fsreg>,condition
2986 					}
2987 					else                /* MOVT/F.D - MIPS IV */
2988 					{
2989 						UML_FDMOVc(block, condition, FPR64(FDREG), FPR64(FSREG));   // fdmov   <fdreg>,<fsreg>,condition
2990 					}
2991 					return true;
2992 
2993 				case 0x12:
2994 					UML_DCMP(block, R64(RTREG), 0);                             // dcmp    <rtreg>,0
2995 					if (IS_SINGLE(op))  /* MOVZ.S - MIPS IV */
2996 					{
2997 						UML_FSMOVc(block, COND_Z, FPR32(FDREG), FPR32(FSREG));      // fsmov   <fdreg>,<fsreg>,Z
2998 					}
2999 					else                /* MOVZ.D - MIPS IV */
3000 					{
3001 						UML_FDMOVc(block, COND_Z, FPR64(FDREG), FPR64(FSREG));      // fdmov   <fdreg>,<fsreg>,Z
3002 					}
3003 					return true;
3004 
3005 				case 0x13:
3006 					UML_DCMP(block, R64(RTREG), 0);                                 // dcmp    <rtreg>,0
3007 					if (IS_SINGLE(op))  /* MOVN.S - MIPS IV */
3008 					{
3009 						UML_FSMOVc(block, COND_NZ, FPR32(FDREG), FPR32(FSREG));         // fsmov   <fdreg>,<fsreg>,NZ
3010 					}
3011 					else                /* MOVN.D - MIPS IV */
3012 					{
3013 						UML_FDMOVc(block, COND_NZ, FPR64(FDREG), FPR64(FSREG));         // fdmov   <fdreg>,<fsreg>,NZ
3014 					}
3015 					return true;
3016 
3017 				case 0x15:
3018 					if (IS_SINGLE(op))  /* RECIP.S - MIPS IV */
3019 					{
3020 						UML_FSRECIP(block, FPR32(FDREG), FPR32(FSREG));                 // fsrecip <fdreg>,<fsreg>
3021 					}
3022 					else                /* RECIP.D - MIPS IV */
3023 					{
3024 						UML_FDRECIP(block, FPR64(FDREG), FPR64(FSREG));                 // fdrecip <fdreg>,<fsreg>
3025 					}
3026 					return true;
3027 
3028 				case 0x16:
3029 					if (IS_SINGLE(op))  /* RSQRT.S - MIPS IV */
3030 					{
3031 						UML_FSRSQRT(block, FPR32(FDREG), FPR32(FSREG));                 // fsrsqrt <fdreg>,<fsreg>
3032 					}
3033 					else                /* RSQRT.D - MIPS IV */
3034 					{
3035 						UML_FDRSQRT(block, FPR64(FDREG), FPR64(FSREG));                 // fdrsqrt <fdreg>,<fsreg>
3036 					}
3037 					return true;
3038 
3039 				case 0x20:
3040 					if (IS_INTEGRAL(op))
3041 					{
3042 						if (IS_SINGLE(op))  /* CVT.S.W - MIPS I */
3043 						{
3044 							UML_FSFRINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD); // fsfrint <fdreg>,<fsreg>,dword
3045 						}
3046 						else                /* CVT.S.L - MIPS I */
3047 						{
3048 							UML_FSFRINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_QWORD); // fsfrint <fdreg>,<fsreg>,qword
3049 						}
3050 					}
3051 					else                    /* CVT.S.D - MIPS I */
3052 					{
3053 						UML_FSFRFLT(block, FPR32(FDREG), FPR64(FSREG), SIZE_QWORD);         // fsfrflt <fdreg>,<fsreg>,qword
3054 					}
3055 					return true;
3056 
3057 				case 0x21:
3058 					if (IS_INTEGRAL(op))
3059 					{
3060 						if (IS_SINGLE(op))  /* CVT.D.W - MIPS I */
3061 						{
3062 							UML_FDFRINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_DWORD); // fdfrint <fdreg>,<fsreg>,dword
3063 						}
3064 						else                /* CVT.D.L - MIPS I */
3065 						{
3066 							UML_FDFRINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD); // fdfrint <fdreg>,<fsreg>,qword
3067 						}
3068 					}
3069 					else                    /* CVT.D.S - MIPS I */
3070 					{
3071 						UML_FDFRFLT(block, FPR64(FDREG), FPR32(FSREG), SIZE_DWORD);         // fdfrflt <fdreg>,<fsreg>,dword
3072 					}
3073 					return true;
3074 
3075 				case 0x24:
3076 					if (IS_SINGLE(op))  /* CVT.W.S - MIPS I */
3077 					{
3078 						UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), SIZE_DWORD, ROUND_DEFAULT);// fstoint <fdreg>,<fsreg>,dword,default
3079 					}
3080 					else                /* CVT.W.D - MIPS I */
3081 					{
3082 						UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), SIZE_DWORD, ROUND_DEFAULT);// fdtoint <fdreg>,<fsreg>,dword,default
3083 					}
3084 					return true;
3085 
3086 				case 0x25:
3087 					if (IS_SINGLE(op))  /* CVT.L.S - MIPS I */
3088 					{
3089 						UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), SIZE_QWORD, ROUND_DEFAULT);// fstoint <fdreg>,<fsreg>,qword,default
3090 					}
3091 					else                /* CVT.L.D - MIPS I */
3092 					{
3093 						UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), SIZE_QWORD, ROUND_DEFAULT);// fdtoint <fdreg>,<fsreg>,qword,default
3094 					}
3095 					return true;
3096 
3097 				case 0x30:
3098 				case 0x38:              /* C.F.S/D - MIPS I */
3099 					UML_AND(block, CCR132(31), CCR132(31), ~FCCMASK(op >> 8));  // and     ccr31,ccr31,~fccmask[op]
3100 					return true;
3101 
3102 				case 0x31:
3103 				case 0x39:
3104 					if (IS_SINGLE(op))  /* C.UN.S - MIPS I */
3105 					{
3106 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3107 					}
3108 					else                /* C.UN.D - MIPS I */
3109 					{
3110 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3111 					}
3112 					UML_SETc(block, COND_U, I0);                                    // set     i0,u
3113 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3114 																					// rolins  ccr31,i0,fccshift,fcc
3115 					return true;
3116 
3117 				case 0x32:
3118 				case 0x3a:
3119 					if (IS_SINGLE(op))  /* C.EQ.S - MIPS I */
3120 					{
3121 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3122 					}
3123 					else                /* C.EQ.D - MIPS I */
3124 					{
3125 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3126 					}
3127 					UML_SETc(block, COND_E, I0);                                    // set     i0,e
3128 					UML_SETc(block, COND_NU, I1);                               // set     i1,nu
3129 					UML_AND(block, I0, I0, I1);                     // and     i0,i0,i1
3130 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3131 																					// rolins  ccr31,i0,fccshift,fcc
3132 					return true;
3133 
3134 				case 0x33:
3135 				case 0x3b:
3136 					if (IS_SINGLE(op))  /* C.UEQ.S - MIPS I */
3137 					{
3138 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3139 					}
3140 					else                /* C.UEQ.D - MIPS I */
3141 					{
3142 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3143 					}
3144 					UML_SETc(block, COND_U, I0);                                    // set     i0,u
3145 					UML_SETc(block, COND_E, I1);                                    // set     i1,e
3146 					UML_OR(block, I0, I0, I1);                      // or      i0,i0,i1
3147 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3148 																					// rolins  ccr31,i0,fccshift,fcc
3149 					return true;
3150 
3151 				case 0x34:
3152 				case 0x3c:
3153 					if (IS_SINGLE(op))  /* C.OLT.S - MIPS I */
3154 					{
3155 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3156 					}
3157 					else                /* C.OLT.D - MIPS I */
3158 					{
3159 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3160 					}
3161 					UML_SETc(block, COND_B, I0);                                    // set     i0,b
3162 					UML_SETc(block, COND_NU, I1);                               // set     i1,nu
3163 					UML_AND(block, I0, I0, I1);                     // and     i0,i0,i1
3164 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3165 																					// rolins  ccr31,i0,fccshift,fcc
3166 					return true;
3167 
3168 				case 0x35:
3169 				case 0x3d:
3170 					if (IS_SINGLE(op))  /* C.ULT.S - MIPS I */
3171 					{
3172 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3173 					}
3174 					else                /* C.ULT.D - MIPS I */
3175 					{
3176 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3177 					}
3178 					UML_SETc(block, COND_U, I0);                                    // set     i0,u
3179 					UML_SETc(block, COND_B, I1);                                    // set     i1,b
3180 					UML_OR(block, I0, I0, I1);                      // or      i0,i0,i1
3181 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3182 																					// rolins  ccr31,i0,fccshift,fcc
3183 					return true;
3184 
3185 				case 0x36:
3186 				case 0x3e:
3187 					if (IS_SINGLE(op))  /* C.OLE.S - MIPS I */
3188 					{
3189 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3190 					}
3191 					else                /* C.OLE.D - MIPS I */
3192 					{
3193 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3194 					}
3195 					UML_SETc(block, COND_BE, I0);                               // set     i0,be
3196 					UML_SETc(block, COND_NU, I1);                               // set     i1,nu
3197 					UML_AND(block, I0, I0, I1);                     // and     i0,i0,i1
3198 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3199 																					// rolins  ccr31,i0,fccshift,fcc
3200 					return true;
3201 
3202 				case 0x37:
3203 				case 0x3f:
3204 					if (IS_SINGLE(op))  /* C.ULE.S - MIPS I */
3205 					{
3206 						UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG));               // fscmp   <fsreg>,<ftreg>
3207 					}
3208 					else                /* C.ULE.D - MIPS I */
3209 					{
3210 						UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG));               // fdcmp   <fsreg>,<ftreg>
3211 					}
3212 					UML_SETc(block, COND_U, I0);                                    // set     i0,u
3213 					UML_SETc(block, COND_BE, I1);                               // set     i1,be
3214 					UML_OR(block, I0, I0, I1);                      // or      i0,i0,i1
3215 					UML_ROLINS(block, CCR132(31), I0, FCCSHIFT(op >> 8), FCCMASK(op >> 8));
3216 																					// rolins  ccr31,i0,fccshift,fcc
3217 					return true;
3218 			}
3219 			break;
3220 	}
3221 	return false;
3222 }
3223 
3224 /***************************************************************************
3225     COP1X RECOMPILATION
3226 ***************************************************************************/
3227 
3228 /*----------------------------------------------------------
3229     generate_cop1x - compile COP1X opcodes
3230 ----------------------------------------------------------*/
3231 
generate_cop1x(drcuml_block & block,compiler_state & compiler,const opcode_desc * desc)3232 bool mips3_device::generate_cop1x(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
3233 {
3234 	int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
3235 	uint32_t op = desc->opptr.l[0];
3236 
3237 	check_cop1_access(block);
3238 
3239 	switch (op & 0x3f)
3240 	{
3241 		case 0x00:      /* LWXC1 - MIPS IV */
3242 			UML_ADD(block, I0, R32(RSREG), R32(RTREG));         // add     i0,<rsreg>,<rtreg>
3243 			UML_CALLH(block, *m_read32[m_core->mode >> 1]);     // callh   read32
3244 			UML_MOV(block, FPR32(FDREG), I0);                   // mov     <cpr1_fd>,i0
3245 			if (!in_delay_slot)
3246 				generate_update_cycles(block, compiler, desc->pc + 4, true);
3247 			return true;
3248 
3249 		case 0x01:      /* LDXC1 - MIPS IV */
3250 			UML_ADD(block, I0, R32(RSREG), R32(RTREG));         // add     i0,<rsreg>,<rtreg>
3251 			UML_CALLH(block, *m_read64[m_core->mode >> 1]);     // callh   read64
3252 			UML_DMOV(block, FPR64(FDREG), I0);                  // dmov    <cpr1_fd>,i0
3253 			if (!in_delay_slot)
3254 				generate_update_cycles(block, compiler, desc->pc + 4, true);
3255 			return true;
3256 
3257 		case 0x08:      /* SWXC1 - MIPS IV */
3258 			UML_ADD(block, I0, R32(RSREG), R32(RTREG));         // add     i0,<rsreg>,<rtreg>
3259 			UML_MOV(block, I1, FPR32(FSREG));                   // mov     i1,<cpr1_fs>
3260 			UML_CALLH(block, *m_write32[m_core->mode >> 1]);    // callh   write32
3261 			if (!in_delay_slot)
3262 				generate_update_cycles(block, compiler, desc->pc + 4, true);
3263 			return true;
3264 
3265 		case 0x09:      /* SDXC1 - MIPS IV */
3266 			UML_ADD(block, I0, R32(RSREG), R32(RTREG));         // add     i0,<rsreg>,<rtreg>
3267 			UML_DMOV(block, I1, FPR64(FSREG));                  // dmov    i1,<cpr1_fs>
3268 			UML_CALLH(block, *m_write64[m_core->mode >> 1]);    // callh   write64
3269 			if (!in_delay_slot)
3270 				generate_update_cycles(block, compiler, desc->pc + 4, true);
3271 			return true;
3272 
3273 		case 0x0f:      /* PREFX */
3274 			return true;
3275 
3276 		case 0x20:      /* MADD.S - MIPS IV */
3277 			UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG));           // fsmul   f0,<fsreg>,<ftreg>
3278 			UML_FSADD(block, FPR32(FDREG), F0, FPR32(FRREG));           // fsadd   <fdreg>,f0,<frreg>
3279 			return true;
3280 
3281 		case 0x21:      /* MADD.D - MIPS IV */
3282 			UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG));           // fdmul   f0,<fsreg>,<ftreg>
3283 			UML_FDADD(block, FPR64(FDREG), F0, FPR64(FRREG));           // fdadd   <fdreg>,f0,<frreg>
3284 			return true;
3285 
3286 		case 0x28:      /* MSUB.S - MIPS IV */
3287 			UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG));           // fsmul   f0,<fsreg>,<ftreg>
3288 			UML_FSSUB(block, FPR32(FDREG), F0, FPR32(FRREG));           // fssub   <fdreg>,f0,<frreg>
3289 			return true;
3290 
3291 		case 0x29:      /* MSUB.D - MIPS IV */
3292 			UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG));           // fdmul   f0,<fsreg>,<ftreg>
3293 			UML_FDSUB(block, FPR64(FDREG), F0, FPR64(FRREG));           // fdadd   <fdreg>,f0,<frreg>
3294 			return true;
3295 
3296 		case 0x30:      /* NMADD.S - MIPS IV */
3297 			UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG));           // fsmul   f0,<fsreg>,<ftreg>
3298 			UML_FSADD(block, F0, F0, FPR32(FRREG));                     // fsadd   f0,f0,<frreg>
3299 			UML_FSNEG(block, FPR32(FDREG), F0);                         // fsneg   <fdreg>,f0
3300 			return true;
3301 
3302 		case 0x31:      /* NMADD.D - MIPS IV */
3303 			UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG));           // fdmul   f0,<fsreg>,<ftreg>
3304 			UML_FDADD(block, F0, F0, FPR64(FRREG));                     // fdadd   f0,f0,<frreg>
3305 			UML_FDNEG(block, FPR64(FDREG), F0);                         // fdneg   <fdreg>,f0
3306 			return true;
3307 
3308 		case 0x38:      /* NMSUB.S - MIPS IV */
3309 			UML_FSMUL(block, F0, FPR32(FSREG), FPR32(FTREG));           // fsmul   f0,<fsreg>,<ftreg>
3310 			UML_FSSUB(block, FPR32(FDREG), FPR32(FRREG), F0);           // fssub   <fdreg>,<frreg>,f0
3311 			return true;
3312 
3313 		case 0x39:      /* NMSUB.D - MIPS IV */
3314 			UML_FDMUL(block, F0, FPR64(FSREG), FPR64(FTREG));           // fdmul   f0,<fsreg>,<ftreg>
3315 			UML_FDSUB(block, FPR64(FDREG), FPR64(FRREG), F0);           // fdsub   <fdreg>,<frreg>,f0
3316 			return true;
3317 
3318 		default:
3319 			fprintf(stderr, "cop1x %X\n", op);
3320 			break;
3321 	}
3322 	return false;
3323 }
3324 
3325 /***************************************************************************
3326     CODE LOGGING HELPERS
3327 ***************************************************************************/
3328 
3329 /*-------------------------------------------------
3330     log_add_disasm_comment - add a comment
3331     including disassembly of a MIPS instruction
3332 -------------------------------------------------*/
3333 
log_add_disasm_comment(drcuml_block & block,uint32_t pc,uint32_t op)3334 void mips3_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op)
3335 {
3336 	if (m_drcuml->logging())
3337 	{
3338 		mips3_disassembler mips3d;
3339 		std::ostringstream stream;
3340 		mips3d.dasm_one(stream, pc, op);
3341 		const std::string stream_string = stream.str();
3342 		block.append_comment("%08X: %s", pc, stream_string.c_str());                                  // comment
3343 	}
3344 }
3345 
3346 
3347 /*-------------------------------------------------
3348     log_desc_flags_to_string - generate a string
3349     representing the instruction description
3350     flags
3351 -------------------------------------------------*/
3352 
log_desc_flags_to_string(uint32_t flags)3353 const char *mips3_device::log_desc_flags_to_string(uint32_t flags)
3354 {
3355 	static char tempbuf[30];
3356 	char *dest = tempbuf;
3357 
3358 	/* branches */
3359 	if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH)
3360 		*dest++ = 'U';
3361 	else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH)
3362 		*dest++ = 'C';
3363 	else
3364 		*dest++ = '.';
3365 
3366 	/* intrablock branches */
3367 	*dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.';
3368 
3369 	/* branch targets */
3370 	*dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.';
3371 
3372 	/* delay slots */
3373 	*dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.';
3374 
3375 	/* exceptions */
3376 	if (flags & OPFLAG_WILL_CAUSE_EXCEPTION)
3377 		*dest++ = 'E';
3378 	else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION)
3379 		*dest++ = 'e';
3380 	else
3381 		*dest++ = '.';
3382 
3383 	/* read/write */
3384 	if (flags & OPFLAG_READS_MEMORY)
3385 		*dest++ = 'R';
3386 	else if (flags & OPFLAG_WRITES_MEMORY)
3387 		*dest++ = 'W';
3388 	else
3389 		*dest++ = '.';
3390 
3391 	/* TLB validation */
3392 	*dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.';
3393 
3394 	/* TLB modification */
3395 	*dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.';
3396 
3397 	/* redispatch */
3398 	*dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.';
3399 	return tempbuf;
3400 }
3401 
3402 
3403 /*-------------------------------------------------
3404     log_register_list - log a list of GPR registers
3405 -------------------------------------------------*/
3406 
log_register_list(const char * string,const uint32_t * reglist,const uint32_t * regnostarlist)3407 void mips3_device::log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist)
3408 {
3409 	int count = 0;
3410 	int regnum;
3411 
3412 	/* skip if nothing */
3413 	if (reglist[0] == 0 && reglist[1] == 0 && reglist[2] == 0)
3414 		return;
3415 
3416 	m_drcuml->log_printf("[%s:", string);
3417 
3418 	for (regnum = 1; regnum < 32; regnum++)
3419 		if (reglist[0] & REGFLAG_R(regnum))
3420 		{
3421 			m_drcuml->log_printf("%sr%d", (count++ == 0) ? "" : ",", regnum);
3422 			if (regnostarlist != nullptr && !(regnostarlist[0] & REGFLAG_R(regnum)))
3423 				m_drcuml->log_printf("*");
3424 		}
3425 
3426 	for (regnum = 0; regnum < 32; regnum++)
3427 		if (reglist[1] & REGFLAG_CPR1(regnum))
3428 		{
3429 			m_drcuml->log_printf("%sfr%d", (count++ == 0) ? "" : ",", regnum);
3430 			if (regnostarlist != nullptr && !(regnostarlist[1] & REGFLAG_CPR1(regnum)))
3431 				m_drcuml->log_printf("*");
3432 		}
3433 
3434 	if (reglist[2] & REGFLAG_LO)
3435 	{
3436 		m_drcuml->log_printf("%slo", (count++ == 0) ? "" : ",");
3437 		if (regnostarlist != nullptr && !(regnostarlist[2] & REGFLAG_LO))
3438 			m_drcuml->log_printf("*");
3439 	}
3440 	if (reglist[2] & REGFLAG_HI)
3441 	{
3442 		m_drcuml->log_printf("%shi", (count++ == 0) ? "" : ",");
3443 		if (regnostarlist != nullptr && !(regnostarlist[2] & REGFLAG_HI))
3444 			m_drcuml->log_printf("*");
3445 	}
3446 	if (reglist[2] & REGFLAG_FCC)
3447 	{
3448 		m_drcuml->log_printf("%sfcc", (count++ == 0) ? "" : ",");
3449 		if (regnostarlist != nullptr && !(regnostarlist[2] & REGFLAG_FCC))
3450 			m_drcuml->log_printf("*");
3451 	}
3452 
3453 	m_drcuml->log_printf("] ");
3454 }
3455 
3456 
3457 /*-------------------------------------------------
3458     log_opcode_desc - log a list of descriptions
3459 -------------------------------------------------*/
3460 
log_opcode_desc(const opcode_desc * desclist,int indent)3461 void mips3_device::log_opcode_desc(const opcode_desc *desclist, int indent)
3462 {
3463 	/* open the file, creating it if necessary */
3464 	if (indent == 0)
3465 		m_drcuml->log_printf("\nDescriptor list @ %08X\n", desclist->pc);
3466 
3467 	/* output each descriptor */
3468 	for ( ; desclist != nullptr; desclist = desclist->next())
3469 	{
3470 		std::ostringstream buffer;
3471 
3472 		/* disassemle the current instruction and output it to the log */
3473 		if (m_drcuml->logging() || m_drcuml->logging_native())
3474 		{
3475 			if (desclist->flags & OPFLAG_VIRTUAL_NOOP)
3476 				buffer << "<virtual nop>";
3477 			else
3478 			{
3479 				mips3_disassembler mips3d;
3480 				mips3d.dasm_one(buffer, desclist->pc, desclist->opptr.l[0]);
3481 			}
3482 		}
3483 		else
3484 			buffer << "???";
3485 
3486 		const std::string buffer_string = buffer.str();
3487 		m_drcuml->log_printf("%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer_string.c_str());
3488 
3489 		/* output register states */
3490 		log_register_list("use", desclist->regin, nullptr);
3491 		log_register_list("mod", desclist->regout, desclist->regreq);
3492 		m_drcuml->log_printf("\n");
3493 
3494 		/* if we have a delay slot, output it recursively */
3495 		if (desclist->delay.first() != nullptr)
3496 			log_opcode_desc(desclist->delay.first(), indent + 1);
3497 
3498 		/* at the end of a sequence add a dividing line */
3499 		if (desclist->flags & OPFLAG_END_SEQUENCE)
3500 			m_drcuml->log_printf("-----\n");
3501 	}
3502 }
3503