Le 17/05/2026 à 21:17, Kuan-Wei Chiu a écrit :
Executing fmovem.l fpstate, %fpcr/%fpsr results in incorrect values being loaded into the fpu control registers.When fpu control registers are moved to/from memory, they must follow a strict order regardless of the addressing mode: FPCR is always at the lowest address, FPSR at the next, and FPIAR at the highest address. The current implementation in gen_op_fmove_fcr() processes the bitmask incorrectly and uses the wrong loop direction for pre-decrement mode, mapping the registers to the wrong memory addresses. Fix this by correcting the loop iteration order and mask checking to follow the architectural memory layout. Fixes: ba62494483ab ("target-m68k: add FPCR and FPSR") Reported-by: Andreas Schwab <[email protected]> Closes: https://lore.kernel.org/qemu-devel/[email protected] Signed-off-by: Kuan-Wei Chiu <[email protected]>
Reviewed-by: Laurent Vivier <[email protected]>
--- target/m68k/translate.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 138c89d3e5..8d8531b1ad 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4837,24 +4837,26 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s, */if (is_write && mode == 4) {- for (i = 2; i >= 0; i--, mask >>= 1) { - if (mask & 1) { + for (i = 0; i < 3; i++) { + if (mask & (1 << i)) { gen_qemu_store_fcr(s, addr, 1 << i); - if (mask != 1) { + mask &= ~(1 << i); + if (mask != 0) { tcg_gen_subi_i32(addr, addr, opsize_bytes(OS_LONG)); } } } tcg_gen_mov_i32(AREG(insn, 0), addr); } else { - for (i = 0; i < 3; i++, mask >>= 1) { - if (mask & 1) { + for (i = 2; i >= 0; i--) { + if (mask & (1 << i)) { if (is_write) { gen_qemu_store_fcr(s, addr, 1 << i); } else { gen_qemu_load_fcr(s, addr, 1 << i); } - if (mask != 1 || mode == 3) { + mask &= ~(1 << i); + if (mask != 0 || mode == 3) { tcg_gen_addi_i32(addr, addr, opsize_bytes(OS_LONG)); } }
