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