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