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
This commit is contained in:
transistor 2022-09-18 16:09:50 -07:00
parent bbd15abb76
commit fa3e484288

View File

@ -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 {