1use std::collections::{HashMap, VecDeque};
5
6use super::bins::{Bin, Matcher, build_bins, fmt_real};
7use super::decl::{BinKind, CoverpointDecl};
8use super::options::{Level, Options, TypeOptions};
9use super::value::{CovError, Eval, Expr, TypeInfo, Val};
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14pub struct Coverage {
15 pub covered: u64,
16 pub total: u64,
17}
18
19impl Coverage {
20 pub fn percent(&self) -> Option<f64> {
23 (self.total != 0).then(|| 100.0 * self.covered as f64 / self.total as f64)
24 }
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
29pub enum CovEvent {
30 IllegalBin {
32 coverpoint: String,
33 bin: String,
34 value: String,
35 },
36}
37
38#[derive(Debug)]
39pub struct Coverpoint {
40 pub name: String,
41 pub ty: TypeInfo,
42 pub options: Options,
43 pub type_options: TypeOptions,
44 expr: Expr,
45 iff: Option<Expr>,
46 ctor: Vec<Val>,
47 pub bins: Vec<Bin>,
48 singles: HashMap<i128, Vec<usize>>,
50 multi: Vec<usize>,
52 trans: Vec<usize>,
54 default_seqs: Vec<usize>,
56 has_prev: bool,
58 recent: VecDeque<i128>,
60 recent_cap: usize,
61 pub samples: u64,
63 last_sampled: bool,
66 last_hits: Vec<usize>,
70}
71
72#[derive(Clone, Copy)]
74enum Sample {
75 Int(i128),
76 Real(f64),
77}
78
79pub(super) fn truthy(v: Val, what: &str) -> Result<bool, CovError> {
80 match v {
81 Val::Int(i) => Ok(i != 0),
82 Val::Real(r) => Ok(r != 0.0),
83 Val::Unknown | Val::Pat { .. } => Ok(false),
85 other => Err(CovError::BadValue {
86 ctx: what.to_string(),
87 got: format!("{other:?}"),
88 }),
89 }
90}
91
92impl Coverpoint {
93 pub fn new(
97 decl: &CoverpointDecl,
98 cg_opts: &Options,
99 cg_topts: &TypeOptions,
100 ev: &mut dyn Eval,
101 ctor: &[Val],
102 ) -> Result<(Coverpoint, Vec<String>), CovError> {
103 let mut options = cg_opts.inherit();
104 for (n, e) in &decl.options {
105 let v = e.eval(ev, ctor)?;
106 options.set(Level::Coverpoint, n, &v)?;
107 }
108 let mut type_options = cg_topts.inherit();
109 type_options.distribute_first = cg_topts.distribute_first;
113 for (n, e) in &decl.type_options {
114 let v = e.eval(ev, ctor)?;
115 type_options.set(Level::Coverpoint, n, &v)?;
116 }
117 let (bins, warnings) = build_bins(decl, &options, &type_options, ev, ctor)?;
118 let mut singles: HashMap<i128, Vec<usize>> = HashMap::new();
119 let mut multi = Vec::new();
120 let mut trans = Vec::new();
121 let mut default_seqs = Vec::new();
122 let mut recent_cap = 0usize;
123 for (i, b) in bins.iter().enumerate() {
124 match &b.matcher {
125 Matcher::Default => {}
126 Matcher::Trans(t) => {
127 trans.push(i);
128 if b.kind == BinKind::Illegal {
129 recent_cap = recent_cap.max(t.max_len);
130 }
131 }
132 Matcher::DefaultSeq => {
133 default_seqs.push(i);
134 if b.kind == BinKind::Illegal {
135 recent_cap = recent_cap.max(2);
136 }
137 }
138 Matcher::Ints(s) if s.is_empty() => {}
139 Matcher::Ints(s) if s.count() == 1 => {
140 singles.entry(s.intervals()[0].0).or_default().push(i)
141 }
142 _ => multi.push(i),
143 }
144 }
145 Ok((
146 Coverpoint {
147 name: decl.name.clone(),
148 ty: decl.ty,
149 options,
150 type_options,
151 expr: decl.expr.clone(),
152 iff: decl.iff.clone(),
153 ctor: ctor.to_vec(),
154 bins,
155 singles,
156 multi,
157 trans,
158 default_seqs,
159 has_prev: false,
160 recent: VecDeque::new(),
161 recent_cap,
162 samples: 0,
163 last_sampled: false,
164 last_hits: Vec::new(),
165 },
166 warnings,
167 ))
168 }
169
170 fn args(&self, sargs: &[Val]) -> Vec<Val> {
171 let mut a = self.ctor.clone();
172 a.extend_from_slice(sargs);
173 a
174 }
175
176 pub fn sample(&mut self, ev: &mut dyn Eval, sargs: &[Val]) -> Result<Vec<CovEvent>, CovError> {
179 self.last_sampled = false;
180 self.last_hits.clear();
181 let args = self.args(sargs);
182 if let Some(iff) = &self.iff
183 && !truthy(iff.eval(ev, &args)?, "coverpoint iff")?
184 {
185 return Ok(Vec::new());
186 }
187 let v = self.expr.eval(ev, &args)?;
188 self.sample_value(&v, ev, sargs)
189 }
190
191 pub fn sample_value(
193 &mut self,
194 v: &Val,
195 ev: &mut dyn Eval,
196 sargs: &[Val],
197 ) -> Result<Vec<CovEvent>, CovError> {
198 self.last_sampled = false;
199 self.last_hits.clear();
200 self.samples += 1;
201 let s = match (v, self.ty.real) {
202 (Val::Unknown | Val::Pat { .. }, _) => {
205 self.break_trans();
206 return Ok(Vec::new());
207 }
208 (Val::Int(i), false) => Sample::Int(self.ty.value_of(self.ty.bits_of(*i))),
209 (Val::Int(i), true) => Sample::Real(*i as f64),
210 (Val::Real(r), true) => Sample::Real(*r),
211 (other, _) => {
212 return Err(CovError::BadValue {
213 ctx: format!("coverpoint {} sample", self.name),
214 got: format!("{other:?}"),
215 });
216 }
217 };
218 let args = self.args(sargs);
219 self.last_sampled = true;
220 let mut events = self.count_value(s, ev, &args)?;
221 if let Sample::Int(i) = s {
222 events.extend(self.step_trans(i, ev, &args)?);
223 }
224 self.last_hits.sort_unstable();
225 Ok(events)
226 }
227
228 pub fn last_sampled(&self) -> bool {
230 self.last_sampled
231 }
232
233 pub fn last_hits(&self) -> &[usize] {
235 &self.last_hits
236 }
237
238 pub fn cross_bins(&self) -> Vec<usize> {
243 self.bins
244 .iter()
245 .enumerate()
246 .filter(|(_, b)| {
247 b.kind == BinKind::Normal && !b.is_default() && !b.is_default_seq() && !b.empty
248 })
249 .map(|(i, _)| i)
250 .collect()
251 }
252
253 fn break_trans(&mut self) {
255 self.has_prev = false;
256 self.recent.clear();
257 for &i in &self.trans {
258 if let Matcher::Trans(t) = &mut self.bins[i].matcher {
259 t.clear();
260 }
261 }
262 }
263
264 fn step_trans(
266 &mut self,
267 v: i128,
268 ev: &mut dyn Eval,
269 args: &[Val],
270 ) -> Result<Vec<CovEvent>, CovError> {
271 let mut events = Vec::new();
272 if self.trans.is_empty() && self.default_seqs.is_empty() {
273 return Ok(events);
274 }
275 if self.recent_cap > 0 {
276 self.recent.push_back(v);
277 while self.recent.len() > self.recent_cap {
278 self.recent.pop_front();
279 }
280 }
281 let mut matched = Vec::new();
282 let mut pending = false;
283 for k in 0..self.trans.len() {
284 let i = self.trans[k];
285 let Matcher::Trans(t) = &mut self.bins[i].matcher else {
286 unreachable!("trans lists only transition bins");
287 };
288 let st = t.step(v);
289 pending |= st.pending;
290 if st.matched {
291 matched.push(i);
292 }
293 }
294 let default_hit = self.has_prev && matched.is_empty() && !pending;
297 self.has_prev = true;
298 let text = self
299 .recent
300 .iter()
301 .map(|v| v.to_string())
302 .collect::<Vec<_>>();
303 let text = text.join("=>");
304 let mut hit: Vec<usize> = matched;
305 if default_hit {
306 hit.extend(self.default_seqs.iter().copied());
307 }
308 for i in hit {
309 if !self.bin_iff(i, ev, args)? {
310 continue;
311 }
312 let bin = &mut self.bins[i];
313 match bin.kind {
314 BinKind::Ignore => {}
316 BinKind::Normal => {
317 bin.hits = bin.hits.saturating_add(1);
318 if !bin.is_default_seq() {
320 self.last_hits.push(i);
321 }
322 }
323 BinKind::Illegal => {
324 bin.hits = bin.hits.saturating_add(1);
325 events.push(CovEvent::IllegalBin {
326 coverpoint: self.name.clone(),
327 bin: bin.name.clone(),
328 value: text.clone(),
329 });
330 }
331 }
332 }
333 Ok(events)
334 }
335
336 fn count_value(
338 &mut self,
339 s: Sample,
340 ev: &mut dyn Eval,
341 args: &[Val],
342 ) -> Result<Vec<CovEvent>, CovError> {
343 let matched = self.matching(s);
344 let text = match s {
345 Sample::Int(i) => i.to_string(),
346 Sample::Real(r) => fmt_real(r),
347 };
348 let mut events = Vec::new();
349
350 let mut excluded = false;
352 for &i in &matched {
353 if self.bins[i].kind != BinKind::Illegal {
354 continue;
355 }
356 excluded = true;
357 if self.bin_iff(i, ev, args)? {
358 self.bins[i].hits = self.bins[i].hits.saturating_add(1);
359 events.push(CovEvent::IllegalBin {
360 coverpoint: self.name.clone(),
361 bin: self.bins[i].name.clone(),
362 value: text.clone(),
363 });
364 }
365 }
366 excluded |= matched
368 .iter()
369 .any(|&i| self.bins[i].kind == BinKind::Ignore);
370 if excluded {
371 return Ok(events);
372 }
373
374 for &i in &matched {
375 if self.bin_iff(i, ev, args)? {
376 self.bins[i].hits = self.bins[i].hits.saturating_add(1);
377 self.last_hits.push(i);
378 }
379 }
380 if matched.is_empty() {
382 for i in 0..self.bins.len() {
383 if !self.bins[i].is_default() || !self.bin_iff(i, ev, args)? {
384 continue;
385 }
386 let bin = &mut self.bins[i];
387 bin.hits = bin.hits.saturating_add(1);
388 if bin.default_array
389 && let Sample::Int(v) = s
390 {
391 let c = bin.default_values.entry(v).or_insert(0);
392 *c = c.saturating_add(1);
393 }
394 if bin.kind == BinKind::Illegal {
395 events.push(CovEvent::IllegalBin {
396 coverpoint: self.name.clone(),
397 bin: bin.name.clone(),
398 value: text.clone(),
399 });
400 }
401 }
402 }
403 Ok(events)
404 }
405
406 fn bin_iff(&self, i: usize, ev: &mut dyn Eval, args: &[Val]) -> Result<bool, CovError> {
407 match &self.bins[i].iff {
408 None => Ok(true),
409 Some(e) => truthy(e.eval(ev, args)?, "bin iff"),
410 }
411 }
412
413 fn matching(&self, s: Sample) -> Vec<usize> {
415 let mut out = Vec::new();
416 match s {
417 Sample::Int(v) => {
418 if let Some(ix) = self.singles.get(&v) {
419 out.extend(ix.iter().copied());
420 }
421 for &i in &self.multi {
422 let hit = match &self.bins[i].matcher {
423 Matcher::Ints(set) => set.contains(v),
424 Matcher::Pats(pats) => {
425 let bits = self.ty.bits_of(v);
426 pats.iter().any(|&(pb, care)| (bits ^ pb) & care == 0)
427 }
428 Matcher::Reals(_)
429 | Matcher::Default
430 | Matcher::Trans(_)
431 | Matcher::DefaultSeq => false,
432 };
433 if hit {
434 out.push(i);
435 }
436 }
437 }
438 Sample::Real(r) => {
439 for &i in &self.multi {
440 if let Matcher::Reals(items) = &self.bins[i].matcher
441 && items.iter().any(|it| it.contains(r))
442 {
443 out.push(i);
444 }
445 }
446 }
447 }
448 out.sort_unstable();
449 out
450 }
451
452 pub fn coverage(&self) -> Coverage {
456 let mut c = Coverage::default();
457 for b in &self.bins {
458 if b.kind != BinKind::Normal || b.is_default() || b.is_default_seq() || b.empty {
459 continue;
460 }
461 c.total += 1;
462 if b.hits >= self.options.at_least {
463 c.covered += 1;
464 }
465 }
466 c
467 }
468
469 pub fn coverage_bins(&self) -> Vec<(String, u64)> {
473 self.bins
474 .iter()
475 .filter(|b| {
476 b.kind == BinKind::Normal && !b.is_default() && !b.is_default_seq() && !b.empty
477 })
478 .map(|b| (b.name.clone(), b.hits))
479 .collect()
480 }
481
482 pub fn skip(&mut self) {
486 self.last_sampled = false;
487 self.last_hits.clear();
488 self.break_trans();
489 }
490
491 pub fn hits(&self, name: &str) -> Option<u64> {
493 self.bins.iter().find(|b| b.name == name).map(|b| b.hits)
494 }
495
496 pub fn reset(&mut self) {
499 self.samples = 0;
500 self.last_sampled = false;
501 self.last_hits.clear();
502 self.break_trans();
503 for b in &mut self.bins {
504 b.hits = 0;
505 b.default_values.clear();
506 }
507 }
508}