#include <assert.h>
#include <errno.h>
#include <sys/mman.h>
+#include <unistd.h>
#ifdef __MACH__
#include <libkern/OSCacheControl.h>
#endif
#include "new_dynarec_config.h"
#include "../psxhle.h"
#include "../psxinterpreter.h"
+#include "../psxcounters.h"
#include "../gte.h"
#include "emu_if.h" // emulator interface
#include "linkage_offsets.h"
struct ndrc_tramp tramp;
};
-#ifdef BASE_ADDR_DYNAMIC
static struct ndrc_mem *ndrc;
-#else
-static struct ndrc_mem ndrc_ __attribute__((aligned(4096)));
-static struct ndrc_mem *ndrc = &ndrc_;
+#ifndef BASE_ADDR_DYNAMIC
+// reserve .bss space with upto 64k page size in mind
+static char ndrc_bss[((sizeof(*ndrc) + 65535) & ~65535) + 65536];
#endif
#ifdef TC_WRITE_OFFSET
# ifdef __GLIBC__
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
-# include <unistd.h>
# endif
static long ndrc_write_ofs;
#define NDRC_WRITE_OFFSET(x) (void *)((char *)(x) + ndrc_write_ofs)
return &hash_table[((vaddr>>16)^vaddr)&0xFFFF];
}
+#define HASH_TABLE_BAD 0xbac
+
+static void hash_table_clear(void)
+{
+ struct ht_entry *ht_bin;
+ int i, j;
+ for (i = 0; i < ARRAY_SIZE(hash_table); i++) {
+ for (j = 0; j < ARRAY_SIZE(hash_table[i].vaddr); j++) {
+ hash_table[i].vaddr[j] = ~0;
+ hash_table[i].tcaddr[j] = (void *)(uintptr_t)HASH_TABLE_BAD;
+ }
+ }
+ // don't allow ~0 to hit
+ ht_bin = hash_table_get(~0);
+ for (j = 0; j < ARRAY_SIZE(ht_bin->vaddr); j++)
+ ht_bin->vaddr[j] = 1;
+}
+
static void hash_table_add(u_int vaddr, void *tcaddr)
{
struct ht_entry *ht_bin = hash_table_get(vaddr);
//printf("remove hash: %x\n",vaddr);
struct ht_entry *ht_bin = hash_table_get(vaddr);
if (ht_bin->vaddr[1] == vaddr) {
- ht_bin->vaddr[1] = -1;
- ht_bin->tcaddr[1] = NULL;
+ ht_bin->vaddr[1] = ~0;
+ ht_bin->tcaddr[1] = (void *)(uintptr_t)HASH_TABLE_BAD;
}
if (ht_bin->vaddr[0] == vaddr) {
ht_bin->vaddr[0] = ht_bin->vaddr[1];
ht_bin->tcaddr[0] = ht_bin->tcaddr[1];
- ht_bin->vaddr[1] = -1;
- ht_bin->tcaddr[1] = NULL;
+ ht_bin->vaddr[1] = ~0;
+ ht_bin->tcaddr[1] = (void *)(uintptr_t)HASH_TABLE_BAD;
+ }
+}
+
+static void mini_ht_clear(void)
+{
+#ifdef USE_MINI_HT
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mini_ht) - 1; i++) {
+ mini_ht[i][0] = ~0;
+ mini_ht[i][1] = HASH_TABLE_BAD;
}
+ mini_ht[i][0] = 1;
+ mini_ht[i][1] = HASH_TABLE_BAD;
+#endif
}
static void mark_invalid_code(u_int vaddr, u_int len, char invalid)
}
if (hit) {
do_clear_cache();
-#ifdef USE_MINI_HT
- memset(mini_ht, -1, sizeof(mini_ht));
-#endif
+ mini_ht_clear();
}
if (inv_start <= (start_m & ~0xfff) && inv_end >= (start_m | 0xfff))
}
}
- #ifdef USE_MINI_HT
- memset(mini_ht, -1, sizeof(mini_ht));
- #endif
do_clear_cache();
+ mini_ht_clear();
}
// Add an entry to jump_out after making a link
out = ndrc->translation_cache;
}
+static int get_cycle_multiplier(void)
+{
+ return Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
+ ? Config.cycle_multiplier_override : Config.cycle_multiplier;
+}
+
// clear the state completely, instead of just marking
// things invalid like invalidate_all_pages() does
void new_dynarec_clear_full(void)
int n;
out = ndrc->translation_cache;
memset(invalid_code,1,sizeof(invalid_code));
- memset(hash_table,0xff,sizeof(hash_table));
- memset(mini_ht,-1,sizeof(mini_ht));
memset(shadow,0,sizeof(shadow));
+ hash_table_clear();
+ mini_ht_clear();
copy=shadow;
expirep = EXPIRITY_OFFSET;
pending_exception=0;
stat_clear(stat_blocks);
stat_clear(stat_links);
+ if (cycle_multiplier_old != Config.cycle_multiplier
+ || new_dynarec_hacks_old != new_dynarec_hacks)
+ {
+ SysPrintf("ndrc config: mul=%d, ha=%x, pex=%d\n",
+ get_cycle_multiplier(), new_dynarec_hacks, Config.PreciseExceptions);
+ }
cycle_multiplier_old = Config.cycle_multiplier;
new_dynarec_hacks_old = new_dynarec_hacks;
}
+static int pgsize(void)
+{
+#ifdef _SC_PAGESIZE
+ return sysconf(_SC_PAGESIZE);
+#else
+ return 4096;
+#endif
+}
+
void new_dynarec_init(void)
{
- SysPrintf("Init new dynarec, ndrc size %x\n", (int)sizeof(*ndrc));
+ int align = pgsize() - 1;
+ SysPrintf("Init new dynarec, ndrc size %x, pgsize %d\n",
+ (int)sizeof(*ndrc), align + 1);
#ifdef _3DS
check_rosalina();
#endif
#else
#ifndef NO_WRITE_EXEC
+ ndrc = (struct ndrc_mem *)((size_t)(ndrc_bss + align) & ~align);
// not all systems allow execute in data segment by default
// size must be 4K aligned for 3DS?
if (mprotect(ndrc, sizeof(*ndrc),
PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
- SysPrintf("mprotect() failed: %s\n", strerror(errno));
+ SysPrintf("mprotect(%p) failed: %s\n", ndrc, strerror(errno));
#endif
#endif
out = ndrc->translation_cache;
#endif
}
+static void force_intcall(int i)
+{
+ memset(&dops[i], 0, sizeof(dops[i]));
+ dops[i].itype = INTCALL;
+ dops[i].rs1 = CCREG;
+ dops[i].is_exception = 1;
+ cinfo[i].ba = -1;
+}
+
static int apply_hacks(void)
{
int i;
return 1;
}
}
+ if (Config.HLE)
+ {
+ if (start <= psxRegs.biosBranchCheck && psxRegs.biosBranchCheck < start + i*4)
+ {
+ i = (psxRegs.biosBranchCheck - start) / 4u + 23;
+ if (dops[i].is_jump && !dops[i+1].bt)
+ {
+ force_intcall(i);
+ dops[i+1].is_ds = 0;
+ }
+ }
+ }
return 0;
}
-static int is_ld_use_hazard(int ld_rt, const struct decoded_insn *op)
+static int is_ld_use_hazard(const struct decoded_insn *op_ld,
+ const struct decoded_insn *op)
{
- return ld_rt != 0 && (ld_rt == op->rs1 || ld_rt == op->rs2)
- && op->itype != LOADLR && op->itype != CJUMP && op->itype != SJUMP;
-}
-
-static void force_intcall(int i)
-{
- memset(&dops[i], 0, sizeof(dops[i]));
- dops[i].itype = INTCALL;
- dops[i].rs1 = CCREG;
- dops[i].is_exception = 1;
- cinfo[i].ba = -1;
+ if (op_ld->rt1 == 0 || (op_ld->rt1 != op->rs1 && op_ld->rt1 != op->rs2))
+ return 0;
+ if (op_ld->itype == LOADLR && op->itype == LOADLR)
+ return op_ld->rt1 == op_ld->rs1;
+ return op->itype != CJUMP && op->itype != SJUMP;
}
static void disassemble_one(int i, u_int src)
else
dop = &dops[t];
}
- if ((dop && is_ld_use_hazard(dops[i].rt1, dop))
+ if ((dop && is_ld_use_hazard(&dops[i], dop))
|| (!dop && Config.PreciseExceptions)) {
// jump target wants DS result - potential load delay effect
SysPrintf("load delay in DS @%08x (%08x)\n", start + i*4, start);
}
}
else if (i > 0 && dops[i-1].is_delay_load
- && is_ld_use_hazard(dops[i-1].rt1, &dops[i])
+ && is_ld_use_hazard(&dops[i-1], &dops[i])
&& (i < 2 || !dops[i-2].is_ujump)) {
SysPrintf("load delay @%08x (%08x)\n", start + i*4, start);
for (j = i - 1; j > 0 && dops[j-1].is_delay_load; j--)
hit = blocks_remove_matching_addrs(&blocks[block_i], base_offs, base_shift);
if (hit) {
do_clear_cache();
- #ifdef USE_MINI_HT
- memset(mini_ht, -1, sizeof(mini_ht));
- #endif
+ mini_ht_clear();
}
}
else
return 0;
}
- cycle_multiplier_active = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
- ? Config.cycle_multiplier_override : Config.cycle_multiplier;
+ cycle_multiplier_active = get_cycle_multiplier();
source = get_source_start(start, &pagelimit);
if (source == NULL) {
if (addr != hack_addr) {
- SysPrintf("Compile at bogus memory address: %08x\n", addr);
+ SysPrintf("Compile at bogus memory address: %08x, ra=%x\n",
+ addr, psxRegs.GPR.n.ra);
hack_addr = addr;
}
//abort();
void *instr_addr0_override = NULL;
int ds = 0;
- if (start == 0x80030000) {
- // nasty hack for the fastbios thing
- // override block entry to this code
+ if ((Config.HLE && start == 0x80000080) || start == 0x80030000) {
instr_addr0_override = out;
- emit_movimm(start,0);
- // abuse io address var as a flag that we
- // have already returned here once
- emit_readword(&address,1);
- emit_writeword(0,&pcaddr);
- emit_writeword(0,&address);
- emit_cmp(0,1);
+ emit_movimm(start, 0);
+ if (start == 0x80030000) {
+ // for BiosBootBypass() to work
+ // io address var abused as a "already been here" flag
+ emit_readword(&address, 1);
+ emit_writeword(0, &pcaddr);
+ emit_writeword(0, &address);
+ emit_cmp(0, 1);
+ }
+ else {
+ emit_readword(&psxRegs.cpuInRecursion, 1);
+ emit_writeword(0, &pcaddr);
+ emit_test(1, 1);
+ }
#ifdef __aarch64__
emit_jeq(out + 4*2);
emit_far_jump(new_dyna_leave);