use std::ops::Rem; use num_traits::PrimInt; use crsn::asm::instr::Cond; use crsn::asm::instr::op::{EvalRes, OpTrait}; use crsn::runtime::fault::Fault; use crsn::runtime::run_thread::{state::RunState, ThreadInfo}; use crate::defs::ArithOp; impl OpTrait for ArithOp { fn execute(&self, _ti: &ThreadInfo, state: &mut RunState) -> Result { let eres = EvalRes::default(); match self { ArithOp::Test { a } => { state.clear_status(); let res = state.read(*a)?; state.update_status(res); } ArithOp::Compare { a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; state.set_flag(Cond::Equal, x == y); state.set_flag(Cond::Lower, x < y); state.set_flag(Cond::Greater, x > y); // Test flags are set when both arguments have the property if x == y { state.update_status(x); } } ArithOp::Add { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let (res, ov) = if let Some(v) = x.checked_add(y) { (v, false) } else { (x.wrapping_add(y), true) }; state.update_status(res); state.set_flag(Cond::Overflow, ov); state.write(*dst, res)?; } ArithOp::Sub { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let (res, ov) = if let Some(v) = x.checked_sub(y) { (v, false) } else { (x.wrapping_sub(y), true) }; state.update_status(res); state.set_flag(Cond::Overflow, ov); state.write(*dst, res)?; } ArithOp::Mul { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let (res, ov) = if let Some(v) = x.checked_mul(y) { (v, false) } else { (x.wrapping_mul(y), true) }; state.update_status(res); state.set_flag(Cond::Overflow, ov); state.write(*dst, res)?; } ArithOp::Div { dst, rem, a, div } => { state.clear_status(); let x = state.read(*a)?; let d = state.read(*div)?; if d == 0 { state.set_flag(Cond::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) }; state.update_status(res); state.set_flag(Cond::Overflow, ov); state.write(*dst, res)?; state.write(*rem, remainder)?; } } ArithOp::Mod { dst, a, div } => { state.clear_status(); let x = state.read(*a)?; let d = state.read(*div)?; if d == 0 { state.set_flag(Cond::Invalid, true); } else { let (remainder, ov) = if let Some(v) = x.checked_rem(d) { (v, false) } else { (x.wrapping_rem(d), true) }; state.update_status(remainder); state.set_flag(Cond::Overflow, ov); state.write(*dst, remainder)?; } } ArithOp::And { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let res = x & y; state.update_status(res); state.write(*dst, res)?; } ArithOp::Or { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let res = x | y; state.update_status(res); state.write(*dst, res)?; } ArithOp::Xor { dst, a, b } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*b)?; let res = x ^ y; state.update_status(res); state.write(*dst, res)?; } ArithOp::Cpl { dst, a } => { state.clear_status(); let x = state.read(*a)?; let res = !x; state.update_status(res); state.write(*dst, res)?; } ArithOp::Rol { dst, a, n } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*n)?; if y > u32::MAX as u64 { state.set_flag(Cond::Invalid, true); } else { let res = x.rotate_left(y as u32); state.update_status(res); state.write(*dst, res)?; } } ArithOp::Ror { dst, a, n } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*n)?; if y > u32::MAX as u64 { state.set_flag(Cond::Invalid, true); } else { let res = x.rotate_right(y as u32); state.update_status(res); state.write(*dst, res)?; } } ArithOp::Lsl { dst, a, n } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*n)?; let res = x << y; state.update_status(res); state.write(*dst, res)?; } ArithOp::Lsr { dst, a, n } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*n)?; let res = x >> y; state.update_status(res); state.write(*dst, res)?; } ArithOp::Asr { dst, a, n } => { state.clear_status(); let x = state.read(*a)?; let y = state.read(*n)?; if y > u32::MAX as u64 { state.set_flag(Cond::Invalid, true); } else { let res = x.signed_shr(y as u32); state.update_status(res); state.write(*dst, res)?; } } } Ok(eres) } // }