gwr_engine/time/
simtime.rs1use std::rc::Rc;
8
9use gwr_track::entity::Entity;
10use gwr_track::set_time;
11
12use super::clock::Clock;
13use crate::time::clock::TaskWaker;
14
15#[derive(Clone)]
19pub struct SimTime {
20 entity: Rc<Entity>,
21
22 current_ns: f64,
23
24 clocks: Vec<Clock>,
29}
30
31impl SimTime {
32 #[must_use]
33 pub fn new(parent: &Rc<Entity>) -> Self {
34 Self {
35 entity: Rc::new(Entity::new(parent, "time")),
36 current_ns: 0.0,
37 clocks: Vec::new(),
38 }
39 }
40
41 pub fn get_clock(&mut self, freq_mhz: f64) -> Clock {
42 for clock in &self.clocks {
43 if clock.freq_mhz() == freq_mhz {
44 return clock.clone();
45 }
46 }
47 let clock = Clock::new(freq_mhz);
48 self.clocks.push(clock.clone());
49 clock
50 }
51
52 pub fn advance_time(&mut self) -> Option<Vec<TaskWaker>> {
54 if let Some(next_clock) = self.clocks.iter().min_by(|a, b| a.cmp(b)) {
55 if let Some(clock_time) = next_clock.shared_state.waiting_times.borrow_mut().pop() {
56 let next_ns = next_clock.to_ns(&clock_time);
57 if self.current_ns != next_ns {
58 set_time!(self.entity ; next_ns);
59 self.current_ns = next_ns;
60 }
61 next_clock.advance_time(clock_time);
62 next_clock.shared_state.waiting.borrow_mut().pop()
63 } else {
64 None
65 }
66 } else {
67 None
68 }
69 }
70
71 #[must_use]
72 pub fn time_now_ns(&self) -> f64 {
73 self.current_ns
74 }
75
76 #[must_use]
78 pub fn can_exit(&self) -> bool {
79 for clock in &self.clocks {
80 for waiting in clock.shared_state.waiting.borrow().iter() {
81 for task_waker in waiting {
82 if !task_waker.can_exit {
83 return false;
85 }
86 }
87 }
88 }
89 true
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use std::future::Future;
96 use std::pin::Pin;
97 use std::task::{Context, Poll};
98
99 use futures::task::noop_waker;
100 use gwr_track::entity::toplevel;
101 use gwr_track::test_helpers::create_tracker;
102
103 use super::*;
104
105 #[test]
106 fn clock_created_once() {
107 let tracker = create_tracker(file!());
108 let top = toplevel(&tracker, "top");
109
110 let mut time = SimTime::new(&top);
111 let _clk1 = time.get_clock(1000.0);
112 assert_eq!(time.clocks.len(), 1);
113
114 let _clk2 = time.get_clock(1000.0);
115 assert_eq!(time.clocks.len(), 1);
116 }
117
118 #[test]
119 fn create_different_clocks() {
120 let tracker = create_tracker(file!());
121 let top = toplevel(&tracker, "top");
122
123 let mut time = SimTime::new(&top);
124 let _clk1 = time.get_clock(1000.0);
125 assert_eq!(time.clocks.len(), 1);
126
127 let _clk2 = time.get_clock(1800.0);
128 assert_eq!(time.clocks.len(), 2);
129 }
130
131 #[test]
132 fn advance_time_returns_none_without_waiters() {
133 let tracker = create_tracker(file!());
134 let top = toplevel(&tracker, "top");
135
136 let mut time = SimTime::new(&top);
137 assert!(time.advance_time().is_none());
138
139 let _clock = time.get_clock(1000.0);
140 assert!(time.advance_time().is_none());
141 }
142
143 #[test]
144 fn advance_time_handles_equal_times_on_different_clocks() {
145 let tracker = create_tracker(file!());
146 let top = toplevel(&tracker, "top");
147
148 let mut time = SimTime::new(&top);
149 let clock_1ghz = time.get_clock(1000.0);
150 let clock_2ghz = time.get_clock(2000.0);
151 let waker = noop_waker();
152 let mut cx = Context::from_waker(&waker);
153
154 let mut delays = [
155 clock_1ghz.wait_ticks(1),
156 clock_1ghz.wait_ticks(2),
157 clock_2ghz.wait_ticks(2),
158 clock_2ghz.wait_ticks(4),
159 ];
160
161 for delay in &mut delays {
162 assert_eq!(Pin::new(delay).poll(&mut cx), Poll::Pending);
163 }
164
165 for expected_ns in [1.0, 1.0, 2.0, 2.0] {
166 let wakers = time.advance_time().unwrap();
167
168 assert_eq!(wakers.len(), 1);
169 assert_eq!(time.time_now_ns(), expected_ns);
170 }
171
172 assert_eq!(clock_1ghz.tick_now().tick(), 2);
173 assert_eq!(clock_2ghz.tick_now().tick(), 4);
174 assert!(time.advance_time().is_none());
175 }
176}