use std::cmp::Ordering;
use vj_abi::{Bit4, SimTime};
use super::four_state_bit_at;
use super::instance::StateEngine;
use super::write::{ChangeResult, PreWriteHook, SlotLocation};
use super::{FourStateValue, NetKind, SignalAccess, SlotClass, StateCellId};
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
pub enum DriveStrength {
Supply,
Strong,
Pull,
Weak,
HighZ,
}
impl DriveStrength {
fn rank(self) -> u8 {
match self {
DriveStrength::HighZ => 0,
DriveStrength::Weak => 1,
DriveStrength::Pull => 2,
DriveStrength::Strong => 3,
DriveStrength::Supply => 4,
}
}
}
impl PartialOrd for DriveStrength {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for DriveStrength {
fn cmp(&self, other: &Self) -> Ordering {
self.rank().cmp(&other.rank())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
pub struct DriveStrengthPair {
pub s0: DriveStrength,
pub s1: DriveStrength,
}
impl DriveStrengthPair {
pub const STRONG: DriveStrengthPair = DriveStrengthPair {
s0: DriveStrength::Strong,
s1: DriveStrength::Strong,
};
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DriverEntry {
pub source: StateCellId,
pub strength: DriveStrengthPair,
pub forced: bool,
}
#[derive(Clone, Debug)]
pub struct DriverSet {
pub resolved: StateCellId,
pub drivers: Vec<DriverEntry>,
pub net_kind: NetKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DriverError {
UnresolvableUserDefinedNetType,
}
#[derive(Clone, Debug)]
pub struct TriregCharge {
pub last_value: FourStateValue,
pub strength: ChargeStrength,
pub last_drive_time: SimTime,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ChargeStrength {
Small,
Medium,
Large,
}
impl StateEngine {
pub fn trireg_charge(&self, cell: StateCellId) -> Option<&TriregCharge> {
self.trireg_charge.get(&cell)
}
pub fn set_trireg_charge(&mut self, cell: StateCellId, charge: TriregCharge) {
self.trireg_charge.insert(cell, charge);
}
}
fn effective_strength(bit: Bit4, pair: DriveStrengthPair) -> DriveStrength {
match bit {
Bit4::Zero => pair.s0,
Bit4::One => pair.s1,
Bit4::X => match pair.s0.min(pair.s1) {
DriveStrength::HighZ => pair.s0.max(pair.s1),
weaker => weaker,
},
Bit4::Z => pair.s0,
}
}
fn combine_bit(
contributions: &[(Bit4, DriveStrength)],
net_kind: NetKind,
) -> Result<Bit4, DriverError> {
combine_bit_strength(contributions, net_kind).map(|(bit, _)| bit)
}
fn combine_bit_strength(
contributions: &[(Bit4, DriveStrength)],
net_kind: NetKind,
) -> Result<(Bit4, Option<DriveStrength>), DriverError> {
if let NetKind::UserDefined = net_kind {
return Err(DriverError::UnresolvableUserDefinedNetType);
}
let mut live: Vec<(Bit4, DriveStrength)> = contributions
.iter()
.copied()
.filter(|(bit, s)| *bit != Bit4::Z && *s != DriveStrength::HighZ)
.collect();
match net_kind {
NetKind::Tri0 => live.push((Bit4::Zero, DriveStrength::Pull)),
NetKind::Tri1 => live.push((Bit4::One, DriveStrength::Pull)),
_ => {}
}
if live.is_empty() {
return Ok((Bit4::Z, None));
}
if matches!(
net_kind,
NetKind::WAnd | NetKind::TriAnd | NetKind::WOr | NetKind::TriOr
) {
let is_and = matches!(net_kind, NetKind::WAnd | NetKind::TriAnd);
let dominant = if is_and { Bit4::Zero } else { Bit4::One };
let recessive = if is_and { Bit4::One } else { Bit4::Zero };
let top = live.iter().map(|(_, s)| *s).max();
return Ok((
if live.iter().any(|(bit, _)| *bit == dominant) {
dominant
} else if live.iter().any(|(bit, _)| *bit == Bit4::X) {
Bit4::X
} else {
recessive
},
top,
));
}
let max_strength = live
.iter()
.map(|(_, strength)| *strength)
.max()
.expect("live is non-empty, checked above");
let winners: Vec<Bit4> = live
.iter()
.filter(|(_, strength)| *strength == max_strength)
.map(|(bit, _)| *bit)
.collect();
let first = winners[0];
if winners.iter().all(|bit| *bit == first) {
return Ok((first, Some(max_strength)));
}
let x = match net_kind {
NetKind::Wire
| NetKind::Tri
| NetKind::Tri0
| NetKind::Tri1
| NetKind::TriReg
| NetKind::Supply0
| NetKind::Supply1
| NetKind::UWire => Bit4::X,
NetKind::WAnd | NetKind::TriAnd | NetKind::WOr | NetKind::TriOr => {
unreachable!("handled above, before strength grouping")
}
NetKind::UserDefined => unreachable!("returned Err above"),
};
Ok((x, Some(max_strength)))
}
pub fn resolve_strengths(
values: &[(FourStateValue, DriveStrengthPair)],
width: u32,
net_kind: NetKind,
) -> Result<Vec<(Bit4, Option<DriveStrength>)>, DriverError> {
(0..width)
.map(|i| match net_kind {
NetKind::Supply0 => Ok((Bit4::Zero, Some(DriveStrength::Supply))),
NetKind::Supply1 => Ok((Bit4::One, Some(DriveStrength::Supply))),
_ => {
let contributions: Vec<(Bit4, DriveStrength)> = values
.iter()
.map(|(v, strength)| {
let bit = four_state_bit_at(v, i);
(bit, effective_strength(bit, *strength))
})
.collect();
combine_bit_strength(&contributions, net_kind)
}
})
.collect()
}
fn pack_bits4(class: SlotClass, elem_word_count: u32, bits: &[Bit4]) -> FourStateValue {
match class {
SlotClass::Inline => {
let mut val: u64 = 0;
let mut unk: u64 = 0;
for (i, bit) in bits.iter().enumerate() {
let (v, u) = bit.to_val_unk();
if v {
val |= 1u64 << i;
}
if u {
unk |= 1u64 << i;
}
}
FourStateValue::Narrow((val as u128) | ((unk as u128) << 64))
}
SlotClass::Wide | SlotClass::Memory => {
let words = elem_word_count as usize;
let mut aval = vec![0u64; words];
let mut bval = vec![0u64; words];
for (i, bit) in bits.iter().enumerate() {
let (a, b) = bit.to_aval_bval();
let word = i / 64;
let lane = i % 64;
if a {
aval[word] |= 1u64 << lane;
}
if b {
bval[word] |= 1u64 << lane;
}
}
FourStateValue::Wide { aval, bval }
}
SlotClass::ForceWide => {
unreachable!("pack_bits4: set.resolved is never itself SlotClass::ForceWide")
}
}
}
pub fn resolve_values(
values: &[(FourStateValue, DriveStrengthPair)],
width: u32,
net_kind: NetKind,
) -> Result<FourStateValue, DriverError> {
let (class, words) = if width <= 64 {
(SlotClass::Inline, 1)
} else {
(SlotClass::Wide, width.div_ceil(64))
};
let mut bits = Vec::with_capacity(width as usize);
for i in 0..width {
let mut contributions: Vec<(Bit4, DriveStrength)> = values
.iter()
.map(|(v, strength)| {
let bit = four_state_bit_at(v, i);
(bit, effective_strength(bit, *strength))
})
.collect();
if net_kind == NetKind::Supply0 {
contributions.push((Bit4::Zero, DriveStrength::Supply));
} else if net_kind == NetKind::Supply1 {
contributions.push((Bit4::One, DriveStrength::Supply));
}
let bit = combine_bit(&contributions, net_kind)?;
bits.push(bit);
}
Ok(pack_bits4(class, words, &bits))
}
pub fn resolve_net_step(
engine: &mut StateEngine,
set: &DriverSet,
hook: &mut dyn PreWriteHook,
) -> Result<ChangeResult, DriverError> {
if let NetKind::UserDefined = set.net_kind {
return Err(DriverError::UnresolvableUserDefinedNetType);
}
if let Some(forced_entry) = set.drivers.iter().find(|entry| entry.forced) {
let forced_value = engine.read(forced_entry.source);
return Ok(engine.commit_write(set.resolved, forced_value, hook));
}
let resolved_loc: SlotLocation = engine.cells[set.resolved.0 as usize];
let width = resolved_loc.bit_width;
let mut resolved_bits: Vec<Bit4> = Vec::with_capacity(width as usize);
for i in 0..width {
let contributions: Vec<(Bit4, DriveStrength)> = set
.drivers
.iter()
.map(|entry| {
let value = engine.read(entry.source);
let bit = four_state_bit_at(&value, i);
(bit, effective_strength(bit, entry.strength))
})
.collect();
resolved_bits.push(combine_bit(&contributions, set.net_kind)?);
}
let new_value = pack_bits4(
resolved_loc.class,
resolved_loc.elem_word_count,
&resolved_bits,
);
Ok(engine.commit_write(set.resolved, new_value, hook))
}
pub fn force_driver(
engine: &mut StateEngine,
set: &mut DriverSet,
net: StateCellId,
value: FourStateValue,
) -> StateCellId {
assert_eq!(
net, set.resolved,
"force_driver: `net` must be this DriverSet's own resolved cell"
);
let resolved_loc: SlotLocation = engine.cells[set.resolved.0 as usize];
let source = match resolved_loc.class {
SlotClass::Inline => {
let word_offset = unsafe { engine.arena.alloc_inline_word() };
SlotLocation {
class: SlotClass::Inline,
word_offset,
bit_width: resolved_loc.bit_width,
elem_word_count: 1,
row_stride_words: 0,
num_rows: 0,
}
}
SlotClass::Wide | SlotClass::Memory => {
let word_offset = unsafe {
engine
.arena
.alloc_force_wide_words(resolved_loc.elem_word_count)
};
SlotLocation {
class: SlotClass::ForceWide,
word_offset,
bit_width: resolved_loc.bit_width,
elem_word_count: resolved_loc.elem_word_count,
row_stride_words: 0,
num_rows: 0,
}
}
SlotClass::ForceWide => {
unreachable!("force_driver: set.resolved is never itself SlotClass::ForceWide")
}
};
let source = engine.alloc_cell(source);
engine.cell_reset[source.0 as usize] = super::rollback::CellReset::ForceContribution;
engine.commit_write(source, value, &mut ());
set.drivers.push(DriverEntry {
source,
strength: DriveStrengthPair {
s0: DriveStrength::Supply,
s1: DriveStrength::Supply,
},
forced: true,
});
engine.notify_force_observed(net);
source
}
pub fn release_driver(engine: &mut StateEngine, set: &mut DriverSet, forced: StateCellId) {
let before = set.drivers.len();
set.drivers.retain(|entry| entry.source != forced);
assert_eq!(
set.drivers.len(),
before - 1,
"release_driver: `forced` must be the `StateCellId` of a `DriverEntry` \
currently present in `set.drivers` (from a prior `force_driver` call on this same set)"
);
resolve_net_step(engine, set, &mut ()).expect(
"release_driver: force/release only ever targets a non-UserDefined net in v1, \
so resolve_net_step's Err arm is unreachable here",
);
engine.notify_force_observed(set.resolved);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::instance::TemplateRegistry;
fn fresh_engine() -> StateEngine {
StateEngine::new(TemplateRegistry::new())
}
fn scalar_cell(engine: &mut StateEngine) -> StateCellId {
let word_offset = unsafe { engine.arena.alloc_inline_word() };
let loc = SlotLocation {
class: SlotClass::Inline,
word_offset,
bit_width: 1,
elem_word_count: 1,
row_stride_words: 0,
num_rows: 0,
};
engine.alloc_cell(loc)
}
fn seeded_scalar_cell(engine: &mut StateEngine, bit: Bit4) -> StateCellId {
let cell = scalar_cell(engine);
let (v, u) = bit.to_val_unk();
let word = (v as u128) | ((u as u128) << 64);
engine.commit_write(cell, FourStateValue::Narrow(word), &mut ());
cell
}
fn read_bit(engine: &StateEngine, cell: StateCellId) -> Bit4 {
four_state_bit_at(&engine.read(cell), 0)
}
fn strong_pair() -> DriveStrengthPair {
DriveStrengthPair {
s0: DriveStrength::Strong,
s1: DriveStrength::Strong,
}
}
fn wide_cell(engine: &mut StateEngine) -> StateCellId {
let word_offset = unsafe { engine.arena.alloc_wide_words(2) };
let loc = SlotLocation {
class: SlotClass::Wide,
word_offset,
bit_width: 128,
elem_word_count: 2,
row_stride_words: 0,
num_rows: 0,
};
engine.alloc_cell(loc)
}
fn seeded_wide_cell(engine: &mut StateEngine, aval0: u64) -> StateCellId {
let cell = wide_cell(engine);
engine.commit_write(
cell,
FourStateValue::Wide {
aval: vec![aval0, 0],
bval: vec![0, 0],
},
&mut (),
);
cell
}
fn read_wide_aval0(engine: &StateEngine, cell: StateCellId) -> u64 {
match engine.read(cell) {
FourStateValue::Wide { aval, .. } => aval[0],
FourStateValue::Narrow(_) => panic!("expected a Wide value"),
}
}
#[test]
fn k_plus_1_slots_means_k_contribution_cells_plus_one_resolved_cell() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let d0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let d1 = seeded_scalar_cell(&mut engine, Bit4::One);
let d2 = seeded_scalar_cell(&mut engine, Bit4::X);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: d0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: d1,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: d2,
strength: strong_pair(),
forced: false,
},
],
net_kind: NetKind::Wire,
};
assert_eq!(set.drivers.len(), 3);
assert_ne!(set.resolved, d0);
assert_ne!(set.resolved, d1);
assert_ne!(set.resolved, d2);
}
#[test]
fn two_strong_drivers_agreeing_resolve_to_that_value_wire() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let d0 = seeded_scalar_cell(&mut engine, Bit4::One);
let d1 = seeded_scalar_cell(&mut engine, Bit4::One);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: d0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: d1,
strength: strong_pair(),
forced: false,
},
],
net_kind: NetKind::Wire,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(read_bit(&engine, resolved), Bit4::One);
}
#[test]
fn strong_beats_weak_on_a_wire_regardless_of_registration_order() {
for reversed in [false, true] {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let strong0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let weak1 = seeded_scalar_cell(&mut engine, Bit4::One);
let mut drivers = vec![
DriverEntry {
source: strong0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: weak1,
strength: DriveStrengthPair {
s0: DriveStrength::Weak,
s1: DriveStrength::Weak,
},
forced: false,
},
];
if reversed {
drivers.reverse();
}
let set = DriverSet {
resolved,
drivers,
net_kind: NetKind::Wire,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::Zero,
"reversed={reversed}: strong driver must win regardless of registration order"
);
}
}
#[test]
fn effective_strength_reduces_an_x_driving_contributor_by_the_weaker_of_its_two_strengths() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let x_driver = seeded_scalar_cell(&mut engine, Bit4::X);
let zero_driver = seeded_scalar_cell(&mut engine, Bit4::Zero);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: x_driver,
strength: DriveStrengthPair {
s0: DriveStrength::Weak,
s1: DriveStrength::Strong,
},
forced: false,
},
DriverEntry {
source: zero_driver,
strength: strong_pair(),
forced: false,
},
],
net_kind: NetKind::Wire,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::Zero,
"an X-driving contributor's effective strength must be min(s0,s1) = Weak here, \
losing outright to the Strong zero driver -- not max(s0,s1) = Strong, which \
would tie and fold to X"
);
}
#[test]
fn two_strong_disagreeing_drivers_resolve_per_net_kind() {
for (net_kind, expected) in [
(NetKind::Wire, Bit4::X),
(NetKind::WAnd, Bit4::Zero),
(NetKind::WOr, Bit4::One),
] {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let d0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let d1 = seeded_scalar_cell(&mut engine, Bit4::One);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: d0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: d1,
strength: strong_pair(),
forced: false,
},
],
net_kind,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
expected,
"net_kind={net_kind:?}"
);
}
}
#[test]
fn z_valued_drivers_never_participate_undriven_net_reads_as_z() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let d0 = seeded_scalar_cell(&mut engine, Bit4::Z);
let d1 = seeded_scalar_cell(&mut engine, Bit4::Z);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: d0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: d1,
strength: strong_pair(),
forced: false,
},
],
net_kind: NetKind::Wire,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(read_bit(&engine, resolved), Bit4::Z);
}
#[test]
fn heterogeneous_strength_drivers_still_all_participate_in_wand_wor_fold() {
let weak_pair = DriveStrengthPair {
s0: DriveStrength::Weak,
s1: DriveStrength::Weak,
};
{
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let strong1 = seeded_scalar_cell(&mut engine, Bit4::One);
let weak0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: strong1,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: weak0,
strength: weak_pair,
forced: false,
},
],
net_kind: NetKind::WAnd,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::Zero,
"wand must AND-fold every live driver regardless of strength \
(matches iverilog 12: w=0), not drop the weak 0 via strength-grouping"
);
}
{
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let strong0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let weak1 = seeded_scalar_cell(&mut engine, Bit4::One);
let set = DriverSet {
resolved,
drivers: vec![
DriverEntry {
source: strong0,
strength: strong_pair(),
forced: false,
},
DriverEntry {
source: weak1,
strength: weak_pair,
forced: false,
},
],
net_kind: NetKind::WOr,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::One,
"wor must OR-fold every live driver regardless of strength \
(matches iverilog 12: w=1), not drop the weak 1 via strength-grouping"
);
}
}
#[test]
fn force_overrides_a_strong_wire_driver_release_restores_prior_value() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let strong0 = seeded_scalar_cell(&mut engine, Bit4::Zero);
let mut set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: strong0,
strength: strong_pair(),
forced: false,
}],
net_kind: NetKind::Wire,
};
let (v, u) = Bit4::One.to_val_unk();
let one = FourStateValue::Narrow((v as u128) | ((u as u128) << 64));
let forced = force_driver(&mut engine, &mut set, resolved, one);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::One,
"force must win outright over the ordinary strong driver"
);
release_driver(&mut engine, &mut set, forced);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::Zero,
"release must restore the still-present strong driver's value"
);
}
#[test]
fn release_driver_removes_only_the_named_forced_entry_not_every_forced_entry() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let ordinary = seeded_scalar_cell(&mut engine, Bit4::One);
let mut set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: ordinary,
strength: strong_pair(),
forced: false,
}],
net_kind: NetKind::Wire,
};
let (v, u) = Bit4::Zero.to_val_unk();
let zero = FourStateValue::Narrow((v as u128) | ((u as u128) << 64));
let forced_a = force_driver(&mut engine, &mut set, resolved, zero);
let (v, u) = Bit4::X.to_val_unk();
let x = FourStateValue::Narrow((v as u128) | ((u as u128) << 64));
let _forced_b = force_driver(&mut engine, &mut set, resolved, x);
release_driver(&mut engine, &mut set, forced_a);
assert_eq!(
set.drivers.len(),
2,
"releasing forced_a must remove exactly that one entry, leaving the ordinary \
driver and the still-live forced_b entry"
);
assert_eq!(
read_bit(&engine, resolved),
Bit4::X,
"forced_b, pushed after forced_a and never released, must still be the entry \
resolve_net_step's forced short-circuit picks -- not silently removed alongside \
forced_a"
);
}
#[test]
fn combine_bit_and_resolve_net_step_reject_userdefined_net_kind_with_a_typed_error() {
assert_eq!(
combine_bit(&[], NetKind::UserDefined),
Err(DriverError::UnresolvableUserDefinedNetType)
);
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let d0 = seeded_scalar_cell(&mut engine, Bit4::One);
let set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: d0,
strength: strong_pair(),
forced: false,
}],
net_kind: NetKind::UserDefined,
};
let before = read_bit(&engine, resolved);
let result = resolve_net_step(&mut engine, &set, &mut ());
assert_eq!(
result.err(),
Some(DriverError::UnresolvableUserDefinedNetType)
);
assert_eq!(
read_bit(&engine, resolved),
before,
"no partial/guessed commit on the rejected path"
);
}
#[test]
fn undriven_tri0_reads_zero_and_undriven_tri1_reads_one_via_implicit_pull() {
for (net_kind, expected) in [(NetKind::Tri0, Bit4::Zero), (NetKind::Tri1, Bit4::One)] {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let set = DriverSet {
resolved,
drivers: vec![],
net_kind,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
expected,
"net_kind={net_kind:?}: undriven tri0/tri1 must read its implicit pull, not Z"
);
}
}
#[test]
fn tri0_tri1_implicit_pull_beats_an_explicit_weak_driver() {
let weak_pair = DriveStrengthPair {
s0: DriveStrength::Weak,
s1: DriveStrength::Weak,
};
for (net_kind, weak_drives, expected) in [
(NetKind::Tri0, Bit4::One, Bit4::Zero),
(NetKind::Tri1, Bit4::Zero, Bit4::One),
] {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let weak_driver = seeded_scalar_cell(&mut engine, weak_drives);
let set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: weak_driver,
strength: weak_pair,
forced: false,
}],
net_kind,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
expected,
"net_kind={net_kind:?}: the implicit Pull-strength pull must beat an \
explicit Weak driver, matching iverilog 12"
);
}
}
#[test]
fn force_and_release_still_work_on_a_wide_net_after_the_wide_plane_is_sealed() {
let mut engine = fresh_engine();
let resolved = wide_cell(&mut engine);
let strong_driver = seeded_wide_cell(&mut engine, 0xAAAA_AAAA);
let mut set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: strong_driver,
strength: strong_pair(),
forced: false,
}],
net_kind: NetKind::Wire,
};
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(read_wide_aval0(&engine, resolved), 0xAAAA_AAAA);
engine.arena.seal_wide_plane();
assert!(engine.arena.is_wide_plane_sealed());
let forced_value = FourStateValue::Wide {
aval: vec![0xFFFF_FFFF, 0],
bval: vec![0, 0],
};
let forced = force_driver(&mut engine, &mut set, resolved, forced_value);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_wide_aval0(&engine, resolved),
0xFFFF_FFFF,
"force must win outright over the ordinary strong driver on a Wide net"
);
release_driver(&mut engine, &mut set, forced);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_wide_aval0(&engine, resolved),
0xAAAA_AAAA,
"release must restore the still-present strong driver's value"
);
}
#[test]
fn force_overrides_an_ordinary_driver_on_a_wand_net() {
let mut engine = fresh_engine();
let resolved = scalar_cell(&mut engine);
let ordinary = seeded_scalar_cell(&mut engine, Bit4::Zero);
let mut set = DriverSet {
resolved,
drivers: vec![DriverEntry {
source: ordinary,
strength: strong_pair(),
forced: false,
}],
net_kind: NetKind::WAnd,
};
let (v, u) = Bit4::One.to_val_unk();
let one = FourStateValue::Narrow((v as u128) | ((u as u128) << 64));
let forced = force_driver(&mut engine, &mut set, resolved, one);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::One,
"force must win outright on a wand net even though the wired-AND fold of \
the ordinary driver's 0 and the forced 1 would otherwise resolve to 0"
);
release_driver(&mut engine, &mut set, forced);
resolve_net_step(&mut engine, &set, &mut ()).unwrap();
assert_eq!(
read_bit(&engine, resolved),
Bit4::Zero,
"release must restore the still-present ordinary driver's value"
);
}
}