summaryrefslogtreecommitdiff
path: root/src/devices/clock_device.rs
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2025-07-03 15:26:07 +1200
committerBen Bridle <ben@derelict.engineering>2025-07-03 21:24:07 +1200
commit2accc78948fa4a18e37ab0bc405f9b2758acaa3e (patch)
tree2551180ef7fb8f67bfc826de4ad3daf2dd24942e /src/devices/clock_device.rs
downloadbedrock-pc-2accc78948fa4a18e37ab0bc405f9b2758acaa3e.zip
Initial commit
Diffstat (limited to 'src/devices/clock_device.rs')
-rw-r--r--src/devices/clock_device.rs161
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;
+ }
+ }
+}