1use 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum ItemRef {
14 Group,
15 Coverpoint(usize),
17 Cross(usize),
19}
20
21const 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 pub type_name: String,
34 pub options: Options,
36 coverpoints: Vec<Coverpoint>,
37 crosses: Vec<Cross>,
38 cross_items: Vec<Vec<usize>>,
40 group_on: bool,
41 cp_on: Vec<bool>,
42 cross_on: Vec<bool>,
43 pub samples: u64,
45}
46
47impl CovInstance {
48 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 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 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 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 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 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 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 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 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 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 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 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 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}