Merge b3aaedf7d6
into 98b8d43a4a
This commit is contained in:
commit
d0d240f8bd
|
@ -75,6 +75,58 @@ class VerilatedCovImp;
|
|||
ccontextp->_insertp("hier", name, __VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_ST_I(const int width, uint32_t* covp, const IData newData,
|
||||
const IData oldData) {
|
||||
for (int i = 0; i < width; ++i) *(covp + i) += ((newData ^ oldData) >> i) & 1;
|
||||
}
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_ST_Q(const int width, uint32_t* covp, const IData newData,
|
||||
const IData oldData) {
|
||||
for (int i = 0; i < width; ++i) *(covp + i) += ((newData ^ oldData) >> i) & 1;
|
||||
}
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_ST_W(const int width, uint32_t* covp, WDataInP newData,
|
||||
WDataInP oldData) {
|
||||
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
||||
const EData changed = newData[i] ^ oldData[i];
|
||||
if (changed) {
|
||||
for (int j = 0; j < width - i * 32; ++j) *(covp + i * 32 + j) += (changed >> j) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_MT_I(const int width, std::atomic<uint32_t>* covp,
|
||||
const IData newData, const IData oldData) VL_MT_SAFE {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (VL_BITISSET_I((newData ^ oldData), i)) {
|
||||
(covp + i)->fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_MT_Q(const int width, std::atomic<uint32_t>* covp,
|
||||
const IData newData, const IData oldData) VL_MT_SAFE {
|
||||
for (int i = 0; i < width; ++i) {
|
||||
if (VL_BITISSET_Q((newData ^ oldData), i)) {
|
||||
(covp + i)->fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_COV_TOGGLE_CHG_MT_W(const int width, std::atomic<uint32_t>* covp,
|
||||
WDataInP newData, WDataInP oldData) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(width); ++i) {
|
||||
const EData changed = newData[i] ^ oldData[i];
|
||||
if (changed) {
|
||||
for (int j = 0; j < width - i * 32; ++j) {
|
||||
if (VL_BITISSET_E(changed, j)) {
|
||||
(covp + i * 32 + j)->fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCov
|
||||
/// Per-VerilatedContext coverage data class.
|
||||
|
|
|
@ -399,6 +399,52 @@ public:
|
|||
ASTGEN_MEMBERS_AstNodeCase;
|
||||
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||
};
|
||||
class AstNodeCoverDecl VL_NOT_FINAL : public AstNodeStmt {
|
||||
// Coverage analysis point declaration
|
||||
//
|
||||
// [After V3CoverageJoin] Duplicate declaration to get data from instead
|
||||
// @astgen ptr := m_dataDeclp : Optional[AstNodeCoverDecl]
|
||||
string m_page; // Coverage point's page tag
|
||||
string m_text; // Coverage point's text
|
||||
string m_hier; // Coverage point's hierarchy
|
||||
int m_binNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||
public:
|
||||
AstNodeCoverDecl(VNType t, FileLine* fl, const string& page, const string& comment)
|
||||
: AstNodeStmt(t, fl)
|
||||
, m_page{page}
|
||||
, m_text{comment} {}
|
||||
ASTGEN_MEMBERS_AstNodeCoverDecl;
|
||||
const char* broken() const override {
|
||||
if (m_dataDeclp
|
||||
&& (m_dataDeclp == this || m_dataDeclp->m_dataDeclp)) { // Avoid O(n^2) accessing
|
||||
v3fatalSrc("dataDeclp should point to real data, not be a list: " << cvtToHex(this));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
int binNum() const { return m_binNum; }
|
||||
void binNum(int flag) { m_binNum = flag; }
|
||||
virtual int size() const = 0;
|
||||
const string& comment() const { return m_text; } // text to insert in code
|
||||
const string& page() const { return m_page; }
|
||||
const string& hier() const { return m_hier; }
|
||||
void hier(const string& flag) { m_hier = flag; }
|
||||
void comment(const string& flag) { m_text = flag; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
const AstNodeCoverDecl* const asamep = VN_DBG_AS(samep, NodeCoverDecl);
|
||||
return (fileline() == asamep->fileline() && hier() == asamep->hier()
|
||||
&& comment() == asamep->comment() && page() == asamep->page());
|
||||
}
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
void dataDeclp(AstNodeCoverDecl* nodep) { m_dataDeclp = nodep; }
|
||||
// dataDecl nullptr means "use this one", but often you want "this" to
|
||||
// indicate to get data from here
|
||||
AstNodeCoverDecl* dataDeclNullp() const { return m_dataDeclp; }
|
||||
AstNodeCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; }
|
||||
};
|
||||
class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt {
|
||||
// Cover or Assert
|
||||
// Parents: {statement list}
|
||||
|
@ -2978,64 +3024,15 @@ public:
|
|||
return true; // SPECIAL: We don't process code after breaks
|
||||
}
|
||||
};
|
||||
class AstCoverDecl final : public AstNodeStmt {
|
||||
// Coverage analysis point declaration
|
||||
//
|
||||
// [After V3CoverageJoin] Duplicate declaration to get data from instead
|
||||
// @astgen ptr := m_dataDeclp : Optional[AstCoverDecl]
|
||||
string m_page;
|
||||
string m_text;
|
||||
string m_hier;
|
||||
string m_linescov;
|
||||
int m_offset; // Offset column numbers to uniq-ify IFs
|
||||
int m_binNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||
public:
|
||||
AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov,
|
||||
int offset)
|
||||
: ASTGEN_SUPER_CoverDecl(fl)
|
||||
, m_page{page}
|
||||
, m_text{comment}
|
||||
, m_linescov{linescov}
|
||||
, m_offset{offset} {}
|
||||
ASTGEN_MEMBERS_AstCoverDecl;
|
||||
const char* broken() const override {
|
||||
if (m_dataDeclp
|
||||
&& (m_dataDeclp == this || m_dataDeclp->m_dataDeclp)) { // Avoid O(n^2) accessing
|
||||
v3fatalSrc("dataDeclp should point to real data, not be a list: " << cvtToHex(this));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
int binNum() const { return m_binNum; }
|
||||
void binNum(int flag) { m_binNum = flag; }
|
||||
int offset() const { return m_offset; }
|
||||
const string& comment() const { return m_text; } // text to insert in code
|
||||
const string& linescov() const { return m_linescov; }
|
||||
const string& page() const { return m_page; }
|
||||
const string& hier() const { return m_hier; }
|
||||
void hier(const string& flag) { m_hier = flag; }
|
||||
void comment(const string& flag) { m_text = flag; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl);
|
||||
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
|
||||
&& hier() == asamep->hier() && comment() == asamep->comment());
|
||||
}
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
|
||||
// dataDecl nullptr means "use this one", but often you want "this" to
|
||||
// indicate to get data from here
|
||||
AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; }
|
||||
AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; }
|
||||
};
|
||||
class AstCoverInc final : public AstNodeStmt {
|
||||
// Coverage analysis point; increment coverage count
|
||||
// @astgen op1 := toggleExprp : Optional[AstNodeExpr] // [After V3Clock]
|
||||
// @astgen op2 := toggleCovExprp : Optional[AstNodeExpr] // [After V3Clock]
|
||||
// These are expressions to which the node corresponds. Used only in toggle coverage
|
||||
//
|
||||
// @astgen ptr := m_declp : AstCoverDecl // [After V3CoverageJoin] Declaration
|
||||
// @astgen ptr := m_declp : AstNodeCoverDecl // [After V3CoverageJoin] Declaration
|
||||
public:
|
||||
AstCoverInc(FileLine* fl, AstCoverDecl* declp)
|
||||
AstCoverInc(FileLine* fl, AstNodeCoverDecl* declp)
|
||||
: ASTGEN_SUPER_CoverInc(fl)
|
||||
, m_declp{declp} {}
|
||||
ASTGEN_MEMBERS_AstCoverInc;
|
||||
|
@ -3049,7 +3046,7 @@ public:
|
|||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
AstCoverDecl* declp() const { return m_declp; } // Where defined
|
||||
AstNodeCoverDecl* declp() const { return m_declp; } // Where defined
|
||||
};
|
||||
class AstCoverToggle final : public AstNodeStmt {
|
||||
// Toggle analysis of given signal
|
||||
|
@ -3912,6 +3909,47 @@ public:
|
|||
: ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {}
|
||||
ASTGEN_MEMBERS_AstGenCase;
|
||||
};
|
||||
class AstCoverOtherDecl final : public AstNodeCoverDecl {
|
||||
// Coverage analysis point declaration
|
||||
// Used for other than toggle types of coverage
|
||||
string m_linescov;
|
||||
int m_offset; // Offset column numbers to uniq-ify IFs
|
||||
public:
|
||||
AstCoverOtherDecl(FileLine* fl, const string& page, const string& comment,
|
||||
const string& linescov, int offset)
|
||||
: ASTGEN_SUPER_CoverOtherDecl(fl, page, comment)
|
||||
, m_linescov{linescov}
|
||||
, m_offset{offset} {}
|
||||
ASTGEN_MEMBERS_AstCoverOtherDecl;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int offset() const { return m_offset; }
|
||||
int size() const override { return 1; }
|
||||
const string& linescov() const { return m_linescov; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
const AstCoverOtherDecl* const asamep = VN_DBG_AS(samep, CoverOtherDecl);
|
||||
return AstNodeCoverDecl::sameNode(samep) && linescov() == asamep->linescov();
|
||||
}
|
||||
};
|
||||
class AstCoverToggleDecl final : public AstNodeCoverDecl {
|
||||
// Coverage analysis point declaration
|
||||
// Used for toggle coverage
|
||||
const VNumRange m_range; // Packed array range covering each toggle bit
|
||||
public:
|
||||
AstCoverToggleDecl(FileLine* fl, const string& page, const string& comment,
|
||||
const VNumRange& range)
|
||||
: ASTGEN_SUPER_CoverToggleDecl(fl, page, comment)
|
||||
, m_range{range} {}
|
||||
ASTGEN_MEMBERS_AstCoverToggleDecl;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int size() const override { return m_range.elements(); }
|
||||
const VNumRange& range() const { return m_range; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
const AstCoverToggleDecl* const asamep = VN_DBG_AS(samep, CoverToggleDecl);
|
||||
return AstNodeCoverDecl::sameNode(samep) && range() == asamep->range();
|
||||
}
|
||||
};
|
||||
|
||||
// === AstNodeCoverOrAssert ===
|
||||
class AstAssert final : public AstNodeCoverOrAssert {
|
||||
|
|
|
@ -2870,10 +2870,9 @@ void AstBegin::dumpJson(std::ostream& str) const {
|
|||
dumpJsonBoolFunc(str, needProcess);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstCoverDecl::dump(std::ostream& str) const {
|
||||
void AstNodeCoverDecl::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
if (!page().empty()) str << " page=" << page();
|
||||
if (!linescov().empty()) str << " lc=" << linescov();
|
||||
if (this->dataDeclNullp()) {
|
||||
static bool s_recursing = false;
|
||||
str << " -> ";
|
||||
|
@ -2888,12 +2887,30 @@ void AstCoverDecl::dump(std::ostream& str) const {
|
|||
if (binNum()) str << " bin" << std::dec << binNum();
|
||||
}
|
||||
}
|
||||
void AstCoverDecl::dumpJson(std::ostream& str) const {
|
||||
void AstNodeCoverDecl::dumpJson(std::ostream& str) const {
|
||||
dumpJsonStrFunc(str, page);
|
||||
dumpJsonStrFunc(str, linescov);
|
||||
dumpJsonNumFunc(str, binNum);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstCoverOtherDecl::dump(std::ostream& str) const {
|
||||
this->AstNodeCoverDecl::dump(str);
|
||||
if (!linescov().empty()) str << " lc=" << linescov();
|
||||
}
|
||||
void AstCoverOtherDecl::dumpJson(std::ostream& str) const {
|
||||
this->AstNodeCoverDecl::dumpJson(str);
|
||||
dumpJsonStrFunc(str, linescov);
|
||||
}
|
||||
void AstCoverToggleDecl::dump(std::ostream& str) const {
|
||||
this->AstNodeCoverDecl::dump(str);
|
||||
if (range().ranged()) str << " range=[" << range().left() << ":" << range().right() << "]";
|
||||
}
|
||||
void AstCoverToggleDecl::dumpJson(std::ostream& str) const {
|
||||
this->AstNodeCoverDecl::dumpJson(str);
|
||||
if (range().ranged()) {
|
||||
dumpJsonStr(str, "range",
|
||||
std::to_string(range().left()) + ":" + std::to_string(range().right()));
|
||||
}
|
||||
}
|
||||
void AstCoverInc::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
|
|
|
@ -289,7 +289,7 @@ class BeginVisitor final : public VNVisitor {
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstNodeCoverDecl* nodep) override {
|
||||
// Don't need to fix path in coverage statements, they're not under
|
||||
// any BEGINs, but V3Coverage adds them all under the module itself.
|
||||
iterateChildren(nodep);
|
||||
|
|
|
@ -161,10 +161,10 @@ class CCtorsVisitor final : public VNVisitor {
|
|||
if (v3Global.opt.coverage()) {
|
||||
V3CCtorsBuilder configure_coverage{nodep, "_configure_coverage", VCtorType::COVERAGE};
|
||||
for (AstNode* np = nodep->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) {
|
||||
if (AstNodeCoverDecl* const coverp = VN_CAST(np, NodeCoverDecl)) {
|
||||
// ... else we don't have a static VlSym to be able to coverage insert
|
||||
UASSERT_OBJ(!VN_IS(nodep, Class), coverp,
|
||||
"CoverDecl should be in class's package, not class itself");
|
||||
"NodeCoverDecl should be in class's package, not class itself");
|
||||
np = coverp->backp();
|
||||
configure_coverage.add(coverp->unlinkFrBack());
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ class ClassVisitor final : public VNVisitor {
|
|||
// m_toScopeMoves.emplace_back(nodep, m_classScopep);
|
||||
//}
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstNodeCoverDecl* nodep) override {
|
||||
// Need to declare coverage in package, where we have access to symbol table
|
||||
iterateChildren(nodep);
|
||||
if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack());
|
||||
|
|
|
@ -100,18 +100,20 @@ class ClockVisitor final : public VNVisitor {
|
|||
// if (debug()) nodep->dumpTree("- ct: ");
|
||||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
AstNode* const incp = nodep->incp()->unlinkFrBack();
|
||||
AstCoverInc* const incp = nodep->incp()->unlinkFrBack();
|
||||
AstNodeExpr* const origp = nodep->origp()->unlinkFrBack();
|
||||
AstNodeExpr* const changeWrp = nodep->changep()->unlinkFrBack();
|
||||
AstNodeExpr* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
|
||||
AstNodeExpr* comparedp = nullptr;
|
||||
incp->toggleExprp(origp->cloneTree(false));
|
||||
incp->toggleCovExprp(changeRdp->cloneTree(false));
|
||||
// Xor will optimize better than Eq, when CoverToggle has bit selects,
|
||||
// but can only use Xor with non-opaque types
|
||||
if (const AstBasicDType* const bdtypep
|
||||
= VN_CAST(origp->dtypep()->skipRefp(), BasicDType)) {
|
||||
if (!bdtypep->isOpaque()) comparedp = new AstXor{nodep->fileline(), origp, changeRdp};
|
||||
}
|
||||
if (!comparedp) comparedp = AstEq::newTyped(nodep->fileline(), origp, changeRdp);
|
||||
UASSERT_OBJ(comparedp, nodep, "Toggle coverage of non-opaque type variable");
|
||||
AstIf* const newp = new AstIf{nodep->fileline(), comparedp, incp};
|
||||
// We could add another IF to detect posedges, and only increment if so.
|
||||
// It's another whole branch though versus a potential memory miss.
|
||||
|
|
|
@ -180,22 +180,8 @@ class CoverageVisitor final : public VNVisitor {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
AstCoverInc* newCoverInc(FileLine* fl, const string& hier, const string& page_prefix,
|
||||
const string& comment, const string& linescov, int offset,
|
||||
AstCoverInc* newCoverInc(FileLine* fl, AstNodeCoverDecl* const declp,
|
||||
const string& trace_var_name) {
|
||||
// We could use the basename of the filename to the page, but seems
|
||||
// better for code from an include file to be listed under the
|
||||
// module using it rather than the include file.
|
||||
// Note the module name could have parameters appended, we'll consider this
|
||||
// a feature as it allows for each parameterized block to be counted separately.
|
||||
// Someday the user might be allowed to specify a different page suffix
|
||||
const string page = page_prefix + "/" + m_modp->prettyName();
|
||||
|
||||
AstCoverDecl* const declp = new AstCoverDecl{fl, page, comment, linescov, offset};
|
||||
declp->hier(hier);
|
||||
m_modp->addStmtsp(declp);
|
||||
UINFO(9, "new " << declp);
|
||||
|
||||
AstCoverInc* const incp = new AstCoverInc{fl, declp};
|
||||
if (!trace_var_name.empty()
|
||||
&& v3Global.opt.traceCoverage()
|
||||
|
@ -317,9 +303,12 @@ class CoverageVisitor final : public VNVisitor {
|
|||
iterateAndNextNull(nodep->stmtsp());
|
||||
if (m_state.lineCoverageOn(nodep)) {
|
||||
lineTrack(nodep);
|
||||
AstCoverOtherDecl* const declp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_line/" + m_modp->prettyName(),
|
||||
"block", linesCov(m_state, nodep), 0};
|
||||
m_modp->addStmtsp(declp);
|
||||
AstNode* const newp
|
||||
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
||||
0, traceNameForLine(nodep, "block"));
|
||||
= newCoverInc(nodep->fileline(), declp, traceNameForLine(nodep, "block"));
|
||||
insertProcStatement(nodep, newp);
|
||||
}
|
||||
}
|
||||
|
@ -355,9 +344,12 @@ class CoverageVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
if (m_state.lineCoverageOn(nodep)) {
|
||||
lineTrack(nodep);
|
||||
AstCoverOtherDecl* const declp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_line/" + m_modp->prettyName(),
|
||||
"block", linesCov(m_state, nodep), 0};
|
||||
m_modp->addStmtsp(declp);
|
||||
AstNode* const newp
|
||||
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
||||
0, traceNameForLine(nodep, "block"));
|
||||
= newCoverInc(nodep->fileline(), declp, traceNameForLine(nodep, "block"));
|
||||
insertProcStatement(nodep, newp);
|
||||
}
|
||||
}
|
||||
|
@ -403,35 +395,23 @@ class CoverageVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void toggleVarBottom(const ToggleEnt& above, const AstVar* varp) {
|
||||
void toggleVarBottom(const ToggleEnt& above, const AstVar* varp, const VNumRange& range) {
|
||||
const std::string hierPrefix
|
||||
= (m_beginHier != "") ? AstNode::prettyName(m_beginHier) + "." : "";
|
||||
AstCoverToggleDecl* const declp
|
||||
= new AstCoverToggleDecl{varp->fileline(), "v_toggle/" + m_modp->prettyName(),
|
||||
hierPrefix + varp->name() + above.m_comment, range};
|
||||
m_modp->addStmtsp(declp);
|
||||
AstCoverToggle* const newp = new AstCoverToggle{
|
||||
varp->fileline(),
|
||||
newCoverInc(varp->fileline(), "", "v_toggle",
|
||||
hierPrefix + varp->name() + above.m_comment, "", 0, ""),
|
||||
varp->fileline(), newCoverInc(varp->fileline(), declp, ""),
|
||||
above.m_varRefp->cloneTree(false), above.m_chgRefp->cloneTree(false)};
|
||||
m_modp->addStmtsp(newp);
|
||||
}
|
||||
|
||||
void toggleVarRecurse(const AstNodeDType* const dtypep, const int depth, // per-iteration
|
||||
const ToggleEnt& above, const AstVar* const varp) { // Constant
|
||||
if (const AstBasicDType* const bdtypep = VN_CAST(dtypep, BasicDType)) {
|
||||
if (bdtypep->isRanged()) {
|
||||
for (int index_docs = bdtypep->lo(); index_docs < bdtypep->hi() + 1;
|
||||
++index_docs) {
|
||||
const int index_code = index_docs - bdtypep->lo();
|
||||
ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]",
|
||||
new AstSel{varp->fileline(),
|
||||
above.m_varRefp->cloneTree(false), index_code, 1},
|
||||
new AstSel{varp->fileline(),
|
||||
above.m_chgRefp->cloneTree(false), index_code, 1}};
|
||||
toggleVarBottom(newent, varp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else {
|
||||
toggleVarBottom(above, varp);
|
||||
}
|
||||
if (const AstBasicDType* const basicp = VN_CAST(dtypep, BasicDType)) {
|
||||
toggleVarBottom(above, varp, basicp->nrange());
|
||||
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
|
||||
const int index_code = index_docs - adtypep->lo();
|
||||
|
@ -544,20 +524,26 @@ class CoverageVisitor final : public VNVisitor {
|
|||
iterate(nodep->thenp());
|
||||
lineTrack(nodep);
|
||||
AstNodeExpr* const thenp = nodep->thenp()->unlinkFrBack();
|
||||
nodep->thenp(new AstExprStmt{thenp->fileline(),
|
||||
newCoverInc(nodep->fileline(), "", "v_branch",
|
||||
"cond_then", linesCov(m_state, nodep), 0,
|
||||
traceNameForLine(nodep, "cond_then")),
|
||||
thenp});
|
||||
AstCoverOtherDecl* const thenDeclp
|
||||
= new AstCoverOtherDecl{thenp->fileline(), "v_branch/" + m_modp->prettyName(),
|
||||
"cond_then", linesCov(m_state, nodep), 0};
|
||||
m_modp->addStmtsp(thenDeclp);
|
||||
nodep->thenp(new AstExprStmt{
|
||||
thenp->fileline(),
|
||||
newCoverInc(nodep->fileline(), thenDeclp, traceNameForLine(nodep, "cond_then")),
|
||||
thenp});
|
||||
m_state = lastState;
|
||||
createHandle(nodep);
|
||||
iterate(nodep->elsep());
|
||||
AstNodeExpr* const elsep = nodep->elsep()->unlinkFrBack();
|
||||
nodep->elsep(new AstExprStmt{elsep->fileline(),
|
||||
newCoverInc(nodep->fileline(), "", "v_branch",
|
||||
"cond_else", linesCov(m_state, nodep), 1,
|
||||
traceNameForLine(nodep, "cond_else")),
|
||||
elsep});
|
||||
AstCoverOtherDecl* const elseDeclp
|
||||
= new AstCoverOtherDecl{thenp->fileline(), "v_branch/" + m_modp->prettyName(),
|
||||
"cond_else", linesCov(m_state, nodep), 1};
|
||||
m_modp->addStmtsp(elseDeclp);
|
||||
nodep->elsep(new AstExprStmt{
|
||||
elsep->fileline(),
|
||||
newCoverInc(nodep->fileline(), elseDeclp, traceNameForLine(nodep, "cond_else")),
|
||||
elsep});
|
||||
|
||||
m_state = lastState;
|
||||
} else {
|
||||
|
@ -614,22 +600,32 @@ class CoverageVisitor final : public VNVisitor {
|
|||
// Normal if. Linecov shows what's inside the if (not condition that is
|
||||
// always executed)
|
||||
UINFO(4, " COVER-branch: " << nodep);
|
||||
nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_branch", "if",
|
||||
linesCov(ifState, nodep), 0,
|
||||
traceNameForLine(nodep, "if")));
|
||||
AstCoverOtherDecl* const ifDeclp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_branch/" + m_modp->prettyName(),
|
||||
"if", linesCov(ifState, nodep), 0};
|
||||
m_modp->addStmtsp(ifDeclp);
|
||||
nodep->addThensp(
|
||||
newCoverInc(nodep->fileline(), ifDeclp, traceNameForLine(nodep, "if")));
|
||||
// The else has a column offset of 1 to uniquify it relative to the if
|
||||
// As "if" and "else" are more than one character wide, this won't overlap
|
||||
// another token
|
||||
nodep->addElsesp(newCoverInc(nodep->fileline(), "", "v_branch", "else",
|
||||
linesCov(elseState, nodep), 1,
|
||||
traceNameForLine(nodep, "else")));
|
||||
AstCoverOtherDecl* const elseDeclp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_branch/" + m_modp->prettyName(),
|
||||
"else", linesCov(elseState, nodep), 1};
|
||||
m_modp->addStmtsp(elseDeclp);
|
||||
nodep->addElsesp(
|
||||
newCoverInc(nodep->fileline(), elseDeclp, traceNameForLine(nodep, "else")));
|
||||
}
|
||||
// If/else attributes to each block as non-branch coverage
|
||||
else if (first_elsif || cont_elsif) {
|
||||
UINFO(4, " COVER-elsif: " << nodep);
|
||||
if (ifState.lineCoverageOn(nodep)) {
|
||||
nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "elsif",
|
||||
linesCov(ifState, nodep), 0,
|
||||
AstCoverOtherDecl* const elsifDeclp = new AstCoverOtherDecl{
|
||||
nodep->fileline(), "v_line/" + m_modp->prettyName(), "elsif",
|
||||
linesCov(ifState, nodep), 0};
|
||||
m_modp->addStmtsp(elsifDeclp);
|
||||
|
||||
nodep->addThensp(newCoverInc(nodep->fileline(), elsifDeclp,
|
||||
traceNameForLine(nodep, "elsif")));
|
||||
}
|
||||
// and we don't insert the else as the child if-else will do so
|
||||
|
@ -637,14 +633,21 @@ class CoverageVisitor final : public VNVisitor {
|
|||
// Cover as separate blocks (not a branch as is not two-legged)
|
||||
if (ifState.lineCoverageOn(nodep)) {
|
||||
UINFO(4, " COVER-half-if: " << nodep);
|
||||
nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "if",
|
||||
linesCov(ifState, nodep), 0,
|
||||
traceNameForLine(nodep, "if")));
|
||||
AstCoverOtherDecl* const ifDeclp = new AstCoverOtherDecl{
|
||||
nodep->fileline(), "v_line/" + m_modp->prettyName(), "if",
|
||||
linesCov(ifState, nodep), 0};
|
||||
m_modp->addStmtsp(ifDeclp);
|
||||
nodep->addThensp(
|
||||
newCoverInc(nodep->fileline(), ifDeclp, traceNameForLine(nodep, "if")));
|
||||
}
|
||||
if (elseState.lineCoverageOn(nodep)) {
|
||||
UINFO(4, " COVER-half-el: " << nodep);
|
||||
nodep->addElsesp(newCoverInc(nodep->fileline(), "", "v_line", "else",
|
||||
linesCov(elseState, nodep), 1,
|
||||
AstCoverOtherDecl* const elseDeclp = new AstCoverOtherDecl{
|
||||
nodep->fileline(), "v_line/" + m_modp->prettyName(), "else",
|
||||
linesCov(elseState, nodep), 1};
|
||||
m_modp->addStmtsp(elseDeclp);
|
||||
|
||||
nodep->addElsesp(newCoverInc(nodep->fileline(), elseDeclp,
|
||||
traceNameForLine(nodep, "else")));
|
||||
}
|
||||
}
|
||||
|
@ -666,9 +669,12 @@ class CoverageVisitor final : public VNVisitor {
|
|||
if (m_state.lineCoverageOn(nodep)) { // if the case body didn't disable it
|
||||
lineTrack(nodep);
|
||||
UINFO(4, " COVER: " << nodep);
|
||||
nodep->addStmtsp(newCoverInc(nodep->fileline(), "", "v_line", "case",
|
||||
linesCov(m_state, nodep), 0,
|
||||
traceNameForLine(nodep, "case")));
|
||||
AstCoverOtherDecl* const declp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_line/" + m_modp->prettyName(),
|
||||
"case", linesCov(m_state, nodep), 0};
|
||||
m_modp->addStmtsp(declp);
|
||||
nodep->addStmtsp(
|
||||
newCoverInc(nodep->fileline(), declp, traceNameForLine(nodep, "case")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -681,9 +687,13 @@ class CoverageVisitor final : public VNVisitor {
|
|||
if (!nodep->coverincsp() && v3Global.opt.coverageUser()) {
|
||||
// Note the name may be overridden by V3Assert processing
|
||||
lineTrack(nodep);
|
||||
nodep->addCoverincsp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover",
|
||||
linesCov(m_state, nodep), 0,
|
||||
m_beginHier + "_vlCoverageUserTrace"));
|
||||
AstCoverOtherDecl* const declp
|
||||
= new AstCoverOtherDecl{nodep->fileline(), "v_user/" + m_modp->prettyName(),
|
||||
"cover", linesCov(m_state, nodep), 0};
|
||||
declp->hier(m_beginHier);
|
||||
m_modp->addStmtsp(declp);
|
||||
nodep->addCoverincsp(
|
||||
newCoverInc(nodep->fileline(), declp, m_beginHier + "_vlCoverageUserTrace"));
|
||||
}
|
||||
}
|
||||
void visit(AstStop* nodep) override {
|
||||
|
@ -755,8 +765,10 @@ class CoverageVisitor final : public VNVisitor {
|
|||
}
|
||||
comment += ") => ";
|
||||
comment += (m_objective ? '1' : '0');
|
||||
AstNode* const newp
|
||||
= newCoverInc(fl, "", "v_expr", comment, "", 0, traceNameForLine(nodep, name));
|
||||
AstCoverOtherDecl* const declp = new AstCoverOtherDecl{
|
||||
nodep->fileline(), "v_expr/" + m_modp->prettyName(), comment, "", 0};
|
||||
m_modp->addStmtsp(declp);
|
||||
AstNode* const newp = newCoverInc(fl, declp, traceNameForLine(nodep, name));
|
||||
UASSERT_OBJ(condp, nodep, "No terms in expression coverage branch");
|
||||
AstIf* const ifp = new AstIf{fl, condp, newp, nullptr};
|
||||
ifp->user2(true);
|
||||
|
|
|
@ -75,7 +75,7 @@ class CoverageJoinVisitor final : public VNVisitor {
|
|||
// The CoverDecl the duplicate pointed to now needs to point to the
|
||||
// original's data. I.e. the duplicate will get the coverage number
|
||||
// from the non-duplicate
|
||||
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
|
||||
AstNodeCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
|
||||
removep->incp()->declp()->dataDeclp(datadeclp);
|
||||
UINFO(8, " new " << removep->incp()->declp());
|
||||
// Mark the found node as a duplicate of the first node
|
||||
|
|
|
@ -661,7 +661,7 @@ public:
|
|||
}
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstCoverOtherDecl* nodep) override {
|
||||
putns(nodep, "vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl
|
||||
puts("&(vlSymsp->__Vcoverage[");
|
||||
puts(cvtToStr(nodep->dataDeclThisp()->binNum()));
|
||||
|
@ -689,15 +689,67 @@ public:
|
|||
putsQuoted(nodep->linescov());
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstCoverToggleDecl* nodep) override {
|
||||
putns(nodep, "vlSelf->__vlCoverToggleInsert("); // As Declared in emitCoverageDecl
|
||||
puts(cvtToStr(nodep->range().right()));
|
||||
puts(", ");
|
||||
puts(cvtToStr(nodep->range().left()));
|
||||
puts(", ");
|
||||
puts(cvtToStr(nodep->range().ranged()));
|
||||
puts(", ");
|
||||
puts("&(vlSymsp->__Vcoverage[");
|
||||
puts(cvtToStr(nodep->dataDeclThisp()->binNum()));
|
||||
puts("])");
|
||||
// If this isn't the first instantiation of this module under this
|
||||
// design, don't really count the bucket, and rely on verilator_cov to
|
||||
// aggregate counts. This is because Verilator combines all
|
||||
// hierarchies itself, and if verilator_cov also did it, you'd end up
|
||||
// with (number-of-instant) times too many counts in this bin.
|
||||
puts(", first"); // Enable, passed from __Vconfigure parameter
|
||||
puts(", ");
|
||||
putsQuoted(protect(nodep->fileline()->filename()));
|
||||
puts(", ");
|
||||
puts(cvtToStr(nodep->fileline()->lineno()));
|
||||
puts(", ");
|
||||
puts(cvtToStr(nodep->fileline()->firstColumn()));
|
||||
puts(", ");
|
||||
putsQuoted((!nodep->hier().empty() ? "." : "")
|
||||
+ protectWordsIf(nodep->hier(), nodep->protect()));
|
||||
puts(", ");
|
||||
putsQuoted(protectWordsIf(nodep->page(), nodep->protect()));
|
||||
puts(", ");
|
||||
putsQuoted(protectWordsIf(nodep->comment(), nodep->protect()));
|
||||
puts(");\n");
|
||||
}
|
||||
void visit(AstCoverInc* nodep) override {
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
putns(nodep, "vlSymsp->__Vcoverage[");
|
||||
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
|
||||
puts("].fetch_add(1, std::memory_order_relaxed);\n");
|
||||
if (nodep->declp()->size() == 1) {
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
putns(nodep, "vlSymsp->__Vcoverage[");
|
||||
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
|
||||
puts("].fetch_add(1, std::memory_order_relaxed);\n");
|
||||
} else {
|
||||
putns(nodep, "++(vlSymsp->__Vcoverage[");
|
||||
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
|
||||
puts("]);\n");
|
||||
}
|
||||
} else {
|
||||
putns(nodep, "++(vlSymsp->__Vcoverage[");
|
||||
puts("VL_COV_TOGGLE_CHG_");
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
puts("MT_");
|
||||
} else {
|
||||
puts("ST_");
|
||||
}
|
||||
emitIQW(nodep->toggleExprp());
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->declp()->size()));
|
||||
puts(", ");
|
||||
puts("vlSymsp->__Vcoverage + ");
|
||||
puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum()));
|
||||
puts("]);\n");
|
||||
puts(", ");
|
||||
iterateConst(nodep->toggleExprp());
|
||||
puts(", ");
|
||||
iterateConst(nodep->toggleCovExprp());
|
||||
puts(");\n");
|
||||
}
|
||||
}
|
||||
void visit(AstDisableFork* nodep) override { putns(nodep, "vlProcess->disableFork();\n"); }
|
||||
|
|
|
@ -181,6 +181,14 @@ class EmitCHeader final : public EmitCConstInit {
|
|||
"linescovp);\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.coverageToggle() && !VN_IS(modp, Class)) {
|
||||
decorateFirst(first, section);
|
||||
puts("void __vlCoverToggleInsert(int begin, int end, bool ranged, ");
|
||||
puts(v3Global.opt.threads() > 1 ? "std::atomic<uint32_t>" : "uint32_t");
|
||||
puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
||||
puts("const char* hierp, const char* pagep, const char* commentp);\n");
|
||||
}
|
||||
|
||||
if (v3Global.opt.savable()) {
|
||||
decorateFirst(first, section);
|
||||
puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n");
|
||||
|
|
|
@ -103,7 +103,7 @@ class EmitCGatherDependencies final : VNVisitorConst {
|
|||
addSelfDependency(nodep->selfPointer(), nodep->varp());
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstNodeCoverDecl* nodep) override {
|
||||
addSymsDependency();
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
@ -307,17 +307,16 @@ class EmitCImp final : EmitCFunc {
|
|||
splitSizeInc(10);
|
||||
}
|
||||
void emitCoverageImp() {
|
||||
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this
|
||||
// function. This gets around gcc slowness constructing all of the template
|
||||
// arguments.
|
||||
if (v3Global.opt.coverage()) {
|
||||
puts("\n// Coverage\n");
|
||||
// Rather than putting out VL_COVER_INSERT calls directly, we do it via this
|
||||
// function. This gets around gcc slowness constructing all of the template
|
||||
// arguments.
|
||||
puts("void " + prefixNameProtect(m_modp) + "::__vlCoverInsert(");
|
||||
puts(v3Global.opt.threads() > 1 ? "std::atomic<uint32_t>" : "uint32_t");
|
||||
puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
||||
puts("const char* hierp, const char* pagep, const char* commentp, const char* "
|
||||
"linescovp) "
|
||||
"{\n");
|
||||
"linescovp) {\n");
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
puts("assert(sizeof(uint32_t) == sizeof(std::atomic<uint32_t>));\n");
|
||||
puts("uint32_t* count32p = reinterpret_cast<uint32_t*>(countp);\n");
|
||||
|
@ -343,6 +342,48 @@ class EmitCImp final : EmitCFunc {
|
|||
puts("}\n");
|
||||
splitSizeInc(10);
|
||||
}
|
||||
if (v3Global.opt.coverageToggle()) {
|
||||
puts("\n// Toggle Coverage\n");
|
||||
puts("void " + prefixNameProtect(m_modp) + "::__vlCoverToggleInsert(");
|
||||
puts("int begin, int end, bool ranged, ");
|
||||
puts(v3Global.opt.threads() > 1 ? "std::atomic<uint32_t>" : "uint32_t");
|
||||
puts("* countp, bool enable, const char* filenamep, int lineno, int column,\n");
|
||||
puts("const char* hierp, const char* pagep, const char* commentp) {\n");
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
puts("assert(sizeof(uint32_t) == sizeof(std::atomic<uint32_t>));\n");
|
||||
}
|
||||
puts("int step = (end >= begin) ? 1 : -1;\n");
|
||||
// range is inclusive
|
||||
puts("for (int i = begin; i != end + step; i += step) {\n");
|
||||
if (v3Global.opt.threads() > 1) {
|
||||
puts("uint32_t* count32p = reinterpret_cast<uint32_t*>(countp);\n");
|
||||
} else {
|
||||
puts("uint32_t* count32p = countp;\n");
|
||||
}
|
||||
// static doesn't need save-restore as is constant
|
||||
puts("static uint32_t fake_zero_count = 0;\n");
|
||||
puts("std::string fullhier = std::string{VerilatedModule::name()} + hierp;\n");
|
||||
puts("if (!fullhier.empty() && fullhier[0] == '.') fullhier = fullhier.substr(1);\n");
|
||||
puts("std::string commentWithIndex = commentp;\n");
|
||||
puts("if (ranged) commentWithIndex += '[' + std::to_string(i) + ']';\n");
|
||||
// Used for second++ instantiation of identical bin
|
||||
puts("if (!enable) count32p = &fake_zero_count;\n");
|
||||
puts("*count32p = 0;\n");
|
||||
puts("VL_COVER_INSERT(vlSymsp->_vm_contextp__->coveragep(), VerilatedModule::name(), "
|
||||
"count32p,");
|
||||
puts(" \"filename\",filenamep,");
|
||||
puts(" \"lineno\",lineno,");
|
||||
puts(" \"column\",column,\n");
|
||||
puts("\"hier\",fullhier,");
|
||||
puts(" \"page\",pagep,");
|
||||
puts(" \"comment\",commentWithIndex.c_str(),");
|
||||
puts(" \"\", \"\");\n"); // linescov argument, but in toggle coverage it is always
|
||||
// empty
|
||||
puts("++countp;\n");
|
||||
puts("}\n");
|
||||
puts("}\n");
|
||||
splitSizeInc(10);
|
||||
}
|
||||
}
|
||||
void emitDestructorImp(const AstNodeModule* modp) {
|
||||
puts("\n");
|
||||
|
|
|
@ -376,10 +376,11 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||
iterateChildrenConst(nodep);
|
||||
m_statVarScopeBytes += nodep->varp()->dtypep()->widthTotalBytes();
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstNodeCoverDecl* nodep) override {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||
nodep->binNum(m_coverBins++);
|
||||
nodep->binNum(m_coverBins);
|
||||
m_coverBins += nodep->size();
|
||||
}
|
||||
}
|
||||
void visit(AstCFunc* nodep) override {
|
||||
|
|
|
@ -231,7 +231,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
putbs("continue");
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
void visit(AstCoverDecl*) override {} // N/A
|
||||
void visit(AstNodeCoverDecl*) override {} // N/A
|
||||
void visit(AstCoverInc*) override {} // N/A
|
||||
void visit(AstCoverToggle*) override {} // N/A
|
||||
|
||||
|
|
|
@ -459,7 +459,7 @@ class InlineRelinkVisitor final : public VNVisitor {
|
|||
if (afterp) nodep->addScopeEntrp(afterp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
void visit(AstNodeCoverDecl* nodep) override {
|
||||
// Fix path in coverage statements
|
||||
nodep->hier(VString::dot(m_cellp->prettyName(), ".", nodep->hier()));
|
||||
iterateChildren(nodep);
|
||||
|
|
|
@ -545,7 +545,7 @@ class UndrivenVisitor final : public VNVisitorConst {
|
|||
void visit(AstPrimitive*) override {}
|
||||
|
||||
// Coverage artifacts etc shouldn't count as a sink
|
||||
void visit(AstCoverDecl*) override {}
|
||||
void visit(AstNodeCoverDecl*) override {}
|
||||
void visit(AstCoverInc*) override {}
|
||||
void visit(AstCoverToggle*) override {}
|
||||
void visit(AstTraceDecl*) override {}
|
||||
|
|
|
@ -45,6 +45,15 @@
|
|||
} str_queue_t;
|
||||
str_queue_t str_queue;
|
||||
|
||||
typedef struct packed {
|
||||
// verilator lint_off ASCRANGE
|
||||
bit [3:5] x;
|
||||
// verilator lint_on ASCRANGE
|
||||
bit [0:0] y;
|
||||
} str_bit_t;
|
||||
%000002 str_bit_t str_bit;
|
||||
%000002 str_bit_t [5:2] str_bit_arr;
|
||||
|
||||
alpha a1 (/*AUTOINST*/
|
||||
// Outputs
|
||||
.toggle_up (toggle_up),
|
||||
|
@ -97,10 +106,16 @@
|
|||
if (cyc == 3) begin
|
||||
str_queue.q.push_back(1);
|
||||
toggle <= '1;
|
||||
str_bit.x <= '1;
|
||||
str_bit.y <= '1;
|
||||
str_bit_arr[4].x <= '1;
|
||||
end
|
||||
if (cyc == 4) begin
|
||||
if (str_queue.q.size() != 1) $stop;
|
||||
toggle <= '0;
|
||||
str_bit.x[3] <= 0;
|
||||
str_bit.y[0] <= 0;
|
||||
str_bit_arr[4].x[3] <= 0;
|
||||
end
|
||||
else if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
|
@ -21,7 +21,7 @@ test.inline_checks()
|
|||
test.file_grep_not(test.obj_dir + "/coverage.dat", "largeish")
|
||||
|
||||
if test.vlt_all:
|
||||
test.file_grep(test.stats, r'Coverage, Toggle points joined\s+(\d+)', 27)
|
||||
test.file_grep(test.stats, r'Coverage, Toggle points joined\s+(\d+)', 13)
|
||||
|
||||
test.run(cmd=[
|
||||
os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage",
|
||||
|
|
|
@ -44,6 +44,15 @@ module t (/*AUTOARG*/
|
|||
} str_queue_t;
|
||||
str_queue_t str_queue;
|
||||
|
||||
typedef struct packed {
|
||||
// verilator lint_off ASCRANGE
|
||||
bit [3:5] x;
|
||||
// verilator lint_on ASCRANGE
|
||||
bit [0:0] y;
|
||||
} str_bit_t;
|
||||
str_bit_t str_bit;
|
||||
str_bit_t [5:2] str_bit_arr;
|
||||
|
||||
alpha a1 (/*AUTOINST*/
|
||||
// Outputs
|
||||
.toggle_up (toggle_up),
|
||||
|
@ -96,10 +105,16 @@ module t (/*AUTOARG*/
|
|||
if (cyc == 3) begin
|
||||
str_queue.q.push_back(1);
|
||||
toggle <= '1;
|
||||
str_bit.x <= '1;
|
||||
str_bit.y <= '1;
|
||||
str_bit_arr[4].x <= '1;
|
||||
end
|
||||
if (cyc == 4) begin
|
||||
if (str_queue.q.size() != 1) $stop;
|
||||
toggle <= '0;
|
||||
str_bit.x[3] <= 0;
|
||||
str_bit.y[0] <= 0;
|
||||
str_bit_arr[4].x[3] <= 0;
|
||||
end
|
||||
else if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
|
@ -62,6 +62,35 @@
|
|||
} str_queue_t;
|
||||
str_queue_t str_queue;
|
||||
|
||||
typedef struct packed {
|
||||
// verilator lint_off ASCRANGE
|
||||
bit [3:5] x;
|
||||
// verilator lint_on ASCRANGE
|
||||
bit [0:0] y;
|
||||
} str_bit_t;
|
||||
%000002 str_bit_t str_bit;
|
||||
-000002 point: comment=str_bit.x[3] hier=top.t
|
||||
-000001 point: comment=str_bit.x[4] hier=top.t
|
||||
-000001 point: comment=str_bit.x[5] hier=top.t
|
||||
-000002 point: comment=str_bit.y[0] hier=top.t
|
||||
%000002 str_bit_t [5:2] str_bit_arr;
|
||||
-000000 point: comment=str_bit_arr[2].x[3] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[2].x[4] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[2].x[5] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[2].y[0] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[3].x[3] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[3].x[4] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[3].x[5] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[3].y[0] hier=top.t
|
||||
-000002 point: comment=str_bit_arr[4].x[3] hier=top.t
|
||||
-000001 point: comment=str_bit_arr[4].x[4] hier=top.t
|
||||
-000001 point: comment=str_bit_arr[4].x[5] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[4].y[0] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[5].x[3] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[5].x[4] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[5].x[5] hier=top.t
|
||||
-000000 point: comment=str_bit_arr[5].y[0] hier=top.t
|
||||
|
||||
alpha a1 (/*AUTOINST*/
|
||||
// Outputs
|
||||
.toggle_up (toggle_up),
|
||||
|
@ -138,10 +167,16 @@
|
|||
if (cyc == 3) begin
|
||||
str_queue.q.push_back(1);
|
||||
toggle <= '1;
|
||||
str_bit.x <= '1;
|
||||
str_bit.y <= '1;
|
||||
str_bit_arr[4].x <= '1;
|
||||
end
|
||||
if (cyc == 4) begin
|
||||
if (str_queue.q.size() != 1) $stop;
|
||||
toggle <= '0;
|
||||
str_bit.x[3] <= 0;
|
||||
str_bit.y[0] <= 0;
|
||||
str_bit_arr[4].x[3] <= 0;
|
||||
end
|
||||
else if (cyc == 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
|
|
@ -16,6 +16,6 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", "--coverage", "--
|
|||
test.execute()
|
||||
|
||||
if test.vlt:
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 620)
|
||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 478)
|
||||
|
||||
test.passes()
|
||||
|
|
Loading…
Reference in New Issue