use std::ops::Rem; use num_traits::PrimInt; use crsn::asm::instr::op::{OpTrait, EvalRes}; use crsn::runtime::fault::Fault; use crsn::runtime::frame::{CallStack, StackFrame}; use crsn::runtime::program::Program; use crate::defs::ArithOp; impl OpTrait for ArithOp { fn execute(&self, _program: &Program, _call_stack: &mut CallStack, frame: &mut StackFrame) -> Result { let eres = EvalRes::default(); match self { ArithOp::Test { a } => { frame.status.clear(); let res = frame.read(*a)?; frame.status.update(res); } ArithOp::Compare { a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; frame.status.equal = x == y; frame.status.lower = x < y; frame.status.greater = x > y; // Test flags are set when both arguments have the property if x == y { frame.status.update(x); } } ArithOp::Add { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let (res, ov) = if let Some(v) = x.checked_add(y) { (v, false) } else { (x.wrapping_add(y), true) }; frame.status.update(res); frame.status.overflow = ov; frame.write(*dst, res)?; } ArithOp::Sub { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let (res, ov) = if let Some(v) = x.checked_sub(y) { (v, false) } else { (x.wrapping_sub(y), true) }; frame.status.update(res); frame.status.overflow = ov; frame.write(*dst, res)?; } ArithOp::Mul { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let (res, ov) = if let Some(v) = x.checked_mul(y) { (v, false) } else { (x.wrapping_mul(y), true) }; frame.status.update(res); frame.status.overflow = ov; frame.write(*dst, res)?; } ArithOp::Div { dst, rem, a, div } => { frame.status.clear(); let x = frame.read(*a)?; let d = frame.read(*div)?; if d == 0 { frame.status.invalid = true; } else { let (res, remainder, ov) = if let Some(v) = x.checked_div(d) { (v, x.rem(d), false) } else { (x.wrapping_div(d), x.wrapping_rem(d), true) }; frame.status.update(res); frame.status.overflow = ov; frame.write(*dst, res)?; frame.write(*rem, remainder)?; } } ArithOp::Mod { dst, a, div } => { frame.status.clear(); let x = frame.read(*a)?; let d = frame.read(*div)?; if d == 0 { frame.status.invalid = true; } else { let (remainder, ov) = if let Some(v) = x.checked_rem(d) { (v, false) } else { (x.wrapping_rem(d), true) }; frame.status.update(remainder); frame.status.overflow = ov; frame.write(*dst, remainder)?; } } ArithOp::And { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let res = x & y; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Or { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let res = x | y; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Xor { dst, a, b } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*b)?; let res = x ^ y; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Cpl { dst, a } => { frame.status.clear(); let x = frame.read(*a)?; let res = !x; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Rol { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; if y > u32::MAX as u64 { frame.status.invalid = true; } else { let res = x.rotate_left(y as u32); frame.status.update(res); frame.write(*dst, res)?; } } ArithOp::Ror { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; if y > u32::MAX as u64 { frame.status.invalid = true; } else { let res = x.rotate_right(y as u32); frame.status.update(res); frame.write(*dst, res)?; } } ArithOp::Lsl { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; let res = x << y; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Lsr { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; let res = x >> y; frame.status.update(res); frame.write(*dst, res)?; } ArithOp::Asr { dst, a, n } => { frame.status.clear(); let x = frame.read(*a)?; let y = frame.read(*n)?; if y > u32::MAX as u64 { frame.status.invalid = true; } else { let res = x.signed_shr(y as u32); frame.status.update(res); frame.write(*dst, res)?; } } } Ok(eres) } // }