1use sv_lang::{Bit, Compilation, ConstantValue, Design, Digit, LiteralBase, OwnedSVInt, Session};
10use vj_abi::Bit4;
11
12use super::{FourStateValue, four_state_bit_at};
13
14fn bit_to_bit4(b: Bit) -> Bit4 {
19 match b {
20 Bit::Zero => Bit4::Zero,
21 Bit::One => Bit4::One,
22 Bit::X => Bit4::X,
23 Bit::Z => Bit4::Z,
24 }
25}
26
27pub fn bits_to_four_state(bits: &[Bit]) -> FourStateValue {
35 if bits.len() <= 64 {
36 let mut val: u64 = 0;
37 let mut unk: u64 = 0;
38 for (i, &b) in bits.iter().enumerate() {
39 let (v, u) = bit_to_bit4(b).to_val_unk();
40 if v {
41 val |= 1u64 << i;
42 }
43 if u {
44 unk |= 1u64 << i;
45 }
46 }
47 FourStateValue::Narrow((val as u128) | ((unk as u128) << 64))
48 } else {
49 let (aval, bval) = bits_to_aval_bval(bits);
50 FourStateValue::Wide { aval, bval }
51 }
52}
53
54pub fn packed_words(bits: &[Bit]) -> Vec<u64> {
58 let w = bits.len();
59 let mut out = vec![0u64; (2 * w).div_ceil(64).max(1)];
60 for (i, &b) in bits.iter().enumerate() {
61 let (v, u) = bit_to_bit4(b).to_val_unk();
62 if v {
63 out[i / 64] |= 1u64 << (i % 64);
64 }
65 if u {
66 out[(w + i) / 64] |= 1u64 << ((w + i) % 64);
67 }
68 }
69 out
70}
71
72pub fn bits_to_aval_bval(bits: &[Bit]) -> (Vec<u64>, Vec<u64>) {
74 let words = bits.len().div_ceil(64).max(1);
75 let mut aval = vec![0u64; words];
76 let mut bval = vec![0u64; words];
77 for (i, &b) in bits.iter().enumerate() {
78 let (a, bv) = bit_to_bit4(b).to_aval_bval();
79 let word = i / 64;
80 let bit = i % 64;
81 if a {
82 aval[word] |= 1u64 << bit;
83 }
84 if bv {
85 bval[word] |= 1u64 << bit;
86 }
87 }
88 (aval, bval)
89}
90
91fn single_bit_known(value: bool) -> OwnedSVInt {
96 OwnedSVInt::from_digits(
97 1,
98 LiteralBase::Binary,
99 false,
100 false,
101 &[Digit::Value(value as u8)],
102 )
103 .expect("a single known binary digit at width 1 always constructs")
104}
105
106pub fn four_state_to_owned_svint(v: &FourStateValue, width: u32, signed: bool) -> OwnedSVInt {
115 let mut out =
116 OwnedSVInt::create_fill_x(width, signed).expect("caller guarantees a nonzero width");
117 for i in 0..width {
118 match four_state_bit_at(v, i) {
119 Bit4::X => {}
120 Bit4::Zero => {
121 let zero = single_bit_known(false);
122 out.set_range(i as i32, i as i32, &zero)
123 .expect("single-bit range within [0,width) always matches a 1-bit value");
124 }
125 Bit4::One => {
126 let one = single_bit_known(true);
127 out.set_range(i as i32, i as i32, &one)
128 .expect("single-bit range within [0,width) always matches a 1-bit value");
129 }
130 Bit4::Z => {
131 let z = OwnedSVInt::create_fill_z(1, false)
132 .expect("a single-bit fill-z always constructs");
133 out.set_range(i as i32, i as i32, &z)
134 .expect("single-bit range within [0,width) always matches a 1-bit value");
135 }
136 }
137 }
138 out
139}
140
141pub fn four_state_of_constant(cv: &ConstantValue) -> Option<FourStateValue> {
147 Some(bits_to_four_state(&svint_bits(cv.as_integer()?)?))
148}
149
150pub fn constant_expr_bits(e: &sv_lang::Expression<'_>) -> Option<Vec<Bit>> {
153 Some(svint_bits(e.constant_value()?.as_integer()?)?.into_owned())
154}
155
156pub fn svint_bits(v: &sv_lang::SVInt) -> Option<std::borrow::Cow<'_, [Bit]>> {
160 (v.bits().len() == v.bit_width() as usize).then(|| std::borrow::Cow::Borrowed(v.bits()))
161}
162
163pub(crate) fn owned_svint_to_four_state(v: &OwnedSVInt) -> Option<FourStateValue> {
173 Some(bits_to_four_state(&svint_bits(&v.snapshot())?))
174}
175
176pub fn compile_source(src: &str) -> Result<Design, sv_lang::Error> {
180 let session = Session::new();
181 let mut comp = Compilation::new(&session)?;
182 comp.add_source(src)?;
183 comp.compile()
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
195 fn bits_to_four_state_narrow_matches_bit4_table_for_zero_one_x_z() {
196 let bits = [Bit::Zero, Bit::One, Bit::X, Bit::Z];
197 let fv = bits_to_four_state(&bits);
198 let expected: u128 = 0xA | (0xCu128 << 64);
199 match fv {
200 FourStateValue::Narrow(w) => assert_eq!(w, expected),
201 FourStateValue::Wide { .. } => panic!("expected Narrow for 4 bits"),
202 }
203 }
204
205 #[test]
209 fn bits_to_four_state_wide_uses_bit4_aval_bval_table() {
210 let bits = [Bit::X; 65];
211 let fv = bits_to_four_state(&bits);
212 match fv {
213 FourStateValue::Wide { aval, bval } => {
214 assert_eq!(aval.len(), 2);
215 assert_eq!(bval.len(), 2);
216 assert_eq!(aval[0], u64::MAX);
217 assert_eq!(bval[0], u64::MAX);
218 }
219 FourStateValue::Narrow(_) => panic!("expected Wide for 65 bits"),
220 }
221 }
222
223 #[test]
227 fn four_state_to_owned_svint_round_trips_known_and_unknown_bits() {
228 let all_known = FourStateValue::Narrow(0b1010u128);
229 let v = four_state_to_owned_svint(&all_known, 4, false);
230 assert_eq!(v.snapshot().as_u64(), Some(0b1010));
231 assert!(!v.snapshot().has_unknown());
232
233 let with_x = FourStateValue::Narrow(0b1000u128 | (0b0010u128 << 64));
236 let v2 = four_state_to_owned_svint(&with_x, 4, false);
237 assert!(v2.snapshot().has_unknown());
238 assert_eq!(v2.snapshot().bit(1), Some(Bit::X));
239 }
240
241 #[test]
247 fn four_state_of_constant_extracts_bits_from_a_real_compiled_constant() {
248 let design = compile_source("module m; localparam int p = 8'hAA; endmodule\n")
249 .expect("valid SV source compiles");
250 let body = design
251 .top_instances()
252 .next()
253 .expect("one top instance")
254 .instance_body()
255 .expect("instance has a body");
256 let p = body.find("p").expect("p is a member of m");
257 let cv = p
258 .initializer()
259 .expect("p has an initializer")
260 .constant_value()
261 .expect("p's initializer folds to a constant");
262 let fv = four_state_of_constant(&cv).expect("an integer constant yields Some");
263 match fv {
264 FourStateValue::Narrow(word) => {
265 let low_byte = (word & 0xFF) as u8;
266 assert_eq!(low_byte, 0xAA);
267 }
268 FourStateValue::Wide { .. } => panic!("expected Narrow for a 32-bit int constant"),
269 }
270 }
271
272 #[test]
279 fn owned_svint_to_four_state_round_trips_known_and_unknown_bits() {
280 let known = FourStateValue::Narrow(0xAAu128);
281 let v = four_state_to_owned_svint(&known, 8, false);
282 let back = owned_svint_to_four_state(&v).expect("a fully-known 8-bit value round-trips");
283 match back {
284 FourStateValue::Narrow(w) => {
285 assert_eq!(w as u64 & 0xFF, 0xAA);
286 assert_eq!((w >> 64) as u64 & 0xFF, 0, "no unknown bits expected");
287 }
288 FourStateValue::Wide { .. } => panic!("expected Narrow for an 8-bit value"),
289 }
290
291 let with_x = FourStateValue::Narrow(0b1000u128 | (0b0001u128 << 64));
294 let v2 = four_state_to_owned_svint(&with_x, 4, false);
295 let back2 =
296 owned_svint_to_four_state(&v2).expect("a partially-unknown 4-bit value round-trips");
297 match back2 {
298 FourStateValue::Narrow(w) => {
299 assert_eq!(
300 (w >> 64) as u64 & 0b1111,
301 0b0001,
302 "bit 0's unknown-ness must survive the round trip"
303 );
304 assert_eq!(
305 w as u64 & 0b1110,
306 0b1000,
307 "the known bits must survive the round trip"
308 );
309 }
310 FourStateValue::Wide { .. } => panic!("expected Narrow for a 4-bit value"),
311 }
312 }
313
314 #[test]
318 fn four_state_of_constant_reads_a_constant_wider_than_1024_bits() {
319 let design = compile_source(
320 "module m; localparam bit [1099:0] p = {1100{1'b1}};\n\
321 localparam bit [1099:0] q = {550{2'b10}}; endmodule\n",
322 )
323 .expect("valid SV source compiles");
324 let body = design
325 .top_instances()
326 .next()
327 .expect("one top instance")
328 .instance_body()
329 .expect("instance has a body");
330 let init = |name: &str| {
331 body.find(name)
332 .expect("a member of m")
333 .initializer()
334 .expect("an initializer")
335 };
336 let (p, q) = (init("p"), init("q"));
337 let pv = p.constant_value().expect("p folds");
338 assert_eq!(
339 format!("{:?}", four_state_of_constant(&pv)),
340 format!("{:?}", Some(bits_to_four_state(&[Bit::One; 1100]))),
341 );
342 let alternating: Vec<Bit> = (0..1100)
343 .map(|i| if i % 2 == 1 { Bit::One } else { Bit::Zero })
344 .collect();
345 assert_eq!(constant_expr_bits(&q), Some(alternating.clone()));
346 assert_eq!(
347 format!(
348 "{:?}",
349 four_state_of_constant(&q.constant_value().expect("q folds"))
350 ),
351 format!("{:?}", Some(bits_to_four_state(&alternating))),
352 );
353 }
354}