Fixed m68k overflow flags (almost)

This commit is contained in:
transistor 2021-11-04 21:29:52 -07:00
parent 8ba506cc11
commit 7d2a4e4b44
2 changed files with 219 additions and 25 deletions

View File

@ -173,7 +173,9 @@ impl M68k {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_add_sized(existing, value, size);
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size));
let (_, overflow) = overflowing_add_signed_sized(existing, value, size);
self.set_compare_flags(result, size, carry, overflow);
self.set_flag(Flags::Extend, carry);
self.set_target_value(system, dest, result, size)?;
},
Instruction::ADDA(src, dest, size) => {
@ -326,13 +328,15 @@ impl M68k {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_sub_sized(existing, value, size);
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size));
let (_, overflow) = overflowing_add_signed_sized(existing, value, size);
self.set_compare_flags(result, size, carry, overflow);
},
Instruction::CMPA(src, reg, size) => {
let value = sign_extend_to_long(self.get_target_value(system, src, size)?, size) as u32;
let existing = *self.get_a_reg_mut(reg);
let (result, carry) = overflowing_sub_sized(existing, value, Size::Long);
self.set_compare_flags(result, Size::Long, carry, get_overflow(existing, value, result, Size::Long));
let (_, overflow) = overflowing_add_signed_sized(existing, value, size);
self.set_compare_flags(result, Size::Long, carry, overflow);
},
Instruction::DBcc(cond, reg, offset) => {
let condition_true = self.get_current_condition(cond);
@ -546,9 +550,10 @@ impl M68k {
//},
Instruction::NEG(target, size) => {
let original = self.get_target_value(system, target, size)?;
let (value, _) = (0 as u32).overflowing_sub(original);
self.set_target_value(system, target, value, size)?;
self.set_compare_flags(value, size, value != 0, get_overflow(0, original, value, size));
let (result, overflow) = overflowing_sub_signed_sized(0, original, size);
self.set_target_value(system, target, result, size)?;
self.set_compare_flags(result, size, result != 0, overflow);
self.set_flag(Flags::Extend, self.get_flag(Flags::Carry));
},
//Instruction::NEGX(Target, Size) => {
//},
@ -640,7 +645,9 @@ impl M68k {
let value = self.get_target_value(system, src, size)?;
let existing = self.get_target_value(system, dest, size)?;
let (result, carry) = overflowing_sub_sized(existing, value, size);
self.set_compare_flags(result, size, carry, get_overflow(existing, value, result, size));
let (_, overflow) = overflowing_add_signed_sized(existing, value, size);
self.set_compare_flags(result, size, carry, overflow);
self.set_flag(Flags::Extend, carry);
self.set_target_value(system, dest, result, size)?;
},
Instruction::SUBA(src, dest, size) => {
@ -1093,6 +1100,40 @@ fn overflowing_sub_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool
}
}
fn overflowing_add_signed_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) {
match size {
Size::Byte => {
let (result, overflow) = (operand1 as i8).overflowing_add(operand2 as i8);
(result as u32, overflow)
},
Size::Word => {
let (result, overflow) = (operand1 as i16).overflowing_add(operand2 as i16);
(result as u32, overflow)
},
Size::Long => {
let (result, overflow) = (operand1 as i32).overflowing_add(operand2 as i32);
(result as u32, overflow)
},
}
}
fn overflowing_sub_signed_sized(operand1: u32, operand2: u32, size: Size) -> (u32, bool) {
match size {
Size::Byte => {
let (result, overflow) = (operand1 as i8).overflowing_sub(operand2 as i8);
(result as u32, overflow)
},
Size::Word => {
let (result, overflow) = (operand1 as i16).overflowing_sub(operand2 as i16);
(result as u32, overflow)
},
Size::Long => {
let (result, overflow) = (operand1 as i32).overflowing_sub(operand2 as i32);
(result as u32, overflow)
},
}
}
fn shift_operation(value: u32, size: Size, dir: ShiftDirection, arithmetic: bool) -> (u32, bool) {
match dir {
ShiftDirection::Left => {
@ -1151,7 +1192,11 @@ fn get_overflow(operand1: u32, operand2: u32, result: u32, size: Size) -> bool {
let msb2 = get_msb(operand2, size);
let msb_res = get_msb(result, size);
msb1 && msb2 && !msb_res
(msb1 && msb2 && !msb_res) || (!msb1 && !msb2 && msb_res)
}
fn get_twos_complement(value: u32, size: Size) -> u32 {
get_value_sized(!value + 1, size)
}
fn get_msb(value: u32, size: Size) -> bool {

View File

@ -589,7 +589,68 @@ mod execute_tests {
}
#[test]
fn instruction_cmpi_equal() {
fn instruction_add_no_overflow() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x00;
cpu.decoder.instruction = Instruction::ADD(Target::Immediate(0x7f), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.d_reg[0] = 0x7f;
expected_state.sr = 0x2700;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_add_no_overflow_negative() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x01;
cpu.decoder.instruction = Instruction::ADD(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.d_reg[0] = 0x81;
expected_state.sr = 0x2708;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_add_overflow() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x01;
cpu.decoder.instruction = Instruction::ADD(Target::Immediate(0x7f), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.d_reg[0] = 0x80;
expected_state.sr = 0x270A;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_add_carry() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x80;
cpu.decoder.instruction = Instruction::ADD(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.d_reg[0] = 0x00;
expected_state.sr = 0x2717;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_equal() {
let (mut cpu, system) = init_test(M68kType::MC68010);
let value = 0x20;
@ -604,7 +665,7 @@ mod execute_tests {
}
#[test]
fn instruction_cmpi_greater() {
fn instruction_cmp_greater_than() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x20;
@ -617,6 +678,108 @@ mod execute_tests {
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_less_than() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x20;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2700;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_no_overflow() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x00;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x7f), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2709;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_no_overflow_2() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x00;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x8001), Target::DirectDReg(0), Size::Word);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2701;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_overflow() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x00;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x270B;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_overflow_2() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x01;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x8001), Target::DirectDReg(0), Size::Word);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x270B;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_no_carry() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0xFF;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x01), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2708;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_cmp_carry() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x01;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0xFF), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2701;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_blt() {
let (mut cpu, system) = init_test(M68kType::MC68010);
@ -650,20 +813,6 @@ mod execute_tests {
}
#[test]
fn instruction_cmpi_less() {
let (mut cpu, system) = init_test(M68kType::MC68010);
cpu.state.d_reg[0] = 0x20;
cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2700;
cpu.execute_current(&system).unwrap();
assert_eq!(cpu.state, expected_state);
}
#[test]
fn instruction_andi_sr() {
let (mut cpu, system) = init_test(M68kType::MC68010);
@ -855,7 +1004,7 @@ mod execute_tests {
cpu.decoder.instruction = Instruction::NEG(Target::DirectDReg(0), Size::Word);
let mut expected_state = cpu.state.clone();
expected_state.sr = 0x2709;
expected_state.sr = 0x2719;
expected_state.d_reg[0] = 0x0000FF80;
cpu.execute_current(&system).unwrap();