diff options
Diffstat (limited to 'src/devices/math_device.rs')
-rw-r--r-- | src/devices/math_device.rs | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/devices/math_device.rs b/src/devices/math_device.rs new file mode 100644 index 0000000..015545e --- /dev/null +++ b/src/devices/math_device.rs @@ -0,0 +1,141 @@ +use bedrock_core::*; + + +pub struct MathDevice { + pub op1: u16, + pub op2: u16, + + pub sqrt: Option<u16>, + pub atan: Option<u16>, + pub prod: Option<(u16, u16)>, // (low, high) + pub quot: Option<u16>, + pub rem: Option<u16>, +} + +impl MathDevice { + pub fn new() -> Self { + Self { + op1: 0, + op2: 0, + + sqrt: None, + atan: None, + prod: None, + quot: None, + rem: None, + } + } + + pub fn clear(&mut self) { + self.sqrt = None; + self.atan = None; + self.prod = None; + self.quot = None; + self.rem = None; + } + + pub fn atan(&mut self) -> u16 { + match self.atan { + Some(atan) => atan, + None => { + let x = self.op1 as i16 as f64; + let y = self.op2 as i16 as f64; + const SCALE: f64 = 10430.378350470453; // PI * 32768 + self.atan = Some((f64::atan2(x, y) * SCALE) as i16 as u16); + self.atan.unwrap() + } + } + } + + pub fn sqrt(&mut self) -> u16 { + match self.sqrt { + Some(sqrt) => sqrt, + None => { + let input = ((self.op1 as u32) << 16) | (self.op2 as u32); + self.sqrt = Some((input as f64).sqrt() as u16); + self.sqrt.unwrap() + } + } + } + + pub fn prod(&mut self) -> (u16, u16) { + match self.prod { + Some(prod) => prod, + None => { + self.prod = Some(self.op1.widening_mul(self.op2)); + self.prod.unwrap() + } + } + } + + pub fn quot(&mut self) -> u16 { + match self.quot { + Some(quot) => quot, + None => { + self.quot = Some(self.op1.checked_div(self.op2).unwrap_or(0)); + self.quot.unwrap() + } + } + } + + pub fn rem(&mut self) -> u16 { + match self.rem { + Some(rem) => rem, + None => { + self.rem = Some(self.op1.checked_rem(self.op2).unwrap_or(0)); + self.rem.unwrap() + } + } + } +} + +impl Device for MathDevice { + fn read(&mut self, port: u8) -> u8 { + match port { + 0x0 => read_h!(self.op1), + 0x1 => read_l!(self.op1), + 0x2 => read_h!(self.op2), + 0x3 => read_l!(self.op2), + 0x4 => read_h!(self.sqrt()), + 0x5 => read_l!(self.sqrt()), + 0x6 => read_h!(self.atan()), + 0x7 => read_l!(self.atan()), + 0x8 => read_h!(self.prod().1), + 0x9 => read_l!(self.prod().1), + 0xa => read_h!(self.prod().0), + 0xb => read_l!(self.prod().0), + 0xc => read_h!(self.quot()), + 0xd => read_l!(self.quot()), + 0xe => read_h!(self.rem()), + 0xf => read_l!(self.rem()), + _ => unreachable!(), + } + } + + fn write(&mut self, port: u8, value: u8) -> Option<Signal> { + match port { + 0x0 => { write_h!(self.op1, value); self.clear(); }, + 0x1 => { write_l!(self.op1, value); self.clear(); }, + 0x2 => { write_h!(self.op2, value); self.clear(); }, + 0x3 => { write_l!(self.op2, value); self.clear(); }, + 0x4 => (), + 0x5 => (), + 0x6 => (), + 0x7 => (), + 0x8 => (), + 0x9 => (), + 0xa => (), + 0xb => (), + 0xc => (), + 0xd => (), + 0xe => (), + 0xf => (), + _ => unreachable!(), + }; + return None; + } + + fn wake(&mut self) -> bool { + false + } +} |