32x: drc: some constant propagation
[picodrive.git] / cpu / sh2 / compiler.c
CommitLineData
e898de13 1/*
2 * vim:shiftwidth=2:expandtab
44e6452e 3 *
4 * notes:
5 * - tcache, block descriptor, link buffer overflows result in sh2_translate()
6 * failure, followed by full tcache invalidation for that region
9bb5d91c 7 * - jumps between blocks are tracked for SMC handling (in block_links[]),
8 * except jumps between different tcaches
9 *
10 * implemented:
11 * - static register allocation
12 * - remaining register caching and tracking in temporaries
13 * - block-local branch linking
14 * - block linking (except between tcaches)
23686515 15 * - some constant propagation
9bb5d91c 16 *
17 * TODO:
18 * - proper SMC handling
23686515 19 * - better constant propagation
9bb5d91c 20 * - stack caching?
21 * - bug fixing
e898de13 22 */
f0d7b1fa 23#include <stddef.h>
679af8a3 24#include <stdio.h>
25#include <stdlib.h>
26#include <assert.h>
41397701 27
f4bb5d6b 28#include "../../pico/pico_int.h"
679af8a3 29#include "sh2.h"
30#include "compiler.h"
31#include "../drc/cmn.h"
32
23686515 33// features
34#define PROPAGATE_CONSTANTS 1
35#define LINK_BRANCHES 1
36
37// max literal offset from the block end
38#define MAX_LITERAL_OFFSET 32*2
39
8796b7ee 40// debug stuff {
e898de13 41#ifndef DRC_DEBUG
42#define DRC_DEBUG 0
43#endif
44
553c3eaa 45#if DRC_DEBUG
f4bb5d6b 46#define dbg(l,...) { \
47 if ((l) & DRC_DEBUG) \
48 elprintf(EL_STATUS, ##__VA_ARGS__); \
49}
50
e898de13 51#include "mame/sh2dasm.h"
52#include <platform/linux/host_dasm.h>
53static int insns_compiled, hash_collisions, host_insn_count;
553c3eaa 54#define COUNT_OP \
55 host_insn_count++
56#else // !DRC_DEBUG
57#define COUNT_OP
58#define dbg(...)
e898de13 59#endif
553c3eaa 60
e898de13 61#if (DRC_DEBUG & 2)
f4bb5d6b 62static u8 *tcache_dsm_ptrs[3];
e898de13 63static char sh2dasm_buff[64];
f4bb5d6b 64#define do_host_disasm(tcid) \
65 host_dasm(tcache_dsm_ptrs[tcid], tcache_ptr - tcache_dsm_ptrs[tcid]); \
66 tcache_dsm_ptrs[tcid] = tcache_ptr
67#else
68#define do_host_disasm(x)
e898de13 69#endif
e05b81fc 70
71#if (DRC_DEBUG & 4)
72static void REGPARM(3) *sh2_drc_announce_entry(void *block, SH2 *sh2, u32 sr)
73{
74 if (block != NULL)
75 dbg(4, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
76 sh2->pc, block, (signed int)sr >> 12);
77 return block;
78}
79#endif
8796b7ee 80// } debug
e898de13 81
679af8a3 82#define BLOCK_CYCLE_LIMIT 100
f4bb5d6b 83#define MAX_BLOCK_SIZE (BLOCK_CYCLE_LIMIT * 6 * 6)
44e6452e 84#define TCACHE_BUFFERS 3
f4bb5d6b 85
86// we have 3 translation cache buffers, split from one drc/cmn buffer.
87// BIOS shares tcache with data array because it's only used for init
88// and can be discarded early
8796b7ee 89// XXX: need to tune sizes
44e6452e 90static const int tcache_sizes[TCACHE_BUFFERS] = {
f4bb5d6b 91 DRC_TCACHE_SIZE * 6 / 8, // ROM, DRAM
92 DRC_TCACHE_SIZE / 8, // BIOS, data array in master sh2
93 DRC_TCACHE_SIZE / 8, // ... slave
94};
679af8a3 95
44e6452e 96static u8 *tcache_bases[TCACHE_BUFFERS];
97static u8 *tcache_ptrs[TCACHE_BUFFERS];
f4bb5d6b 98
99// ptr for code emiters
100static u8 *tcache_ptr;
e898de13 101
44e6452e 102typedef struct block_desc_ {
103 u32 addr; // SH2 PC address
104 u32 end_addr; // TODO rm?
105 void *tcache_ptr; // translated block for above PC
106 struct block_desc_ *next; // next block with the same PC hash
107#if (DRC_DEBUG & 1)
108 int refcount;
109#endif
110} block_desc;
111
112typedef struct block_link_ {
113 u32 target_pc;
114 void *jump;
115// struct block_link_ *next;
116} block_link;
117
118static const int block_max_counts[TCACHE_BUFFERS] = {
119 4*1024,
120 256,
121 256,
122};
123static block_desc *block_tables[TCACHE_BUFFERS];
124static block_link *block_links[TCACHE_BUFFERS];
125static int block_counts[TCACHE_BUFFERS];
126static int block_link_counts[TCACHE_BUFFERS];
127
c18edb34 128// host register tracking
129enum {
130 HR_FREE,
131 HR_CACHED, // 'val' has sh2_reg_e
23686515 132// HR_CONST, // 'val' has a constant
c18edb34 133 HR_TEMP, // reg used for temp storage
134};
135
23686515 136enum {
137 HRF_DIRTY = 1 << 0, // reg has "dirty" value to be written to ctx
138 HRF_LOCKED = 1 << 1, // HR_CACHED can't be evicted
139};
140
c18edb34 141typedef struct {
23686515 142 u32 hreg:5; // "host" reg
143 u32 greg:5; // "guest" reg
144 u32 type:3;
145 u32 flags:3;
146 u32 stamp:16; // kind of a timestamp
c18edb34 147} temp_reg_t;
148
80599a42 149// note: reg_temp[] must have at least the amount of
3863edbd 150// registers used by handlers in worst case (currently 4)
65c75cb0 151#ifdef ARM
152#include "../drc/emit_arm.c"
153
154static const int reg_map_g2h[] = {
8b4f38f4 155 4, 5, 6, 7,
156 8, -1, -1, -1,
c18edb34 157 -1, -1, -1, -1,
8b4f38f4 158 -1, -1, -1, 9,
159 -1, -1, -1, 10,
c18edb34 160 -1, -1, -1, -1,
161};
162
163static temp_reg_t reg_temp[] = {
164 { 0, },
165 { 1, },
166 { 12, },
167 { 14, },
168 { 2, },
169 { 3, },
65c75cb0 170};
171
e05b81fc 172#elif defined(__i386__)
e898de13 173#include "../drc/emit_x86.c"
174
65c75cb0 175static const int reg_map_g2h[] = {
8b4f38f4 176 xSI,-1, -1, -1,
c18edb34 177 -1, -1, -1, -1,
178 -1, -1, -1, -1,
179 -1, -1, -1, -1,
8b4f38f4 180 -1, -1, -1, xDI,
c18edb34 181 -1, -1, -1, -1,
182};
183
3863edbd 184// ax, cx, dx are usually temporaries by convention
c18edb34 185static temp_reg_t reg_temp[] = {
186 { xAX, },
3863edbd 187 { xBX, },
c18edb34 188 { xCX, },
189 { xDX, },
65c75cb0 190};
191
e05b81fc 192#else
193#error unsupported arch
65c75cb0 194#endif
195
80599a42 196#define T 0x00000001
197#define S 0x00000002
198#define I 0x000000f0
199#define Q 0x00000100
200#define M 0x00000200
18b94127 201#define T_save 0x00000800
80599a42 202
e05b81fc 203#define I_SHIFT 4
f0d7b1fa 204#define Q_SHIFT 8
205#define M_SHIFT 9
206
f4bb5d6b 207// ROM hash table
679af8a3 208#define MAX_HASH_ENTRIES 1024
209#define HASH_MASK (MAX_HASH_ENTRIES - 1)
f4bb5d6b 210static void **hash_table;
679af8a3 211
18b94127 212#define HASH_FUNC(hash_tab, addr) \
213 ((block_desc **)(hash_tab))[(addr) & HASH_MASK]
214
e05b81fc 215static void REGPARM(1) (*sh2_drc_entry)(SH2 *sh2);
216static void (*sh2_drc_dispatcher)(void);
217static void (*sh2_drc_exit)(void);
218static void (*sh2_drc_test_irq)(void);
219static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
220static void REGPARM(2) (*sh2_drc_write8_slot)(u32 a, u32 d);
221static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
222static void REGPARM(2) (*sh2_drc_write16_slot)(u32 a, u32 d);
679af8a3 223
553c3eaa 224extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
679af8a3 225
f4bb5d6b 226static void flush_tcache(int tcid)
227{
553c3eaa 228 dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
f4bb5d6b 229 tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
230 block_counts[tcid], block_max_counts[tcid]);
231
232 block_counts[tcid] = 0;
233 tcache_ptrs[tcid] = tcache_bases[tcid];
234 if (tcid == 0) { // ROM, RAM
235 memset(hash_table, 0, sizeof(hash_table[0]) * MAX_HASH_ENTRIES);
236 memset(Pico32xMem->drcblk_ram, 0, sizeof(Pico32xMem->drcblk_ram));
237 }
238 else
239 memset(Pico32xMem->drcblk_da[tcid - 1], 0, sizeof(Pico32xMem->drcblk_da[0]));
240#if (DRC_DEBUG & 2)
241 tcache_dsm_ptrs[tcid] = tcache_bases[tcid];
242#endif
243}
244
44e6452e 245// add block links (tracked branches)
246static int dr_add_block_link(u32 target_pc, void *jump, int tcache_id)
247{
248 block_link *bl = block_links[tcache_id];
249 int cnt = block_link_counts[tcache_id];
250
251 if (cnt >= block_max_counts[tcache_id] * 2) {
252 printf("bl overflow for tcache %d\n", tcache_id);
253 return -1;
254 }
255
256 bl[cnt].target_pc = target_pc;
257 bl[cnt].jump = jump;
258 block_link_counts[tcache_id]++;
259
260 return 0;
261}
262
679af8a3 263static void *dr_find_block(block_desc *tab, u32 addr)
264{
265 for (tab = tab->next; tab != NULL; tab = tab->next)
266 if (tab->addr == addr)
267 break;
268
269 if (tab != NULL)
270 return tab->tcache_ptr;
271
272 printf("block miss for %08x\n", addr);
273 return NULL;
274}
275
f4bb5d6b 276static block_desc *dr_add_block(u32 addr, int tcache_id, int *blk_id)
679af8a3 277{
f4bb5d6b 278 int *bcount = &block_counts[tcache_id];
679af8a3 279 block_desc *bd;
280
44e6452e 281 if (*bcount >= block_max_counts[tcache_id]) {
282 printf("bd overflow for tcache %d\n", tcache_id);
f4bb5d6b 283 return NULL;
44e6452e 284 }
679af8a3 285
f4bb5d6b 286 bd = &block_tables[tcache_id][*bcount];
679af8a3 287 bd->addr = addr;
288 bd->tcache_ptr = tcache_ptr;
f4bb5d6b 289 *blk_id = *bcount;
290 (*bcount)++;
679af8a3 291
18b94127 292 if ((addr & 0xc6000000) == 0x02000000) { // ROM
293 bd->next = HASH_FUNC(hash_table, addr);
294 HASH_FUNC(hash_table, addr) = bd;
295#if (DRC_DEBUG & 1)
296 if (bd->next != NULL) {
297 printf(" hash collision with %08x\n", bd->next->addr);
298 hash_collisions++;
299 }
300#endif
301 }
302
679af8a3 303 return bd;
304}
305
44e6452e 306#define ADD_TO_ARRAY(array, count, item, failcode) \
307 array[count++] = item; \
308 if (count >= ARRAY_SIZE(array)) { \
309 printf("warning: " #array " overflow\n"); \
310 failcode; \
311 }
312
18b94127 313int find_in_array(u32 *array, size_t size, u32 what)
314{
315 size_t i;
316 for (i = 0; i < size; i++)
317 if (what == array[i])
318 return i;
319
320 return -1;
321}
679af8a3 322
323// ---------------------------------------------------------------
324
23686515 325typedef enum {
326 RC_GR_READ,
327 RC_GR_WRITE,
328 RC_GR_RMW,
329} rc_gr_mode;
330
331static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking);
332
333// guest regs with constants
334static u32 dr_gcregs[24];
335// a mask of constant/dirty regs
336static u32 dr_gcregs_mask;
337static u32 dr_gcregs_dirty;
338
339static void gconst_new(sh2_reg_e r, u32 val)
340{
341#if PROPAGATE_CONSTANTS
342 int i;
343
344 dr_gcregs_mask |= 1 << r;
345 dr_gcregs_dirty |= 1 << r;
346 dr_gcregs[r] = val;
347
348 // throw away old r that we might have cached
349 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
350 if ((reg_temp[i].type == HR_CACHED) &&
351 reg_temp[i].greg == r) {
352 reg_temp[i].type = HR_FREE;
353 reg_temp[i].flags = 0;
354 }
355 }
356#endif
357}
358
359static int gconst_get(sh2_reg_e r, u32 *val)
360{
361 if (dr_gcregs_mask & (1 << r)) {
362 *val = dr_gcregs[r];
363 return 1;
364 }
365 return 0;
366}
367
368static int gconst_check(sh2_reg_e r)
369{
370 if ((dr_gcregs_mask | dr_gcregs_dirty) & (1 << r))
371 return 1;
372 return 0;
373}
374
375// update hr if dirty, else do nothing
376static int gconst_try_read(int hr, sh2_reg_e r)
377{
378 if (dr_gcregs_dirty & (1 << r)) {
379 emith_move_r_imm(hr, dr_gcregs[r]);
380 dr_gcregs_dirty &= ~(1 << r);
381 return 1;
382 }
383 return 0;
384}
385
386static void gconst_check_evict(sh2_reg_e r)
387{
388 if (dr_gcregs_mask & (1 << r))
389 // no longer cached in reg, make dirty again
390 dr_gcregs_dirty |= 1 << r;
391}
392
393static void gconst_kill(sh2_reg_e r)
394{
395 dr_gcregs_mask &= ~(1 << r);
396 dr_gcregs_dirty &= ~(1 << r);
397}
398
399static void gconst_clean(void)
400{
401 int i;
402
403 for (i = 0; i < ARRAY_SIZE(dr_gcregs); i++)
404 if (dr_gcregs_dirty & (1 << i)) {
405 // using RC_GR_READ here: it will call gconst_try_read,
406 // cache the reg and mark it dirty.
407 rcache_get_reg_(i, RC_GR_READ, 0);
408 }
409}
410
411static void gconst_invalidate(void)
412{
413 dr_gcregs_mask = dr_gcregs_dirty = 0;
414}
415
c18edb34 416// register chache
417static u16 rcache_counter;
418
419static temp_reg_t *rcache_evict(void)
41397701 420{
c18edb34 421 // evict reg with oldest stamp
422 int i, oldest = -1;
423 u16 min_stamp = (u16)-1;
424
425 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
23686515 426 if (reg_temp[i].type == HR_CACHED && !(reg_temp[i].flags & HRF_LOCKED) &&
427 reg_temp[i].stamp <= min_stamp) {
428 min_stamp = reg_temp[i].stamp;
429 oldest = i;
430 }
c18edb34 431 }
432
433 if (oldest == -1) {
80599a42 434 printf("no registers to evict, aborting\n");
c18edb34 435 exit(1);
436 }
437
438 i = oldest;
23686515 439 if (reg_temp[i].type == HR_CACHED) {
440 if (reg_temp[i].flags & HRF_DIRTY)
441 // writeback
442 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
443 gconst_check_evict(reg_temp[i].greg);
c18edb34 444 }
445
23686515 446 reg_temp[i].type = HR_FREE;
447 reg_temp[i].flags = 0;
c18edb34 448 return &reg_temp[i];
679af8a3 449}
450
23686515 451static int get_reg_static(sh2_reg_e r, rc_gr_mode mode)
452{
453 int i = reg_map_g2h[r];
454 if (i != -1) {
455 if (mode != RC_GR_WRITE)
456 gconst_try_read(i, r);
457 }
458 return i;
459}
c18edb34 460
80599a42 461// note: must not be called when doing conditional code
23686515 462static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking)
679af8a3 463{
c18edb34 464 temp_reg_t *tr;
23686515 465 int i, ret;
c18edb34 466
23686515 467 // maybe statically mapped?
468 ret = get_reg_static(r, mode);
469 if (ret != -1)
470 goto end;
679af8a3 471
c18edb34 472 rcache_counter++;
473
474 // maybe already cached?
23686515 475 // if so, prefer against gconst (they must be in sync)
c18edb34 476 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 477 if (reg_temp[i].type == HR_CACHED && reg_temp[i].greg == r) {
c18edb34 478 reg_temp[i].stamp = rcache_counter;
479 if (mode != RC_GR_READ)
23686515 480 reg_temp[i].flags |= HRF_DIRTY;
481 ret = reg_temp[i].hreg;
482 goto end;
c18edb34 483 }
679af8a3 484 }
485
c18edb34 486 // use any free reg
487 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 488 if (reg_temp[i].type == HR_FREE) {
c18edb34 489 tr = &reg_temp[i];
490 goto do_alloc;
491 }
492 }
493
494 tr = rcache_evict();
495
496do_alloc:
23686515 497 tr->type = HR_CACHED;
498 if (do_locking)
499 tr->flags |= HRF_LOCKED;
500 if (mode != RC_GR_READ)
501 tr->flags |= HRF_DIRTY;
502 tr->greg = r;
c18edb34 503 tr->stamp = rcache_counter;
23686515 504 ret = tr->hreg;
505
506 if (mode != RC_GR_WRITE) {
507 if (gconst_check(r)) {
508 if (gconst_try_read(ret, r))
509 tr->flags |= HRF_DIRTY;
510 }
511 else
512 emith_ctx_read(tr->hreg, r * 4);
513 }
514
515end:
516 if (mode != RC_GR_READ)
517 gconst_kill(r);
518
519 return ret;
520}
521
522static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
523{
524 return rcache_get_reg_(r, mode, 1);
679af8a3 525}
526
c18edb34 527static int rcache_get_tmp(void)
679af8a3 528{
c18edb34 529 temp_reg_t *tr;
530 int i;
531
532 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 533 if (reg_temp[i].type == HR_FREE) {
c18edb34 534 tr = &reg_temp[i];
535 goto do_alloc;
536 }
537
538 tr = rcache_evict();
539
540do_alloc:
541 tr->type = HR_TEMP;
23686515 542 return tr->hreg;
c18edb34 543}
544
80599a42 545static int rcache_get_arg_id(int arg)
546{
547 int i, r = 0;
548 host_arg2reg(r, arg);
549
550 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 551 if (reg_temp[i].hreg == r)
80599a42 552 break;
553
554 if (i == ARRAY_SIZE(reg_temp))
555 // let's just say it's untracked arg reg
556 return r;
557
23686515 558 if (reg_temp[i].type == HR_CACHED) {
80599a42 559 // writeback
23686515 560 if (reg_temp[i].flags & HRF_DIRTY)
561 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
562 gconst_check_evict(reg_temp[i].greg);
80599a42 563 }
564 else if (reg_temp[i].type == HR_TEMP) {
565 printf("arg %d reg %d already used, aborting\n", arg, r);
566 exit(1);
567 }
568
23686515 569 reg_temp[i].type = HR_FREE;
570 reg_temp[i].flags = 0;
571
80599a42 572 return i;
573}
574
575// get a reg to be used as function arg
80599a42 576static int rcache_get_tmp_arg(int arg)
577{
578 int id = rcache_get_arg_id(arg);
579 reg_temp[id].type = HR_TEMP;
580
23686515 581 return reg_temp[id].hreg;
80599a42 582}
583
23686515 584// same but caches a reg. RC_GR_READ only.
80599a42 585static int rcache_get_reg_arg(int arg, sh2_reg_e r)
586{
587 int i, srcr, dstr, dstid;
23686515 588 int dirty = 0;
80599a42 589
590 dstid = rcache_get_arg_id(arg);
23686515 591 dstr = reg_temp[dstid].hreg;
80599a42 592
593 // maybe already statically mapped?
23686515 594 srcr = get_reg_static(r, RC_GR_READ);
80599a42 595 if (srcr != -1)
596 goto do_cache;
597
598 // maybe already cached?
599 for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
23686515 600 if ((reg_temp[i].type == HR_CACHED) &&
601 reg_temp[i].greg == r)
80599a42 602 {
23686515 603 srcr = reg_temp[i].hreg;
80599a42 604 goto do_cache;
605 }
606 }
607
608 // must read
609 srcr = dstr;
23686515 610 if (gconst_check(r)) {
611 if (gconst_try_read(srcr, r))
612 dirty = 1;
613 }
614 else
615 emith_ctx_read(srcr, r * 4);
80599a42 616
617do_cache:
23686515 618 if (dstr != srcr)
80599a42 619 emith_move_r_r(dstr, srcr);
620
621 reg_temp[dstid].stamp = ++rcache_counter;
622 reg_temp[dstid].type = HR_CACHED;
23686515 623 reg_temp[dstid].greg = r;
624 reg_temp[dstid].flags |= HRF_LOCKED;
625 if (dirty)
626 reg_temp[dstid].flags |= HRF_DIRTY;
80599a42 627 return dstr;
628}
629
c18edb34 630static void rcache_free_tmp(int hr)
631{
632 int i;
633 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 634 if (reg_temp[i].hreg == hr)
c18edb34 635 break;
636
80599a42 637 if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP) {
c18edb34 638 printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
80599a42 639 return;
640 }
641
642 reg_temp[i].type = HR_FREE;
23686515 643 reg_temp[i].flags = 0;
644}
645
646static void rcache_unlock(int hr)
647{
648 int i;
649 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
650 if (reg_temp[i].type == HR_CACHED && reg_temp[i].hreg == hr)
651 reg_temp[i].flags &= ~HRF_LOCKED;
652}
653
654static void rcache_unlock_all(void)
655{
656 int i;
657 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
658 reg_temp[i].flags &= ~HRF_LOCKED;
c18edb34 659}
660
80599a42 661static void rcache_clean(void)
c18edb34 662{
663 int i;
23686515 664 gconst_clean();
665
80599a42 666 for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
23686515 667 if (reg_temp[i].type == HR_CACHED && (reg_temp[i].flags & HRF_DIRTY)) {
c18edb34 668 // writeback
23686515 669 emith_ctx_write(reg_temp[i].hreg, reg_temp[i].greg * 4);
670 reg_temp[i].flags &= ~HRF_DIRTY;
c18edb34 671 }
80599a42 672}
673
674static void rcache_invalidate(void)
675{
676 int i;
23686515 677 for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
c18edb34 678 reg_temp[i].type = HR_FREE;
23686515 679 reg_temp[i].flags = 0;
680 }
c18edb34 681 rcache_counter = 0;
23686515 682
683 gconst_invalidate();
c18edb34 684}
685
80599a42 686static void rcache_flush(void)
687{
688 rcache_clean();
689 rcache_invalidate();
690}
691
c18edb34 692// ---------------------------------------------------------------
693
23686515 694// address space stuff
695static void *dr_get_pc_base(u32 pc, int is_slave)
696{
697 void *ret = NULL;
698 u32 mask = 0;
699
700 if ((pc & ~0x7ff) == 0) {
701 // BIOS
702 ret = is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
703 mask = 0x7ff;
704 }
705 else if ((pc & 0xfffff000) == 0xc0000000) {
706 // data array
707 ret = Pico32xMem->data_array[is_slave];
708 mask = 0xfff;
709 }
710 else if ((pc & 0xc6000000) == 0x06000000) {
711 // SDRAM
712 ret = Pico32xMem->sdram;
713 mask = 0x03ffff;
714 }
715 else if ((pc & 0xc6000000) == 0x02000000) {
716 // ROM
717 ret = Pico.rom;
718 mask = 0x3fffff;
719 }
720
721 if (ret == NULL)
722 return (void *)-1; // NULL is valid value
723
724 return (char *)ret - (pc & ~mask);
725}
726
727static int emit_get_rbase_and_offs(u32 a, u32 *offs)
728{
729 int poffs = -1;
730 u32 mask = 0;
731 int hr;
732
733 if ((a & ~0x7ff) == 0) {
734 // BIOS
735 poffs = offsetof(SH2, p_bios);
736 mask = 0x7ff;
737 }
738 else if ((a & 0xfffff000) == 0xc0000000) {
739 // data array
740 poffs = offsetof(SH2, p_da);
741 mask = 0xfff;
742 }
743 else if ((a & 0xc6000000) == 0x06000000) {
744 // SDRAM
745 poffs = offsetof(SH2, p_sdram);
746 mask = 0x03ffff;
747 }
748 else if ((a & 0xc6000000) == 0x02000000) {
749 // ROM
750 poffs = offsetof(SH2, p_rom);
751 mask = 0x3fffff;
752 }
753
754 if (poffs == -1)
755 return -1;
756
757 // XXX: could use related reg
758 hr = rcache_get_tmp();
759 emith_ctx_read(hr, poffs);
760 emith_add_r_imm(hr, a & mask & ~0xff);
761 *offs = a & 0xff; // XXX: ARM oriented..
762 return hr;
763}
764
765static void REGPARM(3) *lookup_block(u32 pc, int is_slave, int *tcache_id)
766{
767 block_desc *bd = NULL;
768 void *block = NULL;
769 *tcache_id = 0;
770
771 // we have full block id tables for data_array and RAM
772 // BIOS goes to data_array table too
773 if ((pc & 0xe0000000) == 0xc0000000 || (pc & ~0xfff) == 0) {
774 int blkid = Pico32xMem->drcblk_da[is_slave][(pc & 0xfff) >> SH2_DRCBLK_DA_SHIFT];
775 *tcache_id = 1 + is_slave;
776 if (blkid & 1) {
777 bd = &block_tables[*tcache_id][blkid >> 1];
778 block = bd->tcache_ptr;
779 }
780 }
781 // RAM
782 else if ((pc & 0xc6000000) == 0x06000000) {
783 int blkid = Pico32xMem->drcblk_ram[(pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT];
784 if (blkid & 1) {
785 bd = &block_tables[0][blkid >> 1];
786 block = bd->tcache_ptr;
787 }
788 }
789 // ROM
790 else if ((pc & 0xc6000000) == 0x02000000) {
791 bd = HASH_FUNC(hash_table, pc);
792
793 if (bd != NULL) {
794 if (bd->addr == pc)
795 block = bd->tcache_ptr;
796 else
797 block = dr_find_block(bd, pc);
798 }
799 }
800
801#if (DRC_DEBUG & 1)
802 if (bd != NULL)
803 bd->refcount++;
804#endif
805 return block;
806}
807
c18edb34 808static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
809{
23686515 810#if PROPAGATE_CONSTANTS
811 gconst_new(dst, imm);
812#else
c18edb34 813 int hr = rcache_get_reg(dst, RC_GR_WRITE);
814 emith_move_r_imm(hr, imm);
23686515 815#endif
c18edb34 816}
817
818static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
819{
820 int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
821 int hr_s = rcache_get_reg(src, RC_GR_READ);
822
823 emith_move_r_r(hr_d, hr_s);
679af8a3 824}
825
52d759c3 826// T must be clear, and comparison done just before this
827static void emit_or_t_if_eq(int srr)
828{
829 EMITH_SJMP_START(DCOND_NE);
830 emith_or_r_imm_c(DCOND_EQ, srr, T);
831 EMITH_SJMP_END(DCOND_NE);
832}
833
80599a42 834// arguments must be ready
835// reg cache must be clean before call
23686515 836static int emit_memhandler_read_(int size, int ram_check)
679af8a3 837{
b081408f 838 int arg0, arg1;
839 host_arg2reg(arg0, 0);
840
23686515 841 rcache_clean();
842
b081408f 843 // must writeback cycles for poll detection stuff
23686515 844 // FIXME: rm
b081408f 845 if (reg_map_g2h[SHR_SR] != -1)
846 emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
23686515 847
b081408f 848 arg1 = rcache_get_tmp_arg(1);
849 emith_move_r_r(arg1, CONTEXT_REG);
850
851#if 1
23686515 852 if (ram_check && Pico.rom == (void *)0x02000000 && Pico32xMem->sdram == (void *)0x06000000) {
b081408f 853 int tmp = rcache_get_tmp();
854 emith_and_r_r_imm(tmp, arg0, 0xfb000000);
855 emith_cmp_r_imm(tmp, 0x02000000);
856 switch (size) {
857 case 0: // 8
858 EMITH_SJMP3_START(DCOND_NE);
859 emith_eor_r_imm_c(DCOND_EQ, arg0, 1);
860 emith_read8_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
861 EMITH_SJMP3_MID(DCOND_NE);
862 emith_call_cond(DCOND_NE, p32x_sh2_read8);
863 EMITH_SJMP3_END();
864 break;
865 case 1: // 16
866 EMITH_SJMP3_START(DCOND_NE);
867 emith_read16_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
868 EMITH_SJMP3_MID(DCOND_NE);
869 emith_call_cond(DCOND_NE, p32x_sh2_read16);
870 EMITH_SJMP3_END();
871 break;
872 case 2: // 32
873 EMITH_SJMP3_START(DCOND_NE);
874 emith_read_r_r_offs_c(DCOND_EQ, arg0, arg0, 0);
875 emith_ror_c(DCOND_EQ, arg0, arg0, 16);
876 EMITH_SJMP3_MID(DCOND_NE);
877 emith_call_cond(DCOND_NE, p32x_sh2_read32);
878 EMITH_SJMP3_END();
879 break;
880 }
881 }
882 else
883#endif
884 {
885 switch (size) {
886 case 0: // 8
887 emith_call(p32x_sh2_read8);
888 break;
889 case 1: // 16
890 emith_call(p32x_sh2_read16);
891 break;
892 case 2: // 32
893 emith_call(p32x_sh2_read32);
894 break;
895 }
679af8a3 896 }
80599a42 897 rcache_invalidate();
898 // assuming arg0 and retval reg matches
899 return rcache_get_tmp_arg(0);
900}
679af8a3 901
23686515 902static int emit_memhandler_read(int size)
903{
904 return emit_memhandler_read_(size, 1);
905}
906
907static int emit_memhandler_read_rr(sh2_reg_e rd, sh2_reg_e rs, u32 offs, int size)
908{
909 int hr, hr2, ram_check = 1;
910 u32 val, offs2;
911
912 if (gconst_get(rs, &val)) {
913 hr = emit_get_rbase_and_offs(val + offs, &offs2);
914 if (hr != -1) {
915 hr2 = rcache_get_reg(rd, RC_GR_WRITE);
916 switch (size) {
917 case 0: // 8
918 emith_read8_r_r_offs(hr2, hr, offs2 ^ 1);
919 emith_sext(hr2, hr2, 8);
920 break;
921 case 1: // 16
922 emith_read16_r_r_offs(hr2, hr, offs2);
923 emith_sext(hr2, hr2, 16);
924 break;
925 case 2: // 32
926 emith_read_r_r_offs(hr2, hr, offs2);
927 emith_ror(hr2, hr2, 16);
928 break;
929 }
930 rcache_free_tmp(hr);
931 return hr2;
932 }
933
934 ram_check = 0;
935 }
936
937 hr = rcache_get_reg_arg(0, rs);
938 if (offs != 0)
939 emith_add_r_imm(hr, offs);
940 hr = emit_memhandler_read_(size, ram_check);
941 hr2 = rcache_get_reg(rd, RC_GR_WRITE);
942 if (size != 2) {
943 emith_sext(hr2, hr, (size == 1) ? 16 : 8);
944 } else
945 emith_move_r_r(hr2, hr);
946 rcache_free_tmp(hr);
947
948 return hr2;
949}
950
e05b81fc 951static void emit_memhandler_write(int size, u32 pc, int delay)
80599a42 952{
953 int ctxr;
954 host_arg2reg(ctxr, 2);
80599a42 955 switch (size) {
956 case 0: // 8
e05b81fc 957 // XXX: consider inlining sh2_drc_write8
958 if (delay) {
959 emith_call(sh2_drc_write8_slot);
960 } else {
961 emit_move_r_imm32(SHR_PC, pc);
962 rcache_clean();
963 emith_call(sh2_drc_write8);
964 }
80599a42 965 break;
966 case 1: // 16
e05b81fc 967 if (delay) {
968 emith_call(sh2_drc_write16_slot);
969 } else {
970 emit_move_r_imm32(SHR_PC, pc);
971 rcache_clean();
972 emith_call(sh2_drc_write16);
973 }
80599a42 974 break;
975 case 2: // 32
e05b81fc 976 emith_move_r_r(ctxr, CONTEXT_REG);
80599a42 977 emith_call(p32x_sh2_write32);
978 break;
979 }
980 rcache_invalidate();
679af8a3 981}
80599a42 982
52d759c3 983// @(Rx,Ry)
984static int emit_indirect_indexed_read(int rx, int ry, int size)
985{
986 int a0, t;
52d759c3 987 a0 = rcache_get_reg_arg(0, rx);
988 t = rcache_get_reg(ry, RC_GR_READ);
989 emith_add_r_r(a0, t);
990 return emit_memhandler_read(size);
991}
992
f0d7b1fa 993// read @Rn, @rm
994static void emit_indirect_read_double(u32 *rnr, u32 *rmr, int rn, int rm, int size)
995{
996 int tmp;
997
f0d7b1fa 998 rcache_get_reg_arg(0, rn);
999 tmp = emit_memhandler_read(size);
1000 emith_ctx_write(tmp, offsetof(SH2, drc_tmp));
1001 rcache_free_tmp(tmp);
1002 tmp = rcache_get_reg(rn, RC_GR_RMW);
1003 emith_add_r_imm(tmp, 1 << size);
23686515 1004 rcache_unlock(tmp);
f0d7b1fa 1005
f0d7b1fa 1006 rcache_get_reg_arg(0, rm);
1007 *rmr = emit_memhandler_read(size);
1008 *rnr = rcache_get_tmp();
1009 emith_ctx_read(*rnr, offsetof(SH2, drc_tmp));
1010 tmp = rcache_get_reg(rm, RC_GR_RMW);
1011 emith_add_r_imm(tmp, 1 << size);
23686515 1012 rcache_unlock(tmp);
f0d7b1fa 1013}
1014
8796b7ee 1015static void emit_do_static_regs(int is_write, int tmpr)
f0d7b1fa 1016{
8796b7ee 1017 int i, r, count;
1018
1019 for (i = 0; i < ARRAY_SIZE(reg_map_g2h); i++) {
1020 r = reg_map_g2h[i];
1021 if (r == -1)
1022 continue;
1023
1024 for (count = 1; i < ARRAY_SIZE(reg_map_g2h) - 1; i++, r++) {
1025 if (reg_map_g2h[i + 1] != r + 1)
1026 break;
1027 count++;
1028 }
1029
1030 if (count > 1) {
1031 // i, r point to last item
1032 if (is_write)
1033 emith_ctx_write_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
1034 else
1035 emith_ctx_read_multiple(r - count + 1, (i - count + 1) * 4, count, tmpr);
1036 } else {
1037 if (is_write)
1038 emith_ctx_write(r, i * 4);
1039 else
1040 emith_ctx_read(r, i * 4);
1041 }
f0d7b1fa 1042 }
1043}
1044
e05b81fc 1045static void emit_block_entry(void)
f0d7b1fa 1046{
e05b81fc 1047 int arg0, arg1, arg2;
8796b7ee 1048
e05b81fc 1049 host_arg2reg(arg0, 0);
1050 host_arg2reg(arg1, 1);
1051 host_arg2reg(arg2, 2);
8796b7ee 1052
e05b81fc 1053#if (DRC_DEBUG & 4)
1054 emith_move_r_r(arg1, CONTEXT_REG);
1055 emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
1056 emith_call(sh2_drc_announce_entry);
1057 rcache_invalidate();
1058#endif
1059 emith_tst_r_r(arg0, arg0);
1060 EMITH_SJMP_START(DCOND_EQ);
1061 emith_jump_reg_c(DCOND_NE, arg0);
1062 EMITH_SJMP_END(DCOND_EQ);
1063}
8796b7ee 1064
44e6452e 1065void dr_link_blocks(void *target, u32 pc, int tcache_id)
1066{
23686515 1067#if LINK_BRANCHES
44e6452e 1068 block_link *bl = block_links[tcache_id];
1069 int cnt = block_link_counts[tcache_id];
1070 int i;
1071
1072 for (i = 0; i < cnt; i++) {
1073 if (bl[i].target_pc == pc) {
1074 dbg(1, "- link from %p", bl[i].jump);
1075 emith_jump_patch(bl[i].jump, target);
1076 // XXX: sync ARM caches (old jump should be fine)?
1077 }
1078 }
23686515 1079#endif
44e6452e 1080}
1081
1082void *dr_prepare_ext_branch(u32 pc, SH2 *sh2, int tcache_id)
1083{
23686515 1084#if LINK_BRANCHES
44e6452e 1085 int target_tcache_id;
1086 void *target;
1087 int ret;
1088
1089 target = lookup_block(pc, sh2->is_slave, &target_tcache_id);
1090 if (target_tcache_id == tcache_id) {
1091 // allow linking blocks only from local cache
1092 ret = dr_add_block_link(pc, tcache_ptr, tcache_id);
1093 if (ret < 0)
1094 return NULL;
1095 }
1096 if (target == NULL || target_tcache_id != tcache_id)
1097 target = sh2_drc_dispatcher;
1098
1099 return target;
23686515 1100#else
1101 return sh2_drc_dispatcher;
1102#endif
44e6452e 1103}
1104
e898de13 1105#define DELAYED_OP \
18b94127 1106 drcf.delayed_op = 2
1107
1108#define DELAY_SAVE_T(sr) { \
1109 emith_bic_r_imm(sr, T_save); \
1110 emith_tst_r_imm(sr, T); \
1111 EMITH_SJMP_START(DCOND_EQ); \
1112 emith_or_r_imm_c(DCOND_NE, sr, T_save); \
1113 EMITH_SJMP_END(DCOND_EQ); \
1114 drcf.use_saved_t = 1; \
1115}
e898de13 1116
e05b81fc 1117#define FLUSH_CYCLES(sr) \
1118 if (cycles > 0) { \
1119 emith_sub_r_imm(sr, cycles << 12); \
1120 cycles = 0; \
1121 }
1122
e898de13 1123#define CHECK_UNHANDLED_BITS(mask) { \
1124 if ((op & (mask)) != 0) \
1125 goto default_; \
1126}
1127
23686515 1128#define FETCH_OP(pc) \
1129 dr_pc_base[(pc) / 2]
1130
1131#define FETCH32(a) \
1132 ((dr_pc_base[(a) / 2] << 16) | dr_pc_base[(a) / 2 + 1])
1133
80599a42 1134#define GET_Fx() \
1135 ((op >> 4) & 0x0f)
1136
1137#define GET_Rm GET_Fx
1138
1139#define GET_Rn() \
1140 ((op >> 8) & 0x0f)
1141
ed8cf79b 1142#define CHECK_FX_LT(n) \
52d759c3 1143 if (GET_Fx() >= n) \
80599a42 1144 goto default_
1145
44e6452e 1146#define MAX_LOCAL_BRANCHES 32
18b94127 1147
1148// op_flags: data from 1st pass
1149#define OP_FLAGS(pc) op_flags[((pc) - base_pc) / 2]
1150#define OF_DELAY_OP (1 << 0)
1151
e05b81fc 1152static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
679af8a3 1153{
18b94127 1154 // XXX: maybe use structs instead?
1155 void *branch_target_ptr[MAX_LOCAL_BRANCHES];
1156 u32 branch_target_pc[MAX_LOCAL_BRANCHES];
1157 int branch_target_count = 0;
1158 void *branch_patch_ptr[MAX_LOCAL_BRANCHES];
1159 u32 branch_patch_pc[MAX_LOCAL_BRANCHES];
1160 int branch_patch_count = 0;
44e6452e 1161 int pending_branch_cond = -1;
1162 int pending_branch_pc = 0;
18b94127 1163 u8 op_flags[BLOCK_CYCLE_LIMIT + 1];
1164 struct {
1165 u32 delayed_op:2;
1166 u32 test_irq:1;
1167 u32 use_saved_t:1; // delayed op modifies T
1168 } drcf = { 0, };
1169
44e6452e 1170 // PC of current, first, last, last_target_blk SH2 insn
1171 u32 pc, base_pc, end_pc, out_pc;
23686515 1172 u32 last_inlined_literal = 0;
f4bb5d6b 1173 void *block_entry;
679af8a3 1174 block_desc *this_block;
23686515 1175 u16 *dr_pc_base;
18b94127 1176 int blkid_main = 0;
23686515 1177 int skip_op = 0;
18b94127 1178 u32 tmp, tmp2;
1179 int cycles;
1180 int op;
1181 int i;
1182
1183 base_pc = sh2->pc;
679af8a3 1184
23686515 1185 // get base/validate PC
1186 dr_pc_base = dr_get_pc_base(base_pc, sh2->is_slave);
1187 if (dr_pc_base == (void *)-1) {
18b94127 1188 printf("invalid PC, aborting: %08x\n", base_pc);
f4bb5d6b 1189 // FIXME: be less destructive
1190 exit(1);
1191 }
1192
f4bb5d6b 1193 tcache_ptr = tcache_ptrs[tcache_id];
18b94127 1194 this_block = dr_add_block(base_pc, tcache_id, &blkid_main);
44e6452e 1195 if (this_block == NULL)
1196 return NULL;
f4bb5d6b 1197
18b94127 1198 // predict tcache overflow
f4bb5d6b 1199 tmp = tcache_ptr - tcache_bases[tcache_id];
44e6452e 1200 if (tmp > tcache_sizes[tcache_id] - MAX_BLOCK_SIZE) {
1201 printf("tcache %d overflow\n", tcache_id);
18b94127 1202 return NULL;
44e6452e 1203 }
18b94127 1204
1205 block_entry = tcache_ptr;
1206 dbg(1, "== %csh2 block #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
1207 tcache_id, blkid_main, base_pc, block_entry);
1208
44e6452e 1209 dr_link_blocks(tcache_ptr, base_pc, tcache_id);
1210
18b94127 1211 // 1st pass: scan forward for local branches
1212 memset(op_flags, 0, sizeof(op_flags));
1213 for (cycles = 0, pc = base_pc; cycles < BLOCK_CYCLE_LIMIT; cycles++, pc += 2) {
23686515 1214 op = FETCH_OP(pc);
18b94127 1215 if ((op & 0xf000) == 0xa000 || (op & 0xf000) == 0xb000) { // BRA, BSR
44e6452e 1216 signed int offs = ((signed int)(op << 20) >> 19);
18b94127 1217 pc += 2;
1218 OP_FLAGS(pc) |= OF_DELAY_OP;
44e6452e 1219 ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 2,);
18b94127 1220 break;
1221 }
1222 if ((op & 0xf000) == 0) {
1223 op &= 0xff;
44e6452e 1224 if (op == 0x1b) // SLEEP
1225 break;
1226 if (op == 0x23 || op == 0x03 || op == 0x0b || op == 0x2b) { // BRAF, BSRF, RTS, RTE
18b94127 1227 pc += 2;
1228 OP_FLAGS(pc) |= OF_DELAY_OP;
1229 break;
1230 }
1231 continue;
1232 }
1233 if ((op & 0xf0df) == 0x400b) { // JMP, JSR
1234 pc += 2;
1235 OP_FLAGS(pc) |= OF_DELAY_OP;
1236 break;
1237 }
1238 if ((op & 0xf900) == 0x8900) { // BT(S), BF(S)
1239 signed int offs = ((signed int)(op << 24) >> 23);
1240 if (op & 0x0400)
1241 OP_FLAGS(pc + 2) |= OF_DELAY_OP;
44e6452e 1242 ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc + offs + 4, break);
18b94127 1243 }
44e6452e 1244 if ((op & 0xff00) == 0xc300) // TRAPA
1245 break;
f4bb5d6b 1246 }
e898de13 1247
18b94127 1248 end_pc = pc;
679af8a3 1249
18b94127 1250 // clean branch_targets that are not really local,
1251 // and that land on delay slots
1252 for (i = 0, tmp = 0; i < branch_target_count; i++) {
1253 pc = branch_target_pc[i];
1254 if (base_pc <= pc && pc <= end_pc && !(OP_FLAGS(pc) & OF_DELAY_OP))
1255 branch_target_pc[tmp++] = branch_target_pc[i];
e898de13 1256 }
18b94127 1257 branch_target_count = tmp;
1258 memset(branch_target_ptr, 0, sizeof(branch_target_ptr[0]) * branch_target_count);
23686515 1259#if !LINK_BRANCHES
1260 // for debug
1261 branch_target_count = 0;
1262#endif
679af8a3 1263
18b94127 1264 // -------------------------------------------------
1265 // 2nd pass: actual compilation
44e6452e 1266 out_pc = 0;
18b94127 1267 pc = base_pc;
1268 for (cycles = 0; pc <= end_pc || drcf.delayed_op; )
679af8a3 1269 {
18b94127 1270 u32 tmp3, tmp4, sr;
1271
1272 if (drcf.delayed_op > 0)
1273 drcf.delayed_op--;
1274
23686515 1275 op = FETCH_OP(pc);
1276
18b94127 1277 i = find_in_array(branch_target_pc, branch_target_count, pc);
1278 if (i >= 0)
1279 {
1280 if (pc != sh2->pc)
1281 {
1282 /* make "subblock" - just a mid-block entry */
1283 block_desc *subblock;
1284 u16 *drcblk;
1285 int blkid;
1286
1287 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 1288 FLUSH_CYCLES(sr);
23686515 1289 // decide if to flush rcache
1290 if ((op & 0xf0ff) == 0x4010 && FETCH_OP(pc + 2) == 0x8bfd) // DT; BF #-2
1291 rcache_clean();
1292 else
1293 rcache_flush();
18b94127 1294 do_host_disasm(tcache_id);
1295
1296 subblock = dr_add_block(pc, tcache_id, &blkid);
1297 if (subblock == NULL)
1298 return NULL;
1299 subblock->end_addr = pc;
1300
1301 if (tcache_id != 0) { // data array, BIOS
1302 drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
1303 drcblk += (pc & 0x00fff) >> SH2_DRCBLK_DA_SHIFT;
1304 *drcblk = (blkid << 1) | 1;
1305 } else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
1306 drcblk = Pico32xMem->drcblk_ram;
1307 drcblk += (pc & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
1308 *drcblk = (blkid << 1) | 1;
1309 }
1310
44e6452e 1311 dbg(1, "-- %csh2 subblock #%d,%d %08x -> %p", sh2->is_slave ? 's' : 'm',
18b94127 1312 tcache_id, blkid, pc, tcache_ptr);
44e6452e 1313
1314 // since we made a block entry, link any other blocks that jump to current pc
1315 dr_link_blocks(tcache_ptr, pc, tcache_id);
18b94127 1316 }
1317 branch_target_ptr[i] = tcache_ptr;
1318
1319 // must update PC
1320 emit_move_r_imm32(SHR_PC, pc);
1321 rcache_clean();
1322
1323 // check cycles
1324 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
1325 emith_cmp_r_imm(sr, 0);
1326 emith_jump_cond(DCOND_LE, sh2_drc_exit);
23686515 1327 do_host_disasm(tcache_id);
18b94127 1328 }
e898de13 1329
e898de13 1330#if (DRC_DEBUG & 3)
1331 insns_compiled++;
1332#if (DRC_DEBUG & 2)
1333 DasmSH2(sh2dasm_buff, pc, op);
1334 printf("%08x %04x %s\n", pc, op, sh2dasm_buff);
1335#endif
679af8a3 1336#endif
679af8a3 1337
1338 pc += 2;
1339 cycles++;
1340
23686515 1341 if (skip_op > 0) {
1342 skip_op--;
1343 continue;
1344 }
1345
679af8a3 1346 switch ((op >> 12) & 0x0f)
1347 {
3863edbd 1348 /////////////////////////////////////////////
679af8a3 1349 case 0x00:
80599a42 1350 switch (op & 0x0f)
1351 {
1352 case 0x02:
1353 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1354 switch (GET_Fx())
1355 {
1356 case 0: // STC SR,Rn 0000nnnn00000010
1357 tmp2 = SHR_SR;
1358 break;
1359 case 1: // STC GBR,Rn 0000nnnn00010010
1360 tmp2 = SHR_GBR;
1361 break;
1362 case 2: // STC VBR,Rn 0000nnnn00100010
1363 tmp2 = SHR_VBR;
1364 break;
1365 default:
1366 goto default_;
1367 }
ed8cf79b 1368 tmp3 = rcache_get_reg(tmp2, RC_GR_READ);
1369 emith_move_r_r(tmp, tmp3);
1370 if (tmp2 == SHR_SR)
18b94127 1371 emith_clear_msb(tmp, tmp, 22); // reserved bits defined by ISA as 0
80599a42 1372 goto end_op;
e898de13 1373 case 0x03:
1374 CHECK_UNHANDLED_BITS(0xd0);
1375 // BRAF Rm 0000mmmm00100011
1376 // BSRF Rm 0000mmmm00000011
679af8a3 1377 DELAYED_OP;
18b94127 1378 tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE);
80599a42 1379 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
c18edb34 1380 emith_move_r_r(tmp, tmp2);
18b94127 1381 if (op & 0x20)
1382 emith_add_r_imm(tmp, pc + 2);
1383 else { // BSRF
1384 tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE);
1385 emith_move_r_imm(tmp3, pc + 2);
1386 emith_add_r_r(tmp, tmp3);
1387 }
44e6452e 1388 out_pc = (u32)-1;
679af8a3 1389 cycles++;
e898de13 1390 goto end_op;
80599a42 1391 case 0x04: // MOV.B Rm,@(R0,Rn) 0000nnnnmmmm0100
1392 case 0x05: // MOV.W Rm,@(R0,Rn) 0000nnnnmmmm0101
1393 case 0x06: // MOV.L Rm,@(R0,Rn) 0000nnnnmmmm0110
e05b81fc 1394 rcache_clean();
1395 tmp = rcache_get_reg_arg(1, GET_Rm());
1396 tmp2 = rcache_get_reg_arg(0, SHR_R0);
1397 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1398 emith_add_r_r(tmp2, tmp3);
1399 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1400 goto end_op;
1401 case 0x07:
1402 // MUL.L Rm,Rn 0000nnnnmmmm0111
1403 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1404 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1405 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1406 emith_mul(tmp3, tmp2, tmp);
1407 cycles++;
1408 goto end_op;
1409 case 0x08:
1410 CHECK_UNHANDLED_BITS(0xf00);
1411 switch (GET_Fx())
1412 {
1413 case 0: // CLRT 0000000000001000
8796b7ee 1414 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1415 if (drcf.delayed_op)
1416 DELAY_SAVE_T(sr);
8796b7ee 1417 emith_bic_r_imm(sr, T);
80599a42 1418 break;
1419 case 1: // SETT 0000000000011000
8796b7ee 1420 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1421 if (drcf.delayed_op)
1422 DELAY_SAVE_T(sr);
8796b7ee 1423 emith_or_r_imm(sr, T);
80599a42 1424 break;
1425 case 2: // CLRMAC 0000000000101000
23686515 1426 emit_move_r_imm32(SHR_MACL, 0);
1427 emit_move_r_imm32(SHR_MACH, 0);
80599a42 1428 break;
1429 default:
1430 goto default_;
1431 }
1432 goto end_op;
e898de13 1433 case 0x09:
80599a42 1434 switch (GET_Fx())
1435 {
1436 case 0: // NOP 0000000000001001
1437 CHECK_UNHANDLED_BITS(0xf00);
1438 break;
1439 case 1: // DIV0U 0000000000011001
1440 CHECK_UNHANDLED_BITS(0xf00);
8796b7ee 1441 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1442 if (drcf.delayed_op)
1443 DELAY_SAVE_T(sr);
8796b7ee 1444 emith_bic_r_imm(sr, M|Q|T);
80599a42 1445 break;
1446 case 2: // MOVT Rn 0000nnnn00101001
8796b7ee 1447 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
80599a42 1448 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
8796b7ee 1449 emith_clear_msb(tmp2, sr, 31);
80599a42 1450 break;
1451 default:
1452 goto default_;
1453 }
1454 goto end_op;
1455 case 0x0a:
1456 tmp = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
1457 switch (GET_Fx())
1458 {
1459 case 0: // STS MACH,Rn 0000nnnn00001010
ed8cf79b 1460 tmp2 = SHR_MACH;
80599a42 1461 break;
1462 case 1: // STS MACL,Rn 0000nnnn00011010
ed8cf79b 1463 tmp2 = SHR_MACL;
80599a42 1464 break;
1465 case 2: // STS PR,Rn 0000nnnn00101010
ed8cf79b 1466 tmp2 = SHR_PR;
80599a42 1467 break;
1468 default:
1469 goto default_;
1470 }
ed8cf79b 1471 tmp2 = rcache_get_reg(tmp2, RC_GR_READ);
80599a42 1472 emith_move_r_r(tmp, tmp2);
e898de13 1473 goto end_op;
1474 case 0x0b:
80599a42 1475 CHECK_UNHANDLED_BITS(0xf00);
1476 switch (GET_Fx())
1477 {
1478 case 0: // RTS 0000000000001011
1479 DELAYED_OP;
18b94127 1480 emit_move_r_r(SHR_PC, SHR_PR);
44e6452e 1481 out_pc = (u32)-1;
e898de13 1482 cycles++;
80599a42 1483 break;
1484 case 1: // SLEEP 0000000000011011
80599a42 1485 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
1486 emith_clear_msb(tmp, tmp, 20); // clear cycles
44e6452e 1487 out_pc = out_pc - 2;
80599a42 1488 cycles = 1;
e05b81fc 1489 goto end_op;
80599a42 1490 case 2: // RTE 0000000000101011
52d759c3 1491 DELAYED_OP;
52d759c3 1492 // pop PC
23686515 1493 emit_memhandler_read_rr(SHR_PC, SHR_SP, 0, 2);
52d759c3 1494 // pop SR
1495 tmp = rcache_get_reg_arg(0, SHR_SP);
1496 emith_add_r_imm(tmp, 4);
1497 tmp = emit_memhandler_read(2);
18b94127 1498 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1499 emith_write_sr(sr, tmp);
52d759c3 1500 rcache_free_tmp(tmp);
1501 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
1502 emith_add_r_imm(tmp, 4*2);
18b94127 1503 drcf.test_irq = 1;
44e6452e 1504 out_pc = (u32)-1;
e898de13 1505 cycles += 3;
80599a42 1506 break;
1507 default:
1508 goto default_;
e898de13 1509 }
1510 goto end_op;
80599a42 1511 case 0x0c: // MOV.B @(R0,Rm),Rn 0000nnnnmmmm1100
1512 case 0x0d: // MOV.W @(R0,Rm),Rn 0000nnnnmmmm1101
1513 case 0x0e: // MOV.L @(R0,Rm),Rn 0000nnnnmmmm1110
52d759c3 1514 tmp = emit_indirect_indexed_read(SHR_R0, GET_Rm(), op & 3);
80599a42 1515 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
80599a42 1516 if ((op & 3) != 2) {
1517 emith_sext(tmp2, tmp, (op & 1) ? 16 : 8);
1518 } else
1519 emith_move_r_r(tmp2, tmp);
52d759c3 1520 rcache_free_tmp(tmp);
80599a42 1521 goto end_op;
1522 case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
f0d7b1fa 1523 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
f0d7b1fa 1524 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
1525 /* MS 16 MAC bits unused if saturated */
23686515 1526 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
8796b7ee 1527 emith_tst_r_imm(sr, S);
f0d7b1fa 1528 EMITH_SJMP_START(DCOND_EQ);
1529 emith_clear_msb_c(DCOND_NE, tmp4, tmp4, 16);
1530 EMITH_SJMP_END(DCOND_EQ);
23686515 1531 rcache_unlock(sr);
f0d7b1fa 1532 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW); // might evict SR
1533 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 1534 rcache_free_tmp(tmp2);
8796b7ee 1535 sr = rcache_get_reg(SHR_SR, RC_GR_READ); // reget just in case
1536 emith_tst_r_imm(sr, S);
1537
1538 EMITH_JMP_START(DCOND_EQ);
1539 emith_asr(tmp, tmp4, 15);
1540 emith_cmp_r_imm(tmp, -1); // negative overflow (0x80000000..0xffff7fff)
1541 EMITH_SJMP_START(DCOND_GE);
1542 emith_move_r_imm_c(DCOND_LT, tmp4, 0x8000);
1543 emith_move_r_imm_c(DCOND_LT, tmp3, 0x0000);
1544 EMITH_SJMP_END(DCOND_GE);
1545 emith_cmp_r_imm(tmp, 0); // positive overflow (0x00008000..0x7fffffff)
1546 EMITH_SJMP_START(DCOND_LE);
1547 emith_move_r_imm_c(DCOND_GT, tmp4, 0x00007fff);
1548 emith_move_r_imm_c(DCOND_GT, tmp3, 0xffffffff);
1549 EMITH_SJMP_END(DCOND_LE);
1550 EMITH_JMP_END(DCOND_EQ);
1551
1552 rcache_free_tmp(tmp);
f0d7b1fa 1553 cycles += 3;
1554 goto end_op;
80599a42 1555 }
1556 goto default_;
1557
3863edbd 1558 /////////////////////////////////////////////
80599a42 1559 case 0x01:
1560 // MOV.L Rm,@(disp,Rn) 0001nnnnmmmmdddd
1561 rcache_clean();
1562 tmp = rcache_get_reg_arg(0, GET_Rn());
1563 tmp2 = rcache_get_reg_arg(1, GET_Rm());
23686515 1564 if (op & 0x0f)
1565 emith_add_r_imm(tmp, (op & 0x0f) * 4);
e05b81fc 1566 emit_memhandler_write(2, pc, drcf.delayed_op);
80599a42 1567 goto end_op;
1568
1569 case 0x02:
1570 switch (op & 0x0f)
1571 {
1572 case 0x00: // MOV.B Rm,@Rn 0010nnnnmmmm0000
1573 case 0x01: // MOV.W Rm,@Rn 0010nnnnmmmm0001
1574 case 0x02: // MOV.L Rm,@Rn 0010nnnnmmmm0010
1575 rcache_clean();
1576 rcache_get_reg_arg(0, GET_Rn());
1577 rcache_get_reg_arg(1, GET_Rm());
e05b81fc 1578 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1579 goto end_op;
1580 case 0x04: // MOV.B Rm,@–Rn 0010nnnnmmmm0100
1581 case 0x05: // MOV.W Rm,@–Rn 0010nnnnmmmm0101
1582 case 0x06: // MOV.L Rm,@–Rn 0010nnnnmmmm0110
1583 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1584 emith_sub_r_imm(tmp, (1 << (op & 3)));
1585 rcache_clean();
1586 rcache_get_reg_arg(0, GET_Rn());
1587 rcache_get_reg_arg(1, GET_Rm());
e05b81fc 1588 emit_memhandler_write(op & 3, pc, drcf.delayed_op);
80599a42 1589 goto end_op;
1590 case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
8796b7ee 1591 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
80599a42 1592 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1593 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1594 if (drcf.delayed_op)
1595 DELAY_SAVE_T(sr);
8796b7ee 1596 emith_bic_r_imm(sr, M|Q|T);
80599a42 1597 emith_tst_r_imm(tmp2, (1<<31));
1598 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1599 emith_or_r_imm_c(DCOND_NE, sr, Q);
80599a42 1600 EMITH_SJMP_END(DCOND_EQ);
1601 emith_tst_r_imm(tmp3, (1<<31));
1602 EMITH_SJMP_START(DCOND_EQ);
8796b7ee 1603 emith_or_r_imm_c(DCOND_NE, sr, M);
80599a42 1604 EMITH_SJMP_END(DCOND_EQ);
1605 emith_teq_r_r(tmp2, tmp3);
1606 EMITH_SJMP_START(DCOND_PL);
8796b7ee 1607 emith_or_r_imm_c(DCOND_MI, sr, T);
80599a42 1608 EMITH_SJMP_END(DCOND_PL);
1609 goto end_op;
3863edbd 1610 case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
8796b7ee 1611 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1612 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1613 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1614 if (drcf.delayed_op)
1615 DELAY_SAVE_T(sr);
8796b7ee 1616 emith_bic_r_imm(sr, T);
3863edbd 1617 emith_tst_r_r(tmp2, tmp3);
8796b7ee 1618 emit_or_t_if_eq(sr);
3863edbd 1619 goto end_op;
1620 case 0x09: // AND Rm,Rn 0010nnnnmmmm1001
1621 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1622 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1623 emith_and_r_r(tmp, tmp2);
1624 goto end_op;
1625 case 0x0a: // XOR Rm,Rn 0010nnnnmmmm1010
1626 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1627 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1628 emith_eor_r_r(tmp, tmp2);
1629 goto end_op;
1630 case 0x0b: // OR Rm,Rn 0010nnnnmmmm1011
1631 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1632 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1633 emith_or_r_r(tmp, tmp2);
1634 goto end_op;
1635 case 0x0c: // CMP/STR Rm,Rn 0010nnnnmmmm1100
1636 tmp = rcache_get_tmp();
1637 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1638 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1639 emith_eor_r_r_r(tmp, tmp2, tmp3);
8796b7ee 1640 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1641 if (drcf.delayed_op)
1642 DELAY_SAVE_T(sr);
8796b7ee 1643 emith_bic_r_imm(sr, T);
3863edbd 1644 emith_tst_r_imm(tmp, 0x000000ff);
52d759c3 1645 emit_or_t_if_eq(tmp);
3863edbd 1646 emith_tst_r_imm(tmp, 0x0000ff00);
52d759c3 1647 emit_or_t_if_eq(tmp);
3863edbd 1648 emith_tst_r_imm(tmp, 0x00ff0000);
52d759c3 1649 emit_or_t_if_eq(tmp);
3863edbd 1650 emith_tst_r_imm(tmp, 0xff000000);
52d759c3 1651 emit_or_t_if_eq(tmp);
3863edbd 1652 rcache_free_tmp(tmp);
1653 goto end_op;
1654 case 0x0d: // XTRCT Rm,Rn 0010nnnnmmmm1101
1655 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1656 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1657 emith_lsr(tmp, tmp, 16);
f0d7b1fa 1658 emith_or_r_r_lsl(tmp, tmp2, 16);
3863edbd 1659 goto end_op;
1660 case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
1661 case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
1662 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1663 tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1664 if (op & 1) {
1665 emith_sext(tmp, tmp2, 16);
1666 } else
1667 emith_clear_msb(tmp, tmp2, 16);
1668 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1669 tmp2 = rcache_get_tmp();
1670 if (op & 1) {
1671 emith_sext(tmp2, tmp3, 16);
1672 } else
1673 emith_clear_msb(tmp2, tmp3, 16);
1674 emith_mul(tmp, tmp, tmp2);
1675 rcache_free_tmp(tmp2);
1676// FIXME: causes timing issues in Doom?
1677// cycles++;
1678 goto end_op;
679af8a3 1679 }
1680 goto default_;
1681
3863edbd 1682 /////////////////////////////////////////////
1683 case 0x03:
1684 switch (op & 0x0f)
1685 {
1686 case 0x00: // CMP/EQ Rm,Rn 0011nnnnmmmm0000
1687 case 0x02: // CMP/HS Rm,Rn 0011nnnnmmmm0010
1688 case 0x03: // CMP/GE Rm,Rn 0011nnnnmmmm0011
1689 case 0x06: // CMP/HI Rm,Rn 0011nnnnmmmm0110
1690 case 0x07: // CMP/GT Rm,Rn 0011nnnnmmmm0111
8796b7ee 1691 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
3863edbd 1692 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
1693 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
18b94127 1694 if (drcf.delayed_op)
1695 DELAY_SAVE_T(sr);
8796b7ee 1696 emith_bic_r_imm(sr, T);
3863edbd 1697 emith_cmp_r_r(tmp2, tmp3);
1698 switch (op & 0x07)
1699 {
1700 case 0x00: // CMP/EQ
8796b7ee 1701 emit_or_t_if_eq(sr);
3863edbd 1702 break;
1703 case 0x02: // CMP/HS
1704 EMITH_SJMP_START(DCOND_LO);
8796b7ee 1705 emith_or_r_imm_c(DCOND_HS, sr, T);
3863edbd 1706 EMITH_SJMP_END(DCOND_LO);
1707 break;
1708 case 0x03: // CMP/GE
1709 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1710 emith_or_r_imm_c(DCOND_GE, sr, T);
3863edbd 1711 EMITH_SJMP_END(DCOND_LT);
1712 break;
1713 case 0x06: // CMP/HI
1714 EMITH_SJMP_START(DCOND_LS);
8796b7ee 1715 emith_or_r_imm_c(DCOND_HI, sr, T);
3863edbd 1716 EMITH_SJMP_END(DCOND_LS);
1717 break;
1718 case 0x07: // CMP/GT
1719 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1720 emith_or_r_imm_c(DCOND_GT, sr, T);
3863edbd 1721 EMITH_SJMP_END(DCOND_LE);
1722 break;
1723 }
1724 goto end_op;
1725 case 0x04: // DIV1 Rm,Rn 0011nnnnmmmm0100
f0d7b1fa 1726 // Q1 = carry(Rn = (Rn << 1) | T)
1727 // if Q ^ M
1728 // Q2 = carry(Rn += Rm)
1729 // else
1730 // Q2 = carry(Rn -= Rm)
1731 // Q = M ^ Q1 ^ Q2
1732 // T = (Q == M) = !(Q ^ M) = !(Q1 ^ Q2)
1733 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1734 tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1735 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1736 if (drcf.delayed_op)
1737 DELAY_SAVE_T(sr);
8b4f38f4 1738 emith_tpop_carry(sr, 0);
f0d7b1fa 1739 emith_adcf_r_r(tmp2, tmp2);
8b4f38f4 1740 emith_tpush_carry(sr, 0); // keep Q1 in T for now
f0d7b1fa 1741 tmp4 = rcache_get_tmp();
1742 emith_and_r_r_imm(tmp4, sr, M);
1743 emith_eor_r_r_lsr(sr, tmp4, M_SHIFT - Q_SHIFT); // Q ^= M
1744 rcache_free_tmp(tmp4);
1745 // add or sub, invert T if carry to get Q1 ^ Q2
1746 // in: (Q ^ M) passed in Q, Q1 in T
1747 emith_sh2_div1_step(tmp2, tmp3, sr);
18b94127 1748 emith_bic_r_imm(sr, Q);
1749 emith_tst_r_imm(sr, M);
1750 EMITH_SJMP_START(DCOND_EQ);
1751 emith_or_r_imm_c(DCOND_NE, sr, Q); // Q = M
1752 EMITH_SJMP_END(DCOND_EQ);
1753 emith_tst_r_imm(sr, T);
1754 EMITH_SJMP_START(DCOND_EQ);
1755 emith_eor_r_imm_c(DCOND_NE, sr, Q); // Q = M ^ Q1 ^ Q2
1756 EMITH_SJMP_END(DCOND_EQ);
1757 emith_eor_r_imm(sr, T); // T = !(Q1 ^ Q2)
f0d7b1fa 1758 goto end_op;
3863edbd 1759 case 0x05: // DMULU.L Rm,Rn 0011nnnnmmmm0101
1760 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1761 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1762 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1763 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1764 emith_mul_u64(tmp3, tmp4, tmp, tmp2);
1765 goto end_op;
1766 case 0x08: // SUB Rm,Rn 0011nnnnmmmm1000
1767 case 0x0c: // ADD Rm,Rn 0011nnnnmmmm1100
1768 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1769 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1770 if (op & 4) {
1771 emith_add_r_r(tmp, tmp2);
1772 } else
1773 emith_sub_r_r(tmp, tmp2);
1774 goto end_op;
1775 case 0x0a: // SUBC Rm,Rn 0011nnnnmmmm1010
1776 case 0x0e: // ADDC Rm,Rn 0011nnnnmmmm1110
1777 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1778 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1779 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1780 if (drcf.delayed_op)
1781 DELAY_SAVE_T(sr);
3863edbd 1782 if (op & 4) { // adc
8b4f38f4 1783 emith_tpop_carry(sr, 0);
3863edbd 1784 emith_adcf_r_r(tmp, tmp2);
8b4f38f4 1785 emith_tpush_carry(sr, 0);
3863edbd 1786 } else {
8b4f38f4 1787 emith_tpop_carry(sr, 1);
3863edbd 1788 emith_sbcf_r_r(tmp, tmp2);
8b4f38f4 1789 emith_tpush_carry(sr, 1);
3863edbd 1790 }
3863edbd 1791 goto end_op;
1792 case 0x0b: // SUBV Rm,Rn 0011nnnnmmmm1011
1793 case 0x0f: // ADDV Rm,Rn 0011nnnnmmmm1111
1794 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1795 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
8796b7ee 1796 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1797 if (drcf.delayed_op)
1798 DELAY_SAVE_T(sr);
8796b7ee 1799 emith_bic_r_imm(sr, T);
3863edbd 1800 if (op & 4) {
1801 emith_addf_r_r(tmp, tmp2);
1802 } else
1803 emith_subf_r_r(tmp, tmp2);
1804 EMITH_SJMP_START(DCOND_VC);
8796b7ee 1805 emith_or_r_imm_c(DCOND_VS, sr, T);
3863edbd 1806 EMITH_SJMP_END(DCOND_VC);
1807 goto end_op;
1808 case 0x0d: // DMULS.L Rm,Rn 0011nnnnmmmm1101
1809 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
1810 tmp2 = rcache_get_reg(GET_Rm(), RC_GR_READ);
1811 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
1812 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_WRITE);
1813 emith_mul_s64(tmp3, tmp4, tmp, tmp2);
1814 goto end_op;
1815 }
1816 goto default_;
1817
1818 /////////////////////////////////////////////
679af8a3 1819 case 0x04:
3863edbd 1820 switch (op & 0x0f)
1821 {
c18edb34 1822 case 0x00:
3863edbd 1823 switch (GET_Fx())
1824 {
1825 case 0: // SHLL Rn 0100nnnn00000000
1826 case 2: // SHAL Rn 0100nnnn00100000
8796b7ee 1827 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1828 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1829 if (drcf.delayed_op)
1830 DELAY_SAVE_T(sr);
8b4f38f4 1831 emith_tpop_carry(sr, 0); // dummy
3863edbd 1832 emith_lslf(tmp, tmp, 1);
8b4f38f4 1833 emith_tpush_carry(sr, 0);
3863edbd 1834 goto end_op;
1835 case 1: // DT Rn 0100nnnn00010000
8796b7ee 1836 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1837 if (drcf.delayed_op)
1838 DELAY_SAVE_T(sr);
23686515 1839 if (FETCH_OP(pc) == 0x8bfd) { // BF #-2
1840 if (gconst_get(GET_Rn(), &tmp)) {
1841 // XXX: limit burned cycles
1842 emit_move_r_imm32(GET_Rn(), 0);
1843 emith_or_r_imm(sr, T);
1844 cycles += tmp * 4;
1845 skip_op = 1;
1846 }
1847 else
1848 emith_sh2_dtbf_loop();
1849 goto end_op;
1850 }
1851 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
8796b7ee 1852 emith_bic_r_imm(sr, T);
3863edbd 1853 emith_subf_r_imm(tmp, 1);
8796b7ee 1854 emit_or_t_if_eq(sr);
80599a42 1855 goto end_op;
1856 }
3863edbd 1857 goto default_;
ed8cf79b 1858 case 0x01:
1859 switch (GET_Fx())
1860 {
1861 case 0: // SHLR Rn 0100nnnn00000001
1862 case 2: // SHAR Rn 0100nnnn00100001
8796b7ee 1863 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1864 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1865 if (drcf.delayed_op)
1866 DELAY_SAVE_T(sr);
8b4f38f4 1867 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1868 if (op & 0x20) {
1869 emith_asrf(tmp, tmp, 1);
1870 } else
1871 emith_lsrf(tmp, tmp, 1);
8b4f38f4 1872 emith_tpush_carry(sr, 0);
ed8cf79b 1873 goto end_op;
1874 case 1: // CMP/PZ Rn 0100nnnn00010001
8796b7ee 1875 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1876 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1877 if (drcf.delayed_op)
1878 DELAY_SAVE_T(sr);
8796b7ee 1879 emith_bic_r_imm(sr, T);
ed8cf79b 1880 emith_cmp_r_imm(tmp, 0);
1881 EMITH_SJMP_START(DCOND_LT);
8796b7ee 1882 emith_or_r_imm_c(DCOND_GE, sr, T);
ed8cf79b 1883 EMITH_SJMP_END(DCOND_LT);
1884 goto end_op;
1885 }
1886 goto default_;
1887 case 0x02:
1888 case 0x03:
1889 switch (op & 0x3f)
1890 {
1891 case 0x02: // STS.L MACH,@–Rn 0100nnnn00000010
1892 tmp = SHR_MACH;
1893 break;
1894 case 0x12: // STS.L MACL,@–Rn 0100nnnn00010010
1895 tmp = SHR_MACL;
1896 break;
1897 case 0x22: // STS.L PR,@–Rn 0100nnnn00100010
1898 tmp = SHR_PR;
1899 break;
1900 case 0x03: // STC.L SR,@–Rn 0100nnnn00000011
1901 tmp = SHR_SR;
1902 break;
1903 case 0x13: // STC.L GBR,@–Rn 0100nnnn00010011
1904 tmp = SHR_GBR;
1905 break;
1906 case 0x23: // STC.L VBR,@–Rn 0100nnnn00100011
1907 tmp = SHR_VBR;
1908 break;
1909 default:
e898de13 1910 goto default_;
ed8cf79b 1911 }
1912 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1913 emith_sub_r_imm(tmp2, 4);
1914 rcache_clean();
1915 rcache_get_reg_arg(0, GET_Rn());
1916 tmp3 = rcache_get_reg_arg(1, tmp);
1917 if (tmp == SHR_SR)
e05b81fc 1918 emith_clear_msb(tmp3, tmp3, 22); // reserved bits defined by ISA as 0
1919 emit_memhandler_write(2, pc, drcf.delayed_op);
ed8cf79b 1920 goto end_op;
1921 case 0x04:
1922 case 0x05:
1923 switch (op & 0x3f)
1924 {
1925 case 0x04: // ROTL Rn 0100nnnn00000100
1926 case 0x05: // ROTR Rn 0100nnnn00000101
8796b7ee 1927 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1928 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1929 if (drcf.delayed_op)
1930 DELAY_SAVE_T(sr);
8b4f38f4 1931 emith_tpop_carry(sr, 0); // dummy
ed8cf79b 1932 if (op & 1) {
1933 emith_rorf(tmp, tmp, 1);
1934 } else
1935 emith_rolf(tmp, tmp, 1);
8b4f38f4 1936 emith_tpush_carry(sr, 0);
ed8cf79b 1937 goto end_op;
1938 case 0x24: // ROTCL Rn 0100nnnn00100100
1939 case 0x25: // ROTCR Rn 0100nnnn00100101
8796b7ee 1940 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1941 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1942 if (drcf.delayed_op)
1943 DELAY_SAVE_T(sr);
8b4f38f4 1944 emith_tpop_carry(sr, 0);
ed8cf79b 1945 if (op & 1) {
1946 emith_rorcf(tmp);
1947 } else
1948 emith_rolcf(tmp);
8b4f38f4 1949 emith_tpush_carry(sr, 0);
ed8cf79b 1950 goto end_op;
1951 case 0x15: // CMP/PL Rn 0100nnnn00010101
8796b7ee 1952 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
1953 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 1954 if (drcf.delayed_op)
1955 DELAY_SAVE_T(sr);
8796b7ee 1956 emith_bic_r_imm(sr, T);
ed8cf79b 1957 emith_cmp_r_imm(tmp, 0);
1958 EMITH_SJMP_START(DCOND_LE);
8796b7ee 1959 emith_or_r_imm_c(DCOND_GT, sr, T);
ed8cf79b 1960 EMITH_SJMP_END(DCOND_LE);
1961 goto end_op;
1962 }
e898de13 1963 goto default_;
ed8cf79b 1964 case 0x06:
1965 case 0x07:
1966 switch (op & 0x3f)
1967 {
1968 case 0x06: // LDS.L @Rm+,MACH 0100mmmm00000110
1969 tmp = SHR_MACH;
1970 break;
1971 case 0x16: // LDS.L @Rm+,MACL 0100mmmm00010110
1972 tmp = SHR_MACL;
1973 break;
1974 case 0x26: // LDS.L @Rm+,PR 0100mmmm00100110
1975 tmp = SHR_PR;
1976 break;
1977 case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111
1978 tmp = SHR_SR;
1979 break;
1980 case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111
1981 tmp = SHR_GBR;
1982 break;
1983 case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111
1984 tmp = SHR_VBR;
1985 break;
1986 default:
1987 goto default_;
1988 }
ed8cf79b 1989 rcache_get_reg_arg(0, GET_Rn());
1990 tmp2 = emit_memhandler_read(2);
1991 if (tmp == SHR_SR) {
18b94127 1992 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
1993 if (drcf.delayed_op)
1994 DELAY_SAVE_T(sr);
1995 emith_write_sr(sr, tmp2);
1996 drcf.test_irq = 1;
ed8cf79b 1997 } else {
1998 tmp = rcache_get_reg(tmp, RC_GR_WRITE);
1999 emith_move_r_r(tmp, tmp2);
2000 }
2001 rcache_free_tmp(tmp2);
2002 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2003 emith_add_r_imm(tmp, 4);
2004 goto end_op;
52d759c3 2005 case 0x08:
2006 case 0x09:
2007 switch (GET_Fx())
2008 {
2009 case 0:
2010 // SHLL2 Rn 0100nnnn00001000
2011 // SHLR2 Rn 0100nnnn00001001
2012 tmp = 2;
2013 break;
2014 case 1:
2015 // SHLL8 Rn 0100nnnn00011000
2016 // SHLR8 Rn 0100nnnn00011001
2017 tmp = 8;
2018 break;
2019 case 2:
2020 // SHLL16 Rn 0100nnnn00101000
2021 // SHLR16 Rn 0100nnnn00101001
2022 tmp = 16;
2023 break;
2024 default:
2025 goto default_;
2026 }
2027 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2028 if (op & 1) {
2029 emith_lsr(tmp2, tmp2, tmp);
2030 } else
2031 emith_lsl(tmp2, tmp2, tmp);
2032 goto end_op;
2033 case 0x0a:
2034 switch (GET_Fx())
2035 {
2036 case 0: // LDS Rm,MACH 0100mmmm00001010
2037 tmp2 = SHR_MACH;
2038 break;
2039 case 1: // LDS Rm,MACL 0100mmmm00011010
2040 tmp2 = SHR_MACL;
2041 break;
2042 case 2: // LDS Rm,PR 0100mmmm00101010
2043 tmp2 = SHR_PR;
2044 break;
2045 default:
2046 goto default_;
2047 }
2048 emit_move_r_r(tmp2, GET_Rn());
2049 goto end_op;
e898de13 2050 case 0x0b:
52d759c3 2051 switch (GET_Fx())
2052 {
2053 case 0: // JSR @Rm 0100mmmm00001011
2054 case 2: // JMP @Rm 0100mmmm00101011
2055 DELAYED_OP;
2056 if (!(op & 0x20))
2057 emit_move_r_imm32(SHR_PR, pc + 2);
18b94127 2058 emit_move_r_r(SHR_PC, (op >> 8) & 0x0f);
44e6452e 2059 out_pc = (u32)-1;
52d759c3 2060 cycles++;
2061 break;
2062 case 1: // TAS.B @Rn 0100nnnn00011011
2063 // XXX: is TAS working on 32X?
52d759c3 2064 rcache_get_reg_arg(0, GET_Rn());
8796b7ee 2065 tmp = emit_memhandler_read(0);
2066 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2067 if (drcf.delayed_op)
2068 DELAY_SAVE_T(sr);
8796b7ee 2069 emith_bic_r_imm(sr, T);
52d759c3 2070 emith_cmp_r_imm(tmp, 0);
8796b7ee 2071 emit_or_t_if_eq(sr);
52d759c3 2072 rcache_clean();
2073 emith_or_r_imm(tmp, 0x80);
2074 tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
2075 emith_move_r_r(tmp2, tmp);
2076 rcache_free_tmp(tmp);
2077 rcache_get_reg_arg(0, GET_Rn());
e05b81fc 2078 emit_memhandler_write(0, pc, drcf.delayed_op);
52d759c3 2079 cycles += 3;
2080 break;
2081 default:
e898de13 2082 goto default_;
52d759c3 2083 }
e898de13 2084 goto end_op;
2085 case 0x0e:
52d759c3 2086 tmp = rcache_get_reg(GET_Rn(), RC_GR_READ);
2087 switch (GET_Fx())
2088 {
2089 case 0: // LDC Rm,SR 0100mmmm00001110
2090 tmp2 = SHR_SR;
2091 break;
2092 case 1: // LDC Rm,GBR 0100mmmm00011110
2093 tmp2 = SHR_GBR;
2094 break;
2095 case 2: // LDC Rm,VBR 0100mmmm00101110
2096 tmp2 = SHR_VBR;
2097 break;
2098 default:
e898de13 2099 goto default_;
52d759c3 2100 }
2101 if (tmp2 == SHR_SR) {
18b94127 2102 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2103 if (drcf.delayed_op)
2104 DELAY_SAVE_T(sr);
2105 emith_write_sr(sr, tmp);
2106 drcf.test_irq = 1;
52d759c3 2107 } else {
2108 tmp2 = rcache_get_reg(tmp2, RC_GR_WRITE);
2109 emith_move_r_r(tmp2, tmp);
2110 }
2111 goto end_op;
2112 case 0x0f:
23686515 2113 // MAC.W @Rm+,@Rn+ 0100nnnnmmmm1111
f0d7b1fa 2114 emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 1);
2115 emith_sext(tmp, tmp, 16);
2116 emith_sext(tmp2, tmp2, 16);
2117 tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
2118 tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
2119 emith_mula_s64(tmp3, tmp4, tmp, tmp2);
f0d7b1fa 2120 rcache_free_tmp(tmp2);
f0d7b1fa 2121 // XXX: MACH should be untouched when S is set?
8796b7ee 2122 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2123 emith_tst_r_imm(sr, S);
2124 EMITH_JMP_START(DCOND_EQ);
2125
2126 emith_asr(tmp, tmp3, 31);
2127 emith_eorf_r_r(tmp, tmp4); // tmp = ((signed)macl >> 31) ^ mach
2128 EMITH_JMP_START(DCOND_EQ);
2129 emith_move_r_imm(tmp3, 0x80000000);
2130 emith_tst_r_r(tmp4, tmp4);
2131 EMITH_SJMP_START(DCOND_MI);
2132 emith_sub_r_imm_c(DCOND_PL, tmp3, 1); // positive
2133 EMITH_SJMP_END(DCOND_MI);
2134 EMITH_JMP_END(DCOND_EQ);
2135
2136 EMITH_JMP_END(DCOND_EQ);
2137 rcache_free_tmp(tmp);
f0d7b1fa 2138 cycles += 2;
2139 goto end_op;
679af8a3 2140 }
2141 goto default_;
2142
52d759c3 2143 /////////////////////////////////////////////
2144 case 0x05:
2145 // MOV.L @(disp,Rm),Rn 0101nnnnmmmmdddd
23686515 2146 emit_memhandler_read_rr(GET_Rn(), GET_Rm(), (op & 0x0f) * 4, 2);
52d759c3 2147 goto end_op;
2148
2149 /////////////////////////////////////////////
2150 case 0x06:
2151 switch (op & 0x0f)
2152 {
2153 case 0x00: // MOV.B @Rm,Rn 0110nnnnmmmm0000
2154 case 0x01: // MOV.W @Rm,Rn 0110nnnnmmmm0001
2155 case 0x02: // MOV.L @Rm,Rn 0110nnnnmmmm0010
2156 case 0x04: // MOV.B @Rm+,Rn 0110nnnnmmmm0100
2157 case 0x05: // MOV.W @Rm+,Rn 0110nnnnmmmm0101
2158 case 0x06: // MOV.L @Rm+,Rn 0110nnnnmmmm0110
23686515 2159 emit_memhandler_read_rr(GET_Rn(), GET_Rm(), 0, op & 3);
52d759c3 2160 if ((op & 7) >= 4 && GET_Rn() != GET_Rm()) {
2161 tmp = rcache_get_reg(GET_Rm(), RC_GR_RMW);
2162 emith_add_r_imm(tmp, (1 << (op & 3)));
2163 }
2164 goto end_op;
2165 case 0x03:
2166 case 0x07 ... 0x0f:
2167 tmp = rcache_get_reg(GET_Rm(), RC_GR_READ);
2168 tmp2 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2169 switch (op & 0x0f)
2170 {
2171 case 0x03: // MOV Rm,Rn 0110nnnnmmmm0011
2172 emith_move_r_r(tmp2, tmp);
2173 break;
2174 case 0x07: // NOT Rm,Rn 0110nnnnmmmm0111
2175 emith_mvn_r_r(tmp2, tmp);
2176 break;
2177 case 0x08: // SWAP.B Rm,Rn 0110nnnnmmmm1000
2178 tmp3 = tmp2;
2179 if (tmp == tmp2)
2180 tmp3 = rcache_get_tmp();
2181 tmp4 = rcache_get_tmp();
2182 emith_lsr(tmp3, tmp, 16);
f0d7b1fa 2183 emith_or_r_r_lsl(tmp3, tmp, 24);
52d759c3 2184 emith_and_r_r_imm(tmp4, tmp, 0xff00);
f0d7b1fa 2185 emith_or_r_r_lsl(tmp3, tmp4, 8);
52d759c3 2186 emith_rol(tmp2, tmp3, 16);
2187 rcache_free_tmp(tmp4);
2188 if (tmp == tmp2)
2189 rcache_free_tmp(tmp3);
2190 break;
2191 case 0x09: // SWAP.W Rm,Rn 0110nnnnmmmm1001
2192 emith_rol(tmp2, tmp, 16);
2193 break;
2194 case 0x0a: // NEGC Rm,Rn 0110nnnnmmmm1010
8796b7ee 2195 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2196 if (drcf.delayed_op)
2197 DELAY_SAVE_T(sr);
8b4f38f4 2198 emith_tpop_carry(sr, 1);
52d759c3 2199 emith_negcf_r_r(tmp2, tmp);
8b4f38f4 2200 emith_tpush_carry(sr, 1);
52d759c3 2201 break;
2202 case 0x0b: // NEG Rm,Rn 0110nnnnmmmm1011
2203 emith_neg_r_r(tmp2, tmp);
2204 break;
2205 case 0x0c: // EXTU.B Rm,Rn 0110nnnnmmmm1100
2206 emith_clear_msb(tmp2, tmp, 24);
2207 break;
2208 case 0x0d: // EXTU.W Rm,Rn 0110nnnnmmmm1101
2209 emith_clear_msb(tmp2, tmp, 16);
2210 break;
2211 case 0x0e: // EXTS.B Rm,Rn 0110nnnnmmmm1110
2212 emith_sext(tmp2, tmp, 8);
2213 break;
2214 case 0x0f: // EXTS.W Rm,Rn 0110nnnnmmmm1111
2215 emith_sext(tmp2, tmp, 16);
2216 break;
2217 }
2218 goto end_op;
2219 }
2220 goto default_;
2221
2222 /////////////////////////////////////////////
2223 case 0x07:
2224 // ADD #imm,Rn 0111nnnniiiiiiii
2225 tmp = rcache_get_reg(GET_Rn(), RC_GR_RMW);
2226 if (op & 0x80) { // adding negative
2227 emith_sub_r_imm(tmp, -op & 0xff);
2228 } else
2229 emith_add_r_imm(tmp, op & 0xff);
2230 goto end_op;
2231
3863edbd 2232 /////////////////////////////////////////////
e898de13 2233 case 0x08:
52d759c3 2234 switch (op & 0x0f00)
2235 {
2236 case 0x0000: // MOV.B R0,@(disp,Rn) 10000000nnnndddd
2237 case 0x0100: // MOV.W R0,@(disp,Rn) 10000001nnnndddd
2238 rcache_clean();
2239 tmp = rcache_get_reg_arg(0, GET_Rm());
2240 tmp2 = rcache_get_reg_arg(1, SHR_R0);
2241 tmp3 = (op & 0x100) >> 8;
23686515 2242 if (op & 0x0f)
2243 emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
e05b81fc 2244 emit_memhandler_write(tmp3, pc, drcf.delayed_op);
52d759c3 2245 goto end_op;
2246 case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
2247 case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
23686515 2248 tmp = (op & 0x100) >> 8;
2249 emit_memhandler_read_rr(SHR_R0, GET_Rm(), (op & 0x0f) << tmp, tmp);
52d759c3 2250 goto end_op;
2251 case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
2252 // XXX: could use cmn
2253 tmp = rcache_get_tmp();
2254 tmp2 = rcache_get_reg(0, RC_GR_READ);
8796b7ee 2255 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2256 if (drcf.delayed_op)
2257 DELAY_SAVE_T(sr);
52d759c3 2258 emith_move_r_imm_s8(tmp, op & 0xff);
8796b7ee 2259 emith_bic_r_imm(sr, T);
52d759c3 2260 emith_cmp_r_r(tmp2, tmp);
8796b7ee 2261 emit_or_t_if_eq(sr);
52d759c3 2262 rcache_free_tmp(tmp);
2263 goto end_op;
2264 case 0x0d00: // BT/S label 10001101dddddddd
2265 case 0x0f00: // BF/S label 10001111dddddddd
679af8a3 2266 DELAYED_OP;
2267 cycles--;
679af8a3 2268 // fallthrough
44e6452e 2269 case 0x0900: // BT label 10001001dddddddd
2270 case 0x0b00: // BF label 10001011dddddddd
2271 // will handle conditional branches later
2272 pending_branch_cond = (op & 0x0200) ? DCOND_EQ : DCOND_NE;
2273 i = ((signed int)(op << 24) >> 23);
2274 pending_branch_pc = pc + i + 2;
e898de13 2275 cycles += 2;
e898de13 2276 goto end_op;
44e6452e 2277 }
679af8a3 2278 goto default_;
679af8a3 2279
52d759c3 2280 /////////////////////////////////////////////
2281 case 0x09:
2282 // MOV.W @(disp,PC),Rn 1001nnnndddddddd
23686515 2283 tmp = pc + (op & 0xff) * 2 + 2;
2284#if PROPAGATE_CONSTANTS
2285 if (tmp < end_pc + MAX_LITERAL_OFFSET) {
2286 gconst_new(GET_Rn(), (u32)(int)(signed short)FETCH_OP(tmp));
2287 if (last_inlined_literal < tmp)
2288 last_inlined_literal = tmp;
2289 }
2290 else
2291#endif
2292 {
2293 tmp2 = rcache_get_tmp_arg(0);
2294 emith_move_r_imm(tmp2, tmp);
2295 tmp2 = emit_memhandler_read(1);
2296 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2297 emith_sext(tmp3, tmp2, 16);
2298 rcache_free_tmp(tmp2);
2299 }
f0d7b1fa 2300 goto end_op;
52d759c3 2301
3863edbd 2302 /////////////////////////////////////////////
679af8a3 2303 case 0x0a:
2304 // BRA label 1010dddddddddddd
2305 DELAYED_OP;
44e6452e 2306 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
679af8a3 2307 tmp = ((signed int)(op << 20) >> 19);
44e6452e 2308 out_pc = pc + tmp + 2;
2309 if (tmp == (u32)-4)
2310 emith_clear_msb(sr, sr, 20); // burn cycles
679af8a3 2311 cycles++;
e898de13 2312 break;
679af8a3 2313
3863edbd 2314 /////////////////////////////////////////////
679af8a3 2315 case 0x0b:
2316 // BSR label 1011dddddddddddd
2317 DELAYED_OP;
e898de13 2318 emit_move_r_imm32(SHR_PR, pc + 2);
44e6452e 2319 tmp = ((signed int)(op << 20) >> 19);
2320 out_pc = pc + tmp + 2;
2321 cycles++;
2322 break;
679af8a3 2323
52d759c3 2324 /////////////////////////////////////////////
2325 case 0x0c:
2326 switch (op & 0x0f00)
2327 {
2328 case 0x0000: // MOV.B R0,@(disp,GBR) 11000000dddddddd
2329 case 0x0100: // MOV.W R0,@(disp,GBR) 11000001dddddddd
2330 case 0x0200: // MOV.L R0,@(disp,GBR) 11000010dddddddd
2331 rcache_clean();
2332 tmp = rcache_get_reg_arg(0, SHR_GBR);
2333 tmp2 = rcache_get_reg_arg(1, SHR_R0);
2334 tmp3 = (op & 0x300) >> 8;
2335 emith_add_r_imm(tmp, (op & 0xff) << tmp3);
e05b81fc 2336 emit_memhandler_write(tmp3, pc, drcf.delayed_op);
52d759c3 2337 goto end_op;
2338 case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
2339 case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
2340 case 0x0600: // MOV.L @(disp,GBR),R0 11000110dddddddd
23686515 2341 tmp = (op & 0x300) >> 8;
2342 emit_memhandler_read_rr(SHR_R0, SHR_GBR, (op & 0xff) << tmp, tmp);
52d759c3 2343 goto end_op;
2344 case 0x0300: // TRAPA #imm 11000011iiiiiiii
2345 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2346 emith_sub_r_imm(tmp, 4*2);
52d759c3 2347 // push SR
2348 tmp = rcache_get_reg_arg(0, SHR_SP);
2349 emith_add_r_imm(tmp, 4);
2350 tmp = rcache_get_reg_arg(1, SHR_SR);
18b94127 2351 emith_clear_msb(tmp, tmp, 22);
e05b81fc 2352 emit_memhandler_write(2, pc, drcf.delayed_op);
52d759c3 2353 // push PC
2354 rcache_get_reg_arg(0, SHR_SP);
2355 tmp = rcache_get_tmp_arg(1);
2356 emith_move_r_imm(tmp, pc);
e05b81fc 2357 emit_memhandler_write(2, pc, drcf.delayed_op);
52d759c3 2358 // obtain new PC
23686515 2359 emit_memhandler_read_rr(SHR_PC, SHR_VBR, (op & 0xff) * 4, 2);
44e6452e 2360 out_pc = (u32)-1;
52d759c3 2361 cycles += 7;
44e6452e 2362 goto end_op;
52d759c3 2363 case 0x0700: // MOVA @(disp,PC),R0 11000111dddddddd
2364 emit_move_r_imm32(SHR_R0, (pc + (op & 0xff) * 4 + 2) & ~3);
2365 goto end_op;
2366 case 0x0800: // TST #imm,R0 11001000iiiiiiii
8796b7ee 2367 tmp = rcache_get_reg(SHR_R0, RC_GR_READ);
2368 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2369 if (drcf.delayed_op)
2370 DELAY_SAVE_T(sr);
8796b7ee 2371 emith_bic_r_imm(sr, T);
52d759c3 2372 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2373 emit_or_t_if_eq(sr);
52d759c3 2374 goto end_op;
2375 case 0x0900: // AND #imm,R0 11001001iiiiiiii
2376 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2377 emith_and_r_imm(tmp, op & 0xff);
2378 goto end_op;
2379 case 0x0a00: // XOR #imm,R0 11001010iiiiiiii
2380 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2381 emith_eor_r_imm(tmp, op & 0xff);
2382 goto end_op;
2383 case 0x0b00: // OR #imm,R0 11001011iiiiiiii
2384 tmp = rcache_get_reg(SHR_R0, RC_GR_RMW);
2385 emith_or_r_imm(tmp, op & 0xff);
2386 goto end_op;
2387 case 0x0c00: // TST.B #imm,@(R0,GBR) 11001100iiiiiiii
8796b7ee 2388 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2389 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
18b94127 2390 if (drcf.delayed_op)
2391 DELAY_SAVE_T(sr);
8796b7ee 2392 emith_bic_r_imm(sr, T);
52d759c3 2393 emith_tst_r_imm(tmp, op & 0xff);
8796b7ee 2394 emit_or_t_if_eq(sr);
52d759c3 2395 rcache_free_tmp(tmp);
2396 cycles += 2;
2397 goto end_op;
2398 case 0x0d00: // AND.B #imm,@(R0,GBR) 11001101iiiiiiii
2399 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2400 emith_and_r_imm(tmp, op & 0xff);
8796b7ee 2401 goto end_rmw_op;
52d759c3 2402 case 0x0e00: // XOR.B #imm,@(R0,GBR) 11001110iiiiiiii
2403 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2404 emith_eor_r_imm(tmp, op & 0xff);
8796b7ee 2405 goto end_rmw_op;
52d759c3 2406 case 0x0f00: // OR.B #imm,@(R0,GBR) 11001111iiiiiiii
2407 tmp = emit_indirect_indexed_read(SHR_R0, SHR_GBR, 0);
2408 emith_or_r_imm(tmp, op & 0xff);
8796b7ee 2409 end_rmw_op:
2410 tmp2 = rcache_get_tmp_arg(1);
2411 emith_move_r_r(tmp2, tmp);
2412 rcache_free_tmp(tmp);
2413 tmp3 = rcache_get_reg_arg(0, SHR_GBR);
2414 tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
2415 emith_add_r_r(tmp3, tmp4);
e05b81fc 2416 emit_memhandler_write(0, pc, drcf.delayed_op);
52d759c3 2417 cycles += 2;
2418 goto end_op;
2419 }
2420 goto default_;
2421
2422 /////////////////////////////////////////////
2423 case 0x0d:
2424 // MOV.L @(disp,PC),Rn 1101nnnndddddddd
23686515 2425 tmp = (pc + (op & 0xff) * 4 + 2) & ~3;
2426#if PROPAGATE_CONSTANTS
2427 if (tmp < end_pc + MAX_LITERAL_OFFSET) {
2428 gconst_new(GET_Rn(), FETCH32(tmp));
2429 if (last_inlined_literal < tmp)
2430 last_inlined_literal = tmp;
2431 }
2432 else
2433#endif
2434 {
2435 tmp2 = rcache_get_tmp_arg(0);
2436 emith_move_r_imm(tmp2, tmp);
2437 tmp2 = emit_memhandler_read(2);
2438 tmp3 = rcache_get_reg(GET_Rn(), RC_GR_WRITE);
2439 emith_move_r_r(tmp3, tmp2);
2440 rcache_free_tmp(tmp2);
2441 }
f0d7b1fa 2442 goto end_op;
52d759c3 2443
2444 /////////////////////////////////////////////
2445 case 0x0e:
2446 // MOV #imm,Rn 1110nnnniiiiiiii
23686515 2447 emit_move_r_imm32(GET_Rn(), (u32)(signed int)(signed char)op);
52d759c3 2448 goto end_op;
2449
679af8a3 2450 default:
2451 default_:
f0d7b1fa 2452 elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
2453 sh2->is_slave ? 's' : 'm', op, pc - 2);
2454#ifdef DRC_DEBUG_INTERP
679af8a3 2455 emit_move_r_imm32(SHR_PC, pc - 2);
c18edb34 2456 rcache_flush();
f4bb5d6b 2457 emith_pass_arg_r(0, CONTEXT_REG);
2458 emith_pass_arg_imm(1, op);
679af8a3 2459 emith_call(sh2_do_op);
f0d7b1fa 2460#endif
679af8a3 2461 break;
2462 }
2463
e898de13 2464end_op:
23686515 2465 rcache_unlock_all();
2466
44e6452e 2467 // conditional branch handling (with/without delay)
2468 if (pending_branch_cond != -1 && drcf.delayed_op != 2)
2469 {
2470 u32 target_pc = pending_branch_pc;
2471 void *target;
2472
18b94127 2473 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2474 // handle cycles
e05b81fc 2475 FLUSH_CYCLES(sr);
18b94127 2476 rcache_clean();
18b94127 2477 if (drcf.use_saved_t)
2478 emith_tst_r_imm(sr, T_save);
2479 else
2480 emith_tst_r_imm(sr, T);
18b94127 2481
44e6452e 2482 if (find_in_array(branch_target_pc, branch_target_count, target_pc) >= 0) {
2483 // local branch
2484 // XXX: jumps back can be linked already
2485 branch_patch_pc[branch_patch_count] = target_pc;
2486 branch_patch_ptr[branch_patch_count] = tcache_ptr;
2487 emith_jump_cond_patchable(pending_branch_cond, tcache_ptr);
2488
2489 branch_patch_count++;
2490 if (branch_patch_count == MAX_LOCAL_BRANCHES) {
2491 printf("warning: too many local branches\n");
2492 break;
2493 }
2494 }
2495 else {
2496 // can't resolve branch locally, make a block exit
2497 emit_move_r_imm32(SHR_PC, target_pc);
2498 rcache_clean();
2499
2500 target = dr_prepare_ext_branch(target_pc, sh2, tcache_id);
2501 if (target == NULL)
2502 return NULL;
2503 emith_jump_cond_patchable(pending_branch_cond, target);
18b94127 2504 }
44e6452e 2505
2506 drcf.use_saved_t = 0;
2507 pending_branch_cond = -1;
e898de13 2508 }
44e6452e 2509
18b94127 2510 // test irq?
e05b81fc 2511 // XXX: delay slots..
2512 if (drcf.test_irq && drcf.delayed_op != 2) {
2513 if (!drcf.delayed_op)
2514 emit_move_r_imm32(SHR_PC, pc);
2515 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2516 FLUSH_CYCLES(sr);
2517 rcache_flush();
2518 emith_call(sh2_drc_test_irq);
2519 drcf.test_irq = 0;
2520 }
e898de13 2521
f4bb5d6b 2522 do_host_disasm(tcache_id);
52d759c3 2523
44e6452e 2524 if (out_pc != 0 && drcf.delayed_op != 2)
2525 break;
2526 }
f4bb5d6b 2527
18b94127 2528 tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
e05b81fc 2529 FLUSH_CYCLES(tmp);
18b94127 2530 rcache_flush();
44e6452e 2531
2532 if (out_pc == (u32)-1) {
2533 // indirect jump -> back to dispatcher
2534 emith_jump(sh2_drc_dispatcher);
2535 } else {
2536 void *target;
2537 if (out_pc == 0)
2538 out_pc = pc;
2539 emit_move_r_imm32(SHR_PC, out_pc);
2540 rcache_flush();
2541
2542 target = dr_prepare_ext_branch(out_pc, sh2, tcache_id);
2543 if (target == NULL)
2544 return NULL;
2545 emith_jump_patchable(target);
2546 }
18b94127 2547
2548 // link local branches
2549 for (i = 0; i < branch_patch_count; i++) {
2550 void *target;
2551 int t;
18b94127 2552 t = find_in_array(branch_target_pc, branch_target_count, branch_patch_pc[i]);
44e6452e 2553 target = branch_target_ptr[t];
2554 if (target == NULL) {
2555 // flush pc and go back to dispatcher (should no longer happen)
18b94127 2556 printf("stray branch to %08x %p\n", branch_patch_pc[i], tcache_ptr);
2557 target = tcache_ptr;
2558 emit_move_r_imm32(SHR_PC, branch_patch_pc[i]);
2559 rcache_flush();
e05b81fc 2560 emith_jump(sh2_drc_dispatcher);
18b94127 2561 }
2562 emith_jump_patch(branch_patch_ptr[i], target);
2563 }
2564
44e6452e 2565 this_block->end_addr = pc;
23686515 2566 if (last_inlined_literal > pc)
2567 this_block->end_addr = last_inlined_literal + 4;
44e6452e 2568
f4bb5d6b 2569 // mark memory blocks as containing compiled code
18b94127 2570 if (tcache_id != 0) {
f4bb5d6b 2571 // data array, BIOS
2572 u16 *drcblk = Pico32xMem->drcblk_da[sh2->is_slave];
18b94127 2573 tmp = (this_block->addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
f4bb5d6b 2574 tmp2 = (this_block->end_addr & 0xfff) >> SH2_DRCBLK_DA_SHIFT;
18b94127 2575 drcblk[tmp] = (blkid_main << 1) | 1;
f4bb5d6b 2576 for (++tmp; tmp < tmp2; tmp++) {
2577 if (drcblk[tmp])
18b94127 2578 continue; // dont overwrite overlay block(s)
2579 drcblk[tmp] = blkid_main << 1;
f4bb5d6b 2580 }
2581 }
2582 else if ((this_block->addr & 0xc7fc0000) == 0x06000000) { // DRAM
18b94127 2583 tmp = (this_block->addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
f4bb5d6b 2584 tmp2 = (this_block->end_addr & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT;
18b94127 2585 Pico32xMem->drcblk_ram[tmp] = (blkid_main << 1) | 1;
f4bb5d6b 2586 for (++tmp; tmp < tmp2; tmp++) {
2587 if (Pico32xMem->drcblk_ram[tmp])
18b94127 2588 continue;
2589 Pico32xMem->drcblk_ram[tmp] = blkid_main << 1;
f4bb5d6b 2590 }
679af8a3 2591 }
2592
f4bb5d6b 2593 tcache_ptrs[tcache_id] = tcache_ptr;
2594
553c3eaa 2595#ifdef ARM
2596 cache_flush_d_inval_i(block_entry, tcache_ptr);
2597#endif
2598
f4bb5d6b 2599 do_host_disasm(tcache_id);
2600 dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
2601 tcache_id, block_counts[tcache_id],
2602 tcache_ptr - tcache_bases[tcache_id], tcache_sizes[tcache_id],
2603 insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
2604 if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
2605 dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
18b94127 2606/*
2607 printf("~~~\n");
2608 tcache_dsm_ptrs[tcache_id] = block_entry;
2609 do_host_disasm(tcache_id);
2610 printf("~~~\n");
2611*/
2612
553c3eaa 2613#if (DRC_DEBUG & 2)
2614 fflush(stdout);
2615#endif
2616
679af8a3 2617 return block_entry;
679af8a3 2618}
2619
e05b81fc 2620static void sh2_generate_utils(void)
679af8a3 2621{
e05b81fc 2622 int arg0, arg1, arg2, sr, tmp;
2623 void *sh2_drc_write_end, *sh2_drc_write_slot_end;
52d759c3 2624
e05b81fc 2625 host_arg2reg(arg0, 0);
2626 host_arg2reg(arg1, 1);
2627 host_arg2reg(arg2, 2);
2628 emith_move_r_r(arg0, arg0); // nop
679af8a3 2629
e05b81fc 2630 // sh2_drc_exit(void)
2631 sh2_drc_exit = (void *)tcache_ptr;
2632 emit_do_static_regs(1, arg2);
2633 emith_sh2_drc_exit();
679af8a3 2634
e05b81fc 2635 // sh2_drc_dispatcher(void)
2636 sh2_drc_dispatcher = (void *)tcache_ptr;
2637 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2638 emith_cmp_r_imm(sr, 0);
2639 emith_jump_cond(DCOND_LT, sh2_drc_exit);
2640 rcache_invalidate();
2641 emith_ctx_read(arg0, SHR_PC * 4);
2642 emith_ctx_read(arg1, offsetof(SH2, is_slave));
2643 emith_add_r_r_imm(arg2, CONTEXT_REG, offsetof(SH2, drc_tmp));
2644 emith_call(lookup_block);
2645 emit_block_entry();
2646 // lookup failed, call sh2_translate()
2647 emith_move_r_r(arg0, CONTEXT_REG);
2648 emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
2649 emith_call(sh2_translate);
2650 emit_block_entry();
2651 // sh2_translate() failed, flush cache and retry
2652 emith_ctx_read(arg0, offsetof(SH2, drc_tmp));
2653 emith_call(flush_tcache);
2654 emith_move_r_r(arg0, CONTEXT_REG);
2655 emith_ctx_read(arg1, offsetof(SH2, drc_tmp));
2656 emith_call(sh2_translate);
2657 emit_block_entry();
2658 // XXX: can't translate, fail
2659 emith_call(exit);
2660
2661 // sh2_drc_test_irq(void)
2662 // assumes it's called from main function (may jump to dispatcher)
2663 sh2_drc_test_irq = (void *)tcache_ptr;
2664 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2665 sr = rcache_get_reg(SHR_SR, RC_GR_READ);
2666 emith_lsr(arg0, sr, I_SHIFT);
2667 emith_and_r_imm(arg0, 0x0f);
2668 emith_cmp_r_r(arg1, arg0); // pending_level > ((sr >> 4) & 0x0f)?
2669 EMITH_SJMP_START(DCOND_GT);
2670 emith_ret_c(DCOND_LE); // nope, return
2671 EMITH_SJMP_END(DCOND_GT);
2672 // adjust SP
2673 tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
2674 emith_sub_r_imm(tmp, 4*2);
2675 rcache_clean();
2676 // push SR
2677 tmp = rcache_get_reg_arg(0, SHR_SP);
2678 emith_add_r_imm(tmp, 4);
2679 tmp = rcache_get_reg_arg(1, SHR_SR);
2680 emith_clear_msb(tmp, tmp, 22);
2681 emith_move_r_r(arg2, CONTEXT_REG);
2682 emith_call(p32x_sh2_write32);
2683 rcache_invalidate();
2684 // push PC
2685 rcache_get_reg_arg(0, SHR_SP);
2686 emith_ctx_read(arg1, SHR_PC * 4);
2687 emith_move_r_r(arg2, CONTEXT_REG);
2688 emith_call(p32x_sh2_write32);
2689 rcache_invalidate();
2690 // update I, cycles, do callback
2691 emith_ctx_read(arg1, offsetof(SH2, pending_level));
2692 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2693 emith_bic_r_imm(sr, I);
2694 emith_or_r_r_lsl(sr, arg1, I_SHIFT);
2695 emith_sub_r_imm(sr, 13 << 12); // at least 13 cycles
2696 rcache_flush();
2697 emith_move_r_r(arg0, CONTEXT_REG);
2698 emith_call_ctx(offsetof(SH2, irq_callback)); // vector = sh2->irq_callback(sh2, level);
2699 // obtain new PC
2700 emith_lsl(arg0, arg0, 2);
2701 emith_ctx_read(arg1, SHR_VBR * 4);
2702 emith_add_r_r(arg0, arg1);
2703 emit_memhandler_read(2);
2704 emith_ctx_write(arg0, SHR_PC * 4);
2705#ifdef __i386__
2706 emith_add_r_imm(xSP, 4); // fix stack
2707#endif
2708 emith_jump(sh2_drc_dispatcher);
2709 rcache_invalidate();
2710
2711 // sh2_drc_entry(SH2 *sh2)
2712 sh2_drc_entry = (void *)tcache_ptr;
2713 emith_sh2_drc_entry();
2714 emith_move_r_r(CONTEXT_REG, arg0); // move ctx, arg0
2715 emit_do_static_regs(0, arg2);
2716 emith_call(sh2_drc_test_irq);
2717 emith_jump(sh2_drc_dispatcher);
2718
2719 // write-caused irq detection
2720 sh2_drc_write_end = tcache_ptr;
2721 emith_tst_r_r(arg0, arg0);
2722 EMITH_SJMP_START(DCOND_NE);
2723 emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp)); // return
2724 EMITH_SJMP_END(DCOND_NE);
2725 // since PC is up to date, jump to it's block instead of returning
2726 emith_call(sh2_drc_test_irq);
2727 emith_jump_ctx(offsetof(SH2, drc_tmp));
2728
2729 // write-caused irq detection for writes in delay slot
2730 sh2_drc_write_slot_end = tcache_ptr;
2731 emith_tst_r_r(arg0, arg0);
2732 EMITH_SJMP_START(DCOND_NE);
2733 emith_jump_ctx_c(DCOND_EQ, offsetof(SH2, drc_tmp));
2734 EMITH_SJMP_END(DCOND_NE);
2735 // just burn cycles to get back to dispatcher after branch is handled
2736 sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
2737 emith_ctx_write(sr, offsetof(SH2, irq_cycles));
2738 emith_clear_msb(sr, sr, 20); // clear cycles
2739 rcache_flush();
2740 emith_jump_ctx(offsetof(SH2, drc_tmp));
2741
2742 // sh2_drc_write8(u32 a, u32 d)
2743 sh2_drc_write8 = (void *)tcache_ptr;
2744 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2745 emith_ctx_read(arg2, offsetof(SH2, write8_tab));
2746 emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
2747
2748 // sh2_drc_write16(u32 a, u32 d)
2749 sh2_drc_write16 = (void *)tcache_ptr;
2750 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2751 emith_ctx_read(arg2, offsetof(SH2, write16_tab));
2752 emith_sh2_wcall(arg0, arg2, sh2_drc_write_end);
2753
2754 // sh2_drc_write8_slot(u32 a, u32 d)
2755 sh2_drc_write8_slot = (void *)tcache_ptr;
2756 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2757 emith_ctx_read(arg2, offsetof(SH2, write8_tab));
2758 emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
2759
2760 // sh2_drc_write16_slot(u32 a, u32 d)
2761 sh2_drc_write16_slot = (void *)tcache_ptr;
2762 emith_ret_to_ctx(offsetof(SH2, drc_tmp));
2763 emith_ctx_read(arg2, offsetof(SH2, write16_tab));
2764 emith_sh2_wcall(arg0, arg2, sh2_drc_write_slot_end);
2765
2766 rcache_invalidate();
2767#if (DRC_DEBUG & 2)
2768 host_dasm_new_symbol(sh2_drc_entry);
2769 host_dasm_new_symbol(sh2_drc_dispatcher);
2770 host_dasm_new_symbol(sh2_drc_exit);
2771 host_dasm_new_symbol(sh2_drc_test_irq);
2772 host_dasm_new_symbol(sh2_drc_write_end);
2773 host_dasm_new_symbol(sh2_drc_write_slot_end);
2774 host_dasm_new_symbol(sh2_drc_write8);
2775 host_dasm_new_symbol(sh2_drc_write8_slot);
2776 host_dasm_new_symbol(sh2_drc_write16);
2777 host_dasm_new_symbol(sh2_drc_write16_slot);
679af8a3 2778#endif
679af8a3 2779}
2780
f4bb5d6b 2781static void sh2_smc_rm_block(u16 *drcblk, u16 *p, block_desc *btab, u32 a)
2782{
2783 u16 id = *p >> 1;
2784 block_desc *bd = btab + id;
2785
18b94127 2786 // FIXME: skip subblocks; do both directions
44e6452e 2787 // FIXME: collect all branches
f4bb5d6b 2788 dbg(1, " killing block %08x", bd->addr);
2789 bd->addr = bd->end_addr = 0;
2790
2791 while (p > drcblk && (p[-1] >> 1) == id)
2792 p--;
2793
2794 // check for possible overlay block
2795 if (p > 0 && p[-1] != 0) {
2796 bd = btab + (p[-1] >> 1);
2797 if (bd->addr <= a && a < bd->end_addr)
2798 sh2_smc_rm_block(drcblk, p - 1, btab, a);
2799 }
2800
2801 do {
2802 *p++ = 0;
2803 }
2804 while ((*p >> 1) == id);
2805}
2806
2807void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid)
2808{
2809 u16 *drcblk = Pico32xMem->drcblk_ram;
2810 u16 *p = drcblk + ((a & 0x3ffff) >> SH2_DRCBLK_RAM_SHIFT);
2811
2812 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
2813 sh2_smc_rm_block(drcblk, p, block_tables[0], a);
2814}
2815
2816void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid)
2817{
2818 u16 *drcblk = Pico32xMem->drcblk_da[cpuid];
2819 u16 *p = drcblk + ((a & 0xfff) >> SH2_DRCBLK_DA_SHIFT);
2820
2821 dbg(1, "%csh2 smc check @%08x", cpuid ? 's' : 'm', a);
2822 sh2_smc_rm_block(drcblk, p, block_tables[1 + cpuid], a);
2823}
2824
52d759c3 2825void sh2_execute(SH2 *sh2c, int cycles)
679af8a3 2826{
e05b81fc 2827 int ret_cycles;
52d759c3 2828 sh2 = sh2c; // XXX
2829
2830 sh2c->cycles_aim += cycles;
2831 cycles = sh2c->cycles_aim - sh2c->cycles_done;
679af8a3 2832
2833 // cycles are kept in SHR_SR unused bits (upper 20)
18b94127 2834 // bit19 contains T saved for delay slot
2835 // others are usual SH2 flags
52d759c3 2836 sh2c->sr &= 0x3f3;
2837 sh2c->sr |= cycles << 12;
e05b81fc 2838 sh2_drc_entry(sh2c);
679af8a3 2839
e05b81fc 2840 // TODO: irq cycles
2841 ret_cycles = (signed int)sh2c->sr >> 12;
2842 if (ret_cycles > 0)
2843 printf("warning: drc returned with cycles: %d\n", ret_cycles);
679af8a3 2844
e05b81fc 2845 sh2c->cycles_done += cycles - ret_cycles;
679af8a3 2846}
2847
f4bb5d6b 2848#if (DRC_DEBUG & 1)
9bb5d91c 2849void block_stats(void)
f4bb5d6b 2850{
2851 int c, b, i, total = 0;
2852
9bb5d91c 2853 printf("block stats:\n");
f4bb5d6b 2854 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
2855 for (i = 0; i < block_counts[b]; i++)
2856 if (block_tables[b][i].addr != 0)
2857 total += block_tables[b][i].refcount;
2858
2859 for (c = 0; c < 10; c++) {
2860 block_desc *blk, *maxb = NULL;
2861 int max = 0;
2862 for (b = 0; b < ARRAY_SIZE(block_tables); b++) {
2863 for (i = 0; i < block_counts[b]; i++) {
2864 blk = &block_tables[b][i];
2865 if (blk->addr != 0 && blk->refcount > max) {
2866 max = blk->refcount;
2867 maxb = blk;
2868 }
2869 }
2870 }
2871 if (maxb == NULL)
2872 break;
2873 printf("%08x %9d %2.3f%%\n", maxb->addr, maxb->refcount,
2874 (double)maxb->refcount / total * 100.0);
2875 maxb->refcount = 0;
2876 }
553c3eaa 2877
2878 for (b = 0; b < ARRAY_SIZE(block_tables); b++)
2879 for (i = 0; i < block_counts[b]; i++)
2880 block_tables[b][i].refcount = 0;
f4bb5d6b 2881}
553c3eaa 2882#else
2883#define block_stats()
f4bb5d6b 2884#endif
2885
553c3eaa 2886void sh2_drc_flush_all(void)
2887{
2888 block_stats();
2889 flush_tcache(0);
2890 flush_tcache(1);
2891 flush_tcache(2);
2892}
2893
23686515 2894void sh2_drc_mem_setup(SH2 *sh2)
2895{
2896 // fill the convenience pointers
2897 sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
2898 sh2->p_da = Pico32xMem->data_array[sh2->is_slave];
2899 sh2->p_sdram = Pico32xMem->sdram;
2900 sh2->p_rom = Pico.rom;
2901}
2902
679af8a3 2903int sh2_drc_init(SH2 *sh2)
2904{
44e6452e 2905 int i;
7f5a3fc1 2906
44e6452e 2907 if (block_tables[0] == NULL)
2908 {
2909 for (i = 0; i < TCACHE_BUFFERS; i++) {
2910 block_tables[i] = calloc(block_max_counts[i], sizeof(*block_tables[0]));
2911 if (block_tables[i] == NULL)
2912 goto fail;
2913 // max 2 block links (exits) per block
2914 block_links[i] = calloc(block_max_counts[i] * 2, sizeof(*block_links[0]));
2915 if (block_links[i] == NULL)
2916 goto fail;
2917 }
2918 memset(block_counts, 0, sizeof(block_counts));
2919 memset(block_link_counts, 0, sizeof(block_link_counts));
e898de13 2920
44e6452e 2921 drc_cmn_init();
8796b7ee 2922 tcache_ptr = tcache;
2923 sh2_generate_utils();
8b4f38f4 2924#ifdef ARM
2925 cache_flush_d_inval_i(tcache, tcache_ptr);
2926#endif
8796b7ee 2927
8796b7ee 2928 tcache_bases[0] = tcache_ptrs[0] = tcache_ptr;
44e6452e 2929 for (i = 1; i < ARRAY_SIZE(tcache_bases); i++)
f4bb5d6b 2930 tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
f4bb5d6b 2931
553c3eaa 2932 // tmp
2933 PicoOpt |= POPT_DIS_VDP_FIFO;
2934
f4bb5d6b 2935#if (DRC_DEBUG & 2)
2936 for (i = 0; i < ARRAY_SIZE(block_tables); i++)
2937 tcache_dsm_ptrs[i] = tcache_bases[i];
8796b7ee 2938 // disasm the utils
2939 tcache_dsm_ptrs[0] = tcache;
2940 do_host_disasm(0);
f4bb5d6b 2941#endif
e898de13 2942#if (DRC_DEBUG & 1)
2943 hash_collisions = 0;
2944#endif
679af8a3 2945 }
2946
f4bb5d6b 2947 if (hash_table == NULL) {
2948 hash_table = calloc(sizeof(hash_table[0]), MAX_HASH_ENTRIES);
2949 if (hash_table == NULL)
44e6452e 2950 goto fail;
f4bb5d6b 2951 }
41397701 2952
679af8a3 2953 return 0;
44e6452e 2954
2955fail:
2956 sh2_drc_finish(sh2);
2957 return -1;
41397701 2958}
2959
e898de13 2960void sh2_drc_finish(SH2 *sh2)
2961{
44e6452e 2962 int i;
2963
f4bb5d6b 2964 if (block_tables[0] != NULL) {
f4bb5d6b 2965 block_stats();
44e6452e 2966
2967 for (i = 0; i < TCACHE_BUFFERS; i++) {
2968#if (DRC_DEBUG & 2)
2969 printf("~~~ tcache %d\n", i);
2970 tcache_dsm_ptrs[i] = tcache_bases[i];
2971 tcache_ptr = tcache_ptrs[i];
2972 do_host_disasm(i);
2973#endif
2974
2975 if (block_tables[i] != NULL)
2976 free(block_tables[i]);
2977 block_tables[i] = NULL;
2978 if (block_links[i] == NULL)
2979 free(block_links[i]);
2980 block_links[i] = NULL;
2981 }
7f5a3fc1 2982
2983 drc_cmn_cleanup();
e898de13 2984 }
2985
f4bb5d6b 2986 if (hash_table != NULL) {
2987 free(hash_table);
2988 hash_table = NULL;
2989 }
e898de13 2990}