Skip to main content

vj_sim/
driver_counts.rs

1//! `$countdrivers` data (IEEE 1800-2023 D.2, Table D.1): per net bit, how
2//! many drivers are at 0, 1 and x (a driver at `z` is not counted). A net
3//! resolver records them next to its `%v` strengths (`vj_exec::nets`)
4//! under the net's strength key; a net no resolver runs for has at most one
5//! driver, so `sv_rt_net_drivers` reads its count off the net itself.
6
7use std::cell::RefCell;
8use std::collections::HashMap;
9
10/// A bit's driver counts: at 0, at 1, at x.
11pub type BitCounts = [u32; 3];
12
13/// The counts a net no `$countdrivers` meaning exists for records (a net in
14/// a bidirectional switch network): the call stops the run by name.
15pub const UNCOUNTED: BitCounts = [u32::MAX; 3];
16
17thread_local! {
18    /// Each net's per-bit counts (bit 0 first), by strength key. Per thread
19    /// like the runtime's other run state; emptied by
20    /// [`reset_driver_counts_for_new_run`].
21    static COUNTS: RefCell<HashMap<u64, Vec<BitCounts>>> = RefCell::default();
22    /// Each dumped port's per-bit fixture/DUT split, by side key.
23    static SIDES: RefCell<HashMap<u64, Vec<SideBit>>> = RefCell::default();
24}
25
26/// One bit of a net as the test fixture's drivers and the DUT's own drivers
27/// resolve it separately (`$dumpports`, LRM 21.7.4.3.2). Index 0 is the
28/// fixture side (drivers outside the dumped instance), index 1 the DUT side.
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
30pub struct SideBit {
31    /// The side's resolved possible states in the resolver's `Points`
32    /// encoding: bit 0 is `z`, bit `l` (1..=7) is 0 at strength level `l`,
33    /// bit `8 + l` is 1 at level `l`.
34    pub points: [u16; 2],
35    /// How many of the side's drivers are not at `z` on this bit.
36    pub active: [u8; 2],
37    /// Whether the side has any driver at all (connected).
38    pub present: [bool; 2],
39}
40
41/// Forgets every net's counts (the start of a run).
42pub fn reset_driver_counts_for_new_run() {
43    COUNTS.with(|c| c.borrow_mut().clear());
44    SIDES.with(|c| c.borrow_mut().clear());
45}
46
47/// Records the counts of net `key`.
48pub fn set_driver_counts(key: u64, counts: &[BitCounts]) {
49    COUNTS.with(|c| {
50        let mut m = c.borrow_mut();
51        match m.get_mut(&key) {
52            Some(v) if v.as_slice() == counts => {}
53            Some(v) => *v = counts.to_vec(),
54            None => {
55                m.insert(key, counts.to_vec());
56            }
57        }
58    });
59}
60
61/// The recorded counts of bit `bit` of net `key`.
62pub fn driver_counts_of(key: u64, bit: u32) -> Option<BitCounts> {
63    COUNTS.with(|c| {
64        c.borrow()
65            .get(&key)
66            .and_then(|v| v.get(bit as usize).copied())
67    })
68}
69
70/// Records the fixture/DUT split of the port whose side key is `key`.
71pub fn set_sides(key: u64, bits: &[SideBit]) {
72    SIDES.with(|c| {
73        c.borrow_mut().insert(key, bits.to_vec());
74    });
75}
76
77/// The recorded split of bit `bit` of the port with side key `key`.
78pub fn sides_of(key: u64, bit: u32) -> Option<SideBit> {
79    SIDES.with(|c| {
80        c.borrow()
81            .get(&key)
82            .and_then(|v| v.get(bit as usize).copied())
83    })
84}