vj_sim/image/mod.rs
1//! The design image: everything a slang-free runner needs, as plain data.
2//!
3//! `vj build-aot` plans a design with slang, lowers it to machine code, and
4//! embeds one [`DesignImage`] in the produced `.so`; the runner
5//! (`vj-exec`) decodes it and assembles the same `StateEngine` + scheduler
6//! `vj run` assembles, without ever touching slang. `vj run` itself
7//! builds the same value from its own locals and instantiates it through the
8//! same code, so there is exactly one boot sequence (a second one is how "card
9//! vs sim" drift happens).
10//!
11//! The image holds no pointer and no hash-map iteration order: it is a
12//! `Vec`-ordered value with a hand-written, versioned, little-endian codec
13//! ([`codec`]), so equal designs encode to identical bytes.
14
15pub mod codec;
16pub mod covdecl;
17pub mod verif;
18
19use crate::collections::FrozenData;
20use crate::netlist::{InstanceId, TemplateKey};
21use crate::objects::TemplateSnapshot;
22use crate::sched::{ProcessKind, SpawnSpec, WaitTableEntry};
23use crate::state::{DriveStrengthPair, EdgeKind, FourStateValue, NetKind, StateLayout};
24
25/// First eight bytes of an encoded image.
26pub const IMAGE_MAGIC: [u8; 8] = *b"VJ-IMAGE";
27
28/// Bumped on any change to the encoded layout.
29pub const IMAGE_VERSION: u32 = 61;
30
31/// Which kind of state instance an [`InstanceImage`] is.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum InstanceKind {
34 /// An elaborated module instance (`registration_order`).
35 Elaborated,
36 /// A package's variables (a pseudo-instance with its own template).
37 Package,
38 /// The synthetic driver-contribution bank.
39 Bank,
40}
41
42/// One unique `(module, parameters)` template and its state layout.
43#[derive(Clone, Debug, PartialEq)]
44pub struct TemplateImage {
45 pub key: TemplateKey,
46 pub layout: StateLayout,
47}
48
49/// One state instance, in allocation order (the order decides each instance's
50/// arena range and `SimHandle`, so it is part of the design).
51#[derive(Clone, Debug, PartialEq)]
52pub struct InstanceImage {
53 pub id: InstanceId,
54 pub template: TemplateKey,
55 pub kind: InstanceKind,
56 /// Hierarchical path (`top.u0`), empty for package and bank instances.
57 pub path: String,
58}
59
60/// An instance's foreign slots: slots `own..own + targets.len()` alias the
61/// listed `(owner instance, owner slot)` cells.
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct ForeignImage {
64 pub instance: InstanceId,
65 /// The instance's own slot count (what the first foreign slot follows).
66 pub own_slots: u32,
67 /// `Some`: the target names a window of the owner's slot (a `ref` port
68 /// bound to a select, LRM 23.3.3.2) -- its own shape (width, class) is
69 /// already the window's, laid out by `process_lower::SignalSlot`.
70 pub targets: Vec<(InstanceId, u32, Option<crate::state::AliasWindow>)>,
71}
72
73/// A slot whose initial value is overwritten after the reset blit (a net starts
74/// at Z, but the bits a driver drives start at X).
75#[derive(Clone, Debug, PartialEq)]
76pub struct XWindow {
77 pub instance: InstanceId,
78 pub slot: u32,
79 pub value: FourStateValue,
80}
81
82/// A slot's storage class, as a wire or a resolver sees it.
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum PlaceClass {
85 /// At most 64 bits: the accessor ABI's `(val, unk)` scalar.
86 Inline,
87 /// More than 64 bits: `(aval, bval)` word arrays.
88 Wide,
89 /// An unpacked array: `rows` rows of one element each.
90 Memory { rows: u32 },
91}
92
93/// One signal of one instance (the bank included), as a native process
94/// addresses it.
95#[derive(Clone, Copy, Debug, PartialEq, Eq)]
96pub struct PlaceImage {
97 pub instance: InstanceId,
98 /// The slot in the instance's own numbering (a foreign slot included).
99 pub slot: u32,
100 pub width: u32,
101 pub class: PlaceClass,
102}
103
104/// One instance port connection, realized as LRM 23.3.3's synthetic
105/// continuous assignment: a native process copying `src` to `dst`, with static
106/// sensitivity on `src`'s cell. The list order is the registration order (after
107/// the continuous assignments).
108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109pub struct WireImage {
110 pub src: PlaceImage,
111 /// `Some((lo, width))`: only that sub-range of `src` is copied.
112 pub src_range: Option<(u32, u32)>,
113 pub dst: PlaceImage,
114 /// `Some((lo, width))`: the value lands in only that sub-range of `dst`.
115 pub dst_range: Option<(u32, u32)>,
116 /// A bit-select/part-select connection (a read-modify-write of the
117 /// destination), as opposed to a whole-signal or whole-memory copy.
118 pub ranged: bool,
119}
120
121/// One driver of a resolved net: its contribution cell in the bank, its
122/// strength, and its strength-ambiguity mask cell (the bits that are `L`/`H`).
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub struct DriverImage {
125 pub slot: u32,
126 pub strength: DriveStrengthPair,
127 pub ambiguous: Option<u32>,
128 /// A unidirectional MOS gate's driver passes its data input's strength
129 /// (LRM 28.4, Table 28-8), read at resolve time.
130 pub src: Option<StrengthSrc>,
131}
132
133/// Where a MOS gate's driver takes its strength from: the data input net
134/// (`%v` registry `key`, bit `bit`), lowered a level when `resistive`. The
135/// driver drives bit `out_bit` of its net. `tick` is the input group's
136/// strength-change cell, which wakes the output's resolver on a change in
137/// strength only.
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
139pub struct StrengthSrc {
140 pub key: u64,
141 pub bit: u32,
142 pub out_bit: u32,
143 pub resistive: bool,
144 pub tick: u32,
145}
146
147/// A group of nets resolved together (`nets`: one, or several joined by
148/// `inout` ports).
149#[derive(Clone, Debug, PartialEq, Eq)]
150pub struct GroupImage {
151 pub kind: NetKind,
152 pub width: u32,
153 /// `(instance, slot)` of each net.
154 pub nets: Vec<(InstanceId, u32)>,
155 pub drivers: Vec<DriverImage>,
156 /// Part of a switch network, which resolves it.
157 pub switched: bool,
158 /// A `trireg` group's charge decay time in scheduler ticks.
159 pub decay: Option<u64>,
160 /// A `trireg` group's charge strength as a `%v` code (LRM 28.16.1): 5
161 /// small, 4 medium (the default), 6 large.
162 pub charge: u8,
163 /// `%v` registry keys (`vj_runtime::fmt::strength_key`) of the group's
164 /// nets, same order: the resolver records the group's per-bit strengths
165 /// under each. Empty unless the design prints `%v`.
166 pub strength_keys: Vec<u64>,
167 /// A bank cell the resolver bumps whenever the group's strengths change
168 /// (a MOS gate downstream reads them: [`StrengthSrc::tick`]).
169 pub strength_tick: Option<u32>,
170 /// The `$dumpports` port views of the group (LRM 21.7.4.3.2): empty
171 /// unless the design calls `$dumpports`.
172 pub sides: Vec<SideSpec>,
173}
174
175/// One dumped port's split of a group's drivers, for the resolver to resolve
176/// separately (LRM 21.7.4.3.2: the test fixture's drivers and the DUT's own).
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub struct SideSpec {
179 /// The registry key the per-side result is recorded under
180 /// ([`DumpSignalImage::side_key`]).
181 pub key: u64,
182 /// Parallel to the group's `drivers`: the driver belongs to the dumped
183 /// instance (the DUT side), not to the fixture around it.
184 pub inside: Vec<bool>,
185}
186
187/// A bidirectional switch's control terminal.
188#[derive(Clone, Copy, Debug, PartialEq, Eq)]
189pub enum ControlImage {
190 /// Bit `bit` of a `width`-bit signal.
191 Bit {
192 instance: InstanceId,
193 slot: u32,
194 width: u32,
195 bit: u32,
196 },
197 /// 0, 1, or 2 for unknown.
198 Const(u8),
199}
200
201/// When a bidirectional switch conducts.
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum ConductsImage {
204 Always,
205 /// `tranif1` (`true`) / `tranif0` (`false`): when the control is 1 / 0.
206 When(ControlImage, bool),
207}
208
209/// One bit-to-bit bidirectional switch: `(group, bit)` ends, where `group`
210/// indexes [`NetworkImage::groups`].
211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
212pub struct SwitchImage {
213 pub a: (u32, u32),
214 pub b: (u32, u32),
215 pub conducts: ConductsImage,
216 pub resistive: bool,
217}
218
219/// Groups connected by bidirectional switches, resolved together.
220#[derive(Clone, Debug, PartialEq, Eq)]
221pub struct NetworkImage {
222 /// Indices into [`DesignImage::groups`].
223 pub groups: Vec<u32>,
224 pub switches: Vec<SwitchImage>,
225}
226
227/// What a kernel is in the registration order.
228#[derive(Clone, Copy, Debug, PartialEq, Eq)]
229pub enum KernelRole {
230 /// A procedural block (`initial`/`always*`/`final`).
231 Process,
232 /// A module-level continuous assignment: an `AlwaysComb` process with zero
233 /// frame words.
234 ContAssign,
235 /// A variable's non-constant initializer: a continuous assignment that
236 /// seeds from its instance's initialization RNG.
237 VarInit,
238}
239
240/// One compiled kernel the scheduler registers as a process.
241#[derive(Clone, Debug, PartialEq)]
242pub struct KernelImage {
243 /// Index into [`DesignImage::symbols`]: the kernel function's name.
244 pub symbol: u32,
245 pub frame_words: u32,
246 pub kind: ProcessKind,
247 pub instance: InstanceId,
248 pub role: KernelRole,
249 /// `always @*`-style head: registered first, so it is already waiting when
250 /// the time-zero updates change its inputs.
251 pub level_head: bool,
252 /// Runs in the Reactive region (a checker's procedures).
253 pub reactive: bool,
254 /// A program block's `initial` thread (LRM 24.3): the simulation ends
255 /// implicitly once every such thread and its descendants have ended.
256 pub program_initial: bool,
257 /// `false` for a kernel the scheduler never registers (it only hosts an
258 /// assertion's action blocks).
259 pub registered: bool,
260 /// `AlwaysComb`/`AlwaysLatch`: the template slots the whole procedure
261 /// reads, each an "any change" edge.
262 pub read_set: Vec<u32>,
263 /// `AlwaysComb`/`AlwaysLatch`: `(slot, lsb, width)` windows narrowing a
264 /// `read_set` slot the body reads only through constant selects (LRM
265 /// 9.2.2.2.1); a slot without a window is sensitive to its whole value.
266 pub read_windows: Vec<(u32, u32, u32)>,
267 /// `AlwaysFF` with an asynchronous reset: its template slot and edge.
268 pub reset: Option<(u32, EdgeKind)>,
269 /// `ProcessCfg::disable_scopes` as `(resume pc, label, exit pc)`: what a
270 /// `disable` of another process resumes this one at (LRM 9.6.2).
271 pub disable_scopes: Vec<(u32, String, u32)>,
272}
273
274/// A fork branch's kernel (`SpawnSpec::kernel` indexes these).
275#[derive(Clone, Debug, PartialEq, Eq)]
276pub struct ForkBranchImage {
277 pub symbol: u32,
278 pub frame_words: u32,
279 /// `(parent frame word, child frame word)` of each shared variable.
280 pub captures: Vec<(u32, u32)>,
281 /// The branch's `ProcessCfg::disable_scopes` as `(resume pc, label, exit
282 /// pc)`, like [`KernelImage::disable_scopes`].
283 pub disable_scopes: Vec<(u32, String, u32)>,
284}
285
286/// A VCD scope type (LRM 1800-2023 21.7.2.1): what kind of scope a dumped
287/// signal sits in.
288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
289pub enum ScopeKind {
290 /// An elaborated module instance.
291 Module,
292 /// A generate block or a named sequential block.
293 Begin,
294 /// A named fork.
295 Fork,
296 Task,
297 Function,
298}
299
300impl ScopeKind {
301 /// The keyword a VCD `$scope` line uses.
302 pub fn as_str(self) -> &'static str {
303 match self {
304 ScopeKind::Module => "module",
305 ScopeKind::Begin => "begin",
306 ScopeKind::Fork => "fork",
307 ScopeKind::Task => "task",
308 ScopeKind::Function => "function",
309 }
310 }
311}
312
313/// A VCD `$var` type (LRM 1800-2023 21.7.2.1 `var_type`; `parameter` is
314/// not a dumped signal). A `uwire` is `wire` (21.7.2.3); `logic`/`bit`/`byte`
315/// and the other 2/4-state vectors are `reg`; `Event` has no value, only the
316/// marker of a trigger (21.7.2.2).
317#[derive(Clone, Copy, Debug, PartialEq, Eq)]
318pub enum VcdVarType {
319 Reg,
320 Wire,
321 Integer,
322 Time,
323 Real,
324 RealTime,
325 Supply0,
326 Supply1,
327 Tri,
328 TriAnd,
329 TriOr,
330 TriReg,
331 Tri0,
332 Tri1,
333 WAnd,
334 WOr,
335 Event,
336}
337
338impl VcdVarType {
339 pub const ALL: [VcdVarType; 17] = [
340 VcdVarType::Reg,
341 VcdVarType::Wire,
342 VcdVarType::Integer,
343 VcdVarType::Time,
344 VcdVarType::Real,
345 VcdVarType::RealTime,
346 VcdVarType::Supply0,
347 VcdVarType::Supply1,
348 VcdVarType::Tri,
349 VcdVarType::TriAnd,
350 VcdVarType::TriOr,
351 VcdVarType::TriReg,
352 VcdVarType::Tri0,
353 VcdVarType::Tri1,
354 VcdVarType::WAnd,
355 VcdVarType::WOr,
356 VcdVarType::Event,
357 ];
358
359 /// The keyword a VCD `$var` line uses.
360 pub fn as_str(self) -> &'static str {
361 match self {
362 VcdVarType::Reg => "reg",
363 VcdVarType::Wire => "wire",
364 VcdVarType::Integer => "integer",
365 VcdVarType::Time => "time",
366 VcdVarType::Real => "real",
367 VcdVarType::RealTime => "realtime",
368 VcdVarType::Supply0 => "supply0",
369 VcdVarType::Supply1 => "supply1",
370 VcdVarType::Tri => "tri",
371 VcdVarType::TriAnd => "triand",
372 VcdVarType::TriOr => "trior",
373 VcdVarType::TriReg => "trireg",
374 VcdVarType::Tri0 => "tri0",
375 VcdVarType::Tri1 => "tri1",
376 VcdVarType::WAnd => "wand",
377 VcdVarType::WOr => "wor",
378 VcdVarType::Event => "event",
379 }
380 }
381}
382
383/// One statement-coverage site (LRM 40.2.1 a): the module definition it is
384/// declared in and the source identity of the statement (the VPI side maps a
385/// statement object to its site by it, 40.5.2).
386#[derive(Clone, Debug, PartialEq, Eq)]
387pub struct StmtSiteImage {
388 pub def: String,
389 pub buffer: u32,
390 pub start: u64,
391 pub end: u64,
392 /// The slang `StatementKind` as its raw `u16`.
393 pub kind: u16,
394 pub nest: u32,
395}
396
397/// An FSM named by the 40.4 pragmas, in one instance.
398#[derive(Clone, Debug, PartialEq, Eq)]
399pub struct FsmImage {
400 /// The instance whose module carries the pragmas.
401 pub instance: InstanceId,
402 /// The FSM's name (40.4.2).
403 pub name: String,
404 /// The state vector's pieces, most significant first.
405 pub parts: Vec<FsmPartImage>,
406 /// The legal states (40.4.6): the parameter's name and its value.
407 pub states: Vec<(String, u64)>,
408}
409
410/// One piece of an FSM state vector: bits `lsb..=msb` of a signal.
411#[derive(Clone, Debug, PartialEq, Eq)]
412pub struct FsmPartImage {
413 pub slot: u32,
414 pub msb: u32,
415 pub lsb: u32,
416}
417
418/// One signal `$dumpvars` can select (LRM 21.7): a variable or net of an
419/// instance, with the scope path the waveform shows it under. Memories
420/// and collections are not dumpable and are not listed.
421#[derive(Clone, Debug, PartialEq, Eq)]
422pub struct DumpSignalImage {
423 pub instance: InstanceId,
424 /// The name of the module definition `instance` instantiates (what
425 /// `$coverage_*(SV_COV_MODULE, "def name")` selects by, LRM 40.3.2.1).
426 pub def_name: String,
427 /// Scope path, outermost first (`["top", "u1", "blk"]`).
428 pub scope: Vec<String>,
429 /// Each scope's VCD type, parallel to `scope`.
430 pub scope_kinds: Vec<ScopeKind>,
431 pub name: String,
432 pub width: u32,
433 /// The VCD `$var` type (LRM 21.7.2.1 `var_type`).
434 pub var_type: VcdVarType,
435 /// The slot in the instance's own numbering.
436 pub slot: u32,
437 pub wide: bool,
438 /// A `real`/`shortreal`/`realtime`: the cell holds the IEEE bits.
439 pub real: bool,
440 /// A class-typed variable: an object-heap handle, never traced.
441 pub class_handle: bool,
442 /// The direction of the port this signal is the internal symbol of, for
443 /// `$dumpports` (LRM 21.7.3): `None` for a signal that is no port.
444 pub port: Option<PortDir>,
445 /// For a port, the `%v` registry key (`vj_runtime::fmt::strength_key`)
446 /// of the net whose recorded strengths and driver counts describe the
447 /// port's fixture-side value: its own net, or for an input port connected
448 /// to a whole parent net of the same width that net (the child's input
449 /// net carries only a strong copy). `None`: no record (a variable, or a
450 /// design without `$dumpports`), so the port is driven at strong by one
451 /// driver.
452 pub strength_key: Option<u64>,
453 /// For a port, the key [`SideSpec::key`] records the fixture/DUT split
454 /// of its net's drivers under; `None` when the net has no resolver (or
455 /// the design has no `$dumpports`).
456 pub side_key: Option<u64>,
457}
458
459/// A port's direction as extended VCD records it (LRM 21.7.4.3.1): an input
460/// is dumped as the test fixture's value (`D`/`U`/`N`/`Z`), an output as the
461/// device's (`L`/`H`/`X`/`T`), an inout/ref port with the unknown-direction
462/// characters (`0`/`1`/`?`/`F`).
463#[derive(Clone, Copy, Debug, PartialEq, Eq)]
464pub enum PortDir {
465 Input,
466 Output,
467 Inout,
468}
469
470/// What a design needs of DPI-C (LRM 1800-2023 35): the C functions its
471/// imports call, and the SystemVerilog subroutines it exports to C.
472#[derive(Clone, Debug, Default, PartialEq, Eq)]
473pub struct DpiImage {
474 /// The C identifier of every imported function or task, sorted. A runner
475 /// checks each resolves before the design starts.
476 pub imports: Vec<String>,
477 /// Each exported C identifier and the [`DesignImage::symbols`] index of the
478 /// function the C side reaches it through, sorted by identifier.
479 pub exports: Vec<(String, u32)>,
480 /// `(C identifier, instance scope, variant)`: which variant of an export
481 /// each instance that exports it runs.
482 pub variants: Vec<(String, String, u32)>,
483 /// The design has a timed export task (LRM 35.7): every process kernel
484 /// runs on a fiber, so that an import task's C code may block in it
485 /// (`CompiledKernelProcess::with_task_fibers`).
486 pub task_fibers: bool,
487}
488
489/// The run-wide timing options a design was built under (`vj`'s `TimingOptions`), in plain
490/// data. They shape what the build computed (the SDF annotations it replays, the corner it
491/// resolved, the negative-timing planning), so the runner may not change them: it refuses a
492/// conflicting flag by name instead of running a different design from the one that was built.
493#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
494pub struct TimingOptionsImage {
495 /// `--timing-check-per-bit` (LRM 31.8).
496 pub per_bit_vectors: bool,
497 /// `--enable-negative-timing-checks` (LRM 31.9.4).
498 pub negative_timing_checks: bool,
499 /// `--timing-reject-limit-pct`, as the IEEE bits of the percentage.
500 pub reject_limit_pct: Option<u64>,
501 /// `--timing-error-limit-pct`, as the IEEE bits of the percentage.
502 pub error_limit_pct: Option<u64>,
503 /// `--pulse-style`: 0 on-event, 1 on-detect.
504 pub pulse_style: Option<u8>,
505 /// `--showcancelled` / `--noshowcancelled`.
506 pub showcancelled: Option<bool>,
507 /// `--sdf-mtm` (the corner `TOOL_CONTROL` selects): 0 minimum, 1 typical, 2 maximum.
508 pub sdf_mtm: Option<u8>,
509}
510
511/// The design's timing section: the options it was built under and the timing plan (gate and
512/// UDP primitives, delay lines, specify paths, timing checks, SDF annotation deltas) as an
513/// opaque, deterministic byte string. Its typed codec lives in `vj-exec`, which owns the
514/// code that runs it; this crate only carries and checksums it. Empty for a design with no
515/// timing constructs.
516#[derive(Clone, Debug, Default, PartialEq, Eq)]
517pub struct TimingImage {
518 pub options: TimingOptionsImage,
519 pub plan: Vec<u8>,
520}
521
522/// Everything a runner needs to assemble and run one design.
523#[derive(Clone, Debug, PartialEq)]
524pub struct DesignImage {
525 /// `vj_abi::VJ_ABI_VERSION` the kernels were compiled against.
526 pub abi_version: u32,
527 /// The scheduler tick exponent (`1e<tick_exp>` seconds), which `%t`
528 /// defaults to.
529 pub tick_exp: i32,
530 /// Build default for `--x-initial-zero`.
531 pub x_initial_zero: bool,
532 pub templates: Vec<TemplateImage>,
533 pub instances: Vec<InstanceImage>,
534 pub foreign: Vec<ForeignImage>,
535 pub x_windows: Vec<XWindow>,
536 /// Port connection wires, in registration order.
537 pub wires: Vec<WireImage>,
538 /// Resolved net groups (resolvers register in group order, switch
539 /// networks first).
540 pub groups: Vec<GroupImage>,
541 pub networks: Vec<NetworkImage>,
542 /// Every function name the image refers to by index.
543 pub symbols: Vec<String>,
544 pub kernels: Vec<KernelImage>,
545 pub fork_table: Vec<SpawnSpec>,
546 pub fork_branches: Vec<ForkBranchImage>,
547 pub wait_table: Vec<WaitTableEntry>,
548 /// Every interned string but `""`, in id order (`crate::strings::snapshot`).
549 /// A string's id is baked into machine code and into cells' initial
550 /// values, so the runner re-interns these first, in this order.
551 pub strings: Vec<Vec<u8>>,
552 /// Every constant collection (`crate::collections::frozen_snapshot`), the
553 /// same way: entry `i` is handle `(1 << 32) | (i + 1)`.
554 pub collections: Vec<FrozenData>,
555 /// Every class template's runtime metadata (`crate::objects::template_snapshot`),
556 /// by ascending template id. Registered with the object heap before the
557 /// design runs, so `release`, `copy`, `$cast` and the cycle collector see
558 /// the same classes they saw in the process that built the image.
559 pub classes: Vec<TemplateSnapshot>,
560 /// Every dumpable signal, in the order `$dumpvars` numbers them.
561 pub dump_signals: Vec<DumpSignalImage>,
562 /// `Some(defining module name of each statement site)` when the code was
563 /// generated with statement-coverage probes (`build-aot --coverage`, LRM
564 /// 40.2.1 a); `None` otherwise.
565 pub stmt_cov: Option<Vec<StmtSiteImage>>,
566 /// The FSMs the 40.4 pragmas name, one per instance (LRM 40.2.1 c).
567 pub fsms: Vec<FsmImage>,
568 /// The design's DPI-C imports and exports.
569 pub dpi: DpiImage,
570 /// Assertions, checker free variables and sampled-value guards.
571 pub verif: verif::VerifImage,
572 /// Timing options and the timing plan (primitives, specify, timing checks, SDF).
573 pub timing: TimingImage,
574 /// The constraint solver's programs and `randomize()` call-site specs
575 /// (`crate::constraints::registry::snapshot`), opaque here; empty for a
576 /// design that never randomizes.
577 pub randomize: Vec<u8>,
578 /// The resolvers no [`GroupImage`] describes (user-defined nettypes,
579 /// unpacked-array nets), opaque here: its typed codec lives in
580 /// `vj-exec::usernets`, which owns the code that runs it. Empty for a
581 /// design with none.
582 pub native_nets: Vec<u8>,
583 /// The VPI object model (`vj` `vpi::model::VpiModel::encode`: objects, handle
584 /// relations, properties, expression nodes, name indexes), opaque here; empty for an
585 /// image built without VPI. Present so a design runs the same user VPI libraries under
586 /// the AOT runner as under the JIT, with no slang at run time.
587 pub vpi: Vec<u8>,
588}
589
590impl DesignImage {
591 /// An image with no content (for tests and as a builder's start).
592 pub fn empty(abi_version: u32) -> Self {
593 DesignImage {
594 abi_version,
595 tick_exp: 0,
596 x_initial_zero: false,
597 templates: Vec::new(),
598 instances: Vec::new(),
599 foreign: Vec::new(),
600 x_windows: Vec::new(),
601 wires: Vec::new(),
602 groups: Vec::new(),
603 networks: Vec::new(),
604 symbols: Vec::new(),
605 kernels: Vec::new(),
606 fork_table: Vec::new(),
607 fork_branches: Vec::new(),
608 wait_table: Vec::new(),
609 strings: Vec::new(),
610 collections: Vec::new(),
611 classes: Vec::new(),
612 dump_signals: Vec::new(),
613 stmt_cov: None,
614 fsms: Vec::new(),
615 dpi: DpiImage::default(),
616 verif: verif::VerifImage::default(),
617 timing: TimingImage::default(),
618 randomize: Vec::new(),
619 native_nets: Vec::new(),
620 vpi: Vec::new(),
621 }
622 }
623
624 /// Interns `name`, returning its index in [`Self::symbols`].
625 pub fn intern(&mut self, name: &str) -> u32 {
626 if let Some(i) = self.symbols.iter().position(|s| s == name) {
627 return i as u32;
628 }
629 self.symbols.push(name.to_owned());
630 (self.symbols.len() - 1) as u32
631 }
632
633 /// The name behind a symbol index.
634 pub fn symbol(&self, index: u32) -> Option<&str> {
635 self.symbols.get(index as usize).map(String::as_str)
636 }
637
638 /// The synthetic driver-contribution bank, if the design has one.
639 pub fn bank(&self) -> Option<InstanceId> {
640 self.instances
641 .iter()
642 .find(|i| i.kind == InstanceKind::Bank)
643 .map(|i| i.id)
644 }
645
646 /// The layout of `key`'s template.
647 pub fn layout_of(&self, key: &TemplateKey) -> Option<&StateLayout> {
648 self.templates
649 .iter()
650 .find(|t| t.key == *key)
651 .map(|t| &t.layout)
652 }
653}