1use super::*;
2
3#[cfg(test)]
4mod tests;
5mod value;
6mod eval;
7pub mod ext;
8
9pub use value::Value;
10use ext::*;
11
12use std::collections::BTreeMap;
13use std::collections::BTreeSet;
14use std::sync::Arc;
15use std::time::Duration;
16use std::time::SystemTime;
17
18pub type NetId = usize;
19pub type CombId = usize;
20pub type ExtId = usize;
21pub type RegId = usize;
22
23#[derive(Debug)]
24pub struct RegInfo {
25 set_net_id: NetId,
26 val_net_id: NetId,
27 reset: Option<Arc<Expr>>,
28}
29
30#[derive(Debug)]
31pub struct Dependents {
32 pub combs: Vec<CombId>,
33 pub ext_ports: Vec<(ExtId, PortName)>,
34}
35
36#[derive(Debug)]
37pub struct SimCircuit {
38 pub nets: Vec<Net>, pub combs: Vec<Comb>, pub regs: Vec<RegInfo>, pub dependents: Vec<Dependents>, pub net_id_by_ext_port: BTreeMap<(ExtId, PortName), NetId>,
45
46 pub net_id_by_path: BTreeMap<Path, NetId>,
47 pub ext_id_by_path: BTreeMap<Path, ExtId>,
48}
49
50fn make_net_id_by_path(circuit: &Circuit, nets: &[Net]) -> BTreeMap<Path, NetId> {
51 circuit
60 .paths()
61 .iter()
62 .map(|path| {
63 for (net_id, net) in nets.iter().enumerate() {
64 if net.contains(path.clone()) {
65 return (path.clone(), net_id);
66 }
67 }
68 unreachable!()
69 })
70 .collect()
71}
72
73fn make_regs(circuit: &Circuit, net_id_by_path: &BTreeMap<Path, NetId>) -> Vec<RegInfo> {
74 circuit
78 .regs()
79 .iter()
80 .cloned()
81 .map(|path| {
82 let set_net_id = net_id_by_path[&path.set()];
83 let val_net_id = net_id_by_path[&path.clone()];
84 let reset = circuit.reset_for_reg(path);
85
86 RegInfo {
87 set_net_id,
88 val_net_id,
89 reset,
90 }
91 })
92 .collect()
93}
94
95fn make_combs(circuit: &Circuit, net_id_by_path: &BTreeMap<Path, NetId>) -> Vec<Comb> {
96 circuit
104 .wires()
105 .iter()
106 .cloned()
107 .map(|(path, Wire(_loc, target, expr, wiretype))| {
108 let abs_target = path.clone().join(target);
109 let abs_expr = expr.rebase(path.clone());
110 let target_net_id = match wiretype {
111 WireType::Direct => net_id_by_path[&abs_target],
112 WireType::Latch => net_id_by_path[&abs_target.set()],
113 _ => todo!(), };
115 (target_net_id, abs_expr.references_to_nets(&net_id_by_path), wiretype)
116 })
117 .filter(|(target_net_id, expr, _wiretype)| {
118 if let Expr::Net(_loc, _typ, net_id) = &**expr {
119 target_net_id != net_id
120 } else {
121 true
122 }
123 })
124 .map(|(target_net_id, expr, _wiretype)| {
125 Comb(target_net_id, expr)
126 })
127 .collect()
128}
129
130fn make_ext_id_by_path(
131 circuit: &Circuit,
132 net_id_by_path: &BTreeMap<Path, NetId>,
133 nets: &[Net],
134) -> BTreeMap<Path, ExtId> {
135 let mut ext_id_by_path: BTreeMap<Path, ExtId> = BTreeMap::new();
136 let mut ext_dependencies = vec![vec![]; nets.len()];
137
138 for (ext_id, path) in circuit.exts().iter().enumerate() {
139 ext_id_by_path.insert(path.clone(), ext_id);
140
141 let ext_component: &Component = &*circuit.component(path.clone()).unwrap();
142 for child in ext_component.children() {
143 if let Component::Incoming(_loc, name, _typ) = &*child {
144 let incoming_path = path.join(name.to_string().into());
145 let net_id = net_id_by_path[&incoming_path];
146 ext_dependencies[net_id].push((ext_id, name.to_string()));
147 }
148 }
149 }
150
151 ext_id_by_path
152}
153
154fn make_dependents(
155 circuit: &Circuit,
156 net_ids: &[NetId],
157 combs: &[Comb],
158 net_id_by_path: &BTreeMap<Path, NetId>,
159 ext_id_by_path: &BTreeMap<Path, ExtId>,
160) -> Vec<Dependents> {
161 net_ids.iter()
162 .map(|net_id| {
163 let combs: Vec<CombId> = combs.iter().enumerate().filter(|(_comb_id, comb)| comb.depends_on(*net_id)).map(|(comb_id, _comb)| comb_id).collect();
164 let mut ext_ports: Vec<(ExtId, PortName)> = vec![];
165 for path in circuit.exts() {
166 let ext_id = ext_id_by_path[&path];
167 let ext_component = circuit.component(path.clone()).unwrap();
168 match &*ext_component {
169 Component::Ext(_loc, _name, children) => {
170 for child in children {
171 match &**child {
172 Component::Incoming(_loc, name, _typ) => {
173 let port_path = path.join(name.clone().into());
174 let port_net_id = net_id_by_path[&port_path];
175 if port_net_id == *net_id {
176 ext_ports.push((ext_id, name.to_string()))
177 }
178 },
179 _ => (),
180 }
181 }
182 },
183 _ => unreachable!(),
184 }
185 }
186
187 let dependents = Dependents {
188 combs,
189 ext_ports,
190 };
191 dependents
192 })
193 .collect()
194}
195
196fn make_net_id_by_ext_port(
197 circuit: &Circuit,
198 net_id_by_path: &BTreeMap<Path, NetId>,
199 ext_id_by_path: &BTreeMap<Path, ExtId>,
200) -> BTreeMap<(ExtId, PortName), NetId> {
201 let mut net_id_by_ext_port = BTreeMap::new();
202
203 for path in circuit.exts() {
204 let ext_id = ext_id_by_path[&path];
205 let ext_component = circuit.component(path.clone()).unwrap();
206 match &*ext_component {
207 Component::Ext(_loc, _name, children) => {
208 for child in children {
209 match &**child {
210 Component::Outgoing(_loc, name, _typ) => {
211 let port_path = path.join(name.clone().into());
212 let net_id = net_id_by_path[&port_path];
213 net_id_by_ext_port.insert((ext_id, name.clone()), net_id);
214 },
215 _ => (),
216 }
217 }
218 },
219 _ => unreachable!(),
220 }
221 }
222 net_id_by_ext_port
223}
224
225impl SimCircuit {
226 pub fn new(circuit: &Circuit) -> SimCircuit {
227 let nets = nets(circuit);
228 let net_ids: Vec<NetId> = (0..nets.len()).into_iter().collect();
229 let net_id_by_path: BTreeMap<Path, NetId> = make_net_id_by_path(&circuit, &nets);
230 let regs: Vec<RegInfo> = make_regs(&circuit, &net_id_by_path);
231 let combs: Vec<Comb> = make_combs(&circuit, &net_id_by_path);
232 let ext_id_by_path = make_ext_id_by_path(&circuit, &net_id_by_path, &nets);
233
234 let dependents: Vec<Dependents> = make_dependents(
235 &circuit,
236 &net_ids,
237 &combs,
238 &net_id_by_path,
239 &ext_id_by_path,
240 );
241
242 let net_id_by_ext_port = make_net_id_by_ext_port(
243 &circuit,
244 &net_id_by_path,
245 &ext_id_by_path,
246 );
247
248 SimCircuit {
249 nets,
250 combs,
251 regs,
252
253 dependents,
254 net_id_by_ext_port,
255
256 net_id_by_path,
257 ext_id_by_path,
258 }
259 }
260
261 pub fn net_ids(&self) -> Vec<NetId> {
262 (0..self.nets.len()).into_iter().collect()
263 }
264}
265
266pub struct Sim {
267 sim_circuit: Arc<SimCircuit>,
268 net_values: Vec<Value>,
269 exts: Vec<Option<Box<dyn ExtInstance>>>, clock_ticks: u64,
271 start_time: SystemTime,
272 clock_freq_cap: Option<f64>,
273}
274
275impl Sim {
276 pub fn new(circuit: &Circuit) -> Sim {
277 Sim::new_with_exts(circuit, BTreeMap::new())
278 }
279
280 pub fn new_with_exts(circuit: &Circuit, linked_exts: BTreeMap<Path, Box<dyn ExtInstance>>) -> Sim {
281 let sim_circuit = Arc::new(SimCircuit::new(circuit));
282 let net_ids = sim_circuit.net_ids();
283 let net_values: Vec<Value> = net_ids.iter().map(|_net| Value::X).collect();
284
285 let mut ext_id_by_path: BTreeMap<Path, ExtId> = BTreeMap::new();
286 let mut exts: Vec<Option<Box<dyn ExtInstance>>> = vec![];
287
288 for (ext_id, path) in circuit.exts().iter().enumerate() {
289 ext_id_by_path.insert(path.clone(), ext_id);
290 exts.push(None);
291 }
292
293 let mut sim = Sim {
294 sim_circuit,
295 net_values,
296 exts,
297 start_time: SystemTime::now(),
298 clock_ticks: 0,
299 clock_freq_cap: None,
300 };
301 for (path, ext) in linked_exts {
302 sim = sim.ext(path, ext);
303 }
304 sim.broadcast_update_constants();
305 sim
306 }
307
308 pub fn net_values(&self) -> BTreeMap<NetId, Value> {
309 self.net_values.iter().cloned().enumerate().collect()
310 }
311
312 pub fn net(&self, net_id: NetId) -> &Net {
313 &self.sim_circuit.nets[net_id]
314 }
315
316 pub fn cap_clock_freq(mut self, freq: f64) -> Self {
317 self.clock_freq_cap = Some(freq);
318 self
319 }
320
321 fn ext<P: Into<Path>>(mut self, path: P, ext_inst: Box<dyn ExtInstance>) -> Self {
322 let path: Path = path.into();
323 if let Some(ext_id) = self.sim_circuit.ext_id_by_path.get(&path.clone()) {
324 let ext = &mut self.exts[*ext_id];
325 *ext = Some(ext_inst);
326 self
327 } else {
328 panic!("No such path for linkage: {path}")
329 }
330 }
331
332 pub(crate) fn poke_net(&mut self, net_id: NetId, value: Value) {
333 self.net_values[net_id] = value.clone();
334
335 let dependents = &self.sim_circuit.clone().dependents[net_id];
337 for comb_id in dependents.combs.iter() {
338 let comb = &self.sim_circuit.clone().combs[*comb_id];
339 let Comb(target_net_id, expr) = comb;
340 let value = expr.eval(&self);
341 self.poke_net(*target_net_id, value);
342 }
343
344 for (ext_id, port_name) in dependents.ext_ports.iter() {
345 if let Some(ext) = &mut self.exts[*ext_id].as_mut() {
346 for (updated_port_name, updated_value) in ext.update(port_name, value.clone()) {
347 let net_id = self.sim_circuit.net_id_by_ext_port[&(*ext_id, updated_port_name)];
348 self.poke_net(net_id, updated_value);
349 }
350 }
351 }
352 }
353
354 pub(crate) fn peek_net(&self, net_id: NetId) -> Value {
355 self.net_values[net_id].clone()
356 }
357
358 fn net_id(&self, path: Path) -> NetId {
359 if let Some(net_id) = self.sim_circuit.net_id_by_path.get(&path) {
360 *net_id
361 } else {
362 panic!("No net for {path}")
363 }
364 }
365
366 pub fn peek<P: Into<Path>>(&self, path: P) -> Value {
367 let net_id = self.net_id(path.into());
368 self.net_values[net_id].clone()
369 }
370
371 pub fn poke<P: Into<Path>>(&mut self, path: P, value: Value) {
372 let net_id = self.net_id(path.into());
373 self.poke_net(net_id, value);
374 }
375
376 pub fn type_of<P: Into<Path>>(&self, path: P) -> Type {
377 let net_id = self.net_id(path.into());
378 let Net(_driver, _terminals, typ) = &self.sim_circuit.nets[net_id];
379 typ.clone()
380 }
381
382 fn broadcast_update_constants(&mut self) {
383 for Comb(target_net_id, expr) in self.sim_circuit.clone().combs.iter() {
384 if expr.is_constant() {
385 let value = expr.eval(&self);
386 self.poke_net(*target_net_id, value);
387 }
388 }
389 }
390
391 pub fn clock(&mut self) {
392 self.clock_ticks += 1;
393
394 if let Some(clock_freq_cap) = self.clock_freq_cap {
396 let mut clock_freq = self.clocks_per_second();
397 while clock_freq.is_finite() && clock_freq > clock_freq_cap {
398 clock_freq = self.clocks_per_second();
399 }
400 }
401
402let mut updates = vec![];
407 for reginfo in &self.sim_circuit.clone().regs {
408 let value = self.peek_net(reginfo.set_net_id);
409 updates.push((reginfo.val_net_id, value));
410 }
411 for (val_net_id, value) in updates {
412 self.poke_net(val_net_id, value);
413 }
414
415 for ext in &mut self.exts {
416 if let Some(ext) = ext {
417 ext.clock();
418 } else {
419 panic!("Unlinked ext")
421 }
422 }
423 }
424
425 pub fn reset(&mut self) {
426 for reginfo in &self.sim_circuit.clone().regs {
427 if let Some(reset) = ®info.reset {
428 self.poke_net(reginfo.val_net_id, reset.eval(&self));
429 }
430 }
431
432 for ext in &mut self.exts {
433 if let Some(ext) = ext {
434 ext.reset();
435 } else {
436 panic!("Unlinked ext")
438 }
439 }
440 }
441
442 pub fn clocks_per_second(&self) -> f64 {
443 let end_time = SystemTime::now();
444 let duration: Duration = end_time.duration_since(self.start_time).unwrap();
445 1_000_000.0 * self.clock_ticks as f64 / duration.as_micros() as f64
446 }
447}
448
449#[derive(Debug, Clone)]
450pub struct Comb(NetId, Arc<Expr>);
451
452impl Comb {
453 pub fn depends_on(&self, net_id: NetId) -> bool {
454 let Comb(_net_id, expr) = self;
455 expr.depends_on_net(net_id)
456 }
457}
458
459impl std::fmt::Debug for Sim {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
461 for (net_id, value) in self.net_values.iter().enumerate() {
462 let net = &self.sim_circuit.nets[net_id];
463 write!(f, " {:>5} ", format!("{value:?}"))?;
464 writeln!(f, "{}", net.terminals().iter().map(|t| t.to_string()).collect::<Vec<String>>().join(" "))?;
465 }
466
467 Ok(())
468 }
469}
470
471pub fn nets(circuit: &Circuit) -> Vec<Net> {
472 let mut immediate_driver_for: BTreeMap<Path, Path> = BTreeMap::new();
473
474 for (path, Wire(_loc, target, expr, wire_type)) in circuit.wires() {
475 let abs_expr = expr.rebase(path.clone());
476 let target_terminal: Path = match wire_type {
477 WireType::Direct => path.join(target).clone(),
478 WireType::Latch => path.join(target).set(),
479 WireType::Proc => path.join(target).set(),
480 };
481 if let Expr::Reference(_loc, _typ, driver) = &*abs_expr {
482 immediate_driver_for.insert(target_terminal.clone(), driver.clone());
483 }
484 }
485
486 let mut drivers: BTreeSet<Path> = BTreeSet::new();
487 for terminal in circuit.paths() {
488 drivers.insert(driver_for(terminal, &immediate_driver_for));
489 }
490
491 let mut nets: BTreeMap<Path, Net> = BTreeMap::new();
492 for driver in &drivers {
493 let component = circuit.component(driver.clone()).unwrap();
494 let typ = component.type_of().unwrap();
495 nets.insert(driver.clone(), Net::from(driver.clone(), typ));
496 }
497
498 for terminal in circuit.paths() {
499 let driver = driver_for(terminal.clone(), &immediate_driver_for);
500 let net = nets.get_mut(&driver).unwrap();
501 net.add(terminal);
502 }
503
504 let nets: Vec<Net> = nets.values().into_iter().cloned().collect();
505 nets
506}
507
508fn driver_for(terminal: Path, immediate_driver_for: &BTreeMap<Path, Path>) -> Path {
509 let mut driver: &Path = &terminal;
510 while let Some(immediate_driver) = &immediate_driver_for.get(driver) {
511 driver = immediate_driver;
512 }
513 driver.clone()
514}
515
516impl Net {
517 fn from(terminal: Path, typ: Type) -> Net {
518 Net(terminal, vec![], typ)
519 }
520
521 pub fn add(&mut self, terminal: Path) {
522 if self.0 != terminal {
523 self.1.push(terminal);
524 self.1.sort();
525 self.1.dedup();
526 }
527 }
528
529 pub fn driver(&self) -> Path {
530 self.0.clone()
531 }
532
533 pub fn drivees(&self) -> &[Path] {
534 &self.1
535 }
536
537 pub fn terminals(&self) -> Vec<Path> {
538 let mut results = vec![self.0.clone()];
539 for terminal in &self.1 {
540 results.push(terminal.clone());
541 }
542 results
543 }
544
545 pub fn contains(&self, terminal: Path) -> bool {
546 if terminal == self.0 {
547 true
548 } else {
549 self.1.contains(&terminal)
550 }
551 }
552}
553
554#[derive(Clone)]
555pub struct Net(Path, Vec<Path>, Type);
556
557impl std::fmt::Debug for Net {
558 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
559 write!(f, "Net({} {})", self.0, self.1.iter().map(|path| path.to_string()).collect::<Vec<_>>().join(" "))
560 }
561}
562
563impl Expr {
564 pub fn rebase(&self, current_path: Path) -> Arc<Expr> {
565 self.rebase_rec(current_path, &BTreeSet::new())
566 }
567
568 fn rebase_rec(&self, current_path: Path, shadowed: &BTreeSet<Path>) -> Arc<Expr> {
569 Arc::new(match self {
570 Expr::Reference(loc, typ, path) => {
571 if !shadowed.contains(path) {
572 Expr::Reference(loc.clone(), typ.clone(), current_path.join(path.clone()))
573 } else {
574 self.clone()
575 }
576 },
577 Expr::Net(_loc, _typ, _net_id) => panic!("rebase() only works on reference expressions."),
578 Expr::Word(_loc, _typ, _width, _value) => self.clone(),
579 Expr::Enum(_loc, _typ, _typedef, _name) => self.clone(),
580 Expr::Ctor(loc, typ, name, es) => Expr::Ctor(loc.clone(), typ.clone(), name.clone(), es.iter().map(|e| e.rebase_rec(current_path.clone(), shadowed)).collect()),
581 Expr::Struct(loc, typ, fields) => {
582 Expr::Struct(
583 loc.clone(),
584 typ.clone(),
585 fields
586 .iter()
587 .map(|(name, e)| (name.clone(), e.rebase_rec(current_path.clone(), shadowed)))
588 .collect(),
589 )
590 },
591 Expr::Let(loc, typ, name, e, b) => {
592 let new_e = e.rebase_rec(current_path.clone(), shadowed);
593 let mut new_shadowed = shadowed.clone();
594 new_shadowed.insert(name.clone().into());
595 let new_b = b.rebase_rec(current_path, &new_shadowed);
596 Expr::Let(loc.clone(), typ.clone(), name.clone(), new_e, new_b)
597 },
598 Expr::Match(loc, typ, e, arms) => {
599 let new_arms = arms.iter().map(|MatchArm(pat, e)| {
600 let mut new_shadowed = shadowed.clone();
601 new_shadowed.extend(pat.bound_vars());
602 MatchArm(pat.clone(), e.rebase_rec(current_path.clone(), &new_shadowed))
603
604 }).collect();
605 Expr::Match(
606 loc.clone(),
607 typ.clone(),
608 e.rebase_rec(current_path.clone(), shadowed),
609 new_arms,
610 )
611 },
612 Expr::UnOp(loc, typ, op, e) => Expr::UnOp(loc.clone(), typ.clone(), *op, e.rebase_rec(current_path, shadowed)),
613 Expr::BinOp(loc, typ, op, e1, e2) => {
614 Expr::BinOp(
615 loc.clone(),
616 typ.clone(),
617 *op,
618 e1.rebase_rec(current_path.clone(), shadowed),
619 e2.rebase_rec(current_path, shadowed),
620 )
621 },
622 Expr::If(loc, typ, cond, e1, e2) => {
623 Expr::If(
624 loc.clone(),
625 typ.clone(),
626 cond.rebase_rec(current_path.clone(), shadowed),
627 e1.rebase_rec(current_path.clone(), shadowed),
628 e2.rebase_rec(current_path, shadowed),
629 )
630 },
631 Expr::Mux(loc, typ, cond, e1, e2) => {
632 Expr::Mux(
633 loc.clone(),
634 typ.clone(),
635 cond.rebase_rec(current_path.clone(), shadowed),
636 e1.rebase_rec(current_path.clone(), shadowed),
637 e2.rebase_rec(current_path, shadowed),
638 )
639 },
640 Expr::Cat(loc, typ, es) => {
641 Expr::Cat(
642 loc.clone(),
643 typ.clone(),
644 es.iter().map(|e| e.rebase_rec(current_path.clone(), shadowed)).collect(),
645 )
646 },
647 Expr::Sext(loc, typ, e) => Expr::Sext(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed)),
648 Expr::ToWord(loc, typ, e) => Expr::ToWord(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed)),
649 Expr::Vec(loc, typ, es) => Expr::Vec(loc.clone(), typ.clone(), es.iter().map(|e| e.rebase_rec(current_path.clone(), shadowed)).collect()),
650 Expr::IdxField(loc, typ, e, field) => Expr::IdxField(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), field.clone()),
651 Expr::Idx(loc, typ, e, i) => Expr::Idx(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), *i),
652 Expr::IdxRange(loc, typ, e, j, i) => Expr::IdxRange(loc.clone(), typ.clone(), e.rebase_rec(current_path, shadowed), *j, *i),
653 Expr::Call(loc, typ, fndef, es) => {
654 Expr::Call(
655 loc.clone(),
656 typ.clone(),
657 fndef.clone(),
658 es.iter().map(|e| e.rebase_rec(current_path.clone(), shadowed)).collect(),
659 )
660 },
661 Expr::Hole(loc, typ, name) => Expr::Hole(loc.clone(), typ.clone(), name.clone()),
662 })
663 }
664
665 fn references_to_nets(&self, net_id_by_path: &BTreeMap<Path, NetId>) -> Arc<Expr> {
666 self.references_to_nets_rec(net_id_by_path, &BTreeSet::new())
667 }
668
669 fn references_to_nets_rec(&self, net_id_by_path: &BTreeMap<Path, NetId>, shadowed: &BTreeSet<Path>) -> Arc<Expr> {
670 Arc::new(match self {
671 Expr::Reference(loc, typ, path) => {
672 if !shadowed.contains(path) {
673 Expr::Net(loc.clone(), typ.clone(), net_id_by_path[path])
674 } else {
675 self.clone()
676 }
677 },
678 Expr::Net(_loc, _typ, _net_id) => panic!("references_to_nets() only works on reference expressions."),
679 Expr::Word(_loc, _typ, _width, _value) => self.clone(),
680 Expr::Enum(_loc, _typ, _typedef, _name) => self.clone(),
681 Expr::Ctor(loc, typ, name, es) => {
682 Expr::Ctor(
683 loc.clone(),
684 typ.clone(),
685 name.clone(),
686 es.iter().map(|e| e.references_to_nets_rec(net_id_by_path, shadowed)).collect(),
687 )
688 },
689 Expr::Struct(loc, typ, fields) => {
690 Expr::Struct(
691 loc.clone(),
692 typ.clone(),
693 fields
694 .iter()
695 .map(|(name, e)| (name.clone(), e.references_to_nets_rec(net_id_by_path, shadowed)))
696 .collect(),
697 )
698 },
699 Expr::Let(loc, typ, name, e, b) => {
700 let new_e = e.references_to_nets_rec(net_id_by_path, shadowed);
701 let mut new_shadowed = shadowed.clone();
702 new_shadowed.insert(name.clone().into());
703 let new_b = b.references_to_nets_rec(net_id_by_path, &new_shadowed);
704 Expr::Let(loc.clone(), typ.clone(), name.clone(), new_e, new_b)
705 },
706 Expr::UnOp(loc, typ, op, e) => Expr::UnOp(loc.clone(), typ.clone(), *op, e.references_to_nets_rec(net_id_by_path, shadowed)),
707 Expr::BinOp(loc, typ, op, e1, e2) => {
708 Expr::BinOp(
709 loc.clone(),
710 typ.clone(),
711 *op,
712 e1.references_to_nets_rec(net_id_by_path, shadowed),
713 e2.references_to_nets_rec(net_id_by_path, shadowed),
714 )
715 },
716 Expr::If(loc, typ, cond, e1, e2) => {
717 Expr::If(
718 loc.clone(),
719 typ.clone(),
720 cond.references_to_nets_rec(net_id_by_path, shadowed),
721 e1.references_to_nets_rec(net_id_by_path, shadowed),
722 e2.references_to_nets_rec(net_id_by_path, shadowed),
723 )
724 },
725 Expr::Match(loc, typ, e, arms) => {
726 let new_arms = arms.iter().map(|MatchArm(pat, e)| {
727 let mut new_shadowed = shadowed.clone();
728 new_shadowed.extend(pat.bound_vars());
729 MatchArm(pat.clone(), e.references_to_nets_rec(net_id_by_path, &new_shadowed))
730
731 }).collect();
732 Expr::Match(
733 loc.clone(),
734 typ.clone(),
735 e.references_to_nets_rec(net_id_by_path, shadowed),
736 new_arms,
737 )
738 },
739 Expr::Mux(loc, typ, cond, e1, e2) => {
740 Expr::Mux(
741 loc.clone(),
742 typ.clone(),
743 cond.references_to_nets_rec(net_id_by_path, shadowed),
744 e1.references_to_nets_rec(net_id_by_path, shadowed),
745 e2.references_to_nets_rec(net_id_by_path, shadowed),
746 )
747 },
748 Expr::Cat(loc, typ, es) => {
749 Expr::Cat(
750 loc.clone(),
751 typ.clone(),
752 es.iter().map(|e| e.references_to_nets_rec(net_id_by_path, shadowed)).collect(),
753 )
754 },
755 Expr::Sext(loc, typ, e) => Expr::Sext(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed)),
756 Expr::ToWord(loc, typ, e) => Expr::ToWord(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed)),
757 Expr::Vec(loc, typ, es) => Expr::Vec(loc.clone(), typ.clone(), es.iter().map(|e| e.references_to_nets_rec(net_id_by_path, shadowed)).collect()),
758 Expr::IdxField(loc, typ, e, field) => Expr::IdxField(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), field.clone()),
759 Expr::Idx(loc, typ, e, i) => Expr::Idx(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), *i),
760 Expr::IdxRange(loc, typ, e, j, i) => Expr::IdxRange(loc.clone(), typ.clone(), e.references_to_nets_rec(net_id_by_path, shadowed), *j, *i),
761 Expr::Call(loc, typ, fndef, es) => {
762 Expr::Call(
763 loc.clone(),
764 typ.clone(),
765 fndef.clone(),
766 es.iter().map(|e| e.references_to_nets_rec(net_id_by_path, shadowed)).collect(),
767 )
768 },
769 Expr::Hole(loc, typ, name) => Expr::Hole(loc.clone(), typ.clone(), name.clone()),
770 })
771 }
772}