Skip to main content

vj_sim/image/
codec.rs

1//! The design image's wire format: versioned, little-endian, and
2//! deterministic by construction (every collection is a `Vec` encoded in
3//! order; nothing iterates a hash map).
4//!
5//! Layout: `magic(8) | version(u32) | body_len(u64) | body_hash(u64) | body`.
6//! The hash is FNV-1a over the body, checked on decode so a truncated or
7//! corrupted `.so` section is refused loudly rather than half-run.
8
9use super::covdecl::{get_covgroup, put_covgroup};
10use super::verif::{
11    AssertionImage, CasePairImage, ClockingImage, CovClassClockImage, CovExprTermImage,
12    CovGroupImage, CovSamplerImage, FreeGroupImage, FreeVarImage, SampledImage, SampledSiteImage,
13    SpawnCallImage, VerifImage,
14};
15use super::*;
16use crate::collections::Key;
17use crate::netlist::{ClassTemplateId, SymbolKey};
18use crate::objects::{FieldSlot, NestedHandle, RandKind, RandProp, TemplateSnapshot};
19use crate::sched::ProcessKind;
20use crate::sched::assert_control::SiteDesc;
21use crate::state::{
22    DriveStrength, DriveStrengthPair, NetKind, NetLayout, NetShape, SlotClass, SlotDescriptor,
23    SlotOffset, StateLayout,
24};
25use crate::sva::engine::AssertKind;
26use crate::sva::ir::{LeafId, LocalVarId};
27
28/// Why an image failed to decode.
29#[derive(Debug, PartialEq, Eq)]
30pub enum ImageError {
31    Truncated,
32    BadMagic,
33    BadVersion {
34        found: u32,
35        expected: u32,
36    },
37    BadHash,
38    BadTag {
39        what: &'static str,
40        tag: u8,
41    },
42    BadUtf8,
43    TrailingBytes,
44    /// A symbol, instance or template index points outside its table.
45    BadReference(&'static str),
46}
47
48impl std::fmt::Display for ImageError {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        match self {
51            ImageError::Truncated => write!(f, "design image is truncated"),
52            ImageError::BadMagic => write!(f, "not a design image (bad magic)"),
53            ImageError::BadVersion { found, expected } => write!(
54                f,
55                "design image version {found} (this runner reads version {expected})"
56            ),
57            ImageError::BadHash => write!(f, "design image is corrupted (content hash mismatch)"),
58            ImageError::BadTag { what, tag } => {
59                write!(f, "design image has an unknown {what} tag {tag}")
60            }
61            ImageError::BadUtf8 => write!(f, "design image has a non-UTF-8 name"),
62            ImageError::TrailingBytes => write!(f, "design image has trailing bytes"),
63            ImageError::BadReference(what) => {
64                write!(f, "design image has a dangling {what} reference")
65            }
66        }
67    }
68}
69
70impl std::error::Error for ImageError {}
71
72/// FNV-1a, 64 bit.
73fn fnv1a(bytes: &[u8]) -> u64 {
74    let mut h: u64 = 0xcbf2_9ce4_8422_2325;
75    for &b in bytes {
76        h ^= u64::from(b);
77        h = h.wrapping_mul(0x0000_0100_0000_01b3);
78    }
79    h
80}
81
82#[derive(Default)]
83pub struct Writer {
84    pub buf: Vec<u8>,
85}
86
87impl Writer {
88    pub fn u8(&mut self, v: u8) {
89        self.buf.push(v);
90    }
91    pub fn bool(&mut self, v: bool) {
92        self.buf.push(u8::from(v));
93    }
94    pub fn u32(&mut self, v: u32) {
95        self.buf.extend_from_slice(&v.to_le_bytes());
96    }
97    pub fn i32(&mut self, v: i32) {
98        self.buf.extend_from_slice(&v.to_le_bytes());
99    }
100    pub fn u64(&mut self, v: u64) {
101        self.buf.extend_from_slice(&v.to_le_bytes());
102    }
103    pub fn u128(&mut self, v: u128) {
104        self.buf.extend_from_slice(&v.to_le_bytes());
105    }
106    pub fn len(&mut self, n: usize) {
107        self.u64(n as u64);
108    }
109    pub fn str(&mut self, s: &str) {
110        self.bytes(s.as_bytes());
111    }
112    pub fn bytes(&mut self, s: &[u8]) {
113        self.len(s.len());
114        self.buf.extend_from_slice(s);
115    }
116    pub fn words(&mut self, v: &[u64]) {
117        self.len(v.len());
118        for &w in v {
119            self.u64(w);
120        }
121    }
122}
123
124pub struct Reader<'a> {
125    bytes: &'a [u8],
126    pos: usize,
127}
128
129impl<'a> Reader<'a> {
130    pub fn new(bytes: &'a [u8]) -> Self {
131        Reader { bytes, pos: 0 }
132    }
133    fn take(&mut self, n: usize) -> Result<&'a [u8], ImageError> {
134        let end = self.pos.checked_add(n).ok_or(ImageError::Truncated)?;
135        let out = self.bytes.get(self.pos..end).ok_or(ImageError::Truncated)?;
136        self.pos = end;
137        Ok(out)
138    }
139    pub fn u8(&mut self) -> Result<u8, ImageError> {
140        Ok(self.take(1)?[0])
141    }
142    pub fn bool(&mut self) -> Result<bool, ImageError> {
143        match self.u8()? {
144            0 => Ok(false),
145            1 => Ok(true),
146            tag => Err(ImageError::BadTag { what: "bool", tag }),
147        }
148    }
149    pub fn u32(&mut self) -> Result<u32, ImageError> {
150        Ok(u32::from_le_bytes(
151            self.take(4)?.try_into().expect("4 bytes"),
152        ))
153    }
154    pub fn i32(&mut self) -> Result<i32, ImageError> {
155        Ok(i32::from_le_bytes(
156            self.take(4)?.try_into().expect("4 bytes"),
157        ))
158    }
159    pub fn u64(&mut self) -> Result<u64, ImageError> {
160        Ok(u64::from_le_bytes(
161            self.take(8)?.try_into().expect("8 bytes"),
162        ))
163    }
164    pub fn u128(&mut self) -> Result<u128, ImageError> {
165        Ok(u128::from_le_bytes(
166            self.take(16)?.try_into().expect("16 bytes"),
167        ))
168    }
169    /// A collection length, bounded by the bytes left (every element takes at
170    /// least one byte), so a corrupt length cannot request a huge allocation.
171    #[allow(clippy::len_without_is_empty)] // reads a length; the reader has no "emptiness"
172    pub fn len(&mut self) -> Result<usize, ImageError> {
173        let n = self.u64()?;
174        if n > (self.bytes.len() - self.pos) as u64 {
175            return Err(ImageError::Truncated);
176        }
177        Ok(n as usize)
178    }
179    pub fn str(&mut self) -> Result<String, ImageError> {
180        String::from_utf8(self.bytes()?).map_err(|_| ImageError::BadUtf8)
181    }
182    pub fn bytes(&mut self) -> Result<Vec<u8>, ImageError> {
183        let n = self.len()?;
184        Ok(self.take(n)?.to_vec())
185    }
186    pub fn words(&mut self) -> Result<Vec<u64>, ImageError> {
187        let n = self.len()?;
188        // (`len` bounds `n` by the bytes left, each word takes eight.)
189        if n.checked_mul(8)
190            .is_none_or(|b| b > self.bytes.len() - self.pos)
191        {
192            return Err(ImageError::Truncated);
193        }
194        (0..n).map(|_| self.u64()).collect()
195    }
196    pub fn done(&self) -> bool {
197        self.pos == self.bytes.len()
198    }
199}
200
201// ---- leaf enums -----------------------------------------------------------
202
203fn put_nest(w: &mut Writer, n: &crate::collections::Nest) {
204    w.len(n.slots.len());
205    for (off, inner) in &n.slots {
206        w.u32(*off);
207        put_nest(w, inner);
208    }
209}
210
211fn get_nest(r: &mut Reader<'_>) -> Result<crate::collections::Nest, ImageError> {
212    let n = r.len()?;
213    let mut slots = Vec::with_capacity(n);
214    for _ in 0..n {
215        let off = r.u32()?;
216        slots.push((off, get_nest(r)?));
217    }
218    Ok(crate::collections::Nest { slots })
219}
220
221fn put_slot_class(w: &mut Writer, c: SlotClass) {
222    w.u8(match c {
223        SlotClass::Inline => 0,
224        SlotClass::Wide => 1,
225        SlotClass::Memory => 2,
226        SlotClass::ForceWide => 3,
227    });
228}
229fn get_slot_class(r: &mut Reader<'_>) -> Result<SlotClass, ImageError> {
230    Ok(match r.u8()? {
231        0 => SlotClass::Inline,
232        1 => SlotClass::Wide,
233        2 => SlotClass::Memory,
234        3 => SlotClass::ForceWide,
235        tag => {
236            return Err(ImageError::BadTag {
237                what: "slot class",
238                tag,
239            });
240        }
241    })
242}
243
244fn put_edge(w: &mut Writer, e: EdgeKind) {
245    w.u8(match e {
246        EdgeKind::None => 0,
247        EdgeKind::Posedge => 1,
248        EdgeKind::Negedge => 2,
249        EdgeKind::BothEdges => 3,
250    });
251}
252fn get_edge(r: &mut Reader<'_>) -> Result<EdgeKind, ImageError> {
253    Ok(match r.u8()? {
254        0 => EdgeKind::None,
255        1 => EdgeKind::Posedge,
256        2 => EdgeKind::Negedge,
257        3 => EdgeKind::BothEdges,
258        tag => {
259            return Err(ImageError::BadTag {
260                what: "edge kind",
261                tag,
262            });
263        }
264    })
265}
266
267fn put_opt_edge(w: &mut Writer, e: Option<EdgeKind>) {
268    match e {
269        None => w.u8(0),
270        Some(e) => {
271            w.u8(1);
272            put_edge(w, e);
273        }
274    }
275}
276fn get_opt_edge(r: &mut Reader<'_>) -> Result<Option<EdgeKind>, ImageError> {
277    Ok(match r.u8()? {
278        0 => None,
279        1 => Some(get_edge(r)?),
280        tag => {
281            return Err(ImageError::BadTag {
282                what: "option",
283                tag,
284            });
285        }
286    })
287}
288
289fn put_net_kind(w: &mut Writer, k: NetKind) {
290    w.u8(match k {
291        NetKind::Wire => 0,
292        NetKind::WAnd => 1,
293        NetKind::WOr => 2,
294        NetKind::Tri => 3,
295        NetKind::TriAnd => 4,
296        NetKind::TriOr => 5,
297        NetKind::Tri0 => 6,
298        NetKind::Tri1 => 7,
299        NetKind::TriReg => 8,
300        NetKind::Supply0 => 9,
301        NetKind::Supply1 => 10,
302        NetKind::UWire => 11,
303        NetKind::UserDefined => 12,
304    });
305}
306fn get_net_kind(r: &mut Reader<'_>) -> Result<NetKind, ImageError> {
307    Ok(match r.u8()? {
308        0 => NetKind::Wire,
309        1 => NetKind::WAnd,
310        2 => NetKind::WOr,
311        3 => NetKind::Tri,
312        4 => NetKind::TriAnd,
313        5 => NetKind::TriOr,
314        6 => NetKind::Tri0,
315        7 => NetKind::Tri1,
316        8 => NetKind::TriReg,
317        9 => NetKind::Supply0,
318        10 => NetKind::Supply1,
319        11 => NetKind::UWire,
320        12 => NetKind::UserDefined,
321        tag => {
322            return Err(ImageError::BadTag {
323                what: "net kind",
324                tag,
325            });
326        }
327    })
328}
329
330fn put_net_shape(w: &mut Writer, s: NetShape) {
331    w.u8(match s {
332        NetShape::AliasedSingleDriver => 0,
333        NetShape::MultiDriverUniformStrength => 1,
334        NetShape::FullStrengthLattice => 2,
335    });
336}
337fn get_net_shape(r: &mut Reader<'_>) -> Result<NetShape, ImageError> {
338    Ok(match r.u8()? {
339        0 => NetShape::AliasedSingleDriver,
340        1 => NetShape::MultiDriverUniformStrength,
341        2 => NetShape::FullStrengthLattice,
342        tag => {
343            return Err(ImageError::BadTag {
344                what: "net shape",
345                tag,
346            });
347        }
348    })
349}
350
351fn put_process_kind(w: &mut Writer, k: ProcessKind) {
352    w.u8(match k {
353        ProcessKind::Initial => 0,
354        ProcessKind::Always => 1,
355        ProcessKind::AlwaysComb => 2,
356        ProcessKind::AlwaysLatch => 3,
357        ProcessKind::AlwaysFF => 4,
358        ProcessKind::Final => 5,
359    });
360}
361fn get_process_kind(r: &mut Reader<'_>) -> Result<ProcessKind, ImageError> {
362    Ok(match r.u8()? {
363        0 => ProcessKind::Initial,
364        1 => ProcessKind::Always,
365        2 => ProcessKind::AlwaysComb,
366        3 => ProcessKind::AlwaysLatch,
367        4 => ProcessKind::AlwaysFF,
368        5 => ProcessKind::Final,
369        tag => {
370            return Err(ImageError::BadTag {
371                what: "process kind",
372                tag,
373            });
374        }
375    })
376}
377
378// ---- four-state values and layouts ---------------------------------------
379
380pub fn put_four_state(w: &mut Writer, v: &FourStateValue) {
381    match v {
382        FourStateValue::Narrow(word) => {
383            w.u8(0);
384            w.u128(*word);
385        }
386        FourStateValue::Wide { aval, bval } => {
387            w.u8(1);
388            w.len(aval.len());
389            for a in aval {
390                w.u64(*a);
391            }
392            w.len(bval.len());
393            for b in bval {
394                w.u64(*b);
395            }
396        }
397    }
398}
399
400pub fn get_four_state(r: &mut Reader<'_>) -> Result<FourStateValue, ImageError> {
401    Ok(match r.u8()? {
402        0 => FourStateValue::Narrow(r.u128()?),
403        1 => {
404            let n = r.len()?;
405            let aval = (0..n).map(|_| r.u64()).collect::<Result<_, _>>()?;
406            let n = r.len()?;
407            let bval = (0..n).map(|_| r.u64()).collect::<Result<_, _>>()?;
408            FourStateValue::Wide { aval, bval }
409        }
410        tag => {
411            return Err(ImageError::BadTag {
412                what: "four-state value",
413                tag,
414            });
415        }
416    })
417}
418
419pub fn put_layout(w: &mut Writer, l: &StateLayout) {
420    w.u32(l.inline_words);
421    w.u32(l.wide_words);
422    w.len(l.slots.len());
423    for s in &l.slots {
424        w.u32(s.key.0);
425        put_slot_class(w, s.offset.class);
426        w.u32(s.offset.word_offset);
427        w.u32(s.offset.bit_width);
428        w.u32(s.offset.elem_word_count);
429        w.u32(s.offset.row_stride_words);
430        w.u32(s.offset.num_rows);
431        match &s.initial {
432            None => w.u8(0),
433            Some(v) => {
434                w.u8(1);
435                put_four_state(w, v);
436            }
437        }
438        match &s.net_info {
439            None => w.u8(0),
440            Some(n) => {
441                w.u8(1);
442                put_net_kind(w, n.kind);
443                put_net_shape(w, n.shape);
444            }
445        }
446    }
447}
448
449pub fn get_layout(r: &mut Reader<'_>) -> Result<StateLayout, ImageError> {
450    let inline_words = r.u32()?;
451    let wide_words = r.u32()?;
452    let n = r.len()?;
453    let mut slots = Vec::with_capacity(n);
454    for _ in 0..n {
455        let key = SymbolKey(r.u32()?);
456        let offset = SlotOffset {
457            class: get_slot_class(r)?,
458            word_offset: r.u32()?,
459            bit_width: r.u32()?,
460            elem_word_count: r.u32()?,
461            row_stride_words: r.u32()?,
462            num_rows: r.u32()?,
463        };
464        let initial = match r.u8()? {
465            0 => None,
466            1 => Some(get_four_state(r)?),
467            tag => {
468                return Err(ImageError::BadTag {
469                    what: "option",
470                    tag,
471                });
472            }
473        };
474        let net_info = match r.u8()? {
475            0 => None,
476            1 => Some(NetLayout {
477                kind: get_net_kind(r)?,
478                shape: get_net_shape(r)?,
479            }),
480            tag => {
481                return Err(ImageError::BadTag {
482                    what: "option",
483                    tag,
484                });
485            }
486        };
487        slots.push(SlotDescriptor {
488            key,
489            offset,
490            initial,
491            net_info,
492        });
493    }
494    Ok(StateLayout {
495        slots,
496        inline_words,
497        wide_words,
498    })
499}
500
501// ---- sections -------------------------------------------------------------
502
503fn put_key(w: &mut Writer, k: &TemplateKey) {
504    w.u32(k.definition);
505    w.u64(k.params_hash);
506}
507fn get_key(r: &mut Reader<'_>) -> Result<TemplateKey, ImageError> {
508    Ok(TemplateKey {
509        definition: r.u32()?,
510        params_hash: r.u64()?,
511    })
512}
513
514pub fn put_templates(w: &mut Writer, t: &[TemplateImage]) {
515    w.len(t.len());
516    for t in t {
517        put_key(w, &t.key);
518        put_layout(w, &t.layout);
519    }
520}
521pub fn get_templates(r: &mut Reader<'_>) -> Result<Vec<TemplateImage>, ImageError> {
522    let n = r.len()?;
523    (0..n)
524        .map(|_| {
525            Ok(TemplateImage {
526                key: get_key(r)?,
527                layout: get_layout(r)?,
528            })
529        })
530        .collect()
531}
532
533pub fn put_instances(w: &mut Writer, v: &[InstanceImage]) {
534    w.len(v.len());
535    for i in v {
536        w.u32(i.id.0);
537        put_key(w, &i.template);
538        w.u8(match i.kind {
539            InstanceKind::Elaborated => 0,
540            InstanceKind::Package => 1,
541            InstanceKind::Bank => 2,
542        });
543        w.str(&i.path);
544    }
545}
546pub fn get_instances(r: &mut Reader<'_>) -> Result<Vec<InstanceImage>, ImageError> {
547    let n = r.len()?;
548    (0..n)
549        .map(|_| {
550            Ok(InstanceImage {
551                id: InstanceId(r.u32()?),
552                template: get_key(r)?,
553                kind: match r.u8()? {
554                    0 => InstanceKind::Elaborated,
555                    1 => InstanceKind::Package,
556                    2 => InstanceKind::Bank,
557                    tag => {
558                        return Err(ImageError::BadTag {
559                            what: "instance kind",
560                            tag,
561                        });
562                    }
563                },
564                path: r.str()?,
565            })
566        })
567        .collect()
568}
569
570fn put_alias_window(w: &mut Writer, window: Option<crate::state::AliasWindow>) {
571    match window {
572        None => w.u8(0),
573        Some(crate::state::AliasWindow { row, lo, width }) => {
574            w.u8(1);
575            put_opt_u64(w, row);
576            w.u32(lo);
577            w.u32(width);
578        }
579    }
580}
581fn get_alias_window(r: &mut Reader<'_>) -> Result<Option<crate::state::AliasWindow>, ImageError> {
582    match r.u8()? {
583        0 => Ok(None),
584        1 => {
585            let row = get_opt_u64(r, "ForeignImage target window row")?;
586            let lo = r.u32()?;
587            let width = r.u32()?;
588            Ok(Some(crate::state::AliasWindow { row, lo, width }))
589        }
590        tag => Err(ImageError::BadTag {
591            what: "ForeignImage target window",
592            tag,
593        }),
594    }
595}
596
597pub fn put_foreign(w: &mut Writer, v: &[ForeignImage]) {
598    w.len(v.len());
599    for f in v {
600        w.u32(f.instance.0);
601        w.u32(f.own_slots);
602        w.len(f.targets.len());
603        for (owner, slot, window) in &f.targets {
604            w.u32(owner.0);
605            w.u32(*slot);
606            put_alias_window(w, *window);
607        }
608    }
609}
610pub fn get_foreign(r: &mut Reader<'_>) -> Result<Vec<ForeignImage>, ImageError> {
611    let n = r.len()?;
612    (0..n)
613        .map(|_| {
614            let instance = InstanceId(r.u32()?);
615            let own_slots = r.u32()?;
616            let m = r.len()?;
617            let targets = (0..m)
618                .map(|_| Ok((InstanceId(r.u32()?), r.u32()?, get_alias_window(r)?)))
619                .collect::<Result<_, ImageError>>()?;
620            Ok(ForeignImage {
621                instance,
622                own_slots,
623                targets,
624            })
625        })
626        .collect()
627}
628
629pub fn put_x_windows(w: &mut Writer, v: &[XWindow]) {
630    w.len(v.len());
631    for x in v {
632        w.u32(x.instance.0);
633        w.u32(x.slot);
634        put_four_state(w, &x.value);
635    }
636}
637pub fn get_x_windows(r: &mut Reader<'_>) -> Result<Vec<XWindow>, ImageError> {
638    let n = r.len()?;
639    (0..n)
640        .map(|_| {
641            Ok(XWindow {
642                instance: InstanceId(r.u32()?),
643                slot: r.u32()?,
644                value: get_four_state(r)?,
645            })
646        })
647        .collect()
648}
649
650fn put_place(w: &mut Writer, p: &PlaceImage) {
651    w.u32(p.instance.0);
652    w.u32(p.slot);
653    w.u32(p.width);
654    match p.class {
655        PlaceClass::Inline => w.u8(0),
656        PlaceClass::Wide => w.u8(1),
657        PlaceClass::Memory { rows } => {
658            w.u8(2);
659            w.u32(rows);
660        }
661    }
662}
663fn get_place(r: &mut Reader<'_>) -> Result<PlaceImage, ImageError> {
664    let instance = InstanceId(r.u32()?);
665    let slot = r.u32()?;
666    let width = r.u32()?;
667    let class = match r.u8()? {
668        0 => PlaceClass::Inline,
669        1 => PlaceClass::Wide,
670        2 => PlaceClass::Memory { rows: r.u32()? },
671        tag => {
672            return Err(ImageError::BadTag {
673                what: "place class",
674                tag,
675            });
676        }
677    };
678    Ok(PlaceImage {
679        instance,
680        slot,
681        width,
682        class,
683    })
684}
685
686fn put_range(w: &mut Writer, r: Option<(u32, u32)>) {
687    match r {
688        None => w.u8(0),
689        Some((lo, width)) => {
690            w.u8(1);
691            w.u32(lo);
692            w.u32(width);
693        }
694    }
695}
696fn get_range(r: &mut Reader<'_>) -> Result<Option<(u32, u32)>, ImageError> {
697    match r.u8()? {
698        0 => Ok(None),
699        1 => Ok(Some((r.u32()?, r.u32()?))),
700        tag => Err(ImageError::BadTag { what: "range", tag }),
701    }
702}
703
704fn put_opt_u32(w: &mut Writer, v: Option<u32>) {
705    match v {
706        None => w.u8(0),
707        Some(x) => {
708            w.u8(1);
709            w.u32(x);
710        }
711    }
712}
713fn get_opt_u32(r: &mut Reader<'_>) -> Result<Option<u32>, ImageError> {
714    match r.u8()? {
715        0 => Ok(None),
716        1 => Ok(Some(r.u32()?)),
717        tag => Err(ImageError::BadTag {
718            what: "optional u32",
719            tag,
720        }),
721    }
722}
723
724fn put_strength(w: &mut Writer, s: DriveStrength) {
725    w.u8(match s {
726        DriveStrength::Supply => 0,
727        DriveStrength::Strong => 1,
728        DriveStrength::Pull => 2,
729        DriveStrength::Weak => 3,
730        DriveStrength::HighZ => 4,
731    });
732}
733fn get_strength(r: &mut Reader<'_>) -> Result<DriveStrength, ImageError> {
734    match r.u8()? {
735        0 => Ok(DriveStrength::Supply),
736        1 => Ok(DriveStrength::Strong),
737        2 => Ok(DriveStrength::Pull),
738        3 => Ok(DriveStrength::Weak),
739        4 => Ok(DriveStrength::HighZ),
740        tag => Err(ImageError::BadTag {
741            what: "drive strength",
742            tag,
743        }),
744    }
745}
746
747pub fn put_wires(w: &mut Writer, v: &[WireImage]) {
748    w.len(v.len());
749    for x in v {
750        put_place(w, &x.src);
751        put_range(w, x.src_range);
752        put_place(w, &x.dst);
753        put_range(w, x.dst_range);
754        w.bool(x.ranged);
755    }
756}
757pub fn get_wires(r: &mut Reader<'_>) -> Result<Vec<WireImage>, ImageError> {
758    let n = r.len()?;
759    (0..n)
760        .map(|_| {
761            Ok(WireImage {
762                src: get_place(r)?,
763                src_range: get_range(r)?,
764                dst: get_place(r)?,
765                dst_range: get_range(r)?,
766                ranged: r.bool()?,
767            })
768        })
769        .collect()
770}
771
772pub fn put_groups(w: &mut Writer, v: &[GroupImage]) {
773    w.len(v.len());
774    for g in v {
775        put_net_kind(w, g.kind);
776        w.u32(g.width);
777        w.len(g.nets.len());
778        for (inst, slot) in &g.nets {
779            w.u32(inst.0);
780            w.u32(*slot);
781        }
782        w.len(g.drivers.len());
783        for d in &g.drivers {
784            w.u32(d.slot);
785            put_strength(w, d.strength.s0);
786            put_strength(w, d.strength.s1);
787            put_opt_u32(w, d.ambiguous);
788            match &d.src {
789                None => w.u8(0),
790                Some(x) => {
791                    w.u8(1);
792                    w.u64(x.key);
793                    w.u32(x.bit);
794                    w.u32(x.out_bit);
795                    w.bool(x.resistive);
796                    w.u32(x.tick);
797                }
798            }
799        }
800        w.bool(g.switched);
801        match g.decay {
802            None => w.u8(0),
803            Some(t) => {
804                w.u8(1);
805                w.u64(t);
806            }
807        }
808        w.len(g.strength_keys.len());
809        for k in &g.strength_keys {
810            w.u64(*k);
811        }
812        w.u8(g.charge);
813        put_opt_u32(w, g.strength_tick);
814        w.len(g.sides.len());
815        for sd in &g.sides {
816            w.u64(sd.key);
817            w.len(sd.inside.len());
818            for &b in &sd.inside {
819                w.bool(b);
820            }
821        }
822    }
823}
824pub fn get_groups(r: &mut Reader<'_>) -> Result<Vec<GroupImage>, ImageError> {
825    let n = r.len()?;
826    (0..n)
827        .map(|_| {
828            let kind = get_net_kind(r)?;
829            let width = r.u32()?;
830            let m = r.len()?;
831            let nets = (0..m)
832                .map(|_| Ok((InstanceId(r.u32()?), r.u32()?)))
833                .collect::<Result<_, ImageError>>()?;
834            let m = r.len()?;
835            let drivers = (0..m)
836                .map(|_| {
837                    Ok(DriverImage {
838                        slot: r.u32()?,
839                        strength: DriveStrengthPair {
840                            s0: get_strength(r)?,
841                            s1: get_strength(r)?,
842                        },
843                        ambiguous: get_opt_u32(r)?,
844                        src: match r.u8()? {
845                            0 => None,
846                            1 => Some(StrengthSrc {
847                                key: r.u64()?,
848                                bit: r.u32()?,
849                                out_bit: r.u32()?,
850                                resistive: r.bool()?,
851                                tick: r.u32()?,
852                            }),
853                            tag => {
854                                return Err(ImageError::BadTag {
855                                    what: "strength source",
856                                    tag,
857                                });
858                            }
859                        },
860                    })
861                })
862                .collect::<Result<_, ImageError>>()?;
863            let switched = r.bool()?;
864            let decay = match r.u8()? {
865                0 => None,
866                1 => Some(r.u64()?),
867                tag => {
868                    return Err(ImageError::BadTag {
869                        what: "trireg decay",
870                        tag,
871                    });
872                }
873            };
874            let m = r.len()?;
875            let strength_keys = (0..m).map(|_| r.u64()).collect::<Result<_, ImageError>>()?;
876            Ok(GroupImage {
877                kind,
878                width,
879                nets,
880                drivers,
881                switched,
882                decay,
883                strength_keys,
884                charge: r.u8()?,
885                strength_tick: get_opt_u32(r)?,
886                sides: {
887                    let m = r.len()?;
888                    (0..m)
889                        .map(|_| {
890                            let key = r.u64()?;
891                            let k = r.len()?;
892                            let inside = (0..k).map(|_| r.bool()).collect::<Result<_, _>>()?;
893                            Ok(SideSpec { key, inside })
894                        })
895                        .collect::<Result<_, ImageError>>()?
896                },
897            })
898        })
899        .collect()
900}
901
902fn put_conducts(w: &mut Writer, c: &ConductsImage) {
903    match c {
904        ConductsImage::Always => w.u8(0),
905        ConductsImage::When(ctrl, want) => {
906            w.u8(1);
907            match ctrl {
908                ControlImage::Bit {
909                    instance,
910                    slot,
911                    width,
912                    bit,
913                } => {
914                    w.u8(0);
915                    w.u32(instance.0);
916                    w.u32(*slot);
917                    w.u32(*width);
918                    w.u32(*bit);
919                }
920                ControlImage::Const(v) => {
921                    w.u8(1);
922                    w.u8(*v);
923                }
924            }
925            w.bool(*want);
926        }
927    }
928}
929fn get_conducts(r: &mut Reader<'_>) -> Result<ConductsImage, ImageError> {
930    match r.u8()? {
931        0 => Ok(ConductsImage::Always),
932        1 => {
933            let ctrl = match r.u8()? {
934                0 => ControlImage::Bit {
935                    instance: InstanceId(r.u32()?),
936                    slot: r.u32()?,
937                    width: r.u32()?,
938                    bit: r.u32()?,
939                },
940                1 => ControlImage::Const(r.u8()?),
941                tag => {
942                    return Err(ImageError::BadTag {
943                        what: "switch control",
944                        tag,
945                    });
946                }
947            };
948            Ok(ConductsImage::When(ctrl, r.bool()?))
949        }
950        tag => Err(ImageError::BadTag {
951            what: "switch conduction",
952            tag,
953        }),
954    }
955}
956
957pub fn put_networks(w: &mut Writer, v: &[NetworkImage]) {
958    w.len(v.len());
959    for n in v {
960        w.len(n.groups.len());
961        for g in &n.groups {
962            w.u32(*g);
963        }
964        w.len(n.switches.len());
965        for s in &n.switches {
966            w.u32(s.a.0);
967            w.u32(s.a.1);
968            w.u32(s.b.0);
969            w.u32(s.b.1);
970            put_conducts(w, &s.conducts);
971            w.bool(s.resistive);
972        }
973    }
974}
975pub fn get_networks(r: &mut Reader<'_>) -> Result<Vec<NetworkImage>, ImageError> {
976    let n = r.len()?;
977    (0..n)
978        .map(|_| {
979            let m = r.len()?;
980            let groups = (0..m).map(|_| r.u32()).collect::<Result<_, _>>()?;
981            let m = r.len()?;
982            let switches = (0..m)
983                .map(|_| {
984                    Ok(SwitchImage {
985                        a: (r.u32()?, r.u32()?),
986                        b: (r.u32()?, r.u32()?),
987                        conducts: get_conducts(r)?,
988                        resistive: r.bool()?,
989                    })
990                })
991                .collect::<Result<_, ImageError>>()?;
992            Ok(NetworkImage { groups, switches })
993        })
994        .collect()
995}
996
997pub fn put_symbols(w: &mut Writer, v: &[String]) {
998    w.len(v.len());
999    for s in v {
1000        w.str(s);
1001    }
1002}
1003pub fn get_symbols(r: &mut Reader<'_>) -> Result<Vec<String>, ImageError> {
1004    let n = r.len()?;
1005    (0..n).map(|_| r.str()).collect()
1006}
1007
1008pub fn put_kernels(w: &mut Writer, v: &[KernelImage]) {
1009    w.len(v.len());
1010    for k in v {
1011        w.u32(k.symbol);
1012        w.u32(k.frame_words);
1013        put_process_kind(w, k.kind);
1014        w.u32(k.instance.0);
1015        w.u8(match k.role {
1016            KernelRole::Process => 0,
1017            KernelRole::ContAssign => 1,
1018            KernelRole::VarInit => 2,
1019        });
1020        w.bool(k.level_head);
1021        w.bool(k.reactive);
1022        w.bool(k.program_initial);
1023        w.bool(k.registered);
1024        w.len(k.read_set.len());
1025        for s in &k.read_set {
1026            w.u32(*s);
1027        }
1028        w.len(k.read_windows.len());
1029        for (slot, lsb, width) in &k.read_windows {
1030            w.u32(*slot);
1031            w.u32(*lsb);
1032            w.u32(*width);
1033        }
1034        match k.reset {
1035            None => w.u8(0),
1036            Some((slot, edge)) => {
1037                w.u8(1);
1038                w.u32(slot);
1039                put_edge(w, edge);
1040            }
1041        }
1042        w.len(k.disable_scopes.len());
1043        for (resume, label, exit) in &k.disable_scopes {
1044            w.u32(*resume);
1045            w.str(label);
1046            w.u32(*exit);
1047        }
1048    }
1049}
1050pub fn get_kernels(r: &mut Reader<'_>) -> Result<Vec<KernelImage>, ImageError> {
1051    let n = r.len()?;
1052    (0..n)
1053        .map(|_| {
1054            let symbol = r.u32()?;
1055            let frame_words = r.u32()?;
1056            let kind = get_process_kind(r)?;
1057            let instance = InstanceId(r.u32()?);
1058            let role = match r.u8()? {
1059                0 => KernelRole::Process,
1060                1 => KernelRole::ContAssign,
1061                2 => KernelRole::VarInit,
1062                tag => {
1063                    return Err(ImageError::BadTag {
1064                        what: "kernel role",
1065                        tag,
1066                    });
1067                }
1068            };
1069            let level_head = r.bool()?;
1070            let reactive = r.bool()?;
1071            let program_initial = r.bool()?;
1072            let registered = r.bool()?;
1073            let m = r.len()?;
1074            let read_set = (0..m).map(|_| r.u32()).collect::<Result<_, _>>()?;
1075            let m = r.len()?;
1076            let read_windows = (0..m)
1077                .map(|_| Ok((r.u32()?, r.u32()?, r.u32()?)))
1078                .collect::<Result<_, ImageError>>()?;
1079            let reset = match r.u8()? {
1080                0 => None,
1081                1 => Some((r.u32()?, get_edge(r)?)),
1082                tag => {
1083                    return Err(ImageError::BadTag {
1084                        what: "option",
1085                        tag,
1086                    });
1087                }
1088            };
1089            let m = r.len()?;
1090            let disable_scopes = (0..m)
1091                .map(|_| Ok((r.u32()?, r.str()?, r.u32()?)))
1092                .collect::<Result<_, ImageError>>()?;
1093            Ok(KernelImage {
1094                symbol,
1095                frame_words,
1096                kind,
1097                instance,
1098                role,
1099                level_head,
1100                reactive,
1101                program_initial,
1102                registered,
1103                read_set,
1104                read_windows,
1105                reset,
1106                disable_scopes,
1107            })
1108        })
1109        .collect()
1110}
1111
1112pub fn put_fork_table(w: &mut Writer, v: &[SpawnSpec]) {
1113    w.len(v.len());
1114    for s in v {
1115        w.u32(s.kernel);
1116        w.u32(s.entry_pc);
1117        w.u32(s.parent);
1118        w.len(s.disable_name.len());
1119        for n in &s.disable_name {
1120            w.str(n);
1121        }
1122    }
1123}
1124pub fn get_fork_table(r: &mut Reader<'_>) -> Result<Vec<SpawnSpec>, ImageError> {
1125    let n = r.len()?;
1126    (0..n)
1127        .map(|_| {
1128            let kernel = r.u32()?;
1129            let entry_pc = r.u32()?;
1130            let parent = r.u32()?;
1131            let m = r.len()?;
1132            let disable_name = (0..m).map(|_| r.str()).collect::<Result<_, _>>()?;
1133            Ok(SpawnSpec {
1134                kernel,
1135                entry_pc,
1136                parent,
1137                disable_name,
1138            })
1139        })
1140        .collect()
1141}
1142
1143pub fn put_fork_branches(w: &mut Writer, v: &[ForkBranchImage]) {
1144    w.len(v.len());
1145    for b in v {
1146        w.u32(b.symbol);
1147        w.u32(b.frame_words);
1148        w.len(b.captures.len());
1149        for (p, c) in &b.captures {
1150            w.u32(*p);
1151            w.u32(*c);
1152        }
1153        w.len(b.disable_scopes.len());
1154        for (resume, label, exit) in &b.disable_scopes {
1155            w.u32(*resume);
1156            w.str(label);
1157            w.u32(*exit);
1158        }
1159    }
1160}
1161pub fn get_fork_branches(r: &mut Reader<'_>) -> Result<Vec<ForkBranchImage>, ImageError> {
1162    let n = r.len()?;
1163    (0..n)
1164        .map(|_| {
1165            let symbol = r.u32()?;
1166            let frame_words = r.u32()?;
1167            let m = r.len()?;
1168            let captures = (0..m)
1169                .map(|_| Ok((r.u32()?, r.u32()?)))
1170                .collect::<Result<_, ImageError>>()?;
1171            let m = r.len()?;
1172            let disable_scopes = (0..m)
1173                .map(|_| Ok((r.u32()?, r.str()?, r.u32()?)))
1174                .collect::<Result<_, ImageError>>()?;
1175            Ok(ForkBranchImage {
1176                symbol,
1177                frame_words,
1178                captures,
1179                disable_scopes,
1180            })
1181        })
1182        .collect()
1183}
1184
1185pub fn put_wait_table(w: &mut Writer, v: &[WaitTableEntry]) {
1186    w.len(v.len());
1187    for e in v {
1188        w.u32(e.slot);
1189        put_opt_edge(w, e.edge);
1190        match e.select {
1191            None => w.u8(0),
1192            Some((lsb, width)) => {
1193                w.u8(1);
1194                w.u32(lsb);
1195                w.u32(width);
1196            }
1197        }
1198    }
1199}
1200pub fn get_wait_table(r: &mut Reader<'_>) -> Result<Vec<WaitTableEntry>, ImageError> {
1201    let n = r.len()?;
1202    (0..n)
1203        .map(|_| {
1204            let slot = r.u32()?;
1205            let edge = get_opt_edge(r)?;
1206            let select = match r.u8()? {
1207                0 => None,
1208                1 => Some((r.u32()?, r.u32()?)),
1209                tag => {
1210                    return Err(ImageError::BadTag {
1211                        what: "WaitTableEntry::select",
1212                        tag,
1213                    });
1214                }
1215            };
1216            Ok(WaitTableEntry { slot, edge, select })
1217        })
1218        .collect()
1219}
1220
1221pub fn put_strings(w: &mut Writer, v: &[Vec<u8>]) {
1222    w.len(v.len());
1223    for s in v {
1224        w.bytes(s);
1225    }
1226}
1227pub fn get_strings(r: &mut Reader<'_>) -> Result<Vec<Vec<u8>>, ImageError> {
1228    let n = r.len()?;
1229    (0..n).map(|_| r.bytes()).collect()
1230}
1231
1232fn put_collection_key(w: &mut Writer, k: &Key) {
1233    match k {
1234        Key::Int(v) => {
1235            w.u8(0);
1236            w.u128(*v as u128);
1237        }
1238        Key::Big(words) => {
1239            w.u8(1);
1240            w.words(words);
1241        }
1242        Key::Str(bytes) => {
1243            w.u8(2);
1244            w.bytes(bytes);
1245        }
1246    }
1247}
1248fn get_collection_key(r: &mut Reader<'_>) -> Result<Key, ImageError> {
1249    match r.u8()? {
1250        0 => Ok(Key::Int(r.u128()? as i128)),
1251        1 => Ok(Key::Big(r.words()?)),
1252        2 => Ok(Key::Str(r.bytes()?)),
1253        tag => Err(ImageError::BadTag {
1254            what: "collection key",
1255            tag,
1256        }),
1257    }
1258}
1259
1260pub fn put_collections(w: &mut Writer, v: &[FrozenData]) {
1261    w.len(v.len());
1262    for c in v {
1263        match c {
1264            FrozenData::Seq { stride, words } => {
1265                w.u8(0);
1266                w.len(*stride);
1267                w.words(words);
1268            }
1269            FrozenData::Map { entries, default } => {
1270                w.u8(1);
1271                w.len(entries.len());
1272                for (k, value) in entries {
1273                    put_collection_key(w, k);
1274                    w.words(value);
1275                }
1276                match default {
1277                    None => w.u8(0),
1278                    Some(d) => {
1279                        w.u8(1);
1280                        w.words(d);
1281                    }
1282                }
1283            }
1284        }
1285    }
1286}
1287pub fn get_collections(r: &mut Reader<'_>) -> Result<Vec<FrozenData>, ImageError> {
1288    let n = r.len()?;
1289    (0..n)
1290        .map(|_| match r.u8()? {
1291            0 => Ok(FrozenData::Seq {
1292                stride: r.len()?,
1293                words: r.words()?,
1294            }),
1295            1 => {
1296                let n = r.len()?;
1297                let entries = (0..n)
1298                    .map(|_| Ok((get_collection_key(r)?, r.words()?)))
1299                    .collect::<Result<_, ImageError>>()?;
1300                let default = match r.u8()? {
1301                    0 => None,
1302                    1 => Some(r.words()?),
1303                    tag => {
1304                        return Err(ImageError::BadTag {
1305                            what: "collection default",
1306                            tag,
1307                        });
1308                    }
1309                };
1310                Ok(FrozenData::Map { entries, default })
1311            }
1312            tag => Err(ImageError::BadTag {
1313                what: "collection",
1314                tag,
1315            }),
1316        })
1317        .collect()
1318}
1319
1320fn put_field_slot(w: &mut Writer, s: &FieldSlot) {
1321    // Values, not element counts: `Reader::len` would bound them by the bytes left.
1322    w.u64(s.offset as u64);
1323    w.u64(s.words as u64);
1324}
1325fn get_field_slot(r: &mut Reader<'_>) -> Result<FieldSlot, ImageError> {
1326    Ok(FieldSlot {
1327        offset: r.u64()? as usize,
1328        words: r.u64()? as usize,
1329    })
1330}
1331
1332pub fn put_classes(w: &mut Writer, v: &[TemplateSnapshot]) {
1333    w.len(v.len());
1334    for t in v {
1335        w.u32(t.id.0);
1336        w.len(t.handle_fields.len());
1337        t.handle_fields.iter().for_each(|s| put_field_slot(w, s));
1338        w.len(t.collection_fields.len());
1339        t.collection_fields
1340            .iter()
1341            .for_each(|s| put_field_slot(w, s));
1342        w.len(t.nested_handles.len());
1343        for n in &t.nested_handles {
1344            put_field_slot(w, &n.slot);
1345            w.u32(n.bit);
1346            w.bool(n.coll);
1347        }
1348        w.len(t.ancestors.len());
1349        for a in &t.ancestors {
1350            w.u32(a.0);
1351        }
1352        w.len(t.rand_props.len());
1353        for p in &t.rand_props {
1354            put_field_slot(w, &p.slot);
1355            w.u8(match p.kind {
1356                RandKind::Rand => 0,
1357                RandKind::RandC => 1,
1358            });
1359        }
1360    }
1361}
1362pub fn get_classes(r: &mut Reader<'_>) -> Result<Vec<TemplateSnapshot>, ImageError> {
1363    let n = r.len()?;
1364    (0..n)
1365        .map(|_| {
1366            let id = ClassTemplateId(r.u32()?);
1367            let n = r.len()?;
1368            let handle_fields = (0..n)
1369                .map(|_| get_field_slot(r))
1370                .collect::<Result<_, _>>()?;
1371            let n = r.len()?;
1372            let collection_fields = (0..n)
1373                .map(|_| get_field_slot(r))
1374                .collect::<Result<_, _>>()?;
1375            let n = r.len()?;
1376            let nested_handles = (0..n)
1377                .map(|_| {
1378                    Ok(NestedHandle {
1379                        slot: get_field_slot(r)?,
1380                        bit: r.u32()?,
1381                        coll: r.bool()?,
1382                    })
1383                })
1384                .collect::<Result<_, ImageError>>()?;
1385            let n = r.len()?;
1386            let ancestors = (0..n)
1387                .map(|_| Ok(ClassTemplateId(r.u32()?)))
1388                .collect::<Result<_, ImageError>>()?;
1389            let n = r.len()?;
1390            let rand_props = (0..n)
1391                .map(|_| {
1392                    let slot = get_field_slot(r)?;
1393                    let kind = match r.u8()? {
1394                        0 => RandKind::Rand,
1395                        1 => RandKind::RandC,
1396                        tag => {
1397                            return Err(ImageError::BadTag {
1398                                what: "rand kind",
1399                                tag,
1400                            });
1401                        }
1402                    };
1403                    Ok(RandProp { slot, kind })
1404                })
1405                .collect::<Result<_, ImageError>>()?;
1406            Ok(TemplateSnapshot {
1407                id,
1408                handle_fields,
1409                collection_fields,
1410                nested_handles,
1411                ancestors,
1412                rand_props,
1413            })
1414        })
1415        .collect()
1416}
1417
1418pub fn put_stmt_sites(w: &mut Writer, v: &[StmtSiteImage]) {
1419    w.len(v.len());
1420    for s in v {
1421        w.str(&s.def);
1422        w.u32(s.buffer);
1423        w.u64(s.start);
1424        w.u64(s.end);
1425        w.u32(u32::from(s.kind));
1426        w.u32(s.nest);
1427    }
1428}
1429
1430pub fn get_stmt_sites(r: &mut Reader<'_>) -> Result<Vec<StmtSiteImage>, ImageError> {
1431    let n = r.len()?;
1432    (0..n)
1433        .map(|_| {
1434            Ok(StmtSiteImage {
1435                def: r.str()?,
1436                buffer: r.u32()?,
1437                start: r.u64()?,
1438                end: r.u64()?,
1439                kind: r.u32()? as u16,
1440                nest: r.u32()?,
1441            })
1442        })
1443        .collect()
1444}
1445
1446pub fn put_fsms(w: &mut Writer, v: &[FsmImage]) {
1447    w.len(v.len());
1448    for f in v {
1449        w.u32(f.instance.0);
1450        w.str(&f.name);
1451        w.len(f.parts.len());
1452        for p in &f.parts {
1453            w.u32(p.slot);
1454            w.u32(p.msb);
1455            w.u32(p.lsb);
1456        }
1457        w.len(f.states.len());
1458        for (n, val) in &f.states {
1459            w.str(n);
1460            w.u64(*val);
1461        }
1462    }
1463}
1464
1465pub fn get_fsms(r: &mut Reader<'_>) -> Result<Vec<FsmImage>, ImageError> {
1466    let n = r.len()?;
1467    (0..n)
1468        .map(|_| {
1469            let instance = InstanceId(r.u32()?);
1470            let name = r.str()?;
1471            let n = r.len()?;
1472            let parts = (0..n)
1473                .map(|_| {
1474                    Ok(FsmPartImage {
1475                        slot: r.u32()?,
1476                        msb: r.u32()?,
1477                        lsb: r.u32()?,
1478                    })
1479                })
1480                .collect::<Result<_, ImageError>>()?;
1481            let n = r.len()?;
1482            let states = (0..n)
1483                .map(|_| Ok((r.str()?, r.u64()?)))
1484                .collect::<Result<_, ImageError>>()?;
1485            Ok(FsmImage {
1486                instance,
1487                name,
1488                parts,
1489                states,
1490            })
1491        })
1492        .collect()
1493}
1494
1495pub fn put_dump_signals(w: &mut Writer, v: &[DumpSignalImage]) {
1496    w.len(v.len());
1497    for s in v {
1498        w.u32(s.instance.0);
1499        w.str(&s.def_name);
1500        w.len(s.scope.len());
1501        for name in &s.scope {
1502            w.str(name);
1503        }
1504        w.len(s.scope_kinds.len());
1505        for kind in &s.scope_kinds {
1506            w.u8(match kind {
1507                ScopeKind::Module => 0,
1508                ScopeKind::Begin => 1,
1509                ScopeKind::Fork => 2,
1510                ScopeKind::Task => 3,
1511                ScopeKind::Function => 4,
1512            });
1513        }
1514        w.str(&s.name);
1515        w.u32(s.width);
1516        w.u8(VcdVarType::ALL
1517            .iter()
1518            .position(|t| *t == s.var_type)
1519            .unwrap() as u8);
1520        w.u32(s.slot);
1521        w.bool(s.wide);
1522        w.bool(s.real);
1523        w.bool(s.class_handle);
1524        w.u8(match s.port {
1525            None => 0,
1526            Some(PortDir::Input) => 1,
1527            Some(PortDir::Output) => 2,
1528            Some(PortDir::Inout) => 3,
1529        });
1530        put_opt_u64(w, s.strength_key);
1531        put_opt_u64(w, s.side_key);
1532    }
1533}
1534pub fn get_dump_signals(r: &mut Reader<'_>) -> Result<Vec<DumpSignalImage>, ImageError> {
1535    let n = r.len()?;
1536    (0..n)
1537        .map(|_| {
1538            let instance = InstanceId(r.u32()?);
1539            let def_name = r.str()?;
1540            let n = r.len()?;
1541            let scope = (0..n).map(|_| r.str()).collect::<Result<_, _>>()?;
1542            let n = r.len()?;
1543            let scope_kinds = (0..n)
1544                .map(|_| {
1545                    Ok(match r.u8()? {
1546                        0 => ScopeKind::Module,
1547                        1 => ScopeKind::Begin,
1548                        2 => ScopeKind::Fork,
1549                        3 => ScopeKind::Task,
1550                        4 => ScopeKind::Function,
1551                        tag => {
1552                            return Err(ImageError::BadTag {
1553                                what: "scope kind",
1554                                tag,
1555                            });
1556                        }
1557                    })
1558                })
1559                .collect::<Result<_, ImageError>>()?;
1560            Ok(DumpSignalImage {
1561                instance,
1562                def_name,
1563                scope,
1564                scope_kinds,
1565                name: r.str()?,
1566                width: r.u32()?,
1567                var_type: {
1568                    let tag = r.u8()?;
1569                    *VcdVarType::ALL
1570                        .get(tag as usize)
1571                        .ok_or(ImageError::BadTag {
1572                            what: "vcd var type",
1573                            tag,
1574                        })?
1575                },
1576                slot: r.u32()?,
1577                wide: r.bool()?,
1578                real: r.bool()?,
1579                class_handle: r.bool()?,
1580                port: match r.u8()? {
1581                    0 => None,
1582                    1 => Some(PortDir::Input),
1583                    2 => Some(PortDir::Output),
1584                    3 => Some(PortDir::Inout),
1585                    tag => {
1586                        return Err(ImageError::BadTag {
1587                            what: "port direction",
1588                            tag,
1589                        });
1590                    }
1591                },
1592                strength_key: get_opt_u64(r, "port strength key")?,
1593                side_key: get_opt_u64(r, "port side key")?,
1594            })
1595        })
1596        .collect()
1597}
1598
1599pub fn put_dpi(w: &mut Writer, v: &DpiImage) {
1600    w.len(v.imports.len());
1601    for name in &v.imports {
1602        w.str(name);
1603    }
1604    w.len(v.exports.len());
1605    for (name, symbol) in &v.exports {
1606        w.str(name);
1607        w.u32(*symbol);
1608    }
1609    w.len(v.variants.len());
1610    for (name, scope, variant) in &v.variants {
1611        w.str(name);
1612        w.str(scope);
1613        w.u32(*variant);
1614    }
1615    w.bool(v.task_fibers);
1616}
1617pub fn get_dpi(r: &mut Reader<'_>) -> Result<DpiImage, ImageError> {
1618    let n = r.len()?;
1619    let imports = (0..n).map(|_| r.str()).collect::<Result<_, _>>()?;
1620    let n = r.len()?;
1621    let exports = (0..n)
1622        .map(|_| Ok((r.str()?, r.u32()?)))
1623        .collect::<Result<_, ImageError>>()?;
1624    let n = r.len()?;
1625    let variants = (0..n)
1626        .map(|_| Ok((r.str()?, r.str()?, r.u32()?)))
1627        .collect::<Result<_, ImageError>>()?;
1628    Ok(DpiImage {
1629        imports,
1630        exports,
1631        variants,
1632        task_fibers: r.bool()?,
1633    })
1634}
1635
1636// ---- timing ---------------------------------------------------------------
1637
1638fn put_opt_u64(w: &mut Writer, v: Option<u64>) {
1639    match v {
1640        None => w.u8(0),
1641        Some(x) => {
1642            w.u8(1);
1643            w.u64(x);
1644        }
1645    }
1646}
1647fn get_opt_u64(r: &mut Reader<'_>, what: &'static str) -> Result<Option<u64>, ImageError> {
1648    match r.u8()? {
1649        0 => Ok(None),
1650        1 => Ok(Some(r.u64()?)),
1651        tag => Err(ImageError::BadTag { what, tag }),
1652    }
1653}
1654fn put_opt_u8(w: &mut Writer, v: Option<u8>) {
1655    match v {
1656        None => w.u8(0),
1657        Some(x) => {
1658            w.u8(1);
1659            w.u8(x);
1660        }
1661    }
1662}
1663/// An optional small enumeration (`0..=max`): a value outside it is refused.
1664fn get_opt_enum(r: &mut Reader<'_>, what: &'static str, max: u8) -> Result<Option<u8>, ImageError> {
1665    match r.u8()? {
1666        0 => Ok(None),
1667        1 => {
1668            let v = r.u8()?;
1669            if v > max {
1670                return Err(ImageError::BadTag { what, tag: v });
1671            }
1672            Ok(Some(v))
1673        }
1674        tag => Err(ImageError::BadTag { what, tag }),
1675    }
1676}
1677
1678pub fn put_timing(w: &mut Writer, v: &TimingImage) {
1679    let o = &v.options;
1680    w.bool(o.per_bit_vectors);
1681    w.bool(o.negative_timing_checks);
1682    put_opt_u64(w, o.reject_limit_pct);
1683    put_opt_u64(w, o.error_limit_pct);
1684    put_opt_u8(w, o.pulse_style);
1685    put_opt_u8(w, o.showcancelled.map(u8::from));
1686    put_opt_u8(w, o.sdf_mtm);
1687    w.bytes(&v.plan);
1688}
1689pub fn get_timing(r: &mut Reader<'_>) -> Result<TimingImage, ImageError> {
1690    let per_bit_vectors = r.bool()?;
1691    let negative_timing_checks = r.bool()?;
1692    let reject_limit_pct = get_opt_u64(r, "reject limit")?;
1693    let error_limit_pct = get_opt_u64(r, "error limit")?;
1694    let pulse_style = get_opt_enum(r, "pulse style", 1)?;
1695    let showcancelled = get_opt_enum(r, "showcancelled", 1)?.map(|v| v == 1);
1696    let sdf_mtm = get_opt_enum(r, "sdf mtm", 2)?;
1697    Ok(TimingImage {
1698        options: TimingOptionsImage {
1699            per_bit_vectors,
1700            negative_timing_checks,
1701            reject_limit_pct,
1702            error_limit_pct,
1703            pulse_style,
1704            showcancelled,
1705            sdf_mtm,
1706        },
1707        plan: r.bytes()?,
1708    })
1709}
1710
1711// ---- verification ---------------------------------------------------------
1712
1713fn put_assert_kind(w: &mut Writer, k: AssertKind) {
1714    w.u8(match k {
1715        AssertKind::Assert => 0,
1716        AssertKind::Assume => 1,
1717        AssertKind::CoverProperty => 2,
1718        AssertKind::CoverSequence => 3,
1719        AssertKind::Restrict => 4,
1720        AssertKind::Expect => 5,
1721    });
1722}
1723fn get_assert_kind(r: &mut Reader<'_>) -> Result<AssertKind, ImageError> {
1724    Ok(match r.u8()? {
1725        0 => AssertKind::Assert,
1726        1 => AssertKind::Assume,
1727        2 => AssertKind::CoverProperty,
1728        3 => AssertKind::CoverSequence,
1729        4 => AssertKind::Restrict,
1730        5 => AssertKind::Expect,
1731        tag => {
1732            return Err(ImageError::BadTag {
1733                what: "assertion kind",
1734                tag,
1735            });
1736        }
1737    })
1738}
1739
1740fn put_site(w: &mut Writer, s: &Option<SiteDesc>) {
1741    match s {
1742        None => w.u8(0),
1743        Some(SiteDesc {
1744            assertion_type,
1745            directive_type,
1746            scope,
1747            label,
1748        }) => {
1749            w.u8(1);
1750            w.u32(*assertion_type);
1751            w.u32(*directive_type);
1752            w.str(scope);
1753            w.str(label);
1754        }
1755    }
1756}
1757fn get_site(r: &mut Reader<'_>) -> Result<Option<SiteDesc>, ImageError> {
1758    match r.u8()? {
1759        0 => Ok(None),
1760        1 => Ok(Some(SiteDesc {
1761            assertion_type: r.u32()?,
1762            directive_type: r.u32()?,
1763            scope: r.str()?,
1764            label: r.str()?,
1765        })),
1766        tag => Err(ImageError::BadTag {
1767            what: "assertion site",
1768            tag,
1769        }),
1770    }
1771}
1772
1773fn put_u32_pairs(w: &mut Writer, v: &[(u32, u32)]) {
1774    w.len(v.len());
1775    for (a, b) in v {
1776        w.u32(*a);
1777        w.u32(*b);
1778    }
1779}
1780fn get_u32_pairs(r: &mut Reader<'_>) -> Result<Vec<(u32, u32)>, ImageError> {
1781    let n = r.len()?;
1782    (0..n).map(|_| Ok((r.u32()?, r.u32()?))).collect()
1783}
1784
1785fn put_assertion(w: &mut Writer, a: &AssertionImage) {
1786    let AssertionImage {
1787        plan_index,
1788        instance,
1789        kernel,
1790        frame_words,
1791        label,
1792        kind,
1793        ir,
1794        n_clocks,
1795        hist_clocks,
1796        leaf_reads,
1797        leaf_writes,
1798        activated,
1799        captured,
1800        disable_mixed,
1801        tick_history,
1802        history_depth,
1803        future,
1804        future_clock,
1805        src_offset,
1806        leaf_src,
1807        row_len,
1808        snap,
1809        ticks,
1810        leaves,
1811        live_leaves,
1812        cases,
1813        site,
1814        end_cell,
1815        current_words,
1816        observed_words,
1817        coll_words,
1818        coll_nests,
1819        spawn_calls,
1820    } = a;
1821    w.u32(*plan_index);
1822    w.u32(instance.0);
1823    w.u32(*kernel);
1824    w.u32(*frame_words);
1825    w.str(label);
1826    put_assert_kind(w, *kind);
1827    crate::sva::codec::put_property_ir(w, ir);
1828    w.u32(*n_clocks);
1829    w.u32(*hist_clocks);
1830    w.len(leaf_reads.len());
1831    for reads in leaf_reads {
1832        w.len(reads.len());
1833        for v in reads {
1834            w.u32(v.0);
1835        }
1836    }
1837    w.len(leaf_writes.len());
1838    for v in leaf_writes {
1839        put_opt_u32(w, v.map(|v| v.0));
1840    }
1841    w.bool(*activated);
1842    w.len(captured.len());
1843    for v in captured {
1844        w.u32(v.0);
1845    }
1846    w.bool(*disable_mixed);
1847    w.bool(*tick_history);
1848    w.u32(*history_depth);
1849    w.bool(*future);
1850    w.u32(*future_clock);
1851    put_opt_u64(w, *src_offset);
1852    w.len(leaf_src.len());
1853    for (buf, lo, hi) in leaf_src {
1854        w.u32(*buf);
1855        w.u64(*lo);
1856        w.u64(*hi);
1857    }
1858    w.u32(*row_len);
1859    w.u32(*snap);
1860    w.len(ticks.len());
1861    for t in ticks {
1862        w.u32(*t);
1863    }
1864    w.len(leaves.len());
1865    for l in leaves {
1866        put_opt_u32(w, *l);
1867    }
1868    w.len(live_leaves.len());
1869    for l in live_leaves {
1870        put_opt_u32(w, *l);
1871    }
1872    w.len(cases.len());
1873    for CasePairImage {
1874        selector,
1875        label,
1876        symbol,
1877    } in cases
1878    {
1879        w.u32(selector.0);
1880        w.u32(label.0);
1881        w.u32(*symbol);
1882    }
1883    put_site(w, site);
1884    put_opt_u32(w, *end_cell);
1885    w.len(current_words.len());
1886    for (id, base, n) in current_words {
1887        w.str(id);
1888        w.u32(*base);
1889        w.u32(*n);
1890    }
1891    w.len(observed_words.len());
1892    for (base, n) in observed_words {
1893        w.u32(*base);
1894        w.u32(*n);
1895    }
1896    w.len(coll_words.len());
1897    for base in coll_words {
1898        w.u32(*base);
1899    }
1900    w.len(coll_nests.len());
1901    for n in coll_nests {
1902        put_nest(w, n);
1903    }
1904    w.len(spawn_calls.len());
1905    for c in spawn_calls {
1906        w.u32(c.call);
1907        w.u32(c.kernel);
1908        w.u32(c.frame_words);
1909        w.u32(c.entry_pc);
1910    }
1911}
1912fn get_assertion(r: &mut Reader<'_>) -> Result<AssertionImage, ImageError> {
1913    let plan_index = r.u32()?;
1914    let instance = InstanceId(r.u32()?);
1915    let kernel = r.u32()?;
1916    let frame_words = r.u32()?;
1917    let label = r.str()?;
1918    let kind = get_assert_kind(r)?;
1919    let ir = crate::sva::codec::get_property_ir(r)?;
1920    let n_clocks = r.u32()?;
1921    let hist_clocks = r.u32()?;
1922    let n = r.len()?;
1923    let mut leaf_reads = Vec::with_capacity(n);
1924    for _ in 0..n {
1925        let m = r.len()?;
1926        leaf_reads.push(
1927            (0..m)
1928                .map(|_| r.u32().map(LocalVarId))
1929                .collect::<Result<_, _>>()?,
1930        );
1931    }
1932    let n = r.len()?;
1933    let leaf_writes = (0..n)
1934        .map(|_| get_opt_u32(r).map(|v| v.map(LocalVarId)))
1935        .collect::<Result<_, _>>()?;
1936    let activated = r.bool()?;
1937    let n = r.len()?;
1938    let captured = (0..n)
1939        .map(|_| r.u32().map(LocalVarId))
1940        .collect::<Result<_, _>>()?;
1941    let disable_mixed = r.bool()?;
1942    let tick_history = r.bool()?;
1943    let history_depth = r.u32()?;
1944    let future = r.bool()?;
1945    let future_clock = r.u32()?;
1946    let src_offset = get_opt_u64(r, "AssertionImage::src_offset")?;
1947    let n = r.len()?;
1948    let leaf_src = (0..n)
1949        .map(|_| Ok((r.u32()?, r.u64()?, r.u64()?)))
1950        .collect::<Result<_, ImageError>>()?;
1951    let row_len = r.u32()?;
1952    let snap = r.u32()?;
1953    let n = r.len()?;
1954    let ticks = (0..n).map(|_| r.u32()).collect::<Result<_, _>>()?;
1955    let n = r.len()?;
1956    let leaves = (0..n).map(|_| get_opt_u32(r)).collect::<Result<_, _>>()?;
1957    let n = r.len()?;
1958    let live_leaves = (0..n).map(|_| get_opt_u32(r)).collect::<Result<_, _>>()?;
1959    let n = r.len()?;
1960    let cases = (0..n)
1961        .map(|_| {
1962            Ok(CasePairImage {
1963                selector: LeafId(r.u32()?),
1964                label: LeafId(r.u32()?),
1965                symbol: r.u32()?,
1966            })
1967        })
1968        .collect::<Result<_, ImageError>>()?;
1969    let site = get_site(r)?;
1970    let end_cell = get_opt_u32(r)?;
1971    let n = r.len()?;
1972    let current_words = (0..n)
1973        .map(|_| Ok((r.str()?, r.u32()?, r.u32()?)))
1974        .collect::<Result<_, ImageError>>()?;
1975    let n = r.len()?;
1976    let observed_words = (0..n)
1977        .map(|_| Ok((r.u32()?, r.u32()?)))
1978        .collect::<Result<_, ImageError>>()?;
1979    let n = r.len()?;
1980    let coll_words = (0..n).map(|_| r.u32()).collect::<Result<_, ImageError>>()?;
1981    let n = r.len()?;
1982    let coll_nests = (0..n)
1983        .map(|_| get_nest(r))
1984        .collect::<Result<_, ImageError>>()?;
1985    let n = r.len()?;
1986    let spawn_calls = (0..n)
1987        .map(|_| {
1988            Ok(SpawnCallImage {
1989                call: r.u32()?,
1990                kernel: r.u32()?,
1991                frame_words: r.u32()?,
1992                entry_pc: r.u32()?,
1993            })
1994        })
1995        .collect::<Result<_, ImageError>>()?;
1996    Ok(AssertionImage {
1997        plan_index,
1998        instance,
1999        kernel,
2000        frame_words,
2001        label,
2002        kind,
2003        ir,
2004        n_clocks,
2005        hist_clocks,
2006        leaf_reads,
2007        leaf_writes,
2008        activated,
2009        captured,
2010        disable_mixed,
2011        tick_history,
2012        history_depth,
2013        future,
2014        future_clock,
2015        src_offset,
2016        leaf_src,
2017        row_len,
2018        snap,
2019        ticks,
2020        leaves,
2021        live_leaves,
2022        cases,
2023        site,
2024        end_cell,
2025        current_words,
2026        observed_words,
2027        coll_words,
2028        coll_nests,
2029        spawn_calls,
2030    })
2031}
2032
2033pub fn put_verif(w: &mut Writer, v: &VerifImage) {
2034    let VerifImage {
2035        assertions,
2036        free_groups,
2037        sampled,
2038        clocking,
2039        covergroups,
2040    } = v;
2041    w.len(assertions.len());
2042    for a in assertions {
2043        put_assertion(w, a);
2044    }
2045    w.len(free_groups.len());
2046    for FreeGroupImage {
2047        instance,
2048        vars,
2049        rng,
2050    } in free_groups
2051    {
2052        w.u32(instance.0);
2053        w.len(vars.len());
2054        for FreeVarImage {
2055            id,
2056            slot,
2057            width,
2058            wide,
2059        } in vars
2060        {
2061            w.str(id);
2062            w.u32(*slot);
2063            w.u32(*width);
2064            w.bool(*wide);
2065        }
2066        w.u64(*rng);
2067    }
2068    w.len(sampled.len());
2069    for SampledImage {
2070        instance,
2071        sites,
2072        p_copies,
2073    } in sampled
2074    {
2075        w.u32(instance.0);
2076        w.len(sites.len());
2077        for SampledSiteImage { guard, shifts } in sites {
2078            w.u32(*guard);
2079            put_u32_pairs(w, shifts);
2080        }
2081        put_u32_pairs(w, p_copies);
2082    }
2083    w.len(clocking.len());
2084    for ClockingImage {
2085        instance,
2086        terms,
2087        gates,
2088        samples,
2089        skews,
2090        parts,
2091        counter,
2092        term_owners,
2093    } in clocking
2094    {
2095        w.u32(instance.0);
2096        w.len(term_owners.len());
2097        for o in term_owners {
2098            w.u32(o.0);
2099        }
2100        w.len(gates.len());
2101        for (term, g) in gates {
2102            w.u32(*term);
2103            w.u32(*g);
2104        }
2105        w.len(terms.len());
2106        for (slot, edge) in terms {
2107            w.u32(*slot);
2108            put_opt_edge(w, *edge);
2109        }
2110        w.len(samples.len());
2111        for (src, dst, width) in samples {
2112            w.u32(*src);
2113            w.u32(*dst);
2114            w.u32(*width);
2115        }
2116        w.len(skews.len());
2117        for k in skews {
2118            w.u64(*k);
2119        }
2120        w.len(parts.len());
2121        for ps in parts {
2122            w.len(ps.len());
2123            for (slot, width, lsb, len) in ps {
2124                w.u32(*slot);
2125                w.u32(*width);
2126                w.u32(*lsb);
2127                w.u32(*len);
2128            }
2129        }
2130        w.u32(*counter);
2131    }
2132    w.len(covergroups.len());
2133    for CovGroupImage {
2134        type_index,
2135        site,
2136        instance,
2137        decl,
2138        kernels,
2139        sampler,
2140        class_clock,
2141        blocks,
2142    } in covergroups
2143    {
2144        w.u32(*type_index);
2145        w.u32(*site);
2146        w.u32(instance.0);
2147        put_covgroup(w, decl);
2148        w.len(kernels.len());
2149        for k in kernels {
2150            w.u32(*k);
2151        }
2152        match sampler {
2153            None => w.u8(0),
2154            Some(CovSamplerImage {
2155                terms,
2156                gates,
2157                exprs,
2158                strobe,
2159            }) => {
2160                w.u8(1);
2161                w.len(terms.len());
2162                for (slot, edge) in terms {
2163                    w.u32(*slot);
2164                    put_opt_edge(w, *edge);
2165                }
2166                w.len(gates.len());
2167                for (term, g) in gates {
2168                    w.u32(*term);
2169                    w.u32(*g);
2170                }
2171                w.len(exprs.len());
2172                for x in exprs {
2173                    w.u32(x.func);
2174                    put_opt_edge(w, x.edge);
2175                    w.len(x.wake.len());
2176                    for t in &x.wake {
2177                        w.u32(*t);
2178                    }
2179                    w.len(x.gates.len());
2180                    for g in &x.gates {
2181                        w.u32(*g);
2182                    }
2183                }
2184                w.bool(*strobe);
2185            }
2186        }
2187        match class_clock {
2188            None => w.u8(0),
2189            Some(CovClassClockImage {
2190                terms,
2191                gates,
2192                strobe,
2193            }) => {
2194                w.u8(1);
2195                w.len(terms.len());
2196                for (k, edge) in terms {
2197                    w.u32(*k);
2198                    put_opt_edge(w, *edge);
2199                }
2200                w.len(gates.len());
2201                for (term, k) in gates {
2202                    w.u32(*term);
2203                    w.u32(*k);
2204                }
2205                w.bool(*strobe);
2206            }
2207        }
2208        w.len(blocks.len());
2209        for b in blocks {
2210            w.u64(*b);
2211        }
2212    }
2213}
2214pub fn get_verif(r: &mut Reader<'_>) -> Result<VerifImage, ImageError> {
2215    let n = r.len()?;
2216    let assertions = (0..n).map(|_| get_assertion(r)).collect::<Result<_, _>>()?;
2217    let n = r.len()?;
2218    let mut free_groups = Vec::with_capacity(n);
2219    for _ in 0..n {
2220        let instance = InstanceId(r.u32()?);
2221        let m = r.len()?;
2222        let vars = (0..m)
2223            .map(|_| {
2224                Ok(FreeVarImage {
2225                    id: r.str()?,
2226                    slot: r.u32()?,
2227                    width: r.u32()?,
2228                    wide: r.bool()?,
2229                })
2230            })
2231            .collect::<Result<_, ImageError>>()?;
2232        free_groups.push(FreeGroupImage {
2233            instance,
2234            vars,
2235            rng: r.u64()?,
2236        });
2237    }
2238    let n = r.len()?;
2239    let mut sampled = Vec::with_capacity(n);
2240    for _ in 0..n {
2241        let instance = InstanceId(r.u32()?);
2242        let m = r.len()?;
2243        let mut sites = Vec::with_capacity(m);
2244        for _ in 0..m {
2245            sites.push(SampledSiteImage {
2246                guard: r.u32()?,
2247                shifts: get_u32_pairs(r)?,
2248            });
2249        }
2250        sampled.push(SampledImage {
2251            instance,
2252            sites,
2253            p_copies: get_u32_pairs(r)?,
2254        });
2255    }
2256    let n = r.len()?;
2257    let mut clocking = Vec::with_capacity(n);
2258    for _ in 0..n {
2259        let instance = InstanceId(r.u32()?);
2260        let m = r.len()?;
2261        let term_owners = (0..m)
2262            .map(|_| Ok(InstanceId(r.u32()?)))
2263            .collect::<Result<_, ImageError>>()?;
2264        let m = r.len()?;
2265        let gates = (0..m)
2266            .map(|_| Ok((r.u32()?, r.u32()?)))
2267            .collect::<Result<_, ImageError>>()?;
2268        let m = r.len()?;
2269        let terms = (0..m)
2270            .map(|_| Ok((r.u32()?, get_opt_edge(r)?)))
2271            .collect::<Result<_, ImageError>>()?;
2272        let m = r.len()?;
2273        let samples = (0..m)
2274            .map(|_| Ok((r.u32()?, r.u32()?, r.u32()?)))
2275            .collect::<Result<_, ImageError>>()?;
2276        let m = r.len()?;
2277        let skews = (0..m).map(|_| r.u64()).collect::<Result<_, ImageError>>()?;
2278        let m = r.len()?;
2279        let parts = (0..m)
2280            .map(|_| {
2281                let k = r.len()?;
2282                (0..k)
2283                    .map(|_| Ok((r.u32()?, r.u32()?, r.u32()?, r.u32()?)))
2284                    .collect::<Result<Vec<_>, ImageError>>()
2285            })
2286            .collect::<Result<_, ImageError>>()?;
2287        clocking.push(ClockingImage {
2288            instance,
2289            terms,
2290            gates,
2291            samples,
2292            skews,
2293            parts,
2294            counter: r.u32()?,
2295            term_owners,
2296        });
2297    }
2298    let n = r.len()?;
2299    let mut covergroups = Vec::with_capacity(n);
2300    for _ in 0..n {
2301        let type_index = r.u32()?;
2302        let site = r.u32()?;
2303        let instance = InstanceId(r.u32()?);
2304        let decl = get_covgroup(r)?;
2305        let m = r.len()?;
2306        let kernels = (0..m).map(|_| r.u32()).collect::<Result<_, _>>()?;
2307        let sampler = match r.u8()? {
2308            0 => None,
2309            1 => {
2310                let m = r.len()?;
2311                let terms = (0..m)
2312                    .map(|_| Ok((r.u32()?, get_opt_edge(r)?)))
2313                    .collect::<Result<_, ImageError>>()?;
2314                let n = r.len()?;
2315                let gates = (0..n)
2316                    .map(|_| Ok((r.u32()?, r.u32()?)))
2317                    .collect::<Result<_, ImageError>>()?;
2318                let n = r.len()?;
2319                let mut exprs = Vec::with_capacity(n);
2320                for _ in 0..n {
2321                    let func = r.u32()?;
2322                    let edge = get_opt_edge(r)?;
2323                    let m = r.len()?;
2324                    let wake = (0..m).map(|_| r.u32()).collect::<Result<_, _>>()?;
2325                    let m = r.len()?;
2326                    let gates = (0..m).map(|_| r.u32()).collect::<Result<_, _>>()?;
2327                    exprs.push(CovExprTermImage {
2328                        func,
2329                        edge,
2330                        wake,
2331                        gates,
2332                    });
2333                }
2334                Some(CovSamplerImage {
2335                    terms,
2336                    gates,
2337                    exprs,
2338                    strobe: r.bool()?,
2339                })
2340            }
2341            tag => {
2342                return Err(ImageError::BadTag {
2343                    what: "covergroup sampler",
2344                    tag,
2345                });
2346            }
2347        };
2348        let class_clock = match r.u8()? {
2349            0 => None,
2350            1 => {
2351                let m = r.len()?;
2352                let terms = (0..m)
2353                    .map(|_| Ok((r.u32()?, get_opt_edge(r)?)))
2354                    .collect::<Result<_, ImageError>>()?;
2355                let n = r.len()?;
2356                let gates = (0..n)
2357                    .map(|_| Ok((r.u32()?, r.u32()?)))
2358                    .collect::<Result<_, ImageError>>()?;
2359                Some(CovClassClockImage {
2360                    terms,
2361                    gates,
2362                    strobe: r.bool()?,
2363                })
2364            }
2365            tag => {
2366                return Err(ImageError::BadTag {
2367                    what: "covergroup class clock",
2368                    tag,
2369                });
2370            }
2371        };
2372        let m = r.len()?;
2373        let blocks = (0..m).map(|_| r.u64()).collect::<Result<_, _>>()?;
2374        covergroups.push(CovGroupImage {
2375            type_index,
2376            site,
2377            instance,
2378            decl,
2379            kernels,
2380            sampler,
2381            class_clock,
2382            blocks,
2383        });
2384    }
2385    Ok(VerifImage {
2386        assertions,
2387        free_groups,
2388        sampled,
2389        clocking,
2390        covergroups,
2391    })
2392}
2393
2394// ---- whole image ----------------------------------------------------------
2395
2396impl DesignImage {
2397    /// The image's deterministic encoding.
2398    pub fn encode(&self) -> Vec<u8> {
2399        let mut body = Writer::default();
2400        body.u32(self.abi_version);
2401        body.i32(self.tick_exp);
2402        body.bool(self.x_initial_zero);
2403        put_templates(&mut body, &self.templates);
2404        put_instances(&mut body, &self.instances);
2405        put_foreign(&mut body, &self.foreign);
2406        put_x_windows(&mut body, &self.x_windows);
2407        put_wires(&mut body, &self.wires);
2408        put_groups(&mut body, &self.groups);
2409        put_networks(&mut body, &self.networks);
2410        put_symbols(&mut body, &self.symbols);
2411        put_kernels(&mut body, &self.kernels);
2412        put_fork_table(&mut body, &self.fork_table);
2413        put_fork_branches(&mut body, &self.fork_branches);
2414        put_wait_table(&mut body, &self.wait_table);
2415        put_strings(&mut body, &self.strings);
2416        put_collections(&mut body, &self.collections);
2417        put_classes(&mut body, &self.classes);
2418        put_dump_signals(&mut body, &self.dump_signals);
2419        match &self.stmt_cov {
2420            Some(sites) => {
2421                body.u8(1);
2422                put_stmt_sites(&mut body, sites);
2423            }
2424            None => body.u8(0),
2425        }
2426        put_fsms(&mut body, &self.fsms);
2427        put_dpi(&mut body, &self.dpi);
2428        put_verif(&mut body, &self.verif);
2429        put_timing(&mut body, &self.timing);
2430        body.bytes(&self.randomize);
2431        body.bytes(&self.native_nets);
2432        body.bytes(&self.vpi);
2433        let body = body.buf;
2434
2435        let mut out = Writer::default();
2436        out.buf.extend_from_slice(&IMAGE_MAGIC);
2437        out.u32(IMAGE_VERSION);
2438        out.u64(body.len() as u64);
2439        out.u64(fnv1a(&body));
2440        out.buf.extend_from_slice(&body);
2441        out.buf
2442    }
2443
2444    /// Decodes and cross-checks an image (every index must land in its table).
2445    pub fn decode(bytes: &[u8]) -> Result<DesignImage, ImageError> {
2446        let mut r = Reader::new(bytes);
2447        if r.take(8)? != IMAGE_MAGIC {
2448            return Err(ImageError::BadMagic);
2449        }
2450        let version = r.u32()?;
2451        if version != IMAGE_VERSION {
2452            return Err(ImageError::BadVersion {
2453                found: version,
2454                expected: IMAGE_VERSION,
2455            });
2456        }
2457        let body_len = r.u64()?;
2458        let hash = r.u64()?;
2459        if body_len > (bytes.len() - r.pos) as u64 {
2460            return Err(ImageError::Truncated);
2461        }
2462        let body = r.take(body_len as usize)?;
2463        if !r.done() {
2464            return Err(ImageError::TrailingBytes);
2465        }
2466        if fnv1a(body) != hash {
2467            return Err(ImageError::BadHash);
2468        }
2469        let mut r = Reader::new(body);
2470        let image = DesignImage {
2471            abi_version: r.u32()?,
2472            tick_exp: r.i32()?,
2473            x_initial_zero: r.bool()?,
2474            templates: get_templates(&mut r)?,
2475            instances: get_instances(&mut r)?,
2476            foreign: get_foreign(&mut r)?,
2477            x_windows: get_x_windows(&mut r)?,
2478            wires: get_wires(&mut r)?,
2479            groups: get_groups(&mut r)?,
2480            networks: get_networks(&mut r)?,
2481            symbols: get_symbols(&mut r)?,
2482            kernels: get_kernels(&mut r)?,
2483            fork_table: get_fork_table(&mut r)?,
2484            fork_branches: get_fork_branches(&mut r)?,
2485            wait_table: get_wait_table(&mut r)?,
2486            strings: get_strings(&mut r)?,
2487            collections: get_collections(&mut r)?,
2488            classes: get_classes(&mut r)?,
2489            dump_signals: get_dump_signals(&mut r)?,
2490            stmt_cov: match r.u8()? {
2491                0 => None,
2492                1 => Some(get_stmt_sites(&mut r)?),
2493                tag => {
2494                    return Err(ImageError::BadTag {
2495                        what: "statement coverage",
2496                        tag,
2497                    });
2498                }
2499            },
2500            fsms: get_fsms(&mut r)?,
2501            dpi: get_dpi(&mut r)?,
2502            verif: get_verif(&mut r)?,
2503            timing: get_timing(&mut r)?,
2504            randomize: r.bytes()?,
2505            native_nets: r.bytes()?,
2506            vpi: r.bytes()?,
2507        };
2508        if !r.done() {
2509            return Err(ImageError::TrailingBytes);
2510        }
2511        image.validate()?;
2512        Ok(image)
2513    }
2514
2515    /// Every reference in the image lands in its table.
2516    pub fn validate(&self) -> Result<(), ImageError> {
2517        let sym = |i: u32| (i as usize) < self.symbols.len();
2518        let inst = |id: InstanceId| self.instances.iter().any(|i| i.id == id);
2519        for i in &self.instances {
2520            if self.layout_of(&i.template).is_none() {
2521                return Err(ImageError::BadReference("instance template"));
2522            }
2523        }
2524        for k in &self.kernels {
2525            if !sym(k.symbol) {
2526                return Err(ImageError::BadReference("kernel symbol"));
2527            }
2528            if !inst(k.instance) {
2529                return Err(ImageError::BadReference("kernel instance"));
2530            }
2531        }
2532        for (_, symbol) in &self.dpi.exports {
2533            if !sym(*symbol) {
2534                return Err(ImageError::BadReference("DPI export symbol"));
2535            }
2536        }
2537        for a in &self.verif.assertions {
2538            let cases_ok = a.cases.iter().all(|c| sym(c.symbol));
2539            let leaves_ok = a.leaves.iter().flatten().all(|&l| sym(l));
2540            if !inst(a.instance) {
2541                return Err(ImageError::BadReference("assertion instance"));
2542            }
2543            if !sym(a.kernel) || !sym(a.snap) || !a.ticks.iter().all(|&t| sym(t)) {
2544                return Err(ImageError::BadReference("assertion symbol"));
2545            }
2546            if !cases_ok || !leaves_ok {
2547                return Err(ImageError::BadReference("assertion leaf symbol"));
2548            }
2549        }
2550        for g in &self.verif.free_groups {
2551            if !inst(g.instance) {
2552                return Err(ImageError::BadReference("free variable instance"));
2553            }
2554        }
2555        for s in &self.verif.sampled {
2556            if !inst(s.instance) {
2557                return Err(ImageError::BadReference("sampled value instance"));
2558            }
2559            if s.sites.iter().any(|site| !sym(site.guard)) {
2560                return Err(ImageError::BadReference("sampled guard symbol"));
2561            }
2562        }
2563        for c in &self.verif.clocking {
2564            if !inst(c.instance) {
2565                return Err(ImageError::BadReference("clocking block instance"));
2566            }
2567        }
2568        for g in &self.verif.covergroups {
2569            if !inst(g.instance) {
2570                return Err(ImageError::BadReference("covergroup instance"));
2571            }
2572            if !g.kernels.iter().all(|&k| sym(k)) {
2573                return Err(ImageError::BadReference("covergroup kernel symbol"));
2574            }
2575        }
2576        for b in &self.fork_branches {
2577            if !sym(b.symbol) {
2578                return Err(ImageError::BadReference("fork branch symbol"));
2579            }
2580        }
2581        for s in &self.fork_table {
2582            if s.kernel as usize >= self.fork_branches.len() {
2583                return Err(ImageError::BadReference("fork table kernel"));
2584            }
2585        }
2586        for f in &self.foreign {
2587            if !inst(f.instance) || f.targets.iter().any(|(o, _, _)| !inst(*o)) {
2588                return Err(ImageError::BadReference("foreign slot instance"));
2589            }
2590        }
2591        for x in &self.x_windows {
2592            if !inst(x.instance) {
2593                return Err(ImageError::BadReference("x window instance"));
2594            }
2595        }
2596        for x in &self.wires {
2597            if !inst(x.src.instance) || !inst(x.dst.instance) {
2598                return Err(ImageError::BadReference("wire instance"));
2599            }
2600        }
2601        for g in &self.groups {
2602            if g.nets.iter().any(|(i, _)| !inst(*i)) {
2603                return Err(ImageError::BadReference("group net instance"));
2604            }
2605        }
2606        if (!self.groups.is_empty() || !self.networks.is_empty()) && self.bank().is_none() {
2607            return Err(ImageError::BadReference("driver bank"));
2608        }
2609        for n in &self.networks {
2610            if n.groups.iter().any(|&g| g as usize >= self.groups.len()) {
2611                return Err(ImageError::BadReference("network group"));
2612            }
2613            for s in &n.switches {
2614                if s.a.0 as usize >= n.groups.len() || s.b.0 as usize >= n.groups.len() {
2615                    return Err(ImageError::BadReference("switch end"));
2616                }
2617                if let ConductsImage::When(ControlImage::Bit { instance, .. }, _) = s.conducts
2618                    && !inst(instance)
2619                {
2620                    return Err(ImageError::BadReference("switch control instance"));
2621                }
2622            }
2623        }
2624        Ok(())
2625    }
2626}
2627
2628#[cfg(test)]
2629mod tests {
2630    use super::*;
2631
2632    fn slot(key: u32, class: SlotClass, word: u32, width: u32) -> SlotDescriptor {
2633        SlotDescriptor {
2634            key: SymbolKey(key),
2635            offset: SlotOffset {
2636                class,
2637                word_offset: word,
2638                bit_width: width,
2639                elem_word_count: 1,
2640                row_stride_words: 0,
2641                num_rows: 0,
2642            },
2643            initial: None,
2644            net_info: None,
2645        }
2646    }
2647
2648    fn sample_layout() -> StateLayout {
2649        let mut wide = slot(1, SlotClass::Wide, 0, 100);
2650        wide.initial = Some(FourStateValue::Wide {
2651            aval: vec![u64::MAX, 0xf],
2652            bval: vec![0, 3],
2653        });
2654        let mut net = slot(2, SlotClass::Inline, 2, 1);
2655        net.net_info = Some(NetLayout {
2656            kind: NetKind::TriReg,
2657            shape: NetShape::FullStrengthLattice,
2658        });
2659        net.initial = Some(FourStateValue::Narrow((1u128 << 64) | 5));
2660        StateLayout {
2661            slots: vec![slot(0, SlotClass::Inline, 0, 8), wide, net],
2662            inline_words: 3,
2663            wide_words: 2,
2664        }
2665    }
2666
2667    fn key(n: u32) -> TemplateKey {
2668        TemplateKey {
2669            definition: n,
2670            params_hash: u64::from(n) * 7,
2671        }
2672    }
2673
2674    fn sample_image() -> DesignImage {
2675        let mut img = DesignImage::empty(1);
2676        img.tick_exp = -9;
2677        img.x_initial_zero = true;
2678        img.templates = vec![
2679            TemplateImage {
2680                key: key(1),
2681                layout: sample_layout(),
2682            },
2683            TemplateImage {
2684                key: key(u32::MAX),
2685                layout: StateLayout {
2686                    slots: vec![],
2687                    inline_words: 0,
2688                    wide_words: 0,
2689                },
2690            },
2691        ];
2692        img.instances = vec![
2693            InstanceImage {
2694                id: InstanceId(0),
2695                template: key(1),
2696                kind: InstanceKind::Elaborated,
2697                path: "top".into(),
2698            },
2699            InstanceImage {
2700                id: InstanceId(u32::MAX),
2701                template: key(u32::MAX),
2702                kind: InstanceKind::Package,
2703                path: String::new(),
2704            },
2705            InstanceImage {
2706                id: InstanceId(u32::MAX - 1),
2707                template: key(u32::MAX),
2708                kind: InstanceKind::Bank,
2709                path: String::new(),
2710            },
2711        ];
2712        let place = |instance: u32, slot: u32, width: u32, class: PlaceClass| PlaceImage {
2713            instance: InstanceId(instance),
2714            slot,
2715            width,
2716            class,
2717        };
2718        img.wires = vec![
2719            WireImage {
2720                src: place(0, 1, 8, PlaceClass::Inline),
2721                src_range: None,
2722                dst: place(u32::MAX - 1, 0, 8, PlaceClass::Inline),
2723                dst_range: None,
2724                ranged: false,
2725            },
2726            WireImage {
2727                src: place(0, 2, 100, PlaceClass::Wide),
2728                src_range: Some((70, 4)),
2729                dst: place(0, 3, 4, PlaceClass::Inline),
2730                dst_range: Some((0, 4)),
2731                ranged: true,
2732            },
2733            WireImage {
2734                src: place(0, 4, 32, PlaceClass::Memory { rows: 16 }),
2735                src_range: None,
2736                dst: place(0, 5, 32, PlaceClass::Memory { rows: 8 }),
2737                dst_range: None,
2738                ranged: false,
2739            },
2740        ];
2741        let weak = DriveStrengthPair {
2742            s0: DriveStrength::Weak,
2743            s1: DriveStrength::Pull,
2744        };
2745        img.groups = vec![
2746            GroupImage {
2747                kind: NetKind::TriReg,
2748                width: 4,
2749                nets: vec![(InstanceId(0), 2), (InstanceId(u32::MAX), 1)],
2750                drivers: vec![
2751                    DriverImage {
2752                        slot: 0,
2753                        strength: weak,
2754                        ambiguous: Some(1),
2755                        src: Some(StrengthSrc {
2756                            key: 0xbeef,
2757                            bit: 1,
2758                            out_bit: 2,
2759                            resistive: true,
2760                            tick: 9,
2761                        }),
2762                    },
2763                    DriverImage {
2764                        slot: 2,
2765                        strength: DriveStrengthPair {
2766                            s0: DriveStrength::Supply,
2767                            s1: DriveStrength::Strong,
2768                        },
2769                        ambiguous: None,
2770                        src: None,
2771                    },
2772                ],
2773                switched: false,
2774                decay: Some(50),
2775                strength_keys: vec![0xfeed, 7],
2776                strength_tick: Some(5),
2777                sides: vec![SideSpec {
2778                    key: 9,
2779                    inside: vec![true, false],
2780                }],
2781                charge: 6,
2782            },
2783            GroupImage {
2784                kind: NetKind::Wire,
2785                width: 1,
2786                nets: vec![(InstanceId(0), 3)],
2787                drivers: vec![],
2788                switched: true,
2789                decay: None,
2790                strength_keys: vec![],
2791                strength_tick: None,
2792                sides: vec![],
2793                charge: 4,
2794            },
2795        ];
2796        img.networks = vec![NetworkImage {
2797            groups: vec![1],
2798            switches: vec![
2799                SwitchImage {
2800                    a: (0, 0),
2801                    b: (0, 0),
2802                    conducts: ConductsImage::Always,
2803                    resistive: false,
2804                },
2805                SwitchImage {
2806                    a: (0, 0),
2807                    b: (0, 0),
2808                    conducts: ConductsImage::When(
2809                        ControlImage::Bit {
2810                            instance: InstanceId(0),
2811                            slot: 1,
2812                            width: 70,
2813                            bit: 69,
2814                        },
2815                        false,
2816                    ),
2817                    resistive: true,
2818                },
2819                SwitchImage {
2820                    a: (0, 0),
2821                    b: (0, 0),
2822                    conducts: ConductsImage::When(ControlImage::Const(2), true),
2823                    resistive: false,
2824                },
2825            ],
2826        }];
2827        img.foreign = vec![ForeignImage {
2828            instance: InstanceId(0),
2829            own_slots: 3,
2830            targets: vec![(InstanceId(u32::MAX), 4, None)],
2831        }];
2832        img.x_windows = vec![XWindow {
2833            instance: InstanceId(0),
2834            slot: 2,
2835            value: FourStateValue::Narrow(0x1234),
2836        }];
2837        let a = img.intern("vj_proc_0");
2838        let b = img.intern("vj_proc_1");
2839        assert_eq!(img.intern("vj_proc_0"), a);
2840        let c = img.intern("vj_fork_0");
2841        img.kernels = vec![
2842            KernelImage {
2843                symbol: a,
2844                frame_words: 4,
2845                kind: ProcessKind::Always,
2846                instance: InstanceId(0),
2847                role: KernelRole::Process,
2848                level_head: true,
2849                reactive: false,
2850                program_initial: false,
2851                registered: true,
2852                read_set: vec![0, 2],
2853                read_windows: vec![(2, 1, 3)],
2854                reset: None,
2855                disable_scopes: vec![(3, "lp".to_owned(), 7)],
2856            },
2857            KernelImage {
2858                symbol: b,
2859                frame_words: 0,
2860                kind: ProcessKind::AlwaysFF,
2861                instance: InstanceId(0),
2862                role: KernelRole::ContAssign,
2863                level_head: false,
2864                reactive: true,
2865                program_initial: true,
2866                registered: false,
2867                read_set: vec![],
2868                read_windows: vec![],
2869                reset: Some((1, EdgeKind::Negedge)),
2870                disable_scopes: vec![],
2871            },
2872        ];
2873        img.fork_table = vec![SpawnSpec {
2874            kernel: 0,
2875            entry_pc: 3,
2876            parent: 9,
2877            disable_name: vec!["outer".to_owned(), "inner".to_owned()],
2878        }];
2879        img.fork_branches = vec![ForkBranchImage {
2880            symbol: c,
2881            frame_words: 2,
2882            captures: vec![(1, 2), (3, 4)],
2883            disable_scopes: vec![(5, "blk".to_owned(), 6)],
2884        }];
2885        img.wait_table = vec![
2886            WaitTableEntry {
2887                slot: 1,
2888                edge: None,
2889                select: None,
2890            },
2891            WaitTableEntry {
2892                slot: 2,
2893                edge: Some(EdgeKind::Posedge),
2894                select: Some((3, 1)),
2895            },
2896        ];
2897        img.strings = vec![b"hello".to_vec(), b"a b".to_vec()];
2898        img.collections = vec![
2899            FrozenData::Seq {
2900                stride: 2,
2901                words: vec![1, 2, 3, 4],
2902            },
2903            FrozenData::Map {
2904                entries: vec![
2905                    (Key::Int(-5), vec![7]),
2906                    (Key::Big(vec![1, 2]), vec![8]),
2907                    (Key::Str(b"k".to_vec()), vec![9]),
2908                ],
2909                default: Some(vec![6]),
2910            },
2911            FrozenData::Map {
2912                entries: vec![],
2913                default: None,
2914            },
2915        ];
2916        let slot = |offset, words| FieldSlot { offset, words };
2917        img.classes = vec![TemplateSnapshot {
2918            id: ClassTemplateId(3),
2919            handle_fields: vec![slot(1, 1)],
2920            collection_fields: vec![slot(4, 1)],
2921            nested_handles: vec![NestedHandle {
2922                slot: slot(6, 3),
2923                bit: 65,
2924                coll: true,
2925            }],
2926            ancestors: vec![ClassTemplateId(1), ClassTemplateId(3)],
2927            rand_props: vec![
2928                RandProp {
2929                    slot: slot(0, 1),
2930                    kind: RandKind::Rand,
2931                },
2932                RandProp {
2933                    slot: slot(2, 2),
2934                    kind: RandKind::RandC,
2935                },
2936            ],
2937        }];
2938        let export_symbol = img.intern("__vj_export$sv_fn");
2939        img.dpi = DpiImage {
2940            imports: vec!["c_add".to_owned(), "c_puts".to_owned()],
2941            exports: vec![("sv_fn".to_owned(), export_symbol)],
2942            variants: vec![("sv_fn".to_owned(), "top.u1".to_owned(), 2)],
2943            task_fibers: true,
2944        };
2945        img.verif = sample_verif(&mut img);
2946        img.timing = sample_timing();
2947        img.randomize = vec![1, 2, 3, 250];
2948        img.native_nets = vec![7, 8];
2949        img.vpi = vec![9, 10, 11];
2950        img.dump_signals = vec![DumpSignalImage {
2951            instance: InstanceId(0),
2952            def_name: "top_def".to_owned(),
2953            scope: vec!["top".to_owned(), "blk".to_owned()],
2954            scope_kinds: vec![ScopeKind::Module, ScopeKind::Fork],
2955            name: "r".to_owned(),
2956            width: 70,
2957            var_type: VcdVarType::Tri1,
2958            slot: 5,
2959            wide: true,
2960            real: false,
2961            class_handle: false,
2962            port: Some(PortDir::Inout),
2963            strength_key: Some(0xdead_beef),
2964            side_key: Some(0xfade),
2965        }];
2966        img
2967    }
2968
2969    /// Round-trips one section through its put/get pair.
2970    /// One assertion with a real automaton and property, a checker free-variable
2971    /// group and a sampled-value instance: every `VerifImage` field populated.
2972    fn sample_verif(img: &mut DesignImage) -> VerifImage {
2973        use crate::sva::ir::{Automaton, ClockId, Edge, State, ThreadStateId, Transition};
2974        use crate::sva::property::{Prop, PropDecl, PropId, PropertyIr, SeqRef, Strength};
2975        let mut automaton = Automaton::empty();
2976        automaton.states = vec![
2977            State {
2978                edges: vec![Edge {
2979                    guard: Some(LeafId(0)),
2980                    label: Transition::Delay {
2981                        min: 1,
2982                        max: Some(3),
2983                    },
2984                    target: ThreadStateId(1),
2985                }],
2986            },
2987            State {
2988                edges: vec![Edge {
2989                    guard: None,
2990                    label: Transition::Match {
2991                        actions: Vec::new(),
2992                    },
2993                    target: ThreadStateId(1),
2994                }],
2995            },
2996        ];
2997        let ir = PropertyIr {
2998            automaton,
2999            props: vec![
3000                Prop::Seq {
3001                    seq: SeqRef {
3002                        entry: ThreadStateId(0),
3003                        admits_empty: false,
3004                        clock: ClockId(0),
3005                        end_clock: ClockId(0),
3006                    },
3007                    strength: Some(Strength::Strong),
3008                },
3009                Prop::Not(PropId(0)),
3010            ],
3011            decls: vec![PropDecl {
3012                name: "p".to_owned(),
3013                body: PropId(1),
3014            }],
3015            root: PropId(1),
3016            disable: Some(LeafId(1)),
3017            nv_rules: Vec::new(),
3018        };
3019        let kernel = img.intern("a0_action");
3020        let snap = img.intern("a0_snap");
3021        let tick = img.intern("a0_t0");
3022        let leaf = img.intern("a0_l0");
3023        let case = img.intern("a0_c0");
3024        let guard = img.intern("vj_sva_guard_0");
3025        VerifImage {
3026            assertions: vec![AssertionImage {
3027                plan_index: 3,
3028                instance: InstanceId(0),
3029                kernel,
3030                frame_words: 4,
3031                label: "top.chk".to_owned(),
3032                kind: AssertKind::CoverSequence,
3033                ir,
3034                n_clocks: 1,
3035                hist_clocks: 0,
3036                leaf_reads: vec![vec![LocalVarId(0)], Vec::new()],
3037                leaf_writes: vec![None, Some(LocalVarId(1))],
3038                activated: true,
3039                captured: vec![LocalVarId(1)],
3040                disable_mixed: true,
3041                tick_history: true,
3042                history_depth: 2,
3043                future: true,
3044                future_clock: 0,
3045                src_offset: Some(42),
3046                leaf_src: vec![(0, 10, 20), (0, 30, 40)],
3047                row_len: 5,
3048                snap,
3049                ticks: vec![tick],
3050                leaves: vec![Some(leaf), None],
3051                live_leaves: vec![None, None],
3052                cases: vec![CasePairImage {
3053                    selector: LeafId(0),
3054                    label: LeafId(1),
3055                    symbol: case,
3056                }],
3057                site: Some(SiteDesc {
3058                    assertion_type: 1,
3059                    directive_type: 2,
3060                    scope: "top".to_owned(),
3061                    label: "top.chk".to_owned(),
3062                }),
3063                end_cell: Some(7),
3064                current_words: vec![("top.chk.v#0".to_owned(), 2, 1)],
3065                observed_words: vec![(1, 1)],
3066                coll_words: vec![3],
3067                coll_nests: vec![crate::collections::Nest {
3068                    slots: vec![(64, crate::collections::Nest::default())],
3069                }],
3070                spawn_calls: vec![SpawnCallImage {
3071                    call: 1,
3072                    kernel: 6,
3073                    frame_words: 5,
3074                    entry_pc: 2,
3075                }],
3076            }],
3077            free_groups: vec![FreeGroupImage {
3078                instance: InstanceId(0),
3079                vars: vec![FreeVarImage {
3080                    id: "top.chk.v#0".to_owned(),
3081                    slot: 9,
3082                    width: 70,
3083                    wide: true,
3084                }],
3085                rng: 0xdead_beef_u64,
3086            }],
3087            sampled: vec![SampledImage {
3088                instance: InstanceId(0),
3089                sites: vec![SampledSiteImage {
3090                    guard,
3091                    shifts: vec![(1, 2), (2, 3)],
3092                }],
3093                p_copies: vec![(4, 5)],
3094            }],
3095            clocking: vec![ClockingImage {
3096                instance: InstanceId(0),
3097                terms: vec![(1, Some(EdgeKind::Posedge)), (2, None)],
3098                gates: vec![(0, 6)],
3099                samples: vec![(3, 4, 8)],
3100                skews: vec![0],
3101                parts: vec![vec![(1, 8, 2, 4)]],
3102                counter: 5,
3103                term_owners: vec![InstanceId(0), InstanceId(1)],
3104            }],
3105            covergroups: vec![
3106                CovGroupImage {
3107                    type_index: 0,
3108                    site: 0,
3109                    instance: InstanceId(0),
3110                    decl: crate::covergroup::decl::CovGroupDecl::new("cg").coverpoint(
3111                        crate::covergroup::decl::CoverpointDecl {
3112                            name: "a".to_owned(),
3113                            ty: crate::covergroup::value::TypeInfo::unsigned(4),
3114                            expr: crate::covergroup::value::Expr::Kernel(0),
3115                            iff: None,
3116                            bins: vec![crate::covergroup::decl::BinDecl::ranges(
3117                                "b",
3118                                vec![crate::covergroup::decl::RangeItem::Single(
3119                                    crate::covergroup::value::Expr::int(1),
3120                                )],
3121                            )],
3122                            enum_values: None,
3123                            options: Vec::new(),
3124                            type_options: Vec::new(),
3125                        },
3126                    ),
3127                    kernels: vec![0],
3128                    sampler: Some(CovSamplerImage {
3129                        terms: vec![(1, Some(EdgeKind::Negedge)), (2, None)],
3130                        gates: vec![(1, 4)],
3131                        exprs: vec![CovExprTermImage {
3132                            func: 9,
3133                            edge: Some(EdgeKind::Posedge),
3134                            wake: vec![1, 0],
3135                            gates: vec![3],
3136                        }],
3137                        strobe: true,
3138                    }),
3139                    class_clock: Some(CovClassClockImage {
3140                        terms: vec![(0, Some(EdgeKind::Posedge)), (0, None)],
3141                        gates: vec![(1, 0)],
3142                        strobe: true,
3143                    }),
3144                    blocks: vec![7, 0x8000_0000_0000_0001],
3145                },
3146                CovGroupImage {
3147                    type_index: 1,
3148                    site: 0xdead_beef,
3149                    instance: InstanceId(0),
3150                    decl: crate::covergroup::decl::CovGroupDecl::new("pkg"),
3151                    kernels: Vec::new(),
3152                    sampler: None,
3153                    class_clock: None,
3154                    blocks: Vec::new(),
3155                },
3156            ],
3157        }
3158    }
3159
3160    #[test]
3161    fn verif_section_round_trips_and_is_cross_checked() {
3162        let img = sample_image();
3163        assert!(!img.verif.is_empty());
3164        round_trip(img.verif.clone(), put_verif, get_verif);
3165        // A dangling assertion symbol is refused by name.
3166        let mut bad = img.clone();
3167        bad.verif.assertions[0].snap = bad.symbols.len() as u32;
3168        assert_eq!(
3169            DesignImage::decode(&bad.encode()),
3170            Err(ImageError::BadReference("assertion symbol"))
3171        );
3172        let mut bad = img.clone();
3173        bad.verif.sampled[0].sites[0].guard = u32::MAX;
3174        assert_eq!(
3175            DesignImage::decode(&bad.encode()),
3176            Err(ImageError::BadReference("sampled guard symbol"))
3177        );
3178        let mut bad = img.clone();
3179        bad.verif.clocking[0].instance = InstanceId(77);
3180        assert_eq!(
3181            DesignImage::decode(&bad.encode()),
3182            Err(ImageError::BadReference("clocking block instance"))
3183        );
3184        let mut bad = img.clone();
3185        bad.verif.covergroups[0].instance = InstanceId(77);
3186        assert_eq!(
3187            DesignImage::decode(&bad.encode()),
3188            Err(ImageError::BadReference("covergroup instance"))
3189        );
3190        let mut bad = img.clone();
3191        bad.verif.covergroups[0].kernels[0] = u32::MAX;
3192        assert_eq!(
3193            DesignImage::decode(&bad.encode()),
3194            Err(ImageError::BadReference("covergroup kernel symbol"))
3195        );
3196        // An unknown assertion-kind tag is refused by name.
3197        let mut w = Writer::default();
3198        put_assert_kind(&mut w, AssertKind::Expect);
3199        let mut tag = w.buf.clone();
3200        tag[0] = 99;
3201        assert_eq!(
3202            get_assert_kind(&mut Reader::new(&tag)),
3203            Err(ImageError::BadTag {
3204                what: "assertion kind",
3205                tag: 99
3206            })
3207        );
3208    }
3209
3210    fn round_trip<T: PartialEq + std::fmt::Debug>(
3211        value: T,
3212        put: impl Fn(&mut Writer, &T),
3213        get: impl Fn(&mut Reader<'_>) -> Result<T, ImageError>,
3214    ) {
3215        let mut w = Writer::default();
3216        put(&mut w, &value);
3217        let mut r = Reader::new(&w.buf);
3218        let back = get(&mut r).expect("decodes");
3219        assert!(r.done(), "the section is consumed exactly");
3220        assert_eq!(back, value);
3221    }
3222
3223    #[test]
3224    fn four_state_values_round_trip() {
3225        for v in [
3226            FourStateValue::Narrow(0),
3227            FourStateValue::Narrow(u128::MAX),
3228            FourStateValue::Wide {
3229                aval: vec![1, 2, 3],
3230                bval: vec![4, 5, 6],
3231            },
3232            FourStateValue::Wide {
3233                aval: vec![],
3234                bval: vec![],
3235            },
3236        ] {
3237            round_trip(v, put_four_state, get_four_state);
3238        }
3239    }
3240
3241    #[test]
3242    fn layouts_round_trip() {
3243        round_trip(sample_layout(), put_layout, get_layout);
3244    }
3245
3246    #[test]
3247    fn every_section_round_trips() {
3248        let img = sample_image();
3249        round_trip(
3250            img.templates.clone(),
3251            |w, v| put_templates(w, v),
3252            get_templates,
3253        );
3254        round_trip(
3255            img.instances.clone(),
3256            |w, v| put_instances(w, v),
3257            get_instances,
3258        );
3259        round_trip(img.foreign.clone(), |w, v| put_foreign(w, v), get_foreign);
3260        round_trip(
3261            img.x_windows.clone(),
3262            |w, v| put_x_windows(w, v),
3263            get_x_windows,
3264        );
3265        round_trip(img.wires.clone(), |w, v| put_wires(w, v), get_wires);
3266        round_trip(img.groups.clone(), |w, v| put_groups(w, v), get_groups);
3267        round_trip(
3268            img.networks.clone(),
3269            |w, v| put_networks(w, v),
3270            get_networks,
3271        );
3272        round_trip(img.symbols.clone(), |w, v| put_symbols(w, v), get_symbols);
3273        round_trip(img.kernels.clone(), |w, v| put_kernels(w, v), get_kernels);
3274        round_trip(
3275            img.fork_table.clone(),
3276            |w, v| put_fork_table(w, v),
3277            get_fork_table,
3278        );
3279        round_trip(
3280            img.fork_branches.clone(),
3281            |w, v| put_fork_branches(w, v),
3282            get_fork_branches,
3283        );
3284        round_trip(
3285            img.wait_table.clone(),
3286            |w, v| put_wait_table(w, v),
3287            get_wait_table,
3288        );
3289        round_trip(img.strings.clone(), |w, v| put_strings(w, v), get_strings);
3290        round_trip(
3291            img.collections.clone(),
3292            |w, v| put_collections(w, v),
3293            get_collections,
3294        );
3295        round_trip(img.classes.clone(), |w, v| put_classes(w, v), get_classes);
3296        round_trip(
3297            img.dump_signals.clone(),
3298            |w, v| put_dump_signals(w, v),
3299            get_dump_signals,
3300        );
3301        round_trip(img.dpi.clone(), put_dpi, get_dpi);
3302        round_trip(
3303            vec![StmtSiteImage {
3304                def: "top".to_string(),
3305                buffer: 2,
3306                start: 10,
3307                end: 20,
3308                kind: 7,
3309                nest: 1,
3310            }],
3311            |w, v| put_stmt_sites(w, v),
3312            get_stmt_sites,
3313        );
3314        round_trip(
3315            vec![FsmImage {
3316                instance: InstanceId(1),
3317                name: "cs".to_string(),
3318                parts: vec![FsmPartImage {
3319                    slot: 3,
3320                    msb: 3,
3321                    lsb: 0,
3322                }],
3323                states: vec![("S0".to_string(), 0), ("S1".to_string(), 1)],
3324            }],
3325            |w, v| put_fsms(w, v),
3326            get_fsms,
3327        );
3328    }
3329
3330    fn sample_timing() -> TimingImage {
3331        TimingImage {
3332            options: TimingOptionsImage {
3333                per_bit_vectors: true,
3334                negative_timing_checks: true,
3335                reject_limit_pct: Some(12.5f64.to_bits()),
3336                error_limit_pct: None,
3337                pulse_style: Some(1),
3338                showcancelled: Some(false),
3339                sdf_mtm: Some(2),
3340            },
3341            plan: vec![0, 1, 2, 255],
3342        }
3343    }
3344
3345    #[test]
3346    fn timing_section_round_trips() {
3347        round_trip(sample_timing(), put_timing, get_timing);
3348        round_trip(TimingImage::default(), put_timing, get_timing);
3349        let mut img = DesignImage::empty(1);
3350        img.timing = sample_timing();
3351        assert_eq!(DesignImage::decode(&img.encode()).unwrap(), img);
3352        // A bad optional tag is refused by name, not read as a value.
3353        let mut w = Writer::default();
3354        put_timing(&mut w, &sample_timing());
3355        w.buf[2] = 7;
3356        let mut r = Reader::new(&w.buf);
3357        assert!(get_timing(&mut r).is_err());
3358    }
3359
3360    #[test]
3361    fn whole_image_round_trips_and_encodes_deterministically() {
3362        let img = sample_image();
3363        let bytes = img.encode();
3364        assert_eq!(bytes, sample_image().encode(), "equal images, equal bytes");
3365        assert_eq!(&bytes[..8], &IMAGE_MAGIC);
3366        assert_eq!(DesignImage::decode(&bytes).unwrap(), img);
3367        let empty = DesignImage::empty(1);
3368        assert_eq!(DesignImage::decode(&empty.encode()).unwrap(), empty);
3369    }
3370
3371    #[test]
3372    fn corruption_is_refused_by_name() {
3373        let bytes = sample_image().encode();
3374        // Every proper prefix is a decode error, never a panic.
3375        for n in 0..bytes.len() {
3376            assert!(
3377                DesignImage::decode(&bytes[..n]).is_err(),
3378                "prefix of {n} bytes decoded"
3379            );
3380        }
3381        let mut bad = bytes.clone();
3382        bad[0] ^= 1;
3383        assert_eq!(DesignImage::decode(&bad), Err(ImageError::BadMagic));
3384        let mut bad = bytes.clone();
3385        bad[8] = 99;
3386        assert!(matches!(
3387            DesignImage::decode(&bad),
3388            Err(ImageError::BadVersion { found: 99, .. })
3389        ));
3390        let mut bad = bytes.clone();
3391        let last = bad.len() - 1;
3392        bad[last] ^= 0x40;
3393        assert_eq!(DesignImage::decode(&bad), Err(ImageError::BadHash));
3394        let mut bad = bytes.clone();
3395        bad.push(0);
3396        assert_eq!(DesignImage::decode(&bad), Err(ImageError::TrailingBytes));
3397    }
3398
3399    #[test]
3400    fn dangling_references_are_refused() {
3401        let mut img = sample_image();
3402        img.kernels[0].symbol = 99;
3403        assert_eq!(
3404            DesignImage::decode(&img.encode()),
3405            Err(ImageError::BadReference("kernel symbol"))
3406        );
3407        let mut img = sample_image();
3408        img.networks[0].groups[0] = 9;
3409        assert_eq!(
3410            DesignImage::decode(&img.encode()),
3411            Err(ImageError::BadReference("network group"))
3412        );
3413        let mut img = sample_image();
3414        img.instances.pop();
3415        assert_eq!(
3416            DesignImage::decode(&img.encode()),
3417            Err(ImageError::BadReference("wire instance"))
3418        );
3419        let mut img = sample_image();
3420        img.instances[0].template = key(1234);
3421        assert_eq!(
3422            DesignImage::decode(&img.encode()),
3423            Err(ImageError::BadReference("instance template"))
3424        );
3425    }
3426}