From aa86641e16ea705492a7d637156dea31886e644f Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Sat, 12 Apr 2025 23:03:08 -0400 Subject: [PATCH] fix(m68k): correct SR register read (#2161) The SR register in the `CPUM68KState` struct does not contain the value of the lower 5 flags. To compute them, we must OR the CCR values with the SR register to get the true SR value. --- bindings/rust/src/tests/m68k.rs | 19 +++++++++++++++++++ qemu/m68k.h | 1 + qemu/target/m68k/cpu.h | 1 + qemu/target/m68k/helper.c | 4 ++++ qemu/target/m68k/unicorn.c | 3 ++- symbols.sh | 1 + tests/unit/test_m68k.c | 27 ++++++++++++++++++++++++++- 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/bindings/rust/src/tests/m68k.rs b/bindings/rust/src/tests/m68k.rs index 1f8c31b0..4a7fcca0 100644 --- a/bindings/rust/src/tests/m68k.rs +++ b/bindings/rust/src/tests/m68k.rs @@ -20,3 +20,22 @@ fn test_move_to_sr() { let sr = uc.reg_read(RegisterM68K::SR).unwrap(); assert_eq!(sr, 0x2700); } + +#[test] +fn test_sr_contains_flags() { + let code = [ + 0x76, 0xed, // moveq #-19, %d3 + ]; + + let mut uc = uc_common_setup(Arch::M68K, Mode::BIG_ENDIAN, None, &code, ()); + + uc.emu_start(CODE_START, CODE_START + code.len() as u64, 0, 0) + .unwrap(); + + let d3 = uc.reg_read(RegisterM68K::D3).unwrap(); + assert_eq!(d3, 0xffffffed); + + let sr = uc.reg_read(RegisterM68K::SR).unwrap(); + let is_negative = sr & 0x8 == 0x8; + assert!(is_negative, "SR should contain negative flag"); +} diff --git a/qemu/m68k.h b/qemu/m68k.h index c4ac5306..bc21401e 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -1372,6 +1372,7 @@ #define helper_bitrev helper_bitrev_m68k #define helper_ff1 helper_ff1_m68k #define helper_sats helper_sats_m68k +#define cpu_m68k_get_sr cpu_m68k_get_sr_m68k #define cpu_m68k_set_sr cpu_m68k_set_sr_m68k #define helper_set_sr helper_set_sr_m68k #define helper_mac_move helper_mac_move_m68k diff --git a/qemu/target/m68k/cpu.h b/qemu/target/m68k/cpu.h index f137e9a5..263a3d07 100644 --- a/qemu/target/m68k/cpu.h +++ b/qemu/target/m68k/cpu.h @@ -183,6 +183,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); uint32_t cpu_m68k_get_ccr(CPUM68KState *env); void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); +uint32_t cpu_m68k_get_sr(CPUM68KState *env); void cpu_m68k_set_sr(CPUM68KState *env, uint32_t); void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); diff --git a/qemu/target/m68k/helper.c b/qemu/target/m68k/helper.c index b0f2e298..98463eb0 100644 --- a/qemu/target/m68k/helper.c +++ b/qemu/target/m68k/helper.c @@ -591,6 +591,10 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v) return val; } +uint32_t cpu_m68k_get_sr(CPUM68KState *env) { + return env->sr | cpu_m68k_get_ccr(env); +} + void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) { env->sr = sr & 0xffe0; diff --git a/qemu/target/m68k/unicorn.c b/qemu/target/m68k/unicorn.c index ab427f1f..42ef1ff5 100644 --- a/qemu/target/m68k/unicorn.c +++ b/qemu/target/m68k/unicorn.c @@ -72,7 +72,8 @@ uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, break; case UC_M68K_REG_SR: CHECK_REG_TYPE(uint32_t); - *(uint32_t *)value = env->sr; + env->cc_op = CC_OP_FLAGS; + *(uint32_t *)value = cpu_m68k_get_sr(env); break; case UC_M68K_REG_CR_SFC: CHECK_REG_TYPE(uint32_t); diff --git a/symbols.sh b/symbols.sh index ad7b8f09..b1f0064e 100755 --- a/symbols.sh +++ b/symbols.sh @@ -5749,6 +5749,7 @@ m68k_cpu_tlb_fill \ helper_bitrev \ helper_ff1 \ helper_sats \ +cpu_m68k_get_sr \ cpu_m68k_set_sr \ helper_set_sr \ helper_mac_move \ diff --git a/tests/unit/test_m68k.c b/tests/unit/test_m68k.c index 335caf2b..e298a8cd 100644 --- a/tests/unit/test_m68k.c +++ b/tests/unit/test_m68k.c @@ -37,4 +37,29 @@ static void test_move_to_sr(void) OK(uc_close(uc)); } -TEST_LIST = {{"test_move_to_sr", test_move_to_sr}, {NULL, NULL}}; +static void test_sr_contains_flags(void) +{ + uc_engine *uc; + uint8_t code[] = { + 0x76, 0xed, // moveq #-19, %d3 + }; + + uint32_t d3, sr; + + uc_common_setup(&uc, UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, code, sizeof(code), + UC_CPU_M68K_M68000); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code), 0, 0)); + + OK(uc_reg_read(uc, UC_M68K_REG_D3, &d3)); + OK(uc_reg_read(uc, UC_M68K_REG_SR, &sr)); + + TEST_CHECK(d3 == 0xFFFFFFED); + TEST_CHECK((sr & 0x8) /* N flag */ == 0x8); + + OK(uc_close(uc)); +} + +TEST_LIST = {{"test_move_to_sr", test_move_to_sr}, + {"test_sr_contains_flags", test_sr_contains_flags}, + {NULL, NULL}};