Fix ADC and SBC instructions and add test runner script (#5)

This commit is contained in:
2024-01-28 22:54:00 +00:00
committed by GitHub
parent 01b3493547
commit b9699e6276
20 changed files with 450 additions and 162 deletions
+38 -38
View File
@@ -6,6 +6,7 @@ use crate::cpu::bus::Bus;
#[derive(Copy, Clone)]
pub struct ResolveAddressParams {
pub pc_addr: u32,
pub dbr: u8,
pub direct_page_register: u16,
pub stack_pointer: u16,
pub x: u16,
@@ -19,15 +20,14 @@ pub fn immediate(pc_addr: u32) -> u32 {
}
/// OPCODE addr
pub fn absolute(bus: &mut Bus, pc_addr: u32) -> u32 {
(pc_addr & 0xFF0000) |
(bus.read(pc_addr + 1) as u32) |
((bus.read(pc_addr + 2) as u32) << 8)
pub fn absolute(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 {
let addr = (bus.read(pc_addr + 1) as u32) | ((bus.read(pc_addr + 2) as u32) << 8);
((dbr as u32) << 16) | addr
}
/// OPCODE (addr)
pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32) -> u32 {
let addr = absolute(bus, pc_addr);
pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 {
let addr = absolute(bus, pc_addr, dbr);
let dbr = pc_addr & 0xFF0000;
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
}
@@ -40,8 +40,8 @@ pub fn absolute_long(bus: &mut Bus, pc_addr: u32) -> u32 {
}
/// OPCODE (addr)
pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32) -> u32 {
let addr = absolute(bus, pc_addr);
pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 {
let addr = absolute(bus, pc_addr, dbr);
((bus.read(addr) as u32) << 16) |
((bus.read(addr + 1) as u32) << 8) |
(bus.read(addr + 2) as u32)
@@ -69,13 +69,13 @@ pub fn direct_page_indirect_long(bus: &mut Bus, pc_addr: u32, direct_page_regist
/// OPCODE addr,X
/// OPCODE addr,Y
pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 {
absolute(bus, pc_addr) + (xy as u32)
pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 {
absolute(bus, pc_addr, dbr) + (xy as u32)
}
/// OPCODE (addr)
pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 {
let addr = absolute_indexed(bus, pc_addr, xy);
pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 {
let addr = absolute_indexed(bus, pc_addr, xy, dbr);
let dbr = pc_addr & 0xFF0000;
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
}
@@ -112,14 +112,14 @@ pub fn direct_page_indirect_long_indexed(bus: &mut Bus, pc_addr: u32, direct_pag
}
/// OPCODE sr,S
pub fn stack_relative(bus: &mut Bus, pc_addr: u32, stack_pointer: u16) -> u32 {
absolute_indexed(bus, pc_addr, stack_pointer)
pub fn stack_relative(bus: &mut Bus, pc_addr: u32, stack_pointer: u16, dbr: u8) -> u32 {
absolute_indexed(bus, pc_addr, stack_pointer, dbr)
}
/// OPCODE (sr,S),X
/// OPCODE (sr,S),Y
pub fn stack_relative_indirect_indexed(bus: &mut Bus, pc_addr: u32, stack_pointer: u16, xy: u16) -> u32 {
absolute_indexed(bus, pc_addr, stack_pointer) + (xy as u32)
pub fn stack_relative_indirect_indexed(bus: &mut Bus, pc_addr: u32, stack_pointer: u16, xy: u16, dbr: u8) -> u32 {
absolute_indexed(bus, pc_addr, stack_pointer, dbr) + (xy as u32)
}
#[derive(Copy, Clone, PartialEq)]
@@ -167,22 +167,22 @@ impl AddressingMode {
match self {
Self::Accumulator => p.pc_addr,
Self::Immediate => immediate(p.pc_addr),
Self::Absolute => absolute(bus, p.pc_addr),
Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr),
Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr),
Self::Absolute => absolute(bus, p.pc_addr, p.dbr),
Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr, p.dbr),
Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr, p.dbr),
Self::AbsoluteLong => absolute_long(bus, p.pc_addr),
Self::DirectPage => direct_page(bus, p.pc_addr, p.direct_page_register),
Self::DirectPageIndirect => direct_page_indirect(bus, p.pc_addr, p.direct_page_register),
Self::DirectPageIndirectLong => direct_page_indirect_long(bus, p.pc_addr, p.direct_page_register),
Self::AbsoluteIndexed(idx) => absolute_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}),
Self::AbsoluteIndexedIndirect(idx) => absolute_indexed_indirect(bus, p.pc_addr, if idx == X {p.x} else {p.y}),
Self::AbsoluteIndexed(idx) => absolute_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.dbr),
Self::AbsoluteIndexedIndirect(idx) => absolute_indexed_indirect(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.dbr),
Self::AbsoluteLongIndexed(idx) => absolute_long_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}),
Self::DirectPageIndexed(idx) => direct_page_indexed(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}),
Self::DirectPageIndexedIndirect(idx) => direct_page_indexed_indirect(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}),
Self::DirectPageIndirectIndexed(idx) => direct_page_indirect_indexed(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}),
Self::DirectPageIndirectLongIndexed(idx) => direct_page_indirect_long_indexed(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}),
Self::StackRelative => stack_relative(bus, p.pc_addr, p.stack_pointer),
Self::StackRelativeIndirectIndexed(idx) => stack_relative_indirect_indexed(bus, p.pc_addr, p.stack_pointer, if idx == X {p.x} else {p.y}),
Self::StackRelative => stack_relative(bus, p.pc_addr, p.stack_pointer, p.dbr),
Self::StackRelativeIndirectIndexed(idx) => stack_relative_indirect_indexed(bus, p.pc_addr, p.stack_pointer, if idx == X {p.x} else {p.y}, p.dbr),
}
}
@@ -224,13 +224,13 @@ mod addressing_modes_tests {
let pc_addr = 0x000000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(absolute(&mut bus, pc_addr), 0x000201);
assert_eq!(absolute(&mut bus, pc_addr, 0x00), 0x000201);
let mut bus = Bus::new();
let pc_addr = 0x7F0000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(absolute(&mut bus, pc_addr), 0x7F0201);
assert_eq!(absolute(&mut bus, pc_addr, 0x7F), 0x7F0201);
}
#[test]
@@ -241,21 +241,21 @@ mod addressing_modes_tests {
bus.write(pc_addr + 1, addr);
bus.write(addr as u32, 0x02);
bus.write((addr + 1) as u32, 0x01);
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x000201);
assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x000201);
let pc_addr = 0x7E0010;
let addr = 0x55;
bus.write(pc_addr + 1, addr);
bus.write(addr as u32, 0x02);
bus.write((addr + 1) as u32, 0x01);
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0201);
assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x7E0201);
let pc_addr = 0x7E0010;
let addr = 0x55;
bus.write(pc_addr + 1, addr);
bus.write(addr as u32, 0x02);
bus.write((addr + 1) as u32, 0x01);
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0201);
assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x7E0201);
}
#[test]
@@ -284,7 +284,7 @@ mod addressing_modes_tests {
bus.write(addr as u32, 0x03);
bus.write((addr + 1) as u32, 0x02);
bus.write((addr + 2) as u32, 0x01);
assert_eq!(absolute_indirect_long(&mut bus, pc_addr), 0x030201);
assert_eq!(absolute_indirect_long(&mut bus, pc_addr, 0x00), 0x030201);
}
@@ -353,13 +353,13 @@ mod addressing_modes_tests {
let pc_addr = 0x000000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02), 0x000203);
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x00), 0x000203);
let mut bus = Bus::new();
let pc_addr = 0x7F0000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02), 0x7F0203);
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x7F), 0x7F0203);
}
#[test]
@@ -370,7 +370,7 @@ mod addressing_modes_tests {
bus.write(pc_addr + 1, addr);
bus.write(addr as u32, 0x02);
bus.write((addr + 1) as u32, 0x01);
assert_eq!(absolute_indexed_indirect(&mut bus, pc_addr, 0), 0x000201);
assert_eq!(absolute_indexed_indirect(&mut bus, pc_addr, 0, 0x00), 0x000201);
}
#[test]
@@ -480,13 +480,13 @@ mod addressing_modes_tests {
let pc_addr = 0x000000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02), 0x000203);
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02, 0x00), 0x000203);
let mut bus = Bus::new();
let pc_addr = 0x7F0000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02), 0x7F0203);
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02, 0x7F), 0x7F0203);
}
#[test]
@@ -495,13 +495,13 @@ mod addressing_modes_tests {
let pc_addr = 0x000000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02), 0x000205);
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02, 0x00), 0x000205);
let mut bus = Bus::new();
let pc_addr = 0x7F0000;
bus.write(pc_addr + 1, 0x01);
bus.write(pc_addr + 2, 0x02);
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02), 0x7F0205);
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02, 0x7F), 0x7F0205);
}
#[test]
@@ -512,7 +512,7 @@ mod addressing_modes_tests {
bus.write(pc_addr + 2, 0x10);
bus.write(0x001020, 0xFE);
let val = AddressingMode::Absolute.read_8bit(
ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00},
ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00},
&mut bus,
);
assert_eq!(val, 0xFE);
@@ -524,7 +524,7 @@ mod addressing_modes_tests {
bus.write(0x001020, 0xFF);
bus.write(0x001021, 0xEE);
let val = AddressingMode::Absolute.read_16bit(
ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00},
ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00},
&mut bus,
);
assert_eq!(val, 0xEEFF);
+87 -61
View File
@@ -12,7 +12,7 @@ pub fn adc_bin<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4])
}
pub fn adc_bcd<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4]) {
let original_target = value;
let original_target = target;
let original_value = value;
let nibble_bytes = target.bytes() * 2;
let mut is_carry = carry;
@@ -26,8 +26,10 @@ pub fn adc_bcd<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4])
let mut bcd_six_add = 0x06;
let mut carry_shift = 0;
let mut is_overflow = false;
for _ in 0..nibble_bytes {
result = (target & value_mask) + (value & value_mask) + ((is_carry as u32) << carry_shift) + (result & result_mask);
is_overflow = original_target.is_overflow(original_value, T::from_u32(result));
if result > carry_compare {
result = result.wrapping_add(bcd_six_add);
}
@@ -42,57 +44,73 @@ pub fn adc_bcd<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4])
let result = T::from_u32(result);
(result, [
Negative(result.is_negative()),
Overflow(original_target.is_overflow(original_value, result)),
Overflow(is_overflow),
Zero(result.is_zero()),
Carry(is_carry),
])
}
pub fn sbc_bin<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4]) {
let result = target.sbc_snes(value, carry);
(result, [
Negative(result.is_negative()),
Overflow(target.is_overflow(value, result)),
Zero(result.is_zero()),
Carry(target.sbc_will_carry(value, carry)),
])
adc_bin(target, value.invert(), carry)
}
pub fn sbc_bcd<T: SnesNum>(target: T, value: T, carry: bool) -> (T, [Flags; 4]) {
let original_target = value;
let original_value = value;
let nibble_bytes = target.bytes() * 2;
let mut is_carry = carry;
let target = target.to_u32();
let value = value.invert().to_u32();
let mut result = 0;
let mut value_mask = 0x0F;
let mut result_mask = 0x00;
let mut carry_compare = 0x0F;
let mut bcd_six_sub = 0x06;
let mut carry_shift = 0;
for _ in 0..nibble_bytes {
result = (target & value_mask) + (value & value_mask) + ((is_carry as u32) << carry_shift) + (result & result_mask);
if result <= carry_compare {
result = result.wrapping_sub(bcd_six_sub);
if target.bytes() == 1 {
let target = ((target.to_u32() as u16) as i16) & 0xFF;
let value = !(value.to_u32() as u16) as i16;
let mut carry = if carry {1} else {0};
let mut result: i16 = (target & 0x000F) + (value & 0x000F) + carry;
if result <= 0x000F {
result -= 0x06;
}
carry = if result > 0x000F {1} else {0};
result = (target & 0x00F0) + (value & 0x00F0) + (carry << 4) + (result & 0x000F);
let is_overflow = !(target ^ value) & (target ^ result) & 0x80 != 0;
if result <= 0x00FF {
result -= 0x60;
}
let is_carry = result > 0xFF;
let result = T::from_u32(result as u32);
(result, [
Negative(result.is_negative()),
Overflow(is_overflow),
Zero(result.is_zero()),
Carry(is_carry),
])
} else {
let target = ((target.to_u32() as u16) as i32) & 0xFFFF;
let value = !(value.to_u32() as u16) as i32;
let mut carry = if carry {1} else {0};
let mut result: i32 = (target & 0x000F) + (value & 0x000F) + carry;
if result <= 0x000F {
result -= 0x0006;
}
carry = if result > 0x000F {1} else {0};
result = (target & 0x00F0) + (value & 0x00F0) + (carry << 4) + (result & 0x000F);
if result <= 0x00FF {
result -= 0x0060;
}
is_carry = result > carry_compare;
value_mask <<= 4;
bcd_six_sub <<= 4;
carry_shift += 4;
result_mask = (result_mask << 4) | 0xF;
carry_compare = (carry_compare << 4) | 0xF;
}
let result = T::from_u32(result);
(result, [
Negative(result.is_negative()),
Overflow(original_target.is_overflow(original_value, result)),
Zero(result.is_zero()),
Carry(is_carry),
])
carry = if result > 0x00FF {1} else {0};
result = (target & 0x0F00) + (value & 0x0F00) + (carry << 8) + (result & 0x00FF);
if result <= 0x0FFF {
result -= 0x0600;
}
carry = if result > 0x0FFF {1} else {0};
result = (target & 0xF000) + (value & 0xF000) + (carry << 12) + (result & 0x0FFF);
let is_overflow = !(target ^ value) & (target ^ result) & 0x8000 != 0;
if result <= 0xFFFF {
result -= 0x6000;
}
let is_carry = result > 0xFFFF;
let result = T::from_u32((result) as u32);
(result, [
Negative(result.is_negative()),
Overflow(is_overflow),
Zero(result.is_zero()),
Carry(is_carry),
])
}
}
pub fn and<T: SnesNum>(target: T, value: T) -> (T, [Flags; 2]) {
@@ -170,11 +188,11 @@ mod alu_tests {
let (result, affected_flags) = adc_bin(200_u8, 155_u8, false);
assert_eq!(result, 99);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(true), Zero(false), Carry(true)]);
let (result, affected_flags) = adc_bin(200_u8, 155_u8, true);
assert_eq!(result, 100);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(true), Zero(false), Carry(true)]);
let (result, affected_flags) = adc_bin(200_u8, 54_u8, true);
assert_eq!(result, 255);
@@ -184,6 +202,14 @@ mod alu_tests {
assert_eq!(result, 255);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(false)]);
let (result, affected_flags) = adc_bin(0x7F_u8, 0x81_u8, false);
assert_eq!(result, 0x00);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(true), Carry(true)]);
let (result, affected_flags) = adc_bin(0x7F_u8, 0x7F_u8, true);
assert_eq!(result, 0xFF);
assert_eq!(affected_flags, [Negative(true), Overflow(true), Zero(false), Carry(false)]);
// 16 bits
let (result, affected_flags) = adc_bin(0_u16, 0_u16, false);
assert_eq!(result, 0);
@@ -195,11 +221,11 @@ mod alu_tests {
let (result, affected_flags) = adc_bin(65530_u16, 10_u16, false);
assert_eq!(result, 4);
assert_eq!(affected_flags, [Negative(false), Overflow(true), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(false), Carry(true)]);
let (result, affected_flags) = adc_bin(65530_u16, 10_u16, true);
assert_eq!(result, 5);
assert_eq!(affected_flags, [Negative(false), Overflow(true), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(false), Carry(true)]);
let (result, affected_flags) = adc_bin(65530_u16, 4_u16, true);
assert_eq!(result, 65535);
@@ -266,35 +292,35 @@ mod alu_tests {
#[test]
fn test_dec_bin() {
// 8 bit
let (result, affected_flags) = sbc_bin(1_u8, 1_u8, false);
let (result, affected_flags) = sbc_bin(1_u8, 1_u8, true);
assert_eq!(result, 0);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(true), Carry(false)]);
let (result, affected_flags) = sbc_bin(0_u8, 1_u8, false);
assert_eq!(result, 0b11111111);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(true), Carry(true)]);
let (result, affected_flags) = sbc_bin(0_u8, 1_u8, true);
assert_eq!(result, 0b11111111);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(false)]);
let (result, affected_flags) = sbc_bin(0_u8, 1_u8, false);
assert_eq!(result, 0b11111110);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(false)]);
// overflow
let (result, affected_flags) = sbc_bin(0x50_u8, 0xB0_u8, false);
let (result, affected_flags) = sbc_bin(0x50_u8, 0xB0_u8, true);
assert_eq!(result, 0xA0);
assert_eq!(affected_flags, [Negative(true), Overflow(true), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(true), Overflow(true), Zero(false), Carry(false)]);
// 16 bit
let (result, affected_flags) = sbc_bin(1_u16, 1_u16, false);
let (result, affected_flags) = sbc_bin(1_u16, 1_u16, true);
assert_eq!(result, 0);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(true), Carry(false)]);
let (result, affected_flags) = sbc_bin(0_u16, 1_u16, false);
assert_eq!(result, 0b11111111_11111111);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(false), Overflow(false), Zero(true), Carry(true)]);
let (result, affected_flags) = sbc_bin(0_u16, 1_u16, true);
assert_eq!(result, 0b11111111_11111111);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(false)]);
let (result, affected_flags) = sbc_bin(0_u16, 1_u16, false);
assert_eq!(result, 0b11111111_11111110);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(true)]);
assert_eq!(affected_flags, [Negative(true), Overflow(false), Zero(false), Carry(false)]);
}
#[test]
+5 -5
View File
@@ -1,4 +1,4 @@
pub trait SnesNum: Copy + Clone + Sized + Eq + PartialEq {
pub trait SnesNum: Copy + Clone + Sized + Eq + PartialEq + PartialOrd {
fn add_will_carry(&self, v: Self, carry: bool) -> bool;
fn sbc_will_carry(&self, v: Self, carry: bool) -> bool;
fn is_overflow(&self, v: Self, r: Self) -> bool;
@@ -46,10 +46,10 @@ macro_rules! define_operation {
macro_rules! define_is_overflow {
($t:ty) => {
fn is_overflow(&self, v: $t, r: $t) -> bool {
let target = (*self).is_negative();
let value = v.is_negative();
let result = r.is_negative();
(target ^ result) && (target ^ value)
let target_msb = (*self).is_negative();
let value_msb = v.is_negative();
let result_msb = r.is_negative();
(target_msb ^ result_msb) && !(target_msb ^ value_msb)
}
}
}