1
// -*- mode: C++; c-file-style: "cc-mode" -*-
2
//=============================================================================
4
// Code available from: https://verilator.org
6
// Copyright 2001-2024 by Wilson Snyder. This program is free software; you
7
// can redistribute it and/or modify it under the terms of either the GNU
8
// Lesser General Public License Version 3 or the Perl Artistic License
10
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
12
//=============================================================================
15
/// \brief Verilated coverage analysis implementation code
17
/// This file must be compiled and linked against all Verilated objects
20
/// Use "verilator --coverage" to add this to the Makefile for the linker.
22
//=============================================================================
24
#include "verilatedos.h"
26
#include "verilated_cov.h"
29
#include "verilated_cov_key.h"
36
//=============================================================================
38
// Implementation constants
40
struct VerilatedCovConst VL_NOT_FINAL {
42
enum { MAX_KEYS = 33 }; // Maximum user arguments + filename+lineno
43
enum { KEY_UNDEF = 0 }; // Magic key # for unspecified values
46
//=============================================================================
48
// Implementation class for a VerilatedCov item
50
class VerilatedCovImpItem VL_NOT_FINAL {
51
public: // But only local to this file
53
int m_keys[VerilatedCovConst::MAX_KEYS]; // Key
54
int m_vals[VerilatedCovConst::MAX_KEYS]; // Value for specified key
56
// Derived classes should call zero() in their constructor
57
VerilatedCovImpItem() {
58
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
59
m_keys[i] = VerilatedCovConst::KEY_UNDEF;
63
virtual ~VerilatedCovImpItem() = default;
64
virtual uint64_t count() const = 0;
65
virtual void zero() const = 0;
68
//=============================================================================
69
// VerilatedCoverItem templated for a specific class
70
// Creates a new coverage item for the specified type.
71
// This isn't in the header file for auto-magic conversion because it
72
// inlines to too much code and makes compilation too slow.
75
class VerilatedCoverItemSpec final : public VerilatedCovImpItem {
78
T* m_countp; // Count value
81
// cppcheck-suppress truncLongCastReturn
82
uint64_t count() const override { return *m_countp; }
83
void zero() const override { *m_countp = 0; }
85
// cppcheck-suppress noExplicitConstructor
86
explicit VerilatedCoverItemSpec(T* countp)
90
~VerilatedCoverItemSpec() override = default;
93
//=============================================================================
96
// Implementation class for VerilatedCovContext. See that class for
97
// public method information. All value and keys are indexed into a
98
// unique number. Thus we can greatly reduce the storage requirements for
99
// otherwise identical keys.
101
class VerilatedCovImp final : public VerilatedCovContext {
104
using ValueIndexMap = std::map<const std::string, int>;
105
using IndexValueMap = std::map<int, std::string>;
106
using ItemList = std::deque<VerilatedCovImpItem*>;
109
VerilatedContext* const m_contextp; // Context VerilatedCovImp is pointed-to by
110
mutable VerilatedMutex m_mutex; // Protects all members
111
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); // Unique arbitrary value for values
112
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); // Unique arbitrary value for keys
113
ItemList m_items VL_GUARDED_BY(m_mutex); // List of all items
114
int m_nextIndex VL_GUARDED_BY(m_mutex)
115
= (VerilatedCovConst::KEY_UNDEF + 1); // Next insert value
117
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex) = nullptr; // Item about to insert
118
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex) = nullptr; // Filename about to insert
119
int m_insertLineno VL_GUARDED_BY(m_mutex) = 0; // Line number about to insert
120
bool m_forcePerInstance VL_GUARDED_BY(m_mutex) = false; // Force per_instance
124
explicit VerilatedCovImp(VerilatedContext* contextp)
125
: m_contextp{contextp} {}
126
VL_UNCOPYABLE(VerilatedCovImp);
129
friend class VerilatedCovContext;
130
~VerilatedCovImp() override { clearGuts(); }
134
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
135
const auto iter = m_valueIndexes.find(value);
136
if (iter != m_valueIndexes.end()) return iter->second;
138
assert(m_nextIndex > 0); // Didn't rollover
139
m_valueIndexes.emplace(value, m_nextIndex);
140
m_indexValues.emplace(m_nextIndex, value);
143
static std::string dequote(const std::string& text) VL_PURE {
144
// Quote any special characters
146
for (const char* pos = text.c_str(); *pos; ++pos) {
147
if (!std::isprint(*pos) || *pos == '%' || *pos == '"') {
148
constexpr size_t LEN_MAX_HEX = 20;
149
char hex[LEN_MAX_HEX];
150
VL_SNPRINTF(hex, LEN_MAX_HEX, "%%%02X", pos[0]);
158
static bool legalKey(const std::string& key) VL_PURE {
159
// Because we compress long keys to a single letter, and
160
// don't want applications to either get confused if they use
161
// a letter differently, nor want them to rely on our compression...
162
// (Considered using numeric keys, but will remain back compatible.)
163
if (key.length() < 2) return false;
164
if (key.length() == 2 && std::isdigit(key[1])) return false;
167
static std::string keyValueFormatter(const std::string& key,
168
const std::string& value) VL_PURE {
170
if (key.length() == 1 && std::isalpha(key[0])) {
171
name += "\001"s + key;
173
name += "\001"s + dequote(key);
175
name += "\002"s + dequote(value);
178
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
179
// (foo.a.x, foo.b.x) => foo.*.x
180
// (foo.a.x, foo.b.y) => foo.*
181
// (foo.a.x, foo.b) => foo.*
182
if (old == add) return add;
183
if (old.empty()) return add;
184
if (add.empty()) return old;
186
const char* const a = old.c_str();
187
const char* const b = add.c_str();
189
// Scan forward to first mismatch
190
const char* apre = a;
191
const char* bpre = b;
192
while (*apre == *bpre) {
197
// We used to backup and split on only .'s but it seems better to be verbose
198
// and not assume . is the separator
199
const size_t prefix_len = apre - a;
200
const std::string prefix = std::string{a, prefix_len};
202
// Scan backward to last mismatch
203
const char* apost = a + std::strlen(a) - 1;
204
const char* bpost = b + std::strlen(b) - 1;
205
while (*apost == *bpost && apost > apre && bpost > bpre) {
210
// Forward to . so we have a whole word
211
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
213
std::string result = prefix + "*" + suffix;
215
// std::cout << "\nch pre=" << prefix << " s=" << suffix << "\nch a="
216
// << old << "\nch b=" << add << "\ncho=" << result << "\n";
219
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
220
VL_REQUIRES(m_mutex) {
221
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
222
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
223
// We don't compare keys, only values
224
const std::string val = m_indexValues[itemp->m_vals[i]];
225
if (std::string::npos != val.find(match)) { // Found
232
static void selftest() VL_MT_SAFE {
234
#define SELF_CHECK(got, exp) \
236
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest"); \
238
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
239
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
240
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
241
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
242
SELF_CHECK(combineHier("z", "a"), "*");
243
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
244
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
245
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
248
void clearGuts() VL_REQUIRES(m_mutex) {
249
for (const auto& itemp : m_items) VL_DO_DANGLING(delete itemp, itemp);
251
m_indexValues.clear();
252
m_valueIndexes.clear();
253
m_nextIndex = VerilatedCovConst::KEY_UNDEF + 1;
258
std::string defaultFilename() VL_MT_SAFE { return m_contextp->coverageFilename(); }
259
void forcePerInstance(const bool flag) VL_MT_SAFE_EXCLUDES(m_mutex) {
260
Verilated::quiesce();
261
const VerilatedLockGuard lock{m_mutex};
262
m_forcePerInstance = flag;
264
void clear() VL_MT_SAFE_EXCLUDES(m_mutex) {
265
Verilated::quiesce();
266
const VerilatedLockGuard lock{m_mutex};
269
void clearNonMatch(const char* const matchp) VL_MT_SAFE_EXCLUDES(m_mutex) {
270
Verilated::quiesce();
271
const VerilatedLockGuard lock{m_mutex};
272
if (matchp && matchp[0]) {
274
for (const auto& itemp : m_items) {
275
if (!itemMatchesString(itemp, matchp)) {
276
VL_DO_DANGLING(delete itemp, itemp);
278
newlist.push_back(itemp);
284
void zero() VL_MT_SAFE_EXCLUDES(m_mutex) {
285
Verilated::quiesce();
286
const VerilatedLockGuard lock{m_mutex};
287
for (const auto& itemp : m_items) itemp->zero();
290
// We assume there's always call to i/f/p in that order
291
void inserti(VerilatedCovImpItem* itemp) VL_MT_SAFE_EXCLUDES(m_mutex) {
292
const VerilatedLockGuard lock{m_mutex};
296
void insertf(const char* const filenamep, const int lineno) VL_MT_SAFE_EXCLUDES(m_mutex) {
297
const VerilatedLockGuard lock{m_mutex};
298
m_insertFilenamep = filenamep;
299
m_insertLineno = lineno;
301
void insertp(const char* ckeyps[VerilatedCovConst::MAX_KEYS],
302
const char* valps[VerilatedCovConst::MAX_KEYS]) VL_MT_SAFE_EXCLUDES(m_mutex) {
303
const VerilatedLockGuard lock{m_mutex};
305
// First two key/vals are filename
306
ckeyps[0] = "filename";
307
valps[0] = m_insertFilenamep;
308
const std::string linestr = std::to_string(m_insertLineno);
309
ckeyps[1] = "lineno";
310
valps[1] = linestr.c_str();
311
// Default page if not specified
312
const char* fnstartp = m_insertFilenamep;
313
while (const char* foundp = std::strchr(fnstartp, '/')) fnstartp = foundp + 1;
314
const char* fnendp = fnstartp;
315
for (; *fnendp && *fnendp != '.'; fnendp++) {}
316
const size_t page_len = fnendp - fnstartp;
317
const std::string page_default = "sp_user/" + std::string{fnstartp, page_len};
319
valps[2] = page_default.c_str();
322
std::array<std::string, VerilatedCovConst::MAX_KEYS> keys;
323
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
324
if (ckeyps[i] && ckeyps[i][0]) keys[i] = ckeyps[i];
327
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
328
if (!keys[i].empty()) {
329
for (int j = i + 1; j < VerilatedCovConst::MAX_KEYS; ++j) {
330
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
339
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
340
const std::string key = keys[i];
341
if (!keys[i].empty()) {
342
const std::string val = valps[i];
343
// std::cout << " " << __FUNCTION__ << " " << key << " = " << val << "\n";
344
m_insertp->m_keys[addKeynum] = valueIndex(key);
345
m_insertp->m_vals[addKeynum] = valueIndex(val);
347
if (VL_UNCOVERABLE(!legalKey(key))) {
348
const std::string msg
349
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
350
+ key); // LCOV_EXCL_LINE
351
VL_FATAL_MT("", 0, "", msg.c_str());
355
m_items.push_back(m_insertp);
360
void write(const std::string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
361
Verilated::quiesce();
362
const VerilatedLockGuard lock{m_mutex};
365
std::ofstream os{filename};
367
const std::string msg = "%Error: Can't write '"s + filename + "'";
368
VL_FATAL_MT("", 0, "", msg.c_str());
371
os << "# SystemC::Coverage-3\n";
373
// Build list of events; totalize if collapsing hierarchy
374
std::map<const std::string, std::pair<std::string, uint64_t>> eventCounts;
375
for (const auto& itemp : m_items) {
378
bool per_instance = false;
379
if (m_forcePerInstance) per_instance = true;
381
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
382
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
383
const std::string key
384
= VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
385
const std::string val = m_indexValues[itemp->m_vals[i]];
386
if (key == VL_CIK_PER_INSTANCE) {
387
if (val != "0") per_instance = true;
389
if (key == VL_CIK_HIER) {
393
name += keyValueFormatter(key, val);
397
if (per_instance) { // Not collapsing hierarchies
398
name += keyValueFormatter(VL_CIK_HIER, hier);
402
// Group versus point labels don't matter here, downstream
403
// deals with it. Seems bad for sizing though and doesn't
404
// allow easy addition of new group codes (would be
407
// Find or insert the named event
408
const auto cit = eventCounts.find(name);
409
if (cit != eventCounts.end()) {
410
const std::string& oldhier = cit->second.first;
411
cit->second.second += itemp->count();
412
cit->second.first = combineHier(oldhier, hier);
414
eventCounts.emplace(name, std::make_pair(hier, itemp->count()));
419
for (const auto& i : eventCounts) {
420
os << "C '" << std::dec;
422
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
423
os << "' " << i.second.second;
429
//=============================================================================
430
// VerilatedCovContext
432
std::string VerilatedCovContext::defaultFilename() VL_MT_SAFE { return impp()->defaultFilename(); }
433
void VerilatedCovContext::forcePerInstance(bool flag) VL_MT_SAFE {
434
impp()->forcePerInstance(flag);
436
void VerilatedCovContext::clear() VL_MT_SAFE { impp()->clear(); }
437
void VerilatedCovContext::clearNonMatch(const char* matchp) VL_MT_SAFE {
438
impp()->clearNonMatch(matchp);
440
void VerilatedCovContext::zero() VL_MT_SAFE { impp()->zero(); }
441
void VerilatedCovContext::write(const std::string& filename) VL_MT_SAFE {
442
impp()->write(filename);
444
void VerilatedCovContext::_inserti(uint32_t* itemp) VL_MT_SAFE {
445
impp()->inserti(new VerilatedCoverItemSpec<uint32_t>{itemp});
447
void VerilatedCovContext::_inserti(uint64_t* itemp) VL_MT_SAFE {
448
impp()->inserti(new VerilatedCoverItemSpec<uint64_t>{itemp});
450
void VerilatedCovContext::_insertf(const char* filename, int lineno) VL_MT_SAFE {
451
impp()->insertf(filename, lineno);
455
#define K(n) const char* key##n
456
#define A(n) const char *key##n, const char *valp##n // Argument list
457
#define C(n) key##n, valp##n // Calling argument list
458
#define N(n) "", "" // Null argument list
459
void VerilatedCovContext::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9),
460
A(10), A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18),
461
A(19), A(20), A(21), A(22), A(23), A(24), A(25), A(26), A(27),
462
A(28), A(29)) VL_MT_SAFE {
463
const char* keyps[VerilatedCovConst::MAX_KEYS]
464
= {nullptr, nullptr, nullptr, // filename,lineno,page
465
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
466
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
467
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
468
const char* valps[VerilatedCovConst::MAX_KEYS]
469
= {nullptr, nullptr, nullptr, // filename,lineno,page
470
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
471
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
472
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
473
impp()->insertp(keyps, valps);
476
// And versions with fewer arguments (oh for a language with named parameters!)
477
void VerilatedCovContext::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8),
479
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), N(10), N(11), N(12),
480
N(13), N(14), N(15), N(16), N(17), N(18), N(19), N(20), N(21), N(22), N(23), N(24),
481
N(25), N(26), N(27), N(28), N(29));
483
void VerilatedCovContext::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9),
484
A(10), A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18),
486
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), C(11), C(12),
487
C(13), C(14), C(15), C(16), C(17), C(18), C(19), N(20), N(21), N(22), N(23), N(24),
488
N(25), N(26), N(27), N(28), N(29));
490
// Backward compatibility for Verilator
491
void VerilatedCovContext::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
492
const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
493
const std::string val2str = std::to_string(val2);
494
const std::string val3str = std::to_string(val3);
495
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
496
C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
497
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
506
//=============================================================================
510
VerilatedCovContext* VerilatedCov::threadCovp() VL_MT_SAFE {
511
return Verilated::threadContextp()->coveragep();
515
//=============================================================================
518
VerilatedCovContext* VerilatedContext::coveragep() VL_MT_SAFE {
519
static VerilatedMutex s_mutex;
520
// cppcheck-suppress identicalInnerCondition
521
if (VL_UNLIKELY(!m_coveragep)) {
522
const VerilatedLockGuard lock{s_mutex};
523
// cppcheck-suppress identicalInnerCondition
524
if (VL_LIKELY(!m_coveragep)) { // LCOV_EXCL_LINE // Not redundant, prevents race
525
m_coveragep.reset(new VerilatedCovImp{this});
528
return reinterpret_cast<VerilatedCovContext*>(m_coveragep.get());