1use 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#[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 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
72fn 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 #[allow(clippy::len_without_is_empty)] 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 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
201fn 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
378pub 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
501fn 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 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
1636fn 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}
1663fn 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
1711fn 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
2394impl DesignImage {
2397 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 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 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("sv_sim_proc_0");
2838 let b = img.intern("sv_sim_proc_1");
2839 assert_eq!(img.intern("sv_sim_proc_0"), a);
2840 let c = img.intern("sv_sim_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("__svsim_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 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("sv_sim_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 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 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 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 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}