Skip to main content

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