mirror of
https://github.com/transistorfet/moa.git
synced 2025-01-11 05:29:42 +00:00
Fixed m68k overflow flags (almost)
This commit is contained in:
parent
8ba506cc11
commit
7d2a4e4b44
@ -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 {
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user