From fa3e48428843617672c2e64f4bf02eb37c674c5e Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 18 Sep 2022 16:09:50 -0700 Subject: [PATCH] Fixed DIVS overflow flag, and issue with exception processing The signed division overflow was incorrect, and I tried a few bit-wise approaches, but using the signed 32-bit number to determine 16-bit overflow using greater than/less than work perfectly There was also a bug in exception handling where it would push values to the stack before setting the supervisor flag, but the push funcs use the supervisor flag to determine which stack pointer to use, so when an exception happened in user mode, it was pushing to USP when it should have pushed to SSP --- src/cpus/m68k/execute.rs | 47 ++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index 1301777..d2a0582 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -148,26 +148,27 @@ impl M68k { } pub fn setup_group0_exception(&mut self, number: u8) -> Result<(), Error> { + let sr = self.state.sr; let ins_word = self.decoder.instruction_word; let extra_code = self.state.request.get_type_code(); let fault_size = self.state.request.size.in_bytes(); let fault_address = self.state.request.address; + // Changes to the flags must happen after the previous value has been pushed to the stack + self.set_flag(Flags::Supervisor, true); + self.set_flag(Flags::Tracing, false); + let offset = (number as u16) << 2; if self.cputype >= M68kType::MC68010 { self.push_word(offset)?; } self.push_long(self.state.pc - fault_size)?; - self.push_word(self.state.sr)?; + self.push_word(sr)?; self.push_word(ins_word)?; self.push_long(fault_address)?; self.push_word((ins_word & 0xFFF0) | extra_code)?; - // Changes to the flags must happen after the previous value has been pushed to the stack - self.set_flag(Flags::Supervisor, true); - self.set_flag(Flags::Tracing, false); - let vector = self.state.vbr + offset as u32; let addr = self.port.read_beu32(vector as Address)?; self.set_pc(addr)?; @@ -178,13 +179,6 @@ impl M68k { pub fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), Error> { self.state.request.i_n_bit = true; - let offset = (number as u16) << 2; - if self.cputype >= M68kType::MC68010 { - self.push_word(offset)?; - } - self.push_long(self.state.pc)?; - self.push_word(self.state.sr)?; - // Changes to the flags must happen after the previous value has been pushed to the stack self.set_flag(Flags::Supervisor, true); self.set_flag(Flags::Tracing, false); @@ -192,6 +186,14 @@ impl M68k { self.state.sr = (self.state.sr & !(Flags::IntMask as u16)) | ((self.state.current_ipl as u16) << 8); } + let sr = self.state.sr; + let offset = (number as u16) << 2; + if self.cputype >= M68kType::MC68010 { + self.push_word(offset)?; + } + self.push_long(self.state.pc)?; + self.push_word(sr)?; + let vector = self.state.vbr + offset as u32; let addr = self.port.read_beu32(vector as Address)?; self.set_pc(addr)?; @@ -460,16 +462,29 @@ impl M68k { } let existing = get_value_sized(self.state.d_reg[dest as usize], Size::Long); - let (remainder, quotient) = match sign { + let (remainder, quotient, overflow) = match sign { Sign::Signed => { + let existing = existing as i32; let value = sign_extend_to_long(value, Size::Word) as i32; - ((existing as i32 % value) as u32, (existing as i32 / value) as u32) + let quotient = existing / value; + ( + (existing % value) as u32, + quotient as u32, + quotient > i16::MAX as i32 || quotient < i16::MIN as i32 + ) + }, + Sign::Unsigned => { + let quotient = existing / value; + ( + existing % value, + quotient, + (quotient & 0xFFFF0000) != 0 + ) }, - Sign::Unsigned => (existing % value, existing / value), }; // Only update the register if the quotient was large than a 16-bit number - if (quotient & 0xFFFF0000) != 0 { + if !overflow { self.set_compare_flags(quotient as u32, Size::Word, false, false); self.state.d_reg[dest as usize] = (remainder << 16) | (0xFFFF & quotient); } else {