prjunnamed_netlist/
print.rs

1use std::{borrow::Cow, fmt::Display};
2
3use crate::{
4    metadata::MetaItemIndex, Cell, CellRef, Const, ControlNet, Design, IoNet, IoValue, MemoryPortRelation, Net,
5    TargetOutput, Trit, Value,
6};
7
8struct DisplayFn<'a, F: for<'b> Fn(&Design, &mut std::fmt::Formatter<'b>) -> std::fmt::Result>(&'a Design, F);
9
10impl<F: Fn(&Design, &mut std::fmt::Formatter) -> std::fmt::Result> Display for DisplayFn<'_, F> {
11    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
12        self.1(self.0, f)
13    }
14}
15
16impl Design {
17    // For display purposes only: go from a net to a `%x:y`, taking into account that the range may have
18    // to designate only a part of a multi-output cell's combined output.
19    fn find_cell_output(&self, net: Net) -> Result<(Value, usize, usize), Trit> {
20        let (cell_ref, offset) = self.find_cell(net)?;
21        let cell_index = cell_ref.debug_index();
22        match &*cell_ref.get() {
23            Cell::Other(instance) => {
24                for (_name, range) in &instance.outputs {
25                    if range.contains(&offset) {
26                        return Ok((
27                            cell_ref.output().slice(range.clone()),
28                            cell_index + range.start,
29                            offset - range.start,
30                        ));
31                    }
32                }
33                unreachable!()
34            }
35            Cell::Target(target_cell) => {
36                let prototype = self.target_prototype(target_cell);
37                for TargetOutput { range, .. } in &prototype.outputs {
38                    if range.contains(&offset) {
39                        return Ok((
40                            cell_ref.output().slice(range.clone()),
41                            cell_index + range.start,
42                            offset - range.start,
43                        ));
44                    }
45                }
46                unreachable!()
47            }
48            Cell::Memory(memory) => {
49                let mut port_offset = 0;
50                for port in &memory.read_ports {
51                    let port_range = port_offset..port_offset + port.data_len;
52                    if port_range.contains(&offset) {
53                        return Ok((
54                            cell_ref.output().slice(port_range.clone()),
55                            cell_index + port_range.start,
56                            offset - port_range.start,
57                        ));
58                    }
59                    port_offset += port.data_len;
60                }
61                unreachable!()
62            }
63            _ => Ok((cell_ref.output(), cell_index, offset)),
64        }
65    }
66
67    pub(crate) fn write_string(f: &mut std::fmt::Formatter, str: &str) -> std::fmt::Result {
68        write!(f, "\"")?;
69        for byte in str.as_bytes() {
70            if (byte.is_ascii_graphic() || matches!(byte, b' ' | b'\t')) && ![b'\\', b'"'].contains(byte) {
71                write!(f, "{}", *byte as char)?;
72            } else {
73                assert!(byte.is_ascii());
74                write!(f, "\\{:02x}", byte)?;
75            }
76        }
77        write!(f, "\"")?;
78        Ok(())
79    }
80
81    pub(crate) fn write_io_net(&self, f: &mut std::fmt::Formatter, io_net: IoNet) -> std::fmt::Result {
82        if io_net.is_floating() {
83            write!(f, "&_")
84        } else {
85            write!(f, "&")?;
86            match self.find_io(io_net) {
87                Some((name, offset)) => {
88                    Design::write_string(f, name)?;
89                    if self.get_io(name).unwrap().len() > 1 {
90                        write!(f, "+{}", offset)?;
91                    }
92                    Ok(())
93                }
94                None => write!(f, "??"),
95            }
96        }
97    }
98
99    pub(crate) fn write_io_value(&self, f: &mut std::fmt::Formatter, io_value: &IoValue) -> std::fmt::Result {
100        if io_value.is_empty() {
101            write!(f, "[]")
102        } else if io_value.len() == 1 {
103            self.write_io_net(f, io_value[0])
104        } else if io_value.iter().all(IoNet::is_floating) {
105            write!(f, "&_:{}", io_value.len())
106        } else {
107            if let Some((name, _offset)) = self.find_io(io_value[0]) {
108                if self.get_io(name).unwrap() == *io_value {
109                    write!(f, "&")?;
110                    Design::write_string(f, name)?;
111                    write!(f, ":{}", io_value.len())?;
112                    return Ok(());
113                }
114            }
115            write!(f, "[")?;
116            for io_net in io_value.iter().rev() {
117                write!(f, " ")?;
118                self.write_io_net(f, io_net)?;
119            }
120            write!(f, " ]")
121        }
122    }
123
124    pub(crate) fn write_net(&self, f: &mut std::fmt::Formatter, net: Net) -> std::fmt::Result {
125        if let Ok(index) = net.as_cell_index() {
126            if !self.is_valid_cell_index(index) {
127                return write!(f, "%_{index}");
128            }
129        }
130        match self.find_cell_output(net) {
131            Ok((output, index, offset)) => {
132                if output.len() == 1 {
133                    write!(f, "%{index}")
134                } else {
135                    write!(f, "%{index}+{offset}")
136                }
137            }
138            Err(trit) => write!(f, "{trit}"),
139        }
140    }
141
142    pub(crate) fn write_control_net(&self, f: &mut std::fmt::Formatter, control_net: ControlNet) -> std::fmt::Result {
143        if control_net.is_negative() {
144            write!(f, "!")?;
145        };
146        self.write_net(f, control_net.net())
147    }
148
149    pub(crate) fn write_value(&self, f: &mut std::fmt::Formatter, value: &Value) -> std::fmt::Result {
150        enum Chunk {
151            Slice { cell_index: usize, offset: usize, width: usize, repeat: usize },
152            WholeGrainCell { cell_index: usize, width: usize, repeat: usize },
153            NewNet { net: Net, repeat: usize },
154            Const(Const),
155        }
156        let mut index = 0;
157        let mut chunks = vec![];
158        while index < value.len() {
159            if value[index].as_cell_index().map(|index| !self.is_valid_cell_index(index)).unwrap_or(false) {
160                // Value contains newly added cells that we can't look up. Don't try to make
161                // the display nicer, just make sure it doesn't panic.
162                let mut repeat = 1;
163                while index + repeat < value.len() && value[index] == value[index + repeat] {
164                    repeat += 1;
165                }
166                chunks.push(Chunk::NewNet { net: value[index], repeat });
167                index += repeat;
168            } else if let Ok((output, index_a, offset_a)) = self.find_cell_output(value[index]) {
169                let count = value[index..]
170                    .iter()
171                    .enumerate()
172                    .take_while(|(addend, net)| {
173                        if let Ok((_, index_b, offset_b)) = self.find_cell_output(**net) {
174                            index_a == index_b && offset_a + *addend == offset_b
175                        } else {
176                            false
177                        }
178                    })
179                    .count();
180                assert!(count != 0);
181                let mut repeat = 1;
182                while index + (repeat + 1) * count <= value.len()
183                    && value[index..index + count] == value[index + repeat * count..index + (repeat + 1) * count]
184                {
185                    repeat += 1;
186                }
187                if offset_a == 0 && output.len() == count {
188                    chunks.push(Chunk::WholeGrainCell { cell_index: index_a, width: count, repeat });
189                } else {
190                    chunks.push(Chunk::Slice { cell_index: index_a, offset: offset_a, width: count, repeat });
191                }
192                index += count * repeat;
193            } else {
194                let const_value = Const::from_iter(
195                    value[index..].iter().take_while(|net| net.as_const().is_some()).map(|net| net.as_const().unwrap()),
196                );
197                assert!(!const_value.is_empty());
198                index += const_value.len();
199                chunks.push(Chunk::Const(const_value));
200            }
201        }
202        if chunks.is_empty() {
203            return write!(f, "[]");
204        }
205        let single_chunk = chunks.len() == 1;
206        if !single_chunk {
207            write!(f, "[")?;
208        }
209        for chunk in chunks.into_iter().rev() {
210            if !single_chunk {
211                write!(f, " ")?;
212            }
213            match chunk {
214                Chunk::Slice { cell_index, offset, width, repeat } => {
215                    write!(f, "%{cell_index}+{offset}")?;
216                    if width != 1 {
217                        write!(f, ":{width}")?;
218                    }
219                    if repeat != 1 {
220                        write!(f, "*{repeat}")?;
221                    }
222                }
223                Chunk::WholeGrainCell { cell_index, width, repeat } => {
224                    write!(f, "%{cell_index}")?;
225                    if width != 1 {
226                        write!(f, ":{width}")?;
227                    }
228                    if repeat != 1 {
229                        write!(f, "*{repeat}")?;
230                    }
231                }
232                Chunk::Const(const_value) => {
233                    write!(f, "{const_value}")?;
234                }
235                Chunk::NewNet { net, repeat } => {
236                    self.write_net(f, net)?;
237                    if repeat != 1 {
238                        write!(f, "*{repeat}")?;
239                    }
240                }
241            }
242        }
243        if !single_chunk {
244            write!(f, " ]")?;
245        }
246        Ok(())
247    }
248
249    pub(crate) fn write_cell(
250        &self,
251        f: &mut std::fmt::Formatter,
252        prefix: &str,
253        index: usize,
254        cell: &Cell,
255        metadata: MetaItemIndex,
256    ) -> std::fmt::Result {
257        let newline = &format!("\n{prefix}");
258
259        let write_metadata = |f: &mut std::fmt::Formatter| -> std::fmt::Result {
260            if metadata != MetaItemIndex::NONE { write!(f, " {metadata}") } else { Ok(()) }
261        };
262
263        let write_control = |f: &mut std::fmt::Formatter, name: &str, control_net: ControlNet| -> std::fmt::Result {
264            write!(f, "{}=", name)?;
265            self.write_control_net(f, control_net)
266        };
267
268        let write_common = |f: &mut std::fmt::Formatter, name: &str, args: &[&Value]| -> std::fmt::Result {
269            write!(f, "{}", name)?;
270            for arg in args {
271                write!(f, " ")?;
272                self.write_value(f, arg)?;
273            }
274            Ok(())
275        };
276
277        let write_shift =
278            |f: &mut std::fmt::Formatter, name: &str, arg1: &Value, arg2: &Value, stride: u32| -> std::fmt::Result {
279                write!(f, "{} ", name)?;
280                self.write_value(f, arg1)?;
281                write!(f, " ")?;
282                self.write_value(f, arg2)?;
283                write!(f, " #{stride}")?;
284                Ok(())
285            };
286
287        let write_cell_argument = |f: &mut std::fmt::Formatter, keyword: &str, name: &str| -> std::fmt::Result {
288            write!(f, "  {keyword} ")?;
289            Design::write_string(f, name)?;
290            write!(f, " = ")?;
291            Ok(())
292        };
293
294        let single_output = match &cell {
295            Cell::Other(..) => false,
296            Cell::Target(target_cell) if self.target_prototype(target_cell).outputs.len() > 1 => false,
297            Cell::Memory(..) => false,
298            _ => true,
299        };
300        if single_output {
301            write!(f, "{prefix}%{}:{} = ", index, cell.output_len())?;
302        } else {
303            write!(f, "{prefix}%{}:_ = ", index)?; // to be able to find any cell by its index
304        }
305        match &cell {
306            Cell::Buf(arg) => write_common(f, "buf", &[arg])?,
307            Cell::Not(arg) => write_common(f, "not", &[arg])?,
308            Cell::And(arg1, arg2) => write_common(f, "and", &[arg1, arg2])?,
309            Cell::Or(arg1, arg2) => write_common(f, "or", &[arg1, arg2])?,
310            Cell::Xor(arg1, arg2) => write_common(f, "xor", &[arg1, arg2])?,
311            Cell::Mux(arg1, arg2, arg3) => {
312                write!(f, "mux ")?;
313                self.write_net(f, *arg1)?;
314                write!(f, " ")?;
315                self.write_value(f, arg2)?;
316                write!(f, " ")?;
317                self.write_value(f, arg3)?;
318            }
319            Cell::Adc(arg1, arg2, arg3) => {
320                write!(f, "adc ")?;
321                self.write_value(f, arg1)?;
322                write!(f, " ")?;
323                self.write_value(f, arg2)?;
324                write!(f, " ")?;
325                self.write_net(f, *arg3)?;
326            }
327            Cell::Aig(arg1, arg2) => {
328                write!(f, "aig ")?;
329                self.write_control_net(f, *arg1)?;
330                write!(f, " ")?;
331                self.write_control_net(f, *arg2)?;
332            }
333
334            Cell::Eq(arg1, arg2) => write_common(f, "eq", &[arg1, arg2])?,
335            Cell::ULt(arg1, arg2) => write_common(f, "ult", &[arg1, arg2])?,
336            Cell::SLt(arg1, arg2) => write_common(f, "slt", &[arg1, arg2])?,
337
338            Cell::Shl(arg1, arg2, stride) => write_shift(f, "shl", arg1, arg2, *stride)?,
339            Cell::UShr(arg1, arg2, stride) => write_shift(f, "ushr", arg1, arg2, *stride)?,
340            Cell::SShr(arg1, arg2, stride) => write_shift(f, "sshr", arg1, arg2, *stride)?,
341            Cell::XShr(arg1, arg2, stride) => write_shift(f, "xshr", arg1, arg2, *stride)?,
342
343            Cell::Mul(arg1, arg2) => write_common(f, "mul", &[arg1, arg2])?,
344            Cell::UDiv(arg1, arg2) => write_common(f, "udiv", &[arg1, arg2])?,
345            Cell::UMod(arg1, arg2) => write_common(f, "umod", &[arg1, arg2])?,
346            Cell::SDivTrunc(arg1, arg2) => write_common(f, "sdiv_trunc", &[arg1, arg2])?,
347            Cell::SDivFloor(arg1, arg2) => write_common(f, "sdiv_floor", &[arg1, arg2])?,
348            Cell::SModTrunc(arg1, arg2) => write_common(f, "smod_trunc", &[arg1, arg2])?,
349            Cell::SModFloor(arg1, arg2) => write_common(f, "smod_floor", &[arg1, arg2])?,
350
351            Cell::Match(match_cell) => {
352                write!(f, "match")?;
353                if match_cell.enable != Net::ONE {
354                    write!(f, " en=")?;
355                    self.write_net(f, match_cell.enable)?;
356                }
357                write!(f, " ")?;
358                self.write_value(f, &match_cell.value)?;
359                let multiline = match_cell
360                    .patterns
361                    .iter()
362                    .map(|alternates| alternates.iter().map(Const::len).sum::<usize>())
363                    .sum::<usize>()
364                    > 80;
365                write_metadata(f)?;
366                write!(f, " {{")?;
367                if multiline {
368                    write!(f, "{newline}")?;
369                }
370                for alternates in &match_cell.patterns {
371                    if multiline {
372                        write!(f, "  ")?;
373                    } else {
374                        write!(f, " ")?;
375                    }
376                    if alternates.len() == 1 {
377                        let pattern = &alternates[0];
378                        write!(f, "{pattern}")?;
379                    } else {
380                        write!(f, "(")?;
381                        for (index, pattern) in alternates.iter().enumerate() {
382                            if index > 0 {
383                                write!(f, " ")?;
384                            }
385                            write!(f, "{pattern}")?;
386                        }
387                        write!(f, ")")?;
388                    }
389                    if multiline {
390                        write!(f, "{newline}")?;
391                    }
392                }
393                if !multiline {
394                    write!(f, " ")?;
395                }
396                write!(f, "}}")?;
397            }
398            Cell::Assign(assign_cell) => {
399                write!(f, "assign")?;
400                if assign_cell.enable != Net::ONE {
401                    write!(f, " en=")?;
402                    self.write_net(f, assign_cell.enable)?;
403                }
404                write!(f, " ")?;
405                self.write_value(f, &assign_cell.value)?;
406                write!(f, " ")?;
407                self.write_value(f, &assign_cell.update)?;
408                if assign_cell.offset != 0 {
409                    write!(f, " at=#{}", assign_cell.offset)?;
410                }
411            }
412
413            Cell::Dff(flip_flop) => {
414                write_common(f, "dff", &[&flip_flop.data])?;
415                write_control(f, " clk", flip_flop.clock)?;
416                if flip_flop.has_clear() {
417                    write_control(f, " clr", flip_flop.clear)?;
418                    if flip_flop.clear_value != flip_flop.init_value {
419                        write!(f, ",{}", flip_flop.clear_value)?;
420                    }
421                }
422                if flip_flop.has_reset() {
423                    write_control(f, " rst", flip_flop.reset)?;
424                    if flip_flop.reset_value != flip_flop.init_value {
425                        write!(f, ",{}", flip_flop.reset_value)?;
426                    }
427                }
428                if flip_flop.has_enable() {
429                    write_control(f, " en", flip_flop.enable)?;
430                }
431                if flip_flop.has_reset() && flip_flop.has_enable() {
432                    if flip_flop.reset_over_enable {
433                        write!(f, " rst/en")?;
434                    } else {
435                        write!(f, " en/rst")?;
436                    }
437                }
438                if flip_flop.has_init_value() {
439                    write!(f, " init={}", flip_flop.init_value)?;
440                }
441            }
442            Cell::Memory(memory) => {
443                write!(f, "memory depth=#{} width=#{}", memory.depth, memory.width)?;
444                write_metadata(f)?;
445                write!(f, " {{{newline}")?;
446                for write_port in &memory.write_ports {
447                    write!(f, "  write addr=")?;
448                    self.write_value(f, &write_port.addr)?;
449                    write!(f, " data=")?;
450                    self.write_value(f, &write_port.data)?;
451                    if !write_port.mask.is_ones() {
452                        write!(f, " mask=")?;
453                        self.write_value(f, &write_port.mask)?;
454                    }
455                    write_control(f, " clk", write_port.clock)?;
456                    write!(f, "{newline}")?;
457                }
458                let mut port_offset = 0;
459                for read_port in &memory.read_ports {
460                    write!(f, "  %{}:{} = read addr=", index + port_offset, read_port.data_len)?;
461                    self.write_value(f, &read_port.addr)?;
462                    if let Some(ref flip_flop) = read_port.flip_flop {
463                        write_control(f, " clk", flip_flop.clock)?;
464                        if flip_flop.has_clear() {
465                            write_control(f, " clr", flip_flop.clear)?;
466                            if flip_flop.clear_value != flip_flop.init_value {
467                                write!(f, ",{}", flip_flop.clear_value)?;
468                            }
469                        }
470                        if flip_flop.has_reset() {
471                            write_control(f, " rst", flip_flop.reset)?;
472                            if flip_flop.reset_value != flip_flop.init_value {
473                                write!(f, ",{}", flip_flop.reset_value)?;
474                            }
475                        }
476                        if flip_flop.has_enable() {
477                            write_control(f, " en", flip_flop.enable)?;
478                        }
479                        if flip_flop.has_reset() && flip_flop.has_enable() {
480                            if flip_flop.reset_over_enable {
481                                write!(f, " rst/en")?;
482                            } else {
483                                write!(f, " en/rst")?;
484                            }
485                        }
486                        if flip_flop.has_init_value() {
487                            write!(f, " init={}", flip_flop.init_value)?;
488                        }
489                        write!(f, " [")?;
490                        for (index, relation) in flip_flop.relations.iter().enumerate() {
491                            match relation {
492                                MemoryPortRelation::Undefined => write!(f, "undef")?,
493                                MemoryPortRelation::ReadBeforeWrite => write!(f, "rdfirst")?,
494                                MemoryPortRelation::Transparent => write!(f, "trans")?,
495                            }
496                            if index < flip_flop.relations.len() - 1 {
497                                write!(f, " ")?;
498                            }
499                        }
500                        write!(f, "]")?;
501                    }
502                    write!(f, "{newline}")?;
503                    port_offset += read_port.data_len;
504                }
505                let mut rows = Vec::new();
506                for index in 0..memory.depth {
507                    rows.push(memory.init_value.slice((index * memory.width)..((index + 1) * memory.width)));
508                }
509                let mut index = 0;
510                while index < rows.len() {
511                    write!(f, "  init {}", rows[index])?;
512                    let mut repeats = 1;
513                    while rows.get(index) == rows.get(index + repeats) {
514                        repeats += 1;
515                    }
516                    if repeats > 1 {
517                        write!(f, "*{repeats}")?;
518                    }
519                    write!(f, "{newline}")?;
520                    index += repeats;
521                }
522                write!(f, "}}")?;
523            }
524            Cell::IoBuf(io_buffer) => {
525                write!(f, "iobuf ")?;
526                self.write_io_value(f, &io_buffer.io)?;
527                write!(f, " o=")?;
528                self.write_value(f, &io_buffer.output)?;
529                write_control(f, " en", io_buffer.enable)?;
530            }
531            Cell::Other(instance) => {
532                Design::write_string(f, instance.kind.as_str())?;
533                write_metadata(f)?;
534                write!(f, " {{{newline}")?;
535                for (name, value) in instance.params.iter() {
536                    write_cell_argument(f, "param", name)?;
537                    write!(f, "{value}{newline}")?;
538                }
539                for (name, value) in instance.inputs.iter() {
540                    write_cell_argument(f, "input", name)?;
541                    self.write_value(f, value)?;
542                    write!(f, "{newline}")?;
543                }
544                for (name, range) in instance.outputs.iter() {
545                    write!(f, "  %{}:{} = output ", index + range.start, range.len())?;
546                    Design::write_string(f, &name)?;
547                    write!(f, "{newline}")?;
548                }
549                for (name, value) in instance.ios.iter() {
550                    write_cell_argument(f, "io", name)?;
551                    self.write_io_value(f, value)?;
552                    write!(f, "{newline}")?;
553                }
554                write!(f, "}}")?;
555            }
556            Cell::Target(target_cell) => {
557                write!(f, "target ")?;
558                let prototype = self.target_prototype(target_cell);
559                Design::write_string(f, &target_cell.kind)?;
560                write_metadata(f)?;
561                write!(f, " {{{newline}")?;
562                for (param, value) in prototype.params.iter().zip(target_cell.params.iter()) {
563                    write_cell_argument(f, "param", &param.name)?;
564                    write!(f, "{value}{newline}")?;
565                }
566                for target_input in &prototype.inputs {
567                    write_cell_argument(f, "input", &target_input.name)?;
568                    self.write_value(f, &target_cell.inputs.slice(target_input.range.clone()))?;
569                    write!(f, "{newline}")?;
570                }
571                if prototype.outputs.len() > 1 {
572                    for target_output in &prototype.outputs {
573                        write!(f, "  %{}:{} = output ", index + target_output.range.start, target_output.range.len())?;
574                        Design::write_string(f, &target_output.name)?;
575                        write!(f, "{newline}")?;
576                    }
577                }
578                for target_io in &prototype.ios {
579                    write_cell_argument(f, "io", &target_io.name)?;
580                    self.write_io_value(f, &target_cell.ios.slice(target_io.range.clone()))?;
581                    write!(f, "{newline}")?;
582                }
583                write!(f, "}}")?;
584            }
585
586            Cell::Input(name, _size) => {
587                write!(f, "input ")?;
588                Design::write_string(f, name)?;
589            }
590            Cell::Output(name, value) => {
591                write!(f, "output ")?;
592                Design::write_string(f, name)?;
593                write!(f, " ")?;
594                self.write_value(f, value)?;
595            }
596            Cell::Name(name, value) => {
597                write!(f, "name ")?;
598                Design::write_string(f, name)?;
599                write!(f, " ")?;
600                self.write_value(f, value)?;
601            }
602            Cell::Debug(name, value) => {
603                write!(f, "debug ")?;
604                Design::write_string(f, name)?;
605                write!(f, " ")?;
606                self.write_value(f, value)?;
607            }
608        }
609        match cell {
610            Cell::Match(..) | Cell::Memory(..) | Cell::Other(..) | Cell::Target(..) => (),
611            _ => write_metadata(f)?,
612        }
613        Ok(())
614    }
615
616    pub fn display_net(&self, net: impl Into<Net>) -> impl Display + '_ {
617        let net = net.into();
618        DisplayFn(self, move |design: &Design, f| design.write_net(f, net))
619    }
620
621    pub fn display_control_net(&self, net: impl Into<ControlNet>) -> impl Display + '_ {
622        let net = net.into();
623        DisplayFn(self, move |design: &Design, f| design.write_control_net(f, net))
624    }
625
626    pub fn display_value<'a, 'b: 'a>(&'a self, value: impl Into<Cow<'b, Value>>) -> impl Display + 'a {
627        let value = value.into();
628        DisplayFn(self, move |design: &Design, f| design.write_value(f, &value))
629    }
630
631    pub fn display_cell<'a>(&'a self, cell_ref: CellRef<'a>) -> impl Display + 'a {
632        DisplayFn(self, move |design: &Design, f| {
633            design.write_cell(f, "", cell_ref.debug_index(), &*cell_ref.get(), cell_ref.metadata().index())
634        })
635    }
636}