From 904eaa2fa765f795e72d739eee1a086e25c0f129 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Tue, 21 Nov 2023 23:35:07 +0100 Subject: [PATCH] [dynarec] "Fix" ARM-mode STM instruction writeback Move writeback to the end of the instruction (instead of the start). This is also wrong but fixes some common cases (ie. push sp). --- arm/arm64_emit.h | 14 ++++++++------ arm/arm_emit.h | 27 +++++++++++++++------------ mips/mips_emit.h | 20 ++++++++++++-------- x86/x86_emit.h | 29 ++++++++++++++++------------- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/arm/arm64_emit.h b/arm/arm64_emit.h index 2728865..86910e6 100644 --- a/arm/arm64_emit.h +++ b/arm/arm64_emit.h @@ -1379,12 +1379,13 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address, u32 store_mask) generate_load_reg_pc(reg_a1, i, 8); \ generate_function_call(execute_aligned_store32) \ -#define arm_block_memory_final_load() \ +#define arm_block_memory_final_load(writeback_type) \ arm_block_memory_load() \ -#define arm_block_memory_final_store() \ +#define arm_block_memory_final_store(writeback_type) \ generate_load_pc(reg_a2, (pc + 4)); \ generate_load_reg(reg_a1, i) \ + arm_block_memory_writeback_post_store(writeback_type); \ generate_function_call(execute_store_u32); \ #define arm_block_memory_adjust_pc_store() \ @@ -1417,13 +1418,14 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address, u32 store_mask) // Only emit writeback if the register is not in the list -#define arm_block_memory_writeback_load(writeback_type) \ +#define arm_block_memory_writeback_pre_load(writeback_type) \ if(!((reg_list >> rn) & 0x01)) \ { \ arm_block_memory_writeback_##writeback_type(); \ } \ -#define arm_block_memory_writeback_store(writeback_type) \ +#define arm_block_memory_writeback_pre_store(writeback_type) +#define arm_block_memory_writeback_post_store(writeback_type) \ arm_block_memory_writeback_##writeback_type() \ #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ @@ -1434,7 +1436,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address, u32 store_mask) u32 base_reg = arm_to_a64_reg[rn]; \ \ arm_block_memory_offset_##offset_type(); \ - arm_block_memory_writeback_##access_type(writeback_type); \ + arm_block_memory_writeback_pre_##access_type(writeback_type); \ \ { \ aa64_emit_andi(reg_save0, reg_save0, 30, 29); /* clear 2 LSB */ \ @@ -1452,7 +1454,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address, u32 store_mask) } \ else \ { \ - arm_block_memory_final_##access_type(); \ + arm_block_memory_final_##access_type(writeback_type); \ break; \ } \ } \ diff --git a/arm/arm_emit.h b/arm/arm_emit.h index ab242d0..b1fadbe 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -1485,11 +1485,12 @@ static void trace_instruction(u32 pc, u32 mode) arm_generate_load_reg_pc(reg_a1, i, 8); \ generate_store_call_u32_safe() \ -#define arm_block_memory_final_load() \ +#define arm_block_memory_final_load(writeback_type) \ arm_block_memory_load() \ -#define arm_block_memory_final_store() \ +#define arm_block_memory_final_store(writeback_type) \ arm_generate_load_reg_pc(reg_a1, i, 12); \ + arm_block_memory_writeback_post_store(writeback_type); \ generate_store_call_u32(); \ write32((pc + 4)) \ @@ -1513,28 +1514,30 @@ static void trace_instruction(u32 pc, u32 mode) generate_add_imm(reg_s0, 4, 0) \ #define arm_block_memory_writeback_down() \ - arm_generate_load_reg(reg_a0, rn); \ - generate_sub_imm(reg_a0, (word_bit_count(reg_list) * 4), 0); \ - arm_generate_store_reg(reg_a0, rn) \ + arm_generate_load_reg(reg_a2, rn); \ + generate_sub_imm(reg_a2, (word_bit_count(reg_list) * 4), 0); \ + arm_generate_store_reg(reg_a2, rn) \ #define arm_block_memory_writeback_up() \ - arm_generate_load_reg(reg_a0, rn); \ - generate_add_imm(reg_a0, (word_bit_count(reg_list) * 4), 0); \ - arm_generate_store_reg(reg_a0, rn) \ + arm_generate_load_reg(reg_a2, rn); \ + generate_add_imm(reg_a2, (word_bit_count(reg_list) * 4), 0); \ + arm_generate_store_reg(reg_a2, rn) \ #define arm_block_memory_writeback_no() /* Only emit writeback if the register is not in the list */ -#define arm_block_memory_writeback_load(writeback_type) \ +#define arm_block_memory_writeback_pre_load(writeback_type) \ if(!((reg_list >> rn) & 0x01)) \ { \ arm_block_memory_writeback_##writeback_type(); \ } \ -#define arm_block_memory_writeback_store(writeback_type) \ +#define arm_block_memory_writeback_post_store(writeback_type) \ arm_block_memory_writeback_##writeback_type() \ +#define arm_block_memory_writeback_pre_store(writeback_type) + #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ { \ arm_decode_block_trans(); \ @@ -1543,7 +1546,7 @@ static void trace_instruction(u32 pc, u32 mode) \ arm_generate_load_reg(reg_s0, rn); \ arm_block_memory_offset_##offset_type(); \ - arm_block_memory_writeback_##access_type(writeback_type); \ + arm_block_memory_writeback_pre_##access_type(writeback_type); \ ARM_BIC_REG_IMM(0, reg_s0, reg_s0, 0x03, 0); \ arm_generate_store_reg(reg_s0, REG_SAVE); \ \ @@ -1561,7 +1564,7 @@ static void trace_instruction(u32 pc, u32 mode) } \ else \ { \ - arm_block_memory_final_##access_type(); \ + arm_block_memory_final_##access_type(writeback_type); \ break; \ } \ } \ diff --git a/mips/mips_emit.h b/mips/mips_emit.h index 68c1638..2500aed 100644 --- a/mips/mips_emit.h +++ b/mips/mips_emit.h @@ -1309,13 +1309,14 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address) generate_load_reg_pc(reg_a1, i, 8); \ generate_function_call_swap_delay(execute_aligned_store32) \ -#define arm_block_memory_final_load() \ +#define arm_block_memory_final_load(writeback_type) \ arm_block_memory_load() \ -#define arm_block_memory_final_store() \ +#define arm_block_memory_final_store(writeback_type) \ generate_load_pc(reg_a2, (pc + 4)); \ - mips_emit_jal(mips_absolute_offset(execute_store_u32)); \ - generate_load_reg(reg_a1, i) \ + generate_load_reg(reg_a1, i); \ + arm_block_memory_writeback_post_store(writeback_type); \ + generate_function_call_swap_delay(execute_store_u32); \ #define arm_block_memory_adjust_pc_store() \ @@ -1366,13 +1367,15 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address) // Only emit writeback if the register is not in the list -#define arm_block_memory_writeback_load(writeback_type) \ +#define arm_block_memory_writeback_post_load(writeback_type) +#define arm_block_memory_writeback_pre_load(writeback_type) \ if(!((reg_list >> rn) & 0x01)) \ { \ arm_block_memory_writeback_##writeback_type(); \ } \ -#define arm_block_memory_writeback_store(writeback_type) \ +#define arm_block_memory_writeback_pre_store(writeback_type) +#define arm_block_memory_writeback_post_store(writeback_type) \ arm_block_memory_writeback_##writeback_type() \ #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ @@ -1383,7 +1386,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address) u32 base_reg = arm_to_mips_reg[rn]; \ \ arm_block_memory_offset_##offset_type(); \ - arm_block_memory_writeback_##access_type(writeback_type); \ + arm_block_memory_writeback_pre_##access_type(writeback_type); \ \ if(rn == REG_SP) \ { \ @@ -1409,6 +1412,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address) } \ } \ \ + arm_block_memory_writeback_post_##access_type(writeback_type); \ arm_block_memory_sp_adjust_pc_##access_type(); \ } \ else \ @@ -1428,7 +1432,7 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 address) } \ else \ { \ - arm_block_memory_final_##access_type(); \ + arm_block_memory_final_##access_type(writeback_type); \ break; \ } \ } \ diff --git a/x86/x86_emit.h b/x86/x86_emit.h index ebe4b28..dd63597 100644 --- a/x86/x86_emit.h +++ b/x86/x86_emit.h @@ -1504,11 +1504,12 @@ u32 execute_store_cpsr_body() generate_load_reg_pc(a1, i, 8); \ generate_function_call(execute_store_aligned_u32) \ -#define arm_block_memory_final_load() \ +#define arm_block_memory_final_load(writeback_type) \ arm_block_memory_load() \ -#define arm_block_memory_final_store() \ +#define arm_block_memory_final_store(writeback_type) \ generate_load_reg_pc(a1, i, 12); \ + arm_block_memory_writeback_post_store(writeback_type); \ generate_store_reg_i32(pc + 4, REG_PC); \ generate_function_call(execute_store_u32) \ @@ -1532,26 +1533,28 @@ u32 execute_store_cpsr_body() generate_add_imm(a0, 4) \ #define arm_block_memory_writeback_down() \ - generate_load_reg(a0, rn) \ - generate_add_imm(a0, -(word_bit_count(reg_list) * 4)); \ - generate_store_reg(a0, rn) \ + generate_load_reg(a2, rn) \ + generate_add_imm(a2, -(word_bit_count(reg_list) * 4)); \ + generate_store_reg(a2, rn) \ #define arm_block_memory_writeback_up() \ - generate_load_reg(a0, rn); \ - generate_add_imm(a0, (word_bit_count(reg_list) * 4)); \ - generate_store_reg(a0, rn) \ + generate_load_reg(a2, rn); \ + generate_add_imm(a2, (word_bit_count(reg_list) * 4)); \ + generate_store_reg(a2, rn) \ #define arm_block_memory_writeback_no() // Only emit writeback if the register is not in the list -#define arm_block_memory_writeback_load(writeback_type) \ +#define arm_block_memory_writeback_pre_load(writeback_type) \ if(!((reg_list >> rn) & 0x01)) \ { \ arm_block_memory_writeback_##writeback_type(); \ } \ -#define arm_block_memory_writeback_store(writeback_type) \ +#define arm_block_memory_writeback_pre_store(writeback_type) \ + +#define arm_block_memory_writeback_post_store(writeback_type) \ arm_block_memory_writeback_##writeback_type() \ #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \ @@ -1564,14 +1567,14 @@ u32 execute_store_cpsr_body() arm_block_memory_offset_##offset_type(); \ generate_and_imm(a0, ~0x03); \ generate_store_reg(a0, REG_SAVE3); \ - arm_block_memory_writeback_##access_type(writeback_type); \ + arm_block_memory_writeback_pre_##access_type(writeback_type); \ \ for(i = 0; i < 16; i++) \ { \ if((reg_list >> i) & 0x01) \ { \ cycle_count++; \ - generate_load_reg(a0, REG_SAVE3); \ + generate_load_reg(a0, REG_SAVE3); \ generate_add_imm(a0, offset) \ if(reg_list & ~((2 << i) - 1)) \ { \ @@ -1580,7 +1583,7 @@ u32 execute_store_cpsr_body() } \ else \ { \ - arm_block_memory_final_##access_type(); \ + arm_block_memory_final_##access_type(writeback_type); \ } \ } \ } \