1use std::{borrow::Cow, hash::Hash};
2
3use crate::{ControlNet, Design, Net, TargetCellPurity, Trit, Value};
4
5mod decision;
6mod flip_flop;
7mod memory;
8mod io_buffer;
9mod target;
10mod instance;
11
12pub use decision::{MatchCell, AssignCell};
13pub use flip_flop::FlipFlop;
14pub use memory::{Memory, MemoryWritePort, MemoryReadPort, MemoryReadFlipFlop, MemoryPortRelation};
15pub use io_buffer::IoBuffer;
16pub use target::TargetCell;
17pub use instance::Instance;
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub(crate) enum CellRepr {
26 Const(Trit),
30
31 Void,
37
38 Skip(u32),
41
42 Buf(Net),
43 Not(Net),
44 And(Net, Net),
45 Or(Net, Net),
46 Xor(Net, Net),
47 Mux(Net, Net, Net), Adc(Net, Net, Net), Aig(Net, bool, Net, bool),
50
51 Boxed(Box<Cell>),
52}
53
54#[derive(Clone, Debug, PartialEq, Eq, Hash)]
64pub enum Cell {
65 Const(Trit),
66 Buf(Value),
67 Not(Value),
68 And(Value, Value),
73 Or(Value, Value),
78 Xor(Value, Value),
79 Mux(Net, Value, Value),
85 Adc(Value, Value, Net), Aig(ControlNet, ControlNet),
97
98 Eq(Value, Value),
99 ULt(Value, Value),
100 SLt(Value, Value),
101
102 Shl(Value, Value, u32),
114 UShr(Value, Value, u32),
118 SShr(Value, Value, u32),
127 XShr(Value, Value, u32),
131
132 Mul(Value, Value),
134 UDiv(Value, Value),
135 UMod(Value, Value),
136 SDivTrunc(Value, Value),
137 SDivFloor(Value, Value),
138 SModTrunc(Value, Value),
139 SModFloor(Value, Value),
140
141 Match(MatchCell),
142 Assign(AssignCell),
143
144 Dff(FlipFlop),
145 Memory(Memory),
146 IoBuf(IoBuffer),
147 Target(TargetCell),
148 Other(Instance),
149
150 Input(String, usize),
156 Output(String, Value),
162 Name(String, Value),
174 Debug(String, Value),
186}
187
188impl Cell {
189 pub fn validate(&self, design: &Design) {
190 match self {
191 Cell::Const(_) => (),
192 Cell::Buf(_) => (),
193 Cell::Not(_) => (),
194 Cell::Aig(..) => (),
195 Cell::And(arg1, arg2)
196 | Cell::Or(arg1, arg2)
197 | Cell::Xor(arg1, arg2)
198 | Cell::Mux(_, arg1, arg2)
199 | Cell::Adc(arg1, arg2, _)
200 | Cell::Eq(arg1, arg2)
201 | Cell::ULt(arg1, arg2)
202 | Cell::Mul(arg1, arg2)
203 | Cell::UDiv(arg1, arg2)
204 | Cell::UMod(arg1, arg2) => assert_eq!(arg1.len(), arg2.len()),
205 Cell::SLt(arg1, arg2)
206 | Cell::SDivTrunc(arg1, arg2)
207 | Cell::SDivFloor(arg1, arg2)
208 | Cell::SModTrunc(arg1, arg2)
209 | Cell::SModFloor(arg1, arg2) => {
210 assert_eq!(arg1.len(), arg2.len());
211 assert!(!arg1.is_empty());
212 }
213
214 Cell::Shl(..) => (),
215 Cell::UShr(..) => (),
216 Cell::SShr(arg1, _, _) => assert!(!arg1.is_empty()),
217 Cell::XShr(..) => (),
218
219 Cell::Match(match_cell) => {
220 for alternates in &match_cell.patterns {
221 for pattern in alternates {
222 assert_eq!(match_cell.value.len(), pattern.len());
223 }
224 }
225 }
226 Cell::Assign(assign_cell) => {
227 assert!(assign_cell.value.len() >= assign_cell.update.len() + assign_cell.offset);
228 }
229
230 Cell::Dff(flip_flop) => {
231 assert_eq!(flip_flop.data.len(), flip_flop.init_value.len());
232 assert_eq!(flip_flop.data.len(), flip_flop.clear_value.len());
233 assert_eq!(flip_flop.data.len(), flip_flop.reset_value.len());
234 }
235 Cell::Memory(memory) => {
236 assert_eq!(memory.init_value.len(), memory.depth * memory.width);
237 for port in &memory.write_ports {
238 assert_eq!(port.data.len(), port.mask.len());
239 if memory.width == 0 {
240 assert_eq!(port.data.len(), 0);
241 } else {
242 assert_eq!(port.data.len() % memory.width, 0);
243 let wide_factor = port.data.len() / memory.width;
244 assert!(wide_factor.is_power_of_two());
245 assert_eq!(memory.depth % wide_factor, 0);
246 }
247 }
248 for port in &memory.read_ports {
249 if memory.width == 0 {
250 assert_eq!(port.data_len, 0);
251 } else {
252 assert_eq!(port.data_len % memory.width, 0);
253 let wide_factor = port.data_len / memory.width;
254 assert!(wide_factor.is_power_of_two());
255 assert_eq!(memory.depth % wide_factor, 0);
256 }
257 if let Some(ref flip_flop) = port.flip_flop {
258 assert_eq!(flip_flop.clear_value.len(), port.data_len);
259 assert_eq!(flip_flop.reset_value.len(), port.data_len);
260 assert_eq!(flip_flop.init_value.len(), port.data_len);
261 assert_eq!(flip_flop.relations.len(), memory.write_ports.len());
262 for (write_port_index, &relation) in flip_flop.relations.iter().enumerate() {
263 if relation != MemoryPortRelation::Undefined {
264 assert_eq!(memory.write_ports[write_port_index].clock, flip_flop.clock);
265 }
266 }
267 }
268 }
269 }
270 Cell::IoBuf(io_buffer) => {
271 assert_eq!(io_buffer.output.len(), io_buffer.io.len());
272 }
273 Cell::Target(target_cell) => {
274 let prototype = design.target_prototype(target_cell);
275 assert_eq!(target_cell.params.len(), prototype.params.len());
276 for (param, value) in prototype.params.iter().zip(target_cell.params.iter()) {
277 assert!(param.kind.is_valid(value));
278 }
279 assert_eq!(target_cell.inputs.len(), prototype.input_len);
280 assert_eq!(target_cell.output_len, prototype.output_len);
281 assert_eq!(target_cell.ios.len(), prototype.io_len);
282 let target = design.target().unwrap();
283 target.validate(design, target_cell);
284 }
285 Cell::Other(_instance) => {
286 }
288 Cell::Input(..) => (),
289 Cell::Output(..) => (),
290 Cell::Name(..) | Cell::Debug(..) => (),
291 }
292 }
293
294 pub fn slice(&self, range: impl std::ops::RangeBounds<usize> + Clone) -> Option<Cell> {
297 match self {
298 Cell::Buf(arg) => Some(Cell::Buf(arg.slice(range))),
299 Cell::Not(arg) => Some(Cell::Not(arg.slice(range))),
300 Cell::And(arg1, arg2) => Some(Cell::And(arg1.slice(range.clone()), arg2.slice(range))),
301 Cell::Or(arg1, arg2) => Some(Cell::Or(arg1.slice(range.clone()), arg2.slice(range))),
302 Cell::Xor(arg1, arg2) => Some(Cell::Xor(arg1.slice(range.clone()), arg2.slice(range))),
303 Cell::Mux(arg1, arg2, arg3) => Some(Cell::Mux(*arg1, arg2.slice(range.clone()), arg3.slice(range))),
304 Cell::Dff(flip_flop) => Some(Cell::Dff(flip_flop.slice(range))),
305 Cell::IoBuf(io_buffer) => Some(Cell::IoBuf(io_buffer.slice(range))),
306 _ => None,
307 }
308 }
309}
310
311impl<'a> From<&'a Cell> for Cow<'a, Cell> {
312 fn from(value: &'a Cell) -> Self {
313 Cow::Borrowed(value)
314 }
315}
316
317impl From<Cell> for Cow<'_, Cell> {
318 fn from(value: Cell) -> Self {
319 Cow::Owned(value)
320 }
321}
322
323impl CellRepr {
324 pub fn get(&self) -> Cow<'_, Cell> {
325 match *self {
326 CellRepr::Void => unreachable!("void cell"),
327 CellRepr::Skip(_) => unreachable!("skip cell"),
328
329 CellRepr::Const(trit) => Cow::Owned(Cell::Const(trit)),
330 CellRepr::Buf(arg) => Cow::Owned(Cell::Buf(Value::from(arg))),
331 CellRepr::Not(arg) => Cow::Owned(Cell::Not(Value::from(arg))),
332 CellRepr::And(arg1, arg2) => Cow::Owned(Cell::And(Value::from(arg1), Value::from(arg2))),
333 CellRepr::Or(arg1, arg2) => Cow::Owned(Cell::Or(Value::from(arg1), Value::from(arg2))),
334 CellRepr::Xor(arg1, arg2) => Cow::Owned(Cell::Xor(Value::from(arg1), Value::from(arg2))),
335 CellRepr::Mux(arg1, arg2, arg3) => Cow::Owned(Cell::Mux(arg1, Value::from(arg2), Value::from(arg3))),
336 CellRepr::Adc(arg1, arg2, arg3) => Cow::Owned(Cell::Adc(Value::from(arg1), Value::from(arg2), arg3)),
337 CellRepr::Aig(arg1, inv1, arg2, inv2) => {
338 Cow::Owned(Cell::Aig(ControlNet::from_net_invert(arg1, inv1), ControlNet::from_net_invert(arg2, inv2)))
339 }
340
341 CellRepr::Boxed(ref cell) => Cow::Borrowed(cell),
342 }
343 }
344}
345
346impl From<Cell> for CellRepr {
347 fn from(value: Cell) -> Self {
348 match value {
349 Cell::Buf(arg) if arg.len() == 1 => CellRepr::Buf(arg[0]),
350 Cell::Not(arg) if arg.len() == 1 => CellRepr::Not(arg[0]),
351 Cell::And(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::And(arg1[0], arg2[0]),
352 Cell::Or(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Or(arg1[0], arg2[0]),
353 Cell::Xor(arg1, arg2) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Xor(arg1[0], arg2[0]),
354 Cell::Mux(arg1, arg2, arg3) if arg2.len() == 1 && arg3.len() == 1 => CellRepr::Mux(arg1, arg2[0], arg3[0]),
355 Cell::Adc(arg1, arg2, arg3) if arg1.len() == 1 && arg2.len() == 1 => CellRepr::Adc(arg1[0], arg2[0], arg3),
356 Cell::Aig(arg1, arg2) => CellRepr::Aig(arg1.net(), arg1.is_negative(), arg2.net(), arg2.is_negative()),
357
358 cell => CellRepr::Boxed(Box::new(cell)),
359 }
360 }
361}
362
363impl CellRepr {
364 pub fn output_len(&self) -> usize {
365 match self {
366 CellRepr::Void => unreachable!("void cell"),
367 CellRepr::Skip(_) => unreachable!("skip cell"),
368
369 CellRepr::Const(_)
370 | CellRepr::Buf(..)
371 | CellRepr::Not(..)
372 | CellRepr::And(..)
373 | CellRepr::Or(..)
374 | CellRepr::Xor(..)
375 | CellRepr::Mux(..)
376 | CellRepr::Aig(..) => 1,
377 CellRepr::Adc(..) => 2,
378
379 CellRepr::Boxed(cell) => cell.output_len(),
380 }
381 }
382
383 pub(crate) fn visit(&self, mut f: impl FnMut(Net)) {
384 match self {
385 CellRepr::Void => unreachable!("void cell"),
386 CellRepr::Skip(_) => unreachable!("skip cell"),
387
388 CellRepr::Const(_) => (),
389 CellRepr::Buf(arg) | CellRepr::Not(arg) => arg.visit(&mut f),
390 CellRepr::And(arg1, arg2)
391 | CellRepr::Or(arg1, arg2)
392 | CellRepr::Xor(arg1, arg2)
393 | CellRepr::Aig(arg1, _, arg2, _) => {
394 arg1.visit(&mut f);
395 arg2.visit(&mut f);
396 }
397 CellRepr::Mux(arg1, arg2, arg3) | CellRepr::Adc(arg1, arg2, arg3) => {
398 arg1.visit(&mut f);
399 arg2.visit(&mut f);
400 arg3.visit(&mut f);
401 }
402
403 CellRepr::Boxed(cell) => cell.visit(&mut f),
404 }
405 }
406
407 pub(crate) fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
408 match self {
409 CellRepr::Void => unreachable!("void cell"),
410 CellRepr::Skip(_) => unreachable!("skip cell"),
411
412 CellRepr::Const(_) => (),
413 CellRepr::Buf(arg) | CellRepr::Not(arg) => arg.visit_mut(&mut f),
414 CellRepr::And(arg1, arg2)
415 | CellRepr::Or(arg1, arg2)
416 | CellRepr::Xor(arg1, arg2)
417 | CellRepr::Aig(arg1, _, arg2, _) => {
418 arg1.visit_mut(&mut f);
419 arg2.visit_mut(&mut f);
420 }
421 CellRepr::Mux(arg1, arg2, arg3) | CellRepr::Adc(arg1, arg2, arg3) => {
422 arg1.visit_mut(&mut f);
423 arg2.visit_mut(&mut f);
424 arg3.visit_mut(&mut f);
425 }
426
427 CellRepr::Boxed(cell) => cell.visit_mut(&mut f),
428 }
429 }
430}
431
432impl Cell {
433 pub fn output_len(&self) -> usize {
434 match self {
435 Cell::Const(_) => 1,
436 Cell::Buf(arg) | Cell::Not(arg) => arg.len(),
437 Cell::And(arg1, arg2) | Cell::Or(arg1, arg2) | Cell::Xor(arg1, arg2) | Cell::Mux(_, arg1, arg2) => {
438 debug_assert_eq!(arg1.len(), arg2.len());
439 arg1.len()
440 }
441 Cell::Adc(arg1, arg2, _) => {
442 debug_assert_eq!(arg1.len(), arg2.len());
443 arg1.len() + 1
444 }
445 Cell::Aig(..) => 1,
446
447 Cell::Eq(..) | Cell::ULt(..) | Cell::SLt(..) => 1,
448
449 Cell::Shl(arg1, _, _) | Cell::UShr(arg1, _, _) | Cell::SShr(arg1, _, _) | Cell::XShr(arg1, _, _) => {
450 arg1.len()
451 }
452
453 Cell::Mul(arg1, arg2)
454 | Cell::UDiv(arg1, arg2)
455 | Cell::UMod(arg1, arg2)
456 | Cell::SDivTrunc(arg1, arg2)
457 | Cell::SDivFloor(arg1, arg2)
458 | Cell::SModTrunc(arg1, arg2)
459 | Cell::SModFloor(arg1, arg2) => {
460 debug_assert_eq!(arg1.len(), arg2.len());
461 arg1.len()
462 }
463
464 Cell::Match(match_cell) => match_cell.output_len(),
465 Cell::Assign(assign_cell) => assign_cell.output_len(),
466
467 Cell::Dff(flip_flop) => flip_flop.output_len(),
468 Cell::Memory(memory) => memory.output_len(),
469 Cell::IoBuf(io_buffer) => io_buffer.output_len(),
470 Cell::Target(target_cell) => target_cell.output_len,
471 Cell::Other(instance) => instance.output_len(),
472
473 Cell::Input(_, width) => *width,
474 Cell::Output(..) => 0,
475 Cell::Name(..) | Cell::Debug(..) => 0,
476 }
477 }
478
479 pub fn has_effects(&self, design: &Design) -> bool {
480 match self {
481 Cell::IoBuf(_) | Cell::Other(_) | Cell::Input(..) | Cell::Output(..) | Cell::Name(..) => true,
482 Cell::Target(target_cell) => design.target_prototype(target_cell).purity == TargetCellPurity::HasEffects,
483 _ => false,
484 }
485 }
486
487 pub fn has_state(&self, design: &Design) -> bool {
488 match self {
489 Cell::IoBuf(_)
490 | Cell::Other(_)
491 | Cell::Input(..)
492 | Cell::Output(..)
493 | Cell::Name(..)
494 | Cell::Memory(..)
495 | Cell::Dff(..) => true,
496 Cell::Target(target_cell) => design.target_prototype(target_cell).purity != TargetCellPurity::Pure,
497 _ => false,
498 }
499 }
500
501 pub fn visit(&self, mut f: impl FnMut(Net)) {
502 match self {
503 Cell::Const(_) => (),
504 Cell::Input(..) => (),
505 Cell::Buf(arg) | Cell::Not(arg) | Cell::Output(_, arg) | Cell::Name(_, arg) | Cell::Debug(_, arg) => {
506 arg.visit(&mut f)
507 }
508 Cell::And(arg1, arg2)
509 | Cell::Or(arg1, arg2)
510 | Cell::Xor(arg1, arg2)
511 | Cell::Mul(arg1, arg2)
512 | Cell::UDiv(arg1, arg2)
513 | Cell::UMod(arg1, arg2)
514 | Cell::SDivTrunc(arg1, arg2)
515 | Cell::SDivFloor(arg1, arg2)
516 | Cell::SModTrunc(arg1, arg2)
517 | Cell::SModFloor(arg1, arg2)
518 | Cell::Eq(arg1, arg2)
519 | Cell::ULt(arg1, arg2)
520 | Cell::SLt(arg1, arg2)
521 | Cell::Shl(arg1, arg2, _)
522 | Cell::UShr(arg1, arg2, _)
523 | Cell::SShr(arg1, arg2, _)
524 | Cell::XShr(arg1, arg2, _) => {
525 arg1.visit(&mut f);
526 arg2.visit(&mut f);
527 }
528 Cell::Aig(arg1, arg2) => {
529 arg1.visit(&mut f);
530 arg2.visit(&mut f);
531 }
532 Cell::Mux(net, value1, value2) | Cell::Adc(value1, value2, net) => {
533 value1.visit(&mut f);
534 value2.visit(&mut f);
535 net.visit(&mut f);
536 }
537 Cell::Match(match_cell) => match_cell.visit(&mut f),
538 Cell::Assign(assign_cell) => assign_cell.visit(&mut f),
539 Cell::Dff(flip_flop) => flip_flop.visit(&mut f),
540 Cell::Memory(memory) => memory.visit(&mut f),
541 Cell::IoBuf(io_buffer) => io_buffer.visit(&mut f),
542 Cell::Target(target_cell) => target_cell.visit(&mut f),
543 Cell::Other(instance) => instance.visit(&mut f),
544 }
545 }
546
547 pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
548 match self {
549 Cell::Const(_) => (),
550 Cell::Input(..) => (),
551 Cell::Buf(arg) | Cell::Not(arg) | Cell::Output(_, arg) | Cell::Name(_, arg) | Cell::Debug(_, arg) => {
552 arg.visit_mut(&mut f)
553 }
554 Cell::And(arg1, arg2)
555 | Cell::Or(arg1, arg2)
556 | Cell::Xor(arg1, arg2)
557 | Cell::Mul(arg1, arg2)
558 | Cell::UDiv(arg1, arg2)
559 | Cell::UMod(arg1, arg2)
560 | Cell::SDivTrunc(arg1, arg2)
561 | Cell::SDivFloor(arg1, arg2)
562 | Cell::SModTrunc(arg1, arg2)
563 | Cell::SModFloor(arg1, arg2)
564 | Cell::Eq(arg1, arg2)
565 | Cell::ULt(arg1, arg2)
566 | Cell::SLt(arg1, arg2)
567 | Cell::Shl(arg1, arg2, _)
568 | Cell::UShr(arg1, arg2, _)
569 | Cell::SShr(arg1, arg2, _)
570 | Cell::XShr(arg1, arg2, _) => {
571 arg1.visit_mut(&mut f);
572 arg2.visit_mut(&mut f);
573 }
574 Cell::Aig(arg1, arg2) => {
575 arg1.visit_mut(&mut f);
576 arg2.visit_mut(&mut f);
577 }
578 Cell::Mux(net, value1, value2) | Cell::Adc(value1, value2, net) => {
579 value1.visit_mut(&mut f);
580 value2.visit_mut(&mut f);
581 net.visit_mut(&mut f);
582 }
583 Cell::Match(match_cell) => match_cell.visit_mut(&mut f),
584 Cell::Assign(assign_cell) => assign_cell.visit_mut(&mut f),
585 Cell::Dff(flip_flop) => flip_flop.visit_mut(&mut f),
586 Cell::Memory(memory) => memory.visit_mut(&mut f),
587 Cell::IoBuf(io_buffer) => io_buffer.visit_mut(&mut f),
588 Cell::Target(target_cell) => target_cell.visit_mut(&mut f),
589 Cell::Other(instance) => instance.visit_mut(&mut f),
590 }
591 }
592}
593
594#[cfg(test)]
595mod test {
596 use crate::cell::CellRepr;
597
598 #[test]
599 fn test_size() {
600 assert!(size_of::<CellRepr>() == 16);
601 }
602}