diff --git a/runtime/src/ops/math.rs b/runtime/src/ops/math.rs index 8e7f149c..cb81f858 100644 --- a/runtime/src/ops/math.rs +++ b/runtime/src/ops/math.rs @@ -66,9 +66,13 @@ pub fn or(x: I, y: I, flags: &mut Flags) -> I { /// neg: Two's Complement Negation pub fn neg(x: I, flags: &mut Flags) -> I { - let (result, of) = I::zero().overflowing_sub(&x); + let (result, _) = I::zero().overflowing_sub(&x); flags.set(Flags::ZF, result.is_zero()); + flags.set(Flags::SF, result.high_bit().is_one()); flags.set(Flags::CF, !result.is_zero()); + // Only the most negative value overflows: it is the one input whose + // negation is still negative. + let of = x.high_bit().is_one() && result.high_bit().is_one(); flags.set(Flags::OF, of); flags.set(Flags::PF, result.low_byte().count_ones() % 2 == 0); result @@ -180,6 +184,31 @@ mod tests { (result, flags) } + fn neg8(x: u8) -> (u8, Flags) { + let mut flags = Flags::default(); + let result = neg(x, &mut flags); + (result, flags) + } + + #[test] + fn neg_flags() { + let (result, flags) = neg8(0x00); + assert_eq!(result, 0x00); + assert_eq!(flags.to_string(), "PF ZF"); + + let (result, flags) = neg8(0x01); + assert_eq!(result, 0xff); + assert_eq!(flags.to_string(), "CF PF SF"); + + let (result, flags) = neg8(0xff); + assert_eq!(result, 0x01); + assert_eq!(flags.to_string(), "CF"); + + let (result, flags) = neg8(0x80); + assert_eq!(result, 0x80); + assert_eq!(flags.to_string(), "CF SF OF"); + } + #[test] fn sbb_edge_cases() { let (result, flags) = sbb8(0x00, 0x7f, true);