#define DRC_DEBUG 0
#endif
+#if DRC_DEBUG
#define dbg(l,...) { \
if ((l) & DRC_DEBUG) \
elprintf(EL_STATUS, ##__VA_ARGS__); \
}
-#if DRC_DEBUG
#include "mame/sh2dasm.h"
#include <platform/linux/host_dasm.h>
static int insns_compiled, hash_collisions, host_insn_count;
+#define COUNT_OP \
+ host_insn_count++
+#else // !DRC_DEBUG
+#define COUNT_OP
+#define dbg(...)
#endif
+
#if (DRC_DEBUG & 2)
static u8 *tcache_dsm_ptrs[3];
static char sh2dasm_buff[64];
// ptr for code emiters
static u8 *tcache_ptr;
+// host register tracking
+enum {
+ HR_FREE,
+ HR_CACHED, // 'val' has sh2_reg_e
+ HR_CACHED_DIRTY,
+ HR_CONST, // 'val' has constant
+ HR_TEMP, // reg used for temp storage
+};
+
+typedef struct {
+ u8 reg;
+ u8 type;
+ u16 stamp; // kind of a timestamp
+ u32 val;
+} temp_reg_t;
+
#ifdef ARM
#include "../drc/emit_arm.c"
static const int reg_map_g2h[] = {
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+};
+
+static temp_reg_t reg_temp[] = {
+ { 0, },
+ { 1, },
+ { 12, },
+ { 14, },
+ { 2, },
+ { 3, },
};
#else
#include "../drc/emit_x86.c"
static const int reg_map_g2h[] = {
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+};
+
+// ax, cx, dx are usually temporaries
+static temp_reg_t reg_temp[] = {
+ { xAX, },
+ { xCX, },
+ { xDX, },
};
#endif
extern void sh2_drc_exit(void);
// tmp
-extern void __attribute__((regparm(2))) sh2_do_op(SH2 *sh2, int opcode);
-static void __attribute__((regparm(1))) sh2_test_irq(SH2 *sh2);
+extern void REGPARM(2) sh2_do_op(SH2 *sh2, int opcode);
+static void REGPARM(1) sh2_test_irq(SH2 *sh2);
static void flush_tcache(int tcid)
{
- printf("tcache #%d flush! (%d/%d, bds %d/%d)\n", tcid,
+ dbg(1, "tcache #%d flush! (%d/%d, bds %d/%d)", tcid,
tcache_ptrs[tcid] - tcache_bases[tcid], tcache_sizes[tcid],
block_counts[tcid], block_max_counts[tcid]);
// ---------------------------------------------------------------
-static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
+// register chache
+static u16 rcache_counter;
+
+static temp_reg_t *rcache_evict(void)
{
- int host_dst = reg_map_g2h[dst];
- int tmp = 0;
-
- if (host_dst != -1)
- tmp = host_dst;
- emith_move_r_imm(tmp, imm);
- if (host_dst == -1)
- emith_ctx_write(tmp, dst * 4);
+ // evict reg with oldest stamp
+ int i, oldest = -1;
+ u16 min_stamp = (u16)-1;
+
+ for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
+ if (reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY)
+ if (reg_temp[i].stamp <= min_stamp) {
+ min_stamp = reg_temp[i].stamp;
+ oldest = i;
+ }
+ }
+
+ if (oldest == -1) {
+ printf("no registers to ec=vict, aborting\n");
+ exit(1);
+ }
+
+ i = oldest;
+ if (reg_temp[i].type == HR_CACHED_DIRTY) {
+ // writeback
+ emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
+ }
+
+ return ®_temp[i];
}
-static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
+typedef enum {
+ RC_GR_READ,
+ RC_GR_WRITE,
+ RC_GR_RMW,
+} rc_gr_mode;
+
+static int rcache_get_reg(sh2_reg_e r, rc_gr_mode mode)
{
- int host_dst = reg_map_g2h[dst], host_src = reg_map_g2h[src];
- int tmp = 0;
+ temp_reg_t *tr;
+ int i;
+
+ // maybe already statically mapped?
+ i = reg_map_g2h[r];
+ if (i != -1)
+ return i;
+
+ rcache_counter++;
- if (host_dst != -1 && host_src != -1) {
- emith_move_r_r(host_dst, host_src);
- return;
+ // maybe already cached?
+ for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
+ if ((reg_temp[i].type == HR_CACHED || reg_temp[i].type == HR_CACHED_DIRTY) &&
+ reg_temp[i].val == r)
+ {
+ reg_temp[i].stamp = rcache_counter;
+ if (mode != RC_GR_READ)
+ reg_temp[i].type = HR_CACHED_DIRTY;
+ return reg_temp[i].reg;
+ }
+ }
+
+ // use any free reg
+ for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
+ if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
+ tr = ®_temp[i];
+ goto do_alloc;
+ }
}
- if (host_src != -1)
- tmp = host_src;
- if (host_dst != -1)
- tmp = host_dst;
+ tr = rcache_evict();
- if (host_src == -1)
- emith_ctx_read(tmp, src * 4);
- if (host_dst == -1)
- emith_ctx_write(tmp, dst * 4);
+do_alloc:
+ if (mode != RC_GR_WRITE)
+ emith_ctx_read(tr->reg, r * 4);
+
+ tr->type = mode != RC_GR_READ ? HR_CACHED_DIRTY : HR_CACHED;
+ tr->val = r;
+ tr->stamp = rcache_counter;
+ return tr->reg;
}
-static void emit_braf(sh2_reg_e reg, u32 pc)
+static int rcache_get_tmp(void)
{
- int host_reg = reg_map_g2h[reg];
- if (host_reg == -1) {
- emith_ctx_read(0, reg * 4);
- } else
- emith_move_r_r(0, host_reg);
- emith_add_r_imm(0, pc);
-
- emith_ctx_write(0, SHR_PPC * 4);
+ temp_reg_t *tr;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
+ if (reg_temp[i].type == HR_FREE || reg_temp[i].type == HR_CONST) {
+ tr = ®_temp[i];
+ goto do_alloc;
+ }
+
+ tr = rcache_evict();
+
+do_alloc:
+ tr->type = HR_TEMP;
+ return tr->reg;
+}
+
+static void rcache_free_tmp(int hr)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(reg_temp); i++)
+ if (reg_temp[i].reg == hr)
+ break;
+
+ if (i == ARRAY_SIZE(reg_temp) || reg_temp[i].type != HR_TEMP)
+ printf("rcache_free_tmp fail: #%i hr %d, type %d\n", i, hr, reg_temp[i].type);
+}
+
+static void rcache_flush(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(reg_temp); i++) {
+ if (reg_temp[i].type == HR_CACHED_DIRTY) {
+ // writeback
+ emith_ctx_write(reg_temp[i].reg, reg_temp[i].val * 4);
+ }
+ reg_temp[i].type = HR_FREE;
+ }
+ rcache_counter = 0;
+}
+
+// ---------------------------------------------------------------
+
+static void emit_move_r_imm32(sh2_reg_e dst, u32 imm)
+{
+ int hr = rcache_get_reg(dst, RC_GR_WRITE);
+ emith_move_r_imm(hr, imm);
+}
+
+static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
+{
+ int hr_d = rcache_get_reg(dst, RC_GR_WRITE);
+ int hr_s = rcache_get_reg(src, RC_GR_READ);
+
+ emith_move_r_r(hr_d, hr_s);
}
/*
DELAYED_OP;
if (!(op & 0x20))
emit_move_r_imm32(SHR_PR, pc + 2);
- emit_braf((op >> 8) & 0x0f, pc + 2);
+ tmp = rcache_get_reg(SHR_PPC, RC_GR_WRITE);
+ tmp2 = rcache_get_reg((op >> 8) & 0x0f, RC_GR_READ);
+ emith_move_r_r(tmp, tmp2);
+ emith_add_r_imm(tmp, pc + 2);
cycles++;
goto end_op;
case 0x09:
// RTE 0000000000101011
//emit_move_r_r(SHR_PC, SHR_PR);
emit_move_r_imm32(SHR_PC, pc - 2);
+ rcache_flush();
emith_pass_arg_r(0, CONTEXT_REG);
emith_pass_arg_imm(1, op);
emith_call(sh2_do_op);
case 0x04:
switch (op & 0x0f) {
+ case 0x00:
+ if ((op & 0xf0) != 1)
+ goto default_;
+ // DT Rn 0100nnnn00010000
+ goto default_;
case 0x07:
if ((op & 0xf0) != 0)
goto default_;
default:
default_:
emit_move_r_imm32(SHR_PC, pc - 2);
+ rcache_flush();
emith_pass_arg_r(0, CONTEXT_REG);
emith_pass_arg_imm(1, op);
emith_call(sh2_do_op);
emit_move_r_r(SHR_PC, SHR_PPC);
if (test_irq && delayed_op != 2) {
+ rcache_flush();
emith_pass_arg_r(0, CONTEXT_REG);
emith_call(sh2_test_irq);
break;
}
}
- if (reg_map_g2h[SHR_SR] == -1) {
- emith_ctx_sub(cycles << 12, SHR_SR * 4);
- } else
- emith_sub_r_imm(reg_map_g2h[SHR_SR], cycles << 12);
+ tmp = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ emith_sub_r_imm(tmp, cycles << 12);
+ rcache_flush();
emith_jump(sh2_drc_exit);
tcache_ptrs[tcache_id] = tcache_ptr;
+#ifdef ARM
+ cache_flush_d_inval_i(block_entry, tcache_ptr);
+#endif
+
do_host_disasm(tcache_id);
dbg(1, " block #%d,%d tcache %d/%d, insns %d -> %d %.3f",
tcache_id, block_counts[tcache_id],
insns_compiled, host_insn_count, (double)host_insn_count / insns_compiled);
if ((sh2->pc & 0xc6000000) == 0x02000000) // ROM
dbg(1, " hash collisions %d/%d", hash_collisions, block_counts[tcache_id]);
+#if (DRC_DEBUG & 2)
+ fflush(stdout);
+#endif
+
return block_entry;
/*
unimplemented:
sh2->cycles_done += cycles - ((signed int)sh2->sr >> 12);
}
-static void __attribute__((regparm(1))) sh2_test_irq(SH2 *sh2)
+static void REGPARM(1) sh2_test_irq(SH2 *sh2)
{
if (sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
{
(double)maxb->refcount / total * 100.0);
maxb->refcount = 0;
}
+
+ for (b = 0; b < ARRAY_SIZE(block_tables); b++)
+ for (i = 0; i < block_counts[b]; i++)
+ block_tables[b][i].refcount = 0;
}
+#else
+#define block_stats()
#endif
+void sh2_drc_flush_all(void)
+{
+ block_stats();
+ flush_tcache(0);
+ flush_tcache(1);
+ flush_tcache(2);
+}
+
int sh2_drc_init(SH2 *sh2)
{
if (block_tables[0] == NULL) {
int i, cnt;
+
+ drc_cmn_init();
+
cnt = block_max_counts[0] + block_max_counts[1] + block_max_counts[2];
block_tables[0] = calloc(cnt, sizeof(*block_tables[0]));
if (block_tables[0] == NULL)
tcache_bases[i] = tcache_ptrs[i] = tcache_bases[i - 1] + tcache_sizes[i - 1];
}
+ // tmp
+ PicoOpt |= POPT_DIS_VDP_FIFO;
+
#if (DRC_DEBUG & 2)
for (i = 0; i < ARRAY_SIZE(block_tables); i++)
tcache_dsm_ptrs[i] = tcache_bases[i];
void sh2_drc_finish(SH2 *sh2)
{
if (block_tables[0] != NULL) {
-#if (DRC_DEBUG & 1)
block_stats();
-#endif
free(block_tables[0]);
memset(block_tables, 0, sizeof(block_tables));
+
+ drc_cmn_cleanup();
}
if (hash_table != NULL) {