use std::fmt::{Display, Formatter}; use std::fmt; use crate::asm::data::literal::{is_negative, is_positive, Value}; use crate::asm::instr::Cond; #[derive(Default, Clone, Debug)] pub struct StatusFlags { /// Arguments are equal pub equal: bool, /// A < B pub lower: bool, /// A > B pub greater: bool, /// Register is zero pub zero: bool, /// Register is positive pub positive: bool, /// Register is negative pub negative: bool, /// Overflow (multiplication etc.) pub overflow: bool, /// Invalid flag pub invalid: bool, /// Arithmetic carry pub carry: bool, /// Buffer full pub full: bool, /// Buffer empty pub empty: bool, } impl StatusFlags { #[inline(always)] pub fn clear(&mut self) { *self = Self::default(); } pub fn store(&self) -> Value { let mut val = 0u64; if self.equal { val |= 0x01; } if self.lower { val |= 0x02; } if self.greater { val |= 0x04; } if self.zero { val |= 0x08; } if self.positive { val |= 0x10; } if self.negative { val |= 0x20; } if self.overflow { val |= 0x40; } if self.invalid { val |= 0x80; } if self.carry { val |= 0x100; } if self.full { val |= 0x200; } if self.empty { val |= 0x400; } val } pub fn load(&mut self, val: Value) { if val & 0x01 != 0 { self.equal = true; } if val & 0x02 != 0 { self.lower = true; } if val & 0x04 != 0 { self.greater = true; } if val & 0x08 != 0 { self.zero = true; } if val & 0x10 != 0 { self.positive = true; } if val & 0x20 != 0 { self.negative = true; } if val & 0x40 != 0 { self.overflow = true; } if val & 0x80 != 0 { self.invalid = true; } if val & 0x100 != 0 { self.carry = true; } if val & 0x200 != 0 { self.full = true; } if val & 0x400 != 0 { self.empty = true; } } #[inline(always)] pub fn update(&mut self, val: Value) { self.zero = val == 0; self.positive = is_positive(val); self.negative = is_negative(val); } #[inline(always)] pub fn test(&self, cond: Cond) -> bool { match cond { Cond::Equal => self.equal, Cond::NotEqual => !self.equal, Cond::Zero => self.zero, Cond::NotZero => !self.zero, Cond::Lower => self.lower, Cond::LowerOrEqual => self.lower || self.equal, Cond::Greater => self.greater, Cond::GreaterOrEqual => self.greater || self.equal, Cond::Positive => self.positive, Cond::NonPositive => !self.positive, Cond::Negative => self.negative, Cond::NonNegative => !self.negative, Cond::Overflow => self.overflow, Cond::NotOverflow => !self.overflow, Cond::Invalid => self.invalid, Cond::Valid => !self.invalid, Cond::Carry => self.carry, Cond::NotCarry => !self.carry, Cond::Full => self.full, Cond::NotFull => !self.full, Cond::Empty => self.empty, Cond::NotEmpty => !self.empty, } } #[inline(always)] pub fn set(&mut self, cond: Cond) { match cond { Cond::Equal => { self.equal = true; } Cond::Zero => { self.zero = true; } Cond::Lower => { self.lower = true; } Cond::Greater => { self.lower = false; self.equal = false; self.greater = true; } Cond::Positive => { self.positive = true; } Cond::Negative => { self.negative = true; } Cond::Overflow => { self.overflow = true; } Cond::Invalid => { self.invalid = true; } Cond::Carry => { self.carry = true; } Cond::Empty => { self.empty = true; } Cond::Full => { self.full = true; } other => { error!("Cannot set cond by {:?}", other); // ...and do nothing. Don't panic, we don't want to crash the runtime! } } } } impl Display for StatusFlags { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("[")?; if self.equal { f.write_str(" =")?; } if self.zero { f.write_str(" 0")?; } if self.lower { f.write_str(" Lt")?; } if self.greater { f.write_str(" Gt")?; } if self.positive { f.write_str(" +")?; } if self.negative { f.write_str(" -")?; } if self.overflow { f.write_str(" Ov")?; } if self.invalid { f.write_str(" Inv")?; } if self.carry { f.write_str(" C")?; } if self.full { f.write_str(" Full")?; } if self.empty { f.write_str(" Emp")?; } f.write_str(" ]")?; Ok(()) } }