Skip to main content

vj_sim/covergroup/
instance.rs

1//! One covergroup instance (IEEE 1800-2023 19.3): its coverpoints and crosses,
2//! instance options, sampling, `start` / `stop` and instance coverage.
3
4use super::compute::{Score, item_score, weighted_score};
5use super::coverpoint::{CovEvent, Coverpoint};
6use super::cross::Cross;
7use super::decl::CovGroupDecl;
8use super::options::{Level, Options, TypeOptions};
9use super::value::{CovError, Eval, Val};
10
11/// A covergroup or one of its coverage items.
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum ItemRef {
14    Group,
15    /// Index into the covergroup's coverpoints.
16    Coverpoint(usize),
17    /// Index into the covergroup's crosses.
18    Cross(usize),
19}
20
21/// Instance options that 19.7 lets only the covergroup definition set.
22const DEFINITION_ONLY: [&str; 5] = [
23    "per_instance",
24    "get_inst_coverage",
25    "auto_bin_max",
26    "detect_overlap",
27    "cross_retain_auto_bins",
28];
29
30#[derive(Debug)]
31pub struct CovInstance {
32    /// The covergroup type's name.
33    pub type_name: String,
34    /// `option.*` of the covergroup (including `name`, `set_inst_name`).
35    pub options: Options,
36    coverpoints: Vec<Coverpoint>,
37    crosses: Vec<Cross>,
38    /// For each cross, the indices of its coverpoints in item order.
39    cross_items: Vec<Vec<usize>>,
40    group_on: bool,
41    cp_on: Vec<bool>,
42    cross_on: Vec<bool>,
43    /// Sample events this instance took part in (not stopped).
44    pub samples: u64,
45}
46
47impl CovInstance {
48    /// Instantiates `decl` with constructor arguments `ctor`; `topts` are the
49    /// covergroup's type options in effect, `auto_name` the name used when
50    /// the covergroup does not assign `option.name` (19.7: "unique name").
51    /// Returns the instance and the warnings the bins raised.
52    pub fn new(
53        decl: &CovGroupDecl,
54        topts: &TypeOptions,
55        auto_name: String,
56        ev: &mut dyn Eval,
57        ctor: &[Val],
58    ) -> Result<(CovInstance, Vec<String>), CovError> {
59        let mut options = Options::default();
60        for (n, e) in &decl.options {
61            let v = e.eval(ev, ctor)?;
62            options.set(Level::Covergroup, n, &v)?;
63        }
64        if options.name.is_empty() {
65            options.name = auto_name;
66        }
67        let mut warnings = Vec::new();
68        let mut coverpoints: Vec<Coverpoint> = Vec::with_capacity(decl.coverpoints.len());
69        for d in &decl.coverpoints {
70            let (cp, w) = Coverpoint::new(d, &options, topts, ev, ctor)?;
71            warnings.extend(w);
72            coverpoints.push(cp);
73        }
74        let mut crosses = Vec::with_capacity(decl.crosses.len());
75        let mut cross_items = Vec::with_capacity(decl.crosses.len());
76        for d in &decl.crosses {
77            let mut idx = Vec::with_capacity(d.items.len());
78            for item in &d.items {
79                let i = coverpoints
80                    .iter()
81                    .position(|c| &c.name == item)
82                    .ok_or_else(|| CovError::CrossSelect {
83                        cross: d.name.clone(),
84                        detail: format!(
85                            "item {item} is not a coverpoint of covergroup {}",
86                            decl.name
87                        ),
88                    })?;
89                idx.push(i);
90            }
91            let refs: Vec<&Coverpoint> = idx.iter().map(|&i| &coverpoints[i]).collect();
92            let (x, w) = Cross::new(d, &refs, &options, topts, ev, ctor)?;
93            warnings.extend(w);
94            crosses.push(x);
95            cross_items.push(idx);
96        }
97        Ok((
98            CovInstance {
99                type_name: decl.name.clone(),
100                options,
101                cp_on: vec![true; coverpoints.len()],
102                cross_on: vec![true; crosses.len()],
103                coverpoints,
104                crosses,
105                cross_items,
106                group_on: true,
107                samples: 0,
108            },
109            warnings,
110        ))
111    }
112
113    pub fn name(&self) -> &str {
114        &self.options.name
115    }
116
117    /// `set_inst_name(name)` (19.8).
118    pub fn set_inst_name(&mut self, name: &str) {
119        self.options.name = name.to_string();
120    }
121
122    pub fn coverpoints(&self) -> &[Coverpoint] {
123        &self.coverpoints
124    }
125
126    pub fn crosses(&self) -> &[Cross] {
127        &self.crosses
128    }
129
130    pub fn coverpoint(&self, name: &str) -> Option<&Coverpoint> {
131        self.coverpoints.iter().find(|c| c.name == name)
132    }
133
134    pub fn cross(&self, name: &str) -> Option<&Cross> {
135        self.crosses.iter().find(|c| c.name == name)
136    }
137
138    /// The reference to the coverpoint or cross called `name`.
139    pub fn find_item(&self, name: &str) -> Option<ItemRef> {
140        if let Some(i) = self.coverpoints.iter().position(|c| c.name == name) {
141            return Some(ItemRef::Coverpoint(i));
142        }
143        self.crosses
144            .iter()
145            .position(|c| c.name == name)
146            .map(ItemRef::Cross)
147    }
148
149    fn check(&self, item: ItemRef) -> Result<(), CovError> {
150        let ok = match item {
151            ItemRef::Group => true,
152            ItemRef::Coverpoint(i) => i < self.coverpoints.len(),
153            ItemRef::Cross(i) => i < self.crosses.len(),
154        };
155        if ok {
156            Ok(())
157        } else {
158            Err(CovError::UnknownItem {
159                group: self.type_name.clone(),
160                item: format!("{item:?}"),
161            })
162        }
163    }
164
165    /// Whether the item is collecting (the covergroup must be started too).
166    pub fn is_started(&self, item: ItemRef) -> Result<bool, CovError> {
167        self.check(item)?;
168        Ok(match item {
169            ItemRef::Group => self.group_on,
170            ItemRef::Coverpoint(i) => self.cp_on[i],
171            ItemRef::Cross(i) => self.cross_on[i],
172        })
173    }
174
175    /// `start()` (19.8): collection resumes. The covergroup's own switch is
176    /// independent of its items': starting the group does not start a coverpoint
177    /// that was stopped on its own.
178    pub fn start(&mut self, item: ItemRef) -> Result<(), CovError> {
179        self.check(item)?;
180        match item {
181            ItemRef::Group => self.group_on = true,
182            ItemRef::Coverpoint(i) => self.cp_on[i] = true,
183            ItemRef::Cross(i) => self.cross_on[i] = true,
184        }
185        Ok(())
186    }
187
188    /// `stop()` (19.8): later samples do not count. Sequences in flight are
189    /// dropped (the gap breaks consecutiveness, see [`Coverpoint::skip`]).
190    pub fn stop(&mut self, item: ItemRef) -> Result<(), CovError> {
191        self.check(item)?;
192        match item {
193            ItemRef::Group => {
194                self.group_on = false;
195                self.coverpoints.iter_mut().for_each(Coverpoint::skip);
196            }
197            ItemRef::Coverpoint(i) => {
198                self.cp_on[i] = false;
199                self.coverpoints[i].skip();
200            }
201            ItemRef::Cross(i) => self.cross_on[i] = false,
202        }
203        Ok(())
204    }
205
206    /// One sampling event with the `sample()` arguments `sargs` (19.3, 19.8).
207    pub fn sample(&mut self, ev: &mut dyn Eval, sargs: &[Val]) -> Result<Vec<CovEvent>, CovError> {
208        if !self.group_on {
209            return Ok(Vec::new());
210        }
211        self.samples += 1;
212        let mut events = Vec::new();
213        for (cp, on) in self.coverpoints.iter_mut().zip(&self.cp_on) {
214            if *on {
215                events.extend(cp.sample(ev, sargs)?);
216            } else {
217                cp.skip();
218            }
219        }
220        for ((x, on), idx) in self
221            .crosses
222            .iter_mut()
223            .zip(&self.cross_on)
224            .zip(&self.cross_items)
225        {
226            if *on {
227                let cps: Vec<&Coverpoint> = idx.iter().map(|&i| &self.coverpoints[i]).collect();
228                events.extend(x.sample(&cps, ev, sargs)?);
229            }
230        }
231        Ok(events)
232    }
233
234    /// `option.<name> = v` executed procedurally (19.7). The options only the
235    /// definition may set are refused.
236    pub fn set_option(&mut self, item: ItemRef, name: &str, v: &Val) -> Result<(), CovError> {
237        self.check(item)?;
238        let (opts, level) = match item {
239            ItemRef::Group => (&mut self.options, Level::Covergroup),
240            ItemRef::Coverpoint(i) => (&mut self.coverpoints[i].options, Level::Coverpoint),
241            ItemRef::Cross(i) => (&mut self.crosses[i].options, Level::Cross),
242        };
243        let mut next = opts.clone();
244        next.set(level, name, v)?;
245        if DEFINITION_ONLY.contains(&name) {
246            return Err(CovError::DefinitionOnlyOption {
247                option: name.to_string(),
248            });
249        }
250        *opts = next;
251        Ok(())
252    }
253
254    /// `option.<name>` read back.
255    pub fn get_option(&self, item: ItemRef, name: &str) -> Result<Val, CovError> {
256        self.check(item)?;
257        match item {
258            ItemRef::Group => self.options.get(Level::Covergroup, name),
259            ItemRef::Coverpoint(i) => self.coverpoints[i].options.get(Level::Coverpoint, name),
260            ItemRef::Cross(i) => self.crosses[i].options.get(Level::Cross, name),
261        }
262    }
263
264    /// The `option.weight` of an item of this instance.
265    pub fn weight(&self, item: ItemRef) -> Result<i64, CovError> {
266        self.check(item)?;
267        Ok(match item {
268            ItemRef::Group => self.options.weight,
269            ItemRef::Coverpoint(i) => self.coverpoints[i].options.weight,
270            ItemRef::Cross(i) => self.crosses[i].options.weight,
271        })
272    }
273
274    /// The `option.at_least` of an item (the covergroup's own is only the
275    /// default its items started with).
276    pub fn at_least(&self, item: ItemRef) -> Result<u64, CovError> {
277        self.check(item)?;
278        Ok(match item {
279            ItemRef::Group => self.options.at_least,
280            ItemRef::Coverpoint(i) => self.coverpoints[i].options.at_least,
281            ItemRef::Cross(i) => self.crosses[i].options.at_least,
282        })
283    }
284
285    /// The bins an item's coverage is measured over, with hit counts.
286    pub fn item_bins(&self, item: ItemRef) -> Result<Vec<(String, u64)>, CovError> {
287        self.check(item)?;
288        match item {
289            ItemRef::Group => Err(CovError::Unsupported(
290                "a covergroup has coverpoints and crosses, not bins".to_string(),
291            )),
292            ItemRef::Coverpoint(i) => Ok(self.coverpoints[i].coverage_bins()),
293            ItemRef::Cross(i) => Ok(self.crosses[i].coverage_bins()),
294        }
295    }
296
297    /// `get_inst_coverage()` of this instance's own bins (19.11.1-19.11.2,
298    /// the weighted average of 19.11 for the group). 19.11.3's exception for
299    /// `merge_instances` is applied by the caller that knows the type.
300    pub fn own_score(&self, item: ItemRef) -> Result<Score, CovError> {
301        self.check(item)?;
302        Ok(match item {
303            ItemRef::Group => {
304                let mut parts = Vec::new();
305                for (i, c) in self.coverpoints.iter().enumerate() {
306                    parts.push((c.options.weight, self.own_score(ItemRef::Coverpoint(i))?));
307                }
308                for (i, x) in self.crosses.iter().enumerate() {
309                    parts.push((x.options.weight, self.own_score(ItemRef::Cross(i))?));
310                }
311                weighted_score(self.options.weight, &parts)
312            }
313            ItemRef::Coverpoint(i) => {
314                let c = &self.coverpoints[i];
315                item_score(c.options.weight, c.coverage())
316            }
317            ItemRef::Cross(i) => {
318                let x = &self.crosses[i];
319                item_score(x.options.weight, x.coverage())
320            }
321        })
322    }
323}