Support compile time trace signal selection with tracing_on/off (#3323).

This commit is contained in:
Wilson Snyder 2022-05-12 22:27:38 -04:00
parent cddbe4642f
commit 71dedccbbe
13 changed files with 431 additions and 11 deletions

View File

@ -13,6 +13,7 @@ Verilator 4.223 devel
**Minor:**
* Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD]
* Fix hang with large case statement optimization (#3405). [Mike Urbach]

View File

@ -1676,9 +1676,28 @@ The grammar of configuration commands is as follows:
.. option:: tracing_off [-file "<filename>" [-lines <line> [ - <line> ]]]
Enable/disable waveform tracing for all future signals declared in the
specified filename (or wildcard with '\*' or '?', or all files if
omitted) and range of line numbers (or all lines if omitted).
.. option:: tracing_on [-scope "<scopename>" [-levels <levels> ]]
For tracing_off, instances below any module in the files/ranges
specified will also not be traced.
.. option:: tracing_off [-scope "<scopename>" [-levels <levels> ]]
Enable/disable waveform tracing for all future signals declared in
all files.
With -file, enable/disable waveform tracing in the specified
filename (or wildcard with '\*' or '?'), and -line range of line
numbers (or all lines if omitted).
For tracing_off with -file, instances below any module in the
files/ranges specified will also not be traced. To overcome this
feature, use tracing_on on the upper module declaration and on any
cells, or use the -scope flavor of the command.
With -scope enable/disable waveform tracing for the specified scope (or
wildcard with '\*' or '?'), and optional --levels number of levels
below. These controls only take place after other file/line/module
based controls have indicated the signal should be traced.
With -levels (used with -scope), the number of levels below that
scope which the rule is to match, where 0 means all levels below, 1
the exact level as the provided scope, and 2 meaning an additional
level of children below the provided scope, etc.

View File

@ -339,12 +339,109 @@ public:
using V3ConfigFileResolver = V3ConfigWildcardResolver<V3ConfigFile>;
//######################################################################
// ScopeTrace tracking
class V3ConfigScopeTraceEntry final {
public:
const string m_scope; // Scope or regexp to match
const bool m_on = false; // True to enable message
int m_levels = 0; // # levels, 0 = all, 1 = only this, ...
// CONSTRUCTORS
V3ConfigScopeTraceEntry(const string& scope, bool on, int levels)
: m_scope{scope}
, m_on{on}
, m_levels{levels} {}
~V3ConfigScopeTraceEntry() = default;
bool operator<(const V3ConfigScopeTraceEntry& other) const {
if (m_on < other.m_on) return true;
if (m_on > other.m_on) return false;
if (m_levels < other.m_levels) return true;
if (m_levels > other.m_levels) return false;
return m_scope < other.m_scope;
}
};
// Tracks what matches are known to hit against V3ConfigScopeTraceEntries
class V3ConfigScopeTraceEntryMatch final {
public:
const V3ConfigScopeTraceEntry* m_entryp;
const string m_scopepart;
V3ConfigScopeTraceEntryMatch(const V3ConfigScopeTraceEntry* entryp, const string& scopepart)
: m_entryp{entryp}
, m_scopepart{scopepart} {}
bool operator<(const V3ConfigScopeTraceEntryMatch& other) const {
if (m_entryp < other.m_entryp) return true;
if (m_entryp > other.m_entryp) return false;
return m_scopepart < other.m_scopepart;
}
};
class V3ConfigScopeTraceResolver final {
std::vector<V3ConfigScopeTraceEntry> m_entries; // User specified on/offs and levels
std::map<V3ConfigScopeTraceEntryMatch, bool> m_matchCache; // Matching entries for speed
public:
void addScopeTraceOn(bool on, const string& scope, int levels) {
UINFO(9, "addScopeTraceOn " << on << " '" << scope << "' "
<< " levels=" << levels << endl);
m_entries.emplace_back(V3ConfigScopeTraceEntry{scope, on, levels});
m_matchCache.clear();
}
bool getEntryMatch(const V3ConfigScopeTraceEntry* entp, const string& scopepart) {
// Return if a entry matches the scopepart, with memoization
const auto& key = V3ConfigScopeTraceEntryMatch{entp, scopepart};
const auto& it = m_matchCache.find(key);
if (it != m_matchCache.end()) return it->second; // Cached
const bool matched = VString::wildmatch(scopepart, entp->m_scope);
m_matchCache.emplace(key, matched);
return matched;
}
bool getScopeTraceOn(const string& scope) {
// Apply in the order the user provided them, so they can choose on/off preferencing
int maxLevel = 1;
for (const auto& ch : scope) {
if (ch == '.') ++maxLevel;
}
UINFO(9, "getScopeTraceOn " << scope << " maxLevel=" << maxLevel << endl);
bool enabled = true;
for (const auto& ent : m_entries) {
// We apply shortest match first for each rule component
// (Otherwise the levels would be useless as "--scope top* --levels 1" would
// always match at every scopepart, and we wound't know how to count levels)
int partLevel = 1;
for (string::size_type partEnd = 0; true;) {
partEnd = scope.find('.', partEnd + 1);
if (partEnd == string::npos) partEnd = scope.length();
const std::string scopepart = scope.substr(0, partEnd);
if (getEntryMatch(&ent, scopepart)) {
const bool levelMatch
= !ent.m_levels || (ent.m_levels >= maxLevel - partLevel);
if (levelMatch) enabled = ent.m_on;
UINFO(9, "getScopeTraceOn-part " << scope << " enabled=" << enabled
<< " @ lev=" << partLevel
<< (levelMatch ? "[match]" : "[miss]")
<< " from scopepart=" << scopepart << endl);
break;
}
if (partEnd == scope.length()) break;
++partLevel;
}
}
return enabled;
}
};
//######################################################################
// Resolve modules and files in the design
class V3ConfigResolver final {
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
V3ConfigScopeTraceResolver m_scopeTraces; // Regexp to trace enables
std::unordered_map<string, std::unordered_map<string, uint64_t>>
m_profileData; // Access to profile_data records
FileLine* m_profileFileLine = nullptr;
@ -359,6 +456,7 @@ public:
}
V3ConfigModuleResolver& modules() { return m_modules; }
V3ConfigFileResolver& files() { return m_files; }
V3ConfigScopeTraceResolver& scopeTraces() { return m_scopeTraces; }
void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost) {
if (!m_profileFileLine) m_profileFileLine = fl;
@ -428,6 +526,10 @@ void V3Config::addProfileData(FileLine* fl, const string& model, const string& k
V3ConfigResolver::s().addProfileData(fl, model, key, cost);
}
void V3Config::addScopeTraceOn(bool on, const string& scope, int levels) {
V3ConfigResolver::s().scopeTraces().addScopeTraceOn(on, scope, levels);
}
void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& var, VAttrType attr, AstSenTree* sensep) {
// Semantics: sensep only if public_flat_rw
@ -534,6 +636,9 @@ uint64_t V3Config::getProfileData(const string& model, const string& key) {
FileLine* V3Config::getProfileDataFileLine() {
return V3ConfigResolver::s().getProfileDataFileLine();
}
bool V3Config::getScopeTraceOn(const string& scope) {
return V3ConfigResolver::s().scopeTraces().getScopeTraceOn(scope);
}
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());

View File

@ -37,6 +37,7 @@ public:
static void addModulePragma(const string& module, VPragmaType pragma);
static void addProfileData(FileLine* fl, const string& model, const string& key,
uint64_t cost);
static void addScopeTraceOn(bool on, const string& scope, int levels);
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& signal, VAttrType type, AstSenTree* nodep);
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
@ -50,6 +51,7 @@ public:
static uint64_t getProfileData(const string& model, const string& key);
static FileLine* getProfileDataFileLine();
static bool getScopeTraceOn(const string& scope);
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
};

View File

@ -25,9 +25,10 @@
#include "verilated_trace_defs.h" // For VLT_TRACE_SCOPE_*
#include "V3Global.h"
#include "V3TraceDecl.h"
#include "V3Config.h"
#include "V3EmitCBase.h"
#include "V3Stats.h"
#include "V3TraceDecl.h"
#include <algorithm>
#include <functional>
@ -140,10 +141,13 @@ private:
return "Verilator trace_off";
} else if (!nodep->isTrace()) {
return "Verilator instance trace_off";
} else if (!v3Global.opt.traceUnderscore()) {
} else {
const string prettyName = varp->prettyName();
if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore";
if (prettyName.find("._") != string::npos) return "Inlined leading underscore";
if (!v3Global.opt.traceUnderscore()) {
if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore";
if (prettyName.find("._") != string::npos) return "Inlined leading underscore";
}
if (!V3Config::getScopeTraceOn(prettyName)) return "Vlt scope trace_off";
}
return nullptr;
}

View File

@ -138,12 +138,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
-?"-cost" { FL; return yVLT_D_COST; }
-?"-file" { FL; return yVLT_D_FILE; }
-?"-function" { FL; return yVLT_D_FUNCTION; }
-?"-levels" { FL; return yVLT_D_LEVELS; }
-?"-lines" { FL; return yVLT_D_LINES; }
-?"-match" { FL; return yVLT_D_MATCH; }
-?"-model" { FL; return yVLT_D_MODEL; }
-?"-module" { FL; return yVLT_D_MODULE; }
-?"-mtask" { FL; return yVLT_D_MTASK; }
-?"-rule" { FL; return yVLT_D_RULE; }
-?"-scope" { FL; return yVLT_D_SCOPE; }
-?"-task" { FL; return yVLT_D_TASK; }
-?"-var" { FL; return yVLT_D_VAR; }

View File

@ -366,12 +366,14 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yVLT_D_COST "--cost"
%token<fl> yVLT_D_FILE "--file"
%token<fl> yVLT_D_FUNCTION "--function"
%token<fl> yVLT_D_LEVELS "--levels"
%token<fl> yVLT_D_LINES "--lines"
%token<fl> yVLT_D_MATCH "--match"
%token<fl> yVLT_D_MODEL "--model"
%token<fl> yVLT_D_MODULE "--module"
%token<fl> yVLT_D_MTASK "--mtask"
%token<fl> yVLT_D_RULE "--rule"
%token<fl> yVLT_D_SCOPE "--scope"
%token<fl> yVLT_D_TASK "--task"
%token<fl> yVLT_D_VAR "--var"
@ -6458,6 +6460,18 @@ vltItem:
{ V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt()+1); }
| vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM
{ V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); }
| vltOffFront yVLT_D_SCOPE yaSTRING
{ if ($1 != V3ErrorCode::I_TRACING) {
$<fl>1->v3error("Argument -scope only supported for tracing_on/off");
} else {
V3Config::addScopeTraceOn(false, *$3, 0);
}}
| vltOffFront yVLT_D_SCOPE yaSTRING yVLT_D_LEVELS yaINTNUM
{ if ($1 != V3ErrorCode::I_TRACING) {
$<fl>1->v3error("Argument -scope only supported for tracing_on/off_off");
} else {
V3Config::addScopeTraceOn(false, *$3, $5->toUInt());
}}
| vltOffFront yVLT_D_FILE yaSTRING yVLT_D_MATCH yaSTRING
{ if (($1 == V3ErrorCode::I_COVERAGE) || ($1 == V3ErrorCode::I_TRACING)) {
$<fl>1->v3error("Argument -match only supported for lint_off");
@ -6472,6 +6486,18 @@ vltItem:
{ V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt()+1); }
| vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM
{ V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt()+1); }
| vltOnFront yVLT_D_SCOPE yaSTRING
{ if ($1 != V3ErrorCode::I_TRACING) {
$<fl>1->v3error("Argument -scope only supported for tracing_on/off");
} else {
V3Config::addScopeTraceOn(true, *$3, 0);
}}
| vltOnFront yVLT_D_SCOPE yaSTRING yVLT_D_LEVELS yaINTNUM
{ if ($1 != V3ErrorCode::I_TRACING) {
$<fl>1->v3error("Argument -scope only supported for tracing_on/off_off");
} else {
V3Config::addScopeTraceOn(true, *$3, $5->toUInt());
}}
| vltVarAttrFront vltDModuleE vltDFTaskE vltVarAttrVarE attr_event_controlE
{ V3Config::addVarAttr($<fl>1, *$2, *$3, *$4, $1, $5); }
| vltInlineFront vltDModuleE vltDFTaskE

View File

@ -0,0 +1,157 @@
$version Generated by VerilatedVcd $end
$date Thu May 12 22:13:21 2022 $end
$timescale 1ps $end
$scope module top $end
$var wire 1 ) clk $end
$scope module t $end
$var wire 1 ) clk $end
$scope module sub1a $end
$var wire 32 * ADD [31:0] $end
$var wire 32 # cyc [31:0] $end
$var wire 32 $ value [31:0] $end
$upscope $end
$scope module sub1b $end
$var wire 32 + ADD [31:0] $end
$var wire 32 # cyc [31:0] $end
$var wire 32 % value [31:0] $end
$scope module sub2a $end
$var wire 32 # cyc [31:0] $end
$var wire 32 & value [31:0] $end
$upscope $end
$scope module sub2b $end
$var wire 32 , ADD [31:0] $end
$var wire 32 # cyc [31:0] $end
$var wire 32 ' value [31:0] $end
$upscope $end
$scope module sub2c $end
$var wire 32 - ADD [31:0] $end
$var wire 32 # cyc [31:0] $end
$var wire 32 ( value [31:0] $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
#0
b00000000000000000000000000000000 #
b00000000000000000000000000001010 $
b00000000000000000000000000010100 %
b00000000000000000000000000010101 &
b00000000000000000000000000010110 '
b00000000000000000000000000010111 (
0)
b00000000000000000000000000001010 *
b00000000000000000000000000010100 +
b00000000000000000000000000010110 ,
b00000000000000000000000000010111 -
#10
b00000000000000000000000000000001 #
b00000000000000000000000000001011 $
b00000000000000000000000000010101 %
b00000000000000000000000000010110 &
b00000000000000000000000000010111 '
b00000000000000000000000000011000 (
1)
#15
0)
#20
b00000000000000000000000000000010 #
b00000000000000000000000000001100 $
b00000000000000000000000000010110 %
b00000000000000000000000000010111 &
b00000000000000000000000000011000 '
b00000000000000000000000000011001 (
1)
#25
0)
#30
b00000000000000000000000000000011 #
b00000000000000000000000000001101 $
b00000000000000000000000000010111 %
b00000000000000000000000000011000 &
b00000000000000000000000000011001 '
b00000000000000000000000000011010 (
1)
#35
0)
#40
b00000000000000000000000000000100 #
b00000000000000000000000000001110 $
b00000000000000000000000000011000 %
b00000000000000000000000000011001 &
b00000000000000000000000000011010 '
b00000000000000000000000000011011 (
1)
#45
0)
#50
b00000000000000000000000000000101 #
b00000000000000000000000000001111 $
b00000000000000000000000000011001 %
b00000000000000000000000000011010 &
b00000000000000000000000000011011 '
b00000000000000000000000000011100 (
1)
#55
0)
#60
b00000000000000000000000000000110 #
b00000000000000000000000000010000 $
b00000000000000000000000000011010 %
b00000000000000000000000000011011 &
b00000000000000000000000000011100 '
b00000000000000000000000000011101 (
1)
#65
0)
#70
b00000000000000000000000000000111 #
b00000000000000000000000000010001 $
b00000000000000000000000000011011 %
b00000000000000000000000000011100 &
b00000000000000000000000000011101 '
b00000000000000000000000000011110 (
1)
#75
0)
#80
b00000000000000000000000000001000 #
b00000000000000000000000000010010 $
b00000000000000000000000000011100 %
b00000000000000000000000000011101 &
b00000000000000000000000000011110 '
b00000000000000000000000000011111 (
1)
#85
0)
#90
b00000000000000000000000000001001 #
b00000000000000000000000000010011 $
b00000000000000000000000000011101 %
b00000000000000000000000000011110 &
b00000000000000000000000000011111 '
b00000000000000000000000000100000 (
1)
#95
0)
#100
b00000000000000000000000000001010 #
b00000000000000000000000000010100 $
b00000000000000000000000000011110 %
b00000000000000000000000000011111 &
b00000000000000000000000000100000 '
b00000000000000000000000000100001 (
1)
#105
0)
#110
b00000000000000000000000000001011 #
b00000000000000000000000000010101 $
b00000000000000000000000000011111 %
b00000000000000000000000000100000 &
b00000000000000000000000000100001 '
b00000000000000000000000000100010 (
1)

View File

@ -0,0 +1,26 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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
scenarios(vlt_all => 1);
top_filename("t/t_trace_scope_vlt.v");
compile(
v_flags2 => ["--trace t/t_trace_scope_vlt.vlt"],
);
execute(
check_finished => 1,
);
vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename});
ok(1);
1;

View File

@ -0,0 +1,42 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
int cyc;
sub1 #(10) sub1a (.*);
sub1 #(20) sub1b (.*);
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc == 10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub1 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
sub2 #(ADD + 1) sub2a(.*);
sub2 #(ADD + 2) sub2b(.*);
sub2 #(ADD + 3) sub2c(.*);
endmodule
module sub2 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
endmodule

View File

@ -0,0 +1,13 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2022 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`verilator_config
tracing_off -scope "t*" -levels 0
tracing_on -scope "t.clk"
tracing_on -scope "t.sub1a" -levels 1
tracing_on -scope "t.sub1b" -levels 2
tracing_off -scope "*.sub2a.ADD"

View File

@ -1,7 +1,22 @@
%Error: t/t_vlt_syntax_bad.vlt:9:20: sensitivity not expected for attribute
9 | public -module "t" @(posedge clk)
| ^
%Error: t/t_vlt_syntax_bad.vlt:10:1: isolate_assignments only applies to signals or functions/tasks
10 | isolate_assignments -module "t"
%Error: t/t_vlt_syntax_bad.vlt:11:1: isolate_assignments only applies to signals or functions/tasks
11 | isolate_assignments -module "t"
| ^~~~~~~~~~~~~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:13:1: Argument -match only supported for lint_off
13 | tracing_off --file "*" -match "nothing"
| ^~~~~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:15:1: Argument -scope only supported for tracing_on/off
15 | lint_off --rule UNOPTFLAT -scope "top*"
| ^~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:16:1: Argument -scope only supported for tracing_on/off_off
16 | lint_off --rule UNOPTFLAT -scope "top*" -levels 0
| ^~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:17:1: Argument -scope only supported for tracing_on/off
17 | lint_on --rule UNOPTFLAT -scope "top*"
| ^~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:18:1: Argument -scope only supported for tracing_on/off_off
18 | lint_on --rule UNOPTFLAT -scope "top*" -levels 0
| ^~~~~~~
%Error: Exiting due to

View File

@ -7,4 +7,12 @@
`verilator_config
public -module "t" @(posedge clk)
// only signals/functions/tasks
isolate_assignments -module "t"
// -match not supported
tracing_off --file "*" -match "nothing"
// -scope not supported
lint_off --rule UNOPTFLAT -scope "top*"
lint_off --rule UNOPTFLAT -scope "top*" -levels 0
lint_on --rule UNOPTFLAT -scope "top*"
lint_on --rule UNOPTFLAT -scope "top*" -levels 0