diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2025-07-03 15:26:07 +1200 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-07-03 21:24:07 +1200 |
commit | 2accc78948fa4a18e37ab0bc405f9b2758acaa3e (patch) | |
tree | 2551180ef7fb8f67bfc826de4ad3daf2dd24942e /src/devices/clock_device.rs | |
download | bedrock-pc-2accc78948fa4a18e37ab0bc405f9b2758acaa3e.zip |
Initial commit
Diffstat (limited to 'src/devices/clock_device.rs')
-rw-r--r-- | src/devices/clock_device.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/devices/clock_device.rs b/src/devices/clock_device.rs new file mode 100644 index 0000000..d06a92c --- /dev/null +++ b/src/devices/clock_device.rs @@ -0,0 +1,161 @@ +use crate::*; + +use chrono::prelude::*; + + +pub struct ClockDevice { + pub epoch: Instant, + pub uptime_read: u16, + + pub t1: CountdownTimer, + pub t2: CountdownTimer, + pub t3: CountdownTimer, + pub t4: CountdownTimer, +} + + +impl Device for ClockDevice { + fn read(&mut self, port: u8) -> u8 { + match port { + 0x0 => Local::now().year().saturating_sub(2000) as u8, + 0x1 => Local::now().month().saturating_sub(1) as u8, + 0x2 => Local::now().day().saturating_sub(1) as u8, + 0x3 => Local::now().hour() as u8, + 0x4 => Local::now().minute() as u8, + 0x5 => Local::now().second() as u8, + 0x6 => { self.uptime_read = self.uptime() as u16; + read_h!(self.uptime_read) }, + 0x7 => read_l!(self.uptime_read), + 0x8 => { self.t1.update(); read_h!(self.t1.read) }, + 0x9 => read_l!(self.t1.read), + 0xA => { self.t2.update(); read_h!(self.t2.read) }, + 0xB => read_l!(self.t2.read), + 0xC => { self.t3.update(); read_h!(self.t3.read) }, + 0xD => read_l!(self.t3.read), + 0xE => { self.t4.update(); read_h!(self.t4.read) }, + 0xF => read_l!(self.t4.read), + _ => unreachable!(), + } + } + + fn write(&mut self, port: u8, value: u8) -> Option<Signal> { + match port { + 0x0 => (), + 0x1 => (), + 0x2 => (), + 0x3 => (), + 0x4 => (), + 0x5 => (), + 0x6 => (), + 0x7 => (), + 0x8 => write_h!(self.t1.write, value), + 0x9 => { write_l!(self.t1.write, value); self.t1.commit() }, + 0xA => write_h!(self.t2.write, value), + 0xB => { write_l!(self.t2.write, value); self.t2.commit() }, + 0xC => write_h!(self.t3.write, value), + 0xD => { write_l!(self.t3.write, value); self.t3.commit() }, + 0xE => write_h!(self.t4.write, value), + 0xF => { write_l!(self.t4.write, value); self.t4.commit() }, + _ => unreachable!(), + }; + return None; + } + + fn wake(&mut self) -> bool { + let t1 = self.t1.wake(); + let t2 = self.t2.wake(); + let t3 = self.t3.wake(); + let t4 = self.t4.wake(); + return t1 | t2 | t3 | t4; + } + + fn reset(&mut self) { + self.epoch = Instant::now(); + self.uptime_read = 0; + self.t1.reset(); + self.t2.reset(); + self.t3.reset(); + self.t4.reset(); + } +} + + +impl ClockDevice { + pub fn new() -> Self { + Self { + epoch: Instant::now(), + uptime_read: 0, + + t1: CountdownTimer::new(), + t2: CountdownTimer::new(), + t3: CountdownTimer::new(), + t4: CountdownTimer::new(), + } + } + + pub fn uptime(&self) -> u64 { + (self.epoch.elapsed().as_nanos() * 256 / 1_000_000_000) as u64 + } +} + + + +pub struct CountdownTimer { + pub end: Option<Instant>, + pub read: u16, + pub write: u16, + pub wake: bool, +} + +impl CountdownTimer { + pub fn new() -> Self { + Self { + end: None, + read: 0, + write: 0, + wake: false, + } + } + + pub fn reset(&mut self) { + self.end = None; + self.read = 0; + self.write = 0; + self.wake = false; + } + + pub fn wake(&mut self) -> bool { + if let Some(end) = self.end { + if end <= Instant::now() { + self.end = None; + self.wake = true; + } + } + std::mem::take(&mut self.wake) + } + + pub fn update(&mut self) { + if let Some(end) = self.end { + let now = Instant::now(); + if end > now { + let nanos = (end - now).as_nanos(); + self.read = (nanos * 256 / 1_000_000_000) as u16; + } else { + self.read = 0; + self.end = None; + self.wake = true; + } + } else { + self.read = 0; + } + } + + pub fn commit(&mut self) { + if self.write > 0 { + let nanos = (self.write as u64) * 1_000_000_000 / 256; + self.end = Some(Instant::now() + Duration::from_nanos(nanos)); + } else { + self.end = None; + } + } +} |