1use bit_set::BitSet;
2use celox_design::DomainKind;
3use fxhash::FxHashMap;
4
5use crate::{
6 SignalRef, SimulatorErrorCode,
7 backend::{EventHandle, SimBackend},
8 scheduler::{ClockDef, Scheduler, SimEvent},
9};
10
11pub trait SimulationExecutor {
16 type Backend: SimBackend;
17
18 fn backend(&self) -> &Self::Backend;
19 fn backend_mut(&mut self) -> &mut Self::Backend;
20 fn eval_comb(&mut self) -> Result<(), SimulatorErrorCode>;
21 fn eval_apply_ff_at(
22 &mut self,
23 event: <Self::Backend as SimBackend>::Event,
24 ) -> Result<(), SimulatorErrorCode>;
25 fn eval_only_ff_at(
26 &mut self,
27 event: <Self::Backend as SimBackend>::Event,
28 ) -> Result<(), SimulatorErrorCode>;
29 fn apply_ff_at(
30 &mut self,
31 event: <Self::Backend as SimBackend>::Event,
32 ) -> Result<(), SimulatorErrorCode>;
33
34 fn stage_external_event(
37 &mut self,
38 _event: <Self::Backend as SimBackend>::Event,
39 _timestamp: u64,
40 ) -> Result<(), SimulatorErrorCode> {
41 Ok(())
42 }
43
44 fn fire_external_event(
47 &mut self,
48 _event: <Self::Backend as SimBackend>::Event,
49 _timestamp: u64,
50 ) -> Result<(), SimulatorErrorCode> {
51 Ok(())
52 }
53
54 fn finish_timed_step(&mut self, _timestamp: u64) {}
56}
57
58pub struct EventInfo<B: SimBackend> {
60 pub canonical_id: usize,
61 pub is_cascaded: bool,
62 pub eval_ff_event: Option<B::Event>,
63 pub eval_only_event: Option<B::Event>,
64 pub apply_event: Option<B::Event>,
65}
66
67impl<B: SimBackend> Clone for EventInfo<B> {
68 fn clone(&self) -> Self {
69 *self
70 }
71}
72
73impl<B: SimBackend> Copy for EventInfo<B> {}
74
75impl<B: SimBackend> std::fmt::Debug for EventInfo<B> {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 f.debug_struct("EventInfo")
78 .field("canonical_id", &self.canonical_id)
79 .field("is_cascaded", &self.is_cascaded)
80 .field("eval_ff_event", &self.eval_ff_event)
81 .field("eval_only_event", &self.eval_only_event)
82 .field("apply_event", &self.apply_event)
83 .finish()
84 }
85}
86
87pub struct SimulationState<B: SimBackend> {
89 scheduler: Scheduler<B>,
90 last_clock_values: BitSet,
91 topo_signals: Vec<(SignalRef, usize, usize)>,
92 domain_kinds: Vec<Option<DomainKind>>,
93 event_info: Vec<EventInfo<B>>,
94 signal_to_id: FxHashMap<SignalRef, usize>,
95}
96
97impl<B: SimBackend> SimulationState<B> {
98 pub fn synchronize_event_values(&mut self, backend: &B) {
100 self.last_clock_values.make_empty();
101 for (signal, id, _) in &self.topo_signals {
102 if *id == usize::MAX {
103 continue;
104 }
105 let value: u8 = backend.get_as(*signal);
106 if value != 0 {
107 self.last_clock_values.insert(*id);
108 }
109 }
110 }
111
112 fn replace_triggers_with_stable_edges(&self, backend: &mut B) {
113 backend.clear_triggered_bits();
114 for (signal, id, _) in &self.topo_signals {
115 if *id == usize::MAX {
116 continue;
117 }
118 let was_nonzero = self.last_clock_values.contains(*id);
119 let value: u8 = backend.get_as(*signal);
120 let is_nonzero = value != 0;
121 let triggered = match self.domain_kinds[*id] {
122 Some(DomainKind::ClockPosedge | DomainKind::ResetAsyncHigh) => {
123 !was_nonzero && is_nonzero
124 }
125 Some(DomainKind::ClockNegedge | DomainKind::ResetAsyncLow) => {
126 was_nonzero && !is_nonzero
127 }
128 _ => was_nonzero != is_nonzero,
129 };
130 if triggered {
131 backend.mark_triggered_bit(*id);
132 }
133 }
134 }
135
136 pub fn new(
137 backend: &B,
138 topo_signals: Vec<(SignalRef, usize, usize)>,
139 domain_kinds: Vec<Option<DomainKind>>,
140 event_info: Vec<EventInfo<B>>,
141 ) -> Self {
142 let mut last_clock_values = BitSet::with_capacity(backend.num_events());
143 let mut signal_to_id = FxHashMap::default();
144 for (signal, id, _) in topo_signals.iter().copied() {
145 if id == usize::MAX {
146 continue;
147 }
148 signal_to_id.insert(signal, id);
149 let value: u8 = backend.get_as(signal);
150 if value != 0 {
151 last_clock_values.insert(id);
152 }
153 }
154
155 Self {
156 scheduler: Scheduler::new(),
157 last_clock_values,
158 topo_signals,
159 domain_kinds,
160 event_info,
161 signal_to_id,
162 }
163 }
164
165 pub fn add_clock(
166 &mut self,
167 event: B::Event,
168 signal: SignalRef,
169 period: u64,
170 initial_delay: u64,
171 ) {
172 let event_id = event.id();
173 if event_id >= self.scheduler.clocks.len() {
174 self.scheduler.clocks.resize(event_id + 1, None);
175 }
176 self.scheduler.clocks[event_id] = Some(ClockDef { period });
177 self.scheduler.push(SimEvent {
178 time: initial_delay,
179 event_ref: event,
180 signal,
181 next_val: 1,
182 });
183 }
184
185 pub fn schedule(&mut self, event: B::Event, signal: SignalRef, time: u64, value: u8) {
186 self.scheduler.push(SimEvent {
187 time,
188 event_ref: event,
189 signal,
190 next_val: value,
191 });
192 }
193
194 pub fn step<E>(&mut self, executor: &mut E) -> Result<Option<u64>, SimulatorErrorCode>
195 where
196 E: SimulationExecutor<Backend = B>,
197 {
198 let (current_time, events_to_process) = match self.scheduler.pop_all_at_next_time() {
199 Some(events) => events,
200 None => return Ok(None),
201 };
202 self.scheduler.time = current_time;
203
204 let num_events = executor.backend().num_events();
205 for event in &events_to_process {
206 executor.backend_mut().set(event.signal, event.next_val);
207 }
208
209 let mut triggered_domains = BitSet::with_capacity(num_events);
210 let mut discovered_in_this_step = BitSet::with_capacity(num_events);
211 let mut scheduled_trigger_ids = BitSet::with_capacity(num_events);
212 let mut has_scheduled_event_signal = false;
213 executor.backend_mut().clear_triggered_bits();
214
215 for event in &events_to_process {
216 if let Some(&id) = self.signal_to_id.get(&event.signal) {
217 has_scheduled_event_signal = true;
218 let was_nonzero = self.last_clock_values.contains(id);
219 let is_nonzero = event.next_val != 0;
220 let triggered = match self.domain_kinds[id] {
221 Some(DomainKind::ClockPosedge | DomainKind::ResetAsyncHigh) => {
222 !was_nonzero && is_nonzero
223 }
224 Some(DomainKind::ClockNegedge | DomainKind::ResetAsyncLow) => {
225 was_nonzero && !is_nonzero
226 }
227 _ => !was_nonzero && is_nonzero,
228 };
229 if triggered {
230 scheduled_trigger_ids.insert(id);
231 executor.backend_mut().mark_triggered_bit(id);
232 }
233 }
234 }
235
236 executor.eval_comb()?;
237 if has_scheduled_event_signal {
238 if scheduled_trigger_ids.is_empty() {
244 self.replace_triggers_with_stable_edges(executor.backend_mut());
245 } else {
246 executor.backend_mut().clear_triggered_bits();
247 for id in scheduled_trigger_ids.iter() {
248 executor.backend_mut().mark_triggered_bit(id);
249 }
250 }
251 }
252
253 let mut comb_already_done = false;
254 loop {
255 let mut any_new_outer_loop_trigger = false;
256 let mut newly_triggered = Vec::new();
257
258 loop {
259 let mut any_new_sequential_trigger = false;
260 let marked_bits = executor.backend().get_triggered_bits();
261 executor.backend_mut().clear_triggered_bits();
262
263 let mut can_use_eval_apply =
264 triggered_domains.is_empty() && marked_bits.count() == 1;
265 if can_use_eval_apply {
266 let single_id = marked_bits.iter().next().expect("one marked trigger");
267 let info = self.event_info[single_id];
268 can_use_eval_apply = !info.is_cascaded;
269 if can_use_eval_apply {
270 if let Some(event) = info.eval_ff_event {
271 discovered_in_this_step.insert(single_id);
272 triggered_domains.insert(info.canonical_id);
273 any_new_outer_loop_trigger = true;
274 executor.stage_external_event(event, current_time)?;
275 executor.eval_apply_ff_at(event)?;
276 executor.fire_external_event(event, current_time)?;
277 executor.eval_comb()?;
278 if has_scheduled_event_signal {
279 self.replace_triggers_with_stable_edges(executor.backend_mut());
280 }
281 comb_already_done = true;
282 break;
283 }
284 }
285 }
286
287 for id in marked_bits.iter() {
288 if discovered_in_this_step.contains(id) {
289 continue;
290 }
291 discovered_in_this_step.insert(id);
292
293 let info = self.event_info[id];
294 if triggered_domains.contains(info.canonical_id) {
295 continue;
296 }
297 triggered_domains.insert(info.canonical_id);
298 any_new_sequential_trigger = true;
299 newly_triggered.push(info.canonical_id);
300
301 if let Some(event) = info.eval_only_event {
302 executor.stage_external_event(
303 info.eval_ff_event.unwrap_or(event),
304 current_time,
305 )?;
306 executor.eval_only_ff_at(event)?;
307 } else if let Some(event) = info.eval_ff_event {
308 executor.stage_external_event(event, current_time)?;
309 executor.eval_apply_ff_at(event)?;
310 } else {
311 unreachable!(
312 "FF trigger discovered without a corresponding execution unit"
313 );
314 }
315 }
316
317 if !any_new_sequential_trigger {
318 break;
319 }
320 }
321
322 if newly_triggered.is_empty() && !any_new_outer_loop_trigger {
323 break;
324 }
325
326 for id in &newly_triggered {
327 if let Some(event) = self.event_info[*id].apply_event {
328 executor.apply_ff_at(event)?;
329 }
330 }
331 for id in &newly_triggered {
332 if let Some(event) = self.event_info[*id].eval_ff_event {
333 executor.fire_external_event(event, current_time)?;
334 }
335 }
336
337 if comb_already_done {
338 comb_already_done = false;
339 } else {
340 executor.eval_comb()?;
341 if has_scheduled_event_signal {
342 self.replace_triggers_with_stable_edges(executor.backend_mut());
343 }
344 }
345 }
346
347 for (signal, id, _) in &self.topo_signals {
348 if *id == usize::MAX {
349 continue;
350 }
351 let value: u8 = executor.backend().get_as(*signal);
352 if value != 0 {
353 self.last_clock_values.insert(*id);
354 } else {
355 self.last_clock_values.remove(*id);
356 }
357 }
358
359 for event in &events_to_process {
360 let event_id = event.event_ref.id();
361 if let Some(Some(clock)) = self.scheduler.clocks.get(event_id) {
362 self.scheduler.push(SimEvent {
363 time: current_time + clock.period / 2,
364 event_ref: event.event_ref,
365 signal: event.signal,
366 next_val: 1 - event.next_val,
367 });
368 }
369 }
370
371 executor.finish_timed_step(current_time);
372 Ok(Some(current_time))
373 }
374
375 pub fn time(&self) -> u64 {
376 self.scheduler.time
377 }
378
379 pub fn set_time(&mut self, time: u64) {
380 self.scheduler.time = time;
381 }
382
383 pub fn next_event_time(&self) -> Option<u64> {
384 self.scheduler.next_event_time()
385 }
386}