aboutsummaryrefslogtreecommitdiff
path: root/libpcsxcore/new_dynarec
diff options
context:
space:
mode:
Diffstat (limited to 'libpcsxcore/new_dynarec')
-rw-r--r--libpcsxcore/new_dynarec/assem_arm.c144
-rw-r--r--libpcsxcore/new_dynarec/emu_if.c35
-rw-r--r--libpcsxcore/new_dynarec/emu_if.h26
-rw-r--r--libpcsxcore/new_dynarec/linkage_arm.s10
-rw-r--r--libpcsxcore/new_dynarec/new_dynarec.c5
-rw-r--r--libpcsxcore/new_dynarec/pcsxmem.c4
-rw-r--r--libpcsxcore/new_dynarec/pcsxmem.h2
7 files changed, 160 insertions, 66 deletions
diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c
index 29ad13f..d0d43f4 100644
--- a/libpcsxcore/new_dynarec/assem_arm.c
+++ b/libpcsxcore/new_dynarec/assem_arm.c
@@ -19,6 +19,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#ifdef PCSX
+#include "../gte_arm.h"
+#include "../gte_neon.h"
+#include "pcnt.h"
+#endif
+
extern int cycle_count;
extern int last_count;
extern int pcaddr;
@@ -1924,6 +1930,16 @@ void emit_movzwl_indexed(int offset, int rs, int rt)
output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
}
}
+static void emit_ldrd(int offset, int rs, int rt)
+{
+ assert(offset>-256&&offset<256);
+ assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
+ if(offset>=0) {
+ output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf));
+ }else{
+ output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf));
+ }
+}
void emit_readword(int addr, int rt)
{
u_int offset = addr-(u_int)&dynarec_local;
@@ -2568,34 +2584,40 @@ void emit_jno_unlikely(int a)
output_w32(0x72800000|rd_rn_rm(15,15,0));
}
-// Save registers before function call
-void save_regs(u_int reglist)
+static void save_regs_all(u_int reglist)
{
- reglist&=0x100f; // only save the caller-save registers, r0-r3, r12
+ int i;
if(!reglist) return;
assem_debug("stmia fp,{");
- if(reglist&1) assem_debug("r0, ");
- if(reglist&2) assem_debug("r1, ");
- if(reglist&4) assem_debug("r2, ");
- if(reglist&8) assem_debug("r3, ");
- if(reglist&0x1000) assem_debug("r12");
+ for(i=0;i<16;i++)
+ if(reglist&(1<<i))
+ assem_debug("r%d,",i);
assem_debug("}\n");
output_w32(0xe88b0000|reglist);
}
-// Restore registers after function call
-void restore_regs(u_int reglist)
+static void restore_regs_all(u_int reglist)
{
- reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12
+ int i;
if(!reglist) return;
assem_debug("ldmia fp,{");
- if(reglist&1) assem_debug("r0, ");
- if(reglist&2) assem_debug("r1, ");
- if(reglist&4) assem_debug("r2, ");
- if(reglist&8) assem_debug("r3, ");
- if(reglist&0x1000) assem_debug("r12");
+ for(i=0;i<16;i++)
+ if(reglist&(1<<i))
+ assem_debug("r%d,",i);
assem_debug("}\n");
output_w32(0xe89b0000|reglist);
}
+// Save registers before function call
+static void save_regs(u_int reglist)
+{
+ reglist&=0x100f; // only save the caller-save registers, r0-r3, r12
+ save_regs_all(reglist);
+}
+// Restore registers after function call
+static void restore_regs(u_int reglist)
+{
+ reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12
+ restore_regs_all(reglist);
+}
// Write back consts using r14 so we don't disturb the other registers
void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i)
@@ -4385,36 +4407,96 @@ void cop2_assemble(int i,struct regstat *i_regs)
}
}
-void c2op_assemble(int i,struct regstat *i_regs)
+static void c2op_prologue(u_int op,u_int reglist)
+{
+ save_regs_all(reglist);
+ emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
+}
+
+static void c2op_epilogue(u_int op,u_int reglist)
+{
+ restore_regs_all(reglist);
+}
+
+static void c2op_assemble(int i,struct regstat *i_regs)
{
signed char temp=get_reg(i_regs->regmap,-1);
u_int c2op=source[i]&0x3f;
u_int hr,reglist=0;
- int need_flags;
+ int need_flags,need_ir;
for(hr=0;hr<HOST_REGS;hr++) {
if(i_regs->regmap[hr]>=0) reglist|=1<<hr;
}
- if(i==0||itype[i-1]!=C2OP)
- save_regs(reglist);
if (gte_handlers[c2op]!=NULL) {
- int cc=get_reg(i_regs->regmap,CCREG);
- emit_movimm(source[i],1); // opcode
- if (cc>=0&&gte_cycletab[c2op])
- emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: could just adjust ccadj?
- emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs
- emit_writeword(1,(int)&psxRegs.code);
need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works
- assem_debug("gte unneeded %016llx, need_flags %d\n",gte_unneeded[i+1],need_flags);
+ need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00;
+ assem_debug("gte unneeded %016llx, need_flags %d, need_ir %d\n",
+ gte_unneeded[i+1],need_flags,need_ir);
#ifdef ARMv5_ONLY
// let's take more risk here
need_flags=need_flags&&gte_reads_flags;
#endif
- emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]));
- }
+ switch(c2op) {
+ case GTE_MVMVA: {
+ int shift = (source[i] >> 19) & 1;
+ int v = (source[i] >> 15) & 3;
+ int cv = (source[i] >> 13) & 3;
+ int mx = (source[i] >> 17) & 3;
+ int lm = (source[i] >> 10) & 1;
+ reglist&=0x10ff; // +{r4-r7}
+ c2op_prologue(c2op,reglist);
+ /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */
+ if(v<3)
+ emit_ldrd(v*8,0,4);
+ else {
+ emit_movzwl_indexed(9*4,0,4); // gteIR
+ emit_movzwl_indexed(10*4,0,6);
+ emit_movzwl_indexed(11*4,0,5);
+ emit_orrshl_imm(6,16,4);
+ }
+ if(mx<3)
+ emit_addimm(0,32*4+mx*8*4,6);
+ else
+ emit_readword((int)&zeromem_ptr,6);
+ if(cv<3)
+ emit_addimm(0,32*4+(cv*8+5)*4,7);
+ else
+ emit_readword((int)&zeromem_ptr,7);
+#ifdef __ARM_NEON__
+ emit_movimm(source[i],1); // opcode
+ emit_call((int)gteMVMVA_part_neon);
+ if(need_flags) {
+ emit_movimm(lm,1);
+ emit_call((int)gteMACtoIR_flags_neon);
+ }
+#else
+ if(cv==3&&shift)
+ emit_call((int)gteMVMVA_part_cv3sh12_arm);
+ else {
+ emit_movimm(shift,1);
+ emit_call((int)(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm));
+ }
+ if(need_flags||need_ir) {
+ if(need_flags)
+ emit_call((int)(lm?gteMACtoIR_lm1:gteMACtoIR_lm0));
+ else
+ emit_call((int)(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf)); // lm0 borked
+ }
+#endif
+ break;
+ }
- if(i>=slen-1||itype[i+1]!=C2OP)
- restore_regs(reglist);
+ default:
+ reglist&=0x100f;
+ c2op_prologue(c2op,reglist);
+ emit_movimm(source[i],1); // opcode
+ emit_writeword(1,(int)&psxRegs.code);
+ emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op]));
+ break;
+ }
+ c2op_epilogue(c2op,reglist);
+ }
}
void cop1_unusable(int i,struct regstat *i_regs)
diff --git a/libpcsxcore/new_dynarec/emu_if.c b/libpcsxcore/new_dynarec/emu_if.c
index 92eb68f..485a7c8 100644
--- a/libpcsxcore/new_dynarec/emu_if.c
+++ b/libpcsxcore/new_dynarec/emu_if.c
@@ -177,31 +177,6 @@ const char gte_cycletab[64] = {
23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 39,
};
-enum gte_opcodes {
- GTE_RTPS = 0x01,
- GTE_NCLIP = 0x06,
- GTE_OP = 0x0c,
- GTE_DPCS = 0x10,
- GTE_INTPL = 0x11,
- GTE_MVMVA = 0x12,
- GTE_NCDS = 0x13,
- GTE_CDP = 0x14,
- GTE_NCDT = 0x16,
- GTE_NCCS = 0x1b,
- GTE_CC = 0x1c,
- GTE_NCS = 0x1e,
- GTE_NCT = 0x20,
- GTE_SQR = 0x28,
- GTE_DCPL = 0x29,
- GTE_DPCT = 0x2a,
- GTE_AVSZ3 = 0x2d,
- GTE_AVSZ4 = 0x2e,
- GTE_RTPT = 0x30,
- GTE_GPF = 0x3d,
- GTE_GPL = 0x3e,
- GTE_NCCT = 0x3f,
-};
-
#define GCBIT(x) \
(1ll << (32+x))
#define GDBIT(x) \
@@ -298,17 +273,17 @@ static int ari64_init()
gte_handlers_nf[0x30] = gteRTPT_nf_arm;
#endif
#ifdef __ARM_NEON__
- // compiler's _nf version is still a lot slower then neon
+ // compiler's _nf version is still a lot slower than neon
// _nf_arm RTPS is roughly the same, RTPT slower
gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
- gte_handlers[0x12] = gte_handlers_nf[0x12] = gteMVMVA_neon;
#endif
#endif
#ifdef DRC_DBG
memcpy(gte_handlers_nf, gte_handlers, sizeof(gte_handlers_nf));
#endif
psxH_ptr = psxH;
+ zeromem_ptr = zero_mem;
return 0;
}
@@ -399,14 +374,14 @@ void do_insn_cmp() {}
#endif
#if defined(__x86_64__) || defined(__i386__)
-unsigned int address, readmem_word, word;
-unsigned short hword;
-unsigned char byte;
+unsigned int address;
int pending_exception, stop;
unsigned int next_interupt;
int new_dynarec_did_compile;
int cycle_multiplier;
void *psxH_ptr;
+void *zeromem_ptr;
+u8 zero_mem[0x1000];
void new_dynarec_init() {}
void new_dyna_start() {}
void new_dynarec_cleanup() {}
diff --git a/libpcsxcore/new_dynarec/emu_if.h b/libpcsxcore/new_dynarec/emu_if.h
index 90e32e7..6b6305c 100644
--- a/libpcsxcore/new_dynarec/emu_if.h
+++ b/libpcsxcore/new_dynarec/emu_if.h
@@ -24,6 +24,31 @@ extern int reg_cop0[];
#define Count psxRegs.cycle // psxRegs.CP0.n.Count
/* COP2/GTE */
+enum gte_opcodes {
+ GTE_RTPS = 0x01,
+ GTE_NCLIP = 0x06,
+ GTE_OP = 0x0c,
+ GTE_DPCS = 0x10,
+ GTE_INTPL = 0x11,
+ GTE_MVMVA = 0x12,
+ GTE_NCDS = 0x13,
+ GTE_CDP = 0x14,
+ GTE_NCDT = 0x16,
+ GTE_NCCS = 0x1b,
+ GTE_CC = 0x1c,
+ GTE_NCS = 0x1e,
+ GTE_NCT = 0x20,
+ GTE_SQR = 0x28,
+ GTE_DCPL = 0x29,
+ GTE_DPCT = 0x2a,
+ GTE_AVSZ3 = 0x2d,
+ GTE_AVSZ4 = 0x2e,
+ GTE_RTPT = 0x30,
+ GTE_GPF = 0x3d,
+ GTE_GPL = 0x3e,
+ GTE_NCCT = 0x3f,
+};
+
extern int reg_cop2d[], reg_cop2c[];
extern void *gte_handlers[64];
extern void *gte_handlers_nf[64];
@@ -57,6 +82,7 @@ void rcnt2_read_count_m1(u32 addr, u32, u32 cycles);
extern unsigned int address;
extern void *psxH_ptr;
+extern void *zeromem_ptr;
// same as invalid_code, just a region for ram write checks (inclusive)
extern u32 inv_code_start, inv_code_end;
diff --git a/libpcsxcore/new_dynarec/linkage_arm.s b/libpcsxcore/new_dynarec/linkage_arm.s
index 19c9686..5c1adc9 100644
--- a/libpcsxcore/new_dynarec/linkage_arm.s
+++ b/libpcsxcore/new_dynarec/linkage_arm.s
@@ -49,6 +49,7 @@ rdram = 0x80000000
.global mem_rtab
.global mem_wtab
.global psxH_ptr
+ .global zeromem_ptr
.global inv_code_start
.global inv_code_end
.global rcnts
@@ -135,7 +136,10 @@ mem_wtab = mem_rtab + 4
psxH_ptr = mem_wtab + 4
.type psxH_ptr, %object
.size psxH_ptr, 4
-inv_code_start = psxH_ptr + 4
+zeromem_ptr = psxH_ptr + 4
+ .type zeromem_ptr, %object
+ .size zeromem_ptr, 4
+inv_code_start = zeromem_ptr + 4
.type inv_code_start, %object
.size inv_code_start, 4
inv_code_end = inv_code_start + 4
@@ -146,8 +150,8 @@ branch_target = inv_code_end + 4
.size branch_target, 4
align0 = branch_target + 4 /* unused/alignment */
.type align0, %object
- .size align0, 4
-mini_ht = align0 + 4
+ .size align0, 16
+mini_ht = align0 + 16
.type mini_ht, %object
.size mini_ht, 256
restore_candidate = mini_ht + 256
diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c
index ce77e00..e2c63ed 100644
--- a/libpcsxcore/new_dynarec/new_dynarec.c
+++ b/libpcsxcore/new_dynarec/new_dynarec.c
@@ -9736,6 +9736,11 @@ int new_recompile_block(int addr)
cc=0;
}
#ifdef PCSX
+ else if(itype[i]==C2OP&&gte_cycletab[source[i]&0x3f]>2)
+ {
+ // GTE runs in parallel until accessed, divide by 2 for a rough guess
+ cc+=gte_cycletab[source[i]&0x3f]/2;
+ }
else if(/*itype[i]==LOAD||*/itype[i]==STORE||itype[i]==C1LS) // load causes weird timing issues
{
cc+=2; // 2 cycle penalty (after CLOCK_DIVIDER)
diff --git a/libpcsxcore/new_dynarec/pcsxmem.c b/libpcsxcore/new_dynarec/pcsxmem.c
index 586c760..e56abb7 100644
--- a/libpcsxcore/new_dynarec/pcsxmem.c
+++ b/libpcsxcore/new_dynarec/pcsxmem.c
@@ -40,7 +40,7 @@ static void map_item(u32 *out, const void *h, u32 flag)
#define IOMEM16(a) (0x1000/4 + (((a) & 0xfff) / 2))
#define IOMEM8(a) (0x1000/4 + 0x1000/2 + ((a) & 0xfff))
-static u8 unmapped_mem[0x1000];
+u8 zero_mem[0x1000];
u32 read_mem_dummy()
{
@@ -290,7 +290,7 @@ void new_dyna_pcsx_mem_init(void)
// default/unmapped memhandlers
for (i = 0; i < 0x100000; i++) {
//map_item(&mem_readtab[i], mem_unmrtab, 1);
- map_l1_mem(mem_readtab, i, 0, 0x1000, unmapped_mem);
+ map_l1_mem(mem_readtab, i, 0, 0x1000, zero_mem);
map_item(&mem_writetab[i], mem_unmwtab, 1);
}
diff --git a/libpcsxcore/new_dynarec/pcsxmem.h b/libpcsxcore/new_dynarec/pcsxmem.h
index a3b08e1..f962562 100644
--- a/libpcsxcore/new_dynarec/pcsxmem.h
+++ b/libpcsxcore/new_dynarec/pcsxmem.h
@@ -1,4 +1,6 @@
+extern u8 zero_mem[0x1000];
+
void new_dyna_pcsx_mem_init(void);
void new_dyna_pcsx_mem_reset(void);
void new_dyna_pcsx_mem_load_state(void);