Support expression coverage (#5719)
This commit is contained in:
parent
fe15171649
commit
34ced254c0
|
|
@ -328,6 +328,8 @@ detailed descriptions of these arguments.
|
||||||
--compiler-include Include additional header in the precompiled one
|
--compiler-include Include additional header in the precompiled one
|
||||||
--converge-limit <loops> Tune convergence settle time
|
--converge-limit <loops> Tune convergence settle time
|
||||||
--coverage Enable all coverage
|
--coverage Enable all coverage
|
||||||
|
--coverage-expr Enable expression coverage
|
||||||
|
--coverage-expr-max <value> Maximum permutations allowed for an expression
|
||||||
--coverage-line Enable line coverage
|
--coverage-line Enable line coverage
|
||||||
--coverage-max-width <width> Maximum array depth for coverage
|
--coverage-max-width <width> Maximum array depth for coverage
|
||||||
--coverage-toggle Enable toggle coverage
|
--coverage-toggle Enable toggle coverage
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,17 @@ Summary:
|
||||||
.. option:: --coverage
|
.. option:: --coverage
|
||||||
|
|
||||||
Enables all forms of coverage, an alias for :vlopt:`--coverage-line`
|
Enables all forms of coverage, an alias for :vlopt:`--coverage-line`
|
||||||
:vlopt:`--coverage-toggle` :vlopt:`--coverage-user`.
|
:vlopt:`--coverage-toggle :vlopt:`--coverage-expr`` :vlopt:`--coverage-user`.
|
||||||
|
|
||||||
|
.. option:: --coverage-expr
|
||||||
|
|
||||||
|
Enables expression coverage analysis. See :ref:`Expression Coverage`.
|
||||||
|
|
||||||
|
.. option:: --coverage-expr-max <value>
|
||||||
|
|
||||||
|
Rarely needed. Specifies the maximum number of permutations able to be
|
||||||
|
covered for a given expression. Defaults to 32. Increasing may slow
|
||||||
|
coverage simulations and make analyzing the results unwieldy.
|
||||||
|
|
||||||
.. option:: --coverage-line
|
.. option:: --coverage-line
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ to read multiple inputs. If no data file is specified, by default,
|
||||||
Specifies the directory name to which source files with annotated coverage
|
Specifies the directory name to which source files with annotated coverage
|
||||||
data should be written.
|
data should be written.
|
||||||
|
|
||||||
Points are children of each line coverage- branches or toggle points.
|
Points are children of each line coverage- branches, expressions or toggle points.
|
||||||
When point counts are aggregated into a line, the minimum and maximum counts
|
When point counts are aggregated into a line, the minimum and maximum counts
|
||||||
are used to determine the status of the line (complete, partial, failing)
|
are used to determine the status of the line (complete, partial, failing)
|
||||||
The count is equal to the maximum of the points.
|
The count is equal to the maximum of the points.
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,41 @@ A :option:`/*verilator&32;coverage_off*/`
|
||||||
signals that do not need toggle analysis, such as RAMs and register files.
|
signals that do not need toggle analysis, such as RAMs and register files.
|
||||||
|
|
||||||
|
|
||||||
|
.. _Expression Coverage:
|
||||||
|
|
||||||
|
Expression Coverage
|
||||||
|
-------------
|
||||||
|
|
||||||
|
With :vlopt:`--coverage` or :vlopt:`--coverage-expr`, Verilator will
|
||||||
|
automatically add coverage analysis at each expression, indicating with
|
||||||
|
a truth table how every Boolean truth-table possiblity in the expression occurred.
|
||||||
|
|
||||||
|
Multi-bit expressions are ignored, but sub-expressions with are entirely
|
||||||
|
Boolean are analyzed. Expression coverage does not fully explore the truth
|
||||||
|
table of an expression, rather is looks at each term's contribution. E.g.
|
||||||
|
an AND operation will check coverage for TT, XF and FX.
|
||||||
|
|
||||||
|
Some expressions may produce too many cover points. Verilator limits the
|
||||||
|
maximum number of cover poitns per expression to 32, but this may be
|
||||||
|
controlled with :vlopt:`--coverage-expr-max`.
|
||||||
|
|
||||||
|
Below is an example showing expression coverage produced from `verilator_coverage`
|
||||||
|
as applied to the condition expression inside an if statement. Each line
|
||||||
|
shows the minimum number of terms and their values (e.g. `(t1==0 && t2==1)`) needed
|
||||||
|
to reach a result for the overall expression (e.g. `=> 1`). Each line also
|
||||||
|
shows the number of times this combination was hit. Note that individual lines
|
||||||
|
are not mutually exclusive.
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%000004 if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
|
||||||
.. _Suppressing Coverage:
|
.. _Suppressing Coverage:
|
||||||
|
|
||||||
Suppressing Coverage
|
Suppressing Coverage
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
#include "V3Coverage.h"
|
#include "V3Coverage.h"
|
||||||
|
|
||||||
|
#include "V3EmitV.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
@ -39,6 +42,18 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
// TYPES
|
// TYPES
|
||||||
using LinenoSet = std::set<int>;
|
using LinenoSet = std::set<int>;
|
||||||
|
|
||||||
|
struct CoverTerm final {
|
||||||
|
AstNodeExpr* m_exprp; // Expression branch term
|
||||||
|
bool m_objective; // Term objective
|
||||||
|
std::string m_emitV; // V3EmitV string for cover point comment
|
||||||
|
CoverTerm(AstNodeExpr* exprp, bool objective, const string& emitV)
|
||||||
|
: m_exprp{exprp}
|
||||||
|
, m_objective{objective}
|
||||||
|
, m_emitV(emitV) {}
|
||||||
|
};
|
||||||
|
using CoverExpr = std::deque<CoverTerm>;
|
||||||
|
using CoverExprs = std::list<CoverExpr>;
|
||||||
|
|
||||||
struct ToggleEnt final {
|
struct ToggleEnt final {
|
||||||
const string m_comment; // Comment for coverage dump
|
const string m_comment; // Comment for coverage dump
|
||||||
AstNodeExpr* m_varRefp; // How to get to this element
|
AstNodeExpr* m_varRefp; // How to get to this element
|
||||||
|
|
@ -64,12 +79,20 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||||
&& v3Global.opt.coverageLine();
|
&& v3Global.opt.coverageLine();
|
||||||
}
|
}
|
||||||
|
bool exprCoverageOn(const AstNode* nodep) const {
|
||||||
|
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||||
|
&& v3Global.opt.coverageExpr();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Objective : uint8_t { NONE, SEEKING, ABORTED };
|
||||||
|
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Entire netlist:
|
// Entire netlist:
|
||||||
// AstIf::user1() -> bool. True indicates ifelse processed
|
// AstIf::user1() -> bool. True indicates ifelse processed
|
||||||
|
// AstIf::user2() -> bool. True indicates coverage-generated
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
int m_nextHandle = 0;
|
int m_nextHandle = 0;
|
||||||
|
|
@ -77,6 +100,13 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
// STATE - for current visit position (use VL_RESTORER)
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
CheckState m_state; // State save-restored on each new coverage scope/block
|
CheckState m_state; // State save-restored on each new coverage scope/block
|
||||||
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
||||||
|
AstNode* m_exprStmtsp = nullptr; // Node to add expr coverage to
|
||||||
|
bool m_then = false; // Whether we're iterating the then or else branch
|
||||||
|
// when m_exprStmtps is an AstIf
|
||||||
|
CoverExprs m_exprs; // List of expressions that can reach objective
|
||||||
|
Objective m_seeking = NONE; // Seeking objective for expression coverage
|
||||||
|
bool m_objective = false; // Expression objective
|
||||||
|
bool m_ifCond = false; // Visiting if condition
|
||||||
bool m_inToggleOff = false; // In function/task etc
|
bool m_inToggleOff = false; // In function/task etc
|
||||||
string m_beginHier; // AstBegin hier name for user coverage points
|
string m_beginHier; // AstBegin hier name for user coverage points
|
||||||
|
|
||||||
|
|
@ -160,7 +190,7 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
UINFO(9, "line create h" << m_state.m_handle << " " << nodep << endl);
|
UINFO(9, "line create h" << m_state.m_handle << " " << nodep << endl);
|
||||||
}
|
}
|
||||||
void lineTrack(const AstNode* nodep) {
|
void lineTrack(const AstNode* nodep) {
|
||||||
if (m_state.lineCoverageOn(nodep)
|
if (m_state.lineCoverageOn(nodep) && !m_ifCond
|
||||||
&& m_state.m_nodep->fileline()->filenameno() == nodep->fileline()->filenameno()) {
|
&& m_state.m_nodep->fileline()->filenameno() == nodep->fileline()->filenameno()) {
|
||||||
for (int lineno = nodep->fileline()->firstLineno();
|
for (int lineno = nodep->fileline()->firstLineno();
|
||||||
lineno <= nodep->fileline()->lastLineno(); ++lineno) {
|
lineno <= nodep->fileline()->lastLineno(); ++lineno) {
|
||||||
|
|
@ -222,13 +252,36 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
|
void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
|
||||||
void visit(AstWhile* nodep) override { iterateProcedure(nodep); }
|
// we can cover expressions in while loops, but the counting goes outside
|
||||||
|
// the while, see: "minimally-intelligent decision about ... clock domain"
|
||||||
|
// in the Toggle Coverage docs
|
||||||
|
void visit(AstWhile* nodep) override { iterateProcedure(nodep, false); }
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
||||||
}
|
}
|
||||||
void iterateProcedure(AstNode* nodep) {
|
|
||||||
|
void insertProcStatement(AstNode* nodep, AstNode* stmtp) {
|
||||||
|
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstIf* const itemp = VN_CAST(nodep, If)) {
|
||||||
|
if (m_then) {
|
||||||
|
itemp->addThensp(stmtp);
|
||||||
|
} else {
|
||||||
|
itemp->addElsesp(stmtp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodep->v3fatalSrc("Bad node type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void iterateProcedure(AstNode* nodep, bool exprProc = true) {
|
||||||
VL_RESTORER(m_state);
|
VL_RESTORER(m_state);
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
VL_RESTORER(m_inToggleOff);
|
VL_RESTORER(m_inToggleOff);
|
||||||
|
if (exprProc) m_exprStmtsp = nodep;
|
||||||
m_inToggleOff = true;
|
m_inToggleOff = true;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
@ -237,15 +290,7 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
AstNode* const newp
|
AstNode* const newp
|
||||||
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
||||||
0, traceNameForLine(nodep, "block"));
|
0, traceNameForLine(nodep, "block"));
|
||||||
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
|
insertProcStatement(nodep, newp);
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
|
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
|
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else {
|
|
||||||
nodep->v3fatalSrc("Bad node type");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,6 +449,8 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
// VISITORS - LINE COVERAGE
|
// VISITORS - LINE COVERAGE
|
||||||
// Note not AstNodeIf; other types don't get covered
|
// Note not AstNodeIf; other types don't get covered
|
||||||
void visit(AstIf* nodep) override {
|
void visit(AstIf* nodep) override {
|
||||||
|
if (nodep->user2()) return;
|
||||||
|
|
||||||
UINFO(4, " IF: " << nodep << endl);
|
UINFO(4, " IF: " << nodep << endl);
|
||||||
if (m_state.m_on) {
|
if (m_state.m_on) {
|
||||||
// An else-if. When we iterate the if, use "elsif" marking
|
// An else-if. When we iterate the if, use "elsif" marking
|
||||||
|
|
@ -422,6 +469,10 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
CheckState ifState;
|
CheckState ifState;
|
||||||
CheckState elseState;
|
CheckState elseState;
|
||||||
{
|
{
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
|
VL_RESTORER(m_then);
|
||||||
|
m_exprStmtsp = nodep;
|
||||||
|
m_then = true;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateAndNextNull(nodep->thensp());
|
iterateAndNextNull(nodep->thensp());
|
||||||
lineTrack(nodep);
|
lineTrack(nodep);
|
||||||
|
|
@ -429,6 +480,10 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
m_state = lastState;
|
m_state = lastState;
|
||||||
{
|
{
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
|
VL_RESTORER(m_then);
|
||||||
|
m_exprStmtsp = nodep;
|
||||||
|
m_then = false;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateAndNextNull(nodep->elsesp());
|
iterateAndNextNull(nodep->elsesp());
|
||||||
elseState = m_state;
|
elseState = m_state;
|
||||||
|
|
@ -478,6 +533,9 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
m_state = lastState;
|
m_state = lastState;
|
||||||
}
|
}
|
||||||
|
VL_RESTORER(m_ifCond);
|
||||||
|
m_ifCond = true;
|
||||||
|
iterateAndNextNull(nodep->condp());
|
||||||
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
|
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
|
||||||
}
|
}
|
||||||
void visit(AstCaseItem* nodep) override {
|
void visit(AstCaseItem* nodep) override {
|
||||||
|
|
@ -542,6 +600,301 @@ class CoverageVisitor final : public VNVisitor {
|
||||||
lineTrack(nodep);
|
lineTrack(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void abortExprCoverage() {
|
||||||
|
// is possible to hit max while in NONE, see: exprReduce()
|
||||||
|
// if that happens we don't want to set ABORTED if it isn't already
|
||||||
|
// since that will bleed into other expressions
|
||||||
|
if (m_seeking != NONE) m_seeking = ABORTED;
|
||||||
|
m_exprs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkMaxExprs(size_t additional = 0) {
|
||||||
|
if (m_seeking != ABORTED
|
||||||
|
&& static_cast<int>(m_exprs.size() + additional) <= v3Global.opt.coverageExprMax())
|
||||||
|
return false;
|
||||||
|
abortExprCoverage();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addExprCoverInc(AstNodeExpr* nodep, int start = 0) {
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
int count = start;
|
||||||
|
for (CoverExpr& expr : m_exprs) {
|
||||||
|
const string name = "expr_" + std::to_string(count);
|
||||||
|
string comment = "(";
|
||||||
|
bool first = true;
|
||||||
|
AstNodeExpr* condp = nullptr;
|
||||||
|
for (CoverTerm& term : expr) {
|
||||||
|
comment += (first ? "" : " && ") + term.m_emitV
|
||||||
|
+ "==" + (term.m_objective ? "1" : "0");
|
||||||
|
AstNodeExpr* const clonep = term.m_exprp->cloneTree(true);
|
||||||
|
AstNodeExpr* const termp = term.m_objective ? clonep : new AstLogNot{fl, clonep};
|
||||||
|
if (condp) {
|
||||||
|
condp = new AstLogAnd{fl, condp, termp};
|
||||||
|
} else {
|
||||||
|
condp = termp;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
comment += ") => ";
|
||||||
|
comment += (m_objective ? '1' : '0');
|
||||||
|
AstNode* const newp
|
||||||
|
= newCoverInc(fl, "", "v_expr", comment, "", 0, 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);
|
||||||
|
insertProcStatement(m_exprStmtsp, ifp);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void coverExprs(AstNodeExpr* nodep) {
|
||||||
|
if (!m_state.exprCoverageOn(nodep) || nodep->dtypep()->width() != 1 || !m_exprStmtsp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UASSERT_OBJ(m_seeking == NONE, nodep, "recursively covering expressions is not expected");
|
||||||
|
UASSERT_OBJ(m_exprs.empty(), nodep, "unexpected expression coverage garbage");
|
||||||
|
VL_RESTORER(m_seeking);
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
VL_RESTORER(m_exprs);
|
||||||
|
|
||||||
|
m_seeking = SEEKING;
|
||||||
|
m_objective = false;
|
||||||
|
iterate(nodep);
|
||||||
|
CoverExprs falseExprs;
|
||||||
|
m_exprs.swap(falseExprs);
|
||||||
|
|
||||||
|
m_objective = true;
|
||||||
|
iterate(nodep);
|
||||||
|
if (checkMaxExprs(falseExprs.size())) return;
|
||||||
|
|
||||||
|
addExprCoverInc(nodep);
|
||||||
|
const int start = m_exprs.size();
|
||||||
|
m_objective = false;
|
||||||
|
m_exprs.swap(falseExprs);
|
||||||
|
addExprCoverInc(nodep, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exprEither(AstNodeBiop* nodep, bool overrideObjective = false, bool lObjective = false,
|
||||||
|
bool rObjective = false) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
AstNodeExpr* const rhsp = nodep->rhsp();
|
||||||
|
|
||||||
|
if (overrideObjective) m_objective = lObjective;
|
||||||
|
iterate(lhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs lhsExprs;
|
||||||
|
m_exprs.swap(lhsExprs);
|
||||||
|
if (overrideObjective) m_objective = rObjective;
|
||||||
|
iterate(rhsp);
|
||||||
|
m_exprs.splice(m_exprs.end(), lhsExprs);
|
||||||
|
checkMaxExprs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void exprBoth(AstNodeBiop* nodep, bool overrideObjective = false, bool lObjective = false,
|
||||||
|
bool rObjective = false) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
AstNodeExpr* const rhsp = nodep->rhsp();
|
||||||
|
|
||||||
|
if (overrideObjective) m_objective = lObjective;
|
||||||
|
iterate(lhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs lhsExprs;
|
||||||
|
m_exprs.swap(lhsExprs);
|
||||||
|
if (overrideObjective) m_objective = rObjective;
|
||||||
|
iterate(rhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs rhsExprs;
|
||||||
|
m_exprs.swap(rhsExprs);
|
||||||
|
|
||||||
|
for (CoverExpr& l : lhsExprs) {
|
||||||
|
for (CoverExpr& r : rhsExprs) {
|
||||||
|
// array size 2 -> (false, true)
|
||||||
|
std::array<std::set<AstVar*>, 2> varps;
|
||||||
|
std::array<std::set<std::string>, 2> strs;
|
||||||
|
|
||||||
|
UASSERT_OBJ(!l.empty() && !r.empty(), nodep, "Empty coverage expression branch");
|
||||||
|
CoverExpr expr;
|
||||||
|
|
||||||
|
// Compare Vars for simple VarRefs otherwise compare stringified terms
|
||||||
|
// remove redundant terms and remove entire expression branches when
|
||||||
|
// terms conflict
|
||||||
|
// Equivalent terms which don't match on either of these criteria will
|
||||||
|
// not be flagged as redundant or impossible, however the results will
|
||||||
|
// still be valid, albeit messier
|
||||||
|
for (CoverTerm& term : l) {
|
||||||
|
if (AstNodeVarRef* const refp = VN_CAST(term.m_exprp, NodeVarRef)) {
|
||||||
|
varps[term.m_objective].insert(refp->varp());
|
||||||
|
} else {
|
||||||
|
strs[term.m_objective].insert(term.m_emitV);
|
||||||
|
}
|
||||||
|
expr.push_back(term);
|
||||||
|
}
|
||||||
|
bool impossible = false;
|
||||||
|
for (CoverTerm& term : r) {
|
||||||
|
bool redundant = false;
|
||||||
|
if (AstNodeVarRef* const refp = VN_CAST(term.m_exprp, NodeVarRef)) {
|
||||||
|
if (varps[term.m_objective].find(refp->varp())
|
||||||
|
!= varps[term.m_objective].end())
|
||||||
|
redundant = true;
|
||||||
|
if (varps[!term.m_objective].find(refp->varp())
|
||||||
|
!= varps[!term.m_objective].end())
|
||||||
|
impossible = true;
|
||||||
|
} else {
|
||||||
|
if (strs[term.m_objective].find(term.m_emitV)
|
||||||
|
!= strs[term.m_objective].end())
|
||||||
|
redundant = true;
|
||||||
|
if (strs[!term.m_objective].find(term.m_emitV)
|
||||||
|
!= strs[!term.m_objective].end())
|
||||||
|
impossible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!redundant) expr.push_back(term);
|
||||||
|
}
|
||||||
|
if (!impossible) m_exprs.push_back(std::move(expr));
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void orExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprEither(nodep);
|
||||||
|
} else {
|
||||||
|
exprBoth(nodep);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstLogOr* nodep) override { orExpr(nodep); }
|
||||||
|
void visit(AstOr* nodep) override { orExpr(nodep); }
|
||||||
|
|
||||||
|
void andExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprBoth(nodep);
|
||||||
|
} else {
|
||||||
|
exprEither(nodep);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstLogAnd* nodep) override { andExpr(nodep); }
|
||||||
|
void visit(AstAnd* nodep) override { andExpr(nodep); }
|
||||||
|
|
||||||
|
void xorExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
for (const bool lObjective : {false, true}) {
|
||||||
|
CoverExprs prevExprs;
|
||||||
|
m_exprs.swap(prevExprs);
|
||||||
|
const bool rObjective = lObjective ^ m_objective;
|
||||||
|
exprBoth(nodep, true, lObjective, rObjective);
|
||||||
|
m_exprs.splice(m_exprs.end(), prevExprs);
|
||||||
|
if (checkMaxExprs()) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstXor* nodep) override { xorExpr(nodep); }
|
||||||
|
|
||||||
|
void exprNot(AstNodeExpr* nodep) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
m_objective = !m_objective;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstNot* nodep) override { exprNot(nodep); }
|
||||||
|
void visit(AstLogNot* nodep) override { exprNot(nodep); }
|
||||||
|
|
||||||
|
template <typename T_Oper>
|
||||||
|
void exprReduce(AstNodeUniop* nodep) {
|
||||||
|
if (m_seeking != ABORTED) {
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
const int width = lhsp->dtypep()->width();
|
||||||
|
const size_t expected = std::is_same<T_Oper, AstXor>::value ? 0x1 << width : width + 1;
|
||||||
|
if (checkMaxExprs(expected)) return;
|
||||||
|
AstNodeExpr* unrolledp = new AstSel{fl, lhsp->cloneTree(true),
|
||||||
|
new AstConst{fl, static_cast<uint32_t>(width - 1)},
|
||||||
|
new AstConst{fl, 1}};
|
||||||
|
for (int bit = width - 2; bit >= 0; bit--) {
|
||||||
|
AstSel* const selp = new AstSel{fl, lhsp->cloneTree(true),
|
||||||
|
new AstConst{fl, static_cast<uint32_t>(bit)},
|
||||||
|
new AstConst{fl, 1}};
|
||||||
|
unrolledp = new T_Oper{fl, selp, unrolledp};
|
||||||
|
}
|
||||||
|
iterate(unrolledp);
|
||||||
|
pushDeletep(unrolledp);
|
||||||
|
} else {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstRedOr* nodep) override { exprReduce<AstOr>(nodep); }
|
||||||
|
void visit(AstRedAnd* nodep) override { exprReduce<AstAnd>(nodep); }
|
||||||
|
void visit(AstRedXor* nodep) override { exprReduce<AstXor>(nodep); }
|
||||||
|
|
||||||
|
void visit(AstLogIf* nodep) override {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprEither(nodep, true, false, true);
|
||||||
|
} else {
|
||||||
|
exprBoth(nodep, true, true, false);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstLogEq* nodep) override {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
m_objective = !m_objective;
|
||||||
|
xorExpr(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstCond* nodep) override {
|
||||||
|
if (m_seeking == NONE) coverExprs(nodep->condp());
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambdas not supported for expression coverage
|
||||||
|
void visit(AstWith* nodep) override {
|
||||||
|
VL_RESTORER(m_seeking);
|
||||||
|
if (m_seeking == SEEKING) abortExprCoverage();
|
||||||
|
m_seeking = ABORTED;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstNodeExpr* nodep) override {
|
||||||
|
if (m_seeking != SEEKING) {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
} else {
|
||||||
|
std::stringstream emitV;
|
||||||
|
V3EmitV::verilogForTree(nodep, emitV);
|
||||||
|
// Add new expression with a single term
|
||||||
|
CoverExpr expr;
|
||||||
|
expr.emplace_back(nodep, m_objective, emitV.str());
|
||||||
|
m_exprs.push_back(std::move(expr));
|
||||||
|
checkMaxExprs();
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS - BOTH
|
// VISITORS - BOTH
|
||||||
void visit(AstNode* nodep) override {
|
void visit(AstNode* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
|
||||||
|
|
@ -1238,6 +1238,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
||||||
DECL_OPTION("-compiler-include", CbVal, callStrSetter(&V3Options::addCompilerIncludes));
|
DECL_OPTION("-compiler-include", CbVal, callStrSetter(&V3Options::addCompilerIncludes));
|
||||||
DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
|
DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
|
||||||
DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
|
DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
|
||||||
|
DECL_OPTION("-coverage-expr", OnOff, &m_coverageExpr);
|
||||||
|
DECL_OPTION("-coverage-expr-max", Set, &m_coverageExprMax);
|
||||||
DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
|
DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
|
||||||
DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
|
DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
|
||||||
DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
|
DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ private:
|
||||||
bool m_build = false; // main switch: --build
|
bool m_build = false; // main switch: --build
|
||||||
bool m_cmake = false; // main switch: --make cmake
|
bool m_cmake = false; // main switch: --make cmake
|
||||||
bool m_context = true; // main switch: --Wcontext
|
bool m_context = true; // main switch: --Wcontext
|
||||||
|
bool m_coverageExpr = false; // main switch: --coverage-expr
|
||||||
bool m_coverageLine = false; // main switch: --coverage-block
|
bool m_coverageLine = false; // main switch: --coverage-block
|
||||||
bool m_coverageToggle = false; // main switch: --coverage-toggle
|
bool m_coverageToggle = false; // main switch: --coverage-toggle
|
||||||
bool m_coverageUnderscore = false; // main switch: --coverage-underscore
|
bool m_coverageUnderscore = false; // main switch: --coverage-underscore
|
||||||
|
|
@ -305,6 +306,7 @@ private:
|
||||||
bool m_xmlOnly = false; // main switch: --xml-only
|
bool m_xmlOnly = false; // main switch: --xml-only
|
||||||
|
|
||||||
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
||||||
|
int m_coverageExprMax = 32; // main switch: --coverage-expr-max
|
||||||
int m_convergeLimit = 100; // main switch: --converge-limit
|
int m_convergeLimit = 100; // main switch: --converge-limit
|
||||||
int m_coverageMaxWidth = 256; // main switch: --coverage-max-width
|
int m_coverageMaxWidth = 256; // main switch: --coverage-max-width
|
||||||
int m_expandLimit = 64; // main switch: --expand-limit
|
int m_expandLimit = 64; // main switch: --expand-limit
|
||||||
|
|
@ -426,7 +428,9 @@ private:
|
||||||
void addLibExtV(const string& libext);
|
void addLibExtV(const string& libext);
|
||||||
void optimize(int level);
|
void optimize(int level);
|
||||||
void showVersion(bool verbose);
|
void showVersion(bool verbose);
|
||||||
void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
|
void coverage(bool flag) {
|
||||||
|
m_coverageLine = m_coverageToggle = m_coverageExpr = m_coverageUser = flag;
|
||||||
|
}
|
||||||
static bool suffixed(const string& sw, const char* arg);
|
static bool suffixed(const string& sw, const char* arg);
|
||||||
static string parseFileArg(const string& optdir, const string& relfilename);
|
static string parseFileArg(const string& optdir, const string& relfilename);
|
||||||
string filePathCheckOneDir(const string& modname, const string& dirname);
|
string filePathCheckOneDir(const string& modname, const string& dirname);
|
||||||
|
|
@ -488,8 +492,9 @@ public:
|
||||||
bool cmake() const { return m_cmake; }
|
bool cmake() const { return m_cmake; }
|
||||||
bool context() const VL_MT_SAFE { return m_context; }
|
bool context() const VL_MT_SAFE { return m_context; }
|
||||||
bool coverage() const VL_MT_SAFE {
|
bool coverage() const VL_MT_SAFE {
|
||||||
return m_coverageLine || m_coverageToggle || m_coverageUser;
|
return m_coverageLine || m_coverageToggle || m_coverageExpr || m_coverageUser;
|
||||||
}
|
}
|
||||||
|
bool coverageExpr() const { return m_coverageExpr; }
|
||||||
bool coverageLine() const { return m_coverageLine; }
|
bool coverageLine() const { return m_coverageLine; }
|
||||||
bool coverageToggle() const { return m_coverageToggle; }
|
bool coverageToggle() const { return m_coverageToggle; }
|
||||||
bool coverageUnderscore() const { return m_coverageUnderscore; }
|
bool coverageUnderscore() const { return m_coverageUnderscore; }
|
||||||
|
|
@ -565,6 +570,7 @@ public:
|
||||||
|
|
||||||
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
|
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
|
||||||
int convergeLimit() const { return m_convergeLimit; }
|
int convergeLimit() const { return m_convergeLimit; }
|
||||||
|
int coverageExprMax() const { return m_coverageExprMax; }
|
||||||
int coverageMaxWidth() const { return m_coverageMaxWidth; }
|
int coverageMaxWidth() const { return m_coverageMaxWidth; }
|
||||||
bool dumpTreeAddrids() const VL_MT_SAFE;
|
bool dumpTreeAddrids() const VL_MT_SAFE;
|
||||||
int expandLimit() const { return m_expandLimit; }
|
int expandLimit() const { return m_expandLimit; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,317 @@
|
||||||
|
// // verilator_coverage annotation
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc;
|
||||||
|
initial cyc=1;
|
||||||
|
|
||||||
|
integer some_int;
|
||||||
|
integer other_int;
|
||||||
|
logic some_bool;
|
||||||
|
|
||||||
|
wire t1 = cyc[0];
|
||||||
|
wire t2 = cyc[1];
|
||||||
|
wire t3 = cyc[2];
|
||||||
|
wire t4 = cyc[3];
|
||||||
|
|
||||||
|
localparam bit ONE = 1'b1;
|
||||||
|
localparam bit ZERO = 1'b0;
|
||||||
|
|
||||||
|
function automatic bit invert(bit x);
|
||||||
|
000015 return ~x;
|
||||||
|
+000012 point: comment=(x==0) => 1 hier=top.t
|
||||||
|
+000015 point: comment=(x==1) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic bit and_oper(bit a, bit b);
|
||||||
|
%000005 return a & b;
|
||||||
|
-000004 point: comment=(a==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(a==1 && b==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(b==0) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
%000004 if ((~cyc[0] && cyc[1]) || (~cyc[2] && cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[0]==0 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==1 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[1]==0 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[1]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000004 if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000005 if (t3 && (t1 == t2)) $write("");
|
||||||
|
-000005 point: comment=((t1 == t2)==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==1 && (t1 == t2)==1) => 1 hier=top.t
|
||||||
|
%000005 if (123 == (124 - 32'(t1 || t2))) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000004 some_int <= (t2 || t3) ? 345 : 567;
|
||||||
|
-000003 point: comment=(t2==0 && t3==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t3==1) => 1 hier=top.t
|
||||||
|
%000005 some_bool <= t1 && t2;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000004 if ((!t1 && t2) | (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 ^ t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
%000005 if (~(t1 & t2)) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 1 hier=top.t
|
||||||
|
%000004 if (t1 -> t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 <-> t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
%000005 if (&cyc[2:0]) $write("");
|
||||||
|
-000004 point: comment=(cyc[2:0][0]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][1]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
%000007 if (&cyc[3:2]) $write("");
|
||||||
|
-000005 point: comment=(cyc[3:2][0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[3:2][0]==1 && cyc[3:2][1]==1) => 1 hier=top.t
|
||||||
|
-000007 point: comment=(cyc[3:2][1]==0) => 0 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000002 if (^cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0] || cyc[3]) $write("");
|
||||||
|
-000000 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & 1'b1) $write("");
|
||||||
|
-000000 point: comment=(1'h1==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && 1'h1==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & 1'b0) $write("");
|
||||||
|
-000009 point: comment=(1'h0==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && 1'h0==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & ONE) $write("");
|
||||||
|
-000000 point: comment=(ONE==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && ONE==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & ZERO) $write("");
|
||||||
|
-000009 point: comment=(ZERO==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && ZERO==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 && t2) begin
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
$write("");
|
||||||
|
%000003 end else if (t1 || t2) begin
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
$write("");
|
||||||
|
end
|
||||||
|
%000005 if (invert(t1) && t2) $write("");
|
||||||
|
-000005 point: comment=(invert(t1)==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(invert(t1)==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
if (and_oper(t1, t2)) $write("");
|
||||||
|
%000005 if (t2 && t3) begin
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1 && t3==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
%000001 if (t1 && t2) $write("");
|
||||||
|
-000001 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
if (0 == 1) begin
|
||||||
|
for (int loop_var = 0; loop_var < 1; loop_var++) begin
|
||||||
|
%000000 if (cyc[loop_var] && t2) $write("");
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// stop at the first layer even if there's more to find
|
||||||
|
%000007 if ((cyc[3+32'(t1 && t2)+:2] == cyc[5+32'(t3 || t4)+:2]) || cyc[31]) $write("");
|
||||||
|
-000002 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==0 && cyc[31]==0) => 0 hier=top.t
|
||||||
|
-000007 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[31]==1) => 1 hier=top.t
|
||||||
|
// impossible branches and redundant terms
|
||||||
|
%000005 if ((t1 && t2) && ~(t1 && t3) && (t1 || t4)) $write("");
|
||||||
|
-000003 point: comment=(t1==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1 && t3==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[0] && cyc[2]) && (cyc[0] || cyc[3])) $write("");
|
||||||
|
-000003 point: comment=(cyc[0]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
// demonstrate current limitations of term matching scheme
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[1-1] && cyc[2]) && (cyc[2-2] || cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
//verilator coverage_off
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
//verilator coverage_on
|
||||||
|
if ((~t1 && t2)
|
||||||
|
%000004 ||
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
(~t3 && t4)) $write("");
|
||||||
|
// intentionally testing wonkified expression terms
|
||||||
|
if (
|
||||||
|
cyc[
|
||||||
|
0
|
||||||
|
%000005 ] &
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
cyc
|
||||||
|
[1]) $write("");
|
||||||
|
// for now each ternary condition is considered in isolation
|
||||||
|
%000005 other_int <= t1 ? t2 ? 1 : 2 : 3;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
// no expression coverage for multi-bit expressions
|
||||||
|
if ((cyc[1:0] & cyc[3:2]) == 2'b11) $write("");
|
||||||
|
// truth table is too large
|
||||||
|
if (^cyc[6:0]) $write("");
|
||||||
|
// this one is too big even for t_cover_expr_max
|
||||||
|
if (^cyc) $write("");
|
||||||
|
if (cyc==9) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
%000005 if (t1 && t2) $write("");
|
||||||
|
-000005 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
|
||||||
|
logic ta, tb, tc;
|
||||||
|
initial begin
|
||||||
|
int q[5];
|
||||||
|
int qv[$];
|
||||||
|
|
||||||
|
q = '{1, 2, 2, 4, 3};
|
||||||
|
// lambas not handled
|
||||||
|
// NB: there is a bug w/ tracing find_first (maybe lambdas in general?)
|
||||||
|
// tracing_off does not work around the bug
|
||||||
|
qv = q.find_first with (item[0] & item[1]);
|
||||||
|
ta = '1;
|
||||||
|
tb = '0;
|
||||||
|
tc = '0;
|
||||||
|
%000001 while (ta || tb || tc) begin
|
||||||
|
-000001 point: comment=(ta==0 && tb==0 && tc==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(ta==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tb==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tc==1) => 1 hier=top.t
|
||||||
|
tc = tb;
|
||||||
|
tb = ta;
|
||||||
|
ta = '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sub the_sub_1 (.p(t1), .q(t2));
|
||||||
|
sub the_sub_2 (.p(t3), .q(t4));
|
||||||
|
// TODO -- non-process expressions
|
||||||
|
sub the_sub_3 (.p(t1 ? t2 : t3), .q(t4));
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// pragma for expr coverage off / on
|
||||||
|
// investigate cover point sorting in annotated source
|
||||||
|
// consider reporting don't care terms
|
||||||
|
//
|
||||||
|
// Branches which are statically impossible to reach are still reported.
|
||||||
|
// E.g.
|
||||||
|
// -000000 point: comment=(t1=1 && t2=1 && 1'h0=1) => 1 hier=top.t
|
||||||
|
// These could potentially be pruned, but they currently follow suit for
|
||||||
|
// what branch coverage does. Perhaps a switch should be added to not
|
||||||
|
// count statically impossible things.
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (
|
||||||
|
input p,
|
||||||
|
input q
|
||||||
|
);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
~000019 if (p && q) $write("");
|
||||||
|
+000017 point: comment=(p==0) => 0 hier=top.t.the_sub_*
|
||||||
|
-000002 point: comment=(p==1 && q==1) => 1 hier=top.t.the_sub_*
|
||||||
|
+000019 point: comment=(q==0) => 0 hier=top.t.the_sub_*
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=['--cc', '--coverage-expr'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
# Read the input .v file and do any CHECK_COVER requests
|
||||||
|
test.inline_checks()
|
||||||
|
|
||||||
|
test.run(cmd=[
|
||||||
|
os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage",
|
||||||
|
"--annotate-points",
|
||||||
|
"--annotate",
|
||||||
|
test.obj_dir + "/annotated",
|
||||||
|
test.obj_dir + "/coverage.dat",
|
||||||
|
],
|
||||||
|
verilator_run=True)
|
||||||
|
|
||||||
|
top = Path(test.top_filename)
|
||||||
|
test.files_identical(test.obj_dir + f"/annotated/{top.name}", test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc;
|
||||||
|
initial cyc=1;
|
||||||
|
|
||||||
|
integer some_int;
|
||||||
|
integer other_int;
|
||||||
|
logic some_bool;
|
||||||
|
|
||||||
|
wire t1 = cyc[0];
|
||||||
|
wire t2 = cyc[1];
|
||||||
|
wire t3 = cyc[2];
|
||||||
|
wire t4 = cyc[3];
|
||||||
|
|
||||||
|
localparam bit ONE = 1'b1;
|
||||||
|
localparam bit ZERO = 1'b0;
|
||||||
|
|
||||||
|
function automatic bit invert(bit x);
|
||||||
|
return ~x;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic bit and_oper(bit a, bit b);
|
||||||
|
return a & b;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
if ((~cyc[0] && cyc[1]) || (~cyc[2] && cyc[3])) $write("");
|
||||||
|
if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
if (t3 && (t1 == t2)) $write("");
|
||||||
|
if (123 == (124 - 32'(t1 || t2))) $write("");
|
||||||
|
some_int <= (t2 || t3) ? 345 : 567;
|
||||||
|
some_bool <= t1 && t2;
|
||||||
|
if (t1 & t2) $write("");
|
||||||
|
if ((!t1 && t2) | (~t3 && t4)) $write("");
|
||||||
|
if (t1 ^ t2) $write("");
|
||||||
|
if (~(t1 & t2)) $write("");
|
||||||
|
if (t1 -> t2) $write("");
|
||||||
|
if (t1 <-> t2) $write("");
|
||||||
|
if (&cyc[2:0]) $write("");
|
||||||
|
if (&cyc[3:2]) $write("");
|
||||||
|
if (|cyc[2:0]) $write("");
|
||||||
|
if (^cyc[2:0]) $write("");
|
||||||
|
if (|cyc[2:0] || cyc[3]) $write("");
|
||||||
|
if (t1 & t2 & 1'b1) $write("");
|
||||||
|
if (t1 & t2 & 1'b0) $write("");
|
||||||
|
if (t1 & t2 & ONE) $write("");
|
||||||
|
if (t1 & t2 & ZERO) $write("");
|
||||||
|
if (t1 && t2) begin
|
||||||
|
$write("");
|
||||||
|
end else if (t1 || t2) begin
|
||||||
|
$write("");
|
||||||
|
end
|
||||||
|
if (invert(t1) && t2) $write("");
|
||||||
|
if (and_oper(t1, t2)) $write("");
|
||||||
|
if (t2 && t3) begin
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
end
|
||||||
|
if (0 == 1) begin
|
||||||
|
for (int loop_var = 0; loop_var < 1; loop_var++) begin
|
||||||
|
if (cyc[loop_var] && t2) $write("");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// stop at the first layer even if there's more to find
|
||||||
|
if ((cyc[3+32'(t1 && t2)+:2] == cyc[5+32'(t3 || t4)+:2]) || cyc[31]) $write("");
|
||||||
|
// impossible branches and redundant terms
|
||||||
|
if ((t1 && t2) && ~(t1 && t3) && (t1 || t4)) $write("");
|
||||||
|
if ((cyc[0] && cyc[1]) && ~(cyc[0] && cyc[2]) && (cyc[0] || cyc[3])) $write("");
|
||||||
|
// demonstrate current limitations of term matching scheme
|
||||||
|
if ((cyc[0] && cyc[1]) && ~(cyc[1-1] && cyc[2]) && (cyc[2-2] || cyc[3])) $write("");
|
||||||
|
//verilator coverage_off
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
//verilator coverage_on
|
||||||
|
if ((~t1 && t2)
|
||||||
|
||
|
||||||
|
(~t3 && t4)) $write("");
|
||||||
|
// intentionally testing wonkified expression terms
|
||||||
|
if (
|
||||||
|
cyc[
|
||||||
|
0
|
||||||
|
] &
|
||||||
|
cyc
|
||||||
|
[1]) $write("");
|
||||||
|
// for now each ternary condition is considered in isolation
|
||||||
|
other_int <= t1 ? t2 ? 1 : 2 : 3;
|
||||||
|
// no expression coverage for multi-bit expressions
|
||||||
|
if ((cyc[1:0] & cyc[3:2]) == 2'b11) $write("");
|
||||||
|
// truth table is too large
|
||||||
|
if (^cyc[6:0]) $write("");
|
||||||
|
// this one is too big even for t_cover_expr_max
|
||||||
|
if (^cyc) $write("");
|
||||||
|
if (cyc==9) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
end
|
||||||
|
|
||||||
|
logic ta, tb, tc;
|
||||||
|
initial begin
|
||||||
|
int q[5];
|
||||||
|
int qv[$];
|
||||||
|
|
||||||
|
q = '{1, 2, 2, 4, 3};
|
||||||
|
// lambas not handled
|
||||||
|
// NB: there is a bug w/ tracing find_first (maybe lambdas in general?)
|
||||||
|
// tracing_off does not work around the bug
|
||||||
|
qv = q.find_first with (item[0] & item[1]);
|
||||||
|
ta = '1;
|
||||||
|
tb = '0;
|
||||||
|
tc = '0;
|
||||||
|
while (ta || tb || tc) begin
|
||||||
|
tc = tb;
|
||||||
|
tb = ta;
|
||||||
|
ta = '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sub the_sub_1 (.p(t1), .q(t2));
|
||||||
|
sub the_sub_2 (.p(t3), .q(t4));
|
||||||
|
// TODO -- non-process expressions
|
||||||
|
sub the_sub_3 (.p(t1 ? t2 : t3), .q(t4));
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// pragma for expr coverage off / on
|
||||||
|
// investigate cover point sorting in annotated source
|
||||||
|
// consider reporting don't care terms
|
||||||
|
//
|
||||||
|
// Branches which are statically impossible to reach are still reported.
|
||||||
|
// E.g.
|
||||||
|
// -000000 point: comment=(t1=1 && t2=1 && 1'h0=1) => 1 hier=top.t
|
||||||
|
// These could potentially be pruned, but they currently follow suit for
|
||||||
|
// what branch coverage does. Perhaps a switch should be added to not
|
||||||
|
// count statically impossible things.
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (
|
||||||
|
input p,
|
||||||
|
input q
|
||||||
|
);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
if (p && q) $write("");
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,445 @@
|
||||||
|
// // verilator_coverage annotation
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc;
|
||||||
|
initial cyc=1;
|
||||||
|
|
||||||
|
integer some_int;
|
||||||
|
integer other_int;
|
||||||
|
logic some_bool;
|
||||||
|
|
||||||
|
wire t1 = cyc[0];
|
||||||
|
wire t2 = cyc[1];
|
||||||
|
wire t3 = cyc[2];
|
||||||
|
wire t4 = cyc[3];
|
||||||
|
|
||||||
|
localparam bit ONE = 1'b1;
|
||||||
|
localparam bit ZERO = 1'b0;
|
||||||
|
|
||||||
|
function automatic bit invert(bit x);
|
||||||
|
000015 return ~x;
|
||||||
|
+000012 point: comment=(x==0) => 1 hier=top.t
|
||||||
|
+000015 point: comment=(x==1) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic bit and_oper(bit a, bit b);
|
||||||
|
%000005 return a & b;
|
||||||
|
-000004 point: comment=(a==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(a==1 && b==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(b==0) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
%000004 if ((~cyc[0] && cyc[1]) || (~cyc[2] && cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[0]==0 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==1 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[1]==0 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[1]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000004 if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000005 if (t3 && (t1 == t2)) $write("");
|
||||||
|
-000005 point: comment=((t1 == t2)==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==1 && (t1 == t2)==1) => 1 hier=top.t
|
||||||
|
%000005 if (123 == (124 - 32'(t1 || t2))) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000004 some_int <= (t2 || t3) ? 345 : 567;
|
||||||
|
-000003 point: comment=(t2==0 && t3==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t3==1) => 1 hier=top.t
|
||||||
|
%000005 some_bool <= t1 && t2;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000004 if ((!t1 && t2) | (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 ^ t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
%000005 if (~(t1 & t2)) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 1 hier=top.t
|
||||||
|
%000004 if (t1 -> t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 <-> t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
%000005 if (&cyc[2:0]) $write("");
|
||||||
|
-000004 point: comment=(cyc[2:0][0]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][1]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
%000007 if (&cyc[3:2]) $write("");
|
||||||
|
-000005 point: comment=(cyc[3:2][0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[3:2][0]==1 && cyc[3:2][1]==1) => 1 hier=top.t
|
||||||
|
-000007 point: comment=(cyc[3:2][1]==0) => 0 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000002 if (^cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0] || cyc[3]) $write("");
|
||||||
|
-000000 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & 1'b1) $write("");
|
||||||
|
-000000 point: comment=(1'h1==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && 1'h1==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & 1'b0) $write("");
|
||||||
|
-000009 point: comment=(1'h0==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && 1'h0==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & ONE) $write("");
|
||||||
|
-000000 point: comment=(ONE==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && ONE==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & ZERO) $write("");
|
||||||
|
-000009 point: comment=(ZERO==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && ZERO==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 && t2) begin
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
$write("");
|
||||||
|
%000003 end else if (t1 || t2) begin
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
$write("");
|
||||||
|
end
|
||||||
|
%000005 if (invert(t1) && t2) $write("");
|
||||||
|
-000005 point: comment=(invert(t1)==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(invert(t1)==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
if (and_oper(t1, t2)) $write("");
|
||||||
|
%000005 if (t2 && t3) begin
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1 && t3==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
%000001 if (t1 && t2) $write("");
|
||||||
|
-000001 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
if (0 == 1) begin
|
||||||
|
for (int loop_var = 0; loop_var < 1; loop_var++) begin
|
||||||
|
%000000 if (cyc[loop_var] && t2) $write("");
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// stop at the first layer even if there's more to find
|
||||||
|
%000007 if ((cyc[3+32'(t1 && t2)+:2] == cyc[5+32'(t3 || t4)+:2]) || cyc[31]) $write("");
|
||||||
|
-000002 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==0 && cyc[31]==0) => 0 hier=top.t
|
||||||
|
-000007 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[31]==1) => 1 hier=top.t
|
||||||
|
// impossible branches and redundant terms
|
||||||
|
%000005 if ((t1 && t2) && ~(t1 && t3) && (t1 || t4)) $write("");
|
||||||
|
-000003 point: comment=(t1==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1 && t3==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[0] && cyc[2]) && (cyc[0] || cyc[3])) $write("");
|
||||||
|
-000003 point: comment=(cyc[0]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
// demonstrate current limitations of term matching scheme
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[1-1] && cyc[2]) && (cyc[2-2] || cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
//verilator coverage_off
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
//verilator coverage_on
|
||||||
|
if ((~t1 && t2)
|
||||||
|
%000004 ||
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
(~t3 && t4)) $write("");
|
||||||
|
// intentionally testing wonkified expression terms
|
||||||
|
if (
|
||||||
|
cyc[
|
||||||
|
0
|
||||||
|
%000005 ] &
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
cyc
|
||||||
|
[1]) $write("");
|
||||||
|
// for now each ternary condition is considered in isolation
|
||||||
|
%000005 other_int <= t1 ? t2 ? 1 : 2 : 3;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
// no expression coverage for multi-bit expressions
|
||||||
|
if ((cyc[1:0] & cyc[3:2]) == 2'b11) $write("");
|
||||||
|
// truth table is too large
|
||||||
|
%000001 if (^cyc[6:0]) $write("");
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==0 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==0 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==0 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==0 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==0 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==0) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==0 && cyc[6:0][6]==1) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[6:0][0]==1 && cyc[6:0][1]==1 && cyc[6:0][2]==1 && cyc[6:0][3]==1 && cyc[6:0][4]==1 && cyc[6:0][5]==1 && cyc[6:0][6]==1) => 1 hier=top.t
|
||||||
|
// this one is too big even for t_cover_expr_max
|
||||||
|
if (^cyc) $write("");
|
||||||
|
if (cyc==9) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
%000005 if (t1 && t2) $write("");
|
||||||
|
-000005 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
|
||||||
|
logic ta, tb, tc;
|
||||||
|
initial begin
|
||||||
|
int q[5];
|
||||||
|
int qv[$];
|
||||||
|
|
||||||
|
q = '{1, 2, 2, 4, 3};
|
||||||
|
// lambas not handled
|
||||||
|
// NB: there is a bug w/ tracing find_first (maybe lambdas in general?)
|
||||||
|
// tracing_off does not work around the bug
|
||||||
|
qv = q.find_first with (item[0] & item[1]);
|
||||||
|
ta = '1;
|
||||||
|
tb = '0;
|
||||||
|
tc = '0;
|
||||||
|
%000001 while (ta || tb || tc) begin
|
||||||
|
-000001 point: comment=(ta==0 && tb==0 && tc==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(ta==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tb==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tc==1) => 1 hier=top.t
|
||||||
|
tc = tb;
|
||||||
|
tb = ta;
|
||||||
|
ta = '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sub the_sub_1 (.p(t1), .q(t2));
|
||||||
|
sub the_sub_2 (.p(t3), .q(t4));
|
||||||
|
// TODO -- non-process expressions
|
||||||
|
sub the_sub_3 (.p(t1 ? t2 : t3), .q(t4));
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// pragma for expr coverage off / on
|
||||||
|
// investigate cover point sorting in annotated source
|
||||||
|
// consider reporting don't care terms
|
||||||
|
//
|
||||||
|
// Branches which are statically impossible to reach are still reported.
|
||||||
|
// E.g.
|
||||||
|
// -000000 point: comment=(t1=1 && t2=1 && 1'h0=1) => 1 hier=top.t
|
||||||
|
// These could potentially be pruned, but they currently follow suit for
|
||||||
|
// what branch coverage does. Perhaps a switch should be added to not
|
||||||
|
// count statically impossible things.
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (
|
||||||
|
input p,
|
||||||
|
input q
|
||||||
|
);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
~000019 if (p && q) $write("");
|
||||||
|
+000017 point: comment=(p==0) => 0 hier=top.t.the_sub_*
|
||||||
|
-000002 point: comment=(p==1 && q==1) => 1 hier=top.t.the_sub_*
|
||||||
|
+000019 point: comment=(q==0) => 0 hier=top.t.the_sub_*
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
test.top_filename = "t/t_cover_expr.v"
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=['--cc', '--coverage-expr', '--coverage-expr-max', '128'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
# Read the input .v file and do any CHECK_COVER requests
|
||||||
|
test.inline_checks()
|
||||||
|
|
||||||
|
test.run(cmd=[
|
||||||
|
os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage",
|
||||||
|
"--annotate-points",
|
||||||
|
"--annotate",
|
||||||
|
test.obj_dir + "/annotated",
|
||||||
|
test.obj_dir + "/coverage.dat",
|
||||||
|
],
|
||||||
|
verilator_run=True)
|
||||||
|
|
||||||
|
top = Path(test.top_filename)
|
||||||
|
test.files_identical(test.obj_dir + f"/annotated/{top.name}", test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,317 @@
|
||||||
|
// // verilator_coverage annotation
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2024 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc;
|
||||||
|
initial cyc=1;
|
||||||
|
|
||||||
|
integer some_int;
|
||||||
|
integer other_int;
|
||||||
|
logic some_bool;
|
||||||
|
|
||||||
|
wire t1 = cyc[0];
|
||||||
|
wire t2 = cyc[1];
|
||||||
|
wire t3 = cyc[2];
|
||||||
|
wire t4 = cyc[3];
|
||||||
|
|
||||||
|
localparam bit ONE = 1'b1;
|
||||||
|
localparam bit ZERO = 1'b0;
|
||||||
|
|
||||||
|
function automatic bit invert(bit x);
|
||||||
|
000015 return ~x;
|
||||||
|
+000012 point: comment=(x==0) => 1 hier=top.t
|
||||||
|
+000015 point: comment=(x==1) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic bit and_oper(bit a, bit b);
|
||||||
|
%000005 return a & b;
|
||||||
|
-000004 point: comment=(a==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(a==1 && b==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(b==0) => 0 hier=top.t
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
%000004 if ((~cyc[0] && cyc[1]) || (~cyc[2] && cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[0]==0 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==1 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[1]==0 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[1]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000004 if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000005 if (t3 && (t1 == t2)) $write("");
|
||||||
|
-000005 point: comment=((t1 == t2)==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==1 && (t1 == t2)==1) => 1 hier=top.t
|
||||||
|
%000005 if (123 == (124 - 32'(t1 || t2))) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000004 some_int <= (t2 || t3) ? 345 : 567;
|
||||||
|
-000003 point: comment=(t2==0 && t3==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(t3==1) => 1 hier=top.t
|
||||||
|
%000005 some_bool <= t1 && t2;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000004 if ((!t1 && t2) | (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 ^ t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
%000005 if (~(t1 & t2)) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 1 hier=top.t
|
||||||
|
%000004 if (t1 -> t2) $write("");
|
||||||
|
-000004 point: comment=(t1==0) => 1 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
%000003 if (t1 <-> t2) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1 && t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
%000005 if (&cyc[2:0]) $write("");
|
||||||
|
-000004 point: comment=(cyc[2:0][0]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][1]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
%000007 if (&cyc[3:2]) $write("");
|
||||||
|
-000005 point: comment=(cyc[3:2][0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[3:2][0]==1 && cyc[3:2][1]==1) => 1 hier=top.t
|
||||||
|
-000007 point: comment=(cyc[3:2][1]==0) => 0 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000002 if (^cyc[2:0]) $write("");
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==0) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==0 && cyc[2:0][2]==1) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[2:0][0]==1 && cyc[2:0][1]==1 && cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
%000005 if (|cyc[2:0] || cyc[3]) $write("");
|
||||||
|
-000000 point: comment=(cyc[2:0][0]==0 && cyc[2:0][1]==0 && cyc[2:0][2]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[2:0][0]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][1]==1) => 1 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[2:0][2]==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[3]==1) => 1 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & 1'b1) $write("");
|
||||||
|
-000000 point: comment=(1'h1==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && 1'h1==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & 1'b0) $write("");
|
||||||
|
-000009 point: comment=(1'h0==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && 1'h0==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 & t2 & ONE) $write("");
|
||||||
|
-000000 point: comment=(ONE==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1 && ONE==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000009 if (t1 & t2 & ZERO) $write("");
|
||||||
|
-000009 point: comment=(ZERO==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && ZERO==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if (t1 && t2) begin
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
$write("");
|
||||||
|
%000003 end else if (t1 || t2) begin
|
||||||
|
-000002 point: comment=(t1==0 && t2==0) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1) => 1 hier=top.t
|
||||||
|
$write("");
|
||||||
|
end
|
||||||
|
%000005 if (invert(t1) && t2) $write("");
|
||||||
|
-000005 point: comment=(invert(t1)==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(invert(t1)==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
if (and_oper(t1, t2)) $write("");
|
||||||
|
%000005 if (t2 && t3) begin
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==1 && t3==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t3==0) => 0 hier=top.t
|
||||||
|
%000001 if (t1 && t2) $write("");
|
||||||
|
-000001 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
if (0 == 1) begin
|
||||||
|
for (int loop_var = 0; loop_var < 1; loop_var++) begin
|
||||||
|
%000000 if (cyc[loop_var] && t2) $write("");
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[loop_var[4:0]+:32'h1]]==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// stop at the first layer even if there's more to find
|
||||||
|
%000007 if ((cyc[3+32'(t1 && t2)+:2] == cyc[5+32'(t3 || t4)+:2]) || cyc[31]) $write("");
|
||||||
|
-000002 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==0 && cyc[31]==0) => 0 hier=top.t
|
||||||
|
-000007 point: comment=((cyc[(32'sh3 + (t1 && t2))[4:0]+:32'sh2]] == cyc[(32'sh5 + (t3 || t4))[4:0]+:32'sh2]])==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[31]==1) => 1 hier=top.t
|
||||||
|
// impossible branches and redundant terms
|
||||||
|
%000005 if ((t1 && t2) && ~(t1 && t3) && (t1 || t4)) $write("");
|
||||||
|
-000003 point: comment=(t1==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(t1==1 && t2==1 && t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(t1==1 && t2==1 && t3==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[0] && cyc[2]) && (cyc[0] || cyc[3])) $write("");
|
||||||
|
-000003 point: comment=(cyc[0]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
// demonstrate current limitations of term matching scheme
|
||||||
|
%000005 if ((cyc[0] && cyc[1]) && ~(cyc[1-1] && cyc[2]) && (cyc[2-2] || cyc[3])) $write("");
|
||||||
|
-000002 point: comment=(cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==1 && cyc[2]==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==0 && cyc[3]==0) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[(32'sh1 - 32'sh1)[4:0]+:32'h1]]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000001 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[(32'sh2 - 32'sh2)[4:0]+:32'h1]]==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(cyc[0]==1 && cyc[1]==1 && cyc[2]==0 && cyc[3]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
//verilator coverage_off
|
||||||
|
if (t1 && t2) $write("");
|
||||||
|
//verilator coverage_on
|
||||||
|
if ((~t1 && t2)
|
||||||
|
%000004 ||
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
(~t3 && t4)) $write("");
|
||||||
|
// intentionally testing wonkified expression terms
|
||||||
|
if (
|
||||||
|
cyc[
|
||||||
|
0
|
||||||
|
%000005 ] &
|
||||||
|
-000004 point: comment=(cyc[0]==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(cyc[0]==1 && cyc[1]==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(cyc[1]==0) => 0 hier=top.t
|
||||||
|
cyc
|
||||||
|
[1]) $write("");
|
||||||
|
// for now each ternary condition is considered in isolation
|
||||||
|
%000005 other_int <= t1 ? t2 ? 1 : 2 : 3;
|
||||||
|
-000004 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000005 point: comment=(t1==1) => 1 hier=top.t
|
||||||
|
// no expression coverage for multi-bit expressions
|
||||||
|
if ((cyc[1:0] & cyc[3:2]) == 2'b11) $write("");
|
||||||
|
// truth table is too large
|
||||||
|
if (^cyc[6:0]) $write("");
|
||||||
|
// this one is too big even for t_cover_expr_max
|
||||||
|
if (^cyc) $write("");
|
||||||
|
if (cyc==9) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
%000005 if (t1 && t2) $write("");
|
||||||
|
-000005 point: comment=(t1==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t2==1) => 1 hier=top.t
|
||||||
|
-000005 point: comment=(t2==0) => 0 hier=top.t
|
||||||
|
end
|
||||||
|
|
||||||
|
logic ta, tb, tc;
|
||||||
|
initial begin
|
||||||
|
int q[5];
|
||||||
|
int qv[$];
|
||||||
|
|
||||||
|
q = '{1, 2, 2, 4, 3};
|
||||||
|
// lambas not handled
|
||||||
|
// NB: there is a bug w/ tracing find_first (maybe lambdas in general?)
|
||||||
|
// tracing_off does not work around the bug
|
||||||
|
qv = q.find_first with (item[0] & item[1]);
|
||||||
|
ta = '1;
|
||||||
|
tb = '0;
|
||||||
|
tc = '0;
|
||||||
|
%000001 while (ta || tb || tc) begin
|
||||||
|
-000001 point: comment=(ta==0 && tb==0 && tc==0) => 0 hier=top.t
|
||||||
|
-000000 point: comment=(ta==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tb==1) => 1 hier=top.t
|
||||||
|
-000000 point: comment=(tc==1) => 1 hier=top.t
|
||||||
|
tc = tb;
|
||||||
|
tb = ta;
|
||||||
|
ta = '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sub the_sub_1 (.p(t1), .q(t2));
|
||||||
|
sub the_sub_2 (.p(t3), .q(t4));
|
||||||
|
// TODO -- non-process expressions
|
||||||
|
sub the_sub_3 (.p(t1 ? t2 : t3), .q(t4));
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// pragma for expr coverage off / on
|
||||||
|
// investigate cover point sorting in annotated source
|
||||||
|
// consider reporting don't care terms
|
||||||
|
//
|
||||||
|
// Branches which are statically impossible to reach are still reported.
|
||||||
|
// E.g.
|
||||||
|
// -000000 point: comment=(t1=1 && t2=1 && 1'h0=1) => 1 hier=top.t
|
||||||
|
// These could potentially be pruned, but they currently follow suit for
|
||||||
|
// what branch coverage does. Perhaps a switch should be added to not
|
||||||
|
// count statically impossible things.
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub (
|
||||||
|
input p,
|
||||||
|
input q
|
||||||
|
);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
~000019 if (p && q) $write("");
|
||||||
|
+000017 point: comment=(p==0) => 0 hier=top.t.the_sub_*
|
||||||
|
-000002 point: comment=(p==1 && q==1) => 1 hier=top.t.the_sub_*
|
||||||
|
+000019 point: comment=(q==0) => 0 hier=top.t.the_sub_*
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
test.top_filename = "t/t_cover_expr.v"
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=['--cc', '--coverage-expr', '--trace'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
# Read the input .v file and do any CHECK_COVER requests
|
||||||
|
test.inline_checks()
|
||||||
|
|
||||||
|
test.run(cmd=[
|
||||||
|
os.environ["VERILATOR_ROOT"] + "/bin/verilator_coverage",
|
||||||
|
"--annotate-points",
|
||||||
|
"--annotate",
|
||||||
|
test.obj_dir + "/annotated",
|
||||||
|
test.obj_dir + "/coverage.dat",
|
||||||
|
],
|
||||||
|
verilator_run=True)
|
||||||
|
|
||||||
|
top = Path(test.top_filename)
|
||||||
|
test.files_identical(test.obj_dir + f"/annotated/{top.name}", test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -16,6 +16,6 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", "--coverage", "--
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
if test.vlt:
|
||||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 144)
|
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 620)
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -75,5 +75,8 @@ C 'ft/t_wrapper_context.vl38n4pagev_line/topoblockS38-39htop0.top'
|
||||||
C 'ft/t_wrapper_context.vl40n7pagev_branch/topoifS40htop0.top' 0
|
C 'ft/t_wrapper_context.vl40n7pagev_branch/topoifS40htop0.top' 0
|
||||||
C 'ft/t_wrapper_context.vl40n8pagev_branch/topoelseS46htop0.top' 34
|
C 'ft/t_wrapper_context.vl40n8pagev_branch/topoelseS46htop0.top' 34
|
||||||
C 'ft/t_wrapper_context.vl41n11pagev_line/topoelsehtop0.top' 0
|
C 'ft/t_wrapper_context.vl41n11pagev_line/topoelsehtop0.top' 0
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo((counter >= 32'sh5)==0) => 0htop0.top' 0
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo((counter >= 32'sh5)==1 && stop==1) => 1htop0.top' 0
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo(stop==0) => 0htop0.top' 0
|
||||||
C 'ft/t_wrapper_context.vl47n10pagev_branch/topoifS47-49htop0.top' 1
|
C 'ft/t_wrapper_context.vl47n10pagev_branch/topoifS47-49htop0.top' 1
|
||||||
C 'ft/t_wrapper_context.vl47n11pagev_branch/topoelsehtop0.top' 33
|
C 'ft/t_wrapper_context.vl47n11pagev_branch/topoelsehtop0.top' 33
|
||||||
|
|
|
||||||
|
|
@ -75,5 +75,8 @@ C 'ft/t_wrapper_context.vl38n4pagev_line/topoblockS38-39htop1.top'
|
||||||
C 'ft/t_wrapper_context.vl40n7pagev_branch/topoifS40htop1.top' 19
|
C 'ft/t_wrapper_context.vl40n7pagev_branch/topoifS40htop1.top' 19
|
||||||
C 'ft/t_wrapper_context.vl40n8pagev_branch/topoelseS46htop1.top' 0
|
C 'ft/t_wrapper_context.vl40n8pagev_branch/topoelseS46htop1.top' 0
|
||||||
C 'ft/t_wrapper_context.vl41n11pagev_line/topoelsehtop1.top' 18
|
C 'ft/t_wrapper_context.vl41n11pagev_line/topoelsehtop1.top' 18
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo((counter >= 32'sh5)==0) => 0htop1.top' 18
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo((counter >= 32'sh5)==1 && stop==1) => 1htop1.top' 1
|
||||||
|
C 'ft/t_wrapper_context.vl41n27pagev_expr/topo(stop==0) => 0htop1.top' 0
|
||||||
C 'ft/t_wrapper_context.vl47n10pagev_branch/topoifS47-49htop1.top' 0
|
C 'ft/t_wrapper_context.vl47n10pagev_branch/topoifS47-49htop1.top' 0
|
||||||
C 'ft/t_wrapper_context.vl47n11pagev_branch/topoelsehtop1.top' 0
|
C 'ft/t_wrapper_context.vl47n11pagev_branch/topoelsehtop1.top' 0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue