misc gp2x tweaks
[picodrive.git] / cpu / sh2 / compiler.c
CommitLineData
e898de13 1/*
2 * vim:shiftwidth=2:expandtab
3 */
f0d7b1fa 4#include <stddef.h>
679af8a3 5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
41397701 8
f4bb5d6b 9#include "../../pico/pico_int.h"
679af8a3 10#include "sh2.h"
11#include "compiler.h"
12#include "../drc/cmn.h"
13
8796b7ee 14// debug stuff {
e898de13 15#ifndef DRC_DEBUG
16#define DRC_DEBUG 0
17#endif
18
553c3eaa 19#if DRC_DEBUG
f4bb5d6b 20#define dbg(l,...) { \
21 if ((l) & DRC_DEBUG) \
22 elprintf(EL_STATUS, ##__VA_ARGS__); \
23}
24
e898de13 25#include "mame/sh2dasm.h"
26#include <platform/linux/host_dasm.h>
27static int insns_compiled, hash_collisions, host_insn_count;
553c3eaa 28#define COUNT_OP \
29 host_insn_count++
30#else // !DRC_DEBUG
31#define COUNT_OP
32#define dbg(...)
e898de13 33#endif
553c3eaa 34
e898de13 35#if (DRC_DEBUG & 2)
f4bb5d6b 36static u8 *tcache_dsm_ptrs[3];
e898de13 37static char sh2dasm_buff[64];
f4bb5d6b 38#define do_host_disasm(tcid) \
39 host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
40 tcache_dsm_ptrs[tcid] = tcache_ptr
41#else
42#define do_host_disasm(x)
e898de13 43#endif
8796b7ee 44// } debug
e898de13 45
679af8a3 46#define BLOCK_CYCLE_LIMIT 100
f4bb5d6b 47#define MAX_BLOCK_SIZE (BLOCK_CYCLE_LIMIT * 6 * 6)
48
49// we have 3 translation cache buffers, split from one drc/cmn buffer.
50// BIOS shares tcache with data array because it's only used for init
51// and can be discarded early
8796b7ee 52// XXX: need to tune sizes
f4bb5d6b 53static const int tcache_sizes[3] = {
54 DRC_TCACHE_SIZE * 6 / 8, // ROM, DRAM
55 DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
56 DRC_TCACHE_SIZE / 8, // ... slave
57};
679af8a3 58
f4bb5d6b 59static u8 *tcache_bases[3];
60static u8 *tcache_ptrs[3];
61
62// ptr for code emiters
63static u8 *tcache_ptr;
e898de13 64
c18edb34 65// host register tracking
66enum {
67 HR_FREE,
68 HR_CACHED, // 'val' has sh2_reg_e
69 HR_CACHED_DIRTY,
70 HR_CONST, // 'val' has constant
71 HR_TEMP, // reg used for temp storage
72};
73
74typedef struct {
75 u8 reg;
76 u8 type;
77 u16 stamp; // kind of a timestamp
78 u32 val;
79} temp_reg_t;
80
80599a42 81// note: reg_temp[] must have at least the amount of
3863edbd 82// registers used by handlers in worst case (currently 4)
65c75cb0 83#ifdef ARM
84#include "../drc/emit_arm.c"
85
86static const int reg_map_g2h[] = {
8b4f38f4 87 4, 5, 6, 7,
88 8, -1, -1, -1,
c18edb34 89 -1, -1, -1, -1,
8b4f38f4 90 -1, -1, -1, 9,
91 -1, -1, -1, 10,
c18edb34 92 -1, -1, -1, -1,
93};
94
95static temp_reg_t reg_temp[] = {
96 { 0, },
97 { 1, },
98 { 12, },
99 { 14, },
100 { 2, },
101 { 3, },
65c75cb0 102};
103
104#else
e898de13 105#include "../drc/emit_x86.c"
106
65c75cb0 107static const int reg_map_g2h[] = {
8b4f38f4 108 xSI,-1, -1, -1,
c18edb34 109 -1, -1, -1, -1,
110 -1, -1, -1, -1,
111 -1, -1, -1, -1,
8b4f38f4 112 -1, -1, -1, xDI,
c18edb34 113 -1, -1, -1, -1,
114};
115
3863edbd 116// ax, cx, dx are usually temporaries by convention
c18edb34 117static temp_reg_t reg_temp[] = {
118 { xAX, },
3863edbd 119 { xBX, },
c18edb34 120 { xCX, },
121 { xDX, },
65c75cb0 122};
123
124#endif
125
80599a42 126#define T 0x00000001
127#define S 0x00000002
128#define I 0x000000f0
129#define Q 0x00000100
130#define M 0x00000200
131
f0d7b1fa 132#define Q_SHIFT 8
133#define M_SHIFT 9
134
679af8a3 135typedef struct block_desc_ {
136 u32 addr; // SH2 PC address
f4bb5d6b 137 u32 end_addr; // TODO rm?
679af8a3 138 void *tcache_ptr; // translated block for above PC
f4bb5d6b 139 struct block_desc_ *next; // next block with the same PC hash
140#if (DRC_DEBUG & 1)
141 int refcount;
142#endif
679af8a3 143} block_desc;
144
f4bb5d6b 145static const int block_max_counts[3] = {
146 4*1024,
147 256,
148 256,
149};
150static block_desc *block_tables[3];
151static int block_counts[3];
679af8a3 152
f4bb5d6b 153// ROM hash table
679af8a3 154#define MAX_HASH_ENTRIES 1024
155#define HASH_MASK (MAX_HASH_ENTRIES - 1)
f4bb5d6b 156static void **hash_table;
679af8a3 157
8796b7ee 158static void REGPARM(2) (*sh2_drc_entry)(const void *block, SH2 *sh2);
159static void (*sh2_drc_exit)(void);
679af8a3 160
161// tmp
553c3eaa 162extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
163static void REGPARM(1) sh2_test_irq(SH2 *sh2);
679af8a3 164
f4bb5d6b 165static void flush_tcache(int tcid)
166{
553c3eaa 167 dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
f4bb5d6b 168 tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
169 block_counts[tcid], block_max_counts[tcid]);
170
171 block_counts[tcid] = 0;
172 tcache_ptrs[tcid] = tcache_bases[tcid];
173 if (tcid == 0) { // ROM, RAM
174 memset(hash_table, 0, sizeof(hash_table[0]) * MAX_HASH_ENTRIES);
175 memset(Pico32xMem->drcblk_ram, 0, sizeof(Pico32xMem->drcblk_ram));
176 }
177 else
178 memset(Pico32xMem->drcblk_da[tcid - 1], 0, sizeof(Pico32xMem->drcblk_da[0]));
179#if (DRC_DEBUG & 2)
180 tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
181#endif
182}
183
679af8a3 184static void *dr_find_block(block_desc *tab, u32 addr)
185{
186 for (tab = tab->next; tab != NULL; tab = tab->next)
187 if (tab->addr == addr)
188 break;
189
190 if (tab != NULL)
191 return tab->tcache_ptr;
192
193 printf("block miss for %08x\n", addr);
194 return NULL;
195}
196
f4bb5d6b 197static block_desc *dr_add_block(u32 addr, int tcache_id, int *blk_id)
679af8a3 198{
f4bb5d6b 199 int *bcount = &block_counts[tcache_id];
679af8a3 200 block_desc *bd;
201
f4bb5d6b 202 if (*bcount >= block_max_counts[tcache_id])
203 return NULL;
679af8a3 204
f4bb5d6b 205 bd = &block_tables[tcache_id][*bcount];
679af8a3 206 bd->addr = addr;
207 bd->tcache_ptr = tcache_ptr;
f4bb5d6b 208 *blk_id = *bcount;
209 (*bcount)++;
679af8a3 210
211 return bd;
212}
213
214#define HASH_FUNC(hash_tab, addr) \
215 ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
216
217// ---------------------------------------------------------------
218
c18edb34 219// register chache
220static u16 rcache_counter;
221
222static temp_reg_t *rcache_evict(void)
41397701 223{
c18edb34 224 // evict reg with oldest stamp
225 int i, oldest = -1;
226 u16 min_stamp = (u16)-1;
227
228 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
229 if (reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY)
230 if (reg_temp[i].stamp <= min_stamp) {
231 min_stamp = reg_temp[i].stamp;
232 oldest = i;
233 }
234 }
235
236 if (oldest == -1) {
80599a42 237 printf("no registers to evict, aborting\n");
c18edb34 238 exit(1);
239 }
240
241 i = oldest;
242 if (reg_temp[i].type == HR_CACHED_DIRTY) {
243 // writeback
244 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
245 }
246
247 return &reg_temp[i];
679af8a3 248}
249
c18edb34 250typedef enum {
251 RC_GR_READ,
252 RC_GR_WRITE,
253 RC_GR_RMW,
254} rc_gr_mode;
255
80599a42 256// note: must not be called when doing conditional code
c18edb34 257static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
679af8a3 258{
c18edb34 259 temp_reg_t *tr;
260 int i;
261
262 // maybe already statically mapped?
263 i = reg_map_g2h[r];
264 if (i != -1)
265 return i;
679af8a3 266
c18edb34 267 rcache_counter++;
268
269 // maybe already cached?
270 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
271 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
272 reg_temp[i].val == r)
273 {
274 reg_temp[i].stamp = rcache_counter;
275 if (mode != RC_GR_READ)
276 reg_temp[i].type = HR_CACHED_DIRTY;
277 return reg_temp[i].reg;
278 }
679af8a3 279 }
280
c18edb34 281 // use any free reg
282 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
283 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
284 tr = &reg_temp[i];
285 goto do_alloc;
286 }
287 }
288
289 tr = rcache_evict();
290
291do_alloc:
292 if (mode != RC_GR_WRITE)
293 emith_ctx_read(tr->reg, r * 4);
679af8a3 294
c18edb34 295 tr->type = mode != RC_GR_READ ? HR_CACHED_DIRTY : HR_CACHED;
296 tr->val = r;
297 tr->stamp = rcache_counter;
298 return tr->reg;
679af8a3 299}
300
c18edb34 301static int rcache_get_tmp(void)
679af8a3 302{
c18edb34 303 temp_reg_t *tr;
304 int i;
305
306 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
307 if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
308 tr = &reg_temp[i];
309 goto do_alloc;
310 }
311
312 tr = rcache_evict();
313
314do_alloc:
315 tr->type = HR_TEMP;
316 return tr->reg;
317}
318
80599a42 319static int rcache_get_arg_id(int arg)
320{
321 int i, r = 0;
322 host_arg2reg(r, arg);
323
324 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
325 if (reg_temp[i].reg == r)
326 break;
327
328 if (i == ARRAY_SIZE(reg_temp))
329 // let's just say it's untracked arg reg
330 return r;
331
332 if (reg_temp[i].type == HR_CACHED_DIRTY) {
333 // writeback
334 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
335 }
336 else if (reg_temp[i].type == HR_TEMP) {
337 printf("arg %d reg %d already used, aborting\n", arg, r);
338 exit(1);
339 }
340
341 return i;
342}
343
344// get a reg to be used as function arg
345// it's assumed that regs are cleaned before call
346static int rcache_get_tmp_arg(int arg)
347{
348 int id = rcache_get_arg_id(arg);
349 reg_temp[id].type = HR_TEMP;
350
351 return reg_temp[id].reg;
352}
353
354// same but caches reg. RC_GR_READ only.
355static int rcache_get_reg_arg(int arg, sh2_reg_e r)
356{
357 int i, srcr, dstr, dstid;
358
359 dstid = rcache_get_arg_id(arg);
360 dstr = reg_temp[dstid].reg;
361
362 // maybe already statically mapped?
363 srcr = reg_map_g2h[r];
364 if (srcr != -1)
365 goto do_cache;
366
367 // maybe already cached?
368 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
369 if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
370 reg_temp[i].val == r)
371 {
372 srcr = reg_temp[i].reg;
373 goto do_cache;
374 }
375 }
376
377 // must read
378 srcr = dstr;
379 emith_ctx_read(srcr, r * 4);
380
381do_cache:
382 if (srcr != dstr)
383 emith_move_r_r(dstr, srcr);
384
385 reg_temp[dstid].stamp = ++rcache_counter;
386 reg_temp[dstid].type = HR_CACHED;
387 reg_temp[dstid].val = r;
388 return dstr;
389}
390
c18edb34 391static void rcache_free_tmp(int hr)
392{
393 int i;
394 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
395 if (reg_temp[i].reg == hr)
396 break;
397
80599a42 398 if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
c18edb34 399 printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
80599a42 400 return;
401 }
402
403 reg_temp[i].type = HR_FREE;
c18edb34 404}
405
80599a42 406static void rcache_clean(void)
c18edb34 407{
408 int i;
80599a42 409 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
c18edb34 410 if (reg_temp[i].type == HR_CACHED_DIRTY) {
411 // writeback
412 emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
80599a42 413 reg_temp[i].type = HR_CACHED;
c18edb34 414 }
80599a42 415}
416
417static void rcache_invalidate(void)
418{
419 int i;
420 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
c18edb34 421 reg_temp[i].type = HR_FREE;
c18edb34 422 rcache_counter = 0;
423}
424
80599a42 425static void rcache_flush(void)
426{
427 rcache_clean();
428 rcache_invalidate();
429}
430
c18edb34 431// ---------------------------------------------------------------
432
433static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
434{
52d759c3 435 // TODO: propagate this constant
c18edb34 436 int hr = rcache_get_reg(dst, RC_GR_WRITE);
437 emith_move_r_imm(hr, imm);
438}
439
440static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
441{
442 int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
443 int hr_s = rcache_get_reg(src, RC_GR_READ);
444
445 emith_move_r_r(hr_d, hr_s);
679af8a3 446}
447
52d759c3 448// T must be clear, and comparison done just before this
449static void emit_or_t_if_eq(int srr)
450{
451 EMITH_SJMP_START(DCOND_NE);
452 emith_or_r_imm_c(DCOND_EQ, srr, T);
453 EMITH_SJMP_END(DCOND_NE);
454}
455
80599a42 456// arguments must be ready
457// reg cache must be clean before call
458static int emit_memhandler_read(int size)
679af8a3 459{
80599a42 460 int ctxr;
461 host_arg2reg(ctxr, 1);
462 emith_move_r_r(ctxr, CONTEXT_REG);
463 switch (size) {
464 case 0: // 8
465 emith_call(p32x_sh2_read8);
466 break;
467 case 1: // 16
468 emith_call(p32x_sh2_read16);
469 break;
470 case 2: // 32
471 emith_call(p32x_sh2_read32);
679af8a3 472 break;
473 }
80599a42 474 rcache_invalidate();
475 // assuming arg0 and retval reg matches
476 return rcache_get_tmp_arg(0);
477}
679af8a3 478
80599a42 479static void emit_memhandler_write(int size)
480{
481 int ctxr;
482 host_arg2reg(ctxr, 2);
483 emith_move_r_r(ctxr, CONTEXT_REG);
484 switch (size) {
485 case 0: // 8
486 emith_call(p32x_sh2_write8);
487 break;
488 case 1: // 16
489 emith_call(p32x_sh2_write16);
490 break;
491 case 2: // 32
492 emith_call(p32x_sh2_write32);
493 break;
494 }
495 rcache_invalidate();
679af8a3 496}
80599a42 497
52d759c3 498// @(Rx,Ry)
499static int emit_indirect_indexed_read(int rx, int ry, int size)
500{
501 int a0, t;
502 rcache_clean();
503 a0 = rcache_get_reg_arg(0, rx);
504 t = rcache_get_reg(ry, RC_GR_READ);
505 emith_add_r_r(a0, t);
506 return emit_memhandler_read(size);
507}
508
8796b7ee 509// tmp_wr -> @(Rx,Ry)
510static void emit_indirect_indexed_write(int tmp_wr, int rx, int ry, int size)
52d759c3 511{
512 int a0, t;
513 rcache_clean();
8796b7ee 514 t = rcache_get_tmp_arg(1);
515 emith_move_r_r(t, tmp_wr);
52d759c3 516 a0 = rcache_get_reg_arg(0, rx);
517 t = rcache_get_reg(ry, RC_GR_READ);
518 emith_add_r_r(a0, t);
519 emit_memhandler_write(size);
520}
521
f0d7b1fa 522// read @Rn, @rm
523static void emit_indirect_read_double(u32 *rnr, u32 *rmr, int rn, int rm, int size)
524{
525 int tmp;
526
527 rcache_clean();
528 rcache_get_reg_arg(0, rn);
529 tmp = emit_memhandler_read(size);
530 emith_ctx_write(tmp, offsetof(SH2, drc_tmp));
531 rcache_free_tmp(tmp);
532 tmp = rcache_get_reg(rn, RC_GR_RMW);
533 emith_add_r_imm(tmp, 1 << size);
534
535 rcache_clean();
536 rcache_get_reg_arg(0, rm);
537 *rmr = emit_memhandler_read(size);
538 *rnr = rcache_get_tmp();
539 emith_ctx_read(*rnr, offsetof(SH2, drc_tmp));
540 tmp = rcache_get_reg(rm, RC_GR_RMW);
541 emith_add_r_imm(tmp, 1 << size);
542}
543
8796b7ee 544static void emit_do_static_regs(int is_write, int tmpr)
f0d7b1fa 545{
8796b7ee 546 int i, r, count;
547
548 for (i = 0; i < ARRAY_SIZE(reg_map_g2h); i++) {
549 r = reg_map_g2h[i];
550 if (r == -1)
551 continue;
552
553 for (count = 1; i < ARRAY_SIZE(reg_map_g2h) - 1; i++, r++) {
554 if (reg_map_g2h[i + 1] != r + 1)
555 break;
556 count++;
557 }
558
559 if (count > 1) {
560 // i, r point to last item
561 if (is_write)
562 emith_ctx_write_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
563 else
564 emith_ctx_read_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
565 } else {
566 if (is_write)
567 emith_ctx_write(r, i * 4);
568 else
569 emith_ctx_read(r, i * 4);
570 }
f0d7b1fa 571 }
572}
573
8796b7ee 574static void sh2_generate_utils(void)
f0d7b1fa 575{
8796b7ee 576 int ctx, blk, tmp;
577
578 host_arg2reg(blk, 0);
579 host_arg2reg(ctx, 1);
580 host_arg2reg(tmp, 2);
581
582 // sh2_drc_entry(void *block, SH2 *sh2)
583 sh2_drc_entry = (void *)tcache_ptr;
584 emith_sh2_drc_entry();
585 emith_move_r_r(CONTEXT_REG, ctx); // move ctx, arg1
586 emit_do_static_regs(0, tmp);
587 emith_jump_reg(blk); // jump arg0
588
589 // sh2_drc_exit(void)
590 sh2_drc_exit = (void *)tcache_ptr;
591 emit_do_static_regs(1, tmp);
592 emith_sh2_drc_exit();
593
594 rcache_invalidate();
f0d7b1fa 595}
679af8a3 596
e898de13 597#define DELAYED_OP \
598 delayed_op = 2
599
600#define CHECK_UNHANDLED_BITS(mask) { \
601 if ((op & (mask)) != 0) \
602 goto default_; \
603}
604
80599a42 605#define GET_Fx() \
606 ((op >> 4) & 0x0f)
607
608#define GET_Rm GET_Fx
609
610#define GET_Rn() \
611 ((op >> 8) & 0x0f)
612
ed8cf79b 613#define CHECK_FX_LT(n) \
52d759c3 614 if (GET_Fx() >= n) \
80599a42 615 goto default_
616
679af8a3 617static void *sh2_translate(SH2 *sh2, block_desc *other_block)
618{
f4bb5d6b 619 void *block_entry;
679af8a3 620 block_desc *this_block;
41397701 621 unsigned int pc = sh2->pc;
e898de13 622 int op, delayed_op = 0, test_irq = 0;
f4bb5d6b 623 int tcache_id = 0, blkid = 0;
679af8a3 624 int cycles = 0;
f0d7b1fa 625 u32 tmp, tmp2, tmp3, tmp4, sr;
679af8a3 626
f4bb5d6b 627 // validate PC
628 tmp = sh2->pc >> 29;
629 if ((tmp != 0 && tmp != 1 && tmp != 6) || sh2->pc == 0) {
630 printf("invalid PC, aborting: %08x\n", sh2->pc);
631 // FIXME: be less destructive
632 exit(1);
633 }
634
635 if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
636 // data_array, BIOS have separate tcache (shared)
637 tcache_id = 1 + sh2->is_slave;
638 }
639
640 tcache_ptr = tcache_ptrs[tcache_id];
641 this_block = dr_add_block(pc, tcache_id, &blkid);
642
643 tmp = tcache_ptr - tcache_bases[tcache_id];
644 if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE || this_block == NULL) {
645 flush_tcache(tcache_id);
646 tcache_ptr = tcache_ptrs[tcache_id];
647 other_block = NULL; // also gone too due to flush
648 this_block = dr_add_block(pc, tcache_id, &blkid);
649 }
e898de13 650
f4bb5d6b 651 this_block->next = other_block;
652 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
653 HASH_FUNC(hash_table, pc) = this_block;
679af8a3 654
f4bb5d6b 655 block_entry = tcache_ptr;
e898de13 656#if (DRC_DEBUG & 1)
f4bb5d6b 657 printf("== %csh2 block #%d,%d %08x -> %p\n", sh2->is_slave ? 's' : 'm',
658 tcache_id, block_counts[tcache_id], pc, block_entry);
e898de13 659 if (other_block != NULL) {
660 printf(" hash collision with %08x\n", other_block->addr);
661 hash_collisions++;
662 }
679af8a3 663#endif
664
e898de13 665 while (cycles < BLOCK_CYCLE_LIMIT || delayed_op)
679af8a3 666 {
e898de13 667 if (delayed_op > 0)
668 delayed_op--;
669
2b2b46b0 670 op = p32x_sh2_read16(pc, sh2);
e898de13 671
672#if (DRC_DEBUG & 3)
673 insns_compiled++;
674#if (DRC_DEBUG & 2)
675 DasmSH2(sh2dasm_buff, pc, op);
676 printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
677#endif
679af8a3 678#endif
679af8a3 679
680 pc += 2;
681 cycles++;
682
683 switch ((op >> 12) & 0x0f)
684 {
3863edbd 685 /////////////////////////////////////////////
679af8a3 686 case 0x00:
80599a42 687 switch (op & 0x0f)
688 {
689 case 0x02:
690 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
691 switch (GET_Fx())
692 {
693 case 0: // STC SR,Rn 0000nnnn00000010
694 tmp2 = SHR_SR;
695 break;
696 case 1: // STC GBR,Rn 0000nnnn00010010
697 tmp2 = SHR_GBR;
698 break;
699 case 2: // STC VBR,Rn 0000nnnn00100010
700 tmp2 = SHR_VBR;
701 break;
702 default:
703 goto default_;
704 }
ed8cf79b 705 tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
706 emith_move_r_r(tmp, tmp3);
707 if (tmp2 == SHR_SR)
708 emith_clear_msb(tmp, tmp, 20); // reserved bits defined by ISA as 0
80599a42 709 goto end_op;
e898de13 710 case 0x03:
711 CHECK_UNHANDLED_BITS(0xd0);
712 // BRAF Rm 0000mmmm00100011
713 // BSRF Rm 0000mmmm00000011
679af8a3 714 DELAYED_OP;
e898de13 715 if (!(op & 0x20))
716 emit_move_r_imm32(SHR_PR, pc + 2);
c18edb34 717 tmp = rcache_get_reg(SHR_PPC, RC_GR_WRITE);
80599a42 718 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
c18edb34 719 emith_move_r_r(tmp, tmp2);
720 emith_add_r_imm(tmp, pc + 2);
679af8a3 721 cycles++;
e898de13 722 goto end_op;
80599a42 723 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
724 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
725 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
8796b7ee 726 tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
727 emit_indirect_indexed_write(tmp, SHR_R0, GET_Rn(), op & 3);
80599a42 728 goto end_op;
729 case 0x07:
730 // MUL.L Rm,Rn 0000nnnnmmmm0111
731 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
732 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
733 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
734 emith_mul(tmp3, tmp2, tmp);
735 cycles++;
736 goto end_op;
737 case 0x08:
738 CHECK_UNHANDLED_BITS(0xf00);
739 switch (GET_Fx())
740 {
741 case 0: // CLRT 0000000000001000
8796b7ee 742 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
743 emith_bic_r_imm(sr, T);
80599a42 744 break;
745 case 1: // SETT 0000000000011000
8796b7ee 746 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
747 emith_or_r_imm(sr, T);
80599a42 748 break;
749 case 2: // CLRMAC 0000000000101000
750 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
751 emith_move_r_imm(tmp, 0);
752 tmp = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
753 emith_move_r_imm(tmp, 0);
754 break;
755 default:
756 goto default_;
757 }
758 goto end_op;
e898de13 759 case 0x09:
80599a42 760 switch (GET_Fx())
761 {
762 case 0: // NOP 0000000000001001
763 CHECK_UNHANDLED_BITS(0xf00);
764 break;
765 case 1: // DIV0U 0000000000011001
766 CHECK_UNHANDLED_BITS(0xf00);
8796b7ee 767 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
768 emith_bic_r_imm(sr, M|Q|T);
80599a42 769 break;
770 case 2: // MOVT Rn 0000nnnn00101001
8796b7ee 771 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
80599a42 772 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
8796b7ee 773 emith_clear_msb(tmp2, sr, 31);
80599a42 774 break;
775 default:
776 goto default_;
777 }
778 goto end_op;
779 case 0x0a:
780 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
781 switch (GET_Fx())
782 {
783 case 0: // STS MACH,Rn 0000nnnn00001010
ed8cf79b 784 tmp2 = SHR_MACH;
80599a42 785 break;
786 case 1: // STS MACL,Rn 0000nnnn00011010
ed8cf79b 787 tmp2 = SHR_MACL;
80599a42 788 break;
789 case 2: // STS PR,Rn 0000nnnn00101010
ed8cf79b 790 tmp2 = SHR_PR;
80599a42 791 break;
792 default:
793 goto default_;
794 }
ed8cf79b 795 tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
80599a42 796 emith_move_r_r(tmp, tmp2);
e898de13 797 goto end_op;
798 case 0x0b:
80599a42 799 CHECK_UNHANDLED_BITS(0xf00);
800 switch (GET_Fx())
801 {
802 case 0: // RTS 0000000000001011
803 DELAYED_OP;
e898de13 804 emit_move_r_r(SHR_PPC, SHR_PR);
805 cycles++;
80599a42 806 break;
807 case 1: // SLEEP 0000000000011011
808 emit_move_r_imm32(SHR_PC, pc - 2);
809 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
810 emith_clear_msb(tmp, tmp, 20); // clear cycles
811 test_irq = 1;
812 cycles = 1;
813 break;
814 case 2: // RTE 0000000000101011
52d759c3 815 DELAYED_OP;
816 rcache_clean();
817 // pop PC
818 rcache_get_reg_arg(0, SHR_SP);
819 tmp = emit_memhandler_read(2);
820 tmp2 = rcache_get_reg(SHR_PPC, RC_GR_WRITE);
821 emith_move_r_r(tmp2, tmp);
822 rcache_free_tmp(tmp);
823 rcache_clean();
824 // pop SR
825 tmp = rcache_get_reg_arg(0, SHR_SP);
826 emith_add_r_imm(tmp, 4);
827 tmp = emit_memhandler_read(2);
828 emith_write_sr(tmp);
829 rcache_free_tmp(tmp);
830 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
831 emith_add_r_imm(tmp, 4*2);
e898de13 832 test_irq = 1;
833 cycles += 3;
80599a42 834 break;
835 default:
836 goto default_;
e898de13 837 }
838 goto end_op;
80599a42 839 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
840 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
841 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
52d759c3 842 tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
80599a42 843 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
80599a42 844 if ((op & 3) != 2) {
845 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
846 } else
847 emith_move_r_r(tmp2, tmp);
52d759c3 848 rcache_free_tmp(tmp);
80599a42 849 goto end_op;
850 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
f0d7b1fa 851 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
8796b7ee 852 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
f0d7b1fa 853 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
854 /* MS 16 MAC bits unused if saturated */
8796b7ee 855 emith_tst_r_imm(sr, S);
f0d7b1fa 856 EMITH_SJMP_START(DCOND_EQ);
857 emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
858 EMITH_SJMP_END(DCOND_EQ);
859 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
860 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 861 rcache_free_tmp(tmp2);
8796b7ee 862 sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
863 emith_tst_r_imm(sr, S);
864
865 EMITH_JMP_START(DCOND_EQ);
866 emith_asr(tmp, tmp4, 15);
867 emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
868 EMITH_SJMP_START(DCOND_GE);
869 emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
870 emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
871 EMITH_SJMP_END(DCOND_GE);
872 emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
873 EMITH_SJMP_START(DCOND_LE);
874 emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
875 emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
876 EMITH_SJMP_END(DCOND_LE);
877 EMITH_JMP_END(DCOND_EQ);
878
879 rcache_free_tmp(tmp);
f0d7b1fa 880 cycles += 3;
881 goto end_op;
80599a42 882 }
883 goto default_;
884
3863edbd 885 /////////////////////////////////////////////
80599a42 886 case 0x01:
887 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
888 rcache_clean();
889 tmp = rcache_get_reg_arg(0, GET_Rn());
890 tmp2 = rcache_get_reg_arg(1, GET_Rm());
891 emith_add_r_imm(tmp, (op & 0x0f) * 4);
892 emit_memhandler_write(2);
893 goto end_op;
894
895 case 0x02:
896 switch (op & 0x0f)
897 {
898 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
899 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
900 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
901 rcache_clean();
902 rcache_get_reg_arg(0, GET_Rn());
903 rcache_get_reg_arg(1, GET_Rm());
904 emit_memhandler_write(op & 3);
905 goto end_op;
906 case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
907 case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
908 case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
909 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
910 emith_sub_r_imm(tmp, (1 << (op & 3)));
911 rcache_clean();
912 rcache_get_reg_arg(0, GET_Rn());
913 rcache_get_reg_arg(1, GET_Rm());
914 emit_memhandler_write(op & 3);
915 goto end_op;
916 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
8796b7ee 917 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
80599a42 918 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
919 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 920 emith_bic_r_imm(sr, M|Q|T);
80599a42 921 emith_tst_r_imm(tmp2, (1<<31));
922 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 923 emith_or_r_imm_c(DCOND_NE, sr, Q);
80599a42 924 EMITH_SJMP_END(DCOND_EQ);
925 emith_tst_r_imm(tmp3, (1<<31));
926 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 927 emith_or_r_imm_c(DCOND_NE, sr, M);
80599a42 928 EMITH_SJMP_END(DCOND_EQ);
929 emith_teq_r_r(tmp2, tmp3);
930 EMITH_SJMP_START(DCOND_PL);
8796b7ee 931 emith_or_r_imm_c(DCOND_MI, sr, T);
80599a42 932 EMITH_SJMP_END(DCOND_PL);
933 goto end_op;
3863edbd 934 case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
8796b7ee 935 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 936 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
937 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 938 emith_bic_r_imm(sr, T);
3863edbd 939 emith_tst_r_r(tmp2, tmp3);
8796b7ee 940 emit_or_t_if_eq(sr);
3863edbd 941 goto end_op;
942 case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
943 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
944 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
945 emith_and_r_r(tmp, tmp2);
946 goto end_op;
947 case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
948 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
949 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
950 emith_eor_r_r(tmp, tmp2);
951 goto end_op;
952 case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
953 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
954 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
955 emith_or_r_r(tmp, tmp2);
956 goto end_op;
957 case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
958 tmp = rcache_get_tmp();
959 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
960 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
961 emith_eor_r_r_r(tmp, tmp2, tmp3);
8796b7ee 962 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
963 emith_bic_r_imm(sr, T);
3863edbd 964 emith_tst_r_imm(tmp, 0x000000ff);
52d759c3 965 emit_or_t_if_eq(tmp);
3863edbd 966 emith_tst_r_imm(tmp, 0x0000ff00);
52d759c3 967 emit_or_t_if_eq(tmp);
3863edbd 968 emith_tst_r_imm(tmp, 0x00ff0000);
52d759c3 969 emit_or_t_if_eq(tmp);
3863edbd 970 emith_tst_r_imm(tmp, 0xff000000);
52d759c3 971 emit_or_t_if_eq(tmp);
3863edbd 972 rcache_free_tmp(tmp);
973 goto end_op;
974 case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
975 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
976 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
977 emith_lsr(tmp, tmp, 16);
f0d7b1fa 978 emith_or_r_r_lsl(tmp, tmp2, 16);
3863edbd 979 goto end_op;
980 case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
981 case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
982 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
983 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
984 if (op & 1) {
985 emith_sext(tmp, tmp2, 16);
986 } else
987 emith_clear_msb(tmp, tmp2, 16);
988 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
989 tmp2 = rcache_get_tmp();
990 if (op & 1) {
991 emith_sext(tmp2, tmp3, 16);
992 } else
993 emith_clear_msb(tmp2, tmp3, 16);
994 emith_mul(tmp, tmp, tmp2);
995 rcache_free_tmp(tmp2);
996// FIXME: causes timing issues in Doom?
997// cycles++;
998 goto end_op;
679af8a3 999 }
1000 goto default_;
1001
3863edbd 1002 /////////////////////////////////////////////
1003 case 0x03:
1004 switch (op & 0x0f)
1005 {
1006 case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
1007 case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
1008 case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
1009 case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
1010 case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
8796b7ee 1011 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1012 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1013 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1014 emith_bic_r_imm(sr, T);
3863edbd 1015 emith_cmp_r_r(tmp2, tmp3);
1016 switch (op & 0x07)
1017 {
1018 case 0x00: // CMP/EQ
8796b7ee 1019 emit_or_t_if_eq(sr);
3863edbd 1020 break;
1021 case 0x02: // CMP/HS
1022 EMITH_SJMP_START(DCOND_LO);
8796b7ee 1023 emith_or_r_imm_c(DCOND_HS, sr, T);
3863edbd 1024 EMITH_SJMP_END(DCOND_LO);
1025 break;
1026 case 0x03: // CMP/GE
1027 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1028 emith_or_r_imm_c(DCOND_GE, sr, T);
3863edbd 1029 EMITH_SJMP_END(DCOND_LT);
1030 break;
1031 case 0x06: // CMP/HI
1032 EMITH_SJMP_START(DCOND_LS);
8796b7ee 1033 emith_or_r_imm_c(DCOND_HI, sr, T);
3863edbd 1034 EMITH_SJMP_END(DCOND_LS);
1035 break;
1036 case 0x07: // CMP/GT
1037 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1038 emith_or_r_imm_c(DCOND_GT, sr, T);
3863edbd 1039 EMITH_SJMP_END(DCOND_LE);
1040 break;
1041 }
1042 goto end_op;
1043 case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
f0d7b1fa 1044 // Q1 = carry(Rn = (Rn << 1) | T)
1045 // if Q ^ M
1046 // Q2 = carry(Rn += Rm)
1047 // else
1048 // Q2 = carry(Rn -= Rm)
1049 // Q = M ^ Q1 ^ Q2
1050 // T = (Q == M) = !(Q ^ M) = !(Q1 ^ Q2)
1051 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1052 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1053 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1054 emith_tpop_carry(sr, 0);
f0d7b1fa 1055 emith_adcf_r_r(tmp2, tmp2);
8b4f38f4 1056 emith_tpush_carry(sr, 0); // keep Q1 in T for now
f0d7b1fa 1057 tmp4 = rcache_get_tmp();
1058 emith_and_r_r_imm(tmp4, sr, M);
1059 emith_eor_r_r_lsr(sr, tmp4, M_SHIFT - Q_SHIFT); // Q ^= M
1060 rcache_free_tmp(tmp4);
1061 // add or sub, invert T if carry to get Q1 ^ Q2
1062 // in: (Q ^ M) passed in Q, Q1 in T
1063 emith_sh2_div1_step(tmp2, tmp3, sr);
1064 emith_bic_r_imm(sr, Q);
1065 emith_tst_r_imm(sr, M);
1066 EMITH_SJMP_START(DCOND_EQ);
1067 emith_or_r_imm_c(DCOND_NE, sr, Q); // Q = M
1068 EMITH_SJMP_END(DCOND_EQ);
1069 emith_tst_r_imm(sr, T);
1070 EMITH_SJMP_START(DCOND_EQ);
1071 emith_eor_r_imm_c(DCOND_NE, sr, Q); // Q = M ^ Q1 ^ Q2
1072 EMITH_SJMP_END(DCOND_EQ);
1073 emith_eor_r_imm(sr, T); // T = !(Q1 ^ Q2)
1074 goto end_op;
3863edbd 1075 case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
1076 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1077 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1078 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1079 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1080 emith_mul_u64(tmp3, tmp4, tmp, tmp2);
1081 goto end_op;
1082 case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
1083 case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
1084 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1085 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1086 if (op & 4) {
1087 emith_add_r_r(tmp, tmp2);
1088 } else
1089 emith_sub_r_r(tmp, tmp2);
1090 goto end_op;
1091 case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
1092 case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
1093 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1094 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1095 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1096 if (op & 4) { // adc
8b4f38f4 1097 emith_tpop_carry(sr, 0);
3863edbd 1098 emith_adcf_r_r(tmp, tmp2);
8b4f38f4 1099 emith_tpush_carry(sr, 0);
3863edbd 1100 } else {
8b4f38f4 1101 emith_tpop_carry(sr, 1);
3863edbd 1102 emith_sbcf_r_r(tmp, tmp2);
8b4f38f4 1103 emith_tpush_carry(sr, 1);
3863edbd 1104 }
3863edbd 1105 goto end_op;
1106 case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
1107 case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
1108 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1109 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1110 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1111 emith_bic_r_imm(sr, T);
3863edbd 1112 if (op & 4) {
1113 emith_addf_r_r(tmp, tmp2);
1114 } else
1115 emith_subf_r_r(tmp, tmp2);
1116 EMITH_SJMP_START(DCOND_VC);
8796b7ee 1117 emith_or_r_imm_c(DCOND_VS, sr, T);
3863edbd 1118 EMITH_SJMP_END(DCOND_VC);
1119 goto end_op;
1120 case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
1121 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1122 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1123 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1124 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1125 emith_mul_s64(tmp3, tmp4, tmp, tmp2);
1126 goto end_op;
1127 }
1128 goto default_;
1129
1130 /////////////////////////////////////////////
679af8a3 1131 case 0x04:
3863edbd 1132 switch (op & 0x0f)
1133 {
c18edb34 1134 case 0x00:
3863edbd 1135 switch (GET_Fx())
1136 {
1137 case 0: // SHLL Rn 0100nnnn00000000
1138 case 2: // SHAL Rn 0100nnnn00100000
8796b7ee 1139 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1140 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1141 emith_tpop_carry(sr, 0); // dummy
3863edbd 1142 emith_lslf(tmp, tmp, 1);
8b4f38f4 1143 emith_tpush_carry(sr, 0);
3863edbd 1144 goto end_op;
1145 case 1: // DT Rn 0100nnnn00010000
1146 if (p32x_sh2_read16(pc, sh2) == 0x8bfd) { // BF #-2
1147 emith_sh2_dtbf_loop();
1148 goto end_op;
1149 }
1150 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
8796b7ee 1151 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1152 emith_bic_r_imm(sr, T);
3863edbd 1153 emith_subf_r_imm(tmp, 1);
8796b7ee 1154 emit_or_t_if_eq(sr);
80599a42 1155 goto end_op;
1156 }
3863edbd 1157 goto default_;
ed8cf79b 1158 case 0x01:
1159 switch (GET_Fx())
1160 {
1161 case 0: // SHLR Rn 0100nnnn00000001
1162 case 2: // SHAR Rn 0100nnnn00100001
8796b7ee 1163 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1164 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1165 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1166 if (op & 0x20) {
1167 emith_asrf(tmp, tmp, 1);
1168 } else
1169 emith_lsrf(tmp, tmp, 1);
8b4f38f4 1170 emith_tpush_carry(sr, 0);
ed8cf79b 1171 goto end_op;
1172 case 1: // CMP/PZ Rn 0100nnnn00010001
8796b7ee 1173 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1174 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1175 emith_bic_r_imm(sr, T);
ed8cf79b 1176 emith_cmp_r_imm(tmp, 0);
1177 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1178 emith_or_r_imm_c(DCOND_GE, sr, T);
ed8cf79b 1179 EMITH_SJMP_END(DCOND_LT);
1180 goto end_op;
1181 }
1182 goto default_;
1183 case 0x02:
1184 case 0x03:
1185 switch (op & 0x3f)
1186 {
1187 case 0x02: // STS.L MACH,@–Rn 0100nnnn00000010
1188 tmp = SHR_MACH;
1189 break;
1190 case 0x12: // STS.L MACL,@–Rn 0100nnnn00010010
1191 tmp = SHR_MACL;
1192 break;
1193 case 0x22: // STS.L PR,@–Rn 0100nnnn00100010
1194 tmp = SHR_PR;
1195 break;
1196 case 0x03: // STC.L SR,@–Rn 0100nnnn00000011
1197 tmp = SHR_SR;
1198 break;
1199 case 0x13: // STC.L GBR,@–Rn 0100nnnn00010011
1200 tmp = SHR_GBR;
1201 break;
1202 case 0x23: // STC.L VBR,@–Rn 0100nnnn00100011
1203 tmp = SHR_VBR;
1204 break;
1205 default:
e898de13 1206 goto default_;
ed8cf79b 1207 }
1208 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1209 emith_sub_r_imm(tmp2, 4);
1210 rcache_clean();
1211 rcache_get_reg_arg(0, GET_Rn());
1212 tmp3 = rcache_get_reg_arg(1, tmp);
1213 if (tmp == SHR_SR)
1214 emith_clear_msb(tmp3, tmp3, 20); // reserved bits defined by ISA as 0
1215 emit_memhandler_write(2);
1216 goto end_op;
1217 case 0x04:
1218 case 0x05:
1219 switch (op & 0x3f)
1220 {
1221 case 0x04: // ROTL Rn 0100nnnn00000100
1222 case 0x05: // ROTR Rn 0100nnnn00000101
8796b7ee 1223 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1224 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1225 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1226 if (op & 1) {
1227 emith_rorf(tmp, tmp, 1);
1228 } else
1229 emith_rolf(tmp, tmp, 1);
8b4f38f4 1230 emith_tpush_carry(sr, 0);
ed8cf79b 1231 goto end_op;
1232 case 0x24: // ROTCL Rn 0100nnnn00100100
1233 case 0x25: // ROTCR Rn 0100nnnn00100101
8796b7ee 1234 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1235 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1236 emith_tpop_carry(sr, 0);
ed8cf79b 1237 if (op & 1) {
1238 emith_rorcf(tmp);
1239 } else
1240 emith_rolcf(tmp);
8b4f38f4 1241 emith_tpush_carry(sr, 0);
ed8cf79b 1242 goto end_op;
1243 case 0x15: // CMP/PL Rn 0100nnnn00010101
8796b7ee 1244 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1245 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1246 emith_bic_r_imm(sr, T);
ed8cf79b 1247 emith_cmp_r_imm(tmp, 0);
1248 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1249 emith_or_r_imm_c(DCOND_GT, sr, T);
ed8cf79b 1250 EMITH_SJMP_END(DCOND_LE);
1251 goto end_op;
1252 }
e898de13 1253 goto default_;
ed8cf79b 1254 case 0x06:
1255 case 0x07:
1256 switch (op & 0x3f)
1257 {
1258 case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
1259 tmp = SHR_MACH;
1260 break;
1261 case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
1262 tmp = SHR_MACL;
1263 break;
1264 case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
1265 tmp = SHR_PR;
1266 break;
1267 case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
1268 tmp = SHR_SR;
1269 break;
1270 case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
1271 tmp = SHR_GBR;
1272 break;
1273 case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
1274 tmp = SHR_VBR;
1275 break;
1276 default:
1277 goto default_;
1278 }
1279 rcache_clean();
1280 rcache_get_reg_arg(0, GET_Rn());
1281 tmp2 = emit_memhandler_read(2);
1282 if (tmp == SHR_SR) {
1283 emith_write_sr(tmp2);
1284 test_irq = 1;
1285 } else {
1286 tmp = rcache_get_reg(tmp, RC_GR_WRITE);
1287 emith_move_r_r(tmp, tmp2);
1288 }
1289 rcache_free_tmp(tmp2);
1290 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1291 emith_add_r_imm(tmp, 4);
1292 goto end_op;
52d759c3 1293 case 0x08:
1294 case 0x09:
1295 switch (GET_Fx())
1296 {
1297 case 0:
1298 // SHLL2 Rn 0100nnnn00001000
1299 // SHLR2 Rn 0100nnnn00001001
1300 tmp = 2;
1301 break;
1302 case 1:
1303 // SHLL8 Rn 0100nnnn00011000
1304 // SHLR8 Rn 0100nnnn00011001
1305 tmp = 8;
1306 break;
1307 case 2:
1308 // SHLL16 Rn 0100nnnn00101000
1309 // SHLR16 Rn 0100nnnn00101001
1310 tmp = 16;
1311 break;
1312 default:
1313 goto default_;
1314 }
1315 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1316 if (op & 1) {
1317 emith_lsr(tmp2, tmp2, tmp);
1318 } else
1319 emith_lsl(tmp2, tmp2, tmp);
1320 goto end_op;
1321 case 0x0a:
1322 switch (GET_Fx())
1323 {
1324 case 0: // LDS Rm,MACH 0100mmmm00001010
1325 tmp2 = SHR_MACH;
1326 break;
1327 case 1: // LDS Rm,MACL 0100mmmm00011010
1328 tmp2 = SHR_MACL;
1329 break;
1330 case 2: // LDS Rm,PR 0100mmmm00101010
1331 tmp2 = SHR_PR;
1332 break;
1333 default:
1334 goto default_;
1335 }
1336 emit_move_r_r(tmp2, GET_Rn());
1337 goto end_op;
e898de13 1338 case 0x0b:
52d759c3 1339 switch (GET_Fx())
1340 {
1341 case 0: // JSR @Rm 0100mmmm00001011
1342 case 2: // JMP @Rm 0100mmmm00101011
1343 DELAYED_OP;
1344 if (!(op & 0x20))
1345 emit_move_r_imm32(SHR_PR, pc + 2);
1346 emit_move_r_r(SHR_PPC, (op >> 8) & 0x0f);
1347 cycles++;
1348 break;
1349 case 1: // TAS.B @Rn 0100nnnn00011011
1350 // XXX: is TAS working on 32X?
1351 rcache_clean();
1352 rcache_get_reg_arg(0, GET_Rn());
8796b7ee 1353 tmp = emit_memhandler_read(0);
1354 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1355 emith_bic_r_imm(sr, T);
52d759c3 1356 emith_cmp_r_imm(tmp, 0);
8796b7ee 1357 emit_or_t_if_eq(sr);
52d759c3 1358 rcache_clean();
1359 emith_or_r_imm(tmp, 0x80);
1360 tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
1361 emith_move_r_r(tmp2, tmp);
1362 rcache_free_tmp(tmp);
1363 rcache_get_reg_arg(0, GET_Rn());
1364 emit_memhandler_write(0);
1365 cycles += 3;
1366 break;
1367 default:
e898de13 1368 goto default_;
52d759c3 1369 }
e898de13 1370 goto end_op;
1371 case 0x0e:
52d759c3 1372 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1373 switch (GET_Fx())
1374 {
1375 case 0: // LDC Rm,SR 0100mmmm00001110
1376 tmp2 = SHR_SR;
1377 break;
1378 case 1: // LDC Rm,GBR 0100mmmm00011110
1379 tmp2 = SHR_GBR;
1380 break;
1381 case 2: // LDC Rm,VBR 0100mmmm00101110
1382 tmp2 = SHR_VBR;
1383 break;
1384 default:
e898de13 1385 goto default_;
52d759c3 1386 }
1387 if (tmp2 == SHR_SR) {
1388 emith_write_sr(tmp);
52d759c3 1389 test_irq = 1;
1390 } else {
1391 tmp2 = rcache_get_reg(tmp2, RC_GR_WRITE);
1392 emith_move_r_r(tmp2, tmp);
1393 }
1394 goto end_op;
1395 case 0x0f:
1396 // MAC @Rm+,@Rn+ 0100nnnnmmmm1111
f0d7b1fa 1397 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 1);
1398 emith_sext(tmp, tmp, 16);
1399 emith_sext(tmp2, tmp2, 16);
1400 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
1401 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
1402 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 1403 rcache_free_tmp(tmp2);
f0d7b1fa 1404 // XXX: MACH should be untouched when S is set?
8796b7ee 1405 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1406 emith_tst_r_imm(sr, S);
1407 EMITH_JMP_START(DCOND_EQ);
1408
1409 emith_asr(tmp, tmp3, 31);
1410 emith_eorf_r_r(tmp, tmp4); // tmp = ((signed)macl >> 31) ^ mach
1411 EMITH_JMP_START(DCOND_EQ);
1412 emith_move_r_imm(tmp3, 0x80000000);
1413 emith_tst_r_r(tmp4, tmp4);
1414 EMITH_SJMP_START(DCOND_MI);
1415 emith_sub_r_imm_c(DCOND_PL, tmp3, 1); // positive
1416 EMITH_SJMP_END(DCOND_MI);
1417 EMITH_JMP_END(DCOND_EQ);
1418
1419 EMITH_JMP_END(DCOND_EQ);
1420 rcache_free_tmp(tmp);
f0d7b1fa 1421 cycles += 2;
1422 goto end_op;
679af8a3 1423 }
1424 goto default_;
1425
52d759c3 1426 /////////////////////////////////////////////
1427 case 0x05:
1428 // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
1429 rcache_clean();
1430 tmp = rcache_get_reg_arg(0, GET_Rm());
1431 emith_add_r_imm(tmp, (op & 0x0f) * 4);
1432 tmp = emit_memhandler_read(2);
1433 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1434 emith_move_r_r(tmp2, tmp);
1435 rcache_free_tmp(tmp);
1436 goto end_op;
1437
1438 /////////////////////////////////////////////
1439 case 0x06:
1440 switch (op & 0x0f)
1441 {
1442 case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
1443 case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
1444 case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
1445 case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
1446 case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
1447 case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
1448 rcache_clean();
1449 rcache_get_reg_arg(0, GET_Rm());
1450 tmp = emit_memhandler_read(op & 3);
1451 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1452 if ((op & 3) != 2) {
1453 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
1454 } else
1455 emith_move_r_r(tmp2, tmp);
1456 rcache_free_tmp(tmp);
1457 if ((op & 7) >= 4 && GET_Rn() != GET_Rm()) {
1458 tmp = rcache_get_reg(GET_Rm(), RC_GR_RMW);
1459 emith_add_r_imm(tmp, (1 << (op & 3)));
1460 }
1461 goto end_op;
1462 case 0x03:
1463 case 0x07 ... 0x0f:
1464 tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
1465 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1466 switch (op & 0x0f)
1467 {
1468 case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
1469 emith_move_r_r(tmp2, tmp);
1470 break;
1471 case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
1472 emith_mvn_r_r(tmp2, tmp);
1473 break;
1474 case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
1475 tmp3 = tmp2;
1476 if (tmp == tmp2)
1477 tmp3 = rcache_get_tmp();
1478 tmp4 = rcache_get_tmp();
1479 emith_lsr(tmp3, tmp, 16);
f0d7b1fa 1480 emith_or_r_r_lsl(tmp3, tmp, 24);
52d759c3 1481 emith_and_r_r_imm(tmp4, tmp, 0xff00);
f0d7b1fa 1482 emith_or_r_r_lsl(tmp3, tmp4, 8);
52d759c3 1483 emith_rol(tmp2, tmp3, 16);
1484 rcache_free_tmp(tmp4);
1485 if (tmp == tmp2)
1486 rcache_free_tmp(tmp3);
1487 break;
1488 case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
1489 emith_rol(tmp2, tmp, 16);
1490 break;
1491 case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
8796b7ee 1492 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
8b4f38f4 1493 emith_tpop_carry(sr, 1);
52d759c3 1494 emith_negcf_r_r(tmp2, tmp);
8b4f38f4 1495 emith_tpush_carry(sr, 1);
52d759c3 1496 break;
1497 case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
1498 emith_neg_r_r(tmp2, tmp);
1499 break;
1500 case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
1501 emith_clear_msb(tmp2, tmp, 24);
1502 break;
1503 case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
1504 emith_clear_msb(tmp2, tmp, 16);
1505 break;
1506 case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
1507 emith_sext(tmp2, tmp, 8);
1508 break;
1509 case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
1510 emith_sext(tmp2, tmp, 16);
1511 break;
1512 }
1513 goto end_op;
1514 }
1515 goto default_;
1516
1517 /////////////////////////////////////////////
1518 case 0x07:
1519 // ADD #imm,Rn 0111nnnniiiiiiii
1520 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1521 if (op & 0x80) { // adding negative
1522 emith_sub_r_imm(tmp, -op & 0xff);
1523 } else
1524 emith_add_r_imm(tmp, op & 0xff);
1525 goto end_op;
1526
3863edbd 1527 /////////////////////////////////////////////
e898de13 1528 case 0x08:
52d759c3 1529 switch (op & 0x0f00)
1530 {
1531 case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
1532 case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
1533 rcache_clean();
1534 tmp = rcache_get_reg_arg(0, GET_Rm());
1535 tmp2 = rcache_get_reg_arg(1, SHR_R0);
1536 tmp3 = (op & 0x100) >> 8;
1537 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
1538 emit_memhandler_write(tmp3);
1539 goto end_op;
1540 case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
1541 case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
1542 rcache_clean();
1543 tmp = rcache_get_reg_arg(0, GET_Rm());
1544 tmp3 = (op & 0x100) >> 8;
1545 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
1546 tmp = emit_memhandler_read(tmp3);
1547 tmp2 = rcache_get_reg(0, RC_GR_WRITE);
1548 emith_sext(tmp2, tmp, 8 << tmp3);
1549 rcache_free_tmp(tmp);
1550 goto end_op;
1551 case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
1552 // XXX: could use cmn
1553 tmp = rcache_get_tmp();
1554 tmp2 = rcache_get_reg(0, RC_GR_READ);
8796b7ee 1555 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
52d759c3 1556 emith_move_r_imm_s8(tmp, op & 0xff);
8796b7ee 1557 emith_bic_r_imm(sr, T);
52d759c3 1558 emith_cmp_r_r(tmp2, tmp);
8796b7ee 1559 emit_or_t_if_eq(sr);
52d759c3 1560 rcache_free_tmp(tmp);
1561 goto end_op;
1562 case 0x0d00: // BT/S label 10001101dddddddd
1563 case 0x0f00: // BF/S label 10001111dddddddd
679af8a3 1564 DELAYED_OP;
1565 cycles--;
679af8a3 1566 // fallthrough
52d759c3 1567 case 0x0900: // BT label 10001001dddddddd
1568 case 0x0b00: { // BF label 10001011dddddddd
80599a42 1569 // jmp_cond ~ cond when guest doesn't jump
1570 int jmp_cond = (op & 0x0200) ? DCOND_NE : DCOND_EQ;
1571 int insn_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
1572 signed int offs = ((signed int)(op << 24) >> 23);
1573 tmp = rcache_get_reg(delayed_op ? SHR_PPC : SHR_PC, RC_GR_WRITE);
1574 emith_move_r_imm(tmp, pc + (delayed_op ? 2 : 0));
1575 emith_sh2_test_t();
1576 EMITH_SJMP_START(jmp_cond);
1577 if (!delayed_op)
1578 offs += 2;
1579 if (offs < 0) {
1580 emith_sub_r_imm_c(insn_cond, tmp, -offs);
1581 } else
1582 emith_add_r_imm_c(insn_cond, tmp, offs);
1583 EMITH_SJMP_END(jmp_cond);
e898de13 1584 cycles += 2;
1585 if (!delayed_op)
52d759c3 1586 goto end_block_btf;
e898de13 1587 goto end_op;
80599a42 1588 }}
679af8a3 1589 goto default_;
679af8a3 1590
52d759c3 1591 /////////////////////////////////////////////
1592 case 0x09:
1593 // MOV.W @(disp,PC),Rn 1001nnnndddddddd
f0d7b1fa 1594 rcache_clean();
1595 tmp = rcache_get_tmp_arg(0);
1596 emith_move_r_imm(tmp, pc + (op & 0xff) * 2 + 2);
1597 tmp = emit_memhandler_read(1);
1598 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1599 emith_sext(tmp2, tmp, 16);
1600 rcache_free_tmp(tmp);
1601 goto end_op;
52d759c3 1602
3863edbd 1603 /////////////////////////////////////////////
679af8a3 1604 case 0x0a:
1605 // BRA label 1010dddddddddddd
1606 DELAYED_OP;
1607 do_bra:
1608 tmp = ((signed int)(op << 20) >> 19);
e898de13 1609 emit_move_r_imm32(SHR_PPC, pc + tmp + 2);
679af8a3 1610 cycles++;
e898de13 1611 break;
679af8a3 1612
3863edbd 1613 /////////////////////////////////////////////
679af8a3 1614 case 0x0b:
1615 // BSR label 1011dddddddddddd
1616 DELAYED_OP;
e898de13 1617 emit_move_r_imm32(SHR_PR, pc + 2);
679af8a3 1618 goto do_bra;
1619
52d759c3 1620 /////////////////////////////////////////////
1621 case 0x0c:
1622 switch (op & 0x0f00)
1623 {
1624 case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
1625 case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
1626 case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
1627 rcache_clean();
1628 tmp = rcache_get_reg_arg(0, SHR_GBR);
1629 tmp2 = rcache_get_reg_arg(1, SHR_R0);
1630 tmp3 = (op & 0x300) >> 8;
1631 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
1632 emit_memhandler_write(tmp3);
1633 goto end_op;
1634 case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
1635 case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
1636 case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
1637 rcache_clean();
1638 tmp = rcache_get_reg_arg(0, SHR_GBR);
1639 tmp3 = (op & 0x300) >> 8;
1640 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
1641 tmp = emit_memhandler_read(tmp3);
1642 tmp2 = rcache_get_reg(0, RC_GR_WRITE);
1643 if (tmp3 != 2) {
1644 emith_sext(tmp2, tmp, 8 << tmp3);
1645 } else
1646 emith_move_r_r(tmp2, tmp);
1647 rcache_free_tmp(tmp);
1648 goto end_op;
1649 case 0x0300: // TRAPA #imm 11000011iiiiiiii
1650 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
1651 emith_sub_r_imm(tmp, 4*2);
1652 rcache_clean();
1653 // push SR
1654 tmp = rcache_get_reg_arg(0, SHR_SP);
1655 emith_add_r_imm(tmp, 4);
1656 tmp = rcache_get_reg_arg(1, SHR_SR);
1657 emith_clear_msb(tmp, tmp, 20);
1658 emit_memhandler_write(2);
1659 // push PC
1660 rcache_get_reg_arg(0, SHR_SP);
1661 tmp = rcache_get_tmp_arg(1);
1662 emith_move_r_imm(tmp, pc);
1663 emit_memhandler_write(2);
1664 // obtain new PC
1665 tmp = rcache_get_reg_arg(0, SHR_VBR);
1666 emith_add_r_imm(tmp, (op & 0xff) * 4);
1667 tmp = emit_memhandler_read(2);
1668 tmp2 = rcache_get_reg(SHR_PC, RC_GR_WRITE);
1669 emith_move_r_r(tmp2, tmp);
1670 rcache_free_tmp(tmp);
1671 cycles += 7;
1672 goto end_block_btf;
1673 case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
1674 emit_move_r_imm32(SHR_R0, (pc + (op & 0xff) * 4 + 2) & ~3);
1675 goto end_op;
1676 case 0x0800: // TST #imm,R0 11001000iiiiiiii
8796b7ee 1677 tmp = rcache_get_reg(SHR_R0, RC_GR_READ);
1678 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1679 emith_bic_r_imm(sr, T);
52d759c3 1680 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 1681 emit_or_t_if_eq(sr);
52d759c3 1682 goto end_op;
1683 case 0x0900: // AND #imm,R0 11001001iiiiiiii
1684 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
1685 emith_and_r_imm(tmp, op & 0xff);
1686 goto end_op;
1687 case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
1688 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
1689 emith_eor_r_imm(tmp, op & 0xff);
1690 goto end_op;
1691 case 0x0b00: // OR #imm,R0 11001011iiiiiiii
1692 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
1693 emith_or_r_imm(tmp, op & 0xff);
1694 goto end_op;
1695 case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
8796b7ee 1696 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
1697 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1698 emith_bic_r_imm(sr, T);
52d759c3 1699 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 1700 emit_or_t_if_eq(sr);
52d759c3 1701 rcache_free_tmp(tmp);
1702 cycles += 2;
1703 goto end_op;
1704 case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
1705 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
1706 emith_and_r_imm(tmp, op & 0xff);
8796b7ee 1707 goto end_rmw_op;
52d759c3 1708 case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
1709 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
1710 emith_eor_r_imm(tmp, op & 0xff);
8796b7ee 1711 goto end_rmw_op;
52d759c3 1712 case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
1713 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
1714 emith_or_r_imm(tmp, op & 0xff);
8796b7ee 1715 end_rmw_op:
1716 tmp2 = rcache_get_tmp_arg(1);
1717 emith_move_r_r(tmp2, tmp);
1718 rcache_free_tmp(tmp);
1719 tmp3 = rcache_get_reg_arg(0, SHR_GBR);
1720 tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
1721 emith_add_r_r(tmp3, tmp4);
1722 emit_memhandler_write(0);
52d759c3 1723 cycles += 2;
1724 goto end_op;
1725 }
1726 goto default_;
1727
1728 /////////////////////////////////////////////
1729 case 0x0d:
1730 // MOV.L @(disp,PC),Rn 1101nnnndddddddd
f0d7b1fa 1731 rcache_clean();
1732 tmp = rcache_get_tmp_arg(0);
1733 emith_move_r_imm(tmp, (pc + (op & 0xff) * 4 + 2) & ~3);
1734 tmp = emit_memhandler_read(2);
1735 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1736 emith_move_r_r(tmp2, tmp);
1737 rcache_free_tmp(tmp);
1738 goto end_op;
52d759c3 1739
1740 /////////////////////////////////////////////
1741 case 0x0e:
1742 // MOV #imm,Rn 1110nnnniiiiiiii
1743 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1744 emith_move_r_imm_s8(tmp, op & 0xff);
1745 goto end_op;
1746
679af8a3 1747 default:
1748 default_:
f0d7b1fa 1749 elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
1750 sh2->is_slave ? 's' : 'm', op, pc - 2);
1751#ifdef DRC_DEBUG_INTERP
679af8a3 1752 emit_move_r_imm32(SHR_PC, pc - 2);
c18edb34 1753 rcache_flush();
f4bb5d6b 1754 emith_pass_arg_r(0, CONTEXT_REG);
1755 emith_pass_arg_imm(1, op);
679af8a3 1756 emith_call(sh2_do_op);
f0d7b1fa 1757#endif
679af8a3 1758 break;
1759 }
1760
e898de13 1761end_op:
6add7875 1762 if (delayed_op == 1)
e898de13 1763 emit_move_r_r(SHR_PC, SHR_PPC);
6add7875 1764
e898de13 1765 if (test_irq && delayed_op != 2) {
f0d7b1fa 1766 if (!delayed_op)
1767 emit_move_r_imm32(SHR_PC, pc);
c18edb34 1768 rcache_flush();
f4bb5d6b 1769 emith_pass_arg_r(0, CONTEXT_REG);
e898de13 1770 emith_call(sh2_test_irq);
f0d7b1fa 1771 goto end_block_btf;
e898de13 1772 }
6add7875 1773 if (delayed_op == 1)
1774 break;
e898de13 1775
f4bb5d6b 1776 do_host_disasm(tcache_id);
679af8a3 1777 }
1778
52d759c3 1779 // delayed_op means some kind of branch - PC already handled
1780 if (!delayed_op)
1781 emit_move_r_imm32(SHR_PC, pc);
1782
1783end_block_btf:
f4bb5d6b 1784 this_block->end_addr = pc;
1785
1786 // mark memory blocks as containing compiled code
1787 if ((sh2->pc & 0xe0000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
1788 // data array, BIOS
1789 u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
1790 tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
1791 tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
1792 Pico32xMem->drcblk_da[sh2->is_slave][tmp] = (blkid << 1) | 1;
1793 for (++tmp; tmp < tmp2; tmp++) {
1794 if (drcblk[tmp])
1795 break; // dont overwrite overlay block
1796 drcblk[tmp] = blkid << 1;
1797 }
1798 }
1799 else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
1800 tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
1801 tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
1802 Pico32xMem->drcblk_ram[tmp] = (blkid << 1) | 1;
1803 for (++tmp; tmp < tmp2; tmp++) {
1804 if (Pico32xMem->drcblk_ram[tmp])
1805 break;
1806 Pico32xMem->drcblk_ram[tmp] = blkid << 1;
1807 }
679af8a3 1808 }
1809
c18edb34 1810 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
1811 emith_sub_r_imm(tmp, cycles << 12);
1812 rcache_flush();
679af8a3 1813 emith_jump(sh2_drc_exit);
f4bb5d6b 1814 tcache_ptrs[tcache_id] = tcache_ptr;
1815
553c3eaa 1816#ifdef ARM
1817 cache_flush_d_inval_i(block_entry, tcache_ptr);
1818#endif
1819
f4bb5d6b 1820 do_host_disasm(tcache_id);
1821 dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
1822 tcache_id, block_counts[tcache_id],
1823 tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
1824 insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
1825 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
1826 dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
553c3eaa 1827#if (DRC_DEBUG & 2)
1828 fflush(stdout);
1829#endif
1830
679af8a3 1831 return block_entry;
f4bb5d6b 1832/*
679af8a3 1833unimplemented:
1834 // last op
f4bb5d6b 1835 do_host_disasm(tcache_id);
679af8a3 1836 exit(1);
f4bb5d6b 1837*/
679af8a3 1838}
1839
1840void __attribute__((noinline)) sh2_drc_dispatcher(SH2 *sh2)
1841{
52d759c3 1842 // TODO: need to handle self-caused interrupts
1843 sh2_test_irq(sh2);
1844
679af8a3 1845 while (((signed int)sh2->sr >> 12) > 0)
1846 {
679af8a3 1847 void *block = NULL;
f4bb5d6b 1848 block_desc *bd = NULL;
6add7875 1849
1850 // FIXME: must avoid doing it so often..
52d759c3 1851 //sh2_test_irq(sh2);
6add7875 1852
f4bb5d6b 1853 // we have full block id tables for data_array and RAM
1854 // BIOS goes to data_array table too
1855 if ((sh2->pc & 0xff000000) == 0xc0000000 || (sh2->pc & ~0xfff) == 0) {
1856 int blkid = Pico32xMem->drcblk_da[sh2->is_slave][(sh2->pc & 0xfff) >> SH2_DRCBLK_DA_SHIFT];
1857 if (blkid & 1) {
1858 bd = &block_tables[1 + sh2->is_slave][blkid >> 1];
1859 block = bd->tcache_ptr;
1860 }
1861 }
1862 // RAM
1863 else if ((sh2->pc & 0xc6000000) == 0x06000000) {
1864 int blkid = Pico32xMem->drcblk_ram[(sh2->pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT];
1865 if (blkid & 1) {
1866 bd = &block_tables[0][blkid >> 1];
679af8a3 1867 block = bd->tcache_ptr;
f4bb5d6b 1868 }
1869 }
1870 // ROM
1871 else if ((sh2->pc & 0xc6000000) == 0x02000000) {
1872 bd = HASH_FUNC(hash_table, sh2->pc);
1873
1874 if (bd != NULL) {
1875 if (bd->addr == sh2->pc)
1876 block = bd->tcache_ptr;
1877 else
1878 block = dr_find_block(bd, sh2->pc);
1879 }
679af8a3 1880 }
1881
1882 if (block == NULL)
1883 block = sh2_translate(sh2, bd);
1884
f4bb5d6b 1885 dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
1886 sh2->pc, block, (signed int)sh2->sr >> 12);
1887#if (DRC_DEBUG & 1)
1888 if (bd != NULL)
1889 bd->refcount++;
679af8a3 1890#endif
8796b7ee 1891 sh2_drc_entry(block, sh2);
679af8a3 1892 }
1893}
1894
f4bb5d6b 1895static void sh2_smc_rm_block(u16 *drcblk, u16 *p, block_desc *btab, u32 a)
1896{
1897 u16 id = *p >> 1;
1898 block_desc *bd = btab + id;
1899
1900 dbg(1, " killing block %08x", bd->addr);
1901 bd->addr = bd->end_addr = 0;
1902
1903 while (p > drcblk && (p[-1] >> 1) == id)
1904 p--;
1905
1906 // check for possible overlay block
1907 if (p > 0 && p[-1] != 0) {
1908 bd = btab + (p[-1] >> 1);
1909 if (bd->addr <= a && a < bd->end_addr)
1910 sh2_smc_rm_block(drcblk, p - 1, btab, a);
1911 }
1912
1913 do {
1914 *p++ = 0;
1915 }
1916 while ((*p >> 1) == id);
1917}
1918
1919void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
1920{
1921 u16 *drcblk = Pico32xMem->drcblk_ram;
1922 u16 *p = drcblk + ((a & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT);
1923
1924 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
1925 sh2_smc_rm_block(drcblk, p, block_tables[0], a);
1926}
1927
1928void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
1929{
1930 u16 *drcblk = Pico32xMem->drcblk_da[cpuid];
1931 u16 *p = drcblk + ((a & 0xfff) >> SH2_DRCBLK_DA_SHIFT);
1932
1933 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
1934 sh2_smc_rm_block(drcblk, p, block_tables[1 + cpuid], a);
1935}
1936
52d759c3 1937void sh2_execute(SH2 *sh2c, int cycles)
679af8a3 1938{
52d759c3 1939 sh2 = sh2c; // XXX
1940
1941 sh2c->cycles_aim += cycles;
1942 cycles = sh2c->cycles_aim - sh2c->cycles_done;
679af8a3 1943
1944 // cycles are kept in SHR_SR unused bits (upper 20)
52d759c3 1945 sh2c->sr &= 0x3f3;
1946 sh2c->sr |= cycles << 12;
1947 sh2_drc_dispatcher(sh2c);
679af8a3 1948
52d759c3 1949 sh2c->cycles_done += cycles - ((signed int)sh2c->sr >> 12);
679af8a3 1950}
1951
553c3eaa 1952static void REGPARM(1) sh2_test_irq(SH2 *sh2)
679af8a3 1953{
6add7875 1954 if (sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
1955 {
1956 if (sh2->pending_irl > sh2->pending_int_irq)
1957 sh2_do_irq(sh2, sh2->pending_irl, 64 + sh2->pending_irl/2);
1958 else {
1959 sh2_do_irq(sh2, sh2->pending_int_irq, sh2->pending_int_vector);
1960 sh2->pending_int_irq = 0; // auto-clear
1961 sh2->pending_level = sh2->pending_irl;
1962 }
1963 }
679af8a3 1964}
1965
f4bb5d6b 1966#if (DRC_DEBUG & 1)
1967static void block_stats(void)
1968{
1969 int c, b, i, total = 0;
1970
1971 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
1972 for (i = 0; i < block_counts[b]; i++)
1973 if (block_tables[b][i].addr != 0)
1974 total += block_tables[b][i].refcount;
1975
1976 for (c = 0; c < 10; c++) {
1977 block_desc *blk, *maxb = NULL;
1978 int max = 0;
1979 for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
1980 for (i = 0; i < block_counts[b]; i++) {
1981 blk = &block_tables[b][i];
1982 if (blk->addr != 0 && blk->refcount > max) {
1983 max = blk->refcount;
1984 maxb = blk;
1985 }
1986 }
1987 }
1988 if (maxb == NULL)
1989 break;
1990 printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
1991 (double)maxb->refcount / total * 100.0);
1992 maxb->refcount = 0;
1993 }
553c3eaa 1994
1995 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
1996 for (i = 0; i < block_counts[b]; i++)
1997 block_tables[b][i].refcount = 0;
f4bb5d6b 1998}
553c3eaa 1999#else
2000#define block_stats()
f4bb5d6b 2001#endif
2002
553c3eaa 2003void sh2_drc_flush_all(void)
2004{
2005 block_stats();
2006 flush_tcache(0);
2007 flush_tcache(1);
2008 flush_tcache(2);
2009}
2010
679af8a3 2011int sh2_drc_init(SH2 *sh2)
2012{
f4bb5d6b 2013 if (block_tables[0] == NULL) {
2014 int i, cnt;
7f5a3fc1 2015
2016 drc_cmn_init();
2017
f4bb5d6b 2018 cnt = block_max_counts[0] + block_max_counts[1] + block_max_counts[2];
2019 block_tables[0] = calloc(cnt, sizeof(*block_tables[0]));
2020 if (block_tables[0] == NULL)
e898de13 2021 return -1;
2022
8796b7ee 2023 tcache_ptr = tcache;
2024 sh2_generate_utils();
8b4f38f4 2025#ifdef ARM
2026 cache_flush_d_inval_i(tcache, tcache_ptr);
2027#endif
8796b7ee 2028
f4bb5d6b 2029 memset(block_counts, 0, sizeof(block_counts));
8796b7ee 2030 tcache_bases[0] = tcache_ptrs[0] = tcache_ptr;
f4bb5d6b 2031
2032 for (i = 1; i < ARRAY_SIZE(block_tables); i++) {
2033 block_tables[i] = block_tables[i - 1] + block_max_counts[i - 1];
2034 tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
2035 }
2036
553c3eaa 2037 // tmp
2038 PicoOpt |= POPT_DIS_VDP_FIFO;
2039
f4bb5d6b 2040#if (DRC_DEBUG & 2)
2041 for (i = 0; i < ARRAY_SIZE(block_tables); i++)
2042 tcache_dsm_ptrs[i] = tcache_bases[i];
8796b7ee 2043 // disasm the utils
2044 tcache_dsm_ptrs[0] = tcache;
2045 do_host_disasm(0);
f4bb5d6b 2046#endif
e898de13 2047#if (DRC_DEBUG & 1)
2048 hash_collisions = 0;
2049#endif
679af8a3 2050 }
2051
f4bb5d6b 2052 if (hash_table == NULL) {
2053 hash_table = calloc(sizeof(hash_table[0]), MAX_HASH_ENTRIES);
2054 if (hash_table == NULL)
2055 return -1;
2056 }
41397701 2057
679af8a3 2058 return 0;
41397701 2059}
2060
e898de13 2061void sh2_drc_finish(SH2 *sh2)
2062{
f4bb5d6b 2063 if (block_tables[0] != NULL) {
f4bb5d6b 2064 block_stats();
f4bb5d6b 2065 free(block_tables[0]);
2066 memset(block_tables, 0, sizeof(block_tables));
7f5a3fc1 2067
2068 drc_cmn_cleanup();
e898de13 2069 }
2070
f4bb5d6b 2071 if (hash_table != NULL) {
2072 free(hash_table);
2073 hash_table = NULL;
2074 }
e898de13 2075}