Cleanup and test EmitV for internal coverage

This commit is contained in:
Wilson Snyder 2020-09-07 12:58:30 -04:00
parent c1d35c8622
commit 993115d30a
8 changed files with 414 additions and 25 deletions

View File

@ -31,6 +31,7 @@
class EmitVBaseVisitor : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi = false;
bool m_suppressUnknown = false;
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS
@ -51,12 +52,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
// VISITORS
virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); }
virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); }
virtual void visit(AstNodeModule* nodep) override {
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
iterateChildren(nodep);
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
}
virtual void visit(AstPort* nodep) override {}
virtual void visit(AstNodeFTask* nodep) override {
putfs(nodep, nodep->isFunction() ? "function" : "task");
puts(" ");
@ -212,14 +214,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
AstNode* exprsp) {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (fileOrStrgp) {
iterateAndNextNull(fileOrStrgp);
putbs(",");
putbs(", ");
}
putsQuoted(text);
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
puts(",");
puts(", ");
iterateAndNextNull(expp);
}
puts(");\n");
@ -247,7 +249,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, nodep->verilogKwd());
putbs("(");
iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->modep());
puts(");\n");
}
@ -259,13 +261,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstFClose* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
virtual void visit(AstFFlush* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filep()) iterateAndNextNull(nodep->filep());
puts(");\n");
}
@ -282,16 +284,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstNodeReadWriteMem* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
putbs(",");
putbs(", ");
if (nodep->memp()) iterateAndNextNull(nodep->memp());
if (nodep->lsbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->lsbp());
}
if (nodep->msbp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->msbp());
}
puts(");\n");
@ -302,7 +304,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstSysIgnore* nodep) override {
putfs(nodep, nodep->verilogKwd());
putbs(" (");
putbs("(");
iterateAndNextNull(nodep->exprsp());
puts(");\n");
}
@ -358,7 +360,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$past(");
iterateAndNextNull(nodep->exprp());
if (nodep->ticksp()) {
puts(",");
puts(", ");
iterateAndNextNull(nodep->ticksp());
}
puts(")");
@ -482,7 +484,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep, "$_ATTROF(");
iterateAndNextNull(nodep->fromp());
if (nodep->dimp()) {
putbs(",");
putbs(", ");
iterateAndNextNull(nodep->dimp());
}
puts(")");
@ -654,13 +656,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
iterateChildren(nodep);
// Not v3fatalSrc so we keep processing
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
if (!m_suppressUnknown) {
nodep->v3error(
"Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
}
}
public:
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
explicit EmitVBaseVisitor(AstSenTree* domainp = nullptr)
: m_sensesp{domainp} {}
explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp)
: m_suppressUnknown{suppressUnknown}
, m_sensesp{domainp} {}
virtual ~EmitVBaseVisitor() override {}
};
@ -679,8 +685,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); }
public:
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
bool suppressVarSemi = false) {
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi,
bool suppressUnknown)
: EmitVBaseVisitor{suppressUnknown, nullptr} {
m_ofp = ofp;
m_trackText = trackText;
m_suppressVarSemi = suppressVarSemi;
@ -704,7 +711,8 @@ class EmitVStreamVisitor : public EmitVBaseVisitor {
public:
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
: m_os(os) { // Need () or GCC 4.8 false warning
: EmitVBaseVisitor{false, nullptr}
, m_os(os) { // Need () or GCC 4.8 false warning
iterate(nodep);
}
virtual ~EmitVStreamVisitor() override {}
@ -747,9 +755,8 @@ public:
, m_prefix{prefix}
, m_flWidth{flWidth} {
m_column = 0;
m_prefixFl
= v3Global.rootp()
->fileline(); // NETLIST's fileline instead of nullptr to avoid nullptr checks
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to
// avoid nullptr checks
}
virtual ~EmitVPrefixedFormatter() override {
if (m_column) puts("\n");
@ -780,7 +787,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor{domainp}
: EmitVBaseVisitor{false, domainp}
, m_formatter{os, prefix, flWidth} {
if (user3mark) { AstUser3InUse::check(); }
iterate(nodep);
@ -807,7 +814,14 @@ void V3EmitV::emitvFiles() {
V3OutVFile of(vfilep->name());
of.puts("// DESCR"
"IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false);
}
}
}
void V3EmitV::debugEmitV(const string& stage) {
UINFO(2, __FUNCTION__ << ": " << endl);
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
V3OutVFile of(filename);
EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true);
}

View File

@ -31,6 +31,7 @@ public:
static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
int flWidth, AstSenTree* domainp, bool user3mark);
static void emitvFiles();
static void debugEmitV(const string& stage);
};
#endif // Guard

View File

@ -1013,6 +1013,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_debugCheck = flag;
} else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented
m_debugCollision = flag;
} else if (onoff(sw, "-debug-emitv", flag /*ref*/)) { // Undocumented
m_debugEmitV = flag;
} else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented
m_debugExitParse = flag;
} else if (onoff(sw, "-debug-exit-uvm", flag /*ref*/)) { // Undocumented

View File

@ -265,6 +265,7 @@ private:
bool m_coverageUser = false; // main switch: --coverage-func
bool m_debugCheck = false; // main switch: --debug-check
bool m_debugCollision = false; // main switch: --debug-collision
bool m_debugEmitV = false; // main switch: --debug-emitv
bool m_debugExitParse = false; // main switch: --debug-exit-parse
bool m_debugExitUvm = false; // main switch: --debug-exit-uvm
bool m_debugLeak = true; // main switch: --debug-leak
@ -469,6 +470,7 @@ public:
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool debugCollision() const { return m_debugCollision; }
bool debugEmitV() const { return m_debugEmitV; }
bool debugExitParse() const { return m_debugExitParse; }
bool debugExitUvm() const { return m_debugExitUvm; }
bool debugLeak() const { return m_debugLeak; }

View File

@ -106,6 +106,7 @@ static void reportStatsIfEnabled() {
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("final");
}
static void process() {
@ -363,6 +364,7 @@ static void process() {
V3ActiveTop::activeTopAll(v3Global.rootp());
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder");
if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("preorder");
// Order the code; form SBLOCKs and BLOCKCALLs
V3Order::orderAll(v3Global.rootp());

View File

@ -0,0 +1,196 @@
module Vt_debug_emitv;
input logic clk;
input logic in;
signed int [31:0] [0:2] t.array;
logic logic [15:0] t.pubflat;
logic logic [15:0] t.pubflat_r;
int signed int [31:0] t.fd;
int signed int [31:0] t.cyc;
int signed int [31:0] t.fo;
int signed int [31:0] t.sum;
string string t.str;
int signed int [31:0] t._Vpast_0_0;
int signed int [31:0] t._Vpast_1_0;
int signed int [31:0] t.unnamedblk3.i;
@(*)@([settle])@([initial])@(posedge clk)@(negedge
clk)always @(
*)@(
[settle])@(
[initial])@(
posedge
clk)@(
negedge
clk) begin
$display("stmt");
end
always @([settle])@([initial])@(posedge clk)@(negedge
clk) begin
$display("stmt");
end
initial begin
// Function: f
$write("stmt\nstmt 0 99\n");
// Function: t
$display("stmt");
// Function: f
$write("stmt\nstmt 1 -1\n");
// Function: t
$display("stmt");
// Function: f
$display("stmt");
$display("stmt 2 -2");
// Function: t
$display("stmt");
$display("stmt");
end
???? // CFUNC '_final_TOP'
$_CSTMT(Vt_debug_emitv* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
);
// FINAL
$display("stmt");
always @(posedge clk)@(negedge clk) begin
$display("posedge clk");
end
always @(posedge clk)@(negedge clk) begin
__Vdly__t.pubflat_r <= t.pubflat;
end
always @(posedge clk)@(negedge clk) begin
__Vdly__t.cyc <= (32'sh1 + t.cyc);
t.fo = t.cyc;
// Function: inc
__Vtask_t.sub.inc__2__i = t.fo;
__Vtask_t.sub.inc__2__o = (32'h1 + __Vtask_t.sub.inc__2__i[31:1]);
t.sum = __Vtask_t.sub.inc__2__o;
// Function: f
__Vfunc_t.sub.f__3__v = t.sum;
begin : label0
begin : label0
if ((32'sh0 == __Vfunc_t.sub.f__3__v)) begin
__Vfunc_t.sub.f__3__Vfuncout = 32'sh21;
disable label0;
end
__Vfunc_t.sub.f__3__Vfuncout = (32'h1
+ __Vfunc_t.sub.f__3__v[2]);
disable label0;
end
end
t.sum = __Vfunc_t.sub.f__3__Vfuncout;
$display("sum = %~", t.sum);
$c(;);
$display("%d", $c(0));
$fopen(72'h2f6465762f6e756c6c);
$fclose(t.fd);
$fopen(72'h2f6465762f6e756c6c, 8'h72);
$fgetc(t.fd);
$fflush(t.fd);
$fscanf(t.fd, "%d", t.sum);
;
$fdisplay(32'h69203d20, "%d", t.sum);
$fwrite(t.fd, "hello");
$readmemh(t.fd, t.array);
$readmemh(t.fd, t.array, 32'sh0);
$readmemh(t.fd, t.array, 32'sh0, 32'sh0);
t.sum = 32'sh0;
t.unnamedblk3.i = 32'sh0;
begin : label0
while ((t.unnamedblk3.i < t.cyc)) begin
t.sum = (t.sum + t.unnamedblk3.i);
if ((32'sha < t.sum)) begin
disable label0;
end
else begin
t.sum = (32'sh1 + t.sum);
end
t.unnamedblk3.i = (32'h1 + t.unnamedblk3.i);
end
end
if ((32'sh63 == t.cyc)) begin
$finish;
end
if ((32'sh64 == t.cyc)) begin
$stop;
end
if (in) begin
$display("1");
end
else begin
$display("default");
end
if (in) begin
$display("1");
end
else begin
$display("default");
end
if (in) begin
$display("1");
end
else begin
$display("default");
end
if (in) begin
$display("1");
end
else begin
$display("default");
end
if (in) begin
$display("1");
end
else begin
$display("0");
end
priority if (in) begin
$display("1");
end
else begin
$display("0");
end
unique if (in) begin
$display("1");
end
else begin
$display("0");
end
unique0 if (in) begin
$display("1");
end
else begin
$display("0");
end
$display("%d%d", t._Vpast_0_0t._Vpast_1_0,
t._Vpast_1_0);
t.str = $sformatf("cyc=%~", t.cyc);
;
$display("str = %@", t.str);
$display("[%t] [%^]", $time$realtime, $realtime);
end
/*verilator public_flat_rw @(posedge clk)@(negedge
clk) t.pubflat*/
always @(posedge clk)@(negedge clk) begin
__Vdly__t._Vpast_0_0 <= t.cyc;
end
always @(posedge clk)@(negedge clk) begin
__Vdly__t._Vpast_1_0 <= t.cyc;
end
__Vdly__t._Vpast_1_0 = t._Vpast_1_0;
t._Vpast_1_0 = __Vdly__t._Vpast_1_0;
__Vdly__t._Vpast_0_0 = t._Vpast_0_0;
t._Vpast_0_0 = __Vdly__t._Vpast_0_0;
__Vdly__t.cyc = t.cyc;
t.cyc = __Vdly__t.cyc;
__Vdly__t.pubflat_r = t.pubflat_r;
t.pubflat_r = __Vdly__t.pubflat_r;
always @(negedge clk) begin
$display("negedge clk, pfr = %x", t.pubflat_r);
end
int signed int [31:0] __Vtask_t.sub.inc__2__i;
int signed int [31:0] __Vtask_t.sub.inc__2__o;
int signed int [31:0] __Vfunc_t.sub.f__3__Vfuncout;
int signed int [31:0] __Vfunc_t.sub.f__3__v;
logic logic [15:0] __Vdly__t.pubflat_r;
int signed int [31:0] __Vdly__t.cyc;
int signed int [31:0] __Vdly__t._Vpast_0_0;
int signed int [31:0] __Vdly__t._Vpast_1_0;
endmodule

22
test_regress/t/t_debug_emitv.pl Executable file
View File

@ -0,0 +1,22 @@
#!/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 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 => 1);
lint(
# We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions
# Likewise XML
v_flags => ["--lint-only --dump-treei 9 --debug-emitv"],
);
files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__preorder.v", $Self->{golden_filename});
ok(1);
1;

View File

@ -0,0 +1,150 @@
// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference
// as the select expression
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/
// Inputs
clk, in
);
input clk;
input in;
// verilator lint_off UNPACKED
typedef enum {
ZERO,
ONE = 1
} e_t;
typedef struct packed {
e_t a;
} ps_t;
typedef struct {
logic signed [2:0] a;
} us_t;
const ps_t ps[3];
us_t us;
int array[3];
initial array = '{1,2,3};
reg [15:0] pubflat /*verilator public_flat_rw @(posedge clk) */;
reg [15:0] pubflat_r;
wire [15:0] pubflat_w = pubflat;
int fd;
task t;
$display("stmt");
endtask
function int f(input int v);
$display("stmt");
return v == 0 ? 99 : ~v + 1;
endfunction
sub sub();
initial begin
int other;
begin //unnamed
for (int i = 0; i < 3; ++i) begin
other = f(i);
$display("stmt %d %d", i, other);
t();
end
end
begin : named
$display("stmt");
end : named
end
final begin
$display("stmt");
end
always @ (in) begin
$display("stmt");
end
always @ (posedge clk) begin
$display("posedge clk");
pubflat_r <= pubflat_w;
end
always @ (negedge clk) begin
$display("negedge clk, pfr = %x", pubflat_r);
end
int cyc;
int fo;
int sum;
string str;
always_ff @ (posedge clk) begin
cyc <= cyc + 1;
fo = cyc;
sub.inc(fo, sum);
sum = sub.f(sum);
$display("sum = %d", sum);
$c(";");
$display("%d", $c("0"));
fd = $fopen("/dev/null");
$fclose(fd);
fd = $fopen("/dev/null", "r");
$fgetc(fd); // stmt
$fflush(fd);
$fscanf(fd, "%d", sum);
$fdisplay("i = ", sum);
$fwrite(fd, "hello");
$readmemh(fd, array);
$readmemh(fd, array, 0);
$readmemh(fd, array, 0, 0);
sum = 0;
for (int i = 0; i < cyc; ++i) begin
sum += i;
if (sum > 10) break;
else sum += 1;
end
if (cyc == 99) $finish;
if (cyc == 100) $stop;
case (in) // synopsys full_case parallel_case
1: $display("1");
default: $display("default");
endcase
priority case (in)
1: $display("1");
default: $display("default");
endcase
unique case (in)
1: $display("1");
default: $display("default");
endcase
unique0 case (in)
1: $display("1");
default: $display("default");
endcase
if (in) $display("1"); else $display("0");
priority if (in) $display("1"); else $display("0");
unique if (in) $display("1"); else $display("0");
unique0 if (in) $display("1"); else $display("0");
$display($past(cyc), $past(cyc, 1));
str = $sformatf("cyc=%d", cyc);
$display("str = %s", str);
$display("[%t] [%t]", $time, $realtime);
end
endmodule
module sub();
task inc(input int i, output int o);
o = {1'b0, i[31:1]} + 32'd1;
endtask
function int f(input int v);
if (v == 0) return 33;
return {31'd0, v[2]} + 32'd1;
endfunction
endmodule