summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Guillen Fandos2021-03-16 22:57:45 +0100
committerDavid Guillen Fandos2021-03-16 22:58:58 +0100
commit34e672ed25f96c3558534ac24523103f3711e58a (patch)
treef9adf1475cbaa9621bb22eb02c7452a3b6c62922
parent6b503667ec074c55dbcd689595d8fe03aa17e4a4 (diff)
downloadpicogpsp-34e672ed25f96c3558534ac24523103f3711e58a.tar.gz
picogpsp-34e672ed25f96c3558534ac24523103f3711e58a.tar.bz2
picogpsp-34e672ed25f96c3558534ac24523103f3711e58a.zip
Simplify open load handling for MIPS and fix other arches
Also rewrite a bit memory handlers for smaller functions.
-rw-r--r--arm/arm_emit.h2
-rw-r--r--gba_memory.c37
-rw-r--r--gba_memory.h2
-rw-r--r--psp/mips_emit.h128
-rw-r--r--x86/x86_emit.h2
5 files changed, 63 insertions, 108 deletions
diff --git a/arm/arm_emit.h b/arm/arm_emit.h
index 669d422..a5dc930 100644
--- a/arm/arm_emit.h
+++ b/arm/arm_emit.h
@@ -1933,4 +1933,6 @@ void execute_swi_hle_div_c(void)
generate_update_pc(pc); \
generate_indirect_branch_no_cycle_update(type) \
+void init_emitter(void) {}
+
#endif
diff --git a/gba_memory.c b/gba_memory.c
index a01bac5..c59aab1 100644
--- a/gba_memory.c
+++ b/gba_memory.c
@@ -1969,6 +1969,10 @@ u8 function_cc read_memory8(u32 address)
return value;
}
+u32 read_memory8s(u32 address) {
+ return (u32)((s8)read_memory8(address));
+}
+
u16 function_cc read_memory16_signed(u32 address)
{
u16 value;
@@ -1981,22 +1985,21 @@ u16 function_cc read_memory16_signed(u32 address)
return value;
}
+u32 read_memory16s(u32 address) {
+ return (u32)((s16)read_memory16_signed(address));
+}
+
// unaligned reads are actually 32bit
u32 function_cc read_memory16(u32 address)
{
u32 value;
-
- if(address & 0x01)
- {
- address &= ~0x01;
- read_memory(16);
+ bool unaligned = (address & 0x01);
+ address &= ~0x01;
+ read_memory(16);
+ if (unaligned) {
ror(value, value, 8);
}
- else
- {
- read_memory(16);
- }
return value;
}
@@ -2005,18 +2008,10 @@ u32 function_cc read_memory16(u32 address)
u32 function_cc read_memory32(u32 address)
{
u32 value;
- if(address & 0x03)
- {
- u32 rotate = (address & 0x03) * 8;
- address &= ~0x03;
- read_memory(32);
- ror(value, value, rotate);
- }
- else
- {
- read_memory(32);
- }
-
+ u32 rotate = (address & 0x03) * 8;
+ address &= ~0x03;
+ read_memory(32);
+ ror(value, value, rotate);
return value;
}
diff --git a/gba_memory.h b/gba_memory.h
index 1b332ed..07d5fd0 100644
--- a/gba_memory.h
+++ b/gba_memory.h
@@ -157,8 +157,10 @@ typedef enum
} flash_manufacturer_id_type;
u8 function_cc read_memory8(u32 address);
+u32 read_memory8s(u32 address);
u32 function_cc read_memory16(u32 address);
u16 function_cc read_memory16_signed(u32 address);
+u32 read_memory16s(u32 address);
u32 function_cc read_memory32(u32 address);
cpu_alert_type function_cc write_memory8(u32 address, u8 value);
cpu_alert_type function_cc write_memory16(u32 address, u16 value);
diff --git a/psp/mips_emit.h b/psp/mips_emit.h
index 506c440..8d1d8d8 100644
--- a/psp/mips_emit.h
+++ b/psp/mips_emit.h
@@ -2608,6 +2608,7 @@ void write_io_epilogue();
// This is a pointer table to the open load stubs, used by the BIOS (optimization)
u32* openld_core_ptrs[11];
+const u8 ldopmap[6][2] = { {0, 1}, {1, 2}, {2, 4}, {4, 6}, {6, 10}, {10, 11} };
const u8 ldhldrtbl[11] = {0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5};
#define ld_phndlr_branch(memop) \
(((u32*)&stub_arena[ldhldrtbl[(memop)] * 16]) - ((u32*)translation_ptr + 1))
@@ -2732,14 +2733,13 @@ static void emit_pmemld_stub(
if (region == 0) {
// BIOS is *not* mirrored, check that
mips_emit_srl(reg_rv, reg_a0, 14);
- unsigned joff = (openld_core_ptrs[memop_number] - ((u32*)translation_ptr + 1));
- mips_emit_b(bne, reg_zero, reg_rv, joff); // Jumps to read open
-
- // Check whether the read is allowed. Only within BIOS!
- // TODO: FIX THIS! This should be a protected read, not an open one!
- mips_emit_srl(reg_temp, reg_a1, 14);
- unsigned jof2 = (openld_core_ptrs[memop_number] - ((u32*)translation_ptr + 1));
- mips_emit_b(bne, reg_zero, reg_temp, jof2);
+ mips_emit_b(bne, reg_zero, reg_rv, branch_offset(openld_core_ptrs[memop_number]));
+
+ // Check whether the read is allowed. Only within BIOS! (Ignore aligned, bad a1)
+ if (!aligned) {
+ mips_emit_srl(reg_temp, reg_a1, 14);
+ mips_emit_b(bne, reg_zero, reg_temp, branch_offset(openld_core_ptrs[memop_number]));
+ }
}
if (region >= 8 && region <= 12) {
@@ -3029,7 +3029,6 @@ static void emit_ignorestore_stub(unsigned size, u8 **tr_ptr) {
static void emit_saveaccess_stub(u8 **tr_ptr) {
unsigned opt, i, strop;
u8 *translation_ptr = *tr_ptr;
- const u8 opmap[6][2] = { {0, 1}, {1, 2}, {2, 4}, {4, 6}, {6, 10}, {10, 11} };
// Writes to region 8 are directed to RTC (only 16 bit ones though)
tmemld[1][8] = (u32)translation_ptr;
@@ -3045,7 +3044,7 @@ static void emit_saveaccess_stub(u8 **tr_ptr) {
// Map loads to the read handler.
for (opt = 0; opt < 6; opt++) {
// Unalignment is not relevant here, so map them all to the same handler.
- for (i = opmap[opt][0]; i < opmap[opt][1]; i++)
+ for (i = ldopmap[opt][0]; i < ldopmap[opt][1]; i++)
tmemld[i][13] = (u32)translation_ptr;
// Emit just a check + patch jump
mips_emit_srl(reg_temp, reg_a0, 24);
@@ -3112,87 +3111,47 @@ static void emit_saveaccess_stub(u8 **tr_ptr) {
*tr_ptr = translation_ptr;
}
-// Emits openload store memory region stub
-static void emit_openload_stub(
- unsigned memopn, bool signext, unsigned size,
- unsigned alignment, bool aligned, u8 **tr_ptr
-) {
- u8 *jmp1, *jmp2;
+// Emits openload stub
+// These are used for reading unmapped regions, we just make them go
+// through the slow handler since should rarely happen.
+static void emit_openload_stub(unsigned opt, bool signext, unsigned size, u8 **tr_ptr) {
+ int i;
+ const u32 hndreadtbl[] = {
+ (u32)&read_memory8, (u32)&read_memory16, (u32)&read_memory32,
+ (u32)&read_memory8s, (u32)&read_memory16s, (u32)&read_memory32 };
u8 *translation_ptr = *tr_ptr;
// This affects regions 1 and 15
- tmemld[memopn][ 1] = (u32)translation_ptr;
- tmemld[memopn][15] = (u32)translation_ptr;
+ for (i = ldopmap[opt][0]; i < ldopmap[opt][1]; i++)
+ tmemld[i][ 1] = tmemld[i][15] = (u32)translation_ptr;
- // We need to repatch if: alignment is different or
- // if we are accessing a non-ignore region (1 and 15)
+ // Alignment is ignored since the handlers do the magic for us
+ // Only check region match: if we are accessing a non-ignore region
mips_emit_srl(reg_temp, reg_a0, 24);
mips_emit_sltiu(reg_rv, reg_temp, 0x0F);
mips_emit_addiu(reg_temp, reg_temp, -1);
mips_emit_sltu(reg_temp, reg_zero, reg_temp);
mips_emit_and(reg_temp, reg_temp, reg_rv);
- if (!aligned && size != 0) {
- // Also check and aggregate alignment
- mips_emit_ext(reg_rv, reg_a0, 0, size);
- mips_emit_xori(reg_rv, reg_rv, alignment);
- mips_emit_or(reg_temp, reg_rv, reg_temp);
- }
-
// Jump to patch handler
- mips_emit_b(bne, reg_zero, reg_temp, ld_phndlr_branch(memopn));
+ mips_emit_b(bne, reg_zero, reg_temp, branch_handlerid(opt));
// BIOS can jump here to do open loads
- openld_core_ptrs[memopn] = (u32*)translation_ptr;
-
- // Proceed with open load by reading data at PC (previous data in the bus)
- mips_emit_lw(reg_rv, reg_base, ReOff_CPSR); // Read CPSR
- mips_emit_andi(reg_rv, reg_rv, 0x20); // Check T bit
-
- emit_save_regs(aligned);
- mips_emit_sw(mips_reg_ra, reg_base, ReOff_SaveR1);
-
- switch (size) {
- case 0:
- mips_emit_andi(reg_a0, reg_a0, 0x3); // ARM: Isolate two LSB
- mips_emit_andi(reg_temp, reg_a0, 0x1); // Thb: Isolate one LSB
- mips_emit_movn(reg_a0, reg_temp, reg_rv); // Pick thumb or ARM
- genccall(&read_memory8);
- mips_emit_addu(reg_a0, reg_a0, reg_a1); // Add low bits to addr (delay)
- break;
- case 1:
- mips_emit_andi(reg_a0, reg_a0, 0x2); // ARM: Isolate bit 1
- mips_emit_movn(reg_a0, reg_zero, reg_rv); // Thumb: ignore all low bits
- genccall(&read_memory16);
- mips_emit_addu(reg_a0, reg_a0, reg_a1); // Add low bits to addr (delay)
- break;
- default:
- mips_emit_b_filler(beq, reg_zero, reg_rv, jmp1);
- mips_emit_addu(reg_a0, reg_zero, reg_a1); // Move PC to arg0
-
- genccall(&read_memory16);
- mips_emit_nop();
- mips_emit_b_filler(beq, reg_zero, reg_zero, jmp2);
- mips_emit_ins(reg_rv, reg_rv, 16, 16); // res = res | (res << 16) [delay]
-
- generate_branch_patch_conditional(jmp1, translation_ptr);
- genccall(&read_memory32);
+ for (i = ldopmap[opt][0]; i < ldopmap[opt][1]; i++)
+ openld_core_ptrs[i] = (u32*)translation_ptr;
+
+ emit_save_regs(true);
+ mips_emit_sw(mips_reg_ra, reg_base, ReOff_SaveR1); // Delay slot
+ genccall(hndreadtbl[size + (signext ? 3 : 0)]);
+ if (opt < 5) {
+ mips_emit_sw(reg_a1, reg_base, ReOff_RegPC); // Save current PC
+ } else {
+ // Aligned loads do not hold PC in a1 (imprecision)
mips_emit_nop();
- generate_branch_patch_conditional(jmp2, translation_ptr);
- break;
- };
-
- mips_emit_lw(mips_reg_ra, reg_base, ReOff_SaveR1);
- emit_restore_regs(aligned);
-
- // Same behaviour as reading from region14 really (8 bit bus)
- if (!size && signext) {
- mips_emit_seb(reg_rv, reg_rv);
- } else if (size == 1 && alignment) {
- mips_emit_seb(reg_rv, reg_rv);
- } else if (size == 2) {
- mips_emit_rotr(reg_rv, reg_rv, 8 * alignment);
}
+
+ mips_emit_lw(mips_reg_ra, reg_base, ReOff_SaveR1);
+ emit_restore_regs(true);
generate_function_return_swap_delay();
*tr_ptr = translation_ptr;
@@ -3295,17 +3254,12 @@ void init_emitter() {
mips_emit_nop();
// Generate the openload handlers (for accesses to unmapped mem)
- emit_openload_stub(0, false, 0, 0, false, &translation_ptr); // ld u8
- emit_openload_stub(1, true, 0, 0, false, &translation_ptr); // ld s8
- emit_openload_stub(2, false, 1, 0, false, &translation_ptr); // ld u16
- emit_openload_stub(3, false, 1, 1, false, &translation_ptr); // ld u16u1
- emit_openload_stub(4, true, 1, 0, false, &translation_ptr); // ld s16
- emit_openload_stub(5, true, 1, 1, false, &translation_ptr); // ld s16u1
- emit_openload_stub(6, false, 2, 0, false, &translation_ptr); // ld u32
- emit_openload_stub(7, false, 2, 1, false, &translation_ptr); // ld u32u1
- emit_openload_stub(8, false, 2, 2, false, &translation_ptr); // ld u32u2
- emit_openload_stub(9, false, 2, 3, false, &translation_ptr); // ld u32u3
- emit_openload_stub(10,false, 2, 0, true, &translation_ptr); // ld aligned 32
+ emit_openload_stub(0, false, 0, &translation_ptr); // ld u8
+ emit_openload_stub(1, true, 0, &translation_ptr); // ld s8
+ emit_openload_stub(2, false, 1, &translation_ptr); // ld u16
+ emit_openload_stub(3, true, 1, &translation_ptr); // ld s16
+ emit_openload_stub(4, false, 2, &translation_ptr); // ld u32
+ emit_openload_stub(5, false, 2, &translation_ptr); // ld a32
// Here we emit the ignore store area, just checks and does nothing
for (i = 0; i < 4; i++)
diff --git a/x86/x86_emit.h b/x86/x86_emit.h
index 4839618..67a3dc2 100644
--- a/x86/x86_emit.h
+++ b/x86/x86_emit.h
@@ -2299,4 +2299,6 @@ void function_cc swi_hle_div(void)
generate_update_pc(pc); \
generate_indirect_branch_no_cycle_update(type) \
+void init_emitter(void) {}
+
#endif