From 470859f929b1b00a951bf6d2459605e98d678204 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 Oct 2020 08:26:36 -0400 Subject: [PATCH 01/88] devel release --- Changes | 2 ++ configure.ac | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 8887c8af9..a57ebbf3d 100644 --- a/Changes +++ b/Changes @@ -2,6 +2,8 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.103 devel + * Verilator 4.102 2020-10-15 diff --git a/configure.ac b/configure.ac index 9439f43cc..040a50165 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.102 2020-10-15], +AC_INIT([Verilator],[4.103 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From 48597bebaf9528dca522c67d6d37dab0ead72654 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 Oct 2020 20:44:51 -0400 Subject: [PATCH 02/88] Tests: Better static tests --- test_regress/t/t_class_static.out | 9 ++++ test_regress/t/t_class_static.pl | 23 +++++++++ test_regress/t/t_class_static.v | 71 +++++++++++++++++++++++++++ test_regress/t/t_var_static.v | 50 ++++++++++--------- test_regress/t/t_var_static_param.out | 5 ++ test_regress/t/t_var_static_param.pl | 23 +++++++++ test_regress/t/t_var_static_param.v | 34 +++++++++++++ 7 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 test_regress/t/t_class_static.out create mode 100755 test_regress/t/t_class_static.pl create mode 100644 test_regress/t/t_class_static.v create mode 100644 test_regress/t/t_var_static_param.out create mode 100755 test_regress/t/t_var_static_param.pl create mode 100644 test_regress/t/t_var_static_param.v diff --git a/test_regress/t/t_class_static.out b/test_regress/t/t_class_static.out new file mode 100644 index 000000000..678029a0e --- /dev/null +++ b/test_regress/t/t_class_static.out @@ -0,0 +1,9 @@ +%Error-UNSUPPORTED: t/t_class_static.v:12:15: Unsupported: 'static' class members + : ... In instance t + 12 | static int c_st = 2; + | ^~~~ +%Error-UNSUPPORTED: t/t_class_static.v:25:18: Unsupported: 'static' function/task variables + : ... In instance t + 25 | static int st = 2; st++; return st; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_static.pl b/test_regress/t/t_class_static.pl new file mode 100755 index 000000000..1befb2521 --- /dev/null +++ b/test_regress/t/t_class_static.pl @@ -0,0 +1,23 @@ +#!/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(simulator => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all} # Verilator unsupported, bug546 + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static.v b/test_regress/t/t_class_static.v new file mode 100644 index 000000000..ffb92c2d5 --- /dev/null +++ b/test_regress/t/t_class_static.v @@ -0,0 +1,71 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2014 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +class Cls; + int c_no = 2; + //automatic int c_au = 2; // automatic not a legal keyword here + static int c_st = 2; + + function int f_c_no (); + ++c_no; return c_no; + endfunction + function int f_c_st (); + ++c_st; return c_st; + endfunction + + function int f_no_no (); + int au = 2; au++; return au; + endfunction + function int f_no_st (); + static int st = 2; st++; return st; + endfunction + function int f_no_au (); + automatic int au = 2; au++; return au; + endfunction +endclass + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + Cls a = new; + Cls b = new; + + int v; + + initial begin + v = a.f_c_no(); `checkh(v,3); + v = a.f_c_no(); `checkh(v, 4); + v = b.f_c_no(); `checkh(v, 3); + v = b.f_c_no(); `checkh(v, 4); + v = a.f_c_st(); `checkh(v,3); + v = a.f_c_st(); `checkh(v, 4); + v = b.f_c_st(); `checkh(v, 5); + v = b.f_c_st(); `checkh(v, 6); + // + v = a.f_no_no(); `checkh(v, 3); + v = a.f_no_no(); `checkh(v, 3); + v = b.f_no_no(); `checkh(v, 3); + v = b.f_no_no(); `checkh(v, 3); + v = a.f_no_st(); `checkh(v, 3); + v = a.f_no_st(); `checkh(v, 4); + v = b.f_no_st(); `checkh(v, 5); + v = b.f_no_st(); `checkh(v, 6); + v = a.f_no_au(); `checkh(v, 3); + v = a.f_no_au(); `checkh(v, 3); + v = b.f_no_au(); `checkh(v, 3); + v = b.f_no_au(); `checkh(v, 3); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v index 67f772591..8dbc698ff 100644 --- a/test_regress/t/t_var_static.v +++ b/test_regress/t/t_var_static.v @@ -43,27 +43,29 @@ module t (/*AUTOARG*/ automatic int au = 2; au++; return au; endfunction + int v; + initial begin - `checkh(f_no_no(), 3); - `checkh(f_no_no(), 4); - `checkh(f_no_st(), 3); - `checkh(f_no_st(), 4); - `checkh(f_no_au(), 3); - `checkh(f_no_au(), 3); + v = f_no_no(); `checkh(v, 3); + v = f_no_no(); `checkh(v, 4); + v = f_no_st(); `checkh(v, 3); + v = f_no_st(); `checkh(v, 4); + v = f_no_au(); `checkh(v, 3); + v = f_no_au(); `checkh(v, 3); // - `checkh(f_st_no(), 3); - `checkh(f_st_no(), 4); - `checkh(f_st_st(), 3); - `checkh(f_st_st(), 4); - `checkh(f_st_au(), 3); - `checkh(f_st_au(), 3); + v = f_st_no(); `checkh(v, 3); + v = f_st_no(); `checkh(v, 4); + v = f_st_st(); `checkh(v, 3); + v = f_st_st(); `checkh(v, 4); + v = f_st_au(); `checkh(v, 3); + v = f_st_au(); `checkh(v, 3); // - `checkh(f_au_no(), 3); - `checkh(f_au_no(), 3); - `checkh(f_au_st(), 3); - `checkh(f_au_st(), 4); - `checkh(f_au_au(), 3); - `checkh(f_au_au(), 3); + v = f_au_no(); `checkh(v, 3); + v = f_au_no(); `checkh(v, 3); + v = f_au_st(); `checkh(v, 3); + v = f_au_st(); `checkh(v, 4); + v = f_au_au(); `checkh(v, 3); + v = f_au_au(); `checkh(v, 3); // end @@ -78,17 +80,17 @@ module t (/*AUTOARG*/ ist1 = 10; ist2 = 20; iau3 = 30; - `checkh(ist1, 10); - `checkh(ist2, 20); - `checkh(iau3, 30); + v = ist1; `checkh(v, 10); + v = ist2; `checkh(v, 20); + v = iau3; `checkh(v, 30); ++ist1; ++ist2; ++iau3; end else if (cyc == 1) begin - `checkh(ist1, 11); - `checkh(ist2, 21); - `checkh(iau3, 0); + v = ist1; `checkh(v, 11); + v = ist2; `checkh(v, 21); + //TODO v = iau3; `checkh(v, 0); end else if (cyc == 5) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_var_static_param.out b/test_regress/t/t_var_static_param.out new file mode 100644 index 000000000..f58144faa --- /dev/null +++ b/test_regress/t/t_var_static_param.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_var_static_param.v:32:18: Unsupported: 'static' function/task variables + : ... In instance t.subb + 32 | static int st = 2; st += P; return st; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_var_static_param.pl b/test_regress/t/t_var_static_param.pl new file mode 100755 index 000000000..1befb2521 --- /dev/null +++ b/test_regress/t/t_var_static_param.pl @@ -0,0 +1,23 @@ +#!/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(simulator => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all} # Verilator unsupported, bug546 + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_var_static_param.v b/test_regress/t/t_var_static_param.v new file mode 100644 index 000000000..89f381d98 --- /dev/null +++ b/test_regress/t/t_var_static_param.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) + +module t (/*AUTOARG*/); + + sub #(.P(1)) suba (); + sub #(.P(10)) subb (); + + int v; + + initial begin + v = suba.f_no_st(); `checkh(v, 3); + v = suba.f_no_st(); `checkh(v, 4); + v = subb.f_no_st(); `checkh(v, 'hc); + v = subb.f_no_st(); `checkh(v, 'h16); + v = suba.f_no_st(); `checkh(v, 5); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +module sub; + parameter P = 1; + function int f_no_st (); + // This static is unique within each parameterized module + static int st = 2; st += P; return st; + endfunction +endmodule From 5d8019f941dcc1f2e7620568dc6a90e369da40b5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 Oct 2020 21:02:24 -0400 Subject: [PATCH 03/88] Internals: Only need to applyFTask once. No functional change intended. --- src/V3LinkParse.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 09ebb7fb3..3a25a1a68 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -104,12 +104,13 @@ private: // VISITs virtual void visit(AstNodeFTask* nodep) override { - V3Config::applyFTask(m_modp, nodep); - if (!nodep->user1SetOnce()) { // Process only once. + V3Config::applyFTask(m_modp, nodep); cleanFileline(nodep); - m_ftaskp = nodep; - iterateChildren(nodep); + { + m_ftaskp = nodep; + iterateChildren(nodep); + } m_ftaskp = nullptr; } } From d4df94d86697d88e97e0a6b156b6a336a87f47cc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 Oct 2020 21:08:24 -0400 Subject: [PATCH 04/88] Internals: Move static resolution to LinkParse. --- src/V3LinkParse.cpp | 40 +++++++++++++++++++++++++++------------- src/V3LinkResolve.cpp | 18 ------------------ 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 3a25a1a68..b5595a81c 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -57,6 +57,7 @@ private: AstNodeModule* m_modp = nullptr; // Current module AstNodeFTask* m_ftaskp = nullptr; // Current task AstNodeDType* m_dtypep = nullptr; // Current data type + VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -107,11 +108,17 @@ private: if (!nodep->user1SetOnce()) { // Process only once. V3Config::applyFTask(m_modp, nodep); cleanFileline(nodep); + VL_RESTORER(m_ftaskp); + VL_RESTORER(m_lifetime); { m_ftaskp = nodep; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) { + // Automatic always until we support static + m_lifetime = VLifetime::AUTOMATIC; + } iterateChildren(nodep); } - m_ftaskp = nullptr; } } virtual void visit(AstNodeFTaskRef* nodep) override { @@ -173,6 +180,13 @@ private: virtual void visit(AstVar* nodep) override { cleanFileline(nodep); + if (nodep->lifetime().isNone()) { + if (nodep->isFuncLocal() && nodep->isIO()) { + nodep->lifetime(VLifetime::AUTOMATIC); + } else { + nodep->lifetime(m_lifetime); + } + } if (nodep->isParam() && !nodep->valuep() && nodep->fileline()->language() < V3LangCode::L1800_2009) { nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); @@ -224,25 +238,20 @@ private: FileLine* fl = nodep->valuep()->fileline(); if (nodep->isParam() || (m_ftaskp && nodep->isNonOutput())) { // 1. Parameters and function inputs: It's a default to use if not overridden - } else if (VN_IS(m_modp, Class)) { - // 2. Class member init become initials (as might call functions) - // later move into class constructor - nodep->addNextHere(new AstInitial( - fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), VAccess::WRITE), - nodep->valuep()->unlinkFrBack()))); - } else if (!m_ftaskp && nodep->isNonOutput()) { + } else if (!m_ftaskp && !VN_IS(m_modp, Class) && nodep->isNonOutput()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: " << nodep->prettyNameQ()); nodep->valuep()->unlinkFrBack()->deleteTree(); - } // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial + } // 2. Under modules/class, it's an initial value to be loaded at time 0 via an + // AstInitial else if (m_valueModp) { // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* newfl = new FileLine(fl); newfl->warnOff(V3ErrorCode::PROCASSWIRE, true); - nodep->addNextHere(new AstInitial( - newfl, - new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE), - nodep->valuep()->unlinkFrBack()))); + auto* assp + = new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE), + nodep->valuep()->unlinkFrBack()); + nodep->addNextHere(new AstInitial(newfl, assp)); } // 4. Under blocks, it's an initial value to be under an assign else { nodep->addNextHere(new AstAssign(fl, @@ -483,12 +492,17 @@ private: V3Config::applyModule(nodep); VL_RESTORER(m_modp); + VL_RESTORER(m_lifetime); { // Module: Create sim table for entire module and iterate cleanFileline(nodep); // m_modp = nodep; m_valueModp = nodep; + m_lifetime = nodep->lifetime(); + if (m_lifetime.isNone()) { + m_lifetime = VN_IS(nodep, Class) ? VLifetime::AUTOMATIC : VLifetime::STATIC; + } iterateChildren(nodep); } m_valueModp = nodep; diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index bf158a20a..1f7fdaff7 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -51,7 +51,6 @@ private: AstClass* m_classp = nullptr; // Class we're inside AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion - VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime int m_senitemCvtNum = 0; // Temporary signal counter // METHODS @@ -66,23 +65,17 @@ private: UINFO(8, "MODULE " << nodep << endl); if (nodep->dead()) return; VL_RESTORER(m_modp); - VL_RESTORER(m_lifetime); VL_RESTORER(m_senitemCvtNum); { m_modp = nodep; m_senitemCvtNum = 0; - m_lifetime = nodep->lifetime(); - if (m_lifetime.isNone()) m_lifetime = VLifetime::STATIC; iterateChildren(nodep); } } virtual void visit(AstClass* nodep) override { VL_RESTORER(m_classp); - VL_RESTORER(m_lifetime); { m_classp = nodep; - m_lifetime = nodep->lifetime(); - if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; iterateChildren(nodep); } } @@ -106,13 +99,6 @@ private: if (m_classp && nodep->isParam()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: class parameter"); if (m_ftaskp) nodep->funcLocal(true); - if (nodep->lifetime().isNone()) { - if (nodep->isFuncLocal() && nodep->isIO()) { - nodep->lifetime(VLifetime::AUTOMATIC); - } else { - nodep->lifetime(m_lifetime); - } - } if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute m_modp->modPublic(true); // Avoid flattening if signals are exposed @@ -136,15 +122,11 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } - VLifetime origLifetime = m_lifetime; { - m_lifetime = nodep->lifetime(); - if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; m_ftaskp = nodep; iterateChildren(nodep); } m_ftaskp = nullptr; - m_lifetime = origLifetime; if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); } } virtual void visit(AstNodeFTaskRef* nodep) override { From f4ed36785082ce30cbec044642b3d3737dc6b976 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 Oct 2020 21:36:35 -0400 Subject: [PATCH 05/88] Internals: Remove verilator_difftree old cleanups. --- bin/verilator_difftree | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 4fefebdd6..aa22b4534 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -9,22 +9,6 @@ use Pod::Usage; use strict; use vars qw($Debug); -#====================================================================== - -# Old version 1 dump nodes with no dtypep's -our %Ver1_Non_Dtyped = map {$_ => 1} qw( - ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM - CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE - COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT - DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF - IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST - NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE - PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR - SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS - SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT - TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE - UDPTABLELINE UNTILSTABLE VASSERT WHILE ); - #====================================================================== # main @@ -133,8 +117,6 @@ sub filter { $line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno; if ($verCvt) { next if $line =~ /^ NETLIST/; - $line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format - # # Below Ver1_Non_Dtyped may replace above further if ($line =~ /: ([A-Z]+) /) { my $type = $1; next if $type =~ 'DTYPE'; @@ -147,14 +129,7 @@ sub filter { } next; } - if ($Ver1_Non_Dtyped{$type}) { - $line =~ s! w[0-9]+!!g; - } } - $line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format - $line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format - $line =~ s! s?w0$! NoW!g; # OLD: no width -> common format - $line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format } print $f2 $line; } From 4849c0530b801db3767f2ed9365329f695c0da1f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 16 Oct 2020 18:25:32 -0400 Subject: [PATCH 06/88] Fix class extends with typedef. --- src/V3LinkDot.cpp | 68 ++++++++++++++++-------------- test_regress/t/t_class_extends.out | 4 -- test_regress/t/t_class_extends.pl | 8 ++-- 3 files changed, 39 insertions(+), 41 deletions(-) delete mode 100644 test_regress/t/t_class_extends.out diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0bf9e5af6..b1bb00978 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2674,42 +2674,46 @@ private: // Until overridden by a SCOPE m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); m_modp = nodep; - iterateChildren(nodep); - } - for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) { - if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) { - // Replace abstract reference with hard pointer - // Will need later resolution when deal with parameters - if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted - AstClassOrPackageRef* cpackagerefp - = VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef); - if (!cpackagerefp) { - cextp->v3error("Attempting to extend using a non-class "); - } else { - VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name()); - bool ok = false; - if (foundp) { - if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) { - AstClassRefDType* newp - = new AstClassRefDType{nodep->fileline(), classp}; - cextp->childDTypep(newp); - classp->isExtended(true); - nodep->isExtended(true); - VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), - cpackagerefp); - ok = true; + for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) { + if (AstClassExtends* cextp = VN_CAST(itemp, ClassExtends)) { + // Replace abstract reference with hard pointer + // Will need later resolution when deal with parameters + if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted + AstClassOrPackageRef* cpackagerefp + = VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef); + if (!cpackagerefp) { + cextp->v3error("Attempting to extend using a non-class "); + } else { + VSymEnt* foundp = m_curSymp->findIdFallback(cpackagerefp->name()); + bool ok = false; + if (foundp) { + if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) { + UINFO(8, "Import to " << nodep << " from export class " << classp + << endl); + AstClassRefDType* newp + = new AstClassRefDType{nodep->fileline(), classp}; + cextp->childDTypep(newp); + classp->isExtended(true); + nodep->isExtended(true); + VSymEnt* srcp = m_statep->getNodeSym(classp); + m_curSymp->importFromClass(m_statep->symsp(), srcp); + VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), + cpackagerefp); + ok = true; + } + } + if (!ok) { + string suggest = m_statep->suggestSymFallback( + m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); + cpackagerefp->v3error( + "Class to extend not found: " + << cpackagerefp->prettyNameQ() << endl + << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); } - } - if (!ok) { - string suggest = m_statep->suggestSymFallback( - m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); - cpackagerefp->v3error( - "Class to extend not found: " - << cpackagerefp->prettyNameQ() << endl - << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); } } } + iterateChildren(nodep); } // V3Width when determines types needs to find enum values and such // so add members pointing to appropriate enum values diff --git a/test_regress/t/t_class_extends.out b/test_regress/t/t_class_extends.out deleted file mode 100644 index fc51e85d6..000000000 --- a/test_regress/t/t_class_extends.out +++ /dev/null @@ -1,4 +0,0 @@ -%Error: t/t_class_extends.v:25:4: Can't find typedef: 'T' - 25 | T imemberc; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_class_extends.pl b/test_regress/t/t_class_extends.pl index b8b56e6f0..aabcde63e 100755 --- a/test_regress/t/t_class_extends.pl +++ b/test_regress/t/t_class_extends.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; From 44f938e507436b507b40920629b78133b9063c03 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 16 Oct 2020 19:05:28 -0400 Subject: [PATCH 07/88] Use static const for emitted parameter declarations. --- src/V3CUse.cpp | 34 ++++++++++++++++++---------------- src/V3EmitC.cpp | 29 +++++++++++++++++++---------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index dc33b101e..78afb6dea 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -162,23 +162,25 @@ class CUseVisitor : public AstNVisitor { funcp->addStmtsp(new AstCStmt(nodep->fileline(), "std::string out;\n")); std::string comma; for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) { - if (VN_IS(itemp, Var)) { - string stmt = "out += \""; - stmt += comma; - comma = ", "; - stmt += itemp->origNameProtect(); - stmt += ":\" + "; - if (itemp->isWide()) { - stmt += "VL_TO_STRING_W("; - stmt += cvtToStr(itemp->widthWords()); - stmt += ", "; - } else { - stmt += "VL_TO_STRING("; + if (auto* varp = VN_CAST(itemp, Var)) { + if (!varp->isParam()) { + string stmt = "out += \""; + stmt += comma; + comma = ", "; + stmt += itemp->origNameProtect(); + stmt += ":\" + "; + if (itemp->isWide()) { + stmt += "VL_TO_STRING_W("; + stmt += cvtToStr(itemp->widthWords()); + stmt += ", "; + } else { + stmt += "VL_TO_STRING("; + } + stmt += itemp->nameProtect(); + stmt += ");\n"; + nodep->user1(true); // So what we extend dumps this + funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } - stmt += itemp->nameProtect(); - stmt += ");\n"; - nodep->user1(true); // So what we extend dumps this - funcp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } } if (nodep->extendsp() && nodep->extendsp()->classp()->user1()) { diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 467d8af97..6d6e79cd2 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -156,6 +156,7 @@ public: } void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) { + bool anyi = false; for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* varp = VN_CAST(nodep, Var)) { if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) { @@ -172,12 +173,15 @@ public: } } else if (varp->isString()) { if (init) { - emitCtorSep(firstp); - puts(protect("var_" + varp->name()) + " ("); + puts("const std::string "); + puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name()) + + "("); iterateAndNextNull(varp->valuep()); - puts(")"); + puts(");\n"); + anyi = true; } else { - puts("const std::string " + protect("var_" + varp->name()) + ";\n"); + puts("static const std::string " + protect("var_" + varp->name()) + + ";\n"); } } else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output // putsDecoration("// enum ..... "+varp->nameProtect() @@ -187,10 +191,12 @@ public: ->isOpaque()) { // Can't put out e.g. doubles } else { if (init) { - emitCtorSep(firstp); - puts(protect("var_" + varp->name()) + " ("); + puts(varp->isQuad() ? "const QData " : "const IData "); + puts(prefixNameProtect(modp) + "::" + protect("var_" + varp->name()) + + "("); iterateAndNextNull(varp->valuep()); - puts(")"); + puts(");\n"); + anyi = true; } else { // enum puts(varp->isQuad() ? "enum _QData" : "enum _IData"); @@ -198,13 +204,14 @@ public: iterateAndNextNull(varp->valuep()); puts("};\n"); // var - puts(varp->isQuad() ? "const QData " : "const IData "); + puts(varp->isQuad() ? "static const QData " : "static const IData "); puts(protect("var_" + varp->name()) + ";\n"); } } } } } + if (anyi) puts("\n"); } struct CmpName { @@ -2319,6 +2326,9 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) { void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); bool first = true; + string section(""); + emitParams(modp, true, &first, section /*ref*/); + if (VN_IS(modp, Class)) { modp->v3fatalSrc("constructors should be AstCFuncs instead"); } else if (optSystemC() && modp->isTop()) { @@ -2329,8 +2339,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { } emitVarCtors(&first); if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first); - string section(""); - emitParams(modp, true, &first, section /*ref*/); + puts(" {\n"); emitCellCtors(modp); emitSensitives(); From 829db3eefab7ccb3f8ff38fa5854f1aee2797f48 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 16 Oct 2020 19:26:04 -0400 Subject: [PATCH 08/88] Fix tick style on %p formats. --- src/V3CUse.cpp | 2 +- src/V3EmitV.cpp | 2 +- test_regress/t/t_class1.out | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 78afb6dea..3c02364a1 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor { funcp->isStatic(false); funcp->protect(false); AstNode* exprp = new AstCMath(nodep->fileline(), - "std::string(\"`{\") + to_string_middle() + \"}\"", 0); + "std::string(\"'{\") + to_string_middle() + \"}\"", 0); exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp)); nodep->addStmtp(funcp); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 2cd744a85..27e8b3d21 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -490,7 +490,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { puts(")"); } virtual void visit(AstInitArray* nodep) override { - putfs(nodep, "`{"); + putfs(nodep, "'{"); int comma = 0; const AstInitArray::KeyItemMap& mapr = nodep->map(); for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { diff --git a/test_regress/t/t_class1.out b/test_regress/t/t_class1.out index d88b62e63..2e93901d2 100644 --- a/test_regress/t/t_class1.out +++ b/test_regress/t/t_class1.out @@ -1,4 +1,4 @@ Display: null = "null" -Display: newed = "`{imembera:'h0, imemberb:'h0}" -Display: set = "`{imembera:'ha, imemberb:'h14}" +Display: newed = "'{imembera:'h0, imemberb:'h0}" +Display: set = "'{imembera:'ha, imemberb:'h14}" *-* All Finished *-* From cb550e535717b21657fe5009a35f0dfde3a20d04 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 14:21:27 -0400 Subject: [PATCH 09/88] Remove old MSVC 6 workarounds --- src/V3EmitC.cpp | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 6d6e79cd2..b9b267cb9 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1663,13 +1663,11 @@ class EmitCImp : EmitCStmts { } else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) { if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { if (initarp->defaultp()) { - // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - puts("{ int __Vi=0;"); - puts(" for (; __Vi<" + cvtToStr(adtypep->elementsConst())); + puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst())); puts("; ++__Vi) {\n"); emitSetVarConstant(varp->nameProtect() + "[__Vi]", VN_CAST(initarp->defaultp(), Const)); - puts("}}\n"); + puts("}\n"); } const AstInitArray::KeyItemMap& mapr = initarp->map(); for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); @@ -1711,12 +1709,11 @@ class EmitCImp : EmitCStmts { UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp, "Should have swapped msb & lsb earlier."); string ivar = string("__Vi") + cvtToStr(depth); - // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - string pre = ("{ int " + ivar + "=" + cvtToStr(0) + ";" + " for (; " + ivar + "<" + string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<" + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, suffix + "[" + ivar + "]"); - string post = "}}\n"; + string post = "}\n"; return below.empty() ? "" : pre + below + post; } else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { // String's constructor deals with it @@ -2508,10 +2505,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp, "Should have swapped msb & lsb earlier."); string ivar = string("__Vi") + cvtToStr(vecnum); - // MSVC++ pre V7 doesn't support 'for (int ...)', - // so declare in sep block - puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";"); - puts(" for (; " + ivar + "<" + cvtToStr(arrayp->elementsConst())); + puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0)); + puts("; " + ivar + "<" + cvtToStr(arrayp->elementsConst())); puts("; ++" + ivar + ") {\n"); elementp = arrayp->subDTypep()->skipRefp(); } @@ -2522,14 +2517,14 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) { && !(basicp && basicp->keyword() == AstBasicDTypeKwd::STRING)) { int vecnum = vects++; string ivar = string("__Vi") + cvtToStr(vecnum); - puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0) + ";"); - puts(" for (; " + ivar + "<" + cvtToStr(elementp->widthWords())); + puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(0)); + puts("; " + ivar + "<" + cvtToStr(elementp->widthWords())); puts("; ++" + ivar + ") {\n"); } puts("os" + op + varp->nameProtect()); for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); - for (int v = 0; v < vects; ++v) puts("}}\n"); + for (int v = 0; v < vects; ++v) puts("}\n"); } } } @@ -2597,16 +2592,14 @@ void EmitCImp::emitSensitives() { UASSERT_OBJ(arrayp->msb() >= arrayp->lsb(), varp, "Should have swapped msb & lsb earlier."); string ivar = string("__Vi") + cvtToStr(vecnum); - // MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block - puts("{ int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb()) - + ";"); - puts(" for (; " + ivar + "<=" + cvtToStr(arrayp->msb())); + puts("for (int __Vi" + cvtToStr(vecnum) + "=" + cvtToStr(arrayp->lsb())); + puts("; " + ivar + "<=" + cvtToStr(arrayp->msb())); puts("; ++" + ivar + ") {\n"); } puts("sensitive << " + varp->nameProtect()); for (int v = 0; v < vects; ++v) puts("[__Vi" + cvtToStr(v) + "]"); puts(";\n"); - for (int v = 0; v < vects; ++v) puts("}}\n"); + for (int v = 0; v < vects; ++v) puts("}\n"); } } } From 451e961e03ef51d58ee7ae46261cc253f6fc0475 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 16:04:29 -0400 Subject: [PATCH 10/88] Internals: Prep for type method. No functional change intended. --- src/V3AstNodes.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 1462df395..080d8a5c1 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -314,14 +314,13 @@ string AstVar::verilogKwd() const { class AstVar::VlArgTypeRecursed { public: - bool m_isRef; // Is it a reference? string m_type; // The base type, e.g.: "Foo_t"s string m_dims; // Array dimensions, e.g.: "[3][2][1]" - string render(const string& name) const { + string render(const string& name, bool isRef) const { string out; out += m_type; out += " "; - out += m_isRef ? "(&" + name + ")" : name; + out += isRef ? "(&" + name + ")" : name; out += m_dims; return out; } @@ -333,21 +332,22 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& string ostatic; if (isStatic() && namespc.empty()) ostatic = "static "; + bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef())); + VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false); + if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const "; string oname; if (named) { if (!namespc.empty()) oname += namespc + "::"; oname += VIdProtect::protectIf(name(), protect()); } - return ostatic + info.render(oname); + return ostatic + info.render(oname, isRef); } AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, bool compound) const { VlArgTypeRecursed info; - info.m_isRef - = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef())); dtypep = dtypep->skipRefp(); if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { @@ -410,8 +410,6 @@ AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDT UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type"); - if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; } - return info; } From a56e0a6e899d658b69a5b5de4cff88e28133ce33 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 16:48:11 -0400 Subject: [PATCH 11/88] Internals: Prep for type method. No functional change intended. --- src/V3Ast.h | 5 ++ src/V3AstNodes.cpp | 171 +++++++++++++++++++++++---------------------- src/V3AstNodes.h | 5 -- 3 files changed, 92 insertions(+), 89 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index dbcfa1960..fa4b9083c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2439,6 +2439,11 @@ public: const char* charIQWN() const { return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); } + string cType(const string& name, bool forFunc, bool isRef) const; + +private: + class CTypeRecursed; + CTypeRecursed cTypeRecurse(bool forFunc, bool compound) const; }; class AstNodeUOrStructDType : public AstNodeDType { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 080d8a5c1..acd24f932 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -312,20 +312,6 @@ string AstVar::verilogKwd() const { } } -class AstVar::VlArgTypeRecursed { -public: - string m_type; // The base type, e.g.: "Foo_t"s - string m_dims; // Array dimensions, e.g.: "[3][2][1]" - string render(const string& name, bool isRef) const { - string out; - out += m_type; - out += " "; - out += isRef ? "(&" + name + ")" : name; - out += m_dims; - return out; - } -}; - string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc) const { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); @@ -334,7 +320,6 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& bool isRef = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef())); - VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false); if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const "; string oname; @@ -342,75 +327,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& if (!namespc.empty()) oname += namespc + "::"; oname += VIdProtect::protectIf(name(), protect()); } - return ostatic + info.render(oname, isRef); -} - -AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, - bool compound) const { - VlArgTypeRecursed info; - - dtypep = dtypep->skipRefp(); - if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { - const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true); - const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true); - info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">"; - } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { - const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true); - info.m_type = "VlQueue<" + sub.m_type + ">"; - } else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { - const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true); - info.m_type = "VlQueue<" + sub.m_type; - // + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1 - if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1); - info.m_type += ">"; - } else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) { - info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; - } else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { - if (compound) { - v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported"); - } - const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound); - info.m_type = sub.m_type; - info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims; - } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { - // We don't print msb()/lsb() as multidim packed would require recursion, - // and may confuse users as C++ data is stored always with bit 0 used - const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) - ? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/" - : ""; - if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { - info.m_type = "const char*"; - } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { - info.m_type = "const VerilatedScope*"; - } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { - info.m_type = "double"; - } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { - info.m_type = "float"; - } else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) { - info.m_type = "std::string"; - } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width - info.m_type = "CData" + bitvec; - } else if (dtypep->widthMin() <= 16) { - info.m_type = "SData" + bitvec; - } else if (dtypep->widthMin() <= VL_IDATASIZE) { - info.m_type = "IData" + bitvec; - } else if (dtypep->isQuad()) { - info.m_type = "QData" + bitvec; - } else if (dtypep->isWide()) { - if (compound) { - info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; - } else { - info.m_type += "WData" + bitvec; // []'s added later - info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]"; - } - } - } else { - v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName()); - } - - UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type"); - - return info; + return ostatic + dtypep()->cType(oname, forFunc, isRef); } string AstVar::vlEnumType() const { @@ -636,6 +553,92 @@ string AstVar::mtasksString() const { return os.str(); } +class AstNodeDType::CTypeRecursed { +public: + string m_type; // The base type, e.g.: "Foo_t"s + string m_dims; // Array dimensions, e.g.: "[3][2][1]" + string render(const string& name, bool isRef) const { + string out; + out += m_type; + if (name != "") out += " "; + out += isRef ? "(&" + name + ")" : name; + out += m_dims; + return out; + } +}; + +string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const { + CTypeRecursed info = cTypeRecurse(forFunc, false); + return info.render(name, isRef); +} + +AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool forFunc, bool compound) const { + CTypeRecursed info; + + const AstNodeDType* dtypep = this->skipRefp(); + if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { + const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(false, true); + const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(false, true); + info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">"; + } else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, true); + info.m_type = "VlQueue<" + sub.m_type + ">"; + } else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, true); + info.m_type = "VlQueue<" + sub.m_type; + // + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1 + if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1); + info.m_type += ">"; + } else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) { + info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; + } else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { + if (compound) { + v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported"); + } + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, compound); + info.m_type = sub.m_type; + info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims; + } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { + // We don't print msb()/lsb() as multidim packed would require recursion, + // and may confuse users as C++ data is stored always with bit 0 used + const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) + ? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/" + : ""; + if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { + info.m_type = "const char*"; + } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { + info.m_type = "const VerilatedScope*"; + } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { + info.m_type = "double"; + } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { + info.m_type = "float"; + } else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) { + info.m_type = "std::string"; + } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width + info.m_type = "CData" + bitvec; + } else if (dtypep->widthMin() <= 16) { + info.m_type = "SData" + bitvec; + } else if (dtypep->widthMin() <= VL_IDATASIZE) { + info.m_type = "IData" + bitvec; + } else if (dtypep->isQuad()) { + info.m_type = "QData" + bitvec; + } else if (dtypep->isWide()) { + if (compound) { + info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; + } else { + info.m_type += "WData" + bitvec; // []'s added later + info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]"; + } + } + } else { + v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName()); + } + + UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type"); + + return info; +} + AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) { // dimension passed from AstArraySel::dimension // Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar, diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index cf681fad5..25400841a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2182,11 +2182,6 @@ public: void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } string mtasksString() const; - -private: - class VlArgTypeRecursed; - VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, - bool compound) const; }; class AstDefParam : public AstNode { From f62c070d069a1dd3653cfffe89ff5a8b2e204ca2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 18:56:38 -0400 Subject: [PATCH 12/88] Internals: Concat strings only when final; prep for queues. --- src/V3Width.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1bcfaad59..52b564683 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -513,6 +513,8 @@ private: return; } } + } + if (m_vup->final()) { if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) { AstNode* newp = new AstConcatN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack()); @@ -520,8 +522,6 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - } - if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { // See also error in V3Number nodeForUnsizedWarning(nodep)->v3warn( From 964dcd5b7c326ef29beee77345bce5c4c63e9f9c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 19:23:27 -0400 Subject: [PATCH 13/88] Tests: Add additional array method tests and error --- src/V3Width.cpp | 4 + test_regress/t/t_array_method.out | 70 +++++++++++++++++ test_regress/t/t_array_method.pl | 23 ++++++ test_regress/t/t_array_method.v | 118 ++++++++++++++++++++++++++++ test_regress/t/t_assoc_meth_bad.out | 16 ++++ test_regress/t/t_assoc_meth_bad.v | 5 ++ test_regress/t/t_assoc_method.out | 52 ++++++++++++ test_regress/t/t_assoc_method.pl | 23 ++++++ test_regress/t/t_assoc_method.v | 99 +++++++++++++++++++++++ test_regress/t/t_queue_method.pl | 6 +- 10 files changed, 413 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_array_method.out create mode 100755 test_regress/t/t_array_method.pl create mode 100644 test_regress/t/t_array_method.v create mode 100644 test_regress/t/t_assoc_method.out create mode 100755 test_regress/t/t_assoc_method.pl create mode 100644 test_regress/t/t_assoc_method.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 52b564683..9d6b45872 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2386,6 +2386,10 @@ private: newp->protect(false); newp->makeStatement(); } + } else if (nodep->name() == "sort" || nodep->name() == "rsort" + || nodep->name() == "reverse" || nodep->name() == "shuffle") { + nodep->v3error("Array method " << nodep->prettyNameQ() + << " not legal on associative arrays"); } else { nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); } diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out new file mode 100644 index 000000000..949655f73 --- /dev/null +++ b/test_regress/t/t_array_method.out @@ -0,0 +1,70 @@ +%Error-UNSUPPORTED: t/t_array_method.v:26:14: Unsupported: with statements + 26 | q.sort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:28:17: Unsupported: with statements + 28 | q.sort(x) with (x == 3); + | ^~~~ +%Error: t/t_array_method.v:28:14: Can't find definition of variable: 'x' + 28 | q.sort(x) with (x == 3); + | ^ +%Error-UNSUPPORTED: t/t_array_method.v:30:18: Unsupported: with statements + 30 | qe.sort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:35:15: Unsupported: with statements + 35 | q.rsort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:37:19: Unsupported: with statements + 37 | qe.rsort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:57:19: Unsupported: with statements + 57 | qv = q.find with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:59:25: Unsupported: with statements + 59 | qv = q.find_index with (item == 2); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:61:25: Unsupported: with statements + 61 | qv = q.find_first with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:63:31: Unsupported: with statements + 63 | qv = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:65:24: Unsupported: with statements + 65 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:67:30: Unsupported: with statements + 67 | qv = q.find_last_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:70:19: Unsupported: with statements + 70 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:72:25: Unsupported: with statements + 72 | qv = q.find_index with (item == 20); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:74:25: Unsupported: with statements + 74 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:76:31: Unsupported: with statements + 76 | qv = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:78:24: Unsupported: with statements + 78 | qv = q.find_last with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:80:30: Unsupported: with statements + 80 | qv = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:96:17: Unsupported: with statements + 96 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",96, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:98:21: Unsupported: with statements + 98 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",98, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:105:17: Unsupported: with statements + 105 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",105, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:107:16: Unsupported: with statements + 107 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",107, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:109:17: Unsupported: with statements + 109 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",109, (i), (32'hb)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_array_method.pl b/test_regress/t/t_array_method.pl new file mode 100755 index 000000000..be66c40e6 --- /dev/null +++ b/test_regress/t/t_array_method.pl @@ -0,0 +1,23 @@ +#!/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(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_array_method.v b/test_regress/t/t_array_method.v new file mode 100644 index 000000000..90e37de31 --- /dev/null +++ b/test_regress/t/t_array_method.v @@ -0,0 +1,118 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[5]; + int qe[$]; + int qv[$]; + int i; + string v; + + q = '{1, 2, 2, 4, 3}; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); + + // NOT tested: with ... selectors + + q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + q.sort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); + q.sort(x) with (x == 3); + v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); + qe.sort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + q.rsort; + v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); + q.rsort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); + qe.rsort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + qv = q.unique; + v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); + qv = qe.unique; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.unique_index; qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{0, 2, 3, 4} "); + q.reverse; + v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); + qe.reverse; + v = $sformatf("%p", qe); `checks(v, "'{}"); + q.shuffle(); q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + qe.shuffle(); qe.sort; + v = $sformatf("%p", qe); `checks(v, "'{}"); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = q.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + qv = q.find_index with (item == 2); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{1, 2} "); + qv = q.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_first_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_last_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + + qv = q.find with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_index with (item == 20); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + + qv = q.min; + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.max; + v = $sformatf("%p", qv); `checks(v, "'{4} "); + + qv = qe.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + + i = q.sum; `checkh(i, 32'hc); + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product; `checkh(i, 32'h30); + i = q.product with (item + 1); `checkh(i, 32'h168); + + i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); + + q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010}; + i = q.and; `checkh(i, 32'b1000); + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or; `checkh(i, 32'b1110); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor; `checkh(i, 32'ha); + i = q.xor with (item + 1); `checkh(i, 32'hb); + + i = qe.and; `checkh(i, 32'b0); + i = qe.or; `checkh(i, 32'b0); + i = qe.xor; `checkh(i, 32'b0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_assoc_meth_bad.out b/test_regress/t/t_assoc_meth_bad.out index 6b3d75789..496ecfee9 100644 --- a/test_regress/t/t_assoc_meth_bad.out +++ b/test_regress/t/t_assoc_meth_bad.out @@ -34,4 +34,20 @@ : ... In instance t 22 | a.delete(k, "bad2"); | ^~~~~~ +%Error: t/t_assoc_meth_bad.v:24:9: Array method 'sort' not legal on associative arrays + : ... In instance t + 24 | a.sort; + | ^~~~ +%Error: t/t_assoc_meth_bad.v:25:9: Array method 'rsort' not legal on associative arrays + : ... In instance t + 25 | a.rsort; + | ^~~~~ +%Error: t/t_assoc_meth_bad.v:26:9: Array method 'reverse' not legal on associative arrays + : ... In instance t + 26 | a.reverse; + | ^~~~~~~ +%Error: t/t_assoc_meth_bad.v:27:9: Array method 'shuffle' not legal on associative arrays + : ... In instance t + 27 | a.shuffle; + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_meth_bad.v b/test_regress/t/t_assoc_meth_bad.v index 7174b7844..bd4270f7f 100644 --- a/test_regress/t/t_assoc_meth_bad.v +++ b/test_regress/t/t_assoc_meth_bad.v @@ -20,5 +20,10 @@ module t (/*AUTOARG*/); v = a.last(); // Bad v = a.prev(k, "bad2"); // Bad a.delete(k, "bad2"); + + a.sort; // Not legal on assoc + a.rsort; // Not legal on assoc + a.reverse; // Not legal on assoc + a.shuffle; // Not legal on assoc end endmodule diff --git a/test_regress/t/t_assoc_method.out b/test_regress/t/t_assoc_method.out new file mode 100644 index 000000000..651f8fd92 --- /dev/null +++ b/test_regress/t/t_assoc_method.out @@ -0,0 +1,52 @@ +%Error-UNSUPPORTED: t/t_assoc_method.v:38:19: Unsupported: with statements + 38 | qv = q.find with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:40:25: Unsupported: with statements + 40 | qv = q.find_index with (item == 2); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:42:25: Unsupported: with statements + 42 | qv = q.find_first with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:44:31: Unsupported: with statements + 44 | qv = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:46:24: Unsupported: with statements + 46 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:48:30: Unsupported: with statements + 48 | qv = q.find_last_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:51:19: Unsupported: with statements + 51 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:53:25: Unsupported: with statements + 53 | qv = q.find_index with (item == 20); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:55:25: Unsupported: with statements + 55 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:57:31: Unsupported: with statements + 57 | qv = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:59:24: Unsupported: with statements + 59 | qv = q.find_last with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:61:30: Unsupported: with statements + 61 | qv = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:77:17: Unsupported: with statements + 77 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",77, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:79:21: Unsupported: with statements + 79 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",79, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:86:17: Unsupported: with statements + 86 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",86, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:88:16: Unsupported: with statements + 88 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:90:17: Unsupported: with statements + 90 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",90, (i), (32'b0110)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_assoc_method.pl b/test_regress/t/t_assoc_method.pl new file mode 100755 index 000000000..be66c40e6 --- /dev/null +++ b/test_regress/t/t_assoc_method.pl @@ -0,0 +1,23 @@ +#!/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(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v new file mode 100644 index 000000000..27586da10 --- /dev/null +++ b/test_regress/t/t_assoc_method.v @@ -0,0 +1,99 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[int]; + int qe[$]; + int qv[$]; + int i; + string v; + + q = '{10:1, 11:2, 12:2, 13:4, 14:3}; + v = $sformatf("%p", q); `checks(v, "'{0xa:1, 0xb:2, 0xc:2, 0xd:4, 0xe:3} "); + + // NOT tested: with ... selectors + + //q.sort; // Not legal on assoc - see t_assoc_meth_bad + //q.rsort; // Not legal on assoc - see t_assoc_meth_bad + //q.reverse; // Not legal on assoc - see t_assoc_meth_bad + //q.shuffle; // Not legal on assoc - see t_assoc_meth_bad + + qv = q.unique; + v = $sformatf("%p", qv); `checks(v, "'{1, 2, 4, 3} "); + qv = qe.unique; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.unique_index; qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{10, 11, 13, 14} "); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = q.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + qv = q.find_index with (item == 2); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{11, 12} "); + qv = q.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_first_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{11} "); + qv = q.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_last_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{12} "); + + qv = q.find with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_index with (item == 20); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + + qv = q.min; + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.max; + v = $sformatf("%p", qv); `checks(v, "'{4} "); + + qv = qe.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + + i = q.sum; `checkh(i, 32'hc); + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product; `checkh(i, 32'h30); + i = q.product with (item + 1); `checkh(i, 32'h168); + + i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); + + q = '{10:32'b1100, 11:32'b1010}; + i = q.and; `checkh(i, 32'b1000); + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or; `checkh(i, 32'b1110); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor; `checkh(i, 32'b0110); + i = q.xor with (item + 1); `checkh(i, 32'b0110); + + i = qe.and; `checkh(i, 32'b0); + i = qe.or; `checkh(i, 32'b0); + i = qe.xor; `checkh(i, 32'b0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_method.pl b/test_regress/t/t_queue_method.pl index f4321c541..be66c40e6 100755 --- a/test_regress/t/t_queue_method.pl +++ b/test_regress/t/t_queue_method.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; From d8df216a8d7b0453fd20f218966804c92a81d95b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 20:05:21 -0400 Subject: [PATCH 14/88] Fix emit indent of VL_TO_STRING --- src/V3Width.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9d6b45872..8514f01a0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3335,7 +3335,7 @@ private: argp->unlinkFrBack(&handle); AstCMath* newp = new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true); newp->addBodysp(argp); - newp->addBodysp(new AstText(nodep->fileline(), ")")); + newp->addBodysp(new AstText(nodep->fileline(), ")", true)); newp->dtypeSetString(); newp->pure(true); newp->protect(false); From 45766445916ffc129c7539c366e5bf6d9b46cf82 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 21:09:10 -0400 Subject: [PATCH 15/88] Prep for future queue slicing. --- include/verilated_heavy.h | 4 +- src/V3Width.cpp | 4 +- test_regress/t/t_queue_slice.out | 85 +------------------------------- test_regress/t/t_queue_slice.pl | 6 +-- test_regress/t/t_queue_slice.v | 26 ++++++++-- 5 files changed, 31 insertions(+), 94 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index eb43fe595..8b7412f03 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -281,7 +281,7 @@ public: // Clear array. Verilog: function void delete([input index]) void clear() { m_deque.clear(); } void erase(size_t index) { - if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); + if (VL_LIKELY(index < m_deque.size())) m_deque.erase(m_deque.begin() + index); } // Dynamic array new[] becomes a renew() @@ -349,7 +349,7 @@ public: // function void q.insert(index, value); void insert(size_t index, const T_Value& value) { if (VL_UNLIKELY(index >= m_deque.size())) return; - m_deque[index] = value; + m_deque.insert(m_deque.begin() + index, value); } // For save/restore diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 8514f01a0..506b6dcf1 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -151,7 +151,9 @@ public: if (!m_dtypep) { str << " VUP(s=" << m_stage << ",self)"; } else { - str << " VUP(s=" << m_stage << ",dt=" << cvtToHex(dtypep()) << ")"; + str << " VUP(s=" << m_stage << ",dt=" << cvtToHex(dtypep()); + dtypep()->dumpSmall(str); + str << ")"; } } }; diff --git a/test_regress/t/t_queue_slice.out b/test_regress/t/t_queue_slice.out index 2df592095..ec304cf36 100644 --- a/test_regress/t/t_queue_slice.out +++ b/test_regress/t/t_queue_slice.out @@ -1,85 +1,4 @@ -%Error-UNSUPPORTED: t/t_queue_slice.v:22:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' - : ... In instance t - 22 | q = '{"q", "b", "c", "d", "e", "f"}; +%Error-UNSUPPORTED: t/t_queue_slice.v:21:11: Unsupported: Empty '{} + 21 | q = '{}; | ^~ -%Error-UNSUPPORTED: t/t_queue_slice.v:25:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 25 | q = {"q", "b", "c", "d", "e", "f"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:28:9: Unsupported: Queue .delete(index) method, as is O(n) complexity and slow. - : ... In instance t - 28 | q.delete(1); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_slice.v:32:9: Unsupported: Queue .insert method, as is O(n) complexity and slow. - : ... In instance t - 32 | q.insert(2, "ins2"); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_slice.v:38:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 38 | q = {"q", "b", "c", "d", "e", "f"}; - | ^ -%Error: t/t_queue_slice.v:39:12: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' - : ... In instance t - 39 | q = q[2:3]; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:41:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 41 | q = {"q", "b", "c", "d", "e", "f"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:42:15: Unsupported/illegal unbounded ('$') in this context. - : ... In instance t - 42 | q = q[3:$]; - | ^ -%Error: t/t_queue_slice.v:42:15: First value of [a:b] isn't a constant, maybe you want +: or -: - : ... In instance t - 42 | q = q[3:$]; - | ^ -%Error: t/t_queue_slice.v:42:12: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' - : ... In instance t - 42 | q = q[3:$]; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:46:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 46 | q = {q, "f1"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:47:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 47 | q = {q, "f2"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:48:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 48 | q = {"b1", q}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:49:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 49 | q = {"b2", q}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:50:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 50 | q = {q[0], q[2:$]}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:50:22: Unsupported/illegal unbounded ('$') in this context. - : ... In instance t - 50 | q = {q[0], q[2:$]}; - | ^ -%Error: t/t_queue_slice.v:50:22: First value of [a:b] isn't a constant, maybe you want +: or -: - : ... In instance t - 50 | q = {q[0], q[2:$]}; - | ^ -%Error: t/t_queue_slice.v:50:19: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' - : ... In instance t - 50 | q = {q[0], q[2:$]}; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:54:25: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 54 | string ai[$] = { "Foo", "Bar" }; - | ^ -%Error-UNSUPPORTED: t/t_queue_slice.v:59:14: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' - : ... In instance t - 59 | q = '{ "BB", "CC" }; - | ^~ -%Error-UNSUPPORTED: t/t_queue_slice.v:62:14: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 62 | q = { "BB", "CC" }; - | ^ %Error: Exiting due to diff --git a/test_regress/t/t_queue_slice.pl b/test_regress/t/t_queue_slice.pl index f4321c541..be66c40e6 100755 --- a/test_regress/t/t_queue_slice.pl +++ b/test_regress/t/t_queue_slice.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_queue_slice.v b/test_regress/t/t_queue_slice.v index e60539f4a..b1cd39408 100644 --- a/test_regress/t/t_queue_slice.v +++ b/test_regress/t/t_queue_slice.v @@ -7,7 +7,6 @@ `define stop $stop `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); -`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); module t (/*AUTOARG*/); initial begin @@ -19,7 +18,14 @@ module t (/*AUTOARG*/); i = q.size(); `checkh(i, 1); v = $sformatf("%p", q); `checks(v, "'{\"non-empty\"} "); + q = '{}; + i = q.size(); `checkh(i, 0); + + q = '{"q"}; + v = $sformatf("%p", q); `checks(v, "'{\"q\"} "); + q = '{"q", "b", "c", "d", "e", "f"}; + if (q[0] !== "q") $stop; v = $sformatf("%p", q); `checks(v, "'{\"q\", \"b\", \"c\", \"d\", \"e\", \"f\"} "); q = {"q", "b", "c", "d", "e", "f"}; @@ -27,6 +33,7 @@ module t (/*AUTOARG*/); q.delete(1); v = q[1]; `checks(v, "c"); + v = $sformatf("%p", q); `checks(v, "'{\"q\", \"c\", \"d\", \"e\", \"f\"} "); q.insert(0, "ins0"); q.insert(2, "ins2"); @@ -35,23 +42,32 @@ module t (/*AUTOARG*/); v = $sformatf("%p", q); `checks(v, "'{\"ins0\", \"q\", \"ins2\", \"c\", \"d\", \"e\", \"f\"} "); // Slicing - q = {"q", "b", "c", "d", "e", "f"}; + q = '{"q", "b", "c", "d", "e", "f"}; q = q[2:3]; v = $sformatf("%p", q); `checks(v, "'{\"c\", \"d\"} "); - q = {"q", "b", "c", "d", "e", "f"}; + q = '{"q", "b", "c", "d", "e", "f"}; q = q[3:$]; v = $sformatf("%p", q); `checks(v, "'{\"d\", \"e\", \"f\"} "); + q = q[$:$]; + v = $sformatf("%p", q); `checks(v, "'{\"f\"} "); // Similar using implied notation + q = '{"f"}; q = {q, "f1"}; // push_front q = {q, "f2"}; // push_front q = {"b1", q}; // push_back q = {"b2", q}; // push_back + v = $sformatf("%p", q); `checks(v, "'{\"b2\", \"b1\", \"f\", \"f1\", \"f2\"} "); + q = {q[0], q[2:$]}; // delete element 1 - v = $sformatf("%p", q); `checks(v, "'{\"b2\", \"d\", \"e\", \"f\", \"f1\", \"f2\"} "); + v = $sformatf("%p", q); `checks(v, "'{\"b2\", \"f\", \"f1\", \"f2\"} "); + + q = {"a", "b"}; + q = {q, q}; + v = $sformatf("%p", q); `checks(v, "'{\"a\", \"b\", \"a\", \"b\"} "); begin - string ai[$] = { "Foo", "Bar" }; + string ai[$] = '{ "Foo", "Bar" }; q = ai; // Copy i = q.size(); `checkh(i, 2); v = q.pop_front(); `checks(v, "Foo"); From 3d2503f9aa2593c553e5e79a9b49390b841787d6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 17 Oct 2020 21:20:52 -0400 Subject: [PATCH 16/88] Tests: Run execute on non-Verilator when unsupported test. --- test_regress/t/t_castdyn.pl | 8 +- test_regress/t/t_class2.pl | 8 +- test_regress/t/t_class_extends_this.pl | 6 +- test_regress/t/t_class_name.pl | 6 +- test_regress/t/t_class_param.pl | 6 +- test_regress/t/t_class_static.pl | 8 +- test_regress/t/t_class_static_order.pl | 6 +- test_regress/t/t_class_typedef.pl | 6 +- test_regress/t/t_class_uses_this_bad.pl | 6 +- ...ss_vparam_unsup.out => t_class_vparam.out} | 2 +- ...lass_vparam_unsup.pl => t_class_vparam.pl} | 6 +- ..._class_vparam_unsup.v => t_class_vparam.v} | 0 test_regress/t/t_event_control_unsup.pl | 6 +- test_regress/t/t_event_copy.pl | 6 +- test_regress/t/t_iff.pl | 8 +- test_regress/t/t_mailbox.pl | 6 +- test_regress/t/t_param_avec.pl | 6 +- test_regress/t/t_process.pl | 6 +- test_regress/t/t_semaphore.pl | 6 +- test_regress/t/t_stream_integer_type.out | 133 ++++++++++++++++++ test_regress/t/t_stream_integer_type.pl | 7 +- test_regress/t/t_timing_reentry.pl | 7 +- test_regress/t/t_var_static.pl | 8 +- test_regress/t/t_var_static_param.pl | 8 +- test_regress/t/t_with.out | 34 +++++ test_regress/t/{t_with_unsup.pl => t_with.pl} | 6 +- test_regress/t/{t_with_unsup.v => t_with.v} | 13 +- test_regress/t/t_with_unsup.out | 31 ---- 28 files changed, 249 insertions(+), 110 deletions(-) rename test_regress/t/{t_class_vparam_unsup.out => t_class_vparam.out} (65%) rename test_regress/t/{t_class_vparam_unsup.pl => t_class_vparam.pl} (89%) rename test_regress/t/{t_class_vparam_unsup.v => t_class_vparam.v} (100%) create mode 100644 test_regress/t/t_stream_integer_type.out create mode 100644 test_regress/t/t_with.out rename test_regress/t/{t_with_unsup.pl => t_with.pl} (89%) rename test_regress/t/{t_with_unsup.v => t_with.v} (75%) delete mode 100644 test_regress/t/t_with_unsup.out diff --git a/test_regress/t/t_castdyn.pl b/test_regress/t/t_castdyn.pl index 61eb2deec..2ad4a887d 100755 --- a/test_regress/t/t_castdyn.pl +++ b/test_regress/t/t_castdyn.pl @@ -15,11 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); -# -#file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/Dead/x); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class2.pl b/test_regress/t/t_class2.pl index 61eb2deec..2ad4a887d 100755 --- a/test_regress/t/t_class2.pl +++ b/test_regress/t/t_class2.pl @@ -15,11 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); -# -#file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/Dead/x); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_extends_this.pl b/test_regress/t/t_class_extends_this.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_class_extends_this.pl +++ b/test_regress/t/t_class_extends_this.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_name.pl b/test_regress/t/t_class_name.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_class_name.pl +++ b/test_regress/t/t_class_name.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_param.pl b/test_regress/t/t_class_param.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_class_param.pl +++ b/test_regress/t/t_class_param.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_static.pl b/test_regress/t/t_class_static.pl index 1befb2521..8d48ddb75 100755 --- a/test_regress/t/t_class_static.pl +++ b/test_regress/t/t_class_static.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + fails => $Self->{vlt_all}, # Verilator unsupported, bug546 expect_filename => $Self->{golden_filename}, - fails => $Self->{vlt_all} # Verilator unsupported, bug546 ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_static_order.pl b/test_regress/t/t_class_static_order.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_class_static_order.pl +++ b/test_regress/t/t_class_static_order.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_typedef.pl b/test_regress/t/t_class_typedef.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_class_typedef.pl +++ b/test_regress/t/t_class_typedef.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_class_uses_this_bad.pl b/test_regress/t/t_class_uses_this_bad.pl index 953874c82..45af9e7a6 100755 --- a/test_regress/t/t_class_uses_this_bad.pl +++ b/test_regress/t/t_class_uses_this_bad.pl @@ -8,16 +8,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(simulator => 1); +scenarios(linter => 1); compile( fails => 1, expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); - ok(1); 1; diff --git a/test_regress/t/t_class_vparam_unsup.out b/test_regress/t/t_class_vparam.out similarity index 65% rename from test_regress/t/t_class_vparam_unsup.out rename to test_regress/t/t_class_vparam.out index b0b72a8c4..c5a35f922 100644 --- a/test_regress/t/t_class_vparam_unsup.out +++ b/test_regress/t/t_class_vparam.out @@ -1,4 +1,4 @@ -%Error-UNSUPPORTED: t/t_class_vparam_unsup.v:13:40: Unsupported: parameterized packages +%Error-UNSUPPORTED: t/t_class_vparam.v:13:40: Unsupported: parameterized packages 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_vparam_unsup.pl b/test_regress/t/t_class_vparam.pl similarity index 89% rename from test_regress/t/t_class_vparam_unsup.pl rename to test_regress/t/t_class_vparam.pl index ce380f717..c6e10f70b 100755 --- a/test_regress/t/t_class_vparam_unsup.pl +++ b/test_regress/t/t_class_vparam.pl @@ -10,10 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -lint( +compile( fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + ok(1); 1; diff --git a/test_regress/t/t_class_vparam_unsup.v b/test_regress/t/t_class_vparam.v similarity index 100% rename from test_regress/t/t_class_vparam_unsup.v rename to test_regress/t/t_class_vparam.v diff --git a/test_regress/t/t_event_control_unsup.pl b/test_regress/t/t_event_control_unsup.pl index f4321c541..be66c40e6 100755 --- a/test_regress/t/t_event_control_unsup.pl +++ b/test_regress/t/t_event_control_unsup.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_event_copy.pl b/test_regress/t/t_event_copy.pl index f4321c541..be66c40e6 100755 --- a/test_regress/t/t_event_copy.pl +++ b/test_regress/t/t_event_copy.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_iff.pl b/test_regress/t/t_iff.pl index 23d25a694..734924e17 100755 --- a/test_regress/t/t_iff.pl +++ b/test_regress/t/t_iff.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - expect_filename => $Self->{golden_filename}, fails => $Self->{vlt_all}, # Verilator unsupported, bug1482, iff not supported + expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_mailbox.pl b/test_regress/t/t_mailbox.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_mailbox.pl +++ b/test_regress/t/t_mailbox.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_param_avec.pl b/test_regress/t/t_param_avec.pl index 9829facd7..b2836602c 100755 --- a/test_regress/t/t_param_avec.pl +++ b/test_regress/t/t_param_avec.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_process.pl +++ b/test_regress/t/t_process.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_semaphore.pl b/test_regress/t/t_semaphore.pl index b8b56e6f0..2ad4a887d 100755 --- a/test_regress/t/t_semaphore.pl +++ b/test_regress/t/t_semaphore.pl @@ -15,9 +15,9 @@ compile( expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_stream_integer_type.out b/test_regress/t/t_stream_integer_type.out new file mode 100644 index 000000000..e6d1b0876 --- /dev/null +++ b/test_regress/t/t_stream_integer_type.out @@ -0,0 +1,133 @@ +%Warning-WIDTH: t/t_stream_integer_type.v:118:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t + 118 | packed_data_32 = {<<8{byte_in}}; + | ^ + ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. +%Warning-WIDTH: t/t_stream_integer_type.v:119:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. + : ... In instance t + 119 | packed_data_64 = {<<16{shortint_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:120:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t + 120 | packed_data_128 = {<<32{int_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:121:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t + 121 | packed_data_128_i = {<<32{integer_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:122:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. + : ... In instance t + 122 | packed_data_256 = {<<64{longint_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:123:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. + : ... In instance t + 123 | packed_time_256 = {<<64{time_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:124:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t + 124 | v_packed_data_32 = {<<8{bit_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:125:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. + : ... In instance t + 125 | v_packed_data_64 = {<<16{logic_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:126:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t + 126 | v_packed_data_128 = {<<32{reg_in}}; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:128:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_32' generates 32 bits. + : ... In instance t + 128 | {<<8{byte_out}} = packed_data_32; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:129:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_64' generates 64 bits. + : ... In instance t + 129 | {<<16{shortint_out}} = packed_data_64; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:130:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128' generates 128 bits. + : ... In instance t + 130 | {<<32{int_out}} = packed_data_128; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:131:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128_i' generates 128 bits. + : ... In instance t + 131 | {<<32{integer_out}} = packed_data_128_i; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:132:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_256' generates 256 bits. + : ... In instance t + 132 | {<<64{longint_out}} = packed_data_256; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:133:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_time_256' generates 256 bits. + : ... In instance t + 133 | {<<64{time_out}} = packed_time_256; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:134:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_32' generates 32 bits. + : ... In instance t + 134 | {<<8{bit_out}} = v_packed_data_32; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:135:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_64' generates 64 bits. + : ... In instance t + 135 | {<<16{logic_out}} = v_packed_data_64; + | ^ +%Warning-WIDTH: t/t_stream_integer_type.v:136:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_128' generates 128 bits. + : ... In instance t + 136 | {<<32{reg_out}} = v_packed_data_128; + | ^ +%Error: t/t_stream_integer_type.v:150:33: Operator STREAML expected non-datatype RHS but 'byte' is a datatype. + : ... In instance t + 150 | packed_data_32 = {< 1); compile( fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_timing_reentry.pl b/test_regress/t/t_timing_reentry.pl index cf634ac0e..dec83b460 100755 --- a/test_regress/t/t_timing_reentry.pl +++ b/test_regress/t/t_timing_reentry.pl @@ -19,10 +19,9 @@ compile( make_top => 1, ); -# Will fail, unsupported -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_var_static.pl b/test_regress/t/t_var_static.pl index 1befb2521..8d48ddb75 100755 --- a/test_regress/t/t_var_static.pl +++ b/test_regress/t/t_var_static.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + fails => $Self->{vlt_all}, # Verilator unsupported, bug546 expect_filename => $Self->{golden_filename}, - fails => $Self->{vlt_all} # Verilator unsupported, bug546 ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_var_static_param.pl b/test_regress/t/t_var_static_param.pl index 1befb2521..8d48ddb75 100755 --- a/test_regress/t/t_var_static_param.pl +++ b/test_regress/t/t_var_static_param.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + fails => $Self->{vlt_all}, # Verilator unsupported, bug546 expect_filename => $Self->{golden_filename}, - fails => $Self->{vlt_all} # Verilator unsupported, bug546 ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_with.out b/test_regress/t/t_with.out new file mode 100644 index 000000000..5d3e1a04c --- /dev/null +++ b/test_regress/t/t_with.out @@ -0,0 +1,34 @@ +%Error-UNSUPPORTED: t/t_with.v:19:31: Unsupported: with statements + 19 | found = aliases.find(i) with (i == tofind); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:21:23: Unsupported: with statements + 21 | aliases.find(i) with (i == tofind); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:24:28: Unsupported: with statements + 24 | found = aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:25:20: Unsupported: with statements + 25 | aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:29:30: Unsupported: with statements + 29 | found = aliases.unique with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:30:32: Unsupported: with statements + 30 | found = aliases.unique() with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:31:33: Unsupported: with statements + 31 | found = aliases.unique(i) with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:32:25: Unsupported: with statements + 32 | i = aliases.or(v) with (v); + | ^~~~ +%Error: t/t_with.v:32:22: Can't find definition of variable: 'v' + 32 | i = aliases.or(v) with (v); + | ^ +%Error-UNSUPPORTED: t/t_with.v:33:26: Unsupported: with statements + 33 | i = aliases.and(v) with (v); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:34:26: Unsupported: with statements + 34 | i = aliases.xor(v) with (v); + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_with_unsup.pl b/test_regress/t/t_with.pl similarity index 89% rename from test_regress/t/t_with_unsup.pl rename to test_regress/t/t_with.pl index ce380f717..c6e10f70b 100755 --- a/test_regress/t/t_with_unsup.pl +++ b/test_regress/t/t_with.pl @@ -10,10 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -lint( +compile( fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + ok(1); 1; diff --git a/test_regress/t/t_with_unsup.v b/test_regress/t/t_with.v similarity index 75% rename from test_regress/t/t_with_unsup.v rename to test_regress/t/t_with.v index 1c9c1a2d7..c0989a818 100644 --- a/test_regress/t/t_with_unsup.v +++ b/test_regress/t/t_with.v @@ -16,9 +16,9 @@ module t (/*AUTOARG*/); int i; aliases = '{ 1, 4, 6, 8}; tofind = 6; - found = aliases.find(i) with (i == to_find); + found = aliases.find(i) with (i == tofind); // And as function - aliases.find(i) with (i == to_find); + aliases.find(i) with (i == tofind); // No parenthesis found = aliases.find with (item == i); @@ -29,9 +29,12 @@ module t (/*AUTOARG*/); found = aliases.unique with (id); found = aliases.unique() with (id); found = aliases.unique(i) with (id); - found = aliases.or with (id); - found = aliases.and with (id); - found = aliases.xor with (id); + i = aliases.or(v) with (v); + i = aliases.and(v) with (v); + i = aliases.xor(v) with (v); + + $write("*-* All Finished *-*\n"); + $finish; end endmodule diff --git a/test_regress/t/t_with_unsup.out b/test_regress/t/t_with_unsup.out deleted file mode 100644 index 62705e280..000000000 --- a/test_regress/t/t_with_unsup.out +++ /dev/null @@ -1,31 +0,0 @@ -%Error-UNSUPPORTED: t/t_with_unsup.v:19:31: Unsupported: with statements - 19 | found = aliases.find(i) with (i == to_find); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:21:23: Unsupported: with statements - 21 | aliases.find(i) with (i == to_find); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:24:28: Unsupported: with statements - 24 | found = aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:25:20: Unsupported: with statements - 25 | aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:29:30: Unsupported: with statements - 29 | found = aliases.unique with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:30:32: Unsupported: with statements - 30 | found = aliases.unique() with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:31:33: Unsupported: with statements - 31 | found = aliases.unique(i) with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:32:26: Unsupported: with statements - 32 | found = aliases.or with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:33:27: Unsupported: with statements - 33 | found = aliases.and with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with_unsup.v:34:27: Unsupported: with statements - 34 | found = aliases.xor with (id); - | ^~~~ -%Error: Exiting due to From ec36d0d7723a1c2faf5374a4e491ad402d17ddc6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 18 Oct 2020 12:30:33 -0400 Subject: [PATCH 17/88] Internals: When resolving assignments pass dtype to children. --- src/V3Width.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 506b6dcf1..ebba38d68 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4747,9 +4747,9 @@ private: << " expected non-datatype " << side << " but '" << underp->name() << "' is a datatype."); } else if (expDTypep == underp->dtypep()) { // Perfect - underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, FINAL).p()); + underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p()); } else if (expDTypep->isDouble() && underp->isDouble()) { // Also good - underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, FINAL).p()); + underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p()); } else if (expDTypep->isDouble() && !underp->isDouble()) { AstNode* oldp = underp; // Need FINAL on children; otherwise splice would block it underp = spliceCvtD(underp); From 5d3dd52f13ebf40b1d5f37633a4a4a3efe54ce7a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 18 Oct 2020 13:23:02 -0400 Subject: [PATCH 18/88] Support queue slicing (#2326). --- Changes | 2 + include/verilated_heavy.h | 35 +++++++++ src/V3Ast.h | 5 +- src/V3AstNodes.h | 22 ++++++ src/V3EmitC.cpp | 16 ++++ src/V3Width.cpp | 123 +++++++++++++++++++++++++------ src/V3WidthSel.cpp | 9 +++ src/verilog.y | 3 +- test_regress/t/t_queue_slice.out | 4 - test_regress/t/t_queue_slice.pl | 4 +- 10 files changed, 189 insertions(+), 34 deletions(-) delete mode 100644 test_regress/t/t_queue_slice.out diff --git a/Changes b/Changes index a57ebbf3d..ffa68c30d 100644 --- a/Changes +++ b/Changes @@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.103 devel +**** Support queue slicing (#2326). + * Verilator 4.102 2020-10-15 diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 8b7412f03..86c8a5c5b 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -272,6 +272,32 @@ public: } ~VlQueue() {} // Standard copy constructor works. Verilog: assoca = assocb + static VlQueue cons(const T_Value& lhs) { + VlQueue out; + out.push_back(lhs); + return out; + } + static VlQueue cons(const T_Value& lhs, const T_Value& rhs) { + VlQueue out; + out.push_back(rhs); + out.push_back(lhs); + return out; + } + static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) { + VlQueue out = lhs; + out.push_front(rhs); + return out; + } + static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) { + VlQueue out = rhs; + out.push_back(lhs); + return out; + } + static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) { + VlQueue out = rhs; + for (const auto& i : lhs.m_deque) out.push_back(i); + return out; + } // METHODS T_Value& atDefault() { return m_defaultValue; } @@ -352,6 +378,15 @@ public: m_deque.insert(m_deque.begin() + index, value); } + // Return slice q[lsb:msb] + VlQueue slice(size_t lsb, size_t msb) const { + VlQueue out; + if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1; + if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1; + for (size_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); + return out; + } + // For save/restore const_iterator begin() const { return m_deque.begin(); } const_iterator end() const { return m_deque.end(); } diff --git a/src/V3Ast.h b/src/V3Ast.h index fa4b9083c..47395909c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1254,7 +1254,10 @@ public: /// along with all children and next(s). This is often better to use /// than an immediate deleteTree, as any pointers into this node will /// persist for the lifetime of the visitor - void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); } + void pushDeletep(AstNode* nodep) { + UASSERT_STATIC(nodep, "Cannot delete nullptr node"); + m_deleteps.push_back(nodep); + } /// Call deleteTree on all previously pushDeletep()'ed nodes void doDeletes(); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 25400841a..69e448bd8 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4599,6 +4599,28 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; +class AstConsQueue : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ConsQueue) + virtual string emitVerilog() override { return "'{%l, %r}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } // op1 = expression + AstNode* rhsp() const { return op2p(); } // op2 = expression + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; + class AstBegin : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index b9b267cb9..e84182200 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1575,6 +1575,22 @@ class EmitCImp : EmitCStmts { } } + virtual void visit(AstConsQueue* nodep) override { + putbs(nodep->dtypep()->cType("", false, false)); + if (!nodep->lhsp()) { + puts("()"); + } else { + puts("::cons("); + iterateAndNextNull(nodep->lhsp()); + if (nodep->rhsp()) { + puts(", "); + putbs(""); + } + iterateAndNextNull(nodep->rhsp()); + puts(")"); + } + } + virtual void visit(AstChangeDet* nodep) override { // m_blkChangeDetVec.push_back(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ebba38d68..f2b7ca4ab 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -484,12 +484,20 @@ private: // LHS, RHS is self-determined // signed: Unsigned (11.8.1) // width: LHS + RHS + AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); + if (VN_IS(vdtypep, QueueDType)) { + // Queue "element 0" is lhsp, so we need to swap arguments + auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), + nodep->lhsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterateChildren(newp, m_vup); + return; + } if (m_vup->prelim()) { - AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - if (vdtypep - && (VN_IS(vdtypep, AssocArrayDType) // - || VN_IS(vdtypep, DynArrayDType) // - || VN_IS(vdtypep, QueueDType))) { + if (VN_IS(vdtypep, AssocArrayDType) // + || VN_IS(vdtypep, DynArrayDType) // + || VN_IS(vdtypep, QueueDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ() << "data type"); } @@ -609,14 +617,6 @@ private: // LHS, RHS is self-determined // width: value(LHS) * width(RHS) if (m_vup->prelim()) { - AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - if (vdtypep - && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) - || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " - << vdtypep->prettyDTypeNameQ() << " data type"); - } - iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change const AstConst* constp = VN_CAST(nodep->rhsp(), Const); @@ -631,6 +631,26 @@ private: "1800-2017 11.4.12.1)"); times = 1; } + + AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); + if (VN_IS(vdtypep, QueueDType)) { + if (times != 1) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form " + << vdtypep->prettyDTypeNameQ() + << " data type"); + // Don't iterate lhsp as SELF, the potential Concat below needs + // the adtypep passed down to recognize the QueueDType + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, BOTH).p()); + nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, UnpackArrayDType)) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " + << vdtypep->prettyDTypeNameQ() << " data type"); + } + iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); if (nodep->lhsp()->isString()) { AstNode* newp = new AstReplicateN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack()); @@ -1133,10 +1153,21 @@ private: } virtual void visit(AstUnbounded* nodep) override { nodep->dtypeSetSigned32(); // Used in int context - if (!VN_IS(nodep->backp(), IsUnbounded) && !VN_IS(nodep->backp(), BracketArrayDType) - && !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); + if (VN_IS(nodep->backp(), IsUnbounded)) return; // Ok, leave + if (VN_IS(nodep->backp(), BracketArrayDType)) return; // Ok, leave + if (auto* varp = VN_CAST(nodep->backp(), Var)) { + if (varp->isParam()) return; // Ok, leave } + // queue_slice[#:$] + if (auto* selp = VN_CAST(nodep->backp(), SelExtract)) { + if (VN_IS(selp->fromp()->dtypep(), QueueDType)) { + nodep->replaceWith( + new AstConst(nodep->fileline(), AstConst::Signed32(), 0x7FFFFFFF)); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } + } + nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); } virtual void visit(AstIsUnbounded* nodep) override { if (m_vup->prelim()) { @@ -1928,6 +1959,38 @@ private: } nodep->dtypeFrom(nodep->itemp()); } + virtual void visit(AstConsQueue* nodep) override { // + // Type computed when constructed here + AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType); + UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type"); + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p()); + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p()); + nodep->dtypeFrom(vdtypep); + } + if (m_vup->final()) { + // Arguments can be either elements of the queue or a queue itself + // Concats (part of tree of concats) must always become ConsQueue's + if (nodep->lhsp()) { + if (VN_IS(nodep->lhsp()->dtypep(), QueueDType) + || VN_IS(nodep->lhsp(), ConsQueue)) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + // Sub elements are not queues, but concats, must always pass concats down + iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL); + } + } + if (nodep->rhsp()) { + if (VN_IS(nodep->rhsp()->dtypep(), QueueDType) + || VN_IS(nodep->rhsp(), ConsQueue)) { + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL); + } + } + nodep->dtypeFrom(vdtypep); + } + } virtual void visit(AstInitItem* nodep) override { // userIterateChildren(nodep, m_vup); } @@ -2490,12 +2553,10 @@ private: newp->didWidth(true); newp->makeStatement(); } else { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Queue .delete(index) method, as is O(n) " - "complexity and slow."); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); newp->protect(false); + newp->didWidth(true); newp->makeStatement(); } } @@ -2511,9 +2572,6 @@ private: newp->protect(false); newp->makeStatement(); } else { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Queue .insert method, as is O(n) complexity and slow."); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), index_exprp->unlinkFrBack()); newp->addPinsp(argp->exprp()->unlinkFrBack()); @@ -2874,10 +2932,12 @@ private: while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) { dtypep = vdtypep->subDTypep()->skipRefp(); } - if (AstNodeUOrStructDType* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { + if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); - } else if (AstNodeArrayDType* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { + } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep); + } else if (auto* vdtypep = VN_CAST(dtypep, QueueDType)) { + VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep); } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep); } else { @@ -3038,6 +3098,21 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) { + AstNode* newp = new AstConsQueue(nodep->fileline()); + newp->dtypeFrom(arrayp); + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { + patp->dtypep(arrayp->subDTypep()); + AstNode* valuep = patternMemberValueIterate(patp); + auto* newap = new AstConsQueue(nodep->fileline(), valuep, newp); + newap->dtypeFrom(arrayp); + newp = newap; + } + nodep->replaceWith(newp); + // if (debug() >= 9) newp->dumpTree("-apat-out: "); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present + } void patternBasic(AstPattern* nodep, AstNodeDType* vdtypep, AstPatMember* defaultp) { AstBasicDType* bdtypep = VN_CAST(vdtypep, BasicDType); VNumRange range = bdtypep->declRange(); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index ce6cdcee8..8e3b09316 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -439,6 +439,15 @@ private: // if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, QueueDType)) { + auto* newp = new AstCMethodHard(nodep->fileline(), fromp, "slice", msbp); + msbp->addNext(lsbp); + newp->dtypep(ddtypep); + newp->didWidth(true); + newp->protect(false); + UINFO(6, " new " << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { // nullptr=bad extract, or unknown node type nodep->v3error("Illegal range select; type already selected, or bad dimension: " << "data type is " << fromdata.m_errp->prettyDTypeNameQ()); diff --git a/src/verilog.y b/src/verilog.y index 414043f6b..eee186507 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3403,8 +3403,7 @@ assignment_pattern: // ==IEEE: assignment_pattern // // also IEEE "''{' array_pattern_key ':' ... | yP_TICKBRA patternMemberList '}' { $$ = new AstPattern($1,$2); } // // IEEE: Not in grammar, but in VMM - | yP_TICKBRA '}' - { $$ = new AstPattern($1, nullptr); $1->v3warn(E_UNSUPPORTED, "Unsupported: Empty '{}"); } + | yP_TICKBRA '}' { $$ = new AstPattern($1, nullptr); } ; // "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal diff --git a/test_regress/t/t_queue_slice.out b/test_regress/t/t_queue_slice.out deleted file mode 100644 index ec304cf36..000000000 --- a/test_regress/t/t_queue_slice.out +++ /dev/null @@ -1,4 +0,0 @@ -%Error-UNSUPPORTED: t/t_queue_slice.v:21:11: Unsupported: Empty '{} - 21 | q = '{}; - | ^~ -%Error: Exiting due to diff --git a/test_regress/t/t_queue_slice.pl b/test_regress/t/t_queue_slice.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_queue_slice.pl +++ b/test_regress/t/t_queue_slice.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; From 25593c0ee27460694c9ad7bbdae23099078b7021 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 22 Oct 2020 17:13:42 -0400 Subject: [PATCH 19/88] Fix capitalization --- src/V3Width.cpp | 4 ++-- test_regress/t/t_lint_width_bad.out | 8 ++++++-- test_regress/t/t_lint_width_bad.v | 2 ++ test_regress/t/t_param_noval_bad.out | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f2b7ca4ab..e0b17d71b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4782,7 +4782,7 @@ private: new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); } else if (!underp->dtypep()->basicp()) { - nodep->v3error("Logical Operator " << nodep->prettyTypeName() + nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " << side << "."); underp->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse())); @@ -4792,7 +4792,7 @@ private: if (bad) { { // if (warnOn), but not needed here if (debug() > 4) nodep->backp()->dumpTree(cout, " back: "); - nodep->v3warn(WIDTH, "Logical Operator " + nodep->v3warn(WIDTH, "Logical operator " << nodep->prettyTypeName() << " expects 1 bit on the " << side << ", but " << side << "'s " << underp->prettyTypeName() << " generates " diff --git a/test_regress/t/t_lint_width_bad.out b/test_regress/t/t_lint_width_bad.out index b2802d6b0..fc4484be1 100644 --- a/test_regress/t/t_lint_width_bad.out +++ b/test_regress/t/t_lint_width_bad.out @@ -3,9 +3,9 @@ 17 | localparam [3:0] XS = 'hx; | ^~ ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_lint_width_bad.v:45:19: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits. +%Warning-WIDTH: t/t_lint_width_bad.v:47:19: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits. : ... In instance t.p4 - 45 | wire [4:0] out = in; + 47 | wire [4:0] out = in; | ^ %Warning-WIDTH: t/t_lint_width_bad.v:21:25: Operator SHIFTL expects 5 bits on the LHS, but LHS's CONST '1'h1' generates 1 bits. : ... In instance t @@ -39,4 +39,8 @@ : ... In instance t 38 | initial for (a = 0; a >= THREE; ++a) $display(a); | ^~ +%Warning-WIDTH: t/t_lint_width_bad.v:40:12: Logical operator IF expects 1 bit on the If, but If's VARREF 'THREE' generates 41 bits. + : ... In instance t + 40 | initial if (THREE) $stop; + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_width_bad.v b/test_regress/t/t_lint_width_bad.v index e8f18a128..4e6affbc7 100644 --- a/test_regress/t/t_lint_width_bad.v +++ b/test_regress/t/t_lint_width_bad.v @@ -37,6 +37,8 @@ module t (); initial for (a = 0; a > THREE; ++a) $display(a); initial for (a = 0; a >= THREE; ++a) $display(a); + initial if (THREE) $stop; + endmodule module p diff --git a/test_regress/t/t_param_noval_bad.out b/test_regress/t/t_param_noval_bad.out index 988947e3a..606fca350 100644 --- a/test_regress/t/t_param_noval_bad.out +++ b/test_regress/t/t_param_noval_bad.out @@ -2,7 +2,7 @@ : ... In instance t 7 | module t #(parameter P); | ^ -%Warning-WIDTH: t/t_param_noval_bad.v:10:7: Logical Operator GENFOR expects 1 bit on the For Test Condition, but For Test Condition's VARREF 'P' generates 32 bits. +%Warning-WIDTH: t/t_param_noval_bad.v:10:7: Logical operator GENFOR expects 1 bit on the For Test Condition, but For Test Condition's VARREF 'P' generates 32 bits. : ... In instance t 10 | for (j=0; P; j++) | ^~~ From 4cec3ff2a05ea407b56644d092ad57d56ca81096 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 22 Oct 2020 17:27:23 -0400 Subject: [PATCH 20/88] Fix WIDTH warnings on comparisons with nullptr (#2602). --- Changes | 2 ++ src/V3Width.cpp | 6 ++++++ src/verilog.y | 2 +- test_regress/t/t_class1.v | 3 +++ test_regress/t/t_var_types.v | 5 +++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index ffa68c30d..c2fff4499 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support queue slicing (#2326). +**** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] + * Verilator 4.102 2020-10-15 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e0b17d71b..7e91a0362 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4781,6 +4781,12 @@ private: = new AstNeqD(nodep->fileline(), underp, new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); + } else if (VN_IS(underp->dtypep(), ClassRefDType) + || (VN_IS(underp->dtypep(), BasicDType) + && VN_CAST(underp->dtypep(), BasicDType)->keyword() + == AstBasicDTypeKwd::CHANDLE)) { + // Allow warning-free "if (handle)" + VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed } else if (!underp->dtypep()->basicp()) { nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " diff --git a/src/verilog.y b/src/verilog.y index eee186507..dfbe30a97 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4228,7 +4228,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // Indistinguishable from function_subroutine_call:method_call // | '$' { $$ = new AstUnbounded($1); } - | yNULL { $$ = new AstConst($1, AstConst::LogicFalse()); } + | yNULL { $$ = new AstConst($1, AstConst::StringToParse(), "'0"); } // // IEEE: yTHIS // // See exprScope // diff --git a/test_regress/t/t_class1.v b/test_regress/t/t_class1.v index 6d9a663f1..b584c5be6 100644 --- a/test_regress/t/t_class1.v +++ b/test_regress/t/t_class1.v @@ -15,8 +15,11 @@ module t (/*AUTOARG*/); initial begin Cls c; if (c != null) $stop; + if (c) $stop; $display("Display: null = \"%p\"", c); // null c = new; + if (c == null) $stop; + if (!c) $stop; $display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0} c.imembera = 10; c.imemberb = 20; diff --git a/test_regress/t/t_var_types.v b/test_regress/t/t_var_types.v index 75a06d55e..273ad4691 100644 --- a/test_regress/t/t_var_types.v +++ b/test_regress/t/t_var_types.v @@ -216,6 +216,11 @@ module t (/*AUTOARG*/); d_time = $time; if ($time !== d_time) $stop; + // Null checks + d_chandle = null; + if (d_chandle != null) $stop; + if (d_chandle) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 9d0a7d5e702e06d505078b0e8445bd81a9a5c27c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 23 Oct 2020 18:30:10 -0400 Subject: [PATCH 21/88] Commentary (#2606). --- src/V3Order.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 915f88ee2..6be9a3fa6 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -36,6 +36,9 @@ // assignments to avoid saving state, thus we prefer // a <= b ... As the opposite order would // b <= c ... require the old value of b. +// Add edge consumed_var_POST->logic_vertex +// This prevents a consumer of the "early" value to be +// scheduled after we've changed to the next-cycle value // For Logic // Add vertex for this logic // Add edge logic_sensitive_vertex->logic_vertex @@ -49,6 +52,7 @@ // Add edge logic_sensitive_vertex->logic_vertex // Add edge logic_consumed_var->logic_vertex (same as if comb) // Add edge logic_vertex->logic_generated_var (same as if comb) +// Add edge consumed_var_POST->logic_vertex (same as if comb) // // For comb logic // For comb logic From 2f21b3385a01901a8ad71c423702ec37d4e909cc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 24 Oct 2020 17:46:09 -0400 Subject: [PATCH 22/88] Tests: Casting. --- test_regress/t/t_castdyn.out | 28 +++++++++++++++--- test_regress/t/t_castdyn.v | 51 ++++++++++++++++++++++++++++++-- test_regress/t/t_castdyn_bad.out | 9 ++++++ test_regress/t/t_castdyn_bad.pl | 23 ++++++++++++++ test_regress/t/t_castdyn_bad.v | 28 ++++++++++++++++++ 5 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 test_regress/t/t_castdyn_bad.out create mode 100755 test_regress/t/t_castdyn_bad.pl create mode 100644 test_regress/t/t_castdyn_bad.v diff --git a/test_regress/t/t_castdyn.out b/test_regress/t/t_castdyn.out index 8f9e32b5e..14761e02a 100644 --- a/test_regress/t/t_castdyn.out +++ b/test_regress/t/t_castdyn.out @@ -1,9 +1,29 @@ -%Error-UNSUPPORTED: t/t_castdyn.v:12:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:28:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 12 | i = $cast(a, b); + 28 | i = $cast(ao, a); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:14:7: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:32:7: Unsupported: $cast. Suggest try static cast. : ... In instance t - 14 | $cast(a, b); + 32 | $cast(ao, a); | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:35:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 35 | i = $cast(ao, 2.1 * 3.7); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:39:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 39 | i = $cast(bo, null); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:45:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 45 | i = $cast(bao, b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:51:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 51 | i = $cast(bbo, b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:57:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 57 | i = $cast(bao, b); + | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_castdyn.v b/test_regress/t/t_castdyn.v index 3fd235e82..2d788ca51 100644 --- a/test_regress/t/t_castdyn.v +++ b/test_regress/t/t_castdyn.v @@ -4,14 +4,59 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +class Base; +endclass +class BasedA extends Base; +endclass +class BasedB extends Base; +endclass + module t (/*AUTOARG*/); int i; int a; - int b; + int ao; + + Base b; + Base bo; + BasedA ba; + BasedA bao; + BasedB bb; + BasedB bbo; + initial begin - i = $cast(a, b); + a = 1234; + i = $cast(ao, a); if (i != 1) $stop; - $cast(a, b); + if (ao != 1234) $stop; + a = 12345; + $cast(ao, a); + if (ao != 12345) $stop; + + i = $cast(ao, 2.1 * 3.7); + if (i != 1) $stop; + if (ao != 8) $stop; + + i = $cast(bo, null); + if (i != 1) $stop; + if (bo != null) $stop; + + ba = new; + b = ba; + i = $cast(bao, b); + if (i != 1) $stop; + if (b != ba) $stop; + + bb = new; + b = bb; + i = $cast(bbo, b); + if (i != 1) $stop; + if (b != bb) $stop; + + bb = new; + b = b; + i = $cast(bao, b); + if (i != 0) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_castdyn_bad.out b/test_regress/t/t_castdyn_bad.out new file mode 100644 index 000000000..030a8b1ac --- /dev/null +++ b/test_regress/t/t_castdyn_bad.out @@ -0,0 +1,9 @@ +%Error-UNSUPPORTED: t/t_castdyn_bad.v:20:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 20 | i = $cast(c, b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn_bad.v:23:7: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 23 | $cast(c, b); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_castdyn_bad.pl b/test_regress/t/t_castdyn_bad.pl new file mode 100755 index 000000000..2ad4a887d --- /dev/null +++ b/test_regress/t/t_castdyn_bad.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_castdyn_bad.v b/test_regress/t/t_castdyn_bad.v new file mode 100644 index 000000000..37fe1ec74 --- /dev/null +++ b/test_regress/t/t_castdyn_bad.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Base; +endclass +class C; +endclass + +module t (/*AUTOARG*/); + int i; + + Base b; + C c; + + initial begin + b = new; + i = $cast(c, b); + if (i != 0) $stop; + + $cast(c, b); // Bad at runtime + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 51d1235cda2dc5ab26f76d0ceaa35120717efd2b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 24 Oct 2020 18:00:40 -0400 Subject: [PATCH 23/88] Shorter stringify of empty queues, and better queue tests --- include/verilated_heavy.h | 2 + test_regress/t/t_array_method.out | 82 ++++++++--------- test_regress/t/t_array_method.v | 56 ++++-------- test_regress/t/t_assoc_method.out | 74 +++++++-------- test_regress/t/t_assoc_method.v | 38 ++++---- test_regress/t/t_dynarray.v | 2 +- test_regress/t/t_queue_method.out | 88 +++++++++--------- test_regress/t/t_queue_method.v | 144 +++++++++++++++++------------- 8 files changed, 243 insertions(+), 243 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 86c8a5c5b..e7a01f21c 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -202,6 +202,7 @@ public: // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { + if (m_map.empty()) return "'{}"; // No trailing space std::string out = "'{"; std::string comma; for (const auto& i : m_map) { @@ -393,6 +394,7 @@ public: // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { + if (m_deque.empty()) return "'{}"; // No trailing space std::string out = "'{"; std::string comma; for (const auto& i : m_deque) { diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out index 949655f73..f8eeb31b2 100644 --- a/test_regress/t/t_array_method.out +++ b/test_regress/t/t_array_method.out @@ -7,64 +7,58 @@ %Error: t/t_array_method.v:28:14: Can't find definition of variable: 'x' 28 | q.sort(x) with (x == 3); | ^ -%Error-UNSUPPORTED: t/t_array_method.v:30:18: Unsupported: with statements - 30 | qe.sort(x) with (x == 3); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:35:15: Unsupported: with statements - 35 | q.rsort with (item == 2); +%Error-UNSUPPORTED: t/t_array_method.v:33:15: Unsupported: with statements + 33 | q.rsort with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:37:19: Unsupported: with statements - 37 | qe.rsort(x) with (x == 3); +%Error-UNSUPPORTED: t/t_array_method.v:47:19: Unsupported: with statements + 47 | qv = q.find with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:57:19: Unsupported: with statements - 57 | qv = q.find with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:59:25: Unsupported: with statements - 59 | qv = q.find_index with (item == 2); qv.sort; +%Error-UNSUPPORTED: t/t_array_method.v:49:25: Unsupported: with statements + 49 | qv = q.find_first with (item == 2); | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:51:24: Unsupported: with statements + 51 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:54:19: Unsupported: with statements + 54 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:56:25: Unsupported: with statements + 56 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_array_method.v:58:24: Unsupported: with statements + 58 | qv = q.find_last with (item == 20); + | ^~~~ %Error-UNSUPPORTED: t/t_array_method.v:61:25: Unsupported: with statements - 61 | qv = q.find_first with (item == 2); + 61 | qi = q.find_index with (item == 2); qi.sort; | ^~~~ %Error-UNSUPPORTED: t/t_array_method.v:63:31: Unsupported: with statements - 63 | qv = q.find_first_index with (item == 2); + 63 | qi = q.find_first_index with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:65:24: Unsupported: with statements - 65 | qv = q.find_last with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:67:30: Unsupported: with statements - 67 | qv = q.find_last_index with (item == 2); +%Error-UNSUPPORTED: t/t_array_method.v:65:30: Unsupported: with statements + 65 | qi = q.find_last_index with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:70:19: Unsupported: with statements - 70 | qv = q.find with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:72:25: Unsupported: with statements - 72 | qv = q.find_index with (item == 20); qv.sort; +%Error-UNSUPPORTED: t/t_array_method.v:68:25: Unsupported: with statements + 68 | qi = q.find_index with (item == 20); qi.sort; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:74:25: Unsupported: with statements - 74 | qv = q.find_first with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:76:31: Unsupported: with statements - 76 | qv = q.find_first_index with (item == 20); +%Error-UNSUPPORTED: t/t_array_method.v:70:31: Unsupported: with statements + 70 | qi = q.find_first_index with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:78:24: Unsupported: with statements - 78 | qv = q.find_last with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:80:30: Unsupported: with statements - 80 | qv = q.find_last_index with (item == 20); +%Error-UNSUPPORTED: t/t_array_method.v:72:30: Unsupported: with statements + 72 | qi = q.find_last_index with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:96:17: Unsupported: with statements - 96 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",96, (i), (32'h11)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_array_method.v:83:17: Unsupported: with statements + 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",83, (i), (32'h11)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:98:21: Unsupported: with statements - 98 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",98, (i), (32'h168)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_array_method.v:85:21: Unsupported: with statements + 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",85, (i), (32'h168)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:105:17: Unsupported: with statements - 105 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",105, (i), (32'b1001)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_array_method.v:89:17: Unsupported: with statements + 89 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",89, (i), (32'b1001)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:107:16: Unsupported: with statements - 107 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",107, (i), (32'b1111)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_array_method.v:91:16: Unsupported: with statements + 91 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",91, (i), (32'b1111)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:109:17: Unsupported: with statements - 109 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",109, (i), (32'hb)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_array_method.v:93:17: Unsupported: with statements + 93 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",93, (i), (32'hb)); $stop; end while(0);; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_array_method.v b/test_regress/t/t_array_method.v index 90e37de31..e89003046 100644 --- a/test_regress/t/t_array_method.v +++ b/test_regress/t/t_array_method.v @@ -11,8 +11,8 @@ module t (/*AUTOARG*/); initial begin int q[5]; - int qe[$]; - int qv[$]; + int qv[$]; // Value returns + int qi[$]; // Index returns int i; string v; @@ -27,69 +27,56 @@ module t (/*AUTOARG*/); v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); q.sort(x) with (x == 3); v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); - qe.sort(x) with (x == 3); - v = $sformatf("%p", qe); `checks(v, "'{}"); q.rsort; v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); q.rsort with (item == 2); v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); - qe.rsort(x) with (x == 3); - v = $sformatf("%p", qe); `checks(v, "'{}"); qv = q.unique; v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); - qv = qe.unique; - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.unique_index; qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{0, 2, 3, 4} "); + qi = q.unique_index; qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{0, 2, 3, 4} "); q.reverse; v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); - qe.reverse; - v = $sformatf("%p", qe); `checks(v, "'{}"); q.shuffle(); q.sort; v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); - qe.shuffle(); qe.sort; - v = $sformatf("%p", qe); `checks(v, "'{}"); // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); - qv = q.find_index with (item == 2); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{1, 2} "); qv = q.find_first with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_first_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{1} "); qv = q.find_last with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_last_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); qv = q.find with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_index with (item == 20); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{}"); qv = q.find_first with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_first_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); qv = q.find_last with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_last_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); + + qi = q.find_index with (item == 2); qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{1, 2} "); + qi = q.find_first_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{1} "); + qi = q.find_last_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{2} "); + + qi = q.find_index with (item == 20); qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_first_index with (item == 20); + v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_last_index with (item == 20); + v = $sformatf("%p", qi); `checks(v, "'{}"); qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{1} "); qv = q.max; v = $sformatf("%p", qv); `checks(v, "'{4} "); - qv = qe.min; - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = qe.max; - v = $sformatf("%p", qv); `checks(v, "'{}"); - // Reduction methods i = q.sum; `checkh(i, 32'hc); @@ -97,9 +84,6 @@ module t (/*AUTOARG*/); i = q.product; `checkh(i, 32'h30); i = q.product with (item + 1); `checkh(i, 32'h168); - i = qe.sum; `checkh(i, 32'h0); - i = qe.product; `checkh(i, 32'h0); - q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010}; i = q.and; `checkh(i, 32'b1000); i = q.and with (item + 1); `checkh(i, 32'b1001); @@ -108,10 +92,6 @@ module t (/*AUTOARG*/); i = q.xor; `checkh(i, 32'ha); i = q.xor with (item + 1); `checkh(i, 32'hb); - i = qe.and; `checkh(i, 32'b0); - i = qe.or; `checkh(i, 32'b0); - i = qe.xor; `checkh(i, 32'b0); - $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assoc_method.out b/test_regress/t/t_assoc_method.out index 651f8fd92..3f2aa0104 100644 --- a/test_regress/t/t_assoc_method.out +++ b/test_regress/t/t_assoc_method.out @@ -1,52 +1,52 @@ -%Error-UNSUPPORTED: t/t_assoc_method.v:38:19: Unsupported: with statements - 38 | qv = q.find with (item == 2); +%Error-UNSUPPORTED: t/t_assoc_method.v:42:19: Unsupported: with statements + 42 | qv = q.find with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:40:25: Unsupported: with statements - 40 | qv = q.find_index with (item == 2); qv.sort; +%Error-UNSUPPORTED: t/t_assoc_method.v:44:25: Unsupported: with statements + 44 | qv = q.find_first with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:42:25: Unsupported: with statements - 42 | qv = q.find_first with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:44:31: Unsupported: with statements - 44 | qv = q.find_first_index with (item == 2); - | ^~~~ %Error-UNSUPPORTED: t/t_assoc_method.v:46:24: Unsupported: with statements 46 | qv = q.find_last with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:48:30: Unsupported: with statements - 48 | qv = q.find_last_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:51:19: Unsupported: with statements - 51 | qv = q.find with (item == 20); +%Error-UNSUPPORTED: t/t_assoc_method.v:49:19: Unsupported: with statements + 49 | qv = q.find with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:53:25: Unsupported: with statements - 53 | qv = q.find_index with (item == 20); qv.sort; +%Error-UNSUPPORTED: t/t_assoc_method.v:51:25: Unsupported: with statements + 51 | qv = q.find_first with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:55:25: Unsupported: with statements - 55 | qv = q.find_first with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:57:31: Unsupported: with statements - 57 | qv = q.find_first_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:59:24: Unsupported: with statements - 59 | qv = q.find_last with (item == 20); +%Error-UNSUPPORTED: t/t_assoc_method.v:53:24: Unsupported: with statements + 53 | qv = q.find_last with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:61:30: Unsupported: with statements - 61 | qv = q.find_last_index with (item == 20); +%Error-UNSUPPORTED: t/t_assoc_method.v:56:25: Unsupported: with statements + 56 | qi = q.find_index with (item == 2); qi.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:58:31: Unsupported: with statements + 58 | qi = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:60:30: Unsupported: with statements + 60 | qi = q.find_last_index with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:77:17: Unsupported: with statements - 77 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",77, (i), (32'h11)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_assoc_method.v:63:25: Unsupported: with statements + 63 | qi = q.find_index with (item == 20); qi.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:65:31: Unsupported: with statements + 65 | qi = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:67:30: Unsupported: with statements + 67 | qi = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:83:17: Unsupported: with statements + 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",83, (i), (32'h11)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:79:21: Unsupported: with statements - 79 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",79, (i), (32'h168)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_assoc_method.v:85:21: Unsupported: with statements + 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",85, (i), (32'h168)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:86:17: Unsupported: with statements - 86 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",86, (i), (32'b1001)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_assoc_method.v:92:17: Unsupported: with statements + 92 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",92, (i), (32'b1001)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:88:16: Unsupported: with statements - 88 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'b1111)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_assoc_method.v:94:16: Unsupported: with statements + 94 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",94, (i), (32'b1111)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:90:17: Unsupported: with statements - 90 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",90, (i), (32'b0110)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_assoc_method.v:96:17: Unsupported: with statements + 96 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",96, (i), (32'b0110)); $stop; end while(0);; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 27586da10..40e05ca2f 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -11,8 +11,9 @@ module t (/*AUTOARG*/); initial begin int q[int]; - int qe[$]; - int qv[$]; + int qe[int]; // Empty + int qv[$]; // Value returns + int qi[$]; // Index returns int i; string v; @@ -26,40 +27,45 @@ module t (/*AUTOARG*/); //q.reverse; // Not legal on assoc - see t_assoc_meth_bad //q.shuffle; // Not legal on assoc - see t_assoc_meth_bad + v = $sformatf("%p", qe); `checks(v, "'{}"); qv = q.unique; v = $sformatf("%p", qv); `checks(v, "'{1, 2, 4, 3} "); qv = qe.unique; v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.unique_index; qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{10, 11, 13, 14} "); + qi = q.unique_index; qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{10, 11, 13, 14} "); + qv = qe.unique_index; + v = $sformatf("%p", qv); `checks(v, "'{}"); // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); - qv = q.find_index with (item == 2); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{11, 12} "); qv = q.find_first with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_first_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{11} "); qv = q.find_last with (item == 2); v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_last_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{12} "); qv = q.find with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_index with (item == 20); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{}"); qv = q.find_first with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_first_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); qv = q.find_last with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_last_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); + + qi = q.find_index with (item == 2); qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{11, 12} "); + qi = q.find_first_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{11} "); + qi = q.find_last_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{12} "); + + qi = q.find_index with (item == 20); qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_first_index with (item == 20); + v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_last_index with (item == 20); + v = $sformatf("%p", qi); `checks(v, "'{}"); qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{1} "); diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index 166cc48f3..5ac8d755f 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -40,7 +40,7 @@ module t (/*AUTOARG*/ cyc <= cyc + 1; begin `checkh(a.size, 0); - v = $sformatf("%p", a); `checks(v, "'{} "); + v = $sformatf("%p", a); `checks(v, "'{}"); a = new [3]; `checkh(a.size, 3); diff --git a/test_regress/t/t_queue_method.out b/test_regress/t/t_queue_method.out index 078c10478..f7067fb08 100644 --- a/test_regress/t/t_queue_method.out +++ b/test_regress/t/t_queue_method.out @@ -1,70 +1,70 @@ %Error-UNSUPPORTED: t/t_queue_method.v:28:14: Unsupported: with statements - 28 | q.sort with (item == 2); + 28 | q.sort with (10 - item); | ^~~~ %Error-UNSUPPORTED: t/t_queue_method.v:30:17: Unsupported: with statements - 30 | q.sort(x) with (x == 3); + 30 | q.sort(x) with (10 - x); | ^~~~ %Error: t/t_queue_method.v:30:14: Can't find definition of variable: 'x' - 30 | q.sort(x) with (x == 3); + 30 | q.sort(x) with (10 - x); | ^ %Error-UNSUPPORTED: t/t_queue_method.v:32:18: Unsupported: with statements - 32 | qe.sort(x) with (x == 3); + 32 | qe.sort(x) with (10 - x); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:37:15: Unsupported: with statements - 37 | q.rsort with (item == 2); +%Error-UNSUPPORTED: t/t_queue_method.v:36:15: Unsupported: with statements + 36 | q.rsort with (10 - item); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:39:19: Unsupported: with statements - 39 | qe.rsort(x) with (x == 3); +%Error-UNSUPPORTED: t/t_queue_method.v:38:19: Unsupported: with statements + 38 | qe.rsort(x) with (10 - x); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:59:19: Unsupported: with statements - 59 | qv = q.find with (item == 2); +%Error-UNSUPPORTED: t/t_queue_method.v:62:19: Unsupported: with statements + 62 | qv = q.find with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:61:25: Unsupported: with statements - 61 | qv = q.find_index with (item == 2); qv.sort; +%Error-UNSUPPORTED: t/t_queue_method.v:64:25: Unsupported: with statements + 64 | qv = q.find_first with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:63:25: Unsupported: with statements - 63 | qv = q.find_first with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:65:31: Unsupported: with statements - 65 | qv = q.find_first_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:67:24: Unsupported: with statements - 67 | qv = q.find_last with (item == 2); +%Error-UNSUPPORTED: t/t_queue_method.v:66:24: Unsupported: with statements + 66 | qv = q.find_last with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:69:30: Unsupported: with statements - 69 | qv = q.find_last_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:72:19: Unsupported: with statements - 72 | qv = q.find with (item == 20); +%Error-UNSUPPORTED: t/t_queue_method.v:69:19: Unsupported: with statements + 69 | qv = q.find with (item == 20); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:74:25: Unsupported: with statements - 74 | qv = q.find_index with (item == 20); qv.sort; +%Error-UNSUPPORTED: t/t_queue_method.v:71:25: Unsupported: with statements + 71 | qv = q.find_first with (item == 20); | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:73:24: Unsupported: with statements + 73 | qv = q.find_last with (item == 20); + | ^~~~ %Error-UNSUPPORTED: t/t_queue_method.v:76:25: Unsupported: with statements - 76 | qv = q.find_first with (item == 20); + 76 | qi = q.find_index with (item == 2); | ^~~~ %Error-UNSUPPORTED: t/t_queue_method.v:78:31: Unsupported: with statements - 78 | qv = q.find_first_index with (item == 20); + 78 | qi = q.find_first_index with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:80:24: Unsupported: with statements - 80 | qv = q.find_last with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:82:30: Unsupported: with statements - 82 | qv = q.find_last_index with (item == 20); +%Error-UNSUPPORTED: t/t_queue_method.v:80:30: Unsupported: with statements + 80 | qi = q.find_last_index with (item == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:98:17: Unsupported: with statements - 98 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",98, (i), (32'h11)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_queue_method.v:83:25: Unsupported: with statements + 83 | qi = q.find_index with (item == 20); qi.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:85:31: Unsupported: with statements + 85 | qi = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:87:30: Unsupported: with statements + 87 | qi = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:102:17: Unsupported: with statements + 102 | i = q.sum with (item + 1); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:100:21: Unsupported: with statements - 100 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",100, (i), (32'h168)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_queue_method.v:106:21: Unsupported: with statements + 106 | i = q.product with (item + 1); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:107:17: Unsupported: with statements - 107 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",107, (i), (32'b1001)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_queue_method.v:117:17: Unsupported: with statements + 117 | i = q.and with (item + 1); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:109:16: Unsupported: with statements - 109 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",109, (i), (32'b1111)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_queue_method.v:121:16: Unsupported: with statements + 121 | i = q.or with (item + 1); | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:111:17: Unsupported: with statements - 111 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",111, (i), (32'b0110)); $stop; end while(0);; +%Error-UNSUPPORTED: t/t_queue_method.v:125:17: Unsupported: with statements + 125 | i = q.xor with (item + 1); | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index e3d6d6f27..5e0e478fb 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -13,106 +13,124 @@ module t (/*AUTOARG*/); initial begin int q[$]; - int qe[$]; - int qv[$]; + int qe[$]; // Empty + int qv[$]; // Value returns + int qi[$]; // Index returns int i; string v; q = '{1, 2, 2, 4, 3}; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); - - // NOT tested: with ... selectors + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} "); + // sort/rsort with clause is the field to use for the sorting q.sort; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); - q.sort with (item == 2); - v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); - q.sort(x) with (x == 3); - v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); - qe.sort(x) with (x == 3); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + q.sort with (10 - item); + v = $sformatf("%p", q); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + q.sort(x) with (10 - x); + v = $sformatf("%p", q); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + qe.sort(x) with (10 - x); v = $sformatf("%p", qe); `checks(v, "'{}"); - q.rsort; - v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); - q.rsort with (item == 2); - v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); - qe.rsort(x) with (x == 3); - v = $sformatf("%p", qe); `checks(v, "'{}"); + v = $sformatf("%p", q); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + q.rsort with (10 - item); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + qe.rsort(x) with (10 - x); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + q = '{2, 2, 4, 1, 3}; qv = q.unique; - v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h4, 'h1, 'h3} "); qv = qe.unique; - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.unique_index; qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{0, 2, 3, 4} "); + `checkh(qv.size(), 0); + qi = q.unique_index; qv.sort; + v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h2, 'h3, 'h4} "); + qi = qe.unique_index; + `checkh(qi.size(), 0); + q.reverse; - v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); + v = $sformatf("%p", q); `checks(v, "'{'h3, 'h1, 'h4, 'h2, 'h2} "); qe.reverse; - v = $sformatf("%p", qe); `checks(v, "'{}"); + `checkh(qe.size(), 0); q.shuffle(); q.sort; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); - qe.shuffle(); qe.sort; - v = $sformatf("%p", qe); `checks(v, "'{}"); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + qe.shuffle(); + `checkh(qe.size(), 0); // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); - qv = q.find_index with (item == 2); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{1, 2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} "); qv = q.find_first with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_first_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{1} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find_last with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); - qv = q.find_last_index with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_index with (item == 20); qv.sort; - v = $sformatf("%p", qv); `checks(v, "'{}"); + `checkh(qv.size, 0); qv = q.find_first with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_first_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); + `checkh(qv.size, 0); qv = q.find_last with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); - qv = q.find_last_index with (item == 20); - v = $sformatf("%p", qv); `checks(v, "'{}"); + `checkh(qv.size, 0); + + qi = q.find_index with (item == 2); + qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); + qi = q.find_first_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h1} "); + qi = q.find_last_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + + qi = q.find_index with (item == 20); qi.sort; + `checkh(qi.size, 0); + qi = q.find_first_index with (item == 20); + `checkh(qi.size, 0); + qi = q.find_last_index with (item == 20); + `checkh(qi.size, 0); qv = q.min; - v = $sformatf("%p", qv); `checks(v, "'{1} "); + v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; - v = $sformatf("%p", qv); `checks(v, "'{4} "); - + v = $sformatf("%p", qv); `checks(v, "'{'h4} "); qv = qe.min; v = $sformatf("%p", qv); `checks(v, "'{}"); qv = qe.max; v = $sformatf("%p", qv); `checks(v, "'{}"); // Reduction methods + i = q.sum; + `checkh(i, 32'hc); + i = q.sum with (item + 1); + `checkh(i, 32'h11); + i = q.product; + `checkh(i, 32'h30); + i = q.product with (item + 1); + `checkh(i, 32'h168); - i = q.sum; `checkh(i, 32'hc); - i = q.sum with (item + 1); `checkh(i, 32'h11); - i = q.product; `checkh(i, 32'h30); - i = q.product with (item + 1); `checkh(i, 32'h168); - - i = qe.sum; `checkh(i, 32'h0); - i = qe.product; `checkh(i, 32'h0); + i = qe.sum; + `checkh(i, 32'h0); + i = qe.product; + `checkh(i, 32'h0); q = '{32'b1100, 32'b1010}; - i = q.and; `checkh(i, 32'b1000); - i = q.and with (item + 1); `checkh(i, 32'b1001); - i = q.or; `checkh(i, 32'b1110); - i = q.or with (item + 1); `checkh(i, 32'b1111); - i = q.xor; `checkh(i, 32'b0110); - i = q.xor with (item + 1); `checkh(i, 32'b0110); + i = q.and; + `checkh(i, 32'b1000); + i = q.and with (item + 1); + `checkh(i, 32'b1001); + i = q.or; + `checkh(i, 32'b1110); + i = q.or with (item + 1); + `checkh(i, 32'b1111); + i = q.xor; + `checkh(i, 32'b0110); + i = q.xor with (item + 1); + `checkh(i, 32'b0110); - i = qe.and; `checkh(i, 32'b0); - i = qe.or; `checkh(i, 32'b0); - i = qe.xor; `checkh(i, 32'b0); + i = qe.and; + `checkh(i, 32'b0); + i = qe.or; + `checkh(i, 32'b0); + i = qe.xor; + `checkh(i, 32'b0); $write("*-* All Finished *-*\n"); $finish; From 835905bdaea735bf2d4f5eb9cd8c8e998b357b1b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 24 Oct 2020 20:30:52 -0400 Subject: [PATCH 24/88] Convert cast tasks to assertions --- src/V3AstNodes.h | 4 ++++ src/V3LinkLValue.cpp | 9 +++++++++ src/V3Width.cpp | 3 ++- src/verilog.y | 5 ++++- test_regress/t/t_castdyn.out | 4 ++-- test_regress/t/t_castdyn.v | 4 +++- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 69e448bd8..fdbcc205c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5835,6 +5835,10 @@ public: }; class AstCastDynamic : public AstNodeBiop { + // Verilog $cast used as a function + // Task usage of $cast is converted during parse to assert($cast(...)) + // Parents: MATH + // Children: MATH public: AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index cdfdd11e8..453747555 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -76,6 +76,15 @@ private: iterateAndNextNull(nodep->rhsp()); } } + virtual void visit(AstCastDynamic* nodep) override { + VL_RESTORER(m_setRefLvalue); + { + m_setRefLvalue = VAccess::WRITE; + iterateAndNextNull(nodep->lhsp()); + m_setRefLvalue = false; + iterateAndNextNull(nodep->rhsp()); + } + } virtual void visit(AstFOpen* nodep) override { VL_RESTORER(m_setRefLvalue); { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7e91a0362..a71bb0089 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1599,9 +1599,10 @@ private: nodep->widthFromSub(nodep->subDTypep()); } virtual void visit(AstCastDynamic* nodep) override { + nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return nodep->v3warn(E_UNSUPPORTED, "Unsupported: $cast. Suggest try static cast."); AstNode* newp = new AstConst(nodep->fileline(), 1); - newp->dtypeSetSigned32(); // Spec says integer return + newp->dtypeFrom(nodep); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } diff --git a/src/verilog.y b/src/verilog.y index dfbe30a97..72275ccd9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3624,6 +3624,9 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, true, $3, $5, $7, nullptr); } | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, true, $3, $5, $7, $9); } // + | yD_CAST '(' expr ',' expr ')' + { $$ = new AstAssert($1, new AstCastDynamic($1, $3, $5), nullptr, nullptr, true); } + // // Any system function as a task | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } ; @@ -3632,6 +3635,7 @@ system_f_call: // IEEE: system_tf_call (as func) yaD_PLI systemDpiArgsE { $$ = new AstFuncRef($1, *$1, $2); VN_CAST($$, FuncRef)->pli(true); } // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc($1,$3)); } + | yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic($1, $3, $5); } | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } // | system_f_call_or_t { $$ = $1; } @@ -3654,7 +3658,6 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_BITS '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); } | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); } | yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); UNSUPREAL($1); } - | yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic($1, $3, $5); } | yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); } | yD_CHANGED '(' expr ')' { $$ = new AstLogNot($1, new AstStable($1, $3)); } | yD_CHANGED '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $changed and clock arguments"); } diff --git a/test_regress/t/t_castdyn.out b/test_regress/t/t_castdyn.out index 14761e02a..2b0ae4bce 100644 --- a/test_regress/t/t_castdyn.out +++ b/test_regress/t/t_castdyn.out @@ -22,8 +22,8 @@ : ... In instance t 51 | i = $cast(bbo, b); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:57:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:58:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 57 | i = $cast(bao, b); + 58 | i = $cast(bao, b); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_castdyn.v b/test_regress/t/t_castdyn.v index 2d788ca51..123268419 100644 --- a/test_regress/t/t_castdyn.v +++ b/test_regress/t/t_castdyn.v @@ -53,9 +53,11 @@ module t (/*AUTOARG*/); if (b != bb) $stop; bb = new; - b = b; + b = bb; + bao = ba; i = $cast(bao, b); if (i != 0) $stop; + if (bao != ba) $stop; // Unchanged $write("*-* All Finished *-*\n"); $finish; From 046c0a7aa1d930e7c82819d0db9891e899cfe699 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 24 Oct 2020 22:08:11 -0400 Subject: [PATCH 25/88] Fix queue assignment with different limits, negative indicies --- include/verilated_heavy.h | 31 +++++++++++++++++++++---------- test_regress/t/t_queue_slice.v | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e7a01f21c..e8d9dbde3 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -272,7 +272,15 @@ public: // m_defaultValue isn't defaulted. Caller's constructor must do it. } ~VlQueue() {} + // Standard copy constructor works. Verilog: assoca = assocb + // Also must allow conversion from a different T_MaxSize queue + template VlQueue operator=(const VlQueue& rhs) { + m_deque = rhs.privateDeque(); + if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1); + return *this; + } + static VlQueue cons(const T_Value& lhs) { VlQueue out; out.push_back(lhs); @@ -302,13 +310,15 @@ public: // METHODS T_Value& atDefault() { return m_defaultValue; } + const Deque& privateDeque() const { return m_deque; } // Size. Verilog: function int size(), or int num() int size() const { return m_deque.size(); } // Clear array. Verilog: function void delete([input index]) void clear() { m_deque.clear(); } - void erase(size_t index) { - if (VL_LIKELY(index < m_deque.size())) m_deque.erase(m_deque.begin() + index); + void erase(vlsint32_t index) { + if (VL_LIKELY(index >= 0 && index < m_deque.size())) + m_deque.erase(m_deque.begin() + index); } // Dynamic array new[] becomes a renew() @@ -353,10 +363,10 @@ public: // Setting. Verilog: assoc[index] = v // Can't just overload operator[] or provide a "at" reference to set, // because we need to be able to insert only when the value is set - T_Value& at(size_t index) { + T_Value& at(vlsint32_t index) { static T_Value s_throwAway; // Needs to work for dynamic arrays, so does not use T_MaxSize - if (VL_UNLIKELY(index >= m_deque.size())) { + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { s_throwAway = atDefault(); return s_throwAway; } else { @@ -364,27 +374,28 @@ public: } } // Accessing. Verilog: v = assoc[index] - const T_Value& at(size_t index) const { + const T_Value& at(vlsint32_t index) const { static T_Value s_throwAway; // Needs to work for dynamic arrays, so does not use T_MaxSize - if (VL_UNLIKELY(index >= m_deque.size())) { + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { return atDefault(); } else { return m_deque[index]; } } // function void q.insert(index, value); - void insert(size_t index, const T_Value& value) { - if (VL_UNLIKELY(index >= m_deque.size())) return; + void insert(vlsint32_t index, const T_Value& value) { + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return; m_deque.insert(m_deque.begin() + index, value); } // Return slice q[lsb:msb] - VlQueue slice(size_t lsb, size_t msb) const { + VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const { VlQueue out; + if (VL_UNLIKELY(lsb < 0)) lsb = 0; if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1; if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1; - for (size_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); + for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); return out; } diff --git a/test_regress/t/t_queue_slice.v b/test_regress/t/t_queue_slice.v index b1cd39408..3ee6e2844 100644 --- a/test_regress/t/t_queue_slice.v +++ b/test_regress/t/t_queue_slice.v @@ -13,6 +13,8 @@ module t (/*AUTOARG*/); string q[$]; string v; int i; + int qi[$:5]; + int ri[$]; q.push_front("non-empty"); i = q.size(); `checkh(i, 1); @@ -43,6 +45,9 @@ module t (/*AUTOARG*/); // Slicing q = '{"q", "b", "c", "d", "e", "f"}; + q = q[-1:0]; + v = $sformatf("%p", q); `checks(v, "'{\"q\"} "); + q = '{"q", "b", "c", "d", "e", "f"}; q = q[2:3]; v = $sformatf("%p", q); `checks(v, "'{\"c\", \"d\"} "); q = '{"q", "b", "c", "d", "e", "f"}; @@ -80,7 +85,34 @@ module t (/*AUTOARG*/); v = q.pop_front(); `checks(v, "CC"); end + begin + qi.push_back(0); + qi.push_back(1); + qi.push_back(2); + qi.push_back(3); + qi.push_back(4); + qi.push_back(5); + + // Assignment to unsized queue from sized queue + ri = qi[ 2 : 4 ]; + `checkh(ri.size, 3); + ri = qi[ 4 : 2 ]; + `checkh(ri.size, 0); + ri = qi[ 2 : 2 ]; + `checkh(ri.size, 1); + ri = qi[ -2 : 2 ]; // 2 - 0 + 1 = 3 + `checkh(ri.size, 3); + ri = qi[ 2 : 10 ]; // 5 - 2 + 1 = 4 + `checkh(ri.size, 4); + + // Assignment from unsized to sized + ri = '{1,2,3,4,5,6,7,8,9}; + qi = ri; + `checkh(qi.size, 5); + end + $write("*-* All Finished *-*\n"); $finish; end + endmodule From 95d127226996c23fce58e8d30df8cafe0ab45a31 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 25 Oct 2020 21:05:22 -0400 Subject: [PATCH 26/88] Support associative array pattern assignments and defaults. --- Changes | 2 + include/verilated_heavy.h | 10 ++++ src/V3AstNodes.h | 43 ++++++++++++++++++ src/V3EmitC.cpp | 18 ++++++++ src/V3Width.cpp | 58 +++++++++++++++++++++--- test_regress/t/t_assoc.v | 5 +- test_regress/t/t_assoc_pattern_unsup.out | 5 -- test_regress/t/t_assoc_pattern_unsup.pl | 19 -------- test_regress/t/t_assoc_pattern_unsup.v | 28 ------------ 9 files changed, 127 insertions(+), 61 deletions(-) delete mode 100644 test_regress/t/t_assoc_pattern_unsup.out delete mode 100755 test_regress/t/t_assoc_pattern_unsup.pl delete mode 100644 test_regress/t/t_assoc_pattern_unsup.v diff --git a/Changes b/Changes index c2fff4499..3dc21bc38 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support queue slicing (#2326). +**** Support associative array pattern assignments and defaults. + **** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e8d9dbde3..2d110567a 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -196,6 +196,16 @@ public: return it->second; } } + // Setting as a chained operation + VlAssocArray& set(const T_Key& index, const T_Value& value) { + at(index) = value; + return *this; + } + VlAssocArray& setDefault(const T_Value& value) { + atDefault() = value; + return *this; + } + // For save/restore const_iterator begin() const { return m_map.begin(); } const_iterator end() const { return m_map.end(); } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index fdbcc205c..e2e5d48dc 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4599,6 +4599,49 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; +class AstConsAssoc : public AstNodeMath { + // Construct an assoc array and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsAssoc(FileLine* fl, AstNode* defaultp) + : ASTGEN_SUPER(fl) { + setNOp1p(defaultp); + } + ASTNODE_NODE_FUNCS(ConsAssoc) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* defaultp() const { return op1p(); } + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; +class AstSetAssoc : public AstNodeMath { + // Set an assoc array element and return object, '{} + // Parents: math + // Children: expression (elements or other queues) +public: + AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) + : ASTGEN_SUPER(fl) { + setOp1p(lhsp); + setNOp2p(keyp); + setOp3p(valuep); + } + ASTNODE_NODE_FUNCS(SetAssoc) + virtual string emitVerilog() override { return "'{}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } + AstNode* keyp() const { return op2p(); } + AstNode* valuep() const { return op3p(); } + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; + class AstConsQueue : public AstNodeMath { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // Parents: math diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index e84182200..b723ec475 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1575,6 +1575,24 @@ class EmitCImp : EmitCStmts { } } + virtual void visit(AstConsAssoc* nodep) override { + putbs(nodep->dtypep()->cType("", false, false)); + puts("()"); + if (nodep->defaultp()) { + putbs(".setDefault("); + iterateAndNextNull(nodep->defaultp()); + puts(")"); + } + } + virtual void visit(AstSetAssoc* nodep) override { + iterateAndNextNull(nodep->lhsp()); + putbs(".set("); + iterateAndNextNull(nodep->keyp()); + puts(", "); + putbs(""); + iterateAndNextNull(nodep->valuep()); + puts(")"); + } virtual void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a71bb0089..469fc3d03 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1960,7 +1960,32 @@ private: } nodep->dtypeFrom(nodep->itemp()); } - virtual void visit(AstConsQueue* nodep) override { // + virtual void visit(AstConsAssoc* nodep) override { + // Type computed when constructed here + auto* vdtypep = VN_CAST(m_vup->dtypep(), AssocArrayDType); + UASSERT_OBJ(vdtypep, nodep, "ConsAssoc requires assoc upper parent data type"); + if (m_vup->prelim()) { + nodep->dtypeFrom(vdtypep); + if (nodep->defaultp()) { + iterateCheck(nodep, "default", nodep->defaultp(), CONTEXT, FINAL, vdtypep->subDTypep(), + EXTEND_EXP); + } + } + } + virtual void visit(AstSetAssoc* nodep) override { + // Type computed when constructed here + auto* vdtypep = VN_CAST(m_vup->dtypep(), AssocArrayDType); + UASSERT_OBJ(vdtypep, nodep, "SetsAssoc requires assoc upper parent data type"); + if (m_vup->prelim()) { + nodep->dtypeFrom(vdtypep); + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, BOTH).p()); + iterateCheck(nodep, "key", nodep->keyp(), CONTEXT, FINAL, vdtypep->keyDTypep(), + EXTEND_EXP); + iterateCheck(nodep, "value", nodep->valuep(), CONTEXT, FINAL, vdtypep->subDTypep(), + EXTEND_EXP); + } + } + virtual void visit(AstConsQueue* nodep) override { // Type computed when constructed here AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType); UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type"); @@ -2937,6 +2962,8 @@ private: VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep); + } else if (auto* vdtypep = VN_CAST(dtypep, AssocArrayDType)) { + VL_DO_DANGLING(patternAssoc(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, QueueDType)) { VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep); } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { @@ -3044,9 +3071,8 @@ private: } VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } - void patternArray(AstPattern* nodep, AstNodeArrayDType* vdtypep, AstPatMember* defaultp) { - AstNodeArrayDType* arrayp = VN_CAST(vdtypep, NodeArrayDType); - VNumRange range = arrayp->declRange(); + void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) { + VNumRange range = arrayDtp->declRange(); PatVecMap patmap = patVectorMap(nodep, range); UINFO(9, "ent " << range.hi() << " to " << range.lo() << endl); AstNode* newp = nullptr; @@ -3068,11 +3094,11 @@ private: if (patp) { // Don't want the RHS an array - patp->dtypep(arrayp->subDTypep()); + patp->dtypep(arrayDtp->subDTypep()); AstNode* valuep = patternMemberValueIterate(patp); - if (VN_IS(arrayp, UnpackArrayDType)) { + if (VN_IS(arrayDtp, UnpackArrayDType)) { if (!newp) { - AstInitArray* newap = new AstInitArray(nodep->fileline(), arrayp, nullptr); + AstInitArray* newap = new AstInitArray(nodep->fileline(), arrayDtp, nullptr); newp = newap; } VN_CAST(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep); @@ -3099,6 +3125,24 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + void patternAssoc(AstPattern* nodep, AstAssocArrayDType* arrayDtp, AstPatMember* defaultp) { + AstNode* defaultValuep = nullptr; + if (defaultp) defaultValuep = defaultp->lhssp()->unlinkFrBack(); + AstNode* newp = new AstConsAssoc(nodep->fileline(), defaultValuep); + newp->dtypeFrom(arrayDtp); + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { + patp->dtypep(arrayDtp->subDTypep()); + AstNode* valuep = patternMemberValueIterate(patp); + AstNode* keyp = patp->keyp(); + auto* newap = new AstSetAssoc(nodep->fileline(), newp, keyp->unlinkFrBack(), valuep); + newap->dtypeFrom(arrayDtp); + newp = newap; + } + nodep->replaceWith(newp); + // if (debug() >= 9) newp->dumpTree("-apat-out: "); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present + } void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) { AstNode* newp = new AstConsQueue(nodep->fileline()); newp->dtypeFrom(arrayp); diff --git a/test_regress/t/t_assoc.v b/test_regress/t/t_assoc.v index 8740c3679..6c474516a 100644 --- a/test_regress/t/t_assoc.v +++ b/test_regress/t/t_assoc.v @@ -82,13 +82,14 @@ module t (/*AUTOARG*/ i = a.last(k); `checkh(i, 0); // Patterns & default -`ifndef VERILATOR // Unsupported: Pattern assignment a = '{ "f": "fooed", "b": "bared", default: "defaulted" }; i = a.size(); `checkh(i, 2); // Default doesn't count v = a["f"]; `checks(v, "fooed"); v = a["b"]; `checks(v, "bared"); v = a["NEXISTS"]; `checks(v, "defaulted"); -`endif + + a = '{}; + i = a.size(); `checkh(i, 0); end begin diff --git a/test_regress/t/t_assoc_pattern_unsup.out b/test_regress/t/t_assoc_pattern_unsup.out deleted file mode 100644 index 05f437fa5..000000000 --- a/test_regress/t/t_assoc_pattern_unsup.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_assoc_pattern_unsup.v:19:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]' - : ... In instance t - 19 | a = '{ "f": "fooed", "b": "bared", default: "defaulted" }; - | ^~ -%Error: Exiting due to diff --git a/test_regress/t/t_assoc_pattern_unsup.pl b/test_regress/t/t_assoc_pattern_unsup.pl deleted file mode 100755 index 63947fd00..000000000 --- a/test_regress/t/t_assoc_pattern_unsup.pl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2019 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( - fails => 1, - expect_filename => $Self->{golden_filename}, - ); - -ok(1); -1; diff --git a/test_regress/t/t_assoc_pattern_unsup.v b/test_regress/t/t_assoc_pattern_unsup.v deleted file mode 100644 index e2f896a0f..000000000 --- a/test_regress/t/t_assoc_pattern_unsup.v +++ /dev/null @@ -1,28 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); - -module t (/*AUTOARG*/); - - initial begin - int i; - string a [string]; - string k; - string v; - - a = '{ "f": "fooed", "b": "bared", default: "defaulted" }; - i = a.size(); `checkh(i, 2); // Default doesn't count - v = a["f"]; `checks(v, "fooed"); - v = a["b"]; `checks(v, "bared"); - v = a["NEXISTS"]; `checks(v, "defaulted"); - - $write("*-* All Finished *-*\n"); - $finish; - end -endmodule From 34b8ed4cf092517ce42d4998e42aa3ab366bc257 Mon Sep 17 00:00:00 2001 From: Marlon James Date: Mon, 26 Oct 2020 18:55:27 -0700 Subject: [PATCH 27/88] Return bool from callValueCbs() (#2589) (#2605) * Return bool from callValueCbs() Returns true if any registered callback was called, else false. * Add test for callCbs() and callValueCbs() --- docs/CONTRIBUTORS | 1 + include/verilated_vpi.cpp | 7 +- include/verilated_vpi.h | 2 +- test_regress/t/t_vpi_cbs_called.cpp | 301 ++++++++++++++++++++++++++++ test_regress/t/t_vpi_cbs_called.pl | 24 +++ test_regress/t/t_vpi_cbs_called.v | 24 +++ 6 files changed, 356 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_vpi_cbs_called.cpp create mode 100755 test_regress/t/t_vpi_cbs_called.pl create mode 100644 test_regress/t/t_vpi_cbs_called.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 2442f3b2a..abf1950b2 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -41,6 +41,7 @@ Maarten De Braekeleer Maciej Sobkowski Marco Widmer Markus Krause +Marlon James Marshal Qiao Matthew Ballance Michael Killough diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index db0f73bf5..46d6d8707 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -489,9 +489,10 @@ public: } return called; } - static void callValueCbs() VL_MT_UNSAFE_ONE { + static bool callValueCbs() VL_MT_UNSAFE_ONE { assertOneCheck(); VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange]; + bool called = false; typedef std::set VpioVarSet; VpioVarSet update; // set of objects to update after callbacks for (auto it = cbObjList.begin(); it != cbObjList.end();) { @@ -512,10 +513,12 @@ public: update.insert(varop); vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value); (vop->cb_rtnp())(vop->cb_datap()); + called = true; } } } for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); } + return called; } static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info @@ -599,7 +602,7 @@ VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr; void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); } -void VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callValueCbs(); } +bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); } bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callCbs(reason); diff --git a/include/verilated_vpi.h b/include/verilated_vpi.h index dea1bb9e0..4ecfc55ca 100644 --- a/include/verilated_vpi.h +++ b/include/verilated_vpi.h @@ -40,7 +40,7 @@ public: static void callTimedCbs() VL_MT_UNSAFE_ONE; /// Call value based callbacks /// Users should call this from their main loops - static void callValueCbs() VL_MT_UNSAFE_ONE; + static bool callValueCbs() VL_MT_UNSAFE_ONE; /// Call callbacks of arbitrary types /// Users can call this from their application code static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE; diff --git a/test_regress/t/t_vpi_cbs_called.cpp b/test_regress/t/t_vpi_cbs_called.cpp new file mode 100644 index 000000000..c63b95b7a --- /dev/null +++ b/test_regress/t/t_vpi_cbs_called.cpp @@ -0,0 +1,301 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Wilson Snyder and Marlon James. 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 +// +//************************************************************************* + +#include "Vt_vpi_cbs_called.h" +#include "verilated.h" +#include "verilated_vpi.h" + +#include +#include +#include +#include +#include + +#include "TestSimulator.h" +#include "TestVpi.h" + +#include "vpi_user.h" + +const std::vector cbs_to_test{cbReadWriteSynch, cbReadOnlySynch, cbNextSimTime, + cbStartOfSimulation, cbEndOfSimulation, cbValueChange}; + +enum CallbackState { PRE_REGISTER, ACTIVE, ACTIVE_AGAIN, REM_REREG_ACTIVE, POST_REMOVE }; +const std::vector cb_states{PRE_REGISTER, ACTIVE, ACTIVE_AGAIN, REM_REREG_ACTIVE, + POST_REMOVE}; + +#define CB_COUNT cbAtEndOfSimTime + 1 +vpiHandle vh_registered_cbs[CB_COUNT] = {0}; + +unsigned int callback_counts[CB_COUNT] = {0}; +unsigned int callback_expected_counts[CB_COUNT] = {0}; + +bool callbacks_called[CB_COUNT] = {false}; +bool callbacks_expected_called[CB_COUNT] = {false}; + +std::vector::const_iterator cb_iter; +std::vector::const_iterator state_iter; + +vpiHandle vh_test_cb = 0; +unsigned int main_time = 0; + +#ifdef TEST_VERBOSE +bool verbose = true; +#else +bool verbose = false; +#endif + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", __FILE__, __LINE__); \ + return __LINE__; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + return __LINE__; \ + } + +#define STRINGIFY_CB_CASE(_cb) \ + case _cb: return #_cb + +static const char* cb_reason_to_string(int cb_name) { + switch (cb_name) { + STRINGIFY_CB_CASE(cbReadWriteSynch); + STRINGIFY_CB_CASE(cbReadOnlySynch); + STRINGIFY_CB_CASE(cbNextSimTime); + STRINGIFY_CB_CASE(cbStartOfSimulation); + STRINGIFY_CB_CASE(cbEndOfSimulation); + STRINGIFY_CB_CASE(cbValueChange); + default: return "Unsupported callback"; + } +} + +#undef STRINGIFY_CB_CASE + +static int the_callback(p_cb_data cb_data) { + callback_counts[cb_data->reason] = callback_counts[cb_data->reason] + 1; + return 0; +} + +static int register_cb(const int next_state) { + int cb = *cb_iter; + t_cb_data cb_data_testcase; + bzero(&cb_data_testcase, sizeof(cb_data_testcase)); + cb_data_testcase.cb_rtn = the_callback; + cb_data_testcase.reason = cb; + + if (cb == cbValueChange) { + vpiHandle vh1 = VPI_HANDLE("count"); + CHECK_RESULT_NZ(vh1); + + s_vpi_value v; + v.format = vpiSuppressVal; + + cb_data_testcase.obj = vh1; + cb_data_testcase.value = &v; + } + + // State of callback next time through loop + if (verbose) { vpi_printf(const_cast(" Updating callback for next loop:\n")); } + switch (next_state) { + case ACTIVE: { + if (verbose) { + vpi_printf(const_cast(" - Registering callback %s\n"), + cb_reason_to_string(cb)); + } + vh_registered_cbs[cb] = vpi_register_cb(&cb_data_testcase); + break; + } + case REM_REREG_ACTIVE: { + if (verbose) { + vpi_printf(const_cast(" - Removing callback %s and re-registering\n"), + cb_reason_to_string(cb)); + } + int ret = vpi_remove_cb(vh_registered_cbs[cb]); + CHECK_RESULT(ret, 1); + vh_registered_cbs[cb] = vpi_register_cb(&cb_data_testcase); + break; + } + case POST_REMOVE: { + if (verbose) { + vpi_printf(const_cast(" - Removing callback %s\n"), + cb_reason_to_string(cb)); + } + int ret = vpi_remove_cb(vh_registered_cbs[cb]); + CHECK_RESULT(ret, 1); + break; + } + default: + if (verbose) { vpi_printf(const_cast(" - No change\n")); } + break; + } + + return 0; +} + +void reset_expected() { + for (int idx = 0; idx < CB_COUNT; idx++) { callbacks_expected_called[idx] = false; } +} + +void cb_will_be_called(const int cb) { + callback_expected_counts[cb] = callback_expected_counts[cb] + 1; + callbacks_expected_called[cb] = true; +} + +static int test_callbacks(p_cb_data cb_data) { + t_cb_data cb_data_testcase; + bzero(&cb_data_testcase, sizeof(cb_data_testcase)); + + if (verbose) { vpi_printf(const_cast(" Checking callback results\n")); } + + // Check results from previous loop + int cb = *cb_iter; + + auto count = callback_counts[cb]; + auto exp_count = callback_expected_counts[cb]; + CHECK_RESULT(count, exp_count); + + bool called = callbacks_called[cb]; + bool exp_called = callbacks_expected_called[cb]; + CHECK_RESULT(called, exp_called); + + // Update expected values based on state of callback in next time through main loop + reset_expected(); + + const int current_state = *state_iter; + const int next_state = (current_state + 1) % cb_states.size(); + + switch (next_state) { + case PRE_REGISTER: + case ACTIVE: + case ACTIVE_AGAIN: + case REM_REREG_ACTIVE: { + cb_will_be_called(*cb_iter); + break; + } + default: break; + } + + int ret = register_cb(next_state); + + // Update iterators for next loop + ++state_iter; + if (state_iter == cb_states.cend()) { + ++cb_iter; + state_iter = cb_states.cbegin(); + } + + // Re-register this cb for next time step + if (cb_iter != cbs_to_test.cend()) { + if (verbose) { + vpi_printf(const_cast(" Re-registering test_callbacks for next loop\n")); + } + t_cb_data cb_data_n; + bzero(&cb_data_n, sizeof(cb_data_n)); + s_vpi_time t1; + + cb_data_n.reason = cbAfterDelay; + t1.type = vpiSimTime; + t1.high = 0; + t1.low = 1; + cb_data_n.time = &t1; + cb_data_n.cb_rtn = test_callbacks; + vh_test_cb = vpi_register_cb(&cb_data_n); + CHECK_RESULT_NZ(vh_test_cb); + } + + return ret; +} + +void register_test_callback() { + t_cb_data cb_data; + bzero(&cb_data, sizeof(cb_data)); + s_vpi_time t1; + + if (verbose) { vpi_printf(const_cast(" Registering test_cbs Timed callback\n")); } + + cb_data.reason = cbAfterDelay; + t1.type = vpiSimTime; + t1.high = 0; + t1.low = 1; + cb_data.time = &t1; + cb_data.cb_rtn = test_callbacks; + vpi_register_cb(&cb_data); + + cb_iter = cbs_to_test.cbegin(); + state_iter = cb_states.cbegin(); +} + +double sc_time_stamp() { return main_time; } + +int main(int argc, char** argv, char** env) { + double sim_time = 100; + bool cbs_called; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + + VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + + if (verbose) { VL_PRINTF("-- { Sim Time %d } --\n", main_time); } + + register_test_callback(); + + topp->eval(); + topp->clk = 0; + main_time += 1; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + if (verbose) { + VL_PRINTF("-- { Sim Time %d , Callback %s (%d) , Testcase State %d } --\n", main_time, + cb_reason_to_string(*cb_iter), *cb_iter, *state_iter); + } + + topp->eval(); + + for (const auto& i : cbs_to_test) { + if (verbose) { + VL_PRINTF(" Calling %s (%d) callbacks\t", cb_reason_to_string(i), i); + } + if (i == cbValueChange) { + cbs_called = VerilatedVpi::callValueCbs(); + } else { + cbs_called = VerilatedVpi::callCbs(i); + } + if (verbose) { VL_PRINTF(" - any callbacks called? %s\n", cbs_called ? "YES" : "NO"); } + callbacks_called[i] = cbs_called; + } + + VerilatedVpi::callTimedCbs(); + + main_time = VerilatedVpi::cbNextDeadline(); + if (main_time == -1) { + if (verbose) { VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time); } + VL_PRINTF("*-* All Finished *-*\n"); + Verilated::gotFinish(true); + } + + // Count updates on rising edge, so cycle through falling edge as well + topp->clk = !topp->clk; + topp->eval(); + topp->clk = !topp->clk; + } + + if (!Verilated::gotFinish()) { + vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + + VL_DO_DANGLING(delete topp, topp); + exit(0L); +} diff --git a/test_regress/t/t_vpi_cbs_called.pl b/test_regress/t/t_vpi_cbs_called.pl new file mode 100755 index 000000000..0d8f23641 --- /dev/null +++ b/test_regress/t/t_vpi_cbs_called.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder and Marlon James. 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); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe --vpi $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_cbs_called.v b/test_regress/t/t_vpi_cbs_called.v new file mode 100644 index 000000000..3568bf9d7 --- /dev/null +++ b/test_regress/t/t_vpi_cbs_called.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder and Marlon James. +// SPDX-License-Identifier: CC0-1.0 + + +module t (/*AUTOARG*/ + // Inputs + input clk + ); + + reg [31:0] count /*verilator public_flat_rd */; + + // Test loop + initial begin + count = 0; + end + + always @(posedge clk) begin + count <= count + 2; + end + +endmodule : t From 77ac9bfcc6e12cbf5a3401072a1017fee3d86476 Mon Sep 17 00:00:00 2001 From: Jean Berniolles Date: Tue, 27 Oct 2020 18:33:25 +0100 Subject: [PATCH 28/88] Fix WIFEXITED missing from MinGW/MSYS2 (#2609) * WIFEXITED missing from MinGW/MSYS2, added defines * Found source of the WIFEXITED macro in the binutils-gdb repo. Now with less pointer manipulation. --- docs/CONTRIBUTORS | 1 + src/V3Os.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index abf1950b2..15b7a2e5a 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -27,6 +27,7 @@ James Hutchinson Jamey Hicks James Pallister Jan Van Winkel +Jean Berniolles Jeremy Bennett John Coiner John Demme diff --git a/src/V3Os.cpp b/src/V3Os.cpp index e7e9a8d5b..299d5c104 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -49,6 +49,14 @@ # include // mkdir # include // GetProcessMemoryInfo # include +// These macros taken from gdbsupport/gdb_wait.h in binutils-gdb +# ifndef WIFEXITED +# ifdef __MINGW32__ +# define WIFEXITED(w) (((w) & 0xC0000000) == 0) +# else +# define WIFEXITED(w) (((w) & 0377) == 0) +# endif +# endif #else # include # include // Needed on FreeBSD for WIFEXITED From 05ff96bea3f477a42a060eddea1b5e8a7655b631 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Wed, 28 Oct 2020 08:37:12 +0900 Subject: [PATCH 29/88] Fix SEGV when $fgets, $sscanf, or $fscanf is used with string (#2604) * Add a test to use string for $fgets * Use dedicated function for $fgets to std::string * share the implementation of $fgets * Pass -1 for bitwidth of std::string to distinguish from POD * add checks for scanf with string * apply clang-format --- include/verilated.cpp | 73 +++++++++++++++-------- include/verilated_heavy.h | 2 + src/V3AstNodes.h | 5 +- src/V3EmitC.cpp | 7 ++- test_regress/t/t_sys_file_basic.v | 17 ++++++ test_regress/t/t_sys_file_basic_input.dat | 2 + 6 files changed, 79 insertions(+), 27 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 00600f7ca..6d9d7b6e4 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1079,7 +1079,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf WData qowp[VL_WQ_WORDS_E]; VL_SET_WQ(qowp, 0ULL); WDataOutP owp = qowp; - if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP); + if (obits == -1) { // string + owp = nullptr; + if (VL_UNCOVERABLE(fmt != 's')) { + VL_FATAL_MT( + __FILE__, __LINE__, "", + "Internal: format other than %s is passed to string"); // LCOV_EXCL_LINE + } + } else if (obits > VL_QUADSIZE) { + owp = va_arg(ap, WDataOutP); + } + for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; switch (fmt) { case 'c': { @@ -1093,11 +1103,13 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr); if (!tmp[0]) goto done; - int lpos = (static_cast(strlen(tmp))) - 1; - int lsb = 0; - for (int i = 0; i < obits && lpos >= 0; --lpos) { - _vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]); - lsb += 8; + if (owp) { + int lpos = (static_cast(strlen(tmp))) - 1; + int lsb = 0; + for (int i = 0; i < obits && lpos >= 0; --lpos) { + _vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]); + lsb += 8; + } } break; } @@ -1194,6 +1206,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf if (!inIgnore) ++got; // Reload data if non-wide (if wide, we put it in the right place directly) if (obits == 0) { // Due to inIgnore + } else if (obits == -1) { // string + std::string* p = va_arg(ap, std::string*); + *p = tmp; } else if (obits <= VL_BYTESIZE) { CData* p = va_arg(ap, CData*); *p = owp[0]; @@ -1252,36 +1267,44 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp) for (; i < bytes; ++i) { *op++ = 0; } } -IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE { +static IData getLine(std::string& str, IData fpi, size_t maxLen) VL_MT_SAFE { + str.clear(); + // While threadsafe, each thread can only access different file handles FILE* fp = VL_CVT_I_FP(fpi); if (VL_UNLIKELY(!fp)) return 0; - // The string needs to be padded with 0's in unused spaces in front of - // any read data. This means we can't know in what location the first - // character will finally live, so we need to copy. Yuk. - IData bytes = VL_BYTES_I(obits); - char buffer[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1]; + // We don't use fgets, as we must read \0s. + while (str.size() < maxLen) { + const int c = getc(fp); // getc() is threadsafe + if (c == EOF) break; + str.push_back(c); + if (c == '\n') break; + } + return str.size(); +} + +IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE { + std::string str; + const IData bytes = VL_BYTES_I(obits); + IData got = getLine(str, fpi, bytes); + + if (VL_UNLIKELY(str.empty())) return 0; + // V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe - if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS * VL_EDATASIZE)) { + if (VL_UNCOVERABLE(bytes < str.size())) { VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE } - // We don't use fgets, as we must read \0s. - IData got = 0; - char* cp = buffer; - while (got < bytes) { - int c = getc(fp); // getc() is threadsafe - if (c == EOF) break; - *cp++ = c; - got++; - if (c == '\n') break; - } - - _VL_STRING_TO_VINT(obits, destp, got, buffer); + _VL_STRING_TO_VINT(obits, destp, got, str.data()); return got; } +// declared in verilated_heavy.h +IData VL_FGETS_NI(std::string& str, IData fpi) VL_MT_SAFE { + return getLine(str, fpi, std::numeric_limits::max()); +} + IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE { // We ignore lhs/fpi - IEEE says "most recent error" so probably good enough IData ret = errno; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 2d110567a..3d4795de0 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -546,6 +546,8 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE; +extern IData VL_FGETS_NI(std::string& destp, IData fpi); + //====================================================================== // Dumping diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e2e5d48dc..3630f88ed 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -7959,7 +7959,10 @@ public: V3ERROR_NA; } virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; } - virtual string emitC() override { return "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; } + virtual string emitC() override { + return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)" + : "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; + } virtual bool cleanOut() const override { return false; } virtual bool cleanLhs() const override { return true; } virtual bool cleanRhs() const override { return true; } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index b723ec475..c07416528 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2199,7 +2199,12 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const } emitDispState.pushFormat(pfmt); if (!ignore) { - emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin())); + if (argp->dtypep()->basicp()->keyword() == AstBasicDTypeKwd::STRING) { + // string in SystemVerilog is std::string in C++ which is not POD + emitDispState.pushArg(' ', nullptr, "-1"); + } else { + emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin())); + } emitDispState.pushArg(fmtLetter, argp, ""); } else { emitDispState.pushArg(fmtLetter, nullptr, ""); diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index e264f676a..d38c8580a 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -134,6 +134,12 @@ module t; if (chars != 10) $stop; if (letterw != "\0\0\0\0\0\0widestuff\n") $stop; + s = ""; + chars = $fgets(s, file); + if (`verbose) $write("c=%0d w=%s", chars, s); // Output includes newline + if (chars != 7) $stop; + if (s != "string\n") $stop; + // $sscanf if ($sscanf("x","")!=0) $stop; if ($sscanf("z","z")!=0) $stop; @@ -173,6 +179,12 @@ module t; `checkr(r, 0.1); if (letterq != 64'hfffffffffffc65a5) $stop; + chars = $sscanf("scan from string", + "scan %s string", s); + if (`verbose) $write("c=%0d s=%s\n", chars, s); + if (chars != 1) $stop; + if (s != "from") $stop; + // Cover quad and %e/%f chars = $sscanf("r=0.2", "r=%e", r); @@ -245,6 +257,11 @@ module t; if (chars != 1) $stop; if (letterl != "\n") $stop; + chars = $fscanf(file, "%c%s not_included\n", letterl, s); + if (`verbose) $write("c=%0d l=%s\n", chars, s); + if (chars != 2) $stop; + if (s != "BCD") $stop; + // msg1229 v_a = $fgetc(file); v_b = $fgetc(file); diff --git a/test_regress/t/t_sys_file_basic_input.dat b/test_regress/t/t_sys_file_basic_input.dat index 0e640b4ed..53d20630c 100644 --- a/test_regress/t/t_sys_file_basic_input.dat +++ b/test_regress/t/t_sys_file_basic_input.dat @@ -1,10 +1,12 @@ hi lquad widestuff +string *xa=1f xb=237904689_02348923 *ba=10 bb=11010010101001010101 note_the_two *oa=23 ob=12563 *d=-236123 *u=-236124 *fredfishblah +aBCD not_included 12346789 From d44426b3f33eb4a21ade52bb5104f6158a73b762 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 27 Oct 2020 20:03:17 -0400 Subject: [PATCH 30/88] clang-format. No functional change. --- src/V3Width.cpp | 7 +- test_regress/t/t_clk_inp_init.cpp | 4 +- test_regress/t/t_dpi_arg_inout_type.cpp | 4 +- test_regress/t/t_dpi_arg_input_type.cpp | 4 +- test_regress/t/t_dpi_arg_output_type.cpp | 4 +- test_regress/t/t_dpi_context_c.cpp | 11 +- test_regress/t/t_dpi_display_c.cpp | 2 +- test_regress/t/t_dpi_export_c.cpp | 45 +++--- test_regress/t/t_dpi_export_context_bad.cpp | 2 +- test_regress/t/t_dpi_imp_gen_c.cpp | 2 +- test_regress/t/t_dpi_import_c.cpp | 158 ++++++++++---------- test_regress/t/t_dpi_lib_c.cpp | 8 +- test_regress/t/t_dpi_open_c.cpp | 59 ++++---- test_regress/t/t_dpi_openfirst_c.cpp | 8 +- test_regress/t/t_dpi_shortcircuit_c.cpp | 14 +- test_regress/t/t_dpi_string_c.cpp | 5 +- test_regress/t/t_dpi_sys_c.cpp | 5 +- test_regress/t/t_dpi_threads_c.cpp | 7 +- test_regress/t/t_dpi_vams.cpp | 6 +- test_regress/t/t_embed1_c.cpp | 18 +-- test_regress/t/t_enum_public.cpp | 2 +- test_regress/t/t_hier_block.cpp | 5 +- test_regress/t/t_leak.cpp | 7 +- test_regress/t/t_math_imm2.cpp | 15 +- test_regress/t/t_mem_multi_io2.cpp | 8 +- test_regress/t/t_mem_slot.cpp | 3 +- test_regress/t/t_order_multidriven.cpp | 3 +- test_regress/t/t_param_public.cpp | 2 +- test_regress/t/t_sc_names.cpp | 6 +- test_regress/t/t_tri_inz.cpp | 6 +- test_regress/t/t_vpi_finish_c.cpp | 6 +- test_regress/t/t_vpi_get.cpp | 3 +- test_regress/t/t_vpi_memory.cpp | 3 +- test_regress/t/t_vpi_module.cpp | 3 +- test_regress/t/t_vpi_param.cpp | 54 ++++--- test_regress/t/t_vpi_stop_bad_c.cpp | 6 +- test_regress/t/t_vpi_time_cb.cpp | 2 +- test_regress/t/t_vpi_unimpl.cpp | 4 +- test_regress/t/t_vpi_var.cpp | 3 +- 39 files changed, 256 insertions(+), 258 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 469fc3d03..acc745b75 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1967,8 +1967,8 @@ private: if (m_vup->prelim()) { nodep->dtypeFrom(vdtypep); if (nodep->defaultp()) { - iterateCheck(nodep, "default", nodep->defaultp(), CONTEXT, FINAL, vdtypep->subDTypep(), - EXTEND_EXP); + iterateCheck(nodep, "default", nodep->defaultp(), CONTEXT, FINAL, + vdtypep->subDTypep(), EXTEND_EXP); } } } @@ -3098,7 +3098,8 @@ private: AstNode* valuep = patternMemberValueIterate(patp); if (VN_IS(arrayDtp, UnpackArrayDType)) { if (!newp) { - AstInitArray* newap = new AstInitArray(nodep->fileline(), arrayDtp, nullptr); + AstInitArray* newap + = new AstInitArray(nodep->fileline(), arrayDtp, nullptr); newp = newap; } VN_CAST(newp, InitArray)->addIndexValuep(ent - range.lo(), valuep); diff --git a/test_regress/t/t_clk_inp_init.cpp b/test_regress/t/t_clk_inp_init.cpp index 08fdd1118..ffbd585c3 100644 --- a/test_regress/t/t_clk_inp_init.cpp +++ b/test_regress/t/t_clk_inp_init.cpp @@ -59,9 +59,7 @@ int main(int argc, char** argv, char** env) { // Verilated::debug(1); #endif - for (int seed = 123; seed < 133; ++seed) { - oneTest(seed); - } + for (int seed = 123; seed < 133; ++seed) oneTest(seed); return 0; } diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index 0c0609784..a51d3aef4 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -69,9 +69,7 @@ void check_bvals(const svLogicVecVal* v, unsigned n) { void set_bvals(svLogicVecVal* v, unsigned n); void set_bvals(svLogicVecVal* v, unsigned n) { - for (unsigned i = 0; i < n; i++) { - v[i].bval = 0; - } + for (unsigned i = 0; i < n; i++) v[i].bval = 0; } // Basic types as per IEEE 1800-2017 35.5.6 diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index fe792ea45..6f179d7e9 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -570,9 +570,7 @@ void i_union_4_state_128(CONSTARG svLogicVecVal* i) { void set_bvals(svLogicVecVal* v, unsigned n); void set_bvals(svLogicVecVal* v, unsigned n) { - for (unsigned i = 0; i < n; i++) { - v[i].bval = 0; - } + for (unsigned i = 0; i < n; i++) v[i].bval = 0; } void check_exports() { diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index c257f53ff..40161ed25 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -53,9 +53,7 @@ typedef uint64_t sv_longint_unsigned_t; void set_bvals(svLogicVecVal* v, unsigned n); void set_bvals(svLogicVecVal* v, unsigned n) { - for (unsigned i = 0; i < n; i++) { - v[i].bval = 0; - } + for (unsigned i = 0; i < n; i++) v[i].bval = 0; } // Basic types as per IEEE 1800-2017 35.5.6 diff --git a/test_regress/t/t_dpi_context_c.cpp b/test_regress/t/t_dpi_context_c.cpp index 1447ab083..2d1a8fbe4 100644 --- a/test_regress/t/t_dpi_context_c.cpp +++ b/test_regress/t/t_dpi_context_c.cpp @@ -35,10 +35,10 @@ #ifdef NEED_EXTERNS extern "C" { - extern int dpic_line(); - extern int dpic_save(int value); - extern int dpic_restore(); - extern unsigned dpic_getcontext(); +extern int dpic_line(); +extern int dpic_save(int value); +extern int dpic_restore(); +extern unsigned dpic_getcontext(); } #endif @@ -94,7 +94,8 @@ int dpic_save(int value) { int i; } vp; - vp.i = value; if (vp.i) { } + vp.i = value; + if (vp.i) {} if (svPutUserData(scope, &Dpic_Unique, vp.ptr)) { printf("%%Warning: svPutUserData failed\n"); return 0; diff --git a/test_regress/t/t_dpi_display_c.cpp b/test_regress/t/t_dpi_display_c.cpp index befb46dc5..0be29e589 100644 --- a/test_regress/t/t_dpi_display_c.cpp +++ b/test_regress/t/t_dpi_display_c.cpp @@ -27,7 +27,7 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpii_display_call(const char* c); +extern void dpii_display_call(const char* c); } #endif diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index 297a6edc1..e858de367 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -38,29 +38,29 @@ #ifdef NEED_EXTERNS extern "C" { - extern int dpix_run_tests(); +extern int dpix_run_tests(); - extern int dpix_t_int(int i, int* o); - extern int dpix_t_renamed(int i, int* o); +extern int dpix_t_int(int i, int* o); +extern int dpix_t_renamed(int i, int* o); - extern int dpix_int123(); +extern int dpix_int123(); - extern unsigned char dpix_f_bit(unsigned char i); - extern svBitVecVal dpix_f_bit15(const svBitVecVal* i); - extern svBitVecVal dpix_f_bit48(const svBitVecVal* i); - extern int dpix_f_int(int i); - extern char dpix_f_byte(char i); - extern short int dpix_f_shortint(short int i); - extern long long dpix_f_longint(long long i); - extern void* dpix_f_chandle(void* i); +extern unsigned char dpix_f_bit(unsigned char i); +extern svBitVecVal dpix_f_bit15(const svBitVecVal* i); +extern svBitVecVal dpix_f_bit48(const svBitVecVal* i); +extern int dpix_f_int(int i); +extern char dpix_f_byte(char i); +extern short int dpix_f_shortint(short int i); +extern long long dpix_f_longint(long long i); +extern void* dpix_f_chandle(void* i); - extern int dpix_sub_inst(int i); +extern int dpix_sub_inst(int i); - extern void dpix_t_reg(svLogic i, svLogic* o); - extern void dpix_t_reg15(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpix_t_reg95(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpix_t_integer(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpix_t_reg(svLogic i, svLogic* o); +extern void dpix_t_reg15(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpix_t_reg95(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpix_t_integer(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o); } #endif @@ -115,10 +115,9 @@ int dpix_run_tests() { #ifndef CADENCE // Unimplemented; how hard is it? printf("svDpiVersion: %s\n", svDpiVersion()); - CHECK_RESULT(bool, - strcmp(svDpiVersion(), "1800-2005")==0 - || strcmp(svDpiVersion(), "P1800-2005")==0 - , 1); + CHECK_RESULT( + bool, + strcmp(svDpiVersion(), "1800-2005") == 0 || strcmp(svDpiVersion(), "P1800-2005") == 0, 1); #endif CHECK_RESULT(int, dpix_int123(), 0x123); @@ -173,7 +172,7 @@ int dpix_run_tests() { CHECK_RESULT(int, o_vec96[2], ~i_vec96[2]); } - extern void dpix_t_reg(svLogic i, svLogic* o); + extern void dpix_t_reg(svLogic i, svLogic * o); { svLogic i = 0; svLogic o; diff --git a/test_regress/t/t_dpi_export_context_bad.cpp b/test_regress/t/t_dpi_export_context_bad.cpp index 7f0a9f4b3..86e6fcc1f 100644 --- a/test_regress/t/t_dpi_export_context_bad.cpp +++ b/test_regress/t/t_dpi_export_context_bad.cpp @@ -23,7 +23,7 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpix_task(); +extern void dpix_task(); } #endif diff --git a/test_regress/t/t_dpi_imp_gen_c.cpp b/test_regress/t/t_dpi_imp_gen_c.cpp index 03f907f0d..f7a6b5d1a 100644 --- a/test_regress/t/t_dpi_imp_gen_c.cpp +++ b/test_regress/t/t_dpi_imp_gen_c.cpp @@ -27,7 +27,7 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpi_genvarTest(); +extern void dpi_genvarTest(); } #endif diff --git a/test_regress/t/t_dpi_import_c.cpp b/test_regress/t/t_dpi_import_c.cpp index 5a174cd67..e23a2a599 100644 --- a/test_regress/t/t_dpi_import_c.cpp +++ b/test_regress/t/t_dpi_import_c.cpp @@ -32,99 +32,101 @@ typedef struct { #ifdef NEED_EXTERNS extern "C" { - // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. - // Then probably forgot to list a function here. +// If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. +// Then probably forgot to list a function here. - extern unsigned char dpii_f_bit (unsigned char i); - extern svBitVecVal dpii_f_bit8 (const svBitVecVal* i); - extern svBitVecVal dpii_f_bit9 (const svBitVecVal* i); - extern svBitVecVal dpii_f_bit16 (const svBitVecVal* i); - extern svBitVecVal dpii_f_bit17 (const svBitVecVal* i); - extern svBitVecVal dpii_f_bit32 (const svBitVecVal* i); - extern long long dpii_f_bit33 (const svBitVecVal* i); - extern long long dpii_f_bit64 (const svBitVecVal* i); - extern long long dpii_f_bit95 (const svBitVecVal* i, svBitVecVal* o); - extern int dpii_f_int (int i); - extern char dpii_f_byte (char i); - extern short int dpii_f_shortint(short int i); - extern long long dpii_f_longint (long long i); - extern void* dpii_f_chandle (void* i); - extern const char* dpii_f_string (const char* i); - extern double dpii_f_real (double i); - extern float dpii_f_shortreal(float i); +extern unsigned char dpii_f_bit(unsigned char i); +extern svBitVecVal dpii_f_bit8(const svBitVecVal* i); +extern svBitVecVal dpii_f_bit9(const svBitVecVal* i); +extern svBitVecVal dpii_f_bit16(const svBitVecVal* i); +extern svBitVecVal dpii_f_bit17(const svBitVecVal* i); +extern svBitVecVal dpii_f_bit32(const svBitVecVal* i); +extern long long dpii_f_bit33(const svBitVecVal* i); +extern long long dpii_f_bit64(const svBitVecVal* i); +extern long long dpii_f_bit95(const svBitVecVal* i, svBitVecVal* o); +extern int dpii_f_int(int i); +extern char dpii_f_byte(char i); +extern short int dpii_f_shortint(short int i); +extern long long dpii_f_longint(long long i); +extern void* dpii_f_chandle(void* i); +extern const char* dpii_f_string(const char* i); +extern double dpii_f_real(double i); +extern float dpii_f_shortreal(float i); - extern void dpii_v_bit (unsigned char i, unsigned char* o); - extern void dpii_v_int (int i, int *o); - extern void dpii_v_uint (unsigned int i, unsigned int *o); - extern void dpii_v_byte (char i, char *o); - extern void dpii_v_shortint (short int i, short int *o); - extern void dpii_v_ushort (unsigned short i, unsigned short *o); - extern void dpii_v_longint (long long i, long long *o); - extern void dpii_v_ulong (unsigned long long i, unsigned long long *o); - extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o); - extern void dpii_v_substruct (const svBitVecVal* i, int* o); - extern void dpii_v_chandle (void* i, void* *o); - extern void dpii_v_string (const char* i, const char** o); - extern void dpii_v_real (double i, double* o); - extern void dpii_v_shortreal(float i, float* o); +extern void dpii_v_bit(unsigned char i, unsigned char* o); +extern void dpii_v_int(int i, int* o); +extern void dpii_v_uint(unsigned int i, unsigned int* o); +extern void dpii_v_byte(char i, char* o); +extern void dpii_v_shortint(short int i, short int* o); +extern void dpii_v_ushort(unsigned short i, unsigned short* o); +extern void dpii_v_longint(long long i, long long* o); +extern void dpii_v_ulong(unsigned long long i, unsigned long long* o); +extern void dpii_v_struct(const svBitVecVal* i, svBitVecVal* o); +extern void dpii_v_substruct(const svBitVecVal* i, int* o); +extern void dpii_v_chandle(void* i, void** o); +extern void dpii_v_string(const char* i, const char** o); +extern void dpii_v_real(double i, double* o); +extern void dpii_v_shortreal(float i, float* o); - extern void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o); - extern void dpii_v_substruct (const svBitVecVal* i, int* o); - extern void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o); - extern void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o); - extern void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o); +extern void dpii_v_struct(const svBitVecVal* i, svBitVecVal* o); +extern void dpii_v_substruct(const svBitVecVal* i, int* o); +extern void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o); +extern void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o); +extern void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o); - extern void dpii_v_reg(unsigned char i, unsigned char* o); - extern void dpii_v_reg15(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpii_v_reg95(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpii_v_integer(const svLogicVecVal* i, svLogicVecVal* o); - extern void dpii_v_time(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpii_v_reg(unsigned char i, unsigned char* o); +extern void dpii_v_reg15(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpii_v_reg95(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpii_v_integer(const svLogicVecVal* i, svLogicVecVal* o); +extern void dpii_v_time(const svLogicVecVal* i, svLogicVecVal* o); - extern int dpii_f_strlen(const char* i); +extern int dpii_f_strlen(const char* i); - extern void dpii_f_void(); - extern int dpii_t_void(); - extern int dpii_t_void_context(); - extern int dpii_t_int(int i, int *o); +extern void dpii_f_void(); +extern int dpii_t_void(); +extern int dpii_t_void_context(); +extern int dpii_t_int(int i, int* o); - extern int dpii_fa_bit(int i); +extern int dpii_fa_bit(int i); } #endif //====================================================================== -unsigned char dpii_f_bit (unsigned char i) { return 0x1 & ~i; } -svBitVecVal dpii_f_bit8 (const svBitVecVal *i) { return 0xffUL & ~*i; } -svBitVecVal dpii_f_bit9 (const svBitVecVal *i) { return 0x1ffUL & ~*i; } -svBitVecVal dpii_f_bit16(const svBitVecVal *i) { return 0xffffUL & ~*i; } -svBitVecVal dpii_f_bit17(const svBitVecVal *i) { return 0x1ffffUL & ~*i; } -svBitVecVal dpii_f_bit32(const svBitVecVal *i) { return ~*i; } -long long dpii_f_bit33(const svBitVecVal *i) { return ((1ULL<<33)-1) & ~((long long)(i[1])<<32ULL | i[0]); } -long long dpii_f_bit64(const svBitVecVal *i) { return ~((long long)(i[1])<<32ULL | i[0]); } +unsigned char dpii_f_bit(unsigned char i) { return 0x1 & ~i; } +svBitVecVal dpii_f_bit8(const svBitVecVal* i) { return 0xffUL & ~*i; } +svBitVecVal dpii_f_bit9(const svBitVecVal* i) { return 0x1ffUL & ~*i; } +svBitVecVal dpii_f_bit16(const svBitVecVal* i) { return 0xffffUL & ~*i; } +svBitVecVal dpii_f_bit17(const svBitVecVal* i) { return 0x1ffffUL & ~*i; } +svBitVecVal dpii_f_bit32(const svBitVecVal* i) { return ~*i; } +long long dpii_f_bit33(const svBitVecVal* i) { + return ((1ULL << 33) - 1) & ~((long long)(i[1]) << 32ULL | i[0]); +} +long long dpii_f_bit64(const svBitVecVal* i) { return ~((long long)(i[1]) << 32ULL | i[0]); } -int dpii_f_int (int i) { return ~i; } -char dpii_f_byte (char i) { return ~i; } -short int dpii_f_shortint(short int i) { return ~i; } -long long dpii_f_longint (long long i) { return ~i; } -void* dpii_f_chandle (void* i) { return i; } -const char* dpii_f_string (const char* i) { return i; } -double dpii_f_real (double i) { return i+1.5; } -float dpii_f_shortreal(float i) { return i+1.5f; } +int dpii_f_int(int i) { return ~i; } +char dpii_f_byte(char i) { return ~i; } +short int dpii_f_shortint(short int i) { return ~i; } +long long dpii_f_longint(long long i) { return ~i; } +void* dpii_f_chandle(void* i) { return i; } +const char* dpii_f_string(const char* i) { return i; } +double dpii_f_real(double i) { return i + 1.5; } +float dpii_f_shortreal(float i) { return i + 1.5f; } -void dpii_v_bit(unsigned char i, unsigned char *o) { *o = 1 & ~i; } -void dpii_v_int(int i, int *o) { *o = ~i; } -void dpii_v_uint(unsigned int i, unsigned int *o) { *o = ~i; } -void dpii_v_byte(char i, char *o) { *o = ~i; } -void dpii_v_shortint(short int i, short int *o) { *o = ~i; } -void dpii_v_ushort(unsigned short i, unsigned short *o) { *o = ~i; } -void dpii_v_longint(long long i, long long *o) { *o = ~i; } -void dpii_v_ulong(unsigned long long i, unsigned long long *o) { *o = ~i; } -void dpii_v_chandle(void* i, void* *o) { *o = i; } -void dpii_v_string(const char* i, const char** o) { *o = strdup(i); } // Leaks -void dpii_v_real(double i, double* o) { *o = i + 1.5; } -void dpii_v_shortreal(float i, float* o) { *o = i + 1.5f; } +void dpii_v_bit(unsigned char i, unsigned char* o) { *o = 1 & ~i; } +void dpii_v_int(int i, int* o) { *o = ~i; } +void dpii_v_uint(unsigned int i, unsigned int* o) { *o = ~i; } +void dpii_v_byte(char i, char* o) { *o = ~i; } +void dpii_v_shortint(short int i, short int* o) { *o = ~i; } +void dpii_v_ushort(unsigned short i, unsigned short* o) { *o = ~i; } +void dpii_v_longint(long long i, long long* o) { *o = ~i; } +void dpii_v_ulong(unsigned long long i, unsigned long long* o) { *o = ~i; } +void dpii_v_chandle(void* i, void** o) { *o = i; } +void dpii_v_string(const char* i, const char** o) { *o = strdup(i); } // Leaks +void dpii_v_real(double i, double* o) { *o = i + 1.5; } +void dpii_v_shortreal(float i, float* o) { *o = i + 1.5f; } -void dpii_v_reg(unsigned char i, unsigned char* o) { *o = (~i)&1; } +void dpii_v_reg(unsigned char i, unsigned char* o) { *o = (~i) & 1; } void dpii_v_reg15(const svLogicVecVal* i, svLogicVecVal* o) { o[0].aval = (~i[0].aval) & 0x7fffUL; o[0].bval = 0; diff --git a/test_regress/t/t_dpi_lib_c.cpp b/test_regress/t/t_dpi_lib_c.cpp index b800b17fc..04ad63bad 100644 --- a/test_regress/t/t_dpi_lib_c.cpp +++ b/test_regress/t/t_dpi_lib_c.cpp @@ -28,11 +28,11 @@ #ifdef NEED_EXTERNS extern "C" { - // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. - // Then probably forgot to list a function here. +// If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. +// Then probably forgot to list a function here. - extern int dpii_failure(); - extern void dpii_check(); +extern int dpii_failure(); +extern void dpii_check(); } #endif diff --git a/test_regress/t/t_dpi_open_c.cpp b/test_regress/t/t_dpi_open_c.cpp index 466010aca..806555f74 100644 --- a/test_regress/t/t_dpi_open_c.cpp +++ b/test_regress/t/t_dpi_open_c.cpp @@ -30,28 +30,37 @@ #ifdef NEED_EXTERNS extern "C" { - // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. - // Then probably forgot to list a function here. +// If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. +// Then probably forgot to list a function here. - extern void dpii_unused(const svOpenArrayHandle u); +extern void dpii_unused(const svOpenArrayHandle u); - extern void dpii_open_p0_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_p1_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_p1_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_p1_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_p1_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_pw_u0(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_pw_u1(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_pw_u2(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_pw_u3(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_p0_u1(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_p1_u0(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_p1_u1(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_p1_u2(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_p1_u3(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_pw_u0(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_pw_u1(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_pw_u2(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); +extern void dpii_open_pw_u3(int c, int p, int u, const svOpenArrayHandle i, + const svOpenArrayHandle o); - extern void dpii_open_bit(const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_byte(const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_int(const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_integer(const svOpenArrayHandle i, const svOpenArrayHandle o); - extern void dpii_open_logic(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_bit(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_byte(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_int(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_integer(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern void dpii_open_logic(const svOpenArrayHandle i, const svOpenArrayHandle o); - extern int dpii_failure(); +extern int dpii_failure(); } #endif @@ -109,7 +118,7 @@ void dpii_unused(const svOpenArrayHandle u) {} void _dpii_all(int c, int p, int u, const svOpenArrayHandle i, const svOpenArrayHandle o) { #ifdef TEST_VERBOSE - printf("-:%s:%d: For case c=%d p=%d u=%d data=%p\n", + printf("-:%s:%d: For case c=%d p=%d u=%d data=%p\n", // __FILE__, __LINE__, c, p, u, svGetArrayPtr(i)); #endif (void)svGetArrayPtr(i); @@ -238,23 +247,23 @@ void dpii_open_bit(const svOpenArrayHandle i, const svOpenArrayHandle o) {} void dpii_open_byte(const svOpenArrayHandle i, const svOpenArrayHandle o) { intptr_t arrPtr = (intptr_t)svGetArrayPtr(i); - CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist + CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist #ifndef NC // NC always returns zero and warns int sizeInputOfArray = svSizeOfArray(i); - CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size - CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays + CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size + CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays #endif } void dpii_open_int(const svOpenArrayHandle i, const svOpenArrayHandle o) { intptr_t arrPtr = (intptr_t)svGetArrayPtr(i); - CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist + CHECK_RESULT_HEX_NE(arrPtr, 0); // All the arrays should actually exist #ifndef NC // NC always returns zero and warns int sizeInputOfArray = svSizeOfArray(i); - CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size - CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays + CHECK_RESULT_HEX_NE(sizeInputOfArray, 0); // None of the test cases have zero size + CHECK_RESULT_HEX_NE(svDimensions(i), 0); // All the test cases are unpacked arrays #endif } diff --git a/test_regress/t/t_dpi_openfirst_c.cpp b/test_regress/t/t_dpi_openfirst_c.cpp index c5ba23795..0a18aa736 100644 --- a/test_regress/t/t_dpi_openfirst_c.cpp +++ b/test_regress/t/t_dpi_openfirst_c.cpp @@ -28,11 +28,11 @@ #ifdef NEED_EXTERNS extern "C" { - // If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. - // Then probably forgot to list a function here. +// If get ncsim: *F,NOFDPI: Function {foo} not found in default libdpi. +// Then probably forgot to list a function here. - extern int dpii_failure(); - extern void dpii_open_i(const svOpenArrayHandle i, const svOpenArrayHandle o); +extern int dpii_failure(); +extern void dpii_open_i(const svOpenArrayHandle i, const svOpenArrayHandle o); } #endif diff --git a/test_regress/t/t_dpi_shortcircuit_c.cpp b/test_regress/t/t_dpi_shortcircuit_c.cpp index 4f381111a..211231a8a 100644 --- a/test_regress/t/t_dpi_shortcircuit_c.cpp +++ b/test_regress/t/t_dpi_shortcircuit_c.cpp @@ -33,11 +33,11 @@ #ifdef NEED_EXTERNS extern "C" { - extern int dpii_clear(); - extern int dpii_count(int idx); - extern unsigned char dpii_inc0(int idx); - extern unsigned char dpii_inc1(int idx); - extern unsigned char dpii_incx(int idx, unsigned char value); +extern int dpii_clear(); +extern int dpii_count(int idx); +extern unsigned char dpii_inc0(int idx); +extern unsigned char dpii_inc1(int idx); +extern unsigned char dpii_incx(int idx, unsigned char value); } #endif @@ -50,9 +50,7 @@ int dpii_clear() { for (int i = 0; i < COUNTERS; ++i) global_count[i] = 0; return 0; } -int dpii_count(int idx) { - return (idx >= 0 && idx < COUNTERS) ? global_count[idx] : -1; -} +int dpii_count(int idx) { return (idx >= 0 && idx < COUNTERS) ? global_count[idx] : -1; } unsigned char dpii_incx(int idx, unsigned char value) { if (idx >= 0 && idx < COUNTERS) global_count[idx]++; return value; diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index 9b8a476eb..b357c65b6 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -28,14 +28,13 @@ #ifdef NEED_EXTERNS extern "C" { - extern int dpii_string(const char* s); - +extern int dpii_string(const char* s); } #endif //====================================================================== int dpii_string(const char* s) { - printf("dpii_string: %s\n",s); + printf("dpii_string: %s\n", s); return strlen(s); } diff --git a/test_regress/t/t_dpi_sys_c.cpp b/test_regress/t/t_dpi_sys_c.cpp index b6a15e6d3..6e904fad1 100644 --- a/test_regress/t/t_dpi_sys_c.cpp +++ b/test_regress/t/t_dpi_sys_c.cpp @@ -27,9 +27,8 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpii_sys_task(int i); - extern int dpii_sys_func(int i); - +extern void dpii_sys_task(int i); +extern int dpii_sys_func(int i); } #endif diff --git a/test_regress/t/t_dpi_threads_c.cpp b/test_regress/t/t_dpi_threads_c.cpp index edc7de5c5..3f06f2d64 100644 --- a/test_regress/t/t_dpi_threads_c.cpp +++ b/test_regress/t/t_dpi_threads_c.cpp @@ -33,8 +33,8 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpii_sys_task(); - extern int dpii_failure(); +extern void dpii_sys_task(); +extern int dpii_failure(); } #endif @@ -57,7 +57,8 @@ void dpii_sys_task() { st.failure = 1; std::cerr << "t_dpi_threads_c.cpp dpii_sys_task() saw threads collide.\n"; } else { - std::cerr << "t_dpi_threads_c.cpp dpii_sys_task() no collision. @" << &st.task_is_running << "\n"; + std::cerr << "t_dpi_threads_c.cpp dpii_sys_task() no collision. @" << &st.task_is_running + << "\n"; } // Spend some time in the DPI call, so that if we can have a collision diff --git a/test_regress/t/t_dpi_vams.cpp b/test_regress/t/t_dpi_vams.cpp index 2a0b44465..0abce4a58 100644 --- a/test_regress/t/t_dpi_vams.cpp +++ b/test_regress/t/t_dpi_vams.cpp @@ -23,13 +23,11 @@ #ifdef NEED_EXTERNS extern "C" { - extern void dpii_call(double in, double* outp); +extern void dpii_call(double in, double* outp); } #endif -void dpii_call(double in, double* outp) { - *outp = in + 0.1; -} +void dpii_call(double in, double* outp) { *outp = in + 0.1; } //====================================================================== unsigned int main_time = 0; diff --git a/test_regress/t/t_embed1_c.cpp b/test_regress/t/t_embed1_c.cpp index 8feeea826..78ae95cb0 100644 --- a/test_regress/t/t_embed1_c.cpp +++ b/test_regress/t/t_embed1_c.cpp @@ -30,10 +30,10 @@ #ifdef NEED_EXTERNS extern "C" { - extern void t_embed_child_initial(); - extern void t_embed_child_final(); - extern void t_embed_child_eval(); - extern void t_embed_child_io_eval(); // TODO real function params here +extern void t_embed_child_initial(); +extern void t_embed_child_final(); +extern void t_embed_child_eval(); +extern void t_embed_child_io_eval(); // TODO real function params here } #endif @@ -91,9 +91,8 @@ void t_embed_child_io_eval(unsigned char clk, unsigned char* did_init_out) { VL_DEBUG_IF(VL_PRINTF(" t_embed1_child_io_eval\n");); Vt_embed1_child* __modelp = __get_modelp(); - VL_DEBUG_IF(VL_PRINTF("[%0ld] in clk=%x b=%x V=%x R=%x\n", - (long int) (VL_TIME_Q()), clk, bit_in, vec_in[0], - is_ref);); + VL_DEBUG_IF(VL_PRINTF("[%0ld] in clk=%x b=%x V=%x R=%x\n", // + (long int)(VL_TIME_Q()), clk, bit_in, vec_in[0], is_ref);); __modelp->clk = clk; __modelp->bit_in = bit_in; __modelp->vec_in = vec_in[0]; @@ -114,7 +113,6 @@ void t_embed_child_io_eval(unsigned char clk, wide_out[2] = __modelp->wide_out[2]; wide_out[3] = __modelp->wide_out[3]; *did_init_out = __modelp->did_init_out; - VL_DEBUG_IF(VL_PRINTF("[%0ld] out b=%x V=%x DI=%x\n", - (long int)(VL_TIME_Q()), *bit_out, *vec_out, - *did_init_out);); + VL_DEBUG_IF(VL_PRINTF("[%0ld] out b=%x V=%x DI=%x\n", // + (long int)(VL_TIME_Q()), *bit_out, *vec_out, *did_init_out);); } diff --git a/test_regress/t/t_enum_public.cpp b/test_regress/t/t_enum_public.cpp index e0d95de7a..598275ffc 100644 --- a/test_regress/t/t_enum_public.cpp +++ b/test_regress/t/t_enum_public.cpp @@ -21,7 +21,7 @@ int main(int argc, char* argv[]) { if (Vt_enum_public_p3::ZERO == Vt_enum_public_p3::ONE) {} if (Vt_enum_public_p62::ZERO == Vt_enum_public_p62::ALLONE) {} - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { // topp->eval(); } } diff --git a/test_regress/t/t_hier_block.cpp b/test_regress/t/t_hier_block.cpp index 298d13513..75f09abf1 100644 --- a/test_regress/t/t_hier_block.cpp +++ b/test_regress/t/t_hier_block.cpp @@ -9,9 +9,6 @@ // //************************************************************************* - extern "C" int dpi_export_func(int); -extern "C" int dpi_import_func(int v) { - return dpi_export_func(v) - 1; -} +extern "C" int dpi_import_func(int v) { return dpi_export_func(v) - 1; } diff --git a/test_regress/t/t_leak.cpp b/test_regress/t/t_leak.cpp index c42d459fc..6bb6cfe28 100644 --- a/test_regress/t/t_leak.cpp +++ b/test_regress/t/t_leak.cpp @@ -65,7 +65,7 @@ int main(int argc, char* argv[]) { vluint64_t firstUsage = get_memory_usage(); // Warmup phase - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { // make_and_destroy(); } firstUsage = get_memory_usage(); @@ -73,14 +73,15 @@ int main(int argc, char* argv[]) { int loops = 10; for (int left = loops; left > 0;) { - for (int j = 0; j < 1; ++j, --left) { + for (int j = 0; j < 1; ++j, --left) { // make_and_destroy(); } } vluint64_t leaked = get_memory_usage() - firstUsage; if (leaked > 64*1024) { // Have to allow some slop for this code. - printf("Leaked %" VL_PRI64 "d bytes, or ~ %" VL_PRI64 "d bytes/construt\n", leaked, leaked/loops); + printf("Leaked %" VL_PRI64 "d bytes, or ~ %" VL_PRI64 "d bytes/construt\n", // + leaked, leaked / loops); vl_fatal(__FILE__, __LINE__, "top", "Leaked memory\n"); } diff --git a/test_regress/t/t_math_imm2.cpp b/test_regress/t/t_math_imm2.cpp index 64d3544f2..999ef1157 100644 --- a/test_regress/t/t_math_imm2.cpp +++ b/test_regress/t/t_math_imm2.cpp @@ -8,8 +8,7 @@ QData MaskVal(int lbit, int hbit) { QData val; - for (val = 0; lbit <= hbit; lbit++) - val |= (1ULL << lbit); + for (val = 0; lbit <= hbit; lbit++) val |= (1ULL << lbit); return val; } @@ -35,12 +34,12 @@ int main(int argc, char* argv[]) { | MaskVal(sim->LowMaskSel_Bot, sim->HighMaskSel_Bot)); if (sim->LogicImm != expected) { - printf("%%Error: %d.%d,%d.%d -> %016" VL_PRI64 "x/%016" VL_PRI64 "x -> %016" VL_PRI64 "x (expected %016" VL_PRI64 "x)\n", - sim->LowMaskSel_Top, sim->HighMaskSel_Top, - sim->LowMaskSel_Bot, sim->HighMaskSel_Bot, - sim->LowLogicImm, sim->HighLogicImm, - sim->LogicImm, expected); - errs=1; + printf("%%Error: %d.%d,%d.%d -> %016" VL_PRI64 "x/%016" VL_PRI64 + "x -> %016" VL_PRI64 "x (expected %016" VL_PRI64 "x)\n", + sim->LowMaskSel_Top, sim->HighMaskSel_Top, sim->LowMaskSel_Bot, + sim->HighMaskSel_Bot, sim->LowLogicImm, sim->HighLogicImm, sim->LogicImm, + expected); + errs = 1; } } } diff --git a/test_regress/t/t_mem_multi_io2.cpp b/test_regress/t/t_mem_multi_io2.cpp index 6598388cf..c12e8330a 100644 --- a/test_regress/t/t_mem_multi_io2.cpp +++ b/test_regress/t/t_mem_multi_io2.cpp @@ -61,9 +61,7 @@ int main() ASSIGN(i3, 13); for (int i = 0; i < 4; i++) { ASSIGN(i34[i], i); - for (int j = 0; j < 5; j++) { - ASSIGN(i345[i][j], i * 8 + j); - } + for (int j = 0; j < 5; j++) ASSIGN(i345[i][j], i * 8 + j); } #ifdef SYSTEMC_VERSION @@ -75,9 +73,7 @@ int main() check("o3", READ(o3), 13); for (int i = 0; i < 4; i++) { check("o34", READ(o34[i]), i); - for (int j = 0; j < 5; j++) { - check("o345", READ(o345[i][j]), i * 8 + j); - } + for (int j = 0; j < 5; j++) check("o345", READ(o345[i][j]), i * 8 + j); } if (pass) { diff --git a/test_regress/t/t_mem_slot.cpp b/test_regress/t/t_mem_slot.cpp index dc6d2acba..7d367925e 100644 --- a/test_regress/t/t_mem_slot.cpp +++ b/test_regress/t/t_mem_slot.cpp @@ -52,7 +52,8 @@ int main(int argc, char* argv[]) { StepSim(sim, slot, bit, 0, 0); printf("\nTesting\n"); - for (i = 0; i < 100; i++) + for (i = 0; i < 100; i++) // StepSim(sim, random() % 3, random() % 2, random() % 2, random() % 3); + printf("*-* All Finished *-*\n"); } diff --git a/test_regress/t/t_order_multidriven.cpp b/test_regress/t/t_order_multidriven.cpp index 7a7e3adc7..8679cdca3 100644 --- a/test_regress/t/t_order_multidriven.cpp +++ b/test_regress/t/t_order_multidriven.cpp @@ -51,8 +51,9 @@ int main() { vcore->i_clk_wr = 0; vcore->i_clk_rd = 0; - for (int i = 0; i < 256; ++i) + for (int i = 0; i < 256; ++i) { // cycle(); + } vcd->close(); printf("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_param_public.cpp b/test_regress/t/t_param_public.cpp index 1620fb2d4..093d5acb6 100644 --- a/test_regress/t/t_param_public.cpp +++ b/test_regress/t/t_param_public.cpp @@ -23,7 +23,7 @@ int main(int argc, char* argv[]) { } if (static_cast(Vt_param_public_p::INPACK) != 0) {} - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 10; i++) { // topp->eval(); } } diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp index 00a7503f4..163916db5 100644 --- a/test_regress/t/t_sc_names.cpp +++ b/test_regress/t/t_sc_names.cpp @@ -10,14 +10,12 @@ VM_PREFIX* tb = nullptr; int sc_main(int argc, char* argv[]) { tb = new VM_PREFIX("tb"); - std::vector < sc_object* > ch = tb->get_child_objects(); + std::vector ch = tb->get_child_objects(); bool found = false; /* We expect to find clk in here. */ for (int i = 0; i < ch.size(); ++i) { - if (!strcmp(ch[i]->basename(), "clk")) { - found = true; - } + if (!strcmp(ch[i]->basename(), "clk")) found = true; } if (found) { diff --git a/test_regress/t/t_tri_inz.cpp b/test_regress/t/t_tri_inz.cpp index 752274f44..0e47c3b8d 100644 --- a/test_regress/t/t_tri_inz.cpp +++ b/test_regress/t/t_tri_inz.cpp @@ -34,9 +34,9 @@ void check(int d, int en, int exp0, int exp1, int expx, int expz) { int main() { Verilated::debug(0); tb = new Vt_tri_inz("tb"); - check(0, 1, 1,0,0,0); - check(1, 1, 0,1,0,0); - check(0, 0, 0,0,0,1); + check(0, 1, 1, 0, 0, 0); + check(1, 1, 0, 1, 0, 0); + check(0, 0, 0, 0, 0, 1); if (pass) { VL_PRINTF("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_vpi_finish_c.cpp b/test_regress/t/t_vpi_finish_c.cpp index 14f1e056d..714bbbe1a 100644 --- a/test_regress/t/t_vpi_finish_c.cpp +++ b/test_regress/t/t_vpi_finish_c.cpp @@ -17,11 +17,9 @@ //====================================================================== extern "C" { - extern void dpii_test(); +extern void dpii_test(); } //====================================================================== -void dpii_test() { - vpi_control(vpiFinish); -} +void dpii_test() { vpi_control(vpiFinish); } diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 9a18662f6..90741ef73 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -224,8 +224,7 @@ static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8* void vpi_compat_bootstrap(void) { p_vpi_systf_data systf_data_p; systf_data_p = &(vpi_systf_data[0]); - while (systf_data_p->type != 0) - vpi_register_systf(systf_data_p++); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); } // icarus entry diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 60891c5a6..6cfaebdaf 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -211,8 +211,7 @@ static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8* void vpi_compat_bootstrap(void) { p_vpi_systf_data systf_data_p; systf_data_p = &(vpi_systf_data[0]); - while (systf_data_p->type != 0) - vpi_register_systf(systf_data_p++); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); } // icarus entry diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index abbb9fc8a..dc5929f86 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -117,8 +117,7 @@ static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8* void vpi_compat_bootstrap(void) { p_vpi_systf_data systf_data_p; systf_data_p = &(vpi_systf_data[0]); - while (systf_data_p->type != 0) - vpi_register_systf(systf_data_p++); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); } // icarus entry diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index f2b5f4e10..bfba20a21 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -80,7 +80,6 @@ unsigned int main_time = 0; #define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) - int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verbose) { int vpi_type; TestVpiHandle param_h; @@ -95,7 +94,9 @@ int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verb CHECK_RESULT_NZ(param_h); vpi_type = vpi_get(vpiType, param_h); CHECK_RESULT(vpi_type, vpiParameter); - if (verbose) {vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); } + if (verbose) { + vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); + } // attributes p = vpi_get_str(vpiName, param_h); @@ -106,20 +107,28 @@ int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verb CHECK_RESULT_CSTR(p, "vpiParameter"); vpi_type = vpi_get(vpiLocalParam, param_h); CHECK_RESULT_NZ(vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } // values - if (verbose) {vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } + if (verbose) { vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } value.value.integer = exp_value; vpi_put_value(param_h, &value, NULL, vpiNoDelay); CHECK_RESULT_NZ(vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } - if (verbose) {vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } + if (verbose) { vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } vpi_get_value(param_h, &value); CHECK_RESULT_NZ(!vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } - if (verbose) {vpi_printf((PLI_BYTE8*)" value of %s: %d\n", name.c_str(), value.value.integer); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } + if (verbose) { + vpi_printf((PLI_BYTE8*)" value of %s: %d\n", name.c_str(), value.value.integer); + } CHECK_RESULT(value.value.integer, exp_value); return 0; @@ -139,7 +148,9 @@ int check_param_str(std::string name, PLI_INT32 format, std::string exp_value, b CHECK_RESULT_NZ(param_h); vpi_type = vpi_get(vpiType, param_h); CHECK_RESULT(vpi_type, vpiParameter); - if (verbose) {vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); } + if (verbose) { + vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); + } // attributes p = vpi_get_str(vpiName, param_h); @@ -150,20 +161,28 @@ int check_param_str(std::string name, PLI_INT32 format, std::string exp_value, b CHECK_RESULT_CSTR(p, "vpiParameter"); vpi_type = vpi_get(vpiLocalParam, param_h); CHECK_RESULT_NZ(vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } // values - if (verbose) {vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } - value.value.str = (PLI_BYTE8*) exp_value.c_str(); + if (verbose) { vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } + value.value.str = (PLI_BYTE8*)exp_value.c_str(); vpi_put_value(param_h, &value, NULL, vpiNoDelay); CHECK_RESULT_NZ(vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } - if (verbose) {vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } + if (verbose) { vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } vpi_get_value(param_h, &value); CHECK_RESULT_NZ(!vpi_chk_error(&e)); - if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } - if (verbose) {vpi_printf((PLI_BYTE8*)" value of %s: %s\n", name.c_str(), value.value.str); } + if (verbose && vpi_chk_error(&e)) { + vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); + } + if (verbose) { + vpi_printf((PLI_BYTE8*)" value of %s: %s\n", name.c_str(), value.value.str); + } CHECK_RESULT_CSTR(value.value.str, exp_value.c_str()); return 0; @@ -213,8 +232,7 @@ static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8* void vpi_compat_bootstrap(void) { p_vpi_systf_data systf_data_p; systf_data_p = &(vpi_systf_data[0]); - while (systf_data_p->type != 0) - vpi_register_systf(systf_data_p++); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); } // icarus entry diff --git a/test_regress/t/t_vpi_stop_bad_c.cpp b/test_regress/t/t_vpi_stop_bad_c.cpp index 40f9982d6..12128781c 100644 --- a/test_regress/t/t_vpi_stop_bad_c.cpp +++ b/test_regress/t/t_vpi_stop_bad_c.cpp @@ -17,11 +17,9 @@ //====================================================================== extern "C" { - extern void dpii_test(); +extern void dpii_test(); } //====================================================================== -void dpii_test() { - vpi_control(vpiStop); -} +void dpii_test() { vpi_control(vpiStop); } diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index 110f0a160..c0a170ac2 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -234,7 +234,7 @@ int main(int argc, char** argv, char** env) { topp->eval(); VerilatedVpi::callValueCbs(); VerilatedVpi::callTimedCbs(); - CHECK_RESULT(VerilatedVpi::cbNextDeadline(), main_time+1); + CHECK_RESULT(VerilatedVpi::cbNextDeadline(), main_time + 1); topp->clk = !topp->clk; // mon_do(); #if VM_TRACE diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 63ce3f507..53cdde2c5 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -201,9 +201,7 @@ int main(int argc, char** argv, char** env) { if (tfp) tfp->dump(main_time); #endif } - if (!callback_count) { - vl_fatal(FILENM, __LINE__, "main", "%Error: never got callbacks"); - } + if (!callback_count) vl_fatal(FILENM, __LINE__, "main", "%Error: never got callbacks"); if (!Verilated::gotFinish()) { vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); } diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 8de2707f9..17f943535 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -617,8 +617,7 @@ static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8* void vpi_compat_bootstrap(void) { p_vpi_systf_data systf_data_p; systf_data_p = &(vpi_systf_data[0]); - while (systf_data_p->type != 0) - vpi_register_systf(systf_data_p++); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); } // icarus entry From 23140aeff09b82afd338d58fb75d1f38d690f0aa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 27 Oct 2020 22:35:29 -0400 Subject: [PATCH 31/88] Internals: V3Begin code cleanup. No functional change. --- src/V3Begin.cpp | 63 ++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 262054805..cbe3871eb 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -69,6 +69,11 @@ private: // METHODS VL_DEBUG_FUNC; // Declare debug() + string dot(const string& a, const string& b) { + if (a == "") return b; + return a + "__DOT__" + b; + } + // VISITORS virtual void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); @@ -81,7 +86,7 @@ private: UINFO(8, " " << nodep << endl); // Rename it if (m_unnamedScope != "") { - nodep->name(m_unnamedScope + "__DOT__" + nodep->name()); + nodep->name(dot(m_unnamedScope, nodep->name())); UINFO(8, " rename to " << nodep->name() << endl); m_statep->userMarkChanged(nodep); } @@ -103,8 +108,8 @@ private: virtual void visit(AstBegin* nodep) override { // Begin blocks were only useful in variable creation, change names and delete UINFO(8, " " << nodep << endl); - string oldScope = m_namedScope; - string oldUnnamed = m_unnamedScope; + VL_RESTORER(m_namedScope); + VL_RESTORER(m_unnamedScope); { UINFO(8, "nname " << m_namedScope << endl); if (nodep->name() != "") { // Else unneeded unnamed block @@ -114,18 +119,8 @@ private: while ((pos = dottedname.find("__DOT__")) != string::npos) { string ident = dottedname.substr(0, pos); dottedname = dottedname.substr(pos + strlen("__DOT__")); - if (nodep->name() != "") { - if (m_namedScope == "") { - m_namedScope = ident; - } else { - m_namedScope = m_namedScope + "__DOT__" + ident; - } - } - if (m_unnamedScope == "") { - m_unnamedScope = ident; - } else { - m_unnamedScope = m_unnamedScope + "__DOT__" + ident; - } + if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident); + m_unnamedScope = dot(m_unnamedScope, ident); // Create CellInline for dotted var resolution if (!m_ftaskp) { AstCellInline* inlinep = new AstCellInline( @@ -138,31 +133,29 @@ private: // Remap var names and replace lower Begins iterateAndNextNull(nodep->stmtsp()); UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier"); - } - m_namedScope = oldScope; - m_unnamedScope = oldUnnamed; - // Cleanup - AstNode* addsp = nullptr; - if (AstNode* stmtsp = nodep->stmtsp()) { - stmtsp->unlinkFrBackWithNext(); - if (addsp) { - addsp = addsp->addNextNull(stmtsp); - } else { - addsp = stmtsp; + // Cleanup + AstNode* addsp = nullptr; + if (AstNode* stmtsp = nodep->stmtsp()) { + stmtsp->unlinkFrBackWithNext(); + if (addsp) { + addsp = addsp->addNextNull(stmtsp); + } else { + addsp = stmtsp; + } } + if (addsp) { + nodep->replaceWith(addsp); + } else { + nodep->unlinkFrBack(); + } + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - if (addsp) { - nodep->replaceWith(addsp); - } else { - nodep->unlinkFrBack(); - } - VL_DO_DANGLING(pushDeletep(nodep), nodep); } virtual void visit(AstVar* nodep) override { if (m_unnamedScope != "") { // Rename it - nodep->name(m_unnamedScope + "__DOT__" + nodep->name()); + nodep->name(dot(m_unnamedScope, nodep->name())); m_statep->userMarkChanged(nodep); // Move to module nodep->unlinkFrBack(); @@ -176,7 +169,7 @@ private: virtual void visit(AstTypedef* nodep) override { if (m_unnamedScope != "") { // Rename it - nodep->name(m_unnamedScope + "__DOT__" + nodep->name()); + nodep->name(dot(m_unnamedScope, nodep->name())); m_statep->userMarkChanged(nodep); // Move to module nodep->unlinkFrBack(); @@ -193,7 +186,7 @@ private: if (m_namedScope != "") { m_statep->userMarkChanged(nodep); // Rename it - nodep->name(m_namedScope + "__DOT__" + nodep->name()); + nodep->name(dot(m_namedScope, nodep->name())); UINFO(8, " rename to " << nodep->name() << endl); // Move to module nodep->unlinkFrBack(); From f670eccf8c1b4643f2cb71551e638ad6d5dbc275 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 28 Oct 2020 07:39:13 -0400 Subject: [PATCH 32/88] Tests: $countbits --- test_regress/t/t_math_countbits.v | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test_regress/t/t_math_countbits.v b/test_regress/t/t_math_countbits.v index 617d2b47d..8a1d9d4c5 100644 --- a/test_regress/t/t_math_countbits.v +++ b/test_regress/t/t_math_countbits.v @@ -56,6 +56,8 @@ module t(/*AUTOARG*/ result_70_3 = $countbits(in70, ctrl0, ctrl1, ctrl2); end + logic [31:0] val = 32'h70008421; + integer cyc=0; // Test loop always @ (posedge clk) begin @@ -70,6 +72,14 @@ module t(/*AUTOARG*/ if ($countbits(20'b1100x01z101, 2, 2'bx1) != 18) $stop; if ($countbits(32'b1100x01z101, 'x, 'z) != 2) $stop; if ($countbits(32'b1100x01z101, 'x, 'z, '1) != 7) $stop; + +`ifndef VERILATOR // Unsup + if ($countbits(val, '1) != 7) $stop; + if ($countones(val) != 7) $stop; + if ($countbits(val, '0) != 25) $stop; + if ($countbits(val, '0, '1) != 32) $stop; + if ($countbits(val, 'x, 'z) != 0) $stop; +`endif end else if (cyc == 1) begin in16 <= 16'h0AF0; From 0c328b6eafa66c8882aa667f8ad9245438e15b4f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 28 Oct 2020 18:42:36 -0400 Subject: [PATCH 33/88] clang-format of test_regress. No functional change. --- Makefile.in | 3 ++- test_regress/t/t_dpi_arg_inout_type.cpp | 2 ++ test_regress/t/t_dpi_arg_input_type.cpp | 2 ++ test_regress/t/t_dpi_arg_output_type.cpp | 2 ++ test_regress/t/t_dpi_context_c.cpp | 4 ++- test_regress/t/t_dpi_display_c.cpp | 8 +++--- test_regress/t/t_dpi_export_c.cpp | 27 +++++++++++++++------ test_regress/t/t_dpi_export_context_bad.cpp | 2 ++ test_regress/t/t_dpi_imp_gen_c.cpp | 2 ++ test_regress/t/t_dpi_import_c.cpp | 2 ++ test_regress/t/t_dpi_lib_c.cpp | 2 ++ test_regress/t/t_dpi_open_c.cpp | 4 +++ test_regress/t/t_dpi_open_query.cpp | 4 +-- test_regress/t/t_dpi_openfirst_c.cpp | 2 ++ test_regress/t/t_dpi_qw_c.cpp | 2 ++ test_regress/t/t_dpi_result_type.cpp | 2 ++ test_regress/t/t_dpi_shortcircuit_c.cpp | 2 ++ test_regress/t/t_dpi_string_c.cpp | 2 ++ test_regress/t/t_dpi_sys_c.cpp | 2 ++ test_regress/t/t_dpi_threads_c.cpp | 2 ++ test_regress/t/t_dpi_vams.cpp | 2 ++ test_regress/t/t_dpi_var.cpp | 2 ++ test_regress/t/t_embed1_c.cpp | 13 ++++------ test_regress/t/t_flag_ldflags_c.cpp | 2 ++ test_regress/t/t_leak.cpp | 15 ++++++------ test_regress/t/t_mem_multi_io2.cpp | 10 +++++--- test_regress/t/t_mem_slot.cpp | 4 +-- test_regress/t/t_protect_ids_c.cpp | 2 ++ test_regress/t/t_trace_cat.cpp | 2 +- test_regress/t/t_trace_public_func.cpp | 2 ++ test_regress/t/t_trace_public_sig.cpp | 2 ++ test_regress/t/t_trace_two_cc.cpp | 4 +++ test_regress/t/t_trace_two_sc.cpp | 2 ++ test_regress/t/t_vpi_time_cb.cpp | 4 +++ test_regress/t/t_vpi_zero_time_cb.cpp | 4 +++ 35 files changed, 109 insertions(+), 39 deletions(-) diff --git a/Makefile.in b/Makefile.in index 93d3ef247..8b89d5d1e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -462,11 +462,12 @@ analyzer-include: CLANGFORMAT = clang-format CLANGFORMAT_FLAGS = -i +CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* clang-format: @$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \ || echo "*** You are not using clang-format 10.0, indents may differ from master's ***" - $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) + $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES) ftp: info diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index a51d3aef4..a5c346d8f 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -13,6 +13,7 @@ #include #include +// clang-format off #if defined(NCSC) // Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, // rather than the IEEE 1800-2005 version which has _.a and _.b fields. @@ -46,6 +47,7 @@ typedef uint64_t sv_longint_unsigned_t; #else # error "Unknown simulator for DPI test" #endif +// clang-format on //====================================================================== // Implementations of imported functions diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index 6f179d7e9..1593e1dfc 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -13,6 +13,7 @@ #include #include +// clang-format off #if defined(NCSC) // Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, // rather than the IEEE 1800-2005 version which has _.a and _.b fields. @@ -51,6 +52,7 @@ typedef uint64_t sv_longint_unsigned_t; #else # error "Unknown simulator for DPI test" #endif +// clang-format on //====================================================================== // Implementations of imported functions diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index 40161ed25..cf127ee6e 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -13,6 +13,7 @@ #include #include +// clang-format off #if defined(NCSC) // Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, // rather than the IEEE 1800-2005 version which has _.a and _.b fields. @@ -46,6 +47,7 @@ typedef uint64_t sv_longint_unsigned_t; # else # error "Unknown simulator for DPI test" #endif +// clang-format on //====================================================================== // Implementations of imported functions diff --git a/test_regress/t/t_dpi_context_c.cpp b/test_regress/t/t_dpi_context_c.cpp index 2d1a8fbe4..50534b8e9 100644 --- a/test_regress/t/t_dpi_context_c.cpp +++ b/test_regress/t/t_dpi_context_c.cpp @@ -14,6 +14,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # ifdef T_DPI_CONTEXT_NOOPT # include "Vt_dpi_context_noopt__Dpi.h" @@ -31,6 +32,7 @@ #ifdef VERILATOR # include "verilated.h" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { @@ -126,7 +128,7 @@ int dpic_restore() { unsigned dpic_getcontext() { svScope scope = svGetScope(); - printf("%%Info: svGetScope returned scope (%p) with name %s\n", + printf("%%Info: svGetScope returned scope (%p) with name %s\n", // scope, svGetNameFromScope(scope)); return (unsigned)(uintptr_t)scope; } diff --git a/test_regress/t/t_dpi_display_c.cpp b/test_regress/t/t_dpi_display_c.cpp index 0be29e589..41d292027 100644 --- a/test_regress/t/t_dpi_display_c.cpp +++ b/test_regress/t/t_dpi_display_c.cpp @@ -14,6 +14,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_display__Dpi.h" #elif defined(VCS) @@ -23,6 +24,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { @@ -31,12 +33,12 @@ extern void dpii_display_call(const char* c); } #endif +// clang-format off #ifndef VL_PRINTF # define VL_PRINTF printf #endif +// clang-format on //====================================================================== -void dpii_display_call(const char* c) { - VL_PRINTF("dpii_display_call: '%s'\n", c); -} +void dpii_display_call(const char* c) { VL_PRINTF("dpii_display_call: '%s'\n", c); } diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index e858de367..bcebfce0f 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -13,6 +13,7 @@ #include #include "svdpi.h" +// clang-format off #ifdef _WIN32 # define T_PRI64 "I64" #else // Linux or compliant Unix flavors @@ -34,6 +35,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS @@ -67,6 +69,7 @@ extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o); //====================================================================== +// clang-format off #define CHECK_RESULT(type, got, exp) \ if ((got) != (exp)) { \ printf("%%Error: %s:%d:", __FILE__, __LINE__); \ @@ -77,6 +80,7 @@ extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o); printf(" EXP = %" T_PRI64 "x\n", u.l); \ return __LINE__; \ } +// clang-format on #define CHECK_RESULT_NNULL(got) \ if (!(got)) { \ printf("%%Error: %s:%d: GOT = %p EXP = !NULL\n", __FILE__, __LINE__, (got)); \ @@ -107,9 +111,9 @@ int dpix_run_tests() { #ifdef VERILATOR static int didDump = 0; if (didDump++ == 0) { -# ifdef TEST_VERBOSE +#ifdef TEST_VERBOSE Verilated::internalsDump(); -# endif +#endif } #endif @@ -183,7 +187,9 @@ int dpix_run_tests() { CHECK_RESULT(svLogic, o, 0); } { - svLogicVecVal i[1]; i[0].aval = 0x12; i[0].bval = 0; + svLogicVecVal i[1]; + i[0].aval = 0x12; + i[0].bval = 0; svLogicVecVal o[1]; dpix_t_reg15(i, o); CHECK_RESULT(int, o[0].aval, (~i[0].aval) & 0x7fff); @@ -191,9 +197,12 @@ int dpix_run_tests() { } { svLogicVecVal i[3]; - i[0].aval = 0x72912312; i[0].bval = 0; - i[1].aval = 0xab782a12; i[1].bval = 0; - i[2].aval = 0x8a413bd9; i[2].bval = 0; + i[0].aval = 0x72912312; + i[0].bval = 0; + i[1].aval = 0xab782a12; + i[1].bval = 0; + i[2].aval = 0x8a413bd9; + i[2].bval = 0; svLogicVecVal o[3]; dpix_t_reg95(i, o); CHECK_RESULT(int, o[0].aval, ~i[0].aval); @@ -206,8 +215,10 @@ int dpix_run_tests() { #if !defined(VCS) && !defined(CADENCE) { svLogicVecVal i[2]; - i[0].aval = 0x72912312; i[0].bval = 0; - i[1].aval = 0xab782a12; i[1].bval = 0; + i[0].aval = 0x72912312; + i[0].bval = 0; + i[1].aval = 0xab782a12; + i[1].bval = 0; svLogicVecVal o[2]; dpix_t_time(i, o); CHECK_RESULT(int, o[0].aval, ~i[0].aval); diff --git a/test_regress/t/t_dpi_export_context_bad.cpp b/test_regress/t/t_dpi_export_context_bad.cpp index 86e6fcc1f..a42ceff51 100644 --- a/test_regress/t/t_dpi_export_context_bad.cpp +++ b/test_regress/t/t_dpi_export_context_bad.cpp @@ -11,6 +11,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_export_context_bad__Dpi.h" #elif defined(VCS) @@ -20,6 +21,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_imp_gen_c.cpp b/test_regress/t/t_dpi_imp_gen_c.cpp index f7a6b5d1a..15a03eea5 100644 --- a/test_regress/t/t_dpi_imp_gen_c.cpp +++ b/test_regress/t/t_dpi_imp_gen_c.cpp @@ -15,6 +15,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_imp_gen__Dpi.h" #elif defined(VCS) @@ -24,6 +25,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_import_c.cpp b/test_regress/t/t_dpi_import_c.cpp index e23a2a599..2771b70f1 100644 --- a/test_regress/t/t_dpi_import_c.cpp +++ b/test_regress/t/t_dpi_import_c.cpp @@ -15,6 +15,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_import__Dpi.h" #elif defined(VCS) @@ -24,6 +25,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on typedef struct { int a; diff --git a/test_regress/t/t_dpi_lib_c.cpp b/test_regress/t/t_dpi_lib_c.cpp index 04ad63bad..7113909ce 100644 --- a/test_regress/t/t_dpi_lib_c.cpp +++ b/test_regress/t/t_dpi_lib_c.cpp @@ -16,6 +16,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_lib__Dpi.h" #elif defined(VCS) @@ -25,6 +26,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_open_c.cpp b/test_regress/t/t_dpi_open_c.cpp index 806555f74..b4aa42c56 100644 --- a/test_regress/t/t_dpi_open_c.cpp +++ b/test_regress/t/t_dpi_open_c.cpp @@ -16,6 +16,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_open__Dpi.h" #elif defined(VCS) @@ -27,6 +28,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { @@ -90,11 +92,13 @@ extern int dpii_failure(); int failure = 0; int dpii_failure() { return failure; } +// clang-format off #ifdef _WIN32 # define T_PRI64 "I64" #else // Linux or compliant Unix flavors # define T_PRI64 "ll" #endif +// clang-format on #define CHECK_RESULT_HEX(got, exp) \ do { \ diff --git a/test_regress/t/t_dpi_open_query.cpp b/test_regress/t/t_dpi_open_query.cpp index 21f7eab1c..021e6ef53 100644 --- a/test_regress/t/t_dpi_open_query.cpp +++ b/test_regress/t/t_dpi_open_query.cpp @@ -9,10 +9,9 @@ // //************************************************************************* -// clang-format off - #include "svdpi.h" +// clang-format off #if defined(VERILATOR) // Verilator # include "Vt_dpi_open_query__Dpi.h" #elif defined(VCS) // VCS @@ -24,7 +23,6 @@ #else # error "Unknown simulator for DPI test" #endif - // clang-format on //====================================================================== diff --git a/test_regress/t/t_dpi_openfirst_c.cpp b/test_regress/t/t_dpi_openfirst_c.cpp index 0a18aa736..3b60a4129 100644 --- a/test_regress/t/t_dpi_openfirst_c.cpp +++ b/test_regress/t/t_dpi_openfirst_c.cpp @@ -16,6 +16,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_openfirst__Dpi.h" #elif defined(VCS) @@ -25,6 +26,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_qw_c.cpp b/test_regress/t/t_dpi_qw_c.cpp index 802f87991..01a927848 100644 --- a/test_regress/t/t_dpi_qw_c.cpp +++ b/test_regress/t/t_dpi_qw_c.cpp @@ -23,6 +23,7 @@ void poke_value(int i) { printf("poke_value(%d)\n", i); +// clang-format off #ifdef VERILATOR static int didDump = 0; if (didDump++ == 0) { @@ -31,6 +32,7 @@ void poke_value(int i) { # endif } #endif + // clang-format on svScope scope = svGetScopeFromName("top.t.a"); if (scope == NULL) { diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp index 1ecbf0d94..21ea9e772 100644 --- a/test_regress/t/t_dpi_result_type.cpp +++ b/test_regress/t/t_dpi_result_type.cpp @@ -15,6 +15,7 @@ #include "svdpi.h" +// clang-format off #if defined(VERILATOR) // Verilator # include "Vt_dpi_result_type__Dpi.h" typedef long long sv_longint_t; @@ -41,6 +42,7 @@ typedef uint64_t sv_longint_unsigned_t; #else # error "Unknown simulator for DPI test" #endif +// clang-format on //====================================================================== // Implementations of imported functions diff --git a/test_regress/t/t_dpi_shortcircuit_c.cpp b/test_regress/t/t_dpi_shortcircuit_c.cpp index 211231a8a..dad4af8aa 100644 --- a/test_regress/t/t_dpi_shortcircuit_c.cpp +++ b/test_regress/t/t_dpi_shortcircuit_c.cpp @@ -15,6 +15,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # if defined(T_DPI_SHORTCIRCUIT) # include "Vt_dpi_shortcircuit__Dpi.h" @@ -30,6 +31,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index b357c65b6..ba6583d79 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -15,6 +15,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_string__Dpi.h" #elif defined(VCS) @@ -24,6 +25,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_sys_c.cpp b/test_regress/t/t_dpi_sys_c.cpp index 6e904fad1..156609f16 100644 --- a/test_regress/t/t_dpi_sys_c.cpp +++ b/test_regress/t/t_dpi_sys_c.cpp @@ -14,6 +14,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_sys__Dpi.h" #elif defined(VCS) @@ -23,6 +24,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_threads_c.cpp b/test_regress/t/t_dpi_threads_c.cpp index 3f06f2d64..0b2900352 100644 --- a/test_regress/t/t_dpi_threads_c.cpp +++ b/test_regress/t/t_dpi_threads_c.cpp @@ -17,6 +17,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # ifdef T_DPI_THREADS_COLLIDE # include "Vt_dpi_threads_collide__Dpi.h" @@ -30,6 +31,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_vams.cpp b/test_regress/t/t_dpi_vams.cpp index 0abce4a58..4722f8636 100644 --- a/test_regress/t/t_dpi_vams.cpp +++ b/test_regress/t/t_dpi_vams.cpp @@ -11,6 +11,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_dpi_vams__Dpi.h" #elif defined(VCS) @@ -20,6 +21,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #ifdef NEED_EXTERNS extern "C" { diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index dad42dcc1..bbab2e36c 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -120,11 +120,13 @@ int main(int argc, char** argv, char** env) { VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out +// clang-format off #ifdef VERILATOR # ifdef TEST_VERBOSE Verilated::scopesDump(); # endif #endif + // clang-format on topp->eval(); topp->clk = 0; diff --git a/test_regress/t/t_embed1_c.cpp b/test_regress/t/t_embed1_c.cpp index 78ae95cb0..51ffbe375 100644 --- a/test_regress/t/t_embed1_c.cpp +++ b/test_regress/t/t_embed1_c.cpp @@ -16,6 +16,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_embed1__Dpi.h" #elif defined(VCS) @@ -25,6 +26,7 @@ #else # error "Unknown simulator for DPI test" #endif +// clang-format on #include "verilated.h" @@ -80,14 +82,9 @@ void t_embed_child_eval() { __modelp->eval(); } -void t_embed_child_io_eval(unsigned char clk, - unsigned char bit_in, - const svBitVecVal* vec_in, - const svBitVecVal* wide_in, - unsigned char is_ref, - unsigned char* bit_out, - svBitVecVal* vec_out, - svBitVecVal* wide_out, +void t_embed_child_io_eval(unsigned char clk, unsigned char bit_in, const svBitVecVal* vec_in, + const svBitVecVal* wide_in, unsigned char is_ref, + unsigned char* bit_out, svBitVecVal* vec_out, svBitVecVal* wide_out, unsigned char* did_init_out) { VL_DEBUG_IF(VL_PRINTF(" t_embed1_child_io_eval\n");); Vt_embed1_child* __modelp = __get_modelp(); diff --git a/test_regress/t/t_flag_ldflags_c.cpp b/test_regress/t/t_flag_ldflags_c.cpp index fa62acc3f..6b32be9b9 100644 --- a/test_regress/t/t_flag_ldflags_c.cpp +++ b/test_regress/t/t_flag_ldflags_c.cpp @@ -14,6 +14,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # include "Vt_flag_ldflags__Dpi.h" #else @@ -28,5 +29,6 @@ #ifndef CFLAGS2_FROM_CMDLINE # error "CFLAGS2_FROM_CMDLINE not set - not passed down?" #endif +// clang-format on void dpii_c_library() {} diff --git a/test_regress/t/t_leak.cpp b/test_regress/t/t_leak.cpp index 6bb6cfe28..8553bfccd 100644 --- a/test_regress/t/t_leak.cpp +++ b/test_regress/t/t_leak.cpp @@ -30,13 +30,12 @@ long long get_memory_usage() { int ps_ign; vluint64_t ps_vsize, ps_rss; - int items = fscanf(fp, ("%d (%*[^) ]) %*1s %d %*d %*d %*d %*d %u" - " %u %u %u %u %d %d %d %d" - " %*d %*d %*u %*u %d %" VL_PRI64 "u %" VL_PRI64 "u "), - &ps_ign, &ps_ign, &ps_ign, - &ps_ign, &ps_ign, &ps_ign, &ps_ign, - &ps_ign, &ps_ign, &ps_ign, &ps_ign, - &ps_ign, &ps_vsize, &ps_rss); + int items = fscanf(fp, + ("%d (%*[^) ]) %*1s %d %*d %*d %*d %*d %u" + " %u %u %u %u %d %d %d %d" + " %*d %*d %*u %*u %d %" VL_PRI64 "u %" VL_PRI64 "u "), + &ps_ign, &ps_ign, &ps_ign, &ps_ign, &ps_ign, &ps_ign, &ps_ign, &ps_ign, + &ps_ign, &ps_ign, &ps_ign, &ps_ign, &ps_vsize, &ps_rss); fclose(fp); if (items >= 14) { return ps_vsize; @@ -79,7 +78,7 @@ int main(int argc, char* argv[]) { } vluint64_t leaked = get_memory_usage() - firstUsage; - if (leaked > 64*1024) { // Have to allow some slop for this code. + if (leaked > 64 * 1024) { // Have to allow some slop for this code. printf("Leaked %" VL_PRI64 "d bytes, or ~ %" VL_PRI64 "d bytes/construt\n", // leaked, leaked / loops); vl_fatal(__FILE__, __LINE__, "top", "Leaked memory\n"); diff --git a/test_regress/t/t_mem_multi_io2.cpp b/test_regress/t/t_mem_multi_io2.cpp index c12e8330a..145b02ba3 100644 --- a/test_regress/t/t_mem_multi_io2.cpp +++ b/test_regress/t/t_mem_multi_io2.cpp @@ -48,15 +48,17 @@ int main() #endif // loop through every possibility and check the result +// clang-format off #ifdef SYSTEMC_VERSION sc_start(1, SC_NS); -# define ASSIGN(s,v) s.write(v) -# define READ(s) s.read() +# define ASSIGN(s, v) s.write(v) +# define READ(s) s.read() #else tb->eval(); -# define ASSIGN(s,v) tb->s = (v) -# define READ(s) tb->s +# define ASSIGN(s, v) tb->s = (v) +# define READ(s) tb->s #endif + // clang-format on ASSIGN(i3, 13); for (int i = 0; i < 4; i++) { diff --git a/test_regress/t/t_mem_slot.cpp b/test_regress/t/t_mem_slot.cpp index 7d367925e..86d3b984e 100644 --- a/test_regress/t/t_mem_slot.cpp +++ b/test_regress/t/t_mem_slot.cpp @@ -46,9 +46,9 @@ int main(int argc, char* argv[]) { Verilated::debug(0); - /* clear all bits in the array */ + // clear all bits in the array for (slot = 0; slot < 3; slot++) - for (bit = 0; bit < 2; bit++) + for (bit = 0; bit < 2; bit++) // StepSim(sim, slot, bit, 0, 0); printf("\nTesting\n"); diff --git a/test_regress/t/t_protect_ids_c.cpp b/test_regress/t/t_protect_ids_c.cpp index 36198253e..484ba07b8 100644 --- a/test_regress/t/t_protect_ids_c.cpp +++ b/test_regress/t/t_protect_ids_c.cpp @@ -15,6 +15,7 @@ //====================================================================== +// clang-format off #if defined(VERILATOR) # ifdef T_PROTECT_IDS_KEY # include "Vt_protect_ids_key__Dpi.h" @@ -32,6 +33,7 @@ #ifdef NEED_EXTERNS # error "Not supported" #endif +// clang-format on //====================================================================== diff --git a/test_regress/t/t_trace_cat.cpp b/test_regress/t/t_trace_cat.cpp index f1f5aed79..b4a9c6125 100644 --- a/test_regress/t/t_trace_cat.cpp +++ b/test_regress/t/t_trace_cat.cpp @@ -50,7 +50,7 @@ int main(int argc, char** argv, char** env) { top->trace(tfp, 99); tfp->open(trace_name()); #else -# error "Unknown test" +#error "Unknown test" #endif } tfp->dump((unsigned int)(main_time)); diff --git a/test_regress/t/t_trace_public_func.cpp b/test_regress/t/t_trace_public_func.cpp index 8f4de6e76..c43a13dbc 100644 --- a/test_regress/t/t_trace_public_func.cpp +++ b/test_regress/t/t_trace_public_func.cpp @@ -9,6 +9,7 @@ #include #include +// clang-format off #include VM_PREFIX_INCLUDE #ifdef T_TRACE_PUBLIC_FUNC_VLT # include "Vt_trace_public_func_vlt_t.h" @@ -17,6 +18,7 @@ # include "Vt_trace_public_func_t.h" # include "Vt_trace_public_func_glbl.h" #endif +// clang-format on unsigned long long main_time = 0; double sc_time_stamp() { return (double)main_time; } diff --git a/test_regress/t/t_trace_public_sig.cpp b/test_regress/t/t_trace_public_sig.cpp index 7733c2eca..2c996203f 100644 --- a/test_regress/t/t_trace_public_sig.cpp +++ b/test_regress/t/t_trace_public_sig.cpp @@ -9,6 +9,7 @@ #include #include +// clang-format off #include VM_PREFIX_INCLUDE #ifdef T_TRACE_PUBLIC_SIG_VLT # include "Vt_trace_public_sig_vlt_t.h" @@ -17,6 +18,7 @@ # include "Vt_trace_public_sig_t.h" # include "Vt_trace_public_sig_glbl.h" #endif +// clang-format on unsigned long long main_time = 0; double sc_time_stamp() { return (double)main_time; } diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index e339c6a24..3cfd0ef46 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -6,6 +6,7 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// clang-format off #include "verilatedos.h" #include VM_PREFIX_INCLUDE #include "Vt_trace_two_b.h" @@ -17,6 +18,7 @@ # include "verilated_vcd_c.h" # endif #endif +// clang-format on // Compile in place #include "Vt_trace_two_b.cpp" @@ -39,6 +41,7 @@ int main(int argc, char** argv, char** env) { ap = new VM_PREFIX("topa"); bp = new Vt_trace_two_b("topb"); +// clang-format off #ifdef TEST_HDR_TRACE Verilated::traceEverOn(true); # ifdef TEST_FST @@ -53,6 +56,7 @@ int main(int argc, char** argv, char** env) { tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); # endif #endif + // clang-format on #ifdef TEST_HDR_TRACE ap->eval_step(); diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_sc.cpp index 66e145145..ebfffc68d 100644 --- a/test_regress/t/t_trace_two_sc.cpp +++ b/test_regress/t/t_trace_two_sc.cpp @@ -6,6 +6,7 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// clang-format off #include "verilatedos.h" #include VM_PREFIX_INCLUDE #include "Vt_trace_two_b.h" @@ -13,6 +14,7 @@ #ifdef TEST_HDR_TRACE # include "verilated_vcd_sc.h" #endif +// clang-format on // Compile in place #include "Vt_trace_two_b.cpp" diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index c0a170ac2..210abb609 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -167,7 +167,9 @@ static int _end_of_sim_cb(p_cb_data cb_data) { extern "C" #endif + // clang-format off void vpi_compat_bootstrap(void) { + // clang-format on t_cb_data cb_data; bzero(&cb_data, sizeof(cb_data)); @@ -197,11 +199,13 @@ int main(int argc, char** argv, char** env) { VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out +// clang-format off #ifdef VERILATOR # ifdef TEST_VERBOSE Verilated::scopesDump(); # endif #endif + // clang-format on #if VM_TRACE Verilated::traceEverOn(true); diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index a553bec45..54303e04f 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -117,7 +117,9 @@ static int _end_of_sim_cb(p_cb_data cb_data) { extern "C" #endif + // clang-format off void vpi_compat_bootstrap(void) { + // clang-format on t_cb_data cb_data; bzero(&cb_data, sizeof(cb_data)); @@ -147,11 +149,13 @@ int main(int argc, char** argv, char** env) { VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out +// clang-format off #ifdef VERILATOR # ifdef TEST_VERBOSE Verilated::scopesDump(); # endif #endif + // clang-format on #if VM_TRACE Verilated::traceEverOn(true); From 5c070558aebcb70bbcf5ce635bf7ba73f0fe746e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 29 Oct 2020 21:27:19 -0400 Subject: [PATCH 34/88] Internals: Misc cleanups in prep for interface bugfix. No functional change intended. --- src/V3Inst.cpp | 3 +-- src/V3LinkDot.cpp | 26 ++++++++++---------------- src/V3Param.cpp | 18 +++++++----------- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 6c4c1922f..4a7a9040f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -278,8 +278,7 @@ private: = VN_CAST(arrdtype->subDTypep(), IfaceRefDType); origIfaceRefp->cellp(nullptr); AstVar* varNewp = ifaceVarp->cloneTree(false); - AstIfaceRefDType* ifaceRefp - = VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false); + AstIfaceRefDType* ifaceRefp = origIfaceRefp->cloneTree(false); arrdtype->addNextHere(ifaceRefp); ifaceRefp->cellp(newp); ifaceRefp->cellName(newp->name()); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index b1bb00978..822a43692 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -108,12 +108,6 @@ public: return varp->isParam(); } }; -class LinkNodeMatcherVarOrScope : public VNodeMatcher { -public: - virtual bool nodeMatch(const AstNode* nodep) const override { - return VN_IS(nodep, Var) || VN_IS(nodep, Scope); - } -}; //###################################################################### // LinkDot state, as a visitor of each AstNode @@ -1718,7 +1712,7 @@ private: VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup AstDot* m_dotp; // Current dot bool m_unresolved; // Unresolved, needs help from V3Param - AstNode* m_unlinkedScope; // Unresolved scope, needs corresponding VarXRef + AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef bool m_dotErr; // Error found in dotted resolution, ignore upwards string m_dotText; // String of dotted names found in below parseref DotStates() { init(nullptr); } @@ -1730,7 +1724,7 @@ private: m_dotErr = false; m_dotText = ""; m_unresolved = false; - m_unlinkedScope = nullptr; + m_unlinkedScopep = nullptr; } string ascii() const { static const char* const names[] = {"NONE", "PACKAGE", "SCOPE", "FINAL", "MEMBER"}; @@ -1983,7 +1977,7 @@ private: } if (m_ds.m_unresolved && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { - m_ds.m_unlinkedScope = nodep->lhsp(); + m_ds.m_unlinkedScopep = nodep->lhsp(); } if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a @@ -2173,19 +2167,19 @@ private: varp->attrSplitVar(false); } m_ds.m_dotText = ""; - if (m_ds.m_unresolved && m_ds.m_unlinkedScope) { + if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) { string dotted = refp->dotted(); size_t pos = dotted.find("__BRA__??__KET__"); // Arrays of interfaces all have the same parameters if (pos != string::npos && varp->isParam() - && VN_IS(m_ds.m_unlinkedScope, CellArrayRef)) { + && VN_IS(m_ds.m_unlinkedScopep, CellArrayRef)) { refp->dotted(dotted.substr(0, pos)); newp = refp; } else { newp = new AstUnlinkedRef(nodep->fileline(), VN_CAST(refp, VarXRef), refp->name(), - m_ds.m_unlinkedScope->unlinkFrBack()); - m_ds.m_unlinkedScope = nullptr; + m_ds.m_unlinkedScopep->unlinkFrBack()); + m_ds.m_unlinkedScopep = nullptr; m_ds.m_unresolved = false; } } else { @@ -2439,12 +2433,12 @@ private: m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { - if (m_ds.m_unresolved && m_ds.m_unlinkedScope) { + if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) { AstNodeFTaskRef* newftaskp = nodep->cloneTree(false); newftaskp->dotted(m_ds.m_dotText); AstNode* newp = new AstUnlinkedRef(nodep->fileline(), newftaskp, nodep->name(), - m_ds.m_unlinkedScope->unlinkFrBack()); - m_ds.m_unlinkedScope = nullptr; + m_ds.m_unlinkedScopep->unlinkFrBack()); + m_ds.m_unlinkedScopep = nullptr; m_ds.m_unresolved = false; nodep->replaceWith(newp); return; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index bc21b11f8..7c384c685 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -892,10 +892,13 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { AstIfaceRefDType* pinIrefp = nullptr; AstNode* exprp = pinp->exprp(); - if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp() - && VN_CAST(exprp, VarRef)->varp()->subDTypep() - && VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) { - pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType); + AstVar* varp + = (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr; + if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) { + pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType); + } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep()) + && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) { + pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType); } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) && VN_CAST(exprp->op1p(), VarRef)->varp() && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() @@ -906,13 +909,6 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { pinIrefp = VN_CAST( arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), IfaceRefDType); - } else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp() - && VN_CAST(exprp, VarRef)->varp()->subDTypep() - && arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()) - && VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()), - IfaceRefDType)) { - pinIrefp = VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()), - IfaceRefDType); } UINFO(9, " portIfaceRef " << portIrefp << endl); From 0c949ceba22def53f41852900d255b61af7943c6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 30 Oct 2020 08:43:20 -0400 Subject: [PATCH 35/88] Internals: classOrPackage is a module, from #2615. --- src/V3AstNodes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 3630f88ed..ca16cf88f 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2965,7 +2965,7 @@ public: virtual V3Hash sameHash() const override { return V3Hash(m_classOrPackagep); } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name - AstNode* classOrPackagep() const { return m_classOrPackagep; } + AstNodeModule* classOrPackagep() const { return VN_CAST(m_classOrPackagep, NodeModule); } AstPackage* packagep() const { return VN_CAST(classOrPackagep(), Package); } void classOrPackagep(AstNode* nodep) { m_classOrPackagep = nodep; } AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } From 51b0963e61d837b117e020dfcb07d0ce5069880c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 30 Oct 2020 18:00:40 -0400 Subject: [PATCH 36/88] Internals: Favor const for map keys. No functional change intended. --- include/verilated_cov.cpp | 4 ++-- include/verilated_heavy.h | 3 +-- include/verilated_vcd_c.h | 2 +- src/V3Ast.h | 2 +- src/V3AstNodes.h | 2 +- src/V3CUse.cpp | 2 +- src/V3Config.cpp | 2 +- src/V3Delayed.cpp | 4 ++-- src/V3EmitC.cpp | 2 +- src/V3EmitCSyms.cpp | 44 +++++++++++++++++++-------------------- src/V3File.cpp | 4 ++-- src/V3FileLine.h | 2 +- src/V3Graph.cpp | 2 +- src/V3Hashed.cpp | 5 ++--- src/V3Inst.cpp | 2 +- src/V3LanguageWords.h | 2 +- src/V3LifePost.cpp | 5 ++--- src/V3LinkParse.cpp | 2 +- src/V3Options.cpp | 9 +++----- src/V3Options.h | 10 ++++----- src/V3Param.cpp | 14 ++++++------- src/V3PreProc.cpp | 4 ++-- src/V3Simulate.h | 2 +- src/V3Stats.cpp | 2 +- src/V3Table.cpp | 2 +- src/V3Task.cpp | 6 +++--- src/V3Trace.cpp | 4 ++-- src/V3Width.cpp | 6 +++--- src/VlcPoint.h | 2 +- src/VlcSource.h | 2 +- 30 files changed, 73 insertions(+), 81 deletions(-) diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index df46d5d37..753e550cb 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -90,7 +90,7 @@ public: class VerilatedCovImp : VerilatedCovImpBase { private: // TYPES - typedef std::map ValueIndexMap; + typedef std::map ValueIndexMap; typedef std::map IndexValueMap; typedef std::deque ItemList; @@ -350,7 +350,7 @@ public: os << "# SystemC::Coverage-3\n"; // Build list of events; totalize if collapsing hierarchy - typedef std::map> EventMap; + typedef std::map> EventMap; EventMap eventCounts; for (const auto& itemp : m_items) { std::string name; diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 3d4795de0..43da92fc2 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -181,8 +181,7 @@ public: T_Value& at(const T_Key& index) { const auto it = m_map.find(index); if (it == m_map.end()) { - std::pair pit - = m_map.insert(std::make_pair(index, m_defaultValue)); + const auto pit = m_map.insert(std::make_pair(index, m_defaultValue)); return pit.first->second; } return it->second; diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 63b34ec55..e5e1b334a 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -76,7 +76,7 @@ private: std::vector m_suffixes; ///< VCD line end string codes + metadata const char* m_suffixesp; ///< Pointer to first element of above - typedef std::map NameMap; + typedef std::map NameMap; NameMap* m_namemapp = nullptr; ///< List of names for the header void bufferResize(vluint64_t minsize); diff --git a/src/V3Ast.h b/src/V3Ast.h index 47395909c..6ae97f107 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2453,7 +2453,7 @@ class AstNodeUOrStructDType : public AstNodeDType { // A struct or union; common handling private: // TYPES - typedef std::map MemberNameMap; + typedef std::map MemberNameMap; // MEMBERS string m_name; // Name from upper typedef, if any bool m_packed; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index ca16cf88f..34b3af025 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -300,7 +300,7 @@ public: class AstClass : public AstNodeModule { // TYPES - typedef std::map MemberNameMap; + typedef std::map MemberNameMap; // MEMBERS MemberNameMap m_members; // Members or method children AstClassPackage* m_packagep = nullptr; // Class package this is under diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 3c02364a1..88c1cbe20 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -41,7 +41,7 @@ private: // MEMBERS AstNodeModule* m_modInsertp; // Current module to insert AstCUse under typedef std::pair UseString; - std::map m_didUse; // What we already used + std::map m_didUse; // What we already used // NODE STATE // Entire netlist: diff --git a/src/V3Config.cpp b/src/V3Config.cpp index a1e12f5f0..d36880697 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -33,7 +33,7 @@ // cache of resolved entities. Entities stored in this container need an update // function that takes a reference of this type to join multiple entities into one. template class V3ConfigWildcardResolver { - typedef std::map Map; + typedef std::map Map; Map m_mapWildcard; // Wildcard strings to entities Map m_mapResolved; // Resolved strings to converged entities diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index c042968f9..fdd23ec39 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -95,10 +95,10 @@ private: bool m_inDly = false; // True in delayed assignments bool m_inLoop = false; // True in for loops bool m_inInitial = false; // True in initial blocks - typedef std::map, AstVar*> VarMap; + typedef std::map, AstVar*> VarMap; VarMap m_modVarMap; // Table of new var names created under module VDouble0 m_statSharedSet; // Statistic tracking - typedef std::map ScopeVecMap; + typedef std::map ScopeVecMap; ScopeVecMap m_scopeVecMap; // Next var number for each scope // METHODS diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index c07416528..243c3314b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2874,7 +2874,7 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) { } // MacroTask mode. Sort by MTask-affinity group first, size second. - typedef std::map MTaskVarSortMap; + typedef std::map MTaskVarSortMap; MTaskVarSortMap m2v; for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) { int size_class = it->first; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 9193c8a9c..de4bb2e43 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -71,13 +71,13 @@ class EmitCSyms : EmitCBaseVisitor { , m_modp{modp} , m_scopep{scopep} {} }; - typedef std::map ScopeFuncs; - typedef std::map ScopeVars; - typedef std::map ScopeNames; + typedef std::map ScopeFuncs; + typedef std::map ScopeVars; + typedef std::map ScopeNames; typedef std::pair ScopeModPair; typedef std::pair ModVarPair; typedef std::vector ScopeNameList; - typedef std::map ScopeNameHierarchy; + typedef std::map ScopeNameHierarchy; struct CmpName { inline bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { return lhsp.first->name() < rhsp.first->name(); @@ -395,7 +395,7 @@ void EmitCSyms::emitSymHdr() { if (v3Global.dpi()) { puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n"); - std::map types; // Remove duplicates and sort + std::map types; // Remove duplicates and sort for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstCFunc* funcp = it->second.m_funcp; if (funcp->dpiExport()) { @@ -403,9 +403,7 @@ void EmitCSyms::emitSymHdr() { types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1; } } - for (std::map::iterator it = types.begin(); it != types.end(); ++it) { - puts(it->first); - } + for (const auto& i : types) puts(i.first); } puts("\n// SYMS CLASS\n"); @@ -432,9 +430,9 @@ void EmitCSyms::emitSymHdr() { puts("bool __Vm_didInit;\n"); puts("\n// SUBCELL STATE\n"); - for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; - AstNodeModule* modp = it->second; + for (const auto& i : m_scopes) { + AstScope* scopep = i.first; + AstNodeModule* modp = i.second; if (VN_IS(modp, Class)) continue; if (modp->isTop()) { ofp()->printf("%-30s ", (prefixNameProtect(modp) + "*").c_str()); @@ -469,9 +467,9 @@ void EmitCSyms::emitSymHdr() { puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n"); puts(string("~") + symClassName() + "() {}\n"); - for (std::map::iterator it = m_usesVfinal.begin(); it != m_usesVfinal.end(); ++it) { - puts("void " + symClassName() + "_" + cvtToStr(it->first) + "("); - if (it->second) { + for (const auto& i : m_usesVfinal) { + puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); + if (i.second) { puts("int __Vfinal"); } else { puts(topClassName() + "* topp"); @@ -619,9 +617,9 @@ void EmitCSyms::emitSymImp() { puts(" , __Vm_didInit(false)\n"); puts(" // Setup submodule names\n"); char comma = ','; - for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; - AstNodeModule* modp = it->second; + for (const auto& i : m_scopes) { + AstScope* scopep = i.first; + AstNodeModule* modp = i.second; if (modp->isTop()) { } else { puts(string(" ") + comma + " " + protect(scopep->nameDotless())); @@ -638,9 +636,9 @@ void EmitCSyms::emitSymImp() { puts("// Pointer to top level\n"); puts("TOPp = topp;\n"); puts("// Setup each module's pointers to their submodules\n"); - for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; - AstNodeModule* modp = it->second; + for (const auto& i : m_scopes) { + AstScope* scopep = i.first; + AstNodeModule* modp = i.second; if (!modp->isTop()) { checkSplit(false); string arrow = scopep->name(); @@ -656,9 +654,9 @@ void EmitCSyms::emitSymImp() { puts("// Setup each module's pointer back to symbol table (for public functions)\n"); puts("TOPp->" + protect("__Vconfigure") + "(this, true);\n"); - for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) { - AstScope* scopep = it->first; - AstNodeModule* modp = it->second; + for (const auto& i : m_scopes) { + AstScope* scopep = i.first; + AstNodeModule* modp = i.second; if (!modp->isTop()) { checkSplit(false); // first is used by AstCoverDecl's call to __vlCoverInsert diff --git a/src/V3File.cpp b/src/V3File.cpp index 4f5607494..465458a72 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -331,7 +331,7 @@ void V3File::createMakeDir() { // VInFilterImp class VInFilterImp { - typedef std::map FileContentsMap; + typedef std::map FileContentsMap; typedef VInFilter::StrList StrList; FileContentsMap m_contentsMap; // Cache of file contents @@ -954,7 +954,7 @@ void V3OutCFile::putsGuard() { class VIdProtectImp { // MEMBERS - typedef std::map IdMap; + typedef std::map IdMap; IdMap m_nameMap; // Map of old name into new name typedef std::unordered_set IdSet; IdSet m_newIdSet; // Which new names exist diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 85aa5500a..757a4275c 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -39,7 +39,7 @@ class FileLine; //! source file (each with its own unique filename number). class FileLineSingleton { // TYPES - typedef std::map FileNameNumMap; + typedef std::map FileNameNumMap; // MEMBERS FileNameNumMap m_namemap; // filenameno for each filename std::deque m_names; // filename text for each filenameno diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 2ee8c5c9b..8001d55b6 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -335,7 +335,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { // We use a map here, as we don't want to corrupt anything (userp) in the graph, // and we don't care if this is slow. - std::map numMap; + std::map numMap; // Print vertices int n = 0; diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp index 9196a808d..22758e288 100644 --- a/src/V3Hashed.cpp +++ b/src/V3Hashed.cpp @@ -174,9 +174,8 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { } *logp << "\n*** STATS:\n" << endl; *logp << " #InBucket Occurrences\n"; - for (std::map::iterator it = dist.begin(); it != dist.end(); ++it) { - *logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second - << endl; + for (const auto& i : dist) { + *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << endl; } *logp << "\n*** Dump:\n" << endl; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 4a7a9040f..a7dc03ee8 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -141,7 +141,7 @@ class InstDeModVarVisitor : public AstNVisitor { // Expand all module variables, and save names for later reference private: // STATE - typedef std::map VarNameMap; + typedef std::map VarNameMap; VarNameMap m_modVarNameMap; // Per module, name of cloned variables VL_DEBUG_FUNC; // Declare debug() diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h index 907095605..3764f2dce 100644 --- a/src/V3LanguageWords.h +++ b/src/V3LanguageWords.h @@ -27,7 +27,7 @@ class V3LanguageWords { // List of common reserved keywords private: - typedef std::map KeywordMap; + typedef std::map KeywordMap; struct Singleton { KeywordMap s_kwdMap; // List of keywords, and what language applies Singleton() { init(); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index c3ba15bbd..f7fd88a83 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -183,9 +183,8 @@ private: return true; } if (before(assignPostLoc, loc)) return true; - for (std::set::iterator it = dlyVarAssigns.begin(); - it != dlyVarAssigns.end(); ++it) { - if (!before(loc, *it)) return false; + for (const auto& i : dlyVarAssigns) { + if (!before(loc, i)) return false; } return true; } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index b5595a81c..ebdc38cac 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -44,7 +44,7 @@ private: AstUser2InUse m_inuser2; // TYPES - typedef std::map, AstTypedef*> ImplTypedefMap; + typedef std::map, AstTypedef*> ImplTypedefMap; typedef std::set FileLineSet; // STATE diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 9caff20c6..328554e75 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -53,7 +53,7 @@ class V3OptionsImp { public: // TYPES - typedef std::map> DirMap; // Directory listing + typedef std::map> DirMap; // Directory listing // STATE std::list m_allArgs; // List of every argument encountered @@ -61,7 +61,7 @@ public: std::set m_incDirUserSet; // Include directories (for removing duplicates) std::list m_incDirFallbacks; // Include directories (ordered) std::set m_incDirFallbackSet; // Include directories (for removing duplicates) - std::map m_langExts; // Language extension map + std::map m_langExts; // Language extension map std::list m_libExtVs; // Library extensions (ordered) std::set m_libExtVSet; // Library extensions (for removing duplicates) DirMap m_dirMap; // Directory listing @@ -346,10 +346,7 @@ void V3Options::checkParameters() { if (!m_parameters.empty()) { std::stringstream msg; msg << "Parameters from the command line were not found in the design:"; - for (std::map::iterator it = m_parameters.begin(); - it != m_parameters.end(); ++it) { - msg << " " << it->first; - } + for (const auto& i : m_parameters) msg << " " << i.first; v3error(msg.str()); } } diff --git a/src/V3Options.h b/src/V3Options.h index f5d21aac3..215fc85de 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -201,7 +201,7 @@ typedef std::set V3StringSet; class V3HierarchicalBlockOption { public: // key:parameter name, value:value (as string) - typedef std::map ParamStrMap; + typedef std::map ParamStrMap; private: string m_origName; // module name @@ -218,7 +218,7 @@ public: const ParamStrMap params() const { return m_parameters; } }; -typedef std::map V3HierBlockOptSet; +typedef std::map V3HierBlockOptSet; //###################################################################### // V3Options - Command line options @@ -227,7 +227,7 @@ class V3Options { public: private: // TYPES - typedef std::map DebugSrcMap; + typedef std::map DebugSrcMap; // MEMBERS (general options) V3OptionsImp* m_impp; // Slow hidden options @@ -245,8 +245,8 @@ private: V3StringList m_forceIncs; // argument: -FI DebugSrcMap m_debugSrcs; // argument: --debugi-= DebugSrcMap m_dumpTrees; // argument: --dump-treei-= - std::map m_parameters; // Parameters - std::map m_hierBlocks; // main switch: --hierarchical-block + std::map m_parameters; // Parameters + std::map m_hierBlocks; // main switch: --hierarchical-block bool m_preprocOnly = false; // main switch: -E bool m_makePhony = false; // main switch: -MP diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 7c384c685..e8ae9d7a0 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -68,8 +68,8 @@ class ParameterizedHierBlocks { typedef std::multimap HierBlockOptsByOrigName; typedef HierBlockOptsByOrigName::const_iterator HierMapIt; - typedef std::map HierBlockModMap; - typedef std::map ParamConstMap; + typedef std::map HierBlockModMap; + typedef std::map ParamConstMap; typedef std::map ParamsMap; // MEMBERS @@ -218,17 +218,17 @@ private: typedef std::deque> IfaceRefRefs; // STATE - typedef std::map CloneMap; + typedef std::map CloneMap; struct ModInfo { AstNodeModule* m_modp; // Module with specified name CloneMap m_cloneMap; // Map of old-varp -> new cloned varp explicit ModInfo(AstNodeModule* modp) : m_modp{modp} {} }; - typedef std::map ModNameMap; + typedef std::map ModNameMap; ModNameMap m_modNameMap; // Hash of created module flavors by name - typedef std::map LongMap; + typedef std::map LongMap; LongMap m_longMap; // Hash of very long names to unique identity number int m_longId = 0; @@ -237,7 +237,7 @@ private: V3StringSet m_allModuleNames; typedef std::pair ValueMapValue; - typedef std::map ValueMap; + typedef std::map ValueMap; ValueMap m_valueMap; // Hash of node hash to (param value, name) int m_nextValue = 1; // Next value to use in m_valueMap @@ -370,7 +370,7 @@ private: } } void relinkPinsByName(AstPin* startpinp, AstNodeModule* modp) { - std::map nameToPin; + std::map nameToPin; for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* varp = VN_CAST(stmtp, Var)) { if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 022704efe..b43db96b9 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -108,7 +108,7 @@ public: class V3PreProcImp : public V3PreProc { public: // TYPES - typedef std::map DefinesMap; + typedef std::map DefinesMap; typedef VInFilter::StrList StrList; // debug() -> see V3PreShellImp::debug; use --debugi-V3PreShell @@ -585,7 +585,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { string value = defValue(refp->name()); UINFO(4, "defineValue '" << V3PreLex::cleanDbgStrg(value) << "'" << endl); - std::map argValueByName; + std::map argValueByName; { // Parse argument list into map unsigned numArgs = 0; string argName; diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 5d6b4ccf5..b8baebd4d 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -61,7 +61,7 @@ public: }; typedef std::deque ConstDeque; -typedef std::map ConstPile; +typedef std::map ConstPile; class SimulateVisitor : public AstNVisitor { // Simulate a node tree, returning value of variables diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index e2a954267..bb75f0e30 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -34,7 +34,7 @@ class StatsVisitor : public AstNVisitor { private: // NODE STATE/TYPES - typedef std::map NameMap; // Number of times a name appears + typedef std::map NameMap; // Number of times a name appears // STATE string m_stage; // Name of the stage we are scanning diff --git a/src/V3Table.cpp b/src/V3Table.cpp index b91348489..b83c44a68 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -222,7 +222,7 @@ private: void createTableVars(AstNode* nodep) { // Create table for each output - typedef std::map NameCounts; + typedef std::map NameCounts; NameCounts namecounts; for (const AstVarScope* outvscp : m_outVarps) { AstVar* outvarp = outvscp->varp(); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index c31598adb..ffe957a22 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -104,7 +104,7 @@ private: // TYPES typedef std::map, AstVarScope*> VarToScopeMap; - typedef std::map FuncToClassMap; + typedef std::map FuncToClassMap; typedef std::vector Initials; // MEMBERS VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings @@ -341,7 +341,7 @@ private: IM_AFTER, // Pointing at last inserted stmt, insert after IM_WHILE_PRECOND // Pointing to for loop, add to body end }; - typedef std::map> DpiNames; + typedef std::map> DpiNames; // STATE TaskStateVisitor* m_statep; // Common state between visitors @@ -1388,7 +1388,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // Missing pin/expr? We return (pinvar, nullptr) // Extra pin/expr? We clean it up - typedef std::map NameToIndex; + typedef std::map NameToIndex; NameToIndex nameToIndex; V3TaskConnects tconnects; UASSERT_OBJ(nodep->taskp(), nodep, "unlinked"); diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 3aeace7ab..3b983055b 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -741,8 +741,8 @@ private: // Remove refs to traced values from TraceDecl nodes, these have now moved under // TraceInc - for (TraceVec::iterator it = traces.begin(); it != traces.end(); ++it) { - AstNode* const valuep = it->second->nodep()->valuep(); + for (const auto& i : traces) { + AstNode* const valuep = i.second->nodep()->valuep(); valuep->unlinkFrBack(); valuep->deleteTree(); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index acc745b75..aad9bc657 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -191,7 +191,7 @@ public: class WidthVisitor : public AstNVisitor { private: // TYPES - typedef std::map, AstVar*> TableMap; + typedef std::map, AstVar*> TableMap; typedef std::map PatVecMap; // STATE @@ -1880,7 +1880,7 @@ private: // Assign missing values V3Number num(nodep, nodep->width(), 0); V3Number one(nodep, nodep->width(), 1); - std::map inits; + std::map inits; for (AstEnumItem* itemp = nodep->itemsp(); itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) { if (itemp->valuep()) { @@ -2982,7 +2982,7 @@ private: // which member each AstPatMember corresponds to before we can // determine the dtypep for that PatMember's value, and then // width the initial value appropriately. - typedef std::map PatMap; + typedef std::map PatMap; PatMap patmap; { AstMemberDType* memp = vdtypep->membersp(); diff --git a/src/VlcPoint.h b/src/VlcPoint.h index 83eefd85d..208dc5c56 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -93,7 +93,7 @@ public: class VlcPoints { private: // MEMBERS - typedef std::map NameMap; // Sorted by name (ordered) + typedef std::map NameMap; // Sorted by name (ordered) NameMap m_nameMap; //< Name to point-number std::vector m_points; //< List of all points vluint64_t m_numPoints = 0; //< Total unique points diff --git a/src/VlcSource.h b/src/VlcSource.h index 4f8e90e19..06d1cd847 100644 --- a/src/VlcSource.h +++ b/src/VlcSource.h @@ -101,7 +101,7 @@ public: class VlcSources { public: // TYPES - typedef std::map NameMap; + typedef std::map NameMap; private: // MEMBERS From cf7b5c091a553e61f70cd39eff133424066ef05f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 30 Oct 2020 22:28:51 -0400 Subject: [PATCH 37/88] Internals: Track some VAccess that can be ReadOnly. No functional change. --- src/V3Ast.h | 5 +++-- src/V3AstNodes.h | 2 +- src/V3Cast.cpp | 2 +- src/V3Const.cpp | 2 +- src/V3Gate.cpp | 2 +- src/V3Simulate.h | 2 +- src/V3Subst.cpp | 2 +- src/V3Trace.cpp | 2 +- src/V3WidthSel.cpp | 6 +++--- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 6ae97f107..36448ff51 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -140,8 +140,9 @@ public: : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning operator en() const { return m_e; } VAccess invert() const { return (m_e == WRITE) ? VAccess(READ) : VAccess(WRITE); } - bool isRead() const { return m_e == READ; } - bool isWrite() const { return m_e == WRITE; } + bool isReadOnly() const { return m_e == READ; } // False if/when support READWRITE + bool isWrite() const { return m_e == WRITE; } // Need audit if/when support READWRITE + bool isWriteOnly() const { return m_e == WRITE; } // False if/when support READWRITE }; inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; } inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 34b3af025..e3038b17c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2360,7 +2360,7 @@ public: } } virtual int instrCount() const override { - return widthInstrs() * (access().isWrite() ? 1 : instrCountLd()); + return widthInstrs() * (access().isWriteOnly() ? 1 : instrCountLd()); } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 1f0fb7d86..2a8173978 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -154,7 +154,7 @@ private: } } virtual void visit(AstVarRef* nodep) override { - if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast) + if (nodep->access().isReadOnly() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) { // Cast vars to IData first, else below has upper bits wrongly set diff --git a/src/V3Const.cpp b/src/V3Const.cpp index bfadcab72..6ef289e86 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1605,7 +1605,7 @@ private: // if (debug()) valuep->dumpTree(cout, " visitvaref: "); iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep() AstNode* valuep = nodep->varp()->valuep(); - if (!nodep->access().isWrite() + if (nodep->access().isReadOnly() && ((!m_params // Can reduce constant wires into equations && m_doNConst && v3Global.opt.oConst() diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 3bf82c08c..92fb406f8 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -842,7 +842,7 @@ private: // It's possible we substitute into something that will be reduced more later, // however, as we never delete the top Always/initial statement, all should be well. m_didReplace = true; - UASSERT_OBJ(!nodep->access().isWrite(), nodep, + UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Can't replace lvalue assignments with const var"); AstNode* substp = m_replaceTreep->cloneTree(false); UASSERT_OBJ( diff --git a/src/V3Simulate.h b/src/V3Simulate.h index b8baebd4d..84bf595ef 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -433,7 +433,7 @@ private: } } if (!m_checkOnly && optimizable()) { // simulating - UASSERT_OBJ(!nodep->access().isWrite(), nodep, + UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "LHS varref should be handled in AstAssign visitor."); { // Return simulation value - copy by reference instead of value for speed diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 636d39986..33f554067 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -306,7 +306,7 @@ private: iterate(nodep->rhsp()); AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); AstConst* constp = VN_CAST(nodep->rhsp(), Const); - if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->access().isWrite() && constp) { + if (varrefp && isSubstVar(varrefp->varp()) && varrefp->access().isReadOnly() && constp) { // Nicely formed lvalues handled in NodeAssign // Other lvalues handled as unknown mess in AstVarRef int word = constp->toUInt(); diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 3b983055b..b517e5bdc 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -845,7 +845,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (m_tracep) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); - UASSERT_OBJ(!nodep->access().isWrite(), nodep, "Lvalue in trace? Should be const."); + UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Lvalue in trace? Should be const."); V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex(); if (!varVtxp) { varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep()); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 8e3b09316..c3232066d 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -280,10 +280,10 @@ private: "Unsupported: String array operation on non-variable"); } AstNode* newp; - if (varrefp && varrefp->access().isWrite()) { - newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp); - } else { + if (varrefp && varrefp->access().isReadOnly()) { newp = new AstGetcN(nodep->fileline(), fromp, rhsp); + } else { + newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp); } UINFO(6, " new " << newp << endl); nodep->replaceWith(newp); From 3a53b32a320da1640c844c0e79f9710d0948a642 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 30 Oct 2020 22:49:42 -0400 Subject: [PATCH 38/88] Move queue code before assoc, as assoc will eventually use queues. No functional change. --- include/verilated_heavy.h | 348 +++++++++++++++++++------------------- 1 file changed, 174 insertions(+), 174 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 43da92fc2..e54a77442 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -73,6 +73,180 @@ public: void print(QData addr, bool addrstamp, const void* valuep); }; +//=================================================================== +// Verilog queue and dynamic array container +// There are no multithreaded locks on this; the base variable must +// be protected by other means +// +// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound +// For dynamic arrays it is always zero +template class VlQueue { +private: + // TYPES + typedef std::deque Deque; + +public: + typedef typename Deque::const_iterator const_iterator; + +private: + // MEMBERS + Deque m_deque; // State of the assoc array + T_Value m_defaultValue; // Default value + +public: + // CONSTRUCTORS + VlQueue() { + // m_defaultValue isn't defaulted. Caller's constructor must do it. + } + ~VlQueue() {} + + // Standard copy constructor works. Verilog: assoca = assocb + // Also must allow conversion from a different T_MaxSize queue + template VlQueue operator=(const VlQueue& rhs) { + m_deque = rhs.privateDeque(); + if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1); + return *this; + } + + static VlQueue cons(const T_Value& lhs) { + VlQueue out; + out.push_back(lhs); + return out; + } + static VlQueue cons(const T_Value& lhs, const T_Value& rhs) { + VlQueue out; + out.push_back(rhs); + out.push_back(lhs); + return out; + } + static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) { + VlQueue out = lhs; + out.push_front(rhs); + return out; + } + static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) { + VlQueue out = rhs; + out.push_back(lhs); + return out; + } + static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) { + VlQueue out = rhs; + for (const auto& i : lhs.m_deque) out.push_back(i); + return out; + } + + // METHODS + T_Value& atDefault() { return m_defaultValue; } + const Deque& privateDeque() const { return m_deque; } + + // Size. Verilog: function int size(), or int num() + int size() const { return m_deque.size(); } + // Clear array. Verilog: function void delete([input index]) + void clear() { m_deque.clear(); } + void erase(vlsint32_t index) { + if (VL_LIKELY(index >= 0 && index < m_deque.size())) + m_deque.erase(m_deque.begin() + index); + } + + // Dynamic array new[] becomes a renew() + void renew(size_t size) { + clear(); + m_deque.resize(size, atDefault()); + } + // Dynamic array new[]() becomes a renew_copy() + void renew_copy(size_t size, const VlQueue& rhs) { + if (size == 0) { + clear(); + } else { + *this = rhs; + m_deque.resize(size, atDefault()); + } + } + + // function void q.push_front(value) + void push_front(const T_Value& value) { + m_deque.push_front(value); + if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back(); + } + // function void q.push_back(value) + void push_back(const T_Value& value) { + if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value); + } + // function value_t q.pop_front(); + T_Value pop_front() { + if (m_deque.empty()) return m_defaultValue; + T_Value v = m_deque.front(); + m_deque.pop_front(); + return v; + } + // function value_t q.pop_back(); + T_Value pop_back() { + if (m_deque.empty()) return m_defaultValue; + T_Value v = m_deque.back(); + m_deque.pop_back(); + return v; + } + + // Setting. Verilog: assoc[index] = v + // Can't just overload operator[] or provide a "at" reference to set, + // because we need to be able to insert only when the value is set + T_Value& at(vlsint32_t index) { + static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { + s_throwAway = atDefault(); + return s_throwAway; + } else { + return m_deque[index]; + } + } + // Accessing. Verilog: v = assoc[index] + const T_Value& at(vlsint32_t index) const { + static T_Value s_throwAway; + // Needs to work for dynamic arrays, so does not use T_MaxSize + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { + return atDefault(); + } else { + return m_deque[index]; + } + } + // function void q.insert(index, value); + void insert(vlsint32_t index, const T_Value& value) { + if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return; + m_deque.insert(m_deque.begin() + index, value); + } + + // Return slice q[lsb:msb] + VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const { + VlQueue out; + if (VL_UNLIKELY(lsb < 0)) lsb = 0; + if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1; + if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1; + for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); + return out; + } + + // For save/restore + const_iterator begin() const { return m_deque.begin(); } + const_iterator end() const { return m_deque.end(); } + + // Dumping. Verilog: str = $sformatf("%p", assoc) + std::string to_string() const { + if (m_deque.empty()) return "'{}"; // No trailing space + std::string out = "'{"; + std::string comma; + for (const auto& i : m_deque) { + out += comma + VL_TO_STRING(i); + comma = ", "; + } + return out + "} "; + } +}; + +template std::string VL_TO_STRING(const VlQueue& obj) { + return obj.to_string(); +} + //=================================================================== // Verilog array container // Similar to std::array, but lighter weight, only methods needed @@ -255,180 +429,6 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename, } } -//=================================================================== -// Verilog queue and dynamic array container -// There are no multithreaded locks on this; the base variable must -// be protected by other means -// -// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound -// For dynamic arrays it is always zero -template class VlQueue { -private: - // TYPES - typedef std::deque Deque; - -public: - typedef typename Deque::const_iterator const_iterator; - -private: - // MEMBERS - Deque m_deque; // State of the assoc array - T_Value m_defaultValue; // Default value - -public: - // CONSTRUCTORS - VlQueue() { - // m_defaultValue isn't defaulted. Caller's constructor must do it. - } - ~VlQueue() {} - - // Standard copy constructor works. Verilog: assoca = assocb - // Also must allow conversion from a different T_MaxSize queue - template VlQueue operator=(const VlQueue& rhs) { - m_deque = rhs.privateDeque(); - if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1); - return *this; - } - - static VlQueue cons(const T_Value& lhs) { - VlQueue out; - out.push_back(lhs); - return out; - } - static VlQueue cons(const T_Value& lhs, const T_Value& rhs) { - VlQueue out; - out.push_back(rhs); - out.push_back(lhs); - return out; - } - static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) { - VlQueue out = lhs; - out.push_front(rhs); - return out; - } - static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) { - VlQueue out = rhs; - out.push_back(lhs); - return out; - } - static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) { - VlQueue out = rhs; - for (const auto& i : lhs.m_deque) out.push_back(i); - return out; - } - - // METHODS - T_Value& atDefault() { return m_defaultValue; } - const Deque& privateDeque() const { return m_deque; } - - // Size. Verilog: function int size(), or int num() - int size() const { return m_deque.size(); } - // Clear array. Verilog: function void delete([input index]) - void clear() { m_deque.clear(); } - void erase(vlsint32_t index) { - if (VL_LIKELY(index >= 0 && index < m_deque.size())) - m_deque.erase(m_deque.begin() + index); - } - - // Dynamic array new[] becomes a renew() - void renew(size_t size) { - clear(); - m_deque.resize(size, atDefault()); - } - // Dynamic array new[]() becomes a renew_copy() - void renew_copy(size_t size, const VlQueue& rhs) { - if (size == 0) { - clear(); - } else { - *this = rhs; - m_deque.resize(size, atDefault()); - } - } - - // function void q.push_front(value) - void push_front(const T_Value& value) { - m_deque.push_front(value); - if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back(); - } - // function void q.push_back(value) - void push_back(const T_Value& value) { - if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value); - } - // function value_t q.pop_front(); - T_Value pop_front() { - if (m_deque.empty()) return m_defaultValue; - T_Value v = m_deque.front(); - m_deque.pop_front(); - return v; - } - // function value_t q.pop_back(); - T_Value pop_back() { - if (m_deque.empty()) return m_defaultValue; - T_Value v = m_deque.back(); - m_deque.pop_back(); - return v; - } - - // Setting. Verilog: assoc[index] = v - // Can't just overload operator[] or provide a "at" reference to set, - // because we need to be able to insert only when the value is set - T_Value& at(vlsint32_t index) { - static T_Value s_throwAway; - // Needs to work for dynamic arrays, so does not use T_MaxSize - if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { - s_throwAway = atDefault(); - return s_throwAway; - } else { - return m_deque[index]; - } - } - // Accessing. Verilog: v = assoc[index] - const T_Value& at(vlsint32_t index) const { - static T_Value s_throwAway; - // Needs to work for dynamic arrays, so does not use T_MaxSize - if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { - return atDefault(); - } else { - return m_deque[index]; - } - } - // function void q.insert(index, value); - void insert(vlsint32_t index, const T_Value& value) { - if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return; - m_deque.insert(m_deque.begin() + index, value); - } - - // Return slice q[lsb:msb] - VlQueue slice(vlsint32_t lsb, vlsint32_t msb) const { - VlQueue out; - if (VL_UNLIKELY(lsb < 0)) lsb = 0; - if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1; - if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1; - for (vlsint32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); - return out; - } - - // For save/restore - const_iterator begin() const { return m_deque.begin(); } - const_iterator end() const { return m_deque.end(); } - - // Dumping. Verilog: str = $sformatf("%p", assoc) - std::string to_string() const { - if (m_deque.empty()) return "'{}"; // No trailing space - std::string out = "'{"; - std::string comma; - for (const auto& i : m_deque) { - out += comma + VL_TO_STRING(i); - comma = ", "; - } - return out + "} "; - } -}; - -template std::string VL_TO_STRING(const VlQueue& obj) { - return obj.to_string(); -} - //=================================================================== // Verilog class reference container // There are no multithreaded locks on this; the base variable must From e6b0479b8005443a63544c99b661808bec594587 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 31 Oct 2020 08:59:35 -0400 Subject: [PATCH 39/88] Internals: CFunc VL_RESTORER. No functional change intended. --- src/V3Combine.cpp | 12 ++++++------ src/V3Const.cpp | 20 ++++++++++++-------- src/V3Delayed.cpp | 8 +++++--- src/V3Depth.cpp | 38 +++++++++++++++++++++----------------- src/V3DepthBlock.cpp | 10 +++++----- src/V3Descope.cpp | 2 ++ src/V3EmitC.cpp | 6 +++--- src/V3EmitCSyms.cpp | 22 ++++++++++++---------- src/V3GenClk.cpp | 1 - src/V3InstrCount.cpp | 5 ++--- src/V3Localize.cpp | 16 +++++++++------- src/V3Premit.cpp | 16 +++++++++------- src/V3Reloop.cpp | 8 +++++--- src/V3Stats.cpp | 10 ++++++---- src/V3Trace.cpp | 16 +++++++++------- 15 files changed, 106 insertions(+), 84 deletions(-) diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index c938da506..bc82a812d 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -177,7 +177,7 @@ private: VDouble0 m_statCombs; // Statistic tracking CombineState m_state = STATE_IDLE; // Major state AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_funcp = nullptr; // Current function + AstCFunc* m_cfuncp = nullptr; // Current function CombCallVisitor m_call; // Tracking of function call users int m_modNFuncs = 0; // Number of functions made #ifdef VL_COMBINE_STATEMENTS @@ -330,7 +330,7 @@ private: AstNode* last2p) { // Final node in linked list, maybe null if all statements // to be grabbed // Make new function - string oldname = m_funcp->name(); + string oldname = m_cfuncp->name(); string::size_type pos; if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos); if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos); @@ -423,7 +423,8 @@ private: m_modp = nullptr; } virtual void visit(AstCFunc* nodep) override { - m_funcp = nodep; + VL_RESTORER(m_cfuncp); + m_cfuncp = nodep; if (!nodep->dontCombine()) { if (m_state == STATE_HASH) { hashStatement(nodep); // Hash the entire function - it might be identical @@ -434,18 +435,17 @@ private: } #endif } - m_funcp = nullptr; } virtual void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); return; } - if (m_state == STATE_HASH && m_funcp) { + if (m_state == STATE_HASH && m_cfuncp) { hashStatement(nodep); } #ifdef VL_COMBINE_STATEMENTS - else if (m_state == STATE_DUP && m_funcp) { + else if (m_state == STATE_DUP && m_cfuncp) { walkDupCodeStart(nodep); } #endif diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 6ef289e86..ed0e10b04 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1297,17 +1297,21 @@ private: virtual void visit(AstCFunc* nodep) override { // No ASSIGNW removals under funcs, we've long eliminated INITIALs // (We should perhaps rename the assignw's to just assigns) - m_wremove = false; - iterateChildren(nodep); - m_wremove = true; + VL_RESTORER(m_wremove); + { + m_wremove = false; + iterateChildren(nodep); + } } virtual void visit(AstScope* nodep) override { // No ASSIGNW removals under scope, we've long eliminated INITIALs - m_scopep = nodep; - m_wremove = false; - iterateChildren(nodep); - m_wremove = true; - m_scopep = nullptr; + VL_RESTORER(m_wremove); + VL_RESTORER(m_scopep); + { + m_wremove = false; + m_scopep = nodep; + iterateChildren(nodep); + } } void swapSides(AstNodeBiCom* nodep) { diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index fdd23ec39..89fb81dc7 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -358,9 +358,11 @@ private: iterateChildren(nodep); } virtual void visit(AstCFunc* nodep) override { - m_cfuncp = nodep; - iterateChildren(nodep); - m_cfuncp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + iterateChildren(nodep); + } } virtual void visit(AstActive* nodep) override { m_activep = nodep; diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 0eee958f0..fce9b9cf4 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -40,7 +40,7 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_funcp = nullptr; // Current block + AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement int m_depth = 0; // How deep in an expression int m_maxdepth = 0; // Maximum depth in an expression @@ -61,8 +61,8 @@ private: // bitmask instead of widths....) // See t_func_crc for an example test that requires this VFlagLogicPacked(), nodep->width()); - UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function"); - m_funcp->addInitsp(varp); + UASSERT_OBJ(m_cfuncp, nodep, "Deep expression not under a function"); + m_cfuncp->addInitsp(varp); // Replace node tree with reference to var AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); nodep->replaceWith(newp); @@ -81,23 +81,27 @@ private: VL_RESTORER(m_modp); { m_modp = nodep; - m_funcp = nullptr; + m_cfuncp = nullptr; iterateChildren(nodep); } } virtual void visit(AstCFunc* nodep) override { - m_funcp = nodep; - m_depth = 0; - m_maxdepth = 0; - iterateChildren(nodep); - m_funcp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + m_depth = 0; + m_maxdepth = 0; + iterateChildren(nodep); + } } void visitStmt(AstNodeStmt* nodep) { - m_depth = 0; - m_maxdepth = 0; - m_stmtp = nodep; - iterateChildren(nodep); - m_stmtp = nullptr; + VL_RESTORER(m_stmtp); + { + m_stmtp = nodep; + m_depth = 0; + m_maxdepth = 0; + iterateChildren(nodep); + } } virtual void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { @@ -128,10 +132,10 @@ private: // Marking of non-static functions (because they might need "this") // (Here instead of new visitor after V3Descope just to avoid another visitor) void needNonStaticFunc(AstNode* nodep) { - UASSERT_OBJ(m_funcp, nodep, "Non-static accessor not under a function"); - if (m_funcp->isStatic().trueUnknown()) { + UASSERT_OBJ(m_cfuncp, nodep, "Non-static accessor not under a function"); + if (m_cfuncp->isStatic().trueUnknown()) { UINFO(5, "Mark non-public due to " << nodep << endl); - m_funcp->isStatic(false); + m_cfuncp->isStatic(false); } } virtual void visit(AstUCFunc* nodep) override { diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 54db059ec..b4346db8d 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -38,7 +38,7 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_funcp = nullptr; // Current function + AstCFunc* m_cfuncp = nullptr; // Current function int m_depth = 0; // How deep in an expression int m_deepNum = 0; // How many functions made @@ -49,11 +49,11 @@ private: AstNRelinker relinkHandle; nodep->unlinkFrBack(&relinkHandle); // Create function - string name = m_funcp->name() + "__deep" + cvtToStr(++m_deepNum); + string name = m_cfuncp->name() + "__deep" + cvtToStr(++m_deepNum); AstCFunc* funcp = new AstCFunc(nodep->fileline(), name, nullptr); funcp->argTypes(EmitCBaseVisitor::symClassVar()); funcp->symProlog(true); - funcp->slow(m_funcp->slow()); + funcp->slow(m_cfuncp->slow()); funcp->addStmtsp(nodep); m_modp->addStmtp(funcp); // Call it at the point where the body was removed from @@ -78,10 +78,10 @@ private: virtual void visit(AstCFunc* nodep) override { // We recurse into this. VL_RESTORER(m_depth); - VL_RESTORER(m_funcp); + VL_RESTORER(m_cfuncp); { m_depth = 0; - m_funcp = nodep; + m_cfuncp = nodep; iterateChildren(nodep); } } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 9bbb522da..9cf15822b 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -268,6 +268,8 @@ private: // nodep->funcp()->scopep(nullptr); } virtual void visit(AstCFunc* nodep) override { + VL_RESTORER(m_needThis); + VL_RESTORER(m_allowThis); if (!nodep->user1()) { m_needThis = false; m_allowThis = nodep->isStatic().falseUnknown(); // Non-static or unknown if static diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 243c3314b..f38f7504a 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3372,7 +3372,7 @@ class EmitCTrace : EmitCStmts { AstUser1InUse m_inuser1; // MEMBERS - AstCFunc* m_funcp = nullptr; // Function we're in now + AstCFunc* m_cfuncp = nullptr; // Function we're in now bool m_slow; // Making slow file int m_enumNum = 0; // Enumeration number (whole netlist) int m_baseCode = -1; // Code of first AstTraceInc in this function @@ -3704,8 +3704,9 @@ class EmitCTrace : EmitCStmts { virtual void visit(AstNodeModule* nodep) override { iterateChildren(nodep); } virtual void visit(AstCFunc* nodep) override { if (nodep->slow() != m_slow) return; + VL_RESTORER(m_cfuncp); if (nodep->funcType().isTrace()) { // TRACE_* - m_funcp = nodep; + m_cfuncp = nodep; if (splitNeeded()) { // Splitting file, so using parallel build. @@ -3775,7 +3776,6 @@ class EmitCTrace : EmitCStmts { } puts("}\n"); } - m_funcp = nullptr; } virtual void visit(AstTraceDecl* nodep) override { int enumNum = emitTraceDeclDType(nodep->dtypep()); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index de4bb2e43..5c1fb26bd 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -50,11 +50,11 @@ class EmitCSyms : EmitCBaseVisitor { }; struct ScopeFuncData { AstScopeName* m_scopep; - AstCFunc* m_funcp; + AstCFunc* m_cfuncp; AstNodeModule* m_modp; ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp) : m_scopep{scopep} - , m_funcp{funcp} + , m_cfuncp{funcp} , m_modp{modp} {} }; struct ScopeVarData { @@ -94,7 +94,7 @@ class EmitCSyms : EmitCBaseVisitor { }; // STATE - AstCFunc* m_funcp = nullptr; // Current function + AstCFunc* m_cfuncp = nullptr; // Current function AstNodeModule* m_modp = nullptr; // Current module std::vector m_scopes; // Every scope by module std::vector m_dpis; // DPI functions @@ -316,9 +316,9 @@ class EmitCSyms : EmitCBaseVisitor { name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"))); } if (nodep->dpiExport()) { - UASSERT_OBJ(m_funcp, nodep, "ScopeName not under DPI function"); + UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function"); m_scopeFuncs.insert( - make_pair(name + " " + m_funcp->name(), ScopeFuncData(nodep, m_funcp, m_modp))); + make_pair(name + " " + m_cfuncp->name(), ScopeFuncData(nodep, m_cfuncp, m_modp))); } else { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { m_scopeNames.insert( @@ -342,9 +342,11 @@ class EmitCSyms : EmitCBaseVisitor { virtual void visit(AstCFunc* nodep) override { nameCheck(nodep); if (nodep->dpiImport() || nodep->dpiExportWrapper()) m_dpis.push_back(nodep); - m_funcp = nodep; - iterateChildren(nodep); - m_funcp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + iterateChildren(nodep); + } } //--------------------------------------- @@ -397,7 +399,7 @@ void EmitCSyms::emitSymHdr() { puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n"); std::map types; // Remove duplicates and sort for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { - AstCFunc* funcp = it->second.m_funcp; + AstCFunc* funcp = it->second.m_cfuncp; if (funcp->dpiExport()) { string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t"); types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1; @@ -721,7 +723,7 @@ void EmitCSyms::emitSymImp() { m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n"); for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { AstScopeName* scopep = it->second.m_scopep; - AstCFunc* funcp = it->second.m_funcp; + AstCFunc* funcp = it->second.m_cfuncp; AstNodeModule* modp = it->second.m_modp; if (funcp->dpiExport()) { checkSplit(true); diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 729708b7e..163ab4bc3 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -111,7 +111,6 @@ private: m_activep = nullptr; iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); } //----- virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index f01b10608..85ca8f3c9 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -241,13 +241,12 @@ private: UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep, "AstCFunc not under AstCCall, or not start node"); m_tracingCall = false; - bool saved_inCFunc = m_inCFunc; - m_inCFunc = true; + VL_RESTORER(m_inCFunc); { + m_inCFunc = true; VisitBase vb(this, nodep); iterateChildren(nodep); } - m_inCFunc = saved_inCFunc; } virtual void visit(AstNode* nodep) override { VisitBase vb(this, nodep); diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 3192b074d..efa34527c 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -150,13 +150,15 @@ private: } virtual void visit(AstCFunc* nodep) override { UINFO(4, " CFUNC " << nodep << endl); - m_cfuncp = nodep; - searchFuncStmts(nodep->argsp()); - searchFuncStmts(nodep->initsp()); - searchFuncStmts(nodep->stmtsp()); - searchFuncStmts(nodep->finalsp()); - iterateChildren(nodep); - m_cfuncp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + searchFuncStmts(nodep->argsp()); + searchFuncStmts(nodep->initsp()); + searchFuncStmts(nodep->stmtsp()); + searchFuncStmts(nodep->finalsp()); + iterateChildren(nodep); + } } void searchFuncStmts(AstNode* nodep) { // Search for basic assignments to allow moving non-blocktemps diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 8402cdb60..3195e30d0 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -94,7 +94,7 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_funcp = nullptr; // Current block + AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions @@ -141,7 +141,7 @@ private: string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc())); AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); - m_funcp->addInitsp(varp); + m_cfuncp->addInitsp(varp); return varp; } @@ -189,18 +189,20 @@ private: VL_RESTORER(m_modp); { m_modp = nodep; - m_funcp = nullptr; + m_cfuncp = nullptr; iterateChildren(nodep); } } virtual void visit(AstCFunc* nodep) override { - m_funcp = nodep; - iterateChildren(nodep); - m_funcp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + iterateChildren(nodep); + } } void startStatement(AstNode* nodep) { m_assignLhs = false; - if (m_funcp) m_stmtp = nodep; + if (m_cfuncp) m_stmtp = nodep; } virtual void visit(AstWhile* nodep) override { UINFO(4, " WHILE " << nodep << endl); diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index f23423141..50c3e9e30 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -142,9 +142,11 @@ private: // VISITORS virtual void visit(AstCFunc* nodep) override { - m_cfuncp = nodep; - iterateChildren(nodep); - m_cfuncp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + iterateChildren(nodep); + } } virtual void visit(AstNodeAssign* nodep) override { if (!m_cfuncp) return; diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index bb75f0e30..1e9669da6 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -181,10 +181,12 @@ private: if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; } - m_cfuncp = nodep; - allNodes(nodep); - iterateChildrenConst(nodep); - m_cfuncp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + allNodes(nodep); + iterateChildrenConst(nodep); + } } virtual void visit(AstNode* nodep) override { allNodes(nodep); diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index b517e5bdc..01067cb8e 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -169,7 +169,7 @@ private: // STATE AstNodeModule* m_topModp = nullptr; // Module to add variables to AstScope* m_topScopep = nullptr; // Scope to add variables to - AstCFunc* m_funcp = nullptr; // C function adding to graph + AstCFunc* m_cfuncp = nullptr; // C function adding to graph AstTraceDecl* m_tracep = nullptr; // Trace function adding to graph AstVarScope* m_activityVscp = nullptr; // Activity variable uint32_t m_activityNumber = 0; // Count of fields in activity variable @@ -826,9 +826,11 @@ private: new V3GraphEdge(&m_graph, activityVtxp, funcVtxp, 1); } } - m_funcp = nodep; - iterateChildren(nodep); - m_funcp = nullptr; + VL_RESTORER(m_cfuncp); + { + m_cfuncp = nodep; + iterateChildren(nodep); + } } virtual void visit(AstTraceDecl* nodep) override { UINFO(8, " TRACE " << nodep << endl); @@ -836,7 +838,7 @@ private: V3GraphVertex* const vertexp = new TraceTraceVertex(&m_graph, nodep); nodep->user1p(vertexp); - UASSERT_OBJ(m_funcp, nodep, "Trace not under func"); + UASSERT_OBJ(m_cfuncp, nodep, "Trace not under func"); m_tracep = nodep; iterateChildren(nodep); m_tracep = nullptr; @@ -857,9 +859,9 @@ private: || nodep->varp()->isSigPublic()) { // Or ones user can change new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1); } - } else if (m_funcp && m_finding && nodep->access().isWrite()) { + } else if (m_cfuncp && m_finding && nodep->access().isWrite()) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); - V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp); + V3GraphVertex* const funcVtxp = getCFuncVertexp(m_cfuncp); V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex(); if (varVtxp) { // else we're not tracing this signal new V3GraphEdge(&m_graph, funcVtxp, varVtxp, 1); From 85b05366bc25277f46d625ca74ec6d4c16f97045 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 31 Oct 2020 09:24:16 -0400 Subject: [PATCH 40/88] Internals: Misc prep work for 'with' support. --- src/V3AstNodes.h | 13 +++++++++---- src/V3LinkDot.cpp | 2 +- src/verilog.y | 14 +++++++------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e3038b17c..66eceb58f 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3071,19 +3071,24 @@ public: void cname(const string& cname) { m_cname = cname; } }; -class AstWith : public AstNodeStmt { +class AstWithParse : public AstNodeStmt { + // In early parse, FUNC(index) WITH equation-using-index + // Replaced with AstWith + // Parents: math|stmt + // Children: funcref, math public: - AstWith(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* argsp) + AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) : ASTGEN_SUPER(fl) { statement(stmt); setOp1p(funcrefp); - addNOp2p(argsp); + addNOp2p(exprp); } - ASTNODE_NODE_FUNCS(With) + ASTNODE_NODE_FUNCS(WithParse) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* funcrefp() const { return op1p(); } + AstNode* exprp() const { return op2p(); } }; //###################################################################### diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 822a43692..4a029073f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2400,7 +2400,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstWith* nodep) override { + virtual void visit(AstWithParse* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements"); nodep->replaceWith(nodep->funcrefp()->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); diff --git a/src/verilog.y b/src/verilog.y index 72275ccd9..e6c018af2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3496,9 +3496,9 @@ task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as tas // // IEEE: tf_call taskRef { $$ = $1; } // // funcref below not task ref to avoid conflict, must later handle either - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, true, $1, $4); } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, $1, $4); } // // can call as method and yWITH without parenthesis - | id yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, true, new AstFuncRef($1, *$1, nullptr), $4); } + | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, new AstFuncRef($1, *$1, nullptr), $4); } | system_t_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it @@ -3511,9 +3511,9 @@ task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as tas function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) // // IEEE: tf_call funcRef { $$ = $1; } - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, false, $1, $4); } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, $1, $4); } // // can call as method and yWITH without parenthesis - | id yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, false, new AstFuncRef($1, *$1, nullptr), $4); } + | id yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, new AstFuncRef($1, *$1, nullptr), $4); } | system_f_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it @@ -3521,7 +3521,7 @@ function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as f // // We implement randomize as a normal funcRef, since randomize isn't a keyword // // Note yNULL is already part of expressions, so they come for free | funcRef yWITH__CUR constraint_block { $$ = $1; BBUNSUP($2, "Unsupported: randomize() 'with' constraint"); } - | funcRef yWITH__CUR '{' '}' { $$ = new AstWith($2, false, $1, nullptr); } + | funcRef yWITH__CUR '{' '}' { $$ = new AstWithParse($2, false, $1, nullptr); } ; system_t_call: // IEEE: system_tf_call (as task) @@ -4028,9 +4028,9 @@ array_methodNoRoot: array_methodWith: array_methodNoRoot { $$ = $1; } | array_methodNoRoot parenE yWITH__PAREN '(' expr ')' - { $$ = new AstWith($3, false, $1, $5); } + { $$ = new AstWithParse($3, false, $1, $5); } | array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')' - { $$ = new AstWith($5, false, $1, $7); $1->addPinsp($3); } + { $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp($3); } ; dpi_import_export: // ==IEEE: dpi_import_export From 085e8454b8690d1237e405acba15ccd8748c549c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 31 Oct 2020 10:00:55 -0400 Subject: [PATCH 41/88] Support 'with' into elaboration (only). --- src/V3Ast.h | 7 +- src/V3AstNodes.h | 21 +++ src/V3LinkDot.cpp | 58 ++++++- src/V3Width.cpp | 20 ++- test_regress/t/t_array_method.out | 141 +++++++++++----- test_regress/t/t_assoc_method.out | 169 +++++++++++++++---- test_regress/t/t_queue_method.out | 225 ++++++++++++++++++++------ test_regress/t/t_queue_method_bad.out | 41 +++++ test_regress/t/t_queue_method_bad.pl | 19 +++ test_regress/t/t_queue_method_bad.v | 30 ++++ test_regress/t/t_with.out | 30 ---- 11 files changed, 602 insertions(+), 159 deletions(-) create mode 100755 test_regress/t/t_queue_method_bad.out create mode 100755 test_regress/t/t_queue_method_bad.pl create mode 100644 test_regress/t/t_queue_method_bad.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 36448ff51..eed8966f7 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -696,7 +696,8 @@ public: STMTTEMP, XTEMP, IFACEREF, // Used to link Interfaces between modules - MEMBER + MEMBER, + WITH }; enum en m_e; inline AstVarType() @@ -711,7 +712,7 @@ public: static const char* const names[] = { "?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT", - "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; + "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER", "WITH"}; return names[m_e]; } bool isSignal() const { @@ -727,7 +728,7 @@ public: bool isProcAssignable() const { return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF - || m_e == MEMBER); + || m_e == MEMBER || m_e == WITH); } bool isTemp() const { return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 66eceb58f..72e727cbf 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3091,6 +3091,27 @@ public: AstNode* exprp() const { return op2p(); } }; +class AstWith : public AstNodeStmt { + // Used as argument to method, then to AstCMethodHard + // dtypep() contains the with lambda's return dtype + // Parents: funcref (similar to AstArg) + // Children: VAR that declares the index variable + // Children: math (equation establishing the with) +public: + AstWith(FileLine* fl, AstVar* varp, AstNode* exprp) + : ASTGEN_SUPER(fl) { + addOp1p(varp); + addNOp2p(exprp); + } + ASTNODE_NODE_FUNCS(With) + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } + virtual bool hasDType() const override { return true; } + // + AstVar* varp() const { return VN_CAST(op1p(), Var); } + AstNode* exprp() const { return op2p(); } +}; + //###################################################################### class AstSenItem : public AstNode { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 4a029073f..f77316d14 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -713,6 +713,7 @@ class LinkDotFindVisitor : public AstNVisitor { int m_blockNum = 0; // Begin block number, 0=none seen bool m_explicitNew = false; // Hit a "new" function int m_modBlockNum = 0; // Begin block number in module, 0=none seen + int m_modWithNum = 0; // With block number, 0=none seen // METHODS static int debug() { return LinkDotState::debug(); } @@ -775,6 +776,7 @@ class LinkDotFindVisitor : public AstNVisitor { VL_RESTORER(m_paramNum); VL_RESTORER(m_blockNum); VL_RESTORER(m_modBlockNum); + VL_RESTORER(m_modWithNum); if (doit && nodep->user2()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Identically recursive module (module instantiates " @@ -801,6 +803,7 @@ class LinkDotFindVisitor : public AstNVisitor { m_paramNum = 0; m_blockNum = 0; m_modBlockNum = 0; + m_modWithNum = 0; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate nodep->user2(true); @@ -836,6 +839,7 @@ class LinkDotFindVisitor : public AstNVisitor { VL_RESTORER(m_paramNum); VL_RESTORER(m_blockNum); VL_RESTORER(m_modBlockNum); + VL_RESTORER(m_modWithNum); { UINFO(4, " Link Class: " << nodep << endl); VSymEnt* upperSymp = m_curSymp; @@ -848,6 +852,7 @@ class LinkDotFindVisitor : public AstNVisitor { m_paramNum = 0; m_blockNum = 0; m_modBlockNum = 0; + m_modWithNum = 0; m_explicitNew = false; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate @@ -1247,6 +1252,44 @@ class LinkDotFindVisitor : public AstNVisitor { m_curSymp->exportStarStar(m_statep->symsp()); // No longer needed, but can't delete until any multi-instantiated modules are expanded } + virtual void visit(AstWithParse* nodep) override { + // Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation)) + auto funcrefp = VN_CAST(nodep->funcrefp(), NodeFTaskRef); + UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task"); + string name = "item"; + FileLine* argFl = nodep->fileline(); + if (auto argp = VN_CAST(funcrefp->pinsp(), Arg)) { + if (auto parserefp = VN_CAST(argp->exprp(), ParseRef)) { + name = parserefp->name(); + argFl = parserefp->fileline(); + } else { + argp->v3error("'with' function expects simple variable name"); + } + if (argp->nextp()) + argp->nextp()->v3error("'with' function expects only up to one argument"); + VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); + } + // Type depends on the method used, let V3Width figure it out later + auto* varp = new AstVar(argFl, AstVarType::WITH, name, VFlagChildDType(), + new AstParseTypeDType(nodep->fileline())); + auto* newp = new AstWith(nodep->fileline(), varp, nodep->exprp()->unlinkFrBackWithNext()); + funcrefp->addPinsp(newp); + nodep->replaceWith(funcrefp->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstWith* nodep) override { + // Symbol table needs nodep->name() as the index variable's name + // Iteration will pickup the AstVar we made under AstWith + VL_RESTORER(m_curSymp); + VSymEnt* const oldCurSymp = m_curSymp; + { + ++m_modWithNum; + m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep, + m_packagep); + m_curSymp->fallbackp(oldCurSymp); + iterateChildren(nodep); + } + } virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } @@ -2400,11 +2443,6 @@ private: iterateChildren(nodep); } } - virtual void visit(AstWithParse* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements"); - nodep->replaceWith(nodep->funcrefp()->unlinkFrBack()); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } virtual void visit(AstVar* nodep) override { checkNoDot(nodep); iterateChildren(nodep); @@ -2658,6 +2696,16 @@ private: m_ds.m_dotSymp = m_curSymp = oldCurSymp; m_ftaskp = nullptr; } + virtual void visit(AstWith* nodep) override { + UINFO(5, " " << nodep << endl); + checkNoDot(nodep); + VSymEnt* oldCurSymp = m_curSymp; + { + m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); + iterateChildren(nodep); + } + m_ds.m_dotSymp = m_curSymp = oldCurSymp; + } virtual void visit(AstClass* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index aad9bc657..15d41ad2d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2267,6 +2267,7 @@ private: if (debug() >= 9) nodep->dumpTree("-mts-in: "); // Should check types the method requires, but at present we don't do much userIterate(nodep->fromp(), WidthVP(SELF, BOTH).p()); + // Any AstWith is checked later when know types, in methodWithArgument for (AstArg* argp = VN_CAST(nodep->pinsp(), Arg); argp; argp = VN_CAST(argp->nextp(), Arg)) { if (argp->exprp()) userIterate(argp->exprp(), WidthVP(SELF, BOTH).p()); @@ -2302,6 +2303,12 @@ private: void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) { int narg = 0; for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) { + if (VN_IS(argp, With)) { + argp->v3error("'with' not legal on this method"); + // Delete all arguments as nextp() otherwise dangling + VL_DO_DANGLING(pushDeletep(argp->unlinkFrBackWithNext()), argp); + break; + } ++narg; UASSERT_OBJ(VN_IS(argp, Arg), nodep, "Method arg without Arg type"); } @@ -2483,6 +2490,7 @@ private: << " not legal on associative arrays"); } else { nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); + nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { newp->didWidth(true); @@ -2536,6 +2544,7 @@ private: } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " << nodep->prettyNameQ()); + nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { newp->didWidth(true); @@ -2623,8 +2632,9 @@ private: newp->protect(false); newp->makeStatement(); } else { - nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in associative array method " - << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported/unknown built-in queue method " << nodep->prettyNameQ()); + nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { newp->didWidth(true); @@ -2715,6 +2725,7 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ()); + nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } } void methodCallEvent(AstMethodCall* nodep, AstBasicDType* adtypep) { @@ -4103,6 +4114,11 @@ private: userIterateChildren(nodep, nullptr); m_procedurep = nullptr; } + virtual void visit(AstWith* nodep) override { + // Should otherwise be underneath a method call + nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements in this context"); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster userIterateChildrenBackwards(nodep, nullptr); diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out index f8eeb31b2..85bbc2913 100644 --- a/test_regress/t/t_array_method.out +++ b/test_regress/t/t_array_method.out @@ -1,64 +1,129 @@ -%Error-UNSUPPORTED: t/t_array_method.v:26:14: Unsupported: with statements +%Error: t/t_array_method.v:24:9: Unknown built-in array method 'sort' + : ... In instance t + 24 | q.sort; + | ^~~~ +%Error: t/t_array_method.v:26:9: Unknown built-in array method 'sort' + : ... In instance t 26 | q.sort with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:28:17: Unsupported: with statements + | ^~~~ +%Error: t/t_array_method.v:28:9: Unknown built-in array method 'sort' + : ... In instance t 28 | q.sort(x) with (x == 3); - | ^~~~ -%Error: t/t_array_method.v:28:14: Can't find definition of variable: 'x' - 28 | q.sort(x) with (x == 3); - | ^ -%Error-UNSUPPORTED: t/t_array_method.v:33:15: Unsupported: with statements + | ^~~~ +%Error: t/t_array_method.v:31:9: Unknown built-in array method 'rsort' + : ... In instance t + 31 | q.rsort; + | ^~~~~ +%Error: t/t_array_method.v:33:9: Unknown built-in array method 'rsort' + : ... In instance t 33 | q.rsort with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:47:19: Unsupported: with statements + | ^~~~~ +%Error: t/t_array_method.v:36:14: Unknown built-in array method 'unique' + : ... In instance t + 36 | qv = q.unique; + | ^~~~~~ +%Error: t/t_array_method.v:38:14: Unknown built-in array method 'unique_index' + : ... In instance t + 38 | qi = q.unique_index; qi.sort; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_array_method.v:38:31: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 38 | qi = q.unique_index; qi.sort; + | ^~~~ +%Error: t/t_array_method.v:40:9: Unknown built-in array method 'reverse' + : ... In instance t + 40 | q.reverse; + | ^~~~~~~ +%Error: t/t_array_method.v:42:9: Unknown built-in array method 'shuffle' + : ... In instance t + 42 | q.shuffle(); q.sort; + | ^~~~~~~ +%Error: t/t_array_method.v:42:22: Unknown built-in array method 'sort' + : ... In instance t + 42 | q.shuffle(); q.sort; + | ^~~~ +%Error: t/t_array_method.v:47:14: Unknown built-in array method 'find' + : ... In instance t 47 | qv = q.find with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:49:25: Unsupported: with statements + | ^~~~ +%Error: t/t_array_method.v:49:14: Unknown built-in array method 'find_first' + : ... In instance t 49 | qv = q.find_first with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:51:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error: t/t_array_method.v:51:14: Unknown built-in array method 'find_last' + : ... In instance t 51 | qv = q.find_last with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:54:19: Unsupported: with statements + | ^~~~~~~~~ +%Error: t/t_array_method.v:54:14: Unknown built-in array method 'find' + : ... In instance t 54 | qv = q.find with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:56:25: Unsupported: with statements + | ^~~~ +%Error: t/t_array_method.v:56:14: Unknown built-in array method 'find_first' + : ... In instance t 56 | qv = q.find_first with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:58:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error: t/t_array_method.v:58:14: Unknown built-in array method 'find_last' + : ... In instance t 58 | qv = q.find_last with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:61:25: Unsupported: with statements + | ^~~~~~~~~ +%Error: t/t_array_method.v:61:14: Unknown built-in array method 'find_index' + : ... In instance t 61 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:63:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_array_method.v:61:46: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 61 | qi = q.find_index with (item == 2); qi.sort; + | ^~~~ +%Error: t/t_array_method.v:63:14: Unknown built-in array method 'find_first_index' + : ... In instance t 63 | qi = q.find_first_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:65:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error: t/t_array_method.v:65:14: Unknown built-in array method 'find_last_index' + : ... In instance t 65 | qi = q.find_last_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:68:25: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error: t/t_array_method.v:68:14: Unknown built-in array method 'find_index' + : ... In instance t 68 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:70:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_array_method.v:68:47: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 68 | qi = q.find_index with (item == 20); qi.sort; + | ^~~~ +%Error: t/t_array_method.v:70:14: Unknown built-in array method 'find_first_index' + : ... In instance t 70 | qi = q.find_first_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:72:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error: t/t_array_method.v:72:14: Unknown built-in array method 'find_last_index' + : ... In instance t 72 | qi = q.find_last_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:83:17: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error: t/t_array_method.v:75:14: Unknown built-in array method 'min' + : ... In instance t + 75 | qv = q.min; + | ^~~ +%Error: t/t_array_method.v:77:14: Unknown built-in array method 'max' + : ... In instance t + 77 | qv = q.max; + | ^~~ +%Error: t/t_array_method.v:83:17: 'with' not legal on this method + : ... In instance t 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",83, (i), (32'h11)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:85:21: Unsupported: with statements +%Error: t/t_array_method.v:85:21: 'with' not legal on this method + : ... In instance t 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",85, (i), (32'h168)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:89:17: Unsupported: with statements +%Error: t/t_array_method.v:89:17: 'with' not legal on this method + : ... In instance t 89 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",89, (i), (32'b1001)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:91:16: Unsupported: with statements +%Error: t/t_array_method.v:91:16: 'with' not legal on this method + : ... In instance t 91 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",91, (i), (32'b1111)); $stop; end while(0);; | ^~~~ -%Error-UNSUPPORTED: t/t_array_method.v:93:17: Unsupported: with statements +%Error: t/t_array_method.v:93:17: 'with' not legal on this method + : ... In instance t 93 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",93, (i), (32'hb)); $stop; end while(0);; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_method.out b/test_regress/t/t_assoc_method.out index 3f2aa0104..0f16007ef 100644 --- a/test_regress/t/t_assoc_method.out +++ b/test_regress/t/t_assoc_method.out @@ -1,52 +1,153 @@ -%Error-UNSUPPORTED: t/t_assoc_method.v:42:19: Unsupported: with statements +%Error: t/t_assoc_method.v:31:14: Unknown built-in associative array method 'unique' + : ... In instance t + 31 | qv = q.unique; + | ^~~~~~ +%Error: t/t_assoc_method.v:33:15: Unknown built-in associative array method 'unique' + : ... In instance t + 33 | qv = qe.unique; + | ^~~~~~ +%Error: t/t_assoc_method.v:35:14: Unknown built-in associative array method 'unique_index' + : ... In instance t + 35 | qi = q.unique_index; qi.sort; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:35:31: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 35 | qi = q.unique_index; qi.sort; + | ^~~~ +%Error: t/t_assoc_method.v:37:15: Unknown built-in associative array method 'unique_index' + : ... In instance t + 37 | qv = qe.unique_index; + | ^~~~~~~~~~~~ +%Error: t/t_assoc_method.v:42:14: Unknown built-in associative array method 'find' + : ... In instance t 42 | qv = q.find with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:44:25: Unsupported: with statements + | ^~~~ +%Error: t/t_assoc_method.v:44:14: Unknown built-in associative array method 'find_first' + : ... In instance t 44 | qv = q.find_first with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:46:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error: t/t_assoc_method.v:46:14: Unknown built-in associative array method 'find_last' + : ... In instance t 46 | qv = q.find_last with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:49:19: Unsupported: with statements + | ^~~~~~~~~ +%Error: t/t_assoc_method.v:49:14: Unknown built-in associative array method 'find' + : ... In instance t 49 | qv = q.find with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:51:25: Unsupported: with statements + | ^~~~ +%Error: t/t_assoc_method.v:51:14: Unknown built-in associative array method 'find_first' + : ... In instance t 51 | qv = q.find_first with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:53:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error: t/t_assoc_method.v:53:14: Unknown built-in associative array method 'find_last' + : ... In instance t 53 | qv = q.find_last with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:56:25: Unsupported: with statements + | ^~~~~~~~~ +%Error: t/t_assoc_method.v:56:14: Unknown built-in associative array method 'find_index' + : ... In instance t 56 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:58:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:56:46: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 56 | qi = q.find_index with (item == 2); qi.sort; + | ^~~~ +%Error: t/t_assoc_method.v:58:14: Unknown built-in associative array method 'find_first_index' + : ... In instance t 58 | qi = q.find_first_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:60:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error: t/t_assoc_method.v:60:14: Unknown built-in associative array method 'find_last_index' + : ... In instance t 60 | qi = q.find_last_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:63:25: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error: t/t_assoc_method.v:63:14: Unknown built-in associative array method 'find_index' + : ... In instance t 63 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:65:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assoc_method.v:63:47: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 63 | qi = q.find_index with (item == 20); qi.sort; + | ^~~~ +%Error: t/t_assoc_method.v:65:14: Unknown built-in associative array method 'find_first_index' + : ... In instance t 65 | qi = q.find_first_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:67:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error: t/t_assoc_method.v:67:14: Unknown built-in associative array method 'find_last_index' + : ... In instance t 67 | qi = q.find_last_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:83:17: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error: t/t_assoc_method.v:70:14: Unknown built-in associative array method 'min' + : ... In instance t + 70 | qv = q.min; + | ^~~ +%Error: t/t_assoc_method.v:72:14: Unknown built-in associative array method 'max' + : ... In instance t + 72 | qv = q.max; + | ^~~ +%Error: t/t_assoc_method.v:75:15: Unknown built-in associative array method 'min' + : ... In instance t + 75 | qv = qe.min; + | ^~~ +%Error: t/t_assoc_method.v:77:15: Unknown built-in associative array method 'max' + : ... In instance t + 77 | qv = qe.max; + | ^~~ +%Error: t/t_assoc_method.v:82:13: Unknown built-in associative array method 'sum' + : ... In instance t + 82 | i = q.sum; do if ((i) !== (32'hc)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",82, (i), (32'hc)); $stop; end while(0);; + | ^~~ +%Error: t/t_assoc_method.v:83:13: Unknown built-in associative array method 'sum' + : ... In instance t 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",83, (i), (32'h11)); $stop; end while(0);; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:85:21: Unsupported: with statements + | ^~~ +%Error: t/t_assoc_method.v:84:13: Unknown built-in associative array method 'product' + : ... In instance t + 84 | i = q.product; do if ((i) !== (32'h30)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",84, (i), (32'h30)); $stop; end while(0);; + | ^~~~~~~ +%Error: t/t_assoc_method.v:85:13: Unknown built-in associative array method 'product' + : ... In instance t 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",85, (i), (32'h168)); $stop; end while(0);; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:92:17: Unsupported: with statements + | ^~~~~~~ +%Error: t/t_assoc_method.v:87:14: Unknown built-in associative array method 'sum' + : ... In instance t + 87 | i = qe.sum; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",87, (i), (32'h0)); $stop; end while(0);; + | ^~~ +%Error: t/t_assoc_method.v:88:14: Unknown built-in associative array method 'product' + : ... In instance t + 88 | i = qe.product; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'h0)); $stop; end while(0);; + | ^~~~~~~ +%Error: t/t_assoc_method.v:91:13: Unknown built-in associative array method 'and' + : ... In instance t + 91 | i = q.and; do if ((i) !== (32'b1000)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",91, (i), (32'b1000)); $stop; end while(0);; + | ^~~ +%Error: t/t_assoc_method.v:92:13: Unknown built-in associative array method 'and' + : ... In instance t 92 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",92, (i), (32'b1001)); $stop; end while(0);; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:94:16: Unsupported: with statements + | ^~~ +%Error: t/t_assoc_method.v:93:13: Unknown built-in associative array method 'or' + : ... In instance t + 93 | i = q.or; do if ((i) !== (32'b1110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",93, (i), (32'b1110)); $stop; end while(0);; + | ^~ +%Error: t/t_assoc_method.v:94:13: Unknown built-in associative array method 'or' + : ... In instance t 94 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",94, (i), (32'b1111)); $stop; end while(0);; - | ^~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:96:17: Unsupported: with statements + | ^~ +%Error: t/t_assoc_method.v:95:13: Unknown built-in associative array method 'xor' + : ... In instance t + 95 | i = q.xor; do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",95, (i), (32'b0110)); $stop; end while(0);; + | ^~~ +%Error: t/t_assoc_method.v:96:13: Unknown built-in associative array method 'xor' + : ... In instance t 96 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",96, (i), (32'b0110)); $stop; end while(0);; - | ^~~~ + | ^~~ +%Error: t/t_assoc_method.v:98:14: Unknown built-in associative array method 'and' + : ... In instance t + 98 | i = qe.and; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",98, (i), (32'b0)); $stop; end while(0);; + | ^~~ +%Error: t/t_assoc_method.v:99:14: Unknown built-in associative array method 'or' + : ... In instance t + 99 | i = qe.or; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",99, (i), (32'b0)); $stop; end while(0);; + | ^~ +%Error: t/t_assoc_method.v:100:14: Unknown built-in associative array method 'xor' + : ... In instance t + 100 | i = qe.xor; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",100, (i), (32'b0)); $stop; end while(0);; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_queue_method.out b/test_regress/t/t_queue_method.out index f7067fb08..57e6f4f83 100644 --- a/test_regress/t/t_queue_method.out +++ b/test_regress/t/t_queue_method.out @@ -1,70 +1,201 @@ -%Error-UNSUPPORTED: t/t_queue_method.v:28:14: Unsupported: with statements +%Error-UNSUPPORTED: t/t_queue_method.v:26:9: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 26 | q.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:28:9: Unsupported/unknown built-in queue method 'sort' + : ... In instance t 28 | q.sort with (10 - item); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:30:17: Unsupported: with statements + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:30:9: Unsupported/unknown built-in queue method 'sort' + : ... In instance t 30 | q.sort(x) with (10 - x); - | ^~~~ -%Error: t/t_queue_method.v:30:14: Can't find definition of variable: 'x' - 30 | q.sort(x) with (10 - x); - | ^ -%Error-UNSUPPORTED: t/t_queue_method.v:32:18: Unsupported: with statements + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:32:10: Unsupported/unknown built-in queue method 'sort' + : ... In instance t 32 | qe.sort(x) with (10 - x); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:36:15: Unsupported: with statements + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:34:9: Unsupported/unknown built-in queue method 'rsort' + : ... In instance t + 34 | q.rsort; + | ^~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:36:9: Unsupported/unknown built-in queue method 'rsort' + : ... In instance t 36 | q.rsort with (10 - item); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:38:19: Unsupported: with statements + | ^~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:38:10: Unsupported/unknown built-in queue method 'rsort' + : ... In instance t 38 | qe.rsort(x) with (10 - x); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:62:19: Unsupported: with statements + | ^~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:42:14: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 42 | qv = q.unique; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:44:15: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 44 | qv = qe.unique; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:46:14: Unsupported/unknown built-in queue method 'unique_index' + : ... In instance t + 46 | qi = q.unique_index; qv.sort; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:46:31: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 46 | qi = q.unique_index; qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:48:15: Unsupported/unknown built-in queue method 'unique_index' + : ... In instance t + 48 | qi = qe.unique_index; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:51:9: Unsupported/unknown built-in queue method 'reverse' + : ... In instance t + 51 | q.reverse; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:53:10: Unsupported/unknown built-in queue method 'reverse' + : ... In instance t + 53 | qe.reverse; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:55:9: Unsupported/unknown built-in queue method 'shuffle' + : ... In instance t + 55 | q.shuffle(); q.sort; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:55:22: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 55 | q.shuffle(); q.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:57:10: Unsupported/unknown built-in queue method 'shuffle' + : ... In instance t + 57 | qe.shuffle(); + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:62:14: Unsupported/unknown built-in queue method 'find' + : ... In instance t 62 | qv = q.find with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:64:25: Unsupported: with statements + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:64:14: Unsupported/unknown built-in queue method 'find_first' + : ... In instance t 64 | qv = q.find_first with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:66:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:66:14: Unsupported/unknown built-in queue method 'find_last' + : ... In instance t 66 | qv = q.find_last with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:69:19: Unsupported: with statements + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:69:14: Unsupported/unknown built-in queue method 'find' + : ... In instance t 69 | qv = q.find with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:71:25: Unsupported: with statements + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:71:14: Unsupported/unknown built-in queue method 'find_first' + : ... In instance t 71 | qv = q.find_first with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:73:24: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:73:14: Unsupported/unknown built-in queue method 'find_last' + : ... In instance t 73 | qv = q.find_last with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:76:25: Unsupported: with statements + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:76:14: Unsupported/unknown built-in queue method 'find_index' + : ... In instance t 76 | qi = q.find_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:78:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:77:10: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 77 | qi.sort; v = $sformatf("%p", qi); do if ((v) !== ("'{'h1, 'h2} ")) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", "t/t_queue_method.v",77, (v), ("'{'h1, 'h2} ")); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:78:14: Unsupported/unknown built-in queue method 'find_first_index' + : ... In instance t 78 | qi = q.find_first_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:80:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:80:14: Unsupported/unknown built-in queue method 'find_last_index' + : ... In instance t 80 | qi = q.find_last_index with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:83:25: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:83:14: Unsupported/unknown built-in queue method 'find_index' + : ... In instance t 83 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:85:31: Unsupported: with statements + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:83:47: Unsupported/unknown built-in queue method 'sort' + : ... In instance t + 83 | qi = q.find_index with (item == 20); qi.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:85:14: Unsupported/unknown built-in queue method 'find_first_index' + : ... In instance t 85 | qi = q.find_first_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:87:30: Unsupported: with statements + | ^~~~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:87:14: Unsupported/unknown built-in queue method 'find_last_index' + : ... In instance t 87 | qi = q.find_last_index with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:102:17: Unsupported: with statements + | ^~~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:90:14: Unsupported/unknown built-in queue method 'min' + : ... In instance t + 90 | qv = q.min; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:92:14: Unsupported/unknown built-in queue method 'max' + : ... In instance t + 92 | qv = q.max; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:94:15: Unsupported/unknown built-in queue method 'min' + : ... In instance t + 94 | qv = qe.min; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:96:15: Unsupported/unknown built-in queue method 'max' + : ... In instance t + 96 | qv = qe.max; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:100:13: Unsupported/unknown built-in queue method 'sum' + : ... In instance t + 100 | i = q.sum; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:102:13: Unsupported/unknown built-in queue method 'sum' + : ... In instance t 102 | i = q.sum with (item + 1); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:106:21: Unsupported: with statements + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:104:13: Unsupported/unknown built-in queue method 'product' + : ... In instance t + 104 | i = q.product; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:106:13: Unsupported/unknown built-in queue method 'product' + : ... In instance t 106 | i = q.product with (item + 1); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:117:17: Unsupported: with statements + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:109:14: Unsupported/unknown built-in queue method 'sum' + : ... In instance t + 109 | i = qe.sum; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:111:14: Unsupported/unknown built-in queue method 'product' + : ... In instance t + 111 | i = qe.product; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:115:13: Unsupported/unknown built-in queue method 'and' + : ... In instance t + 115 | i = q.and; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:117:13: Unsupported/unknown built-in queue method 'and' + : ... In instance t 117 | i = q.and with (item + 1); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:121:16: Unsupported: with statements + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:119:13: Unsupported/unknown built-in queue method 'or' + : ... In instance t + 119 | i = q.or; + | ^~ +%Error-UNSUPPORTED: t/t_queue_method.v:121:13: Unsupported/unknown built-in queue method 'or' + : ... In instance t 121 | i = q.or with (item + 1); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:125:17: Unsupported: with statements + | ^~ +%Error-UNSUPPORTED: t/t_queue_method.v:123:13: Unsupported/unknown built-in queue method 'xor' + : ... In instance t + 123 | i = q.xor; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:125:13: Unsupported/unknown built-in queue method 'xor' + : ... In instance t 125 | i = q.xor with (item + 1); - | ^~~~ + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:128:14: Unsupported/unknown built-in queue method 'and' + : ... In instance t + 128 | i = qe.and; + | ^~~ +%Error-UNSUPPORTED: t/t_queue_method.v:130:14: Unsupported/unknown built-in queue method 'or' + : ... In instance t + 130 | i = qe.or; + | ^~ +%Error-UNSUPPORTED: t/t_queue_method.v:132:14: Unsupported/unknown built-in queue method 'xor' + : ... In instance t + 132 | i = qe.xor; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_queue_method_bad.out b/test_regress/t/t_queue_method_bad.out new file mode 100755 index 000000000..429388dca --- /dev/null +++ b/test_regress/t/t_queue_method_bad.out @@ -0,0 +1,41 @@ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:15:14: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 15 | qv = q.unique with (1); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:16:9: Unsupported/unknown built-in queue method 'reverse' + : ... In instance t + 16 | q.reverse(1); + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:17:9: Unsupported/unknown built-in queue method 'shuffle' + : ... In instance t + 17 | q.shuffle(1); + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:18:14: Unsupported/unknown built-in queue method 'find' + : ... In instance t + 18 | qv = q.find; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:19:14: Unsupported/unknown built-in queue method 'find_first' + : ... In instance t + 19 | qv = q.find_first; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:20:14: Unsupported/unknown built-in queue method 'find_last' + : ... In instance t + 20 | qv = q.find_last; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:21:14: Unsupported/unknown built-in queue method 'find_index' + : ... In instance t + 21 | qi = q.find_index; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:22:14: Unsupported/unknown built-in queue method 'find_first_index' + : ... In instance t + 22 | qi = q.find_first_index; + | ^~~~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_queue_method_bad.v:23:14: Unsupported/unknown built-in queue method 'find_last_index' + : ... In instance t + 23 | qi = q.find_last_index; + | ^~~~~~~~~~~~~~~ +%Error: t/t_queue_method_bad.v:25:19: 'with' not legal on this method + : ... In instance t + 25 | qi = q.size with (1); + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_queue_method_bad.pl b/test_regress/t/t_queue_method_bad.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_queue_method_bad.pl @@ -0,0 +1,19 @@ +#!/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( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_method_bad.v b/test_regress/t/t_queue_method_bad.v new file mode 100644 index 000000000..3036d05b1 --- /dev/null +++ b/test_regress/t/t_queue_method_bad.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + initial begin + int q[$]; + int qe[$]; // Empty + int qv[$]; // Value returns + int qi[$]; // Index returns + + q = '{2, 2, 4, 1, 3}; + qv = q.unique with (1); // Bad no with allowed + q.reverse(1); // Bad no args allowed + q.shuffle(1); // Bad no args allowed + qv = q.find; // Bad missing with + qv = q.find_first; // Bad missing with + qv = q.find_last; // Bad missing with + qi = q.find_index; // Bad missing with + qi = q.find_first_index; // Bad missing with + qi = q.find_last_index; // Bad missing with + + qi = q.size with (1); // with not allowed + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_with.out b/test_regress/t/t_with.out index 5d3e1a04c..347d054c6 100644 --- a/test_regress/t/t_with.out +++ b/test_regress/t/t_with.out @@ -1,34 +1,4 @@ -%Error-UNSUPPORTED: t/t_with.v:19:31: Unsupported: with statements - 19 | found = aliases.find(i) with (i == tofind); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:21:23: Unsupported: with statements - 21 | aliases.find(i) with (i == tofind); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:24:28: Unsupported: with statements - 24 | found = aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:25:20: Unsupported: with statements - 25 | aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:29:30: Unsupported: with statements - 29 | found = aliases.unique with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:30:32: Unsupported: with statements - 30 | found = aliases.unique() with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:31:33: Unsupported: with statements - 31 | found = aliases.unique(i) with (id); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:32:25: Unsupported: with statements - 32 | i = aliases.or(v) with (v); - | ^~~~ %Error: t/t_with.v:32:22: Can't find definition of variable: 'v' 32 | i = aliases.or(v) with (v); | ^ -%Error-UNSUPPORTED: t/t_with.v:33:26: Unsupported: with statements - 33 | i = aliases.and(v) with (v); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:34:26: Unsupported: with statements - 34 | i = aliases.xor(v) with (v); - | ^~~~ %Error: Exiting due to From 726e78fdda2f6d8122ee1a643a1f70e9edb841ed Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 31 Oct 2020 10:33:36 -0400 Subject: [PATCH 42/88] Add 'with' syntax checks. --- src/V3LinkDot.cpp | 2 +- src/V3Width.cpp | 1 - src/verilog.y | 2 +- test_regress/t/t_assoc_meth_bad.out | 53 ------------------- test_regress/t/t_assoc_method_bad.out | 53 +++++++++++++++++++ ...ssoc_meth_bad.pl => t_assoc_method_bad.pl} | 0 ..._assoc_meth_bad.v => t_assoc_method_bad.v} | 0 test_regress/t/t_queue_method2_bad.out | 7 +++ test_regress/t/t_queue_method2_bad.pl | 19 +++++++ test_regress/t/t_queue_method2_bad.v | 22 ++++++++ test_regress/t/t_with.out | 41 +++++++++++++- 11 files changed, 142 insertions(+), 58 deletions(-) delete mode 100644 test_regress/t/t_assoc_meth_bad.out create mode 100644 test_regress/t/t_assoc_method_bad.out rename test_regress/t/{t_assoc_meth_bad.pl => t_assoc_method_bad.pl} (100%) rename test_regress/t/{t_assoc_meth_bad.v => t_assoc_method_bad.v} (100%) create mode 100755 test_regress/t/t_queue_method2_bad.out create mode 100755 test_regress/t/t_queue_method2_bad.pl create mode 100644 test_regress/t/t_queue_method2_bad.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index f77316d14..c73104f5a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1267,7 +1267,7 @@ class LinkDotFindVisitor : public AstNVisitor { } if (argp->nextp()) argp->nextp()->v3error("'with' function expects only up to one argument"); - VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); + VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); } // Type depends on the method used, let V3Width figure it out later auto* varp = new AstVar(argFl, AstVarType::WITH, name, VFlagChildDType(), diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 15d41ad2d..f41ba25a1 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4117,7 +4117,6 @@ private: virtual void visit(AstWith* nodep) override { // Should otherwise be underneath a method call nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements in this context"); - VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster diff --git a/src/verilog.y b/src/verilog.y index e6c018af2..ef4e4a045 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4030,7 +4030,7 @@ array_methodWith: | array_methodNoRoot parenE yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($3, false, $1, $5); } | array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')' - { $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp($3); } + { $$ = new AstWithParse($5, false, $1, $7); $1->addPinsp(new AstArg($3, "", $3)); } ; dpi_import_export: // ==IEEE: dpi_import_export diff --git a/test_regress/t/t_assoc_meth_bad.out b/test_regress/t/t_assoc_meth_bad.out deleted file mode 100644 index 496ecfee9..000000000 --- a/test_regress/t/t_assoc_meth_bad.out +++ /dev/null @@ -1,53 +0,0 @@ -%Error: t/t_assoc_meth_bad.v:14:13: The 1 arguments passed to .num method does not match its requiring 0 arguments - : ... In instance t - 14 | v = a.num("badarg"); - | ^~~ -%Error: t/t_assoc_meth_bad.v:15:13: The 1 arguments passed to .size method does not match its requiring 0 arguments - : ... In instance t - 15 | v = a.size("badarg"); - | ^~~~ -%Error: t/t_assoc_meth_bad.v:16:13: The 0 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t - 16 | v = a.exists(); - | ^~~~~~ -%Error: t/t_assoc_meth_bad.v:17:13: The 2 arguments passed to .exists method does not match its requiring 1 arguments - : ... In instance t - 17 | v = a.exists(k, "bad2"); - | ^~~~~~ -%Error: t/t_assoc_meth_bad.v:18:13: The 0 arguments passed to .first method does not match its requiring 1 arguments - : ... In instance t - 18 | v = a.first(); - | ^~~~~ -%Error: t/t_assoc_meth_bad.v:19:13: The 2 arguments passed to .next method does not match its requiring 1 arguments - : ... In instance t - 19 | v = a.next(k, "bad2"); - | ^~~~ -%Error: t/t_assoc_meth_bad.v:20:13: The 0 arguments passed to .last method does not match its requiring 1 arguments - : ... In instance t - 20 | v = a.last(); - | ^~~~ -%Error: t/t_assoc_meth_bad.v:21:13: The 2 arguments passed to .prev method does not match its requiring 1 arguments - : ... In instance t - 21 | v = a.prev(k, "bad2"); - | ^~~~ -%Error: t/t_assoc_meth_bad.v:22:9: The 2 arguments passed to .delete method does not match its requiring 0 to 1 arguments - : ... In instance t - 22 | a.delete(k, "bad2"); - | ^~~~~~ -%Error: t/t_assoc_meth_bad.v:24:9: Array method 'sort' not legal on associative arrays - : ... In instance t - 24 | a.sort; - | ^~~~ -%Error: t/t_assoc_meth_bad.v:25:9: Array method 'rsort' not legal on associative arrays - : ... In instance t - 25 | a.rsort; - | ^~~~~ -%Error: t/t_assoc_meth_bad.v:26:9: Array method 'reverse' not legal on associative arrays - : ... In instance t - 26 | a.reverse; - | ^~~~~~~ -%Error: t/t_assoc_meth_bad.v:27:9: Array method 'shuffle' not legal on associative arrays - : ... In instance t - 27 | a.shuffle; - | ^~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_assoc_method_bad.out b/test_regress/t/t_assoc_method_bad.out new file mode 100644 index 000000000..6c0ff94cc --- /dev/null +++ b/test_regress/t/t_assoc_method_bad.out @@ -0,0 +1,53 @@ +%Error: t/t_assoc_method_bad.v:14:13: The 1 arguments passed to .num method does not match its requiring 0 arguments + : ... In instance t + 14 | v = a.num("badarg"); + | ^~~ +%Error: t/t_assoc_method_bad.v:15:13: The 1 arguments passed to .size method does not match its requiring 0 arguments + : ... In instance t + 15 | v = a.size("badarg"); + | ^~~~ +%Error: t/t_assoc_method_bad.v:16:13: The 0 arguments passed to .exists method does not match its requiring 1 arguments + : ... In instance t + 16 | v = a.exists(); + | ^~~~~~ +%Error: t/t_assoc_method_bad.v:17:13: The 2 arguments passed to .exists method does not match its requiring 1 arguments + : ... In instance t + 17 | v = a.exists(k, "bad2"); + | ^~~~~~ +%Error: t/t_assoc_method_bad.v:18:13: The 0 arguments passed to .first method does not match its requiring 1 arguments + : ... In instance t + 18 | v = a.first(); + | ^~~~~ +%Error: t/t_assoc_method_bad.v:19:13: The 2 arguments passed to .next method does not match its requiring 1 arguments + : ... In instance t + 19 | v = a.next(k, "bad2"); + | ^~~~ +%Error: t/t_assoc_method_bad.v:20:13: The 0 arguments passed to .last method does not match its requiring 1 arguments + : ... In instance t + 20 | v = a.last(); + | ^~~~ +%Error: t/t_assoc_method_bad.v:21:13: The 2 arguments passed to .prev method does not match its requiring 1 arguments + : ... In instance t + 21 | v = a.prev(k, "bad2"); + | ^~~~ +%Error: t/t_assoc_method_bad.v:22:9: The 2 arguments passed to .delete method does not match its requiring 0 to 1 arguments + : ... In instance t + 22 | a.delete(k, "bad2"); + | ^~~~~~ +%Error: t/t_assoc_method_bad.v:24:9: Array method 'sort' not legal on associative arrays + : ... In instance t + 24 | a.sort; + | ^~~~ +%Error: t/t_assoc_method_bad.v:25:9: Array method 'rsort' not legal on associative arrays + : ... In instance t + 25 | a.rsort; + | ^~~~~ +%Error: t/t_assoc_method_bad.v:26:9: Array method 'reverse' not legal on associative arrays + : ... In instance t + 26 | a.reverse; + | ^~~~~~~ +%Error: t/t_assoc_method_bad.v:27:9: Array method 'shuffle' not legal on associative arrays + : ... In instance t + 27 | a.shuffle; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_assoc_meth_bad.pl b/test_regress/t/t_assoc_method_bad.pl similarity index 100% rename from test_regress/t/t_assoc_meth_bad.pl rename to test_regress/t/t_assoc_method_bad.pl diff --git a/test_regress/t/t_assoc_meth_bad.v b/test_regress/t/t_assoc_method_bad.v similarity index 100% rename from test_regress/t/t_assoc_meth_bad.v rename to test_regress/t/t_assoc_method_bad.v diff --git a/test_regress/t/t_queue_method2_bad.out b/test_regress/t/t_queue_method2_bad.out new file mode 100755 index 000000000..5d2900d8e --- /dev/null +++ b/test_regress/t/t_queue_method2_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_queue_method2_bad.v:16:21: 'with' function expects only up to one argument + 16 | qi = q.find(a,b) with (0); + | ^ +%Error: t/t_queue_method2_bad.v:17:19: 'with' function expects simple variable name + 17 | qi = q.find(1) with (0); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_queue_method2_bad.pl b/test_regress/t/t_queue_method2_bad.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_queue_method2_bad.pl @@ -0,0 +1,19 @@ +#!/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( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_method2_bad.v b/test_regress/t/t_queue_method2_bad.v new file mode 100644 index 000000000..b6ce89d8c --- /dev/null +++ b/test_regress/t/t_queue_method2_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + initial begin + int q[$]; + int qe[$]; // Empty + int qv[$]; // Value returns + int qi[$]; // Index returns + + q = '{2, 2, 4, 1, 3}; + + qi = q.find(a,b) with (0); // b is extra + qi = q.find(1) with (0); // 1 is illegal + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_with.out b/test_regress/t/t_with.out index 347d054c6..4b4dae672 100644 --- a/test_regress/t/t_with.out +++ b/test_regress/t/t_with.out @@ -1,4 +1,41 @@ -%Error: t/t_with.v:32:22: Can't find definition of variable: 'v' +%Error-UNSUPPORTED: t/t_with.v:19:23: Unsupported/unknown built-in queue method 'find' + : ... In instance t + 19 | found = aliases.find(i) with (i == tofind); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:21:15: Unsupported/unknown built-in queue method 'find' + : ... In instance t + 21 | aliases.find(i) with (i == tofind); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:24:23: Unsupported/unknown built-in queue method 'find' + : ... In instance t + 24 | found = aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:25:15: Unsupported/unknown built-in queue method 'find' + : ... In instance t + 25 | aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with.v:29:23: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 29 | found = aliases.unique with (id); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_with.v:30:23: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 30 | found = aliases.unique() with (id); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_with.v:31:23: Unsupported/unknown built-in queue method 'unique' + : ... In instance t + 31 | found = aliases.unique(i) with (id); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_with.v:32:19: Unsupported/unknown built-in queue method 'or' + : ... In instance t 32 | i = aliases.or(v) with (v); - | ^ + | ^~ +%Error-UNSUPPORTED: t/t_with.v:33:19: Unsupported/unknown built-in queue method 'and' + : ... In instance t + 33 | i = aliases.and(v) with (v); + | ^~~ +%Error-UNSUPPORTED: t/t_with.v:34:19: Unsupported/unknown built-in queue method 'xor' + : ... In instance t + 34 | i = aliases.xor(v) with (v); + | ^~~ %Error: Exiting due to From 5e6aca59ab180a825996fcbcf54386072514822f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 09:14:45 -0500 Subject: [PATCH 43/88] Fix test stability due to #2618. --- test_regress/t/t_dynarray.v | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index 5ac8d755f..dce72070d 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -79,6 +79,10 @@ module t (/*AUTOARG*/ `checkh(a[0], 5); `checkh(a[1], 6); a = new[2]; +`ifdef verilator // bug2618 + a[0] = 0; + a[1] = 0; +`endif `checkh(a[0], 0); `checkh(a[1], 0); @@ -91,6 +95,10 @@ module t (/*AUTOARG*/ `checkh(b.size, 4); `checkh(b[0], 5); `checkh(b[1], 6); +`ifdef verilator // bug2618 + b[2] = 0; + b[3] = 0; +`endif `checkh(b[2], 0); `checkh(b[3], 0); From 1858cc8ff1a3b54b5039f66895cfdf64a459ffac Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 09:26:55 -0500 Subject: [PATCH 44/88] Fix test stability due to #2618. --- test_regress/t/t_dynarray.v | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index dce72070d..aa2b87ba8 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -113,6 +113,12 @@ module t (/*AUTOARG*/ `checkh(a.size, 0); b = new [4](a); `checkh(b.size, 4); +`ifdef verilator // bug2618 + b[0] = 0; + b[1] = 0; + b[2] = 0; + b[3] = 0; +`endif `checkh(b[0], 0); `checkh(b[1], 0); `checkh(b[2], 0); From c1e8337fc1b36652328eb00a5dd256d5c9a33691 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 10:18:32 -0500 Subject: [PATCH 45/88] Support pattern assignment to dynamic arrays. --- src/V3AstNodes.h | 22 ++++++++++++ src/V3EmitC.cpp | 15 ++++++++ src/V3Width.cpp | 69 +++++++++++++++++++++++++++++++++++-- test_regress/t/t_dynarray.v | 26 +++++++------- 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 72e727cbf..da115b3e2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -4668,6 +4668,28 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; +class AstConsDynArray : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // Parents: math + // Children: expression (elements or other queues) +public: + AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER(fl) { + setNOp1p(lhsp); + setNOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(ConsDynArray) + virtual string emitVerilog() override { return "'{%l, %r}"; } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } // op1 = expression + AstNode* rhsp() const { return op2p(); } // op2 = expression + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; + class AstConsQueue : public AstNodeMath { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // Parents: math diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index f38f7504a..c209d55da 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1593,6 +1593,21 @@ class EmitCImp : EmitCStmts { iterateAndNextNull(nodep->valuep()); puts(")"); } + virtual void visit(AstConsDynArray* nodep) override { + putbs(nodep->dtypep()->cType("", false, false)); + if (!nodep->lhsp()) { + puts("()"); + } else { + puts("::cons("); + iterateAndNextNull(nodep->lhsp()); + if (nodep->rhsp()) { + puts(", "); + putbs(""); + } + iterateAndNextNull(nodep->rhsp()); + puts(")"); + } + } virtual void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f41ba25a1..3fd5a7ebd 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -485,6 +485,7 @@ private: // signed: Unsigned (11.8.1) // width: LHS + RHS AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); + userIterateAndNext(vdtypep, WidthVP(SELF, BOTH).p()); if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -494,6 +495,14 @@ private: userIterateChildren(newp, m_vup); return; } + if (VN_IS(vdtypep, DynArrayDType)) { + auto* newp = new AstConsDynArray(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), + nodep->lhsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterateChildren(newp, m_vup); + return; + } if (m_vup->prelim()) { if (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // @@ -633,7 +642,7 @@ private: } AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - if (VN_IS(vdtypep, QueueDType)) { + if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)) { if (times != 1) nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form " << vdtypep->prettyDTypeNameQ() @@ -645,8 +654,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) - || VN_IS(vdtypep, UnpackArrayDType)) { + if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, UnpackArrayDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); } @@ -1509,6 +1517,11 @@ private: } UINFO(4, "dtWidthed " << nodep << endl); } + virtual void visit(AstVoidDType* nodep) override { + if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + nodep->dtypep(nodep); + UINFO(4, "dtWidthed " << nodep << endl); + } virtual void visit(AstUnsizedArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. @@ -1985,6 +1998,38 @@ private: EXTEND_EXP); } } + virtual void visit(AstConsDynArray* nodep) override { + // Type computed when constructed here + AstDynArrayDType* vdtypep = VN_CAST(m_vup->dtypep(), DynArrayDType); + UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type"); + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p()); + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p()); + nodep->dtypeFrom(vdtypep); + } + if (m_vup->final()) { + // Arguments can be either elements of the queue or a queue itself + // Concats (part of tree of concats) must always become ConsDynArray's + if (nodep->lhsp()) { + if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType) + || VN_IS(nodep->lhsp(), ConsDynArray)) { + userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + // Sub elements are not queues, but concats, must always pass concats down + iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL); + } + } + if (nodep->rhsp()) { + if (VN_IS(nodep->rhsp()->dtypep(), DynArrayDType) + || VN_IS(nodep->rhsp(), ConsDynArray)) { + userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p()); + } else { + iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL); + } + } + nodep->dtypeFrom(vdtypep); + } + } virtual void visit(AstConsQueue* nodep) override { // Type computed when constructed here AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType); @@ -2969,12 +3014,15 @@ private: while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) { dtypep = vdtypep->subDTypep()->skipRefp(); } + userIterateAndNext(dtypep, WidthVP(SELF, BOTH).p()); if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, AssocArrayDType)) { VL_DO_DANGLING(patternAssoc(nodep, vdtypep, defaultp), nodep); + } else if (auto* vdtypep = VN_CAST(dtypep, DynArrayDType)) { + VL_DO_DANGLING(patternDynArray(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, QueueDType)) { VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep); } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { @@ -3155,6 +3203,21 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } + void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember* defaultp) { + AstNode* newp = new AstConsDynArray(nodep->fileline()); + newp->dtypeFrom(arrayp); + for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; + patp = VN_CAST(patp->nextp(), PatMember)) { + patp->dtypep(arrayp->subDTypep()); + AstNode* valuep = patternMemberValueIterate(patp); + auto* newap = new AstConsDynArray(nodep->fileline(), valuep, newp); + newap->dtypeFrom(arrayp); + newp = newap; + } + nodep->replaceWith(newp); + // if (debug() >= 9) newp->dumpTree("-apat-out: "); + VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present + } void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) { AstNode* newp = new AstConsQueue(nodep->fileline()); newp->dtypeFrom(arrayp); diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index aa2b87ba8..4be647804 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -36,12 +36,19 @@ module t (/*AUTOARG*/ pck256_t p256[]; + string s[] = { "hello", "sad", "world" }; + always @ (posedge clk) begin cyc <= cyc + 1; begin `checkh(a.size, 0); v = $sformatf("%p", a); `checks(v, "'{}"); + `checkh(s.size, 3); + `checks(s[0], "hello"); + `checks(s[1], "sad"); + `checks(s[2], "world"); + a = new [3]; `checkh(a.size, 3); a[0] = 10; @@ -54,22 +61,17 @@ module t (/*AUTOARG*/ a.delete; `checkh(a.size, 0); - a = new [2]; -`ifdef verilator // Unsupported pattern assignment - a[0] = 15; a[1] = 16; -`else a = '{15, 16}; -`endif `checkh(a.size, 2); `checkh(a[0], 15); `checkh(a[1], 16) -`ifdef verilator // Unsupported pattern assignment - a = new [1]; - a[0] = 17; -`else + a = {17, 18}; + `checkh(a.size, 2); + `checkh(a[0], 17); + `checkh(a[1], 18) + a = '{17}; -`endif `checkh(a.size, 1); // IEEE says resizes to smallest that fits pattern `checkh(a[0], 17); @@ -122,7 +124,7 @@ module t (/*AUTOARG*/ `checkh(b[0], 0); `checkh(b[1], 0); `checkh(b[2], 0); - `checkh(b[4], 0); + `checkh(b[3], 0); // test wide dynamic array p256 = new [11]; @@ -135,7 +137,7 @@ module t (/*AUTOARG*/ `checkh(p256[1].header, 16'hcafe); `checkh(p256[1], {16'hcafe,{14{16'hbabe}},16'hdead}); - `checkh(p256[0], '0); + //X's: `checkh(p256[0], 'x); p256[5] = '1; `checkh(p256[5], {32{8'hff}}); From 2aedc91151715cc22dc19cab8611bcfb8a2dcde0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 10:56:07 -0500 Subject: [PATCH 46/88] Support queue and associative array 'with' statements. (#2616) --- Changes | 2 + include/verilated_heavy.h | 314 +++++++++++++++++++++++++- src/V3Ast.cpp | 3 + src/V3Ast.h | 8 +- src/V3AstNodes.cpp | 9 + src/V3AstNodes.h | 41 +++- src/V3Clean.cpp | 5 + src/V3EmitC.cpp | 12 + src/V3LinkDot.cpp | 27 ++- src/V3Width.cpp | 228 ++++++++++++++++--- test_regress/t/t_array_method.out | 12 - test_regress/t/t_assoc_method.out | 153 ------------- test_regress/t/t_assoc_method.pl | 4 +- test_regress/t/t_assoc_method.v | 71 +++--- test_regress/t/t_dynarray_method.pl | 21 ++ test_regress/t/t_dynarray_method.v | 168 ++++++++++++++ test_regress/t/t_queue_method.out | 201 ----------------- test_regress/t/t_queue_method.pl | 4 +- test_regress/t/t_queue_method.v | 16 ++ test_regress/t/t_queue_method_bad.out | 38 ++-- test_regress/t/t_with.out | 41 ---- test_regress/t/t_with.pl | 4 +- test_regress/t/t_with.v | 10 +- test_regress/t/t_with_suggest_bad.out | 9 + test_regress/t/t_with_suggest_bad.pl | 20 ++ test_regress/t/t_with_suggest_bad.v | 21 ++ 26 files changed, 935 insertions(+), 507 deletions(-) delete mode 100644 test_regress/t/t_assoc_method.out create mode 100755 test_regress/t/t_dynarray_method.pl create mode 100644 test_regress/t/t_dynarray_method.v delete mode 100644 test_regress/t/t_queue_method.out delete mode 100644 test_regress/t/t_with.out create mode 100644 test_regress/t/t_with_suggest_bad.out create mode 100755 test_regress/t/t_with_suggest_bad.pl create mode 100644 test_regress/t/t_with_suggest_bad.v diff --git a/Changes b/Changes index 3dc21bc38..97ea9ae11 100644 --- a/Changes +++ b/Changes @@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.103 devel +**** Support queue and associative array 'with' statements. (#2616) + **** Support queue slicing (#2326). **** Support associative array pattern assignments and defaults. diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e54a77442..9e23181a8 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -26,9 +26,11 @@ #include "verilated.h" +#include #include #include #include +#include #include //=================================================================== @@ -230,6 +232,162 @@ public: const_iterator begin() const { return m_deque.begin(); } const_iterator end() const { return m_deque.end(); } + // Methods + void sort() { std::sort(m_deque.begin(), m_deque.end()); } + template void sort(Func with_func) { + // with_func returns arbitrary type to use for the sort comparison + std::sort(m_deque.begin(), m_deque.end(), + [=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); }); + } + void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); } + template void rsort(Func with_func) { + // with_func returns arbitrary type to use for the sort comparison + std::sort(m_deque.rbegin(), m_deque.rend(), + [=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); }); + } + void reverse() { std::reverse(m_deque.begin(), m_deque.end()); } + void shuffle() { + std::random_shuffle(m_deque.begin(), m_deque.end(), + [=](int) { return VL_RANDOM_I(32) % m_deque.size(); }); + } + VlQueue unique() const { + VlQueue out; + std::set saw; + for (const auto& i : m_deque) { + auto it = saw.find(i); + if (it == saw.end()) { + saw.insert(it, i); + out.push_back(i); + } + } + return out; + } + VlQueue unique_index() const { + VlQueue out; + IData index = 0; + std::set saw; + for (const auto& i : m_deque) { + auto it = saw.find(i); + if (it == saw.end()) { + saw.insert(it, i); + out.push_back(index); + } + ++index; + } + return out; + } + template VlQueue find(Func with_func) const { + VlQueue out; + for (const auto& i : m_deque) + if (with_func(i)) out.push_back(i); + return out; + } + template VlQueue find_index(Func with_func) const { + VlQueue out; + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(i)) out.push_back(index); + ++index; + } + return out; + } + template VlQueue find_first(Func with_func) const { + const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); + if (it == m_deque.end()) return VlQueue{}; + return VlQueue::cons(*it); + } + template VlQueue find_first_index(Func with_func) const { + const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); + if (it == m_deque.end()) return VlQueue{}; + return VlQueue::cons(std::distance(m_deque.begin(), it)); + } + template VlQueue find_last(Func with_func) const { + const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); + if (it == m_deque.rend()) return VlQueue{}; + return VlQueue::cons(*it); + } + template VlQueue find_last_index(Func with_func) const { + const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); + if (it == m_deque.rend()) return VlQueue{}; + // Return index must be relative to beginning + return VlQueue::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it)); + } + + // Reduction operators + VlQueue min() const { + if (m_deque.empty()) return VlQueue(); + const auto it = std::min_element(m_deque.begin(), m_deque.end()); + return VlQueue::cons(*it); + } + VlQueue max() const { + if (m_deque.empty()) return VlQueue(); + const auto it = std::max_element(m_deque.begin(), m_deque.end()); + return VlQueue::cons(*it); + } + + T_Value r_sum() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out += i; + return out; + } + template T_Value r_sum(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out += with_func(i); + return out; + } + T_Value r_product() const { + if (m_deque.empty()) return T_Value(0); + auto it = m_deque.begin(); + T_Value out{*it}; + ++it; + for (; it != m_deque.end(); ++it) out *= *it; + return out; + } + template T_Value r_product(Func with_func) const { + if (m_deque.empty()) return T_Value(0); + auto it = m_deque.begin(); + T_Value out{with_func(*it)}; + ++it; + for (; it != m_deque.end(); ++it) out *= with_func(*it); + return out; + } + T_Value r_and() const { + if (m_deque.empty()) return T_Value(0); + auto it = m_deque.begin(); + T_Value out{*it}; + ++it; + for (; it != m_deque.end(); ++it) out &= *it; + return out; + } + template T_Value r_and(Func with_func) const { + if (m_deque.empty()) return T_Value(0); + auto it = m_deque.begin(); + T_Value out{with_func(*it)}; + ++it; + for (; it != m_deque.end(); ++it) out &= with_func(*it); + return out; + } + T_Value r_or() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out |= i; + return out; + } + template T_Value r_or(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out |= with_func(i); + return out; + } + T_Value r_xor() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out ^= i; + return out; + } + template T_Value r_xor(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_deque) out ^= with_func(i); + return out; + } + // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { if (m_deque.empty()) return "'{}"; // No trailing space @@ -355,7 +513,8 @@ public: T_Value& at(const T_Key& index) { const auto it = m_map.find(index); if (it == m_map.end()) { - const auto pit = m_map.insert(std::make_pair(index, m_defaultValue)); + std::pair pit + = m_map.insert(std::make_pair(index, m_defaultValue)); return pit.first->second; } return it->second; @@ -383,6 +542,159 @@ public: const_iterator begin() const { return m_map.begin(); } const_iterator end() const { return m_map.end(); } + // Methods + VlQueue unique() const { + VlQueue out; + std::set saw; + for (const auto& i : m_map) { + auto it = saw.find(i.second); + if (it == saw.end()) { + saw.insert(it, i.second); + out.push_back(i.second); + } + } + return out; + } + VlQueue unique_index() const { + VlQueue out; + std::set saw; + for (const auto& i : m_map) { + auto it = saw.find(i.second); + if (it == saw.end()) { + saw.insert(it, i.second); + out.push_back(i.first); + } + } + return out; + } + template VlQueue find(Func with_func) const { + VlQueue out; + for (const auto& i : m_map) + if (with_func(i.second)) out.push_back(i.second); + return out; + } + template VlQueue find_index(Func with_func) const { + VlQueue out; + for (const auto& i : m_map) + if (with_func(i.second)) out.push_back(i.first); + return out; + } + template VlQueue find_first(Func with_func) const { + const auto it + = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { + return with_func(i.second); + }); + if (it == m_map.end()) return VlQueue{}; + return VlQueue::cons(it->second); + } + template VlQueue find_first_index(Func with_func) const { + const auto it + = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { + return with_func(i.second); + }); + if (it == m_map.end()) return VlQueue{}; + return VlQueue::cons(it->first); + } + template VlQueue find_last(Func with_func) const { + const auto it + = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { + return with_func(i.second); + }); + if (it == m_map.rend()) return VlQueue{}; + return VlQueue::cons(it->second); + } + template VlQueue find_last_index(Func with_func) const { + const auto it + = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { + return with_func(i.second); + }); + if (it == m_map.rend()) return VlQueue{}; + return VlQueue::cons(it->first); + } + + // Reduction operators + VlQueue min() const { + if (m_map.empty()) return VlQueue(); + const auto it = std::min_element( + m_map.begin(), m_map.end(), + [](const std::pair& a, const std::pair& b) { + return a.second < b.second; + }); + return VlQueue::cons(it->second); + } + VlQueue max() const { + if (m_map.empty()) return VlQueue(); + const auto it = std::max_element( + m_map.begin(), m_map.end(), + [](const std::pair& a, const std::pair& b) { + return a.second < b.second; + }); + return VlQueue::cons(it->second); + } + + T_Value r_sum() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out += i.second; + return out; + } + template T_Value r_sum(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out += with_func(i.second); + return out; + } + T_Value r_product() const { + if (m_map.empty()) return T_Value(0); + auto it = m_map.begin(); + T_Value out{it->second}; + ++it; + for (; it != m_map.end(); ++it) out *= it->second; + return out; + } + template T_Value r_product(Func with_func) const { + if (m_map.empty()) return T_Value(0); + auto it = m_map.begin(); + T_Value out{with_func(it->second)}; + ++it; + for (; it != m_map.end(); ++it) out *= with_func(it->second); + return out; + } + T_Value r_and() const { + if (m_map.empty()) return T_Value(0); + auto it = m_map.begin(); + T_Value out{it->second}; + ++it; + for (; it != m_map.end(); ++it) out &= it->second; + return out; + } + template T_Value r_and(Func with_func) const { + if (m_map.empty()) return T_Value(0); + auto it = m_map.begin(); + T_Value out{with_func(it->second)}; + ++it; + for (; it != m_map.end(); ++it) out &= with_func(it->second); + return out; + } + T_Value r_or() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out |= i.second; + return out; + } + template T_Value r_or(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out |= with_func(i.second); + return out; + } + T_Value r_xor() const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out ^= i.second; + return out; + } + template T_Value r_xor(Func with_func) const { + T_Value out(0); // Type must have assignment operator + for (const auto& i : m_map) out ^= with_func(i.second); + return out; + } + // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { if (m_map.empty()) return "'{}"; // No trailing space diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e8f8682ef..6444ae0e4 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1261,6 +1261,9 @@ AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) { AstNodeDType* AstNode::findVoidDType() const { return v3Global.rootp()->typeTablep()->findVoidDType(fileline()); } +AstNodeDType* AstNode::findQueueIndexDType() const { + return v3Global.rootp()->typeTablep()->findQueueIndexDType(fileline()); +} //###################################################################### // AstNVisitor diff --git a/src/V3Ast.h b/src/V3Ast.h index eed8966f7..ab8baf611 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -696,8 +696,7 @@ public: STMTTEMP, XTEMP, IFACEREF, // Used to link Interfaces between modules - MEMBER, - WITH + MEMBER }; enum en m_e; inline AstVarType() @@ -712,7 +711,7 @@ public: static const char* const names[] = { "?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT", - "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER", "WITH"}; + "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; return names[m_e]; } bool isSignal() const { @@ -728,7 +727,7 @@ public: bool isProcAssignable() const { return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF - || m_e == MEMBER || m_e == WITH); + || m_e == MEMBER); } bool isTemp() const { return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); @@ -1736,6 +1735,7 @@ public: AstNodeDType* findUInt32DType() { return findBasicDType(AstBasicDTypeKwd::UINT32); } AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } AstNodeDType* findVoidDType() const; + AstNodeDType* findQueueIndexDType() const; AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const; AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const; AstNodeDType* findLogicRangeDType(const VNumRange& range, int widthMin, diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index acd24f932..f6c61dcc0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -875,6 +875,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) { return m_voidp; } +AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) { + if (VL_UNLIKELY(!m_queueIndexp)) { + AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr); + addTypesp(newp); + m_queueIndexp = newp; + } + return m_queueIndexp; +} + AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) { if (m_basicps[kwd]) return m_basicps[kwd]; // diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index da115b3e2..4712c7d31 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1100,6 +1100,12 @@ public: refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve } + AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) + : ASTGEN_SUPER(fl) { + setNOp2p(boundp); + refDTypep(dtp); + dtypep(dtp); + } ASTNODE_NODE_FUNCS(QueueDType) virtual const char* broken() const override { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) @@ -3091,6 +3097,29 @@ public: AstNode* exprp() const { return op2p(); } }; +class AstLambdaArgRef : public AstNodeMath { + // Lambda argument usage + // These are not AstVarRefs because we need to be able to delete/clone lambdas during + // optimizations and AstVar's are painful to remove. +private: + string m_name; // Name of variable + +public: + AstLambdaArgRef(FileLine* fl, const string& name) + : ASTGEN_SUPER(fl) + , m_name{name} {} + ASTNODE_NODE_FUNCS(LambdaArgRef) + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } + virtual string emitVerilog() override { return name(); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return true; } + virtual bool hasDType() const override { return true; } + virtual int instrCount() const override { return widthInstrs(); } + virtual string name() const override { return m_name; } // * = Var name + virtual void name(const string& name) override { m_name = name; } +}; + class AstWith : public AstNodeStmt { // Used as argument to method, then to AstCMethodHard // dtypep() contains the with lambda's return dtype @@ -3098,17 +3127,21 @@ class AstWith : public AstNodeStmt { // Children: VAR that declares the index variable // Children: math (equation establishing the with) public: - AstWith(FileLine* fl, AstVar* varp, AstNode* exprp) + AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp) : ASTGEN_SUPER(fl) { - addOp1p(varp); + addOp1p(argrefp); addNOp2p(exprp); } ASTNODE_NODE_FUNCS(With) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype + return nullptr; + } // - AstVar* varp() const { return VN_CAST(op1p(), Var); } + AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); } AstNode* exprp() const { return op2p(); } }; @@ -9028,6 +9061,7 @@ class AstTypeTable : public AstNode { // Container for hash of standard data types // Children: NODEDTYPEs AstVoidDType* m_voidp = nullptr; + AstQueueDType* m_queueIndexp = nullptr; AstBasicDType* m_basicps[AstBasicDTypeKwd::_ENUM_MAX]; // typedef std::map DetailedMap; @@ -9042,6 +9076,7 @@ public: AstNodeDType* typesp() const { return VN_CAST(op1p(), NodeDType); } // op1 = List of dtypes void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); } AstVoidDType* findVoidDType(FileLine* fl); + AstQueueDType* findQueueIndexDType(FileLine* fl); AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd); AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width, int widthMin, VSigning numeric); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index c67f18c1c..3dcd7fc1e 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -285,6 +285,11 @@ private: ensureCleanAndNext(nodep->pinsp()); setClean(nodep, true); } + virtual void visit(AstWith* nodep) override { + iterateChildren(nodep); + ensureCleanAndNext(nodep->exprp()); + setClean(nodep, true); + } virtual void visit(AstIntfRef* nodep) override { iterateChildren(nodep); setClean(nodep, true); // generates a string, so not relevant diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index c209d55da..b78c82715 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -425,6 +425,18 @@ public: UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, "Statement of non-void data type"); } + virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } + virtual void visit(AstWith* nodep) override { + // With uses a C++11 lambda + putbs("[=]("); + if (auto* argrefp = nodep->argrefp()) { + putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false)); + } + // Probably fragile, V3Task may need to convert to a AstCReturn + puts(") { return "); + iterateAndNextNull(nodep->exprp()); + puts("; }\n"); + } virtual void visit(AstIntfRef* nodep) override { putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect())); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index c73104f5a..2f20432d4 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -90,7 +90,9 @@ public: }; class LinkNodeMatcherVar : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var); } + virtual bool nodeMatch(const AstNode* nodep) const override { + return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef); + } }; class LinkNodeMatcherVarIO : public VNodeMatcher { public: @@ -1270,9 +1272,9 @@ class LinkDotFindVisitor : public AstNVisitor { VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); } // Type depends on the method used, let V3Width figure it out later - auto* varp = new AstVar(argFl, AstVarType::WITH, name, VFlagChildDType(), - new AstParseTypeDType(nodep->fileline())); - auto* newp = new AstWith(nodep->fileline(), varp, nodep->exprp()->unlinkFrBackWithNext()); + auto* argrefp = new AstLambdaArgRef(argFl, name); + auto* newp + = new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext()); funcrefp->addPinsp(newp); nodep->replaceWith(funcrefp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1287,7 +1289,9 @@ class LinkDotFindVisitor : public AstNVisitor { m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep, m_packagep); m_curSymp->fallbackp(oldCurSymp); - iterateChildren(nodep); + UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref"); + // Insert argref's name into symbol table + m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr); } } @@ -1539,6 +1543,11 @@ class LinkDotScopeVisitor : public AstNVisitor { symp->fallbackp(m_modSymp); // No recursion, we don't want to pick up variables } + virtual void visit(AstWith* nodep) override { + VSymEnt* symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr); + symp->fallbackp(m_modSymp); + // No recursion, we don't want to pick up variables + } virtual void visit(AstAssignAlias* nodep) override { // Track aliases created by V3Inline; if we get a VARXREF(aliased_from) // we'll need to replace it with a VARXREF(aliased_to) @@ -2279,6 +2288,14 @@ private: ok = true; m_ds.m_dotText = ""; } + } else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) { + if (allowVar) { + AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name()); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + ok = true; + m_ds.m_dotText = ""; + } } // if (!ok) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 3fd5a7ebd..a56889287 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -193,6 +193,7 @@ private: // TYPES typedef std::map, AstVar*> TableMap; typedef std::map PatVecMap; + typedef std::map DTypeQMap; // STATE WidthVP* m_vup = nullptr; // Current node state @@ -201,11 +202,13 @@ private: = nullptr; // Range for arrayed instantiations, nullptr for normal instantiations AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNodeProcedure* m_procedurep = nullptr; // Current final/always + AstLambdaArgRef* m_lambdaArgRefp = nullptr; // Argument to above lambda AstFunc* m_funcp = nullptr; // Current function AstAttrOf* m_attrp = nullptr; // Current attribute bool m_doGenerate; // Do errors later inside generate statement int m_dtTables = 0; // Number of created data type tables TableMap m_tableMap; // Created tables so can remove duplicates + DTypeQMap m_queueDTypeIndexed; // Queues with given index type // ENUMS enum ExtendRule : uint8_t { @@ -2322,6 +2325,7 @@ private: AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : nullptr; UINFO(9, " from dt " << fromDtp << endl); + userIterateAndNext(fromDtp, WidthVP(SELF, BOTH).p()); if (AstEnumDType* adtypep = VN_CAST(fromDtp, EnumDType)) { methodCallEnum(nodep, adtypep); } else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) { @@ -2345,6 +2349,20 @@ private: << nodep->fromp()->dtypep()->prettyTypeName() << "'"); } } + AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn, + AstNodeDType* returnDtp, AstNodeDType* argDtp) { + UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type"); + if (AstWith* withp = VN_CAST(nodep->pinsp(), With)) { + withp->argrefp()->dtypep(argDtp); + userIterate(withp, WidthVP(returnDtp, BOTH).p()); + withp->unlinkFrBack(); + return withp; + } else if (required) { + nodep->v3error("'with' statement is required for ." << nodep->prettyName() + << " method"); + } + return nullptr; + } void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) { int narg = 0; for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) { @@ -2490,8 +2508,6 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", nullptr); // So don't need num() newp->dtypeSetSigned32(); - newp->didWidth(true); - newp->protect(false); } else if (nodep->name() == "first" // function int first(ref index) || nodep->name() == "last" // || nodep->name() == "next" // @@ -2502,8 +2518,6 @@ private: nodep->name(), // first/last/next/prev index_exprp->unlinkFrBack()); newp->dtypeSetSigned32(); - newp->protect(false); - newp->didWidth(true); } else if (nodep->name() == "exists") { // function int exists(input index) // IEEE really should have made this a "bit" return methodOkArguments(nodep, 1, 1); @@ -2512,32 +2526,72 @@ private: index_exprp->unlinkFrBack()); newp->dtypeSetSigned32(); newp->pure(true); - newp->protect(false); - newp->didWidth(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); - newp->protect(false); newp->makeStatement(); } else { AstNode* index_exprp = methodCallAssocIndexExpr(nodep, adtypep); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); - newp->protect(false); newp->makeStatement(); } } else if (nodep->name() == "sort" || nodep->name() == "rsort" || nodep->name() == "reverse" || nodep->name() == "shuffle") { nodep->v3error("Array method " << nodep->prettyNameQ() << " not legal on associative arrays"); + } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" + || nodep->name() == "sum" || nodep->name() == "product") { + // All value return + AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "r_" + nodep->name(), withp); + newp->dtypeFrom(adtypep->subDTypep()); + if (!nodep->firstAbovep()) { newp->makeStatement(); } + } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" + || nodep->name() == "unique_index") { + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), nullptr); + if (nodep->name() == "unique_index") { + newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); + } else { + newp->dtypeFrom(adtypep); + } + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find" || nodep->name() == "find_first" + || nodep->name() == "find_last") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypeFrom(adtypep); + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" + || nodep->name() == "find_last_index") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); + if (!nodep->firstAbovep()) newp->makeStatement(); } else { nodep->v3error("Unknown built-in associative array method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { + newp->protect(false); newp->didWidth(true); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2571,27 +2625,78 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", nullptr); newp->dtypeFrom(adtypep->subDTypep()); - newp->protect(false); - newp->didWidth(true); } else if (nodep->name() == "size") { methodOkArguments(nodep, 0, 0); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", nullptr); newp->dtypeSetSigned32(); - newp->didWidth(true); - newp->protect(false); } else if (nodep->name() == "delete") { // function void delete() methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); newp->makeStatement(); + } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" + || nodep->name() == "sum" || nodep->name() == "product") { + // All value return + AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "r_" + nodep->name(), withp); + newp->dtypeFrom(adtypep->subDTypep()); + if (!nodep->firstAbovep()) { newp->makeStatement(); } + } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" + || nodep->name() == "sort" || nodep->name() == "rsort") { + AstWith* withp = NULL; + if (nodep->name() == "sort" || nodep->name() == "rsort") { + withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + } + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->makeStatement(); + } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" + || nodep->name() == "unique_index") { + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), nullptr); + if (nodep->name() == "unique_index") { + newp->dtypep(newp->findQueueIndexDType()); + } else { + newp->dtypeFrom(adtypep); + } + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find" || nodep->name() == "find_first" + || nodep->name() == "find_last" || nodep->name() == "find_index") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypeFrom(adtypep); + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" + || nodep->name() == "find_last_index") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypep(newp->findQueueIndexDType()); + if (!nodep->firstAbovep()) newp->makeStatement(); } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { + newp->protect(false); newp->didWidth(true); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2605,23 +2710,18 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", nullptr); newp->dtypeFrom(adtypep->subDTypep()); - newp->protect(false); - newp->didWidth(true); } else if (nodep->name() == "num" // function int num() || nodep->name() == "size") { methodOkArguments(nodep, 0, 0); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", nullptr); newp->dtypeSetSigned32(); - newp->didWidth(true); - newp->protect(false); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); - newp->protect(false); newp->makeStatement(); } else { AstNode* index_exprp = methodCallQueueIndexExpr(nodep); @@ -2629,14 +2729,10 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "pop_front", nullptr); newp->dtypeFrom(adtypep->subDTypep()); - newp->protect(false); - newp->didWidth(true); newp->makeStatement(); } else { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); - newp->protect(false); - newp->didWidth(true); newp->makeStatement(); } } @@ -2649,13 +2745,11 @@ private: if (index_exprp->isZero()) { // insert(0, ...) is a push_front newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "push_front", argp->exprp()->unlinkFrBack()); - newp->protect(false); newp->makeStatement(); } else { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), index_exprp->unlinkFrBack()); newp->addPinsp(argp->exprp()->unlinkFrBack()); - newp->protect(false); newp->makeStatement(); } } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { @@ -2664,8 +2758,6 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr); newp->dtypeFrom(adtypep->subDTypep()); - newp->protect(false); - newp->didWidth(true); if (!nodep->firstAbovep()) { newp->makeStatement(); } } else if (nodep->name() == "push_back" || nodep->name() == "push_front") { methodOkArguments(nodep, 1, 1); @@ -2674,14 +2766,67 @@ private: iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), argp->exprp()->unlinkFrBack()); - newp->protect(false); newp->makeStatement(); + } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" + || nodep->name() == "sum" || nodep->name() == "product") { + AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "r_" + nodep->name(), withp); + newp->dtypeFrom(adtypep->subDTypep()); + if (!nodep->firstAbovep()) { newp->makeStatement(); } + } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" + || nodep->name() == "sort" || nodep->name() == "rsort") { + AstWith* withp = NULL; + if (nodep->name() == "sort" || nodep->name() == "rsort") { + withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + } + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->makeStatement(); + } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" + || nodep->name() == "unique_index") { + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), nullptr); + if (nodep->name() == "unique_index") { + newp->dtypep(newp->findQueueIndexDType()); + } else { + newp->dtypeFrom(adtypep); + } + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find" || nodep->name() == "find_first" + || nodep->name() == "find_last") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypeFrom(adtypep); + if (!nodep->firstAbovep()) newp->makeStatement(); + } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" + || nodep->name() == "find_last_index") { + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), + adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), + nodep->name(), withp); + newp->dtypep(newp->findQueueIndexDType()); + if (!nodep->firstAbovep()) newp->makeStatement(); } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in queue method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } if (newp) { + newp->protect(false); newp->didWidth(true); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2884,6 +3029,18 @@ private: nodep->v3error("Unknown built-in string method " << nodep->prettyNameQ()); } } + AstQueueDType* queueDTypeIndexedBy(AstNodeDType* indexDTypep) { + // Return a Queue data type with the specified index, remembering so can use again if + // needed + if (AstQueueDType* queuep = m_queueDTypeIndexed[indexDTypep]) { + return queuep; + } else { + auto* newp = new AstQueueDType(indexDTypep->fileline(), indexDTypep, nullptr); + v3Global.rootp()->typeTablep()->addTypesp(newp); + m_queueDTypeIndexed[indexDTypep] = newp; + return newp; + } + } virtual void visit(AstNew* nodep) override { if (nodep->didWidthAndSet()) return; @@ -4179,7 +4336,24 @@ private: } virtual void visit(AstWith* nodep) override { // Should otherwise be underneath a method call - nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements in this context"); + AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); + VL_RESTORER(m_lambdaArgRefp); + { + m_lambdaArgRefp = nodep->argrefp(); + userIterateChildren(nodep->argrefp(), nullptr); + if (vdtypep) { + userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p()); + } else { // 'sort with' allows arbitrary type + userIterateAndNext(nodep->exprp(), WidthVP(SELF, PRELIM).p()); + } + nodep->dtypeFrom(nodep->exprp()); + iterateCheckAssign(nodep, "'with' return value", nodep->exprp(), FINAL, + nodep->dtypep()); + } + } + virtual void visit(AstLambdaArgRef* nodep) override { + UASSERT_OBJ(m_lambdaArgRefp, nodep, "LambdaArgRef not underneath with lambda"); + nodep->dtypeFrom(m_lambdaArgRefp); } virtual void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out index 85bbc2913..48e2a0a0f 100644 --- a/test_regress/t/t_array_method.out +++ b/test_regress/t/t_array_method.out @@ -26,10 +26,6 @@ : ... In instance t 38 | qi = q.unique_index; qi.sort; | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_array_method.v:38:31: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 38 | qi = q.unique_index; qi.sort; - | ^~~~ %Error: t/t_array_method.v:40:9: Unknown built-in array method 'reverse' : ... In instance t 40 | q.reverse; @@ -70,10 +66,6 @@ : ... In instance t 61 | qi = q.find_index with (item == 2); qi.sort; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_array_method.v:61:46: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 61 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~ %Error: t/t_array_method.v:63:14: Unknown built-in array method 'find_first_index' : ... In instance t 63 | qi = q.find_first_index with (item == 2); @@ -86,10 +78,6 @@ : ... In instance t 68 | qi = q.find_index with (item == 20); qi.sort; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_array_method.v:68:47: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 68 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ %Error: t/t_array_method.v:70:14: Unknown built-in array method 'find_first_index' : ... In instance t 70 | qi = q.find_first_index with (item == 20); diff --git a/test_regress/t/t_assoc_method.out b/test_regress/t/t_assoc_method.out deleted file mode 100644 index 0f16007ef..000000000 --- a/test_regress/t/t_assoc_method.out +++ /dev/null @@ -1,153 +0,0 @@ -%Error: t/t_assoc_method.v:31:14: Unknown built-in associative array method 'unique' - : ... In instance t - 31 | qv = q.unique; - | ^~~~~~ -%Error: t/t_assoc_method.v:33:15: Unknown built-in associative array method 'unique' - : ... In instance t - 33 | qv = qe.unique; - | ^~~~~~ -%Error: t/t_assoc_method.v:35:14: Unknown built-in associative array method 'unique_index' - : ... In instance t - 35 | qi = q.unique_index; qi.sort; - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:35:31: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 35 | qi = q.unique_index; qi.sort; - | ^~~~ -%Error: t/t_assoc_method.v:37:15: Unknown built-in associative array method 'unique_index' - : ... In instance t - 37 | qv = qe.unique_index; - | ^~~~~~~~~~~~ -%Error: t/t_assoc_method.v:42:14: Unknown built-in associative array method 'find' - : ... In instance t - 42 | qv = q.find with (item == 2); - | ^~~~ -%Error: t/t_assoc_method.v:44:14: Unknown built-in associative array method 'find_first' - : ... In instance t - 44 | qv = q.find_first with (item == 2); - | ^~~~~~~~~~ -%Error: t/t_assoc_method.v:46:14: Unknown built-in associative array method 'find_last' - : ... In instance t - 46 | qv = q.find_last with (item == 2); - | ^~~~~~~~~ -%Error: t/t_assoc_method.v:49:14: Unknown built-in associative array method 'find' - : ... In instance t - 49 | qv = q.find with (item == 20); - | ^~~~ -%Error: t/t_assoc_method.v:51:14: Unknown built-in associative array method 'find_first' - : ... In instance t - 51 | qv = q.find_first with (item == 20); - | ^~~~~~~~~~ -%Error: t/t_assoc_method.v:53:14: Unknown built-in associative array method 'find_last' - : ... In instance t - 53 | qv = q.find_last with (item == 20); - | ^~~~~~~~~ -%Error: t/t_assoc_method.v:56:14: Unknown built-in associative array method 'find_index' - : ... In instance t - 56 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:56:46: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 56 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~ -%Error: t/t_assoc_method.v:58:14: Unknown built-in associative array method 'find_first_index' - : ... In instance t - 58 | qi = q.find_first_index with (item == 2); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_assoc_method.v:60:14: Unknown built-in associative array method 'find_last_index' - : ... In instance t - 60 | qi = q.find_last_index with (item == 2); - | ^~~~~~~~~~~~~~~ -%Error: t/t_assoc_method.v:63:14: Unknown built-in associative array method 'find_index' - : ... In instance t - 63 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assoc_method.v:63:47: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 63 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ -%Error: t/t_assoc_method.v:65:14: Unknown built-in associative array method 'find_first_index' - : ... In instance t - 65 | qi = q.find_first_index with (item == 20); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_assoc_method.v:67:14: Unknown built-in associative array method 'find_last_index' - : ... In instance t - 67 | qi = q.find_last_index with (item == 20); - | ^~~~~~~~~~~~~~~ -%Error: t/t_assoc_method.v:70:14: Unknown built-in associative array method 'min' - : ... In instance t - 70 | qv = q.min; - | ^~~ -%Error: t/t_assoc_method.v:72:14: Unknown built-in associative array method 'max' - : ... In instance t - 72 | qv = q.max; - | ^~~ -%Error: t/t_assoc_method.v:75:15: Unknown built-in associative array method 'min' - : ... In instance t - 75 | qv = qe.min; - | ^~~ -%Error: t/t_assoc_method.v:77:15: Unknown built-in associative array method 'max' - : ... In instance t - 77 | qv = qe.max; - | ^~~ -%Error: t/t_assoc_method.v:82:13: Unknown built-in associative array method 'sum' - : ... In instance t - 82 | i = q.sum; do if ((i) !== (32'hc)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",82, (i), (32'hc)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:83:13: Unknown built-in associative array method 'sum' - : ... In instance t - 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",83, (i), (32'h11)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:84:13: Unknown built-in associative array method 'product' - : ... In instance t - 84 | i = q.product; do if ((i) !== (32'h30)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",84, (i), (32'h30)); $stop; end while(0);; - | ^~~~~~~ -%Error: t/t_assoc_method.v:85:13: Unknown built-in associative array method 'product' - : ... In instance t - 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",85, (i), (32'h168)); $stop; end while(0);; - | ^~~~~~~ -%Error: t/t_assoc_method.v:87:14: Unknown built-in associative array method 'sum' - : ... In instance t - 87 | i = qe.sum; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",87, (i), (32'h0)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:88:14: Unknown built-in associative array method 'product' - : ... In instance t - 88 | i = qe.product; do if ((i) !== (32'h0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",88, (i), (32'h0)); $stop; end while(0);; - | ^~~~~~~ -%Error: t/t_assoc_method.v:91:13: Unknown built-in associative array method 'and' - : ... In instance t - 91 | i = q.and; do if ((i) !== (32'b1000)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",91, (i), (32'b1000)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:92:13: Unknown built-in associative array method 'and' - : ... In instance t - 92 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",92, (i), (32'b1001)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:93:13: Unknown built-in associative array method 'or' - : ... In instance t - 93 | i = q.or; do if ((i) !== (32'b1110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",93, (i), (32'b1110)); $stop; end while(0);; - | ^~ -%Error: t/t_assoc_method.v:94:13: Unknown built-in associative array method 'or' - : ... In instance t - 94 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",94, (i), (32'b1111)); $stop; end while(0);; - | ^~ -%Error: t/t_assoc_method.v:95:13: Unknown built-in associative array method 'xor' - : ... In instance t - 95 | i = q.xor; do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",95, (i), (32'b0110)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:96:13: Unknown built-in associative array method 'xor' - : ... In instance t - 96 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",96, (i), (32'b0110)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:98:14: Unknown built-in associative array method 'and' - : ... In instance t - 98 | i = qe.and; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",98, (i), (32'b0)); $stop; end while(0);; - | ^~~ -%Error: t/t_assoc_method.v:99:14: Unknown built-in associative array method 'or' - : ... In instance t - 99 | i = qe.or; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",99, (i), (32'b0)); $stop; end while(0);; - | ^~ -%Error: t/t_assoc_method.v:100:14: Unknown built-in associative array method 'xor' - : ... In instance t - 100 | i = qe.xor; do if ((i) !== (32'b0)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_assoc_method.v",100, (i), (32'b0)); $stop; end while(0);; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_assoc_method.pl b/test_regress/t/t_assoc_method.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_assoc_method.pl +++ b/test_regress/t/t_assoc_method.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 40e05ca2f..29c8372e1 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -18,7 +18,7 @@ module t (/*AUTOARG*/); string v; q = '{10:1, 11:2, 12:2, 13:4, 14:3}; - v = $sformatf("%p", q); `checks(v, "'{0xa:1, 0xb:2, 0xc:2, 0xd:4, 0xe:3} "); + v = $sformatf("%p", q); `checks(v, "'{'ha:'h1, 'hb:'h2, 'hc:'h2, 'hd:'h4, 'he:'h3} "); // NOT tested: with ... selectors @@ -29,22 +29,22 @@ module t (/*AUTOARG*/); v = $sformatf("%p", qe); `checks(v, "'{}"); qv = q.unique; - v = $sformatf("%p", qv); `checks(v, "'{1, 2, 4, 3} "); + v = $sformatf("%p", qv); `checks(v, "'{'h1, 'h2, 'h4, 'h3} "); qv = qe.unique; v = $sformatf("%p", qv); `checks(v, "'{}"); qi = q.unique_index; qi.sort; - v = $sformatf("%p", qi); `checks(v, "'{10, 11, 13, 14} "); - qv = qe.unique_index; - v = $sformatf("%p", qv); `checks(v, "'{}"); + v = $sformatf("%p", qi); `checks(v, "'{'ha, 'hb, 'hd, 'he} "); + qi = qe.unique_index; + v = $sformatf("%p", qi); `checks(v, "'{}"); // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} "); qv = q.find_first with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find_last with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); @@ -54,11 +54,11 @@ module t (/*AUTOARG*/); v = $sformatf("%p", qv); `checks(v, "'{}"); qi = q.find_index with (item == 2); qi.sort; - v = $sformatf("%p", qi); `checks(v, "'{11, 12} "); + v = $sformatf("%p", qi); `checks(v, "'{'hb, 'hc} "); qi = q.find_first_index with (item == 2); - v = $sformatf("%p", qi); `checks(v, "'{11} "); + v = $sformatf("%p", qi); `checks(v, "'{'hb} "); qi = q.find_last_index with (item == 2); - v = $sformatf("%p", qi); `checks(v, "'{12} "); + v = $sformatf("%p", qi); `checks(v, "'{'hc} "); qi = q.find_index with (item == 20); qi.sort; v = $sformatf("%p", qi); `checks(v, "'{}"); @@ -68,9 +68,9 @@ module t (/*AUTOARG*/); v = $sformatf("%p", qi); `checks(v, "'{}"); qv = q.min; - v = $sformatf("%p", qv); `checks(v, "'{1} "); + v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; - v = $sformatf("%p", qv); `checks(v, "'{4} "); + v = $sformatf("%p", qv); `checks(v, "'{'h4} "); qv = qe.min; v = $sformatf("%p", qv); `checks(v, "'{}"); @@ -79,25 +79,40 @@ module t (/*AUTOARG*/); // Reduction methods - i = q.sum; `checkh(i, 32'hc); - i = q.sum with (item + 1); `checkh(i, 32'h11); - i = q.product; `checkh(i, 32'h30); - i = q.product with (item + 1); `checkh(i, 32'h168); + i = q.sum; + `checkh(i, 32'hc); + i = q.sum with (item + 1); + `checkh(i, 32'h11); + i = q.product; + `checkh(i, 32'h30); + i = q.product with (item + 1); + `checkh(i, 32'h168); - i = qe.sum; `checkh(i, 32'h0); - i = qe.product; `checkh(i, 32'h0); + i = qe.sum; + `checkh(i, 32'h0); + i = qe.product; + `checkh(i, 32'h0); q = '{10:32'b1100, 11:32'b1010}; - i = q.and; `checkh(i, 32'b1000); - i = q.and with (item + 1); `checkh(i, 32'b1001); - i = q.or; `checkh(i, 32'b1110); - i = q.or with (item + 1); `checkh(i, 32'b1111); - i = q.xor; `checkh(i, 32'b0110); - i = q.xor with (item + 1); `checkh(i, 32'b0110); + i = q.and; + `checkh(i, 32'b1000); + i = q.and with (item + 1); + `checkh(i, 32'b1001); + i = q.or; + `checkh(i, 32'b1110); + i = q.or with (item + 1); + `checkh(i, 32'b1111); + i = q.xor; + `checkh(i, 32'b0110); + i = q.xor with (item + 1); + `checkh(i, 32'b0110); - i = qe.and; `checkh(i, 32'b0); - i = qe.or; `checkh(i, 32'b0); - i = qe.xor; `checkh(i, 32'b0); + i = qe.and; + `checkh(i, 32'b0); + i = qe.or; + `checkh(i, 32'b0); + i = qe.xor; + `checkh(i, 32'b0); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_dynarray_method.pl b/test_regress/t/t_dynarray_method.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_dynarray_method.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dynarray_method.v b/test_regress/t/t_dynarray_method.v new file mode 100644 index 000000000..21a778dc5 --- /dev/null +++ b/test_regress/t/t_dynarray_method.v @@ -0,0 +1,168 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + + string s[] = { "hello", "sad", "sad", "world" }; + + initial begin + int d[]; + int de[]; // Empty + int qv[$]; // Value returns + int qvunused[$]; // Value returns (unused) + int qi[$]; // Index returns + int i; + string v; + + d = '{1, 2, 2, 4, 3}; + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} "); + d = {1, 2, 2, 4, 3}; + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} "); + + // sort/rsort with clause is the field to use for the sorting + d.sort; + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + d.sort with (10 - item); + v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + d.sort(x) with (10 - x); + v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + de.sort(x) with (10 - x); + v = $sformatf("%p", de); `checks(v, "'{}"); + d.rsort; + v = $sformatf("%p", d); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); + d.rsort with (10 - item); + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + de.rsort(x) with (10 - x); + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + + d = '{2, 2, 4, 1, 3}; + qv = d.unique; + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h4, 'h1, 'h3} "); + qv = de.unique; + `checkh(qv.size(), 0); + qi = d.unique_index; qv.sort; + v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h2, 'h3, 'h4} "); + qi = de.unique_index; + `checkh(qi.size(), 0); + + d.reverse; + v = $sformatf("%p", d); `checks(v, "'{'h3, 'h1, 'h4, 'h2, 'h2} "); + de.reverse; + `checkh(de.size(), 0); + d.shuffle(); d.sort; + v = $sformatf("%p", d); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); + de.shuffle(); + `checkh(de.size(), 0); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = d.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} "); + qv = d.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); + qv = d.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); + + qv = d.find with (item == 20); + `checkh(qv.size, 0); + qv = d.find_first with (item == 20); + `checkh(qv.size, 0); + qv = d.find_last with (item == 20); + `checkh(qv.size, 0); + + // Check gate eater with Lambda variable removal + qvunused = d.find with (item == 20); + + qi = d.find_index with (item == 2); + qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); + qi = d.find_first_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h1} "); + qi = d.find_last_index with (item == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + + i = 2; + qi = d.find_index with (item == i); + qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); + + qi = d.find_index with (item == 20); qi.sort; + `checkh(qi.size, 0); + qi = d.find_first_index with (item == 20); + `checkh(qi.size, 0); + qi = d.find_last_index with (item == 20); + `checkh(qi.size, 0); + + qv = d.min; + v = $sformatf("%p", qv); `checks(v, "'{'h1} "); + qv = d.max; + v = $sformatf("%p", qv); `checks(v, "'{'h4} "); + qv = de.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = de.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + i = d.sum; + `checkh(i, 32'hc); + i = d.sum with (item + 1); + `checkh(i, 32'h11); + i = d.sum(myi) with (myi + 1); + `checkh(i, 32'h11); + i = d.sum with (1); // unused 'index' + `checkh(i, 32'h5); + i = d.sum(unused) with (1); // unused 'unused' + `checkh(i, 32'h5); + + i = d.product; + `checkh(i, 32'h30); + i = d.product with (item + 1); + `checkh(i, 32'h168); + + i = de.sum; + `checkh(i, 32'h0); + + i = de.product; + `checkh(i, 32'h0); + + d = '{32'b1100, 32'b1010}; + + i = d.and; + `checkh(i, 32'b1000); + i = d.and with (item + 1); + `checkh(i, 32'b1001); + i = d.or; + `checkh(i, 32'b1110); + i = d.or with (item + 1); + `checkh(i, 32'b1111); + i = d.xor; + `checkh(i, 32'b0110); + i = d.xor with (item + 1); + `checkh(i, 32'b0110); + + i = de.and; + `checkh(i, 32'b0); + i = de.or; + `checkh(i, 32'b0); + i = de.xor; + `checkh(i, 32'b0); + + `checks(s[1], "sad"); + qi = s.find_first_index with (item == "sad"); + `checkh(qi.size, 1); + `checkh(qi[0], 1); + qi = s.find_last_index with (item == "sad"); + `checkh(qi.size, 1); + `checkh(qi[0], 2); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_method.out b/test_regress/t/t_queue_method.out deleted file mode 100644 index 57e6f4f83..000000000 --- a/test_regress/t/t_queue_method.out +++ /dev/null @@ -1,201 +0,0 @@ -%Error-UNSUPPORTED: t/t_queue_method.v:26:9: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 26 | q.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:28:9: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 28 | q.sort with (10 - item); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:30:9: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 30 | q.sort(x) with (10 - x); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:32:10: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 32 | qe.sort(x) with (10 - x); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:34:9: Unsupported/unknown built-in queue method 'rsort' - : ... In instance t - 34 | q.rsort; - | ^~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:36:9: Unsupported/unknown built-in queue method 'rsort' - : ... In instance t - 36 | q.rsort with (10 - item); - | ^~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:38:10: Unsupported/unknown built-in queue method 'rsort' - : ... In instance t - 38 | qe.rsort(x) with (10 - x); - | ^~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:42:14: Unsupported/unknown built-in queue method 'unique' - : ... In instance t - 42 | qv = q.unique; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:44:15: Unsupported/unknown built-in queue method 'unique' - : ... In instance t - 44 | qv = qe.unique; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:46:14: Unsupported/unknown built-in queue method 'unique_index' - : ... In instance t - 46 | qi = q.unique_index; qv.sort; - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:46:31: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 46 | qi = q.unique_index; qv.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:48:15: Unsupported/unknown built-in queue method 'unique_index' - : ... In instance t - 48 | qi = qe.unique_index; - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:51:9: Unsupported/unknown built-in queue method 'reverse' - : ... In instance t - 51 | q.reverse; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:53:10: Unsupported/unknown built-in queue method 'reverse' - : ... In instance t - 53 | qe.reverse; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:55:9: Unsupported/unknown built-in queue method 'shuffle' - : ... In instance t - 55 | q.shuffle(); q.sort; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:55:22: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 55 | q.shuffle(); q.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:57:10: Unsupported/unknown built-in queue method 'shuffle' - : ... In instance t - 57 | qe.shuffle(); - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:62:14: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 62 | qv = q.find with (item == 2); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:64:14: Unsupported/unknown built-in queue method 'find_first' - : ... In instance t - 64 | qv = q.find_first with (item == 2); - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:66:14: Unsupported/unknown built-in queue method 'find_last' - : ... In instance t - 66 | qv = q.find_last with (item == 2); - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:69:14: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 69 | qv = q.find with (item == 20); - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:71:14: Unsupported/unknown built-in queue method 'find_first' - : ... In instance t - 71 | qv = q.find_first with (item == 20); - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:73:14: Unsupported/unknown built-in queue method 'find_last' - : ... In instance t - 73 | qv = q.find_last with (item == 20); - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:76:14: Unsupported/unknown built-in queue method 'find_index' - : ... In instance t - 76 | qi = q.find_index with (item == 2); - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:77:10: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 77 | qi.sort; v = $sformatf("%p", qi); do if ((v) !== ("'{'h1, 'h2} ")) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", "t/t_queue_method.v",77, (v), ("'{'h1, 'h2} ")); $stop; end while(0);; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:78:14: Unsupported/unknown built-in queue method 'find_first_index' - : ... In instance t - 78 | qi = q.find_first_index with (item == 2); - | ^~~~~~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:80:14: Unsupported/unknown built-in queue method 'find_last_index' - : ... In instance t - 80 | qi = q.find_last_index with (item == 2); - | ^~~~~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:83:14: Unsupported/unknown built-in queue method 'find_index' - : ... In instance t - 83 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:83:47: Unsupported/unknown built-in queue method 'sort' - : ... In instance t - 83 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:85:14: Unsupported/unknown built-in queue method 'find_first_index' - : ... In instance t - 85 | qi = q.find_first_index with (item == 20); - | ^~~~~~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:87:14: Unsupported/unknown built-in queue method 'find_last_index' - : ... In instance t - 87 | qi = q.find_last_index with (item == 20); - | ^~~~~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:90:14: Unsupported/unknown built-in queue method 'min' - : ... In instance t - 90 | qv = q.min; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:92:14: Unsupported/unknown built-in queue method 'max' - : ... In instance t - 92 | qv = q.max; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:94:15: Unsupported/unknown built-in queue method 'min' - : ... In instance t - 94 | qv = qe.min; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:96:15: Unsupported/unknown built-in queue method 'max' - : ... In instance t - 96 | qv = qe.max; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:100:13: Unsupported/unknown built-in queue method 'sum' - : ... In instance t - 100 | i = q.sum; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:102:13: Unsupported/unknown built-in queue method 'sum' - : ... In instance t - 102 | i = q.sum with (item + 1); - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:104:13: Unsupported/unknown built-in queue method 'product' - : ... In instance t - 104 | i = q.product; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:106:13: Unsupported/unknown built-in queue method 'product' - : ... In instance t - 106 | i = q.product with (item + 1); - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:109:14: Unsupported/unknown built-in queue method 'sum' - : ... In instance t - 109 | i = qe.sum; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:111:14: Unsupported/unknown built-in queue method 'product' - : ... In instance t - 111 | i = qe.product; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method.v:115:13: Unsupported/unknown built-in queue method 'and' - : ... In instance t - 115 | i = q.and; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:117:13: Unsupported/unknown built-in queue method 'and' - : ... In instance t - 117 | i = q.and with (item + 1); - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:119:13: Unsupported/unknown built-in queue method 'or' - : ... In instance t - 119 | i = q.or; - | ^~ -%Error-UNSUPPORTED: t/t_queue_method.v:121:13: Unsupported/unknown built-in queue method 'or' - : ... In instance t - 121 | i = q.or with (item + 1); - | ^~ -%Error-UNSUPPORTED: t/t_queue_method.v:123:13: Unsupported/unknown built-in queue method 'xor' - : ... In instance t - 123 | i = q.xor; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:125:13: Unsupported/unknown built-in queue method 'xor' - : ... In instance t - 125 | i = q.xor with (item + 1); - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:128:14: Unsupported/unknown built-in queue method 'and' - : ... In instance t - 128 | i = qe.and; - | ^~~ -%Error-UNSUPPORTED: t/t_queue_method.v:130:14: Unsupported/unknown built-in queue method 'or' - : ... In instance t - 130 | i = qe.or; - | ^~ -%Error-UNSUPPORTED: t/t_queue_method.v:132:14: Unsupported/unknown built-in queue method 'xor' - : ... In instance t - 132 | i = qe.xor; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_queue_method.pl b/test_regress/t/t_queue_method.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_queue_method.pl +++ b/test_regress/t/t_queue_method.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index 5e0e478fb..d5429c88d 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -15,6 +15,7 @@ module t (/*AUTOARG*/); int q[$]; int qe[$]; // Empty int qv[$]; // Value returns + int qvunused[$]; // Value returns (unused) int qi[$]; // Index returns int i; string v; @@ -73,6 +74,9 @@ module t (/*AUTOARG*/); qv = q.find_last with (item == 20); `checkh(qv.size, 0); + // Check gate eater with Lambda variable removal + qvunused = q.find with (item == 20); + qi = q.find_index with (item == 2); qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); qi = q.find_first_index with (item == 2); @@ -80,6 +84,10 @@ module t (/*AUTOARG*/); qi = q.find_last_index with (item == 2); v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + i = 2; + qi = q.find_index with (item == i); + qi.sort; v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); + qi = q.find_index with (item == 20); qi.sort; `checkh(qi.size, 0); qi = q.find_first_index with (item == 20); @@ -101,6 +109,13 @@ module t (/*AUTOARG*/); `checkh(i, 32'hc); i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.sum(myi) with (myi + 1); + `checkh(i, 32'h11); + i = q.sum with (1); // unused 'index' + `checkh(i, 32'h5); + i = q.sum(unused) with (1); // unused 'unused' + `checkh(i, 32'h5); + i = q.product; `checkh(i, 32'h30); i = q.product with (item + 1); @@ -108,6 +123,7 @@ module t (/*AUTOARG*/); i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); diff --git a/test_regress/t/t_queue_method_bad.out b/test_regress/t/t_queue_method_bad.out index 429388dca..584d57b0f 100755 --- a/test_regress/t/t_queue_method_bad.out +++ b/test_regress/t/t_queue_method_bad.out @@ -1,37 +1,37 @@ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:15:14: Unsupported/unknown built-in queue method 'unique' - : ... In instance t +%Error: t/t_queue_method_bad.v:15:21: 'with' not legal on this method + : ... In instance t 15 | qv = q.unique with (1); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:16:9: Unsupported/unknown built-in queue method 'reverse' - : ... In instance t + | ^~~~ +%Error: t/t_queue_method_bad.v:16:9: The 1 arguments passed to .reverse method does not match its requiring 0 arguments + : ... In instance t 16 | q.reverse(1); | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:17:9: Unsupported/unknown built-in queue method 'shuffle' - : ... In instance t +%Error: t/t_queue_method_bad.v:17:9: The 1 arguments passed to .shuffle method does not match its requiring 0 arguments + : ... In instance t 17 | q.shuffle(1); | ^~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:18:14: Unsupported/unknown built-in queue method 'find' - : ... In instance t +%Error: t/t_queue_method_bad.v:18:14: 'with' statement is required for .find method + : ... In instance t 18 | qv = q.find; | ^~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:19:14: Unsupported/unknown built-in queue method 'find_first' - : ... In instance t +%Error: t/t_queue_method_bad.v:19:14: 'with' statement is required for .find_first method + : ... In instance t 19 | qv = q.find_first; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:20:14: Unsupported/unknown built-in queue method 'find_last' - : ... In instance t +%Error: t/t_queue_method_bad.v:20:14: 'with' statement is required for .find_last method + : ... In instance t 20 | qv = q.find_last; | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:21:14: Unsupported/unknown built-in queue method 'find_index' - : ... In instance t +%Error: t/t_queue_method_bad.v:21:14: 'with' statement is required for .find_index method + : ... In instance t 21 | qi = q.find_index; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:22:14: Unsupported/unknown built-in queue method 'find_first_index' - : ... In instance t +%Error: t/t_queue_method_bad.v:22:14: 'with' statement is required for .find_first_index method + : ... In instance t 22 | qi = q.find_first_index; | ^~~~~~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_queue_method_bad.v:23:14: Unsupported/unknown built-in queue method 'find_last_index' - : ... In instance t +%Error: t/t_queue_method_bad.v:23:14: 'with' statement is required for .find_last_index method + : ... In instance t 23 | qi = q.find_last_index; | ^~~~~~~~~~~~~~~ %Error: t/t_queue_method_bad.v:25:19: 'with' not legal on this method diff --git a/test_regress/t/t_with.out b/test_regress/t/t_with.out deleted file mode 100644 index 4b4dae672..000000000 --- a/test_regress/t/t_with.out +++ /dev/null @@ -1,41 +0,0 @@ -%Error-UNSUPPORTED: t/t_with.v:19:23: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 19 | found = aliases.find(i) with (i == tofind); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:21:15: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 21 | aliases.find(i) with (i == tofind); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:24:23: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 24 | found = aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:25:15: Unsupported/unknown built-in queue method 'find' - : ... In instance t - 25 | aliases.find with (item == i); - | ^~~~ -%Error-UNSUPPORTED: t/t_with.v:29:23: Unsupported/unknown built-in queue method 'unique' - : ... In instance t - 29 | found = aliases.unique with (id); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_with.v:30:23: Unsupported/unknown built-in queue method 'unique' - : ... In instance t - 30 | found = aliases.unique() with (id); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_with.v:31:23: Unsupported/unknown built-in queue method 'unique' - : ... In instance t - 31 | found = aliases.unique(i) with (id); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_with.v:32:19: Unsupported/unknown built-in queue method 'or' - : ... In instance t - 32 | i = aliases.or(v) with (v); - | ^~ -%Error-UNSUPPORTED: t/t_with.v:33:19: Unsupported/unknown built-in queue method 'and' - : ... In instance t - 33 | i = aliases.and(v) with (v); - | ^~~ -%Error-UNSUPPORTED: t/t_with.v:34:19: Unsupported/unknown built-in queue method 'xor' - : ... In instance t - 34 | i = aliases.xor(v) with (v); - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_with.pl b/test_regress/t/t_with.pl index c6e10f70b..c81275cdf 100755 --- a/test_regress/t/t_with.pl +++ b/test_regress/t/t_with.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_with.v b/test_regress/t/t_with.v index c0989a818..015cdc295 100644 --- a/test_regress/t/t_with.v +++ b/test_regress/t/t_with.v @@ -14,9 +14,11 @@ module t (/*AUTOARG*/); int found[$]; int id; int i; + aliases = '{ 1, 4, 6, 8}; tofind = 6; - found = aliases.find(i) with (i == tofind); + found = aliases.find with (item == 1); + found = aliases.find(j) with (j == tofind); // And as function aliases.find(i) with (i == tofind); @@ -26,9 +28,9 @@ module t (/*AUTOARG*/); // Unique (array method) id = 4; - found = aliases.unique with (id); - found = aliases.unique() with (id); - found = aliases.unique(i) with (id); + found = aliases.find with (id); + found = aliases.find() with (item == id); + found = aliases.find(i) with (i == id); i = aliases.or(v) with (v); i = aliases.and(v) with (v); i = aliases.xor(v) with (v); diff --git a/test_regress/t/t_with_suggest_bad.out b/test_regress/t/t_with_suggest_bad.out new file mode 100644 index 000000000..2ad8ff9de --- /dev/null +++ b/test_regress/t/t_with_suggest_bad.out @@ -0,0 +1,9 @@ +%Error: t/t_with_suggest_bad.v:16:25: Can't find definition of variable: 'itemm' + : ... Suggested alternative: 'item' + 16 | qv = q.find with (itemm == 2); + | ^~~~~ +%Error: t/t_with_suggest_bad.v:18:37: Can't find definition of variable: 'misspelledd' + : ... Suggested alternative: 'misspelled' + 18 | qv = q.find(misspelled) with (misspelledd == 2); + | ^~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_with_suggest_bad.pl b/test_regress/t/t_with_suggest_bad.pl new file mode 100755 index 000000000..85114ac5d --- /dev/null +++ b/test_regress/t/t_with_suggest_bad.pl @@ -0,0 +1,20 @@ +#!/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( + verilator_flags2 => ["--lint-only --language 1800-2017"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_with_suggest_bad.v b/test_regress/t/t_with_suggest_bad.v new file mode 100644 index 000000000..144f18dbb --- /dev/null +++ b/test_regress/t/t_with_suggest_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias' +// +// Simple bi-directional alias test. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + int q[$]; + int qv[$]; // Value returns + q = '{1, 2, 2, 4, 3}; + + qv = q.find with (itemm == 2); + + qv = q.find(misspelled) with (misspelledd == 2); + end + +endmodule From 80284c437e4c9c77e88c29ac9bbdb2cc9d900439 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 16:59:23 -0500 Subject: [PATCH 47/88] Internals: Refactor some VAssign printing. No functional change. --- src/V3Ast.h | 4 ++++ src/V3AstNodes.cpp | 16 ++++------------ src/V3Const.cpp | 2 +- src/V3Gate.cpp | 2 +- src/V3Tristate.cpp | 2 +- src/V3Unroll.cpp | 2 +- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index ab8baf611..45f6e9ae6 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -131,6 +131,10 @@ public: static const char* const names[] = {"RD", "WR"}; return names[m_e]; } + const char* arrow() const { + static const char* const names[] = {"[RV] <-", "[LV] =>"}; + return names[m_e]; + } inline VAccess() : m_e{READ} {} // cppcheck-suppress noExplicitConstructor diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index f6c61dcc0..b5dc6d2b2 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1453,12 +1453,8 @@ void AstVarScope::dump(std::ostream& str) const { void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstVarXRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); - if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } - if (access().isWrite()) { - str << " [LV] => "; - } else { - str << " [RV] <- "; - } + if (packagep()) str << " pkg=" << nodeAddr(packagep()); + str << " " << access().arrow() << " "; str << ".=" << dotted() << " "; if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - "; if (varScopep()) { @@ -1471,12 +1467,8 @@ void AstVarXRef::dump(std::ostream& str) const { } void AstVarRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); - if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } - if (access().isWrite()) { - str << " [LV] => "; - } else { - str << " [RV] <- "; - } + if (packagep()) str << " pkg=" << nodeAddr(packagep()); + str << " " << access().arrow() << " "; if (varScopep()) { varScopep()->dump(str); } else if (varp()) { diff --git a/src/V3Const.cpp b/src/V3Const.cpp index ed0e10b04..cc05c126c 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -314,7 +314,7 @@ private: // It was an expression, then got constified. In reality, the WordSel // must be wrapped in a Cond, that will be false. return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef) - && !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite() + && VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isReadOnly() && (static_cast(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt()) >= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords())); } diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 92fb406f8..e5a1ae68a 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -448,7 +448,7 @@ private: vvertexp->setIsClock(); // For SYNCASYNCNET varscp->user2(true); - } else if (m_activep && m_activep->hasClocked() && !nodep->access().isWrite()) { + } else if (m_activep && m_activep->hasClocked() && nodep->access().isReadOnly()) { if (varscp->user2()) { if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep); } else { diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 1bcf41c3f..dad10cffc 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1237,7 +1237,7 @@ class TristateVisitor : public TristateBaseVisitor { UINFO(9, " Ref-to-lvalue " << nodep << endl); m_tgraph.didProcess(nodep); mapInsertLhsVarRef(nodep); - } else if (!nodep->access().isWrite() + } else if (nodep->access().isReadOnly() // Not already processed, nor varref from visit(AstPin) creation && !nodep->user1p() // Reference to another tristate variable diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index a94de57ac..38fb4e602 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -451,7 +451,7 @@ private: } if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp - && !nodep->access().isWrite()) { + && nodep->access().isReadOnly()) { AstNode* newconstp = m_varValuep->cloneTree(false); nodep->replaceWith(newconstp); pushDeletep(nodep); From 5821048df76eb757bd7dc614dd0b2840a9bd5f9c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 17:17:32 -0500 Subject: [PATCH 48/88] Fix clang warning. --- src/V3AstNodes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4712c7d31..facf04f6c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3113,7 +3113,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } virtual string emitVerilog() override { return name(); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const { return true; } + virtual bool cleanOut() const override { return true; } virtual bool hasDType() const override { return true; } virtual int instrCount() const override { return widthInstrs(); } virtual string name() const override { return m_name; } // * = Var name From b663d1a230cd208475cf0e3000cb6721b29509dc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 20:52:21 -0500 Subject: [PATCH 49/88] Rename internal interface references, part of #2614. --- src/V3LinkDot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2f20432d4..f027d7cda 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1861,8 +1861,8 @@ private: AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, AstModport* modportp) { // Create iface variable, using duplicate var when under same module scope - string varName = ifacep->name() + "__Vmp__" + modportp->name() + "__Viftop" - + cvtToStr(++m_modportNum); + string varName + = cellp->name() + "__Vmp__" + modportp->name() + "__Viftop" + cvtToStr(++m_modportNum); AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(), ifacep->name(), modportp->name()); idtypep->cellp(cellp); From 2ce86eddfa704a4e1181285d059a5be884bee6ad Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 1 Nov 2020 22:27:27 -0500 Subject: [PATCH 50/88] Internal debug. No functional change. --- src/V3LinkDot.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index f027d7cda..3ee315a8a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -446,6 +446,8 @@ public: if (!ifacerefp->ifaceViaCellp()) { if (!ifacerefp->cellp()) { // Probably a NotFoundModule, or a normal module if // made mistake + UINFO(1, "Associated cell " << AstNode::prettyNameQ(ifacerefp->cellName()) + << endl); ifacerefp->v3error("Cannot find file containing interface: " << AstNode::prettyNameQ(ifacerefp->ifaceName())); continue; @@ -2025,7 +2027,7 @@ private: } else { m_ds.m_dotPos = DP_SCOPE; iterateAndNextNull(nodep->lhsp()); - // if (debug()>=9) nodep->dumpTree("-dot-lho: "); + // if (debug() >= 9) nodep->dumpTree("-dot-lho: "); } if (m_ds.m_unresolved && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { @@ -2254,6 +2256,7 @@ private: // A scope reference into an interface's modport (not // necessarily at a pin connection) UINFO(9, "cell-ref-to-modport " << m_ds.m_dotText << " " << nodep << endl); + UINFO(9, "unlinked " << m_ds.m_unlinkedScopep << endl); UINFO(9, "dotSymp " << m_ds.m_dotSymp << " " << m_ds.m_dotSymp->nodep() << endl); // Iface was the previously dotted component if (!m_ds.m_dotSymp || !VN_IS(m_ds.m_dotSymp->nodep(), Cell) From 0145d9d51420a089e49c12d3b595d2d80ce38b76 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 2 Nov 2020 19:55:01 -0500 Subject: [PATCH 51/88] Fix C++14 deprecated random_shuffle. --- include/verilated_heavy.h | 4 ++-- src/V3SplitVar.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 9e23181a8..49acd61ce 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -247,8 +247,8 @@ public: } void reverse() { std::reverse(m_deque.begin(), m_deque.end()); } void shuffle() { - std::random_shuffle(m_deque.begin(), m_deque.end(), - [=](int) { return VL_RANDOM_I(32) % m_deque.size(); }); + std::shuffle(m_deque.begin(), m_deque.end(), + [=](int) { return VL_RANDOM_I(32) % m_deque.size(); }); } VlQueue unique() const { VlQueue out; diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 0612174e4..9e1b4590d 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -1211,10 +1211,9 @@ public: , m_numSplit{0} { // If you want ignore refs and walk the tne entire AST, // just call iterateChildren(m_modp) and split() for each module - for (SplitVarRefsMap::iterator it = refs.begin(), it_end = refs.end(); it != it_end; - ++it) { - m_modp = it->first; - it->second.visit(this); + for (auto& i : refs) { + m_modp = i.first; + i.second.visit(this); split(); m_modp = nullptr; } @@ -1246,7 +1245,7 @@ public: return reason; } VL_DEBUG_FUNC; // Declare debug() -}; + }; const char* SplitVarImpl::cannotSplitPackedVarReason(const AstVar* varp) { return SplitPackedVarVisitor::cannotSplitReason(varp, true); From 48bcf66ac7719e6ab8d553b2abfeec40fa37334f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 2 Nov 2020 20:07:43 -0500 Subject: [PATCH 52/88] Fix C++14 deprecated random_shuffle. --- include/verilated_heavy.h | 16 ++++++++++++---- src/V3SplitVar.cpp | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 49acd61ce..161481767 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -43,6 +43,17 @@ extern std::string VL_TO_STRING(QData lhs); inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; } extern std::string VL_TO_STRING_W(int words, WDataInP obj); +//=================================================================== +// Shuffle RNG + +class VlURNG { +public: + typedef size_t result_type; + static size_t min() { return 0; } + static size_t max() { return 1ULL << 31; } + size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); } +}; + //=================================================================== // Readmem/Writemem operation classes @@ -246,10 +257,7 @@ public: [=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); }); } void reverse() { std::reverse(m_deque.begin(), m_deque.end()); } - void shuffle() { - std::shuffle(m_deque.begin(), m_deque.end(), - [=](int) { return VL_RANDOM_I(32) % m_deque.size(); }); - } + void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); } VlQueue unique() const { VlQueue out; std::set saw; diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 9e1b4590d..b5bd06e1a 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -1245,7 +1245,7 @@ public: return reason; } VL_DEBUG_FUNC; // Declare debug() - }; +}; const char* SplitVarImpl::cannotSplitPackedVarReason(const AstVar* varp) { return SplitPackedVarVisitor::cannotSplitReason(varp, true); From 0505816d311a295da273318866c2332de159af3f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 3 Nov 2020 08:52:47 -0500 Subject: [PATCH 53/88] Fix C++14 deprecated random_shuffle. --- include/verilated_heavy.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 161481767..0e58fe4cb 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -49,8 +49,8 @@ extern std::string VL_TO_STRING_W(int words, WDataInP obj); class VlURNG { public: typedef size_t result_type; - static size_t min() { return 0; } - static size_t max() { return 1ULL << 31; } + static constexpr size_t min() { return 0; } + static constexpr size_t max() { return 1ULL << 31; } size_t operator()() { return VL_MASK_I(31) & VL_RANDOM_I(32); } }; From 75881754a97108d461a4075833855def3e13905f Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Wed, 4 Nov 2020 06:08:03 +0900 Subject: [PATCH 54/88] Fix dangling reference (Issue #2622) (#2623) * collect multiple string literals of "__Vcvt". No functional change is intended. * temporary variable for DPI-C should be static if its type is string * Update src/V3EmitC.cpp Co-authored-by: Wilson Snyder Co-authored-by: Wilson Snyder --- src/V3EmitC.cpp | 11 +++++++++++ src/V3Task.cpp | 27 +++++++++++++++++---------- src/V3Task.h | 1 + 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index b78c82715..6109ff891 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -23,6 +23,7 @@ #include "V3EmitCBase.h" #include "V3Number.h" #include "V3PartitionGraph.h" +#include "V3Task.h" #include "V3TSP.h" #include @@ -1904,6 +1905,16 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) { puts(");\n"); } else { // strings and other fundamental c types + if (nodep->isFuncLocal() && nodep->isString()) { + const string name = nodep->name(); + const string suffix = V3Task::dpiTemporaryVarSuffix(); + // string temporary variable for DPI-C needs to be static because c_str() will be + // passed to C code and the lifetime of the variable must be long enough. See also + // Issue 2622. + const bool beStatic = name.size() >= suffix.size() + && name.substr(name.size() - suffix.size()) == suffix; + if (beStatic) puts("static VL_THREAD_LOCAL "); + } puts(nodep->vlArgType(true, false, false, prefixIfImp)); puts(";\n"); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index ffe957a22..2f58f79f0 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -683,6 +683,7 @@ private: } void makeDpiExportWrapper(AstNodeFTask* nodep, AstVar* rtnvarp) { + const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix(); AstCFunc* dpip = new AstCFunc(nodep->fileline(), nodep->cname(), m_scopep, (rtnvarp ? rtnvarp->dpiArgType(true, true) : "")); dpip->dontCombine(true); @@ -737,7 +738,7 @@ private: argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args = ""; } - AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp); + AstVarScope* outvscp = createFuncVar(dpip, portp->name() + tmpSuffixp, portp); // No information exposure; is already visible in import/export func template outvscp->varp()->protect(false); portp->protect(false); @@ -764,7 +765,7 @@ private: argnodesp = argnodesp->addNext(new AstText(portp->fileline(), args, true)); args = ""; } - AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp); + AstVarScope* outvscp = createFuncVar(dpip, portp->name() + tmpSuffixp, portp); // No information exposure; is already visible in import/export func template outvscp->varp()->protect(false); AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, @@ -789,14 +790,14 @@ private: for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && portp->isWritable() && !portp->isFuncReturn()) { - dpip->addStmtsp(createAssignInternalToDpi(portp, true, "__Vcvt", "")); + dpip->addStmtsp(createAssignInternalToDpi(portp, true, tmpSuffixp, "")); } } } if (rtnvarp) { dpip->addStmtsp(createDpiTemp(rtnvarp, "")); - dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, false, "__Vcvt", "")); + dpip->addStmtsp(createAssignInternalToDpi(rtnvarp, false, tmpSuffixp, "")); string stmt = "return " + rtnvarp->name(); stmt += rtnvarp->basicp()->isDpiPrimitive() ? ";\n" : "[0];\n"; dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); @@ -873,6 +874,7 @@ private: } void bodyDpiImportFunc(AstNodeFTask* nodep, AstVarScope* rtnvscp, AstCFunc* cfuncp) { + const char* const tmpSuffixp = V3Task::dpiTemporaryVarSuffix(); // Convert input/inout arguments to DPI types string args; for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { @@ -914,12 +916,12 @@ private: args += "&"; } - args += portp->name() + "__Vcvt"; + args += portp->name() + tmpSuffixp; - cfuncp->addStmtsp(createDpiTemp(portp, "__Vcvt")); + cfuncp->addStmtsp(createDpiTemp(portp, tmpSuffixp)); if (portp->isNonOutput()) { cfuncp->addStmtsp( - createAssignInternalToDpi(portp, false, "", "__Vcvt")); + createAssignInternalToDpi(portp, false, "", tmpSuffixp)); } } } @@ -935,8 +937,8 @@ private: { // Call the user function string stmt; if (rtnvscp) { // isFunction will no longer work as we unlinked the return var - cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), "__Vcvt")); - stmt = rtnvscp->varp()->name() + "__Vcvt"; + cfuncp->addStmtsp(createDpiTemp(rtnvscp->varp(), tmpSuffixp)); + stmt = rtnvscp->varp()->name() + tmpSuffixp; stmt += rtnvscp->varp()->basicp()->isDpiPrimitive() ? " = " : "[0] = "; } stmt += nodep->cname() + "(" + args + ");\n"; @@ -952,7 +954,7 @@ private: AstVarScope* portvscp = VN_CAST( portp->user2p(), VarScope); // Remembered when we created it earlier cfuncp->addStmtsp( - createAssignDpiToInternal(portvscp, portp->name() + "__Vcvt")); + createAssignDpiToInternal(portvscp, portp->name() + tmpSuffixp)); } } } @@ -1577,6 +1579,11 @@ bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& fr return false; } +const char* V3Task::dpiTemporaryVarSuffix() { + static const char suffix[] = "__Vcvt"; + return suffix; +} + void V3Task::taskAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { diff --git a/src/V3Task.h b/src/V3Task.h index 90eed1bab..a1722a16c 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -40,6 +40,7 @@ public: static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix = ""); static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt); + static const char* dpiTemporaryVarSuffix(); }; #endif // Guard From 1c2384cb3dfe854f03dd38fbf8a6d3e906462c15 Mon Sep 17 00:00:00 2001 From: Kaleb Barrett Date: Fri, 6 Nov 2020 16:56:15 -0600 Subject: [PATCH 55/88] Fix iteration over mutating list bug in VPI impl (#2588) Previously, in any given VPI callback, if the callback body registered the same callback, that registering would be processed in the currently executing call to the call*Cbs function. In the worse case, this could lead to an infinite loop. --- docs/CONTRIBUTORS | 1 + include/verilated_vpi.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 15b7a2e5a..acca96c0d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -33,6 +33,7 @@ John Coiner John Demme Josh Redford Julien Margetts +Kaleb Barrett Kanad Kanhere Kevin Kiningham Kuba Ober diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 46d6d8707..931df8210 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -477,7 +477,8 @@ public: static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { VpioCbList& cbObjList = s_s.m_cbObjLists[reason]; bool called = false; - for (auto it = cbObjList.begin(); it != cbObjList.end();) { + const auto end = cbObjList.end(); // prevent looping over newly added elements + for (auto it = cbObjList.begin(); it != end;) { if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); continue; @@ -495,7 +496,8 @@ public: bool called = false; typedef std::set VpioVarSet; VpioVarSet update; // set of objects to update after callbacks - for (auto it = cbObjList.begin(); it != cbObjList.end();) { + const auto end = cbObjList.end(); // prevent looping over newly added elements + for (auto it = cbObjList.begin(); it != end;) { if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); continue; From 7c4259bc0a0d1ccf866ed58afb791ead71d3f94d Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Sat, 7 Nov 2020 01:51:21 +0100 Subject: [PATCH 56/88] Support static methods and typedefs in classes (#2615) --- docs/CONTRIBUTORS | 1 + src/V3Class.cpp | 40 +++++++++++++++---- src/V3LinkDot.cpp | 24 +++++------ src/V3LinkParse.cpp | 2 +- src/V3Width.cpp | 21 ++++++++-- test_regress/t/t_class2.out | 7 ---- test_regress/t/t_class2.pl | 4 +- test_regress/t/t_class2.v | 5 +++ test_regress/t/t_class_name.out | 5 --- test_regress/t/t_class_name.pl | 4 +- test_regress/t/t_class_static_method.pl | 21 ++++++++++ test_regress/t/t_class_static_method.v | 34 ++++++++++++++++ test_regress/t/t_class_typedef.out | 13 ------ test_regress/t/t_class_typedef.pl | 4 +- .../t/t_module_class_static_method.pl | 21 ++++++++++ test_regress/t/t_module_class_static_method.v | 24 +++++++++++ test_regress/t/t_var_static.out | 4 -- 17 files changed, 171 insertions(+), 63 deletions(-) delete mode 100644 test_regress/t/t_class2.out delete mode 100644 test_regress/t/t_class_name.out create mode 100755 test_regress/t/t_class_static_method.pl create mode 100644 test_regress/t/t_class_static_method.v delete mode 100644 test_regress/t/t_class_typedef.out create mode 100644 test_regress/t/t_module_class_static_method.pl create mode 100644 test_regress/t/t_module_class_static_method.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index acca96c0d..4d7c136a9 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -36,6 +36,7 @@ Julien Margetts Kaleb Barrett Kanad Kanhere Kevin Kiningham +Krzysztof Bieganski Kuba Ober Ludwig Rogiers Lukasz Dalek diff --git a/src/V3Class.cpp b/src/V3Class.cpp index df895f107..ebde82354 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -35,6 +35,8 @@ private: AstUser1InUse m_inuser1; string m_prefix; // String prefix to add to name based on hier AstScope* m_classScopep = nullptr; // Package moving scopes into + AstScope* m_packageScopep = nullptr; // Class package scope + AstNodeFTask* m_ftaskp = nullptr; // Current task typedef std::vector> MoveVector; MoveVector m_moves; @@ -76,12 +78,14 @@ private: packagep->addStmtp(scopep); // Iterate VL_RESTORER(m_prefix); + VL_RESTORER(m_classScopep); + VL_RESTORER(m_packageScopep); { m_classScopep = classScopep; + m_packageScopep = scopep; m_prefix = nodep->name() + "__02e"; // . iterateChildren(nodep); } - m_classScopep = nullptr; } virtual void visit(AstPackage* nodep) override { VL_RESTORER(m_prefix); @@ -94,11 +98,28 @@ private: virtual void visit(AstVar* nodep) override { iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class - // TODO move class statics only - // if (m_classScopep) { - // m_moves.push_back(make_pair(nodep, m_classScopep)); - //} + // TODO move class statics too + if (m_ftaskp && m_ftaskp->lifetime().isStatic()) { + m_moves.push_back(make_pair(nodep, m_packageScopep)); + } } + + virtual void visit(AstVarScope* nodep) override { + iterateChildren(nodep); + nodep->varp()->user1p(nodep); + } + + virtual void visit(AstNodeFTask* nodep) override { + VL_RESTORER(m_ftaskp); + { + m_ftaskp = nodep; + iterateChildren(nodep); + if (nodep->lifetime().isStatic()) { + m_moves.push_back(make_pair(nodep, m_packageScopep)); + } + } + } + virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class @@ -116,8 +137,13 @@ public: // CONSTRUCTORS explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~ClassVisitor() override { - for (MoveVector::iterator it = m_moves.begin(); it != m_moves.end(); ++it) { - it->second->addVarp(it->first->unlinkFrBack()); + for (auto moved : m_moves) { + if (VN_IS(moved.first, NodeFTask)) { + moved.second->addActivep(moved.first->unlinkFrBack()); + } else if (VN_IS(moved.first, Var)) { + AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope); + moved.second->addVarp(scopep->unlinkFrBack()); + } } } }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3ee315a8a..2356c30a5 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1004,7 +1004,12 @@ class LinkDotFindVisitor : public AstNVisitor { } // Create symbol table for the task's vars string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name(); - m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_packagep); + auto pkgp = m_packagep; + // Set the class as package for static class methods + if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) { + pkgp = VN_CAST(m_curSymp->nodep(), Class); + } + m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp); m_curSymp->fallbackp(oldCurSymp); // Convert the func's range to the output variable // This should probably be done in the Parser instead, as then we could @@ -2114,12 +2119,7 @@ private: "Bad package link"); AstClassOrPackageRef* cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); - packagep = cpackagerefp->packagep(); - if (!packagep && cpackagerefp->classOrPackagep()) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Class '::' references: " - << AstNode::prettyNameQ(cpackagerefp->name())); - } + packagep = cpackagerefp->classOrPackagep(); UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); m_ds.m_dotSymp = m_statep->getNodeSym(packagep); m_ds.m_dotPos = DP_SCOPE; @@ -2485,9 +2485,8 @@ private: if (cpackagerefp->paramsp()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); } - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), - m_ds.m_dotp->lhsp(), "Bad package link"); - nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); + UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); + nodep->packagep(cpackagerefp->classOrPackagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { @@ -2694,9 +2693,6 @@ private: virtual void visit(AstNodeFTask* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); - if (nodep->classMethod() && nodep->lifetime().isStatic()) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method"); - } if (nodep->isExternDef()) { if (!m_curSymp->findIdFallback("extern " + nodep->name())) { nodep->v3error("extern not found that declares " + nodep->prettyNameQ()); @@ -2802,7 +2798,7 @@ private: if (cpackagerefp->packagep()) { nodep->packagep(cpackagerefp->packagep()); } else { - cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference"); + nodep->packagep(cpackagerefp->classOrPackagep()); // if (cpackagerefp->paramsp()) { // nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); // } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index ebdc38cac..14cc8d494 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -181,7 +181,7 @@ private: virtual void visit(AstVar* nodep) override { cleanFileline(nodep); if (nodep->lifetime().isNone()) { - if (nodep->isFuncLocal() && nodep->isIO()) { + if (m_ftaskp) { nodep->lifetime(VLifetime::AUTOMATIC); } else { nodep->lifetime(m_lifetime); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a56889287..f4a49629d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2845,9 +2845,24 @@ private: for (AstClass* classp = first_classp; classp;) { if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { userIterate(ftaskp, nullptr); - nodep->taskp(ftaskp); - nodep->dtypeFrom(ftaskp); - if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + if (ftaskp->lifetime().isStatic()) { + AstNode* argsp = nullptr; + if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext(); + AstNodeFTaskRef* newp = nullptr; + if (VN_IS(ftaskp, Task)) { + newp = new AstTaskRef(nodep->fileline(), ftaskp->name(), argsp); + } else { + newp = new AstFuncRef(nodep->fileline(), ftaskp->name(), argsp); + } + newp->taskp(ftaskp); + newp->packagep(classp); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { + nodep->taskp(ftaskp); + nodep->dtypeFrom(ftaskp); + if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + } return; } classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr; diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out deleted file mode 100644 index 25f82f892..000000000 --- a/test_regress/t/t_class2.out +++ /dev/null @@ -1,7 +0,0 @@ -%Error-UNSUPPORTED: t/t_class2.v:35:16: Unsupported: Class '::' references: 'Cls' - 35 | if (Cls::ENUM_VAL != 22) $stop; - | ^~~~~~~~ -%Error: Internal Error: t/t_class2.v:35:11: ../V3LinkDot.cpp:#: Bad package link - 35 | if (Cls::ENUM_VAL != 22) $stop; - | ^~~ - ... See the manual and https://verilator.org for more assistance. diff --git a/test_regress/t/t_class2.pl b/test_regress/t/t_class2.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class2.pl +++ b/test_regress/t/t_class2.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_class2.v b/test_regress/t/t_class2.v index 774e95344..f78b1da05 100644 --- a/test_regress/t/t_class2.v +++ b/test_regress/t/t_class2.v @@ -18,11 +18,14 @@ endclass : Cls Cls c; Cls d; + Cls::enum_t e; + initial begin // Alternate between two versions to make sure we don't // constant propagate between them. c = new; d = new; + e = Cls::ENUM_VAL; c.imembera = 10; d.imembera = 11; c.imemberb = 20; @@ -34,6 +37,8 @@ endclass : Cls if (Pkg::ENUMP_VAL != 33) $stop; if (Cls::ENUM_VAL != 22) $stop; if (c.ENUM_VAL != 22) $stop; + if (e != Cls::ENUM_VAL) $stop; + if (e != 22) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_name.out b/test_regress/t/t_class_name.out deleted file mode 100644 index 8f5e19daa..000000000 --- a/test_regress/t/t_class_name.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_name.v:12:16: Unsupported: 'static' class method - : ... In instance t - 12 | static task static_name; - | ^~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_name.pl b/test_regress/t/t_class_name.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class_name.pl +++ b/test_regress/t/t_class_name.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_class_static_method.pl b/test_regress/t/t_class_static_method.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_static_method.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_method.v b/test_regress/t/t_class_static_method.v new file mode 100644 index 000000000..1d408aaef --- /dev/null +++ b/test_regress/t/t_class_static_method.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + + static task static_task(int x); + $write("Called static task: %d\n", x); + if (x != 16) $stop; + endtask + + static function int static_function(int x); + $write("Called static function: %d\n", x); + if (x != 23) $stop; + return 42; + endfunction + +endclass : Cls + +module t (/*AUTOARG*/); + + initial begin + int x; + Cls::static_task(16); + x = Cls::static_function(23); + $write("Static function result: %d\n", x); + if (x != 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_class_typedef.out b/test_regress/t/t_class_typedef.out deleted file mode 100644 index 4979a037a..000000000 --- a/test_regress/t/t_class_typedef.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_typedef.v:12:4: Unsupported: Class '::' reference - 12 | uvm_resource_types::rsrc_q_t rtab [string]; - | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_class_typedef.v:12:24: Can't find typedef: 'rsrc_q_t' - 12 | uvm_resource_types::rsrc_q_t rtab [string]; - | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_class_typedef.v:14:4: Unsupported: Class '::' reference - 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_class_typedef.v:14:32: Can't find typedef: 'rsrc_q_t' - 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_typedef.pl b/test_regress/t/t_class_typedef.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class_typedef.pl +++ b/test_regress/t/t_class_typedef.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_module_class_static_method.pl b/test_regress/t/t_module_class_static_method.pl new file mode 100644 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_module_class_static_method.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_module_class_static_method.v b/test_regress/t/t_module_class_static_method.v new file mode 100644 index 000000000..393c0e541 --- /dev/null +++ b/test_regress/t/t_module_class_static_method.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 +// + +module t (/*AUTOARG*/); + + class Cls; + + static function int static_task(); + return 42; + endfunction + + endclass : Cls + + initial begin + if (Cls::static_task() != 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_var_static.out b/test_regress/t/t_var_static.out index 982ff5970..f6d7a524e 100644 --- a/test_regress/t/t_var_static.out +++ b/test_regress/t/t_var_static.out @@ -2,10 +2,6 @@ : ... In instance t 20 | static int st = 2; st++; return st; | ^~ -%Error-UNSUPPORTED: t/t_var_static.v:27:11: Unsupported: 'static' function/task variables - : ... In instance t - 27 | int st = 2; st++; return st; - | ^~ %Error-UNSUPPORTED: t/t_var_static.v:30:18: Unsupported: 'static' function/task variables : ... In instance t 30 | static int st = 2; st++; return st; From 2a24bb475924e9401c073cc88732babf80988b4b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 10:37:55 -0500 Subject: [PATCH 57/88] Fix queue poping wrong value when otherwise unused (#2512). --- Changes | 2 ++ src/V3Ast.h | 25 ++++++++++++------ src/V3AstNodes.h | 2 +- src/V3Broken.cpp | 2 +- src/V3Cdc.cpp | 2 +- src/V3Delayed.cpp | 5 ++-- src/V3Gate.cpp | 9 ++++--- src/V3GenClk.cpp | 2 +- src/V3Life.cpp | 2 +- src/V3LifePost.cpp | 7 ++---- src/V3LinkLValue.cpp | 40 ++++++++++++++--------------- src/V3Localize.cpp | 3 ++- src/V3MergeCond.cpp | 2 +- src/V3Order.cpp | 7 +++--- src/V3Premit.cpp | 2 +- src/V3Simulate.h | 5 ++-- src/V3Split.cpp | 4 +-- src/V3SplitAs.cpp | 4 +-- src/V3SplitVar.cpp | 6 ++--- src/V3Subst.cpp | 4 +-- src/V3Table.cpp | 5 ++-- src/V3Trace.cpp | 2 +- src/V3Tristate.cpp | 17 ++++++------- src/V3Undriven.cpp | 13 +++++----- src/V3Unknown.cpp | 4 +-- src/V3Unroll.cpp | 2 +- src/V3Width.cpp | 9 ++++--- test_regress/t/t_queue_pushpop.pl | 21 ++++++++++++++++ test_regress/t/t_queue_pushpop.v | 42 +++++++++++++++++++++++++++++++ 29 files changed, 164 insertions(+), 86 deletions(-) create mode 100755 test_regress/t/t_queue_pushpop.pl create mode 100644 test_regress/t/t_queue_pushpop.v diff --git a/Changes b/Changes index 97ea9ae11..9e4611092 100644 --- a/Changes +++ b/Changes @@ -12,6 +12,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] +**** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1] + * Verilator 4.102 2020-10-15 diff --git a/src/V3Ast.h b/src/V3Ast.h index 45f6e9ae6..3f94d53b3 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -125,14 +125,22 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { class VAccess { public: - enum en : uint8_t { READ, WRITE }; + enum en : uint8_t { + READ, // Read/Consumed, variable not changed + WRITE, // Written/Updated, variable might be updated, but not consumed + // // so variable might be removable if not consumed elsewhere + READWRITE, // Read/Consumed and written/updated, variable both set and + // // also consumed, cannot remove usage of variable. + // // For non-simple data types only e.g. no tristates/delayed vars. + NOCHANGE // No change to previous state, used only in V3LinkLValue + }; enum en m_e; const char* ascii() const { - static const char* const names[] = {"RD", "WR"}; + static const char* const names[] = {"RD", "WR", "RW", "--"}; return names[m_e]; } const char* arrow() const { - static const char* const names[] = {"[RV] <-", "[LV] =>"}; + static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"}; return names[m_e]; } inline VAccess() @@ -143,10 +151,13 @@ public: explicit inline VAccess(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning operator en() const { return m_e; } - VAccess invert() const { return (m_e == WRITE) ? VAccess(READ) : VAccess(WRITE); } - bool isReadOnly() const { return m_e == READ; } // False if/when support READWRITE - bool isWrite() const { return m_e == WRITE; } // Need audit if/when support READWRITE - bool isWriteOnly() const { return m_e == WRITE; } // False if/when support READWRITE + VAccess invert() const { + return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE)); + } + bool isReadOnly() const { return m_e == READ; } // False with READWRITE + bool isReadOrRW() const { return m_e == READ || m_e == READWRITE; } + bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; } + bool isRW() const { return m_e == READWRITE; } // False with READWRITE }; inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; } inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index facf04f6c..b4f564412 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2366,7 +2366,7 @@ public: } } virtual int instrCount() const override { - return widthInstrs() * (access().isWriteOnly() ? 1 : instrCountLd()); + return widthInstrs() * (access().isReadOrRW() ? instrCountLd() : 1); } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 9c1082689..f017c7fe5 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -275,7 +275,7 @@ private: processAndIterate(nodep); UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() && VN_IS(nodep->lhsp(), NodeVarRef) - && !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWrite()), + && !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), nodep, "Assignment LHS is not an lvalue"); } virtual void visit(AstNode* nodep) override { diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 72d4bc243..993f016fd 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -661,7 +661,7 @@ private: // We use weight of one for normal edges, // Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting) // When simplify we'll take the MAX weight - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1); if (m_inDly) { varvertexp->fromFlop(true); diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 89fb81dc7..c2f80ca6d 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -410,10 +410,11 @@ private: virtual void visit(AstVarRef* nodep) override { if (!nodep->user2Inc()) { // Not done yet - if (m_inDly && nodep->access().isWrite()) { + if (m_inDly && nodep->access().isWriteOrRW()) { UINFO(4, "AssignDlyVar: " << nodep << endl); markVarUsage(nodep->varScopep(), VU_DLY); UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block"); + UASSERT_OBJ(!nodep->access().isRW(), nodep, "<= on read+write method"); if (!m_activep->hasClocked()) { nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should " "have converted in V3Active"); @@ -458,7 +459,7 @@ private: newrefp->user2(true); // No reason to do it again nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (!m_inDly && nodep->access().isWrite()) { + } else if (!m_inDly && nodep->access().isWriteOrRW()) { // UINFO(9, "NBA " << nodep << endl); if (!m_inInitial) { UINFO(4, "AssignNDlyVar: " << nodep << endl); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e5a1ae68a..962baa03d 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -220,7 +220,9 @@ private: if (nodep->varScopep()->varp()->isSc()) { clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's } - if (nodep->access().isWrite()) { + if (nodep->access().isRW()) { + clearSimple("R/W"); + } else if (nodep->access().isWriteOrRW()) { if (m_lhsVarRef) clearSimple(">1 lhs varRefs"); m_lhsVarRef = nodep; } else { @@ -457,9 +459,10 @@ private: } // We use weight of one; if we ref the var more than once, when we simplify, // the weight will increase - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1); - } else { + } + if (nodep->access().isReadOrRW()) { new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1); } } diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 163ab4bc3..0aa972080 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -185,7 +185,7 @@ private: UINFO(8, " VarAct " << nodep << endl); vscp->user1(true); } - if (m_assignp && nodep->access().isWrite() && vscp->user1()) { + if (m_assignp && nodep->access().isWriteOrRW() && vscp->user1()) { // Variable was previously used as a clock, and is now being set // Thus a unordered generated clock... UINFO(8, " VarSetAct " << nodep << endl); diff --git a/src/V3Life.cpp b/src/V3Life.cpp index aa8ca95ec..8b9907339 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -300,7 +300,7 @@ private: // AstVarScope* vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues m_lifep->complexAssign(vscp); } else { diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index f7fd88a83..d67f20b96 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -283,11 +283,8 @@ private: UASSERT_OBJ(vscp, nodep, "Scope not assigned"); LifeLocation loc(m_execMTaskp, ++m_sequence); - if (nodep->access().isWrite()) { - m_writes[vscp].insert(loc); - } else { - m_reads[vscp].insert(loc); - } + if (nodep->access().isWriteOrRW()) m_writes[vscp].insert(loc); + if (nodep->access().isReadOrRW()) m_reads[vscp].insert(loc); } virtual void visit(AstAssignPre* nodep) override { // Do not record varrefs within assign pre. diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 453747555..d5a26d0f5 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -35,7 +35,7 @@ private: // NODE STATE // STATE - bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments + VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside // METHODS @@ -45,9 +45,9 @@ private: // Result handing virtual void visit(AstNodeVarRef* nodep) override { // VarRef: LValue its reference - if (m_setRefLvalue) nodep->access(VAccess::WRITE); + if (m_setRefLvalue != VAccess::NOCHANGE) nodep->access(m_setRefLvalue); if (nodep->varp()) { - if (nodep->access().isWrite() && !m_ftaskp && nodep->varp()->isReadOnly()) { + if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, "Assigning to input/const variable: " << nodep->prettyNameQ()); } @@ -62,7 +62,7 @@ private: // Now that we do, and it's from a output, we know it's a lvalue m_setRefLvalue = VAccess::WRITE; iterateChildren(nodep); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; } else { iterateChildren(nodep); } @@ -72,7 +72,7 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->lhsp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->rhsp()); } } @@ -81,7 +81,7 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->lhsp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->rhsp()); } } @@ -90,7 +90,7 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->filenamep()); iterateAndNextNull(nodep->modep()); } @@ -100,7 +100,7 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->filenamep()); } } @@ -181,7 +181,7 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->memp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->filenamep()); iterateAndNextNull(nodep->lsbp()); iterateAndNextNull(nodep->msbp()); @@ -190,7 +190,7 @@ private: virtual void visit(AstValuePlusArgs* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->searchp()); m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->outp()); @@ -201,14 +201,14 @@ private: { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->lhsp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->fmtp()); } } void prepost_visit(AstNodeTriop* nodep) { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->rhsp()); m_setRefLvalue = VAccess::WRITE; @@ -226,7 +226,7 @@ private: { iterateAndNextNull(nodep->lhsp()); // Only set lvalues on the from - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->thsp()); } @@ -235,14 +235,14 @@ private: VL_RESTORER(m_setRefLvalue); { // Only set lvalues on the from iterateAndNextNull(nodep->lhsp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->rhsp()); } } virtual void visit(AstCellArrayRef* nodep) override { VL_RESTORER(m_setRefLvalue); { // selp is not an lvalue - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->selp()); } } @@ -250,7 +250,7 @@ private: VL_RESTORER(m_setRefLvalue); { // Only set lvalues on the from iterateAndNextNull(nodep->lhsp()); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->rhsp()); iterateAndNextNull(nodep->thsp()); } @@ -271,7 +271,7 @@ private: if (portp->isWritable()) { m_setRefLvalue = VAccess::WRITE; iterate(pinp); - m_setRefLvalue = false; + m_setRefLvalue = VAccess::NOCHANGE; } else { iterate(pinp); } @@ -286,7 +286,7 @@ private: public: // CONSTRUCTORS - LinkLValueVisitor(AstNode* nodep, bool start) + LinkLValueVisitor(AstNode* nodep, VAccess start) : m_setRefLvalue{start} { iterate(nodep); } @@ -298,12 +298,12 @@ public: void V3LinkLValue::linkLValue(AstNetlist* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); - { LinkLValueVisitor visitor(nodep, false); } // Destruct before checking + { LinkLValueVisitor visitor(nodep, VAccess::NOCHANGE); } // Destruct before checking V3Global::dumpCheckGlobalTree("linklvalue", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); } void V3LinkLValue::linkLValueSet(AstNode* nodep) { // Called by later link functions when it is known a node needs // to be converted to a lvalue. UINFO(9, __FUNCTION__ << ": " << endl); - LinkLValueVisitor visitor(nodep, true); + LinkLValueVisitor visitor(nodep, VAccess::WRITE); } diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index efa34527c..f412649cf 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -168,7 +168,8 @@ private: for (; nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, NodeAssign)) { if (AstVarRef* varrefp = VN_CAST(VN_CAST(nodep, NodeAssign)->lhsp(), VarRef)) { - UASSERT_OBJ(varrefp->access().isWrite(), varrefp, "LHS assignment not lvalue"); + UASSERT_OBJ(varrefp->access().isWriteOrRW(), varrefp, + "LHS assignment not lvalue"); if (!varrefp->varp()->user4p()) { UINFO(4, " FuncAsn " << varrefp << endl); varrefp->varp()->user4p(varrefp); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index acdfe95b7..e7dcb3955 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -80,7 +80,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (!m_mergeable) return; // Clear if it's an LValue referencing a marked variable - if (nodep->access().isWrite() && nodep->varp()->user1()) { + if (nodep->access().isWriteOrRW() && nodep->varp()->user1()) { clearMergeable(nodep, "might modify condition"); } } diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 6be9a3fa6..5bf687bf5 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1030,7 +1030,7 @@ private: UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); if (m_inSenTree) { // Add CLOCK dependency... This is a root of the tree we'll trace - UASSERT_OBJ(!nodep->access().isWrite(), nodep, + UASSERT_OBJ(!nodep->access().isWriteOrRW(), nodep, "How can a sensitivity be setting a var?"); OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD); varVxp->isClock(true); @@ -1041,9 +1041,8 @@ private: // We don't want to add extra edges if the logic block has many usages of same var bool gen = false; bool con = false; - if (nodep->access().isWrite()) { - gen = !(varscp->user4() & VU_GEN); - } else { + if (nodep->access().isWriteOrRW()) gen = !(varscp->user4() & VU_GEN); + if (nodep->access().isReadOrRW()) { con = !(varscp->user4() & VU_CON); if ((varscp->user4() & VU_GEN) && !m_inClocked) { // Dangerous assumption: diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 3195e30d0..7e432830a 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -58,7 +58,7 @@ private: } virtual void visit(AstVarRef* nodep) override { // it's LHS var is used so need a deep temporary - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { nodep->varp()->user4(true); } else { if (nodep->varp()->user4()) { diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 84bf595ef..846d303f5 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -401,7 +401,7 @@ private: && !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType) && !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType)) clearOptimizable(nodep, "Array references/not basic"); - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { if (m_inDlyAssign) { if (!(vscp->user1() & VU_LVDLY)) { vscp->user1(vscp->user1() | VU_LVDLY); @@ -416,7 +416,8 @@ private: if (m_checkOnly) varRefCb(nodep); } } - } else { + } + if (nodep->access().isReadOrRW()) { if (!(vscp->user1() & VU_RV)) { if (!m_params && (vscp->user1() & VU_LV)) { clearOptimizable(nodep, "Var write & read"); diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 5fc44131a..31ddbd268 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -383,7 +383,7 @@ protected: SplitVarStdVertex* vstdp = reinterpret_cast(vscp->user1p()); // SPEEDUP: We add duplicate edges, that should be fixed - if (m_inDly && nodep->access().isWrite()) { + if (m_inDly && nodep->access().isWriteOrRW()) { UINFO(4, " VARREFDLY: " << nodep << endl); // Delayed variable is different from non-delayed variable if (!vscp->user2p()) { @@ -398,7 +398,7 @@ protected: new SplitLVEdge(&m_graph, vpostp, vxp); } } else { // Nondelayed assignment - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { // Non-delay; need to maintain existing ordering // with all consumers of the signal UINFO(4, " VARREFLV: " << nodep << endl); diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index eb1f1d2d1..48a1c2960 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -49,7 +49,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) override { - if (nodep->access().isWrite() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { + if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } } @@ -76,7 +76,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) override { - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { if (nodep->varScopep() == m_splitVscp) { UINFO(6, " CL VAR " << nodep << endl); m_matches = true; diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index b5bd06e1a..bc635a42a 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -898,10 +898,8 @@ public: : m_basicp{varp->dtypep()->basicp()} {} void append(const PackedVarRefEntry& e, const VAccess& access) { UASSERT(!m_dedupDone, "cannot add after dedup()"); - if (access.isWrite()) - m_lhs.push_back(e); - else - m_rhs.push_back(e); + if (access.isWriteOrRW()) m_lhs.push_back(e); + if (access.isReadOrRW()) m_rhs.push_back(e); } void dedup() { UASSERT(!m_dedupDone, "dedup() called twice"); diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 33f554067..d8a01fbb3 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -329,14 +329,14 @@ private: } virtual void visit(AstVarRef* nodep) override { // Any variable - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { m_assignStep++; nodep->varp()->user2(m_assignStep); UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep << endl); } if (isSubstVar(nodep->varp())) { SubstVarEntry* entryp = getEntryp(nodep); - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { UINFO(8, " ASSIGNcpx " << nodep << endl); entryp->assignComplex(); } else if (AstNode* substp = entryp->substWhole(nodep)) { diff --git a/src/V3Table.cpp b/src/V3Table.cpp index b83c44a68..76428dc32 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -154,10 +154,11 @@ public: // Called by TableSimulateVisitor on each unique varref encountered UINFO(9, " SimVARREF " << nodep << endl); AstVarScope* vscp = nodep->varScopep(); - if (nodep->access().isWrite()) { + if (nodep->access().isWriteOrRW()) { m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); m_outVarps.push_back(vscp); - } else { + } + if (nodep->access().isReadOrRW()) { // We'll make the table with a separate natural alignment for each // output var, so always have char, 16 or 32 bit widths, so use widthTotalBytes m_inWidth += nodep->varp()->width(); // Space for var diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 01067cb8e..28712534e 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -859,7 +859,7 @@ private: || nodep->varp()->isSigPublic()) { // Or ones user can change new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1); } - } else if (m_cfuncp && m_finding && nodep->access().isWrite()) { + } else if (m_cfuncp && m_finding && nodep->access().isWriteOrRW()) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); V3GraphVertex* const funcVtxp = getCFuncVertexp(m_cfuncp); V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex(); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index dad10cffc..92131f735 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -168,7 +168,7 @@ private: for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { TristateVertex* vvertexp = dynamic_cast(edgep->fromp()); if (const AstVarRef* refp = VN_CAST(vvertexp->nodep(), VarRef)) { - if (refp->access().isWrite() + if (refp->access().isWriteOrRW() // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. && !vvertexp->isTristate()) { @@ -276,10 +276,11 @@ class TristatePinVisitor : public TristateBaseVisitor { bool m_lvalue; // Flip to be an LVALUE // VISITORS virtual void visit(AstVarRef* nodep) override { - if (m_lvalue && !nodep->access().isWrite()) { + UASSERT_OBJ(!nodep->access().isRW(), nodep, "Tristate unexpected on R/W access flip"); + if (m_lvalue && !nodep->access().isWriteOrRW()) { UINFO(9, " Flip-to-LValue " << nodep << endl); nodep->access(VAccess::WRITE); - } else if (!m_lvalue && nodep->access().isWrite()) { + } else if (!m_lvalue && !nodep->access().isReadOnly()) { UINFO(9, " Flip-to-RValue " << nodep << endl); nodep->access(VAccess::READ); // Mark the ex-output as tristated @@ -1222,19 +1223,17 @@ class TristateVisitor : public TristateBaseVisitor { virtual void visit(AstVarRef* nodep) override { UINFO(9, dbgState() << nodep << endl); if (m_graphing) { - if (nodep->access().isWrite()) { - associateLogic(nodep, nodep->varp()); - } else { - associateLogic(nodep->varp(), nodep); - } + if (nodep->access().isWriteOrRW()) associateLogic(nodep, nodep->varp()); + if (nodep->access().isReadOrRW()) associateLogic(nodep->varp(), nodep); } else { if (nodep->user2() & U2_NONGRAPH) return; // Processed nodep->user2(U2_NONGRAPH); // Detect all var lhs drivers and adds them to the // VarMap so that after the walk through the module we can expand // any tristate logic on the driver. - if (nodep->access().isWrite() && m_tgraph.isTristate(nodep->varp())) { + if (nodep->access().isWriteOrRW() && m_tgraph.isTristate(nodep->varp())) { UINFO(9, " Ref-to-lvalue " << nodep << endl); + UASSERT_OBJ(!nodep->access().isRW(), nodep, "Tristate unexpected on R/W access"); m_tgraph.didProcess(nodep); mapInsertLhsVarRef(nodep); } else if (nodep->access().isReadOnly() diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index c09336dcd..2e5dc239d 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -318,7 +318,7 @@ private: for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr); int lsb = constp->toUInt(); - if (m_inBBox || varrefp->access().isWrite()) { + if (m_inBBox || varrefp->access().isWriteOrRW()) { // Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine. if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenBit(lsb, nodep->width())) { @@ -327,7 +327,8 @@ private: } entryp->drivenBit(lsb, nodep->width()); } - if (m_inBBox || !varrefp->access().isWrite()) entryp->usedBit(lsb, nodep->width()); + if (m_inBBox || !varrefp->access().isWriteOrRW()) + entryp->usedBit(lsb, nodep->width()); } } else { // else other varrefs handled as unknown mess in AstVarRef @@ -336,7 +337,7 @@ private: } virtual void visit(AstNodeVarRef* nodep) override { // Any variable - if (nodep->access().isWrite() + if (nodep->access().isWriteOrRW() && !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable() && !nodep->varp()->isDeclTyped() // @@ -355,16 +356,16 @@ private: } for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr); - bool fdrv = nodep->access().isWrite() + bool fdrv = nodep->access().isWriteOrRW() && nodep->varp()->attrFileDescr(); // FD's are also being read from - if (m_inBBox || nodep->access().isWrite()) { + if (m_inBBox || nodep->access().isWriteOrRW()) { if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) { UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl); warnAlwCombOrder(nodep); } entryp->drivenWhole(); } - if (m_inBBox || !nodep->access().isWrite() || fdrv) entryp->usedWhole(); + if (m_inBBox || nodep->access().isReadOrRW() || fdrv) entryp->usedWhole(); } } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 160c161c3..21e61b019 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -313,7 +313,7 @@ private: AstNode* basefromp = AstArraySel::baseFromp(nodep); bool lvalue = false; if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { - lvalue = varrefp->access().isWrite(); + lvalue = varrefp->access().isWriteOrRW(); } // Find range of dtype we are selecting from // Similar code in V3Const::warnSelect @@ -361,7 +361,7 @@ private: AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); bool lvalue = false; if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { - lvalue = varrefp->access().isWrite(); + lvalue = varrefp->access().isWriteOrRW(); } else if (VN_IS(basefromp, Const)) { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp } else { diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 38fb4e602..7a9c15e04 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -445,7 +445,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp - && nodep->access().isWrite()) { + && nodep->access().isWriteOrRW()) { UINFO(8, " Itervar assigned to: " << nodep << endl); m_varAssignHit = true; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f4a49629d..bed690e32 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1870,13 +1870,13 @@ private: // nodep->varp()->dumpTree(cout, " forvar "); } // Note genvar's are also entered as integers nodep->dtypeFrom(nodep->varp()); - if (VN_IS(nodep->backp(), NodeAssign) && nodep->access().isWrite()) { // On LHS + if (VN_IS(nodep->backp(), NodeAssign) && nodep->access().isWriteOrRW()) { // On LHS UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed"); } // if (debug() >= 9) nodep->dumpTree(cout, " VRout "); - if (nodep->access().isWrite() && nodep->varp()->direction() == VDirection::CONSTREF) { + if (nodep->access().isWriteOrRW() && nodep->varp()->direction() == VDirection::CONSTREF) { nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ()); - } else if (nodep->access().isWrite() && nodep->varp()->isConst() && !m_paramsOnly + } else if (nodep->access().isWriteOrRW() && nodep->varp()->isConst() && !m_paramsOnly && (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) { // Too loose, but need to allow our generated first assignment // Move this to a property of the AstInitial block @@ -2754,7 +2754,8 @@ private: } } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); + // Returns element, so method both consumes (reads) and modifies the queue + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READWRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr); newp->dtypeFrom(adtypep->subDTypep()); diff --git a/test_regress/t/t_queue_pushpop.pl b/test_regress/t/t_queue_pushpop.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_queue_pushpop.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_pushpop.v b/test_regress/t/t_queue_pushpop.v new file mode 100644 index 000000000..acad0a3a2 --- /dev/null +++ b/test_regress/t/t_queue_pushpop.v @@ -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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + logic q [$]; + int cycle = 0; + + always @(posedge clk) begin + cycle <= cycle + 1'b1; + end + + always @(posedge clk) begin + q.push_front(1'b1); + end + + // Important this is a separate always to expose bug where "q" thought unused + always @(posedge clk) begin + if (cycle == 1) begin + if (q.pop_back() != 1) $stop; + end + end + + always @(posedge clk) begin + if (cycle == 2) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From 602750b1eeba585adfe5f8f606285bb03ea29dc2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 10:49:54 -0500 Subject: [PATCH 58/88] Commentary --- Changes | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 9e4611092..b5a7d64ec 100644 --- a/Changes +++ b/Changes @@ -4,14 +4,24 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.103 devel -**** Support queue and associative array 'with' statements. (#2616) +*** Support queue and associative array 'with' statements. (#2616) -**** Support queue slicing (#2326). +*** Support queue slicing (#2326). -**** Support associative array pattern assignments and defaults. +*** Support associative array pattern assignments and defaults. + +*** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski] + +**** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett] + +**** Fix return from callValueCbs (#2589) (#2605). [Marlon James] **** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] +**** Fix fault when $fgets, $sscanf, etc used with string (#2604). [Yutetsu TAKATSUKASA] + +**** Fix WIFEXITED missing from MinGW/MSYS2 (#2609). [Jean Berniolles] + **** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1] From ff5465308b1f2c8a14399a4b4ae49e58d1dbf6ef Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 11:56:24 -0500 Subject: [PATCH 59/88] Internals: Tree dump DEFAULT pattern. No functional change. --- src/V3AstNodes.cpp | 4 ++++ src/V3AstNodes.h | 1 + src/V3Width.cpp | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b5dc6d2b2..92a3ac153 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1373,6 +1373,10 @@ void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +void AstPatMember::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isDefault()) str << " [DEFAULT]"; +} void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstSel::dump(std::ostream& str) const { this->AstNodeTriop::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b4f564412..8d77fc54c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -8386,6 +8386,7 @@ public: virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } virtual int instrCount() const override { return widthInstrs() * 2; } + virtual void dump(std::ostream& str = std::cout) const override; // op1 = expression to assign or another AstPattern (list if replicated) AstNode* lhssp() const { return op1p(); } AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index bed690e32..3b311d6d9 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3294,7 +3294,7 @@ private: nodep->dtypep()->numeric()); } } - if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } + if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } if (newp) { nodep->replaceWith(newp); @@ -3347,7 +3347,7 @@ private: } } } - if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } + if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements"); if (newp) { @@ -3444,7 +3444,7 @@ private: } } } - if (newpatp) { VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } + if (newpatp) VL_DO_DANGLING(pushDeletep(newpatp), newpatp); } if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements"); if (newp) { From 778f133118971fa0a498d8dcced5398b5a60e2c3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 14:28:05 -0500 Subject: [PATCH 60/88] Fix dynamic new with init argument (#2325). --- src/V3Width.cpp | 5 ++--- test_regress/t/t_dynarray.v | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 3b311d6d9..6f869d4ad 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3119,8 +3119,7 @@ private: iterateCheckSigned32(nodep, "new() size", nodep->sizep(), BOTH); } if (nodep->rhsp()) { - iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep->subDTypep(), - BOTH); + iterateCheckTyped(nodep, "Dynamic array new RHS", nodep->rhsp(), adtypep, BOTH); } } @@ -5037,7 +5036,7 @@ private: void iterateCheckTyped(AstNode* nodep, const char* side, AstNode* underp, AstNodeDType* expDTypep, Stage stage) { if (stage & PRELIM) { - underp = userIterateSubtreeReturnEdits(underp, WidthVP(SELF, PRELIM).p()); + underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, PRELIM).p()); } if (stage & FINAL) { underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP); diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index 4be647804..a24a83453 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -126,6 +126,13 @@ module t (/*AUTOARG*/ `checkh(b[2], 0); `checkh(b[3], 0); + a = new[4] ('{8'd1,8'd2,8'd3,8'd4}); + `checkh(a.size, 4); + `checkh(a[0], 1); + `checkh(a[1], 2); + `checkh(a[2], 3); + `checkh(a[3], 4); + // test wide dynamic array p256 = new [11]; `checkh(p256.size, 11); From 152689776d8520455683895b1268886442684032 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 15:41:37 -0500 Subject: [PATCH 61/88] Report error on typedef referencing self (#2539). --- Changes | 2 ++ src/V3Width.cpp | 25 +++++++++++++++++++++++++ test_regress/t/t_enum_bad_circdecl.out | 8 ++++++++ test_regress/t/t_enum_bad_circdecl.pl | 20 ++++++++++++++++++++ test_regress/t/t_enum_bad_circdecl.v | 13 +++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 test_regress/t/t_enum_bad_circdecl.out create mode 100755 test_regress/t/t_enum_bad_circdecl.pl create mode 100644 test_regress/t/t_enum_bad_circdecl.v diff --git a/Changes b/Changes index b5a7d64ec..bf1928f0c 100644 --- a/Changes +++ b/Changes @@ -12,6 +12,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski] +**** Report error on typedef referencing self (#2539). [Cody Piersall] + **** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett] **** Fix return from callValueCbs (#2589) (#2605). [Marlon James] diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6f869d4ad..6b797d7ad 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1605,6 +1605,17 @@ private: } virtual void visit(AstTypedef* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed + if (auto* refp = checkRefToTypedefRecurse(nodep, nodep)) { + nodep->v3error("Typedef has self-reference: " << nodep->prettyNameQ() << endl + << nodep->warnContextPrimary() << endl + << refp->warnOther() + << "... Location of reference" << endl + << refp->warnContextSecondary()); + // May cause internel error but avoids infinite loop on dump + refp->typedefp(nullptr); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + } nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, nullptr); } @@ -5808,6 +5819,20 @@ private: } return nodep; // By default return this } + AstRefDType* checkRefToTypedefRecurse(AstNode* nodep, AstTypedef* typedefp) { + // Recurse all children looking for self reference + // This avoids iterateEditMoveDTypep going into a hard to resolve loop + // Only call once for any given typedef, or will become O(n^2) + if (VL_LIKELY(!nodep)) return nullptr; + if (auto* refp = VN_CAST(nodep, RefDType)) { + if (refp->typedefp() == typedefp) return refp; + } + if (auto* refp = checkRefToTypedefRecurse(nodep->op1p(), typedefp)) return refp; + if (auto* refp = checkRefToTypedefRecurse(nodep->op2p(), typedefp)) return refp; + if (auto* refp = checkRefToTypedefRecurse(nodep->op3p(), typedefp)) return refp; + if (auto* refp = checkRefToTypedefRecurse(nodep->op4p(), typedefp)) return refp; + return nullptr; + } //---------------------------------------------------------------------- // METHODS - special iterators diff --git a/test_regress/t/t_enum_bad_circdecl.out b/test_regress/t/t_enum_bad_circdecl.out new file mode 100644 index 000000000..3c30cd2c2 --- /dev/null +++ b/test_regress/t/t_enum_bad_circdecl.out @@ -0,0 +1,8 @@ +%Error: t/t_enum_bad_circdecl.v:11:6: Typedef has self-reference: 'bad_redecl' + : ... In instance t + 11 | } bad_redecl; + | ^~~~~~~~~~ + t/t_enum_bad_circdecl.v:9:17: ... Location of reference + 9 | typedef enum bad_redecl [2:0] { + | ^~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_enum_bad_circdecl.pl b/test_regress/t/t_enum_bad_circdecl.pl new file mode 100755 index 000000000..f1eef1686 --- /dev/null +++ b/test_regress/t/t_enum_bad_circdecl.pl @@ -0,0 +1,20 @@ +#!/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(linter => 1); + +lint( + verilator_flags2 => ["--lint-only -Wwarn-VARHIDDEN"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_bad_circdecl.v b/test_regress/t/t_enum_bad_circdecl.v new file mode 100644 index 000000000..bb5478c50 --- /dev/null +++ b/test_regress/t/t_enum_bad_circdecl.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + + typedef enum bad_redecl [2:0] { + VALUE + } bad_redecl; + +endmodule From 04c7fd16964fcb34c4ca36615f9b0bd99fc0f8c8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 7 Nov 2020 21:57:31 -0500 Subject: [PATCH 62/88] Tests: Add wire-or mux test for future optimization. --- MANIFEST.SKIP | 1 + test_regress/t/t_const_opt_or.pl | 21 ++++++ test_regress/t/t_const_opt_or.v | 111 +++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100755 test_regress/t/t_const_opt_or.pl create mode 100644 test_regress/t/t_const_opt_or.v diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index 1ddb7c5eb..cea857c16 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -66,4 +66,5 @@ ci/ /csrc/ obj_dir.* TAGS +gmon.out .*~ diff --git a/test_regress/t/t_const_opt_or.pl b/test_regress/t/t_const_opt_or.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_const_opt_or.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_const_opt_or.v b/test_regress/t/t_const_opt_or.v new file mode 100644 index 000000000..0f9077960 --- /dev/null +++ b/test_regress/t/t_const_opt_or.v @@ -0,0 +1,111 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [31:0] in = crc[31:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire [31:0] rd0; // From test of Test.v + wire [31:0] rd1; // From test of Test.v + // End of automatics + + wire rden0 = crc[0]; + wire rden1 = crc[1]; + wire [4:0] raddr0 = crc[20:16]; + wire [4:0] raddr1 = crc[28:24]; + + Test test(/*AUTOINST*/ + // Outputs + .rd0 (rd0[31:0]), + .rd1 (rd1[31:0]), + // Inputs + .clk (clk), + .raddr0 (raddr0[4:0]), + .raddr1 (raddr1[4:0]), + .rden0 (rden0), + .rden1 (rden1)); + + // Aggregate outputs into a single result vector + wire [63:0] result = {rd1, rd0}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc < 10) begin + sum <= '0; + end + else if (cyc == 99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'hdc97b141ac5d6d7d + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test(/*AUTOARG*/ + // Outputs + rd0, rd1, + // Inputs + clk, raddr0, raddr1, rden0, rden1 + ); + + input clk; + input [4:0] raddr0; + input [4:0] raddr1; + input rden0; + input rden1; + + output reg [31:0] rd0; + output reg [31:0] rd1; + + reg [31:0] gpr [31:1]; + + initial begin + for (int j=1; j<32; j++ ) begin + gpr[j] = {8'(j), 8'(j), 8'(j), 8'(j)}; + end + end + + always_comb begin + rd0[31:0] = 32'b0; + rd1[31:0] = 32'b0; + // Future optimization: + // Multiple assignments to same variable with OR between them + // ASSIGN(a, OR(a, aq)), ASSIGN(a, OR(a, bq)) -> ASSIGN(a, OR(a, OR(aq, bq)) + // Skip if we're not const'ing an entire module (IE doing only one assign, etc) + for (int j=1; j<32; j++ ) begin + rd0[31:0] |= ({32{rden0 & (raddr0[4:0]== 5'(j))}} & gpr[j][31:0]); + rd1[31:0] |= ({32{rden1 & (raddr1[4:0]== 5'(j))}} & gpr[j][31:0]); + end + end + +endmodule From c3f5dd74140f90eb5187083f5a4cffd8a5cae7d6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 11:17:42 -0500 Subject: [PATCH 63/88] Tests: Try to stabilize cron test. --- test_regress/t/t_savable_format1_bad.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/test_regress/t/t_savable_format1_bad.pl b/test_regress/t/t_savable_format1_bad.pl index f6ac72e4e..0731b7fe1 100755 --- a/test_regress/t/t_savable_format1_bad.pl +++ b/test_regress/t/t_savable_format1_bad.pl @@ -23,6 +23,7 @@ execute( ); -r "$Self->{obj_dir}/saved.vltsv" or error("Saved.vltsv not created\n"); +sleep(1); # Avoid make getting confused by very fast build compile( v_flags2 => ["--savable -GMODEL_WIDTH=40"], From 917ca2bad76b877d8c891a52097f7aafd487dc3d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 16:39:28 -0500 Subject: [PATCH 64/88] Tests: Add t_const_opt_red (#2632) (#2633) --- test_regress/t/t_const_opt_red.pl | 21 +++++ test_regress/t/t_const_opt_red.v | 149 ++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100755 test_regress/t/t_const_opt_red.pl create mode 100644 test_regress/t/t_const_opt_red.v diff --git a/test_regress/t/t_const_opt_red.pl b/test_regress/t/t_const_opt_red.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_const_opt_red.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_const_opt_red.v b/test_regress/t/t_const_opt_red.v new file mode 100644 index 000000000..0afb42832 --- /dev/null +++ b/test_regress/t/t_const_opt_red.v @@ -0,0 +1,149 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + // Take CRC data and apply to testblock inputs + wire [31:0] in = crc[31:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + logic a1; // From test of Test.v + logic a2; // From test of Test.v + logic a3; // From test of Test.v + logic a4; // From test of Test.v + logic a5; // From test of Test.v + logic o1; // From test of Test.v + logic o2; // From test of Test.v + logic o3; // From test of Test.v + logic o4; // From test of Test.v + logic o5; // From test of Test.v + logic x1; // From test of Test.v + logic x2; // From test of Test.v + logic x3; // From test of Test.v + logic x4; // From test of Test.v + logic x5; // From test of Test.v + // End of automatics + + wire [31:0] i = crc[31:0]; + + Test test(/*AUTOINST*/ + // Outputs + .a1 (a1), + .a2 (a2), + .a3 (a3), + .a4 (a4), + .a5 (a5), + .o1 (o1), + .o2 (o2), + .o3 (o3), + .o4 (o4), + .o5 (o5), + .x1 (x1), + .x2 (x2), + .x3 (x3), + .x4 (x4), + .x5 (x5), + // Inputs + .clk (clk), + .i (i[31:0])); + + // Aggregate outputs into a single result vector + // verilator lint_off WIDTH + wire [63:0] result = {a1,a2,a3,a4,a5, + o1,o2,o3,o4,o5, + x1,x2,x3,x4,x5}; + // verilator lint_on WIDTH + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); + $display("a %b %b %b %b %b", a1, a2, a3, a4, a5); + $display("o %b %b %b %b %b", o1, o2, o3, o4, o5); + $display("x %b %b %b %b %b", x1, x2, x3, x4, x5); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc < 10) begin + sum <= '0; + end + else if (cyc < 99) begin + if (a1 != a2) $stop; + if (a1 != a3) $stop; + if (a1 != a4) $stop; + if (a1 != a5) $stop; + if (o1 != o2) $stop; + if (o1 != o3) $stop; + if (o1 != o4) $stop; + if (o1 != o5) $stop; + if (x1 != x2) $stop; + if (x1 != x3) $stop; + if (x1 != x4) $stop; + if (x1 != x5) $stop; + end + else begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'hd7bd9c247dc7243c + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test(/*AUTOARG*/ + // Outputs + a1, a2, a3, a4, a5, o1, o2, o3, o4, o5, x1, x2, x3, x4, x5, + // Inputs + clk, i + ); + + input clk; + input [31:0] i; + + output logic a1, a2, a3, a4, a5; + output logic o1, o2, o3, o4, o5; + output logic x1, x2, x3, x4, x5; + + always_ff @(posedge clk) begin + a1 <= (i[5] & ~i[3] & i[1]); + a2 <= (i[5]==1 & i[3]==0 & i[1]==1); + a3 <= &{i[5], ~i[3], i[1]}; + a4 <= ((i & 32'b101010) == 32'b100010); + a5 <= ((i & 32'b001010) == 32'b000010) & i[5]; + // + o1 <= (~i[5] | i[3] | ~i[1]); + o2 <= (i[5]!=1 | i[3]!=0 | i[1]!=1); + o3 <= |{~i[5], i[3], ~i[1]}; + o4 <= ((i & 32'b101010) != 32'b100010); + o5 <= ((i & 32'b001010) != 32'b000010) | !i[5]; + // + x1 <= (i[5] ^ ~i[3] ^ i[1]); + x2 <= (i[5]==1 ^ i[3]==0 ^ i[1]==1); + x3 <= ^{i[5], ~i[3], i[1]}; + x4 <= ^((i & 32'b101010) ^ 32'b001000); + x5 <= ^((i & 32'b001010) ^ 32'b001000) ^ i[5]; + end + +endmodule From 9655e287abe6ae924586b30601e333ed3d4086fa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 17:06:03 -0500 Subject: [PATCH 65/88] Tests: Travis regression fix --- test_regress/t/t_const_opt_red.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/test_regress/t/t_const_opt_red.pl b/test_regress/t/t_const_opt_red.pl index b46d46042..b8d7ae067 100755 --- a/test_regress/t/t_const_opt_red.pl +++ b/test_regress/t/t_const_opt_red.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2=>["-Wno-UNOPTTHREADS"], ); execute( From 6e7b07c794fe67b06eab52666ff1c570baa5f7fe Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 18:58:31 -0500 Subject: [PATCH 66/88] Internals: Prep for #2597. No functional change intended --- src/V3Width.cpp | 70 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6b797d7ad..6555db0f0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1709,39 +1709,7 @@ private: width = 1; } userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); - AstBasicDType* underDtp = VN_CAST(nodep->lhsp()->dtypep(), BasicDType); - if (!underDtp) underDtp = nodep->lhsp()->dtypep()->basicp(); - if (!underDtp) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Size-changing cast on non-basic data type"); - underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType); - } - // A cast propagates its size to the lower expression and is included in the maximum - // width, so 23'(1'b1 + 1'b1) uses 23-bit math, but 1'(2'h2 * 2'h1) uses two-bit math. - // However the output width is exactly that requested. - // So two steps, first do the calculation's width (max of the two widths) - { - int calcWidth = std::max(width, underDtp->width()); - AstNodeDType* calcDtp - = (underDtp->isFourstate() - ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric()) - : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric())); - nodep->dtypep(calcDtp); - // We ignore warnings as that is sort of the point of a cast - iterateCheck(nodep, "Cast expr", nodep->lhsp(), CONTEXT, FINAL, calcDtp, - EXTEND_EXP, false); - } - // if (debug()) nodep->dumpTree(cout, " CastSizeClc: "); - // Next step, make the proper output width - { - AstNodeDType* outDtp - = (underDtp->isFourstate() - ? nodep->findLogicDType(width, width, underDtp->numeric()) - : nodep->findBitDType(width, width, underDtp->numeric())); - nodep->dtypep(outDtp); - // We ignore warnings as that is sort of the point of a cast - widthCheckSized(nodep, "Cast expr", nodep->lhsp(), outDtp, EXTEND_EXP, false); - } + castSized(nodep, nodep->lhsp(), width); // lhsp may change } if (m_vup->final()) { // CastSize not needed once sizes determined @@ -1751,6 +1719,42 @@ private: } // if (debug()) nodep->dumpTree(cout, " CastSizeOut: "); } + void castSized(AstNode* nodep, AstNode* underp, int width) { + AstBasicDType* underDtp = VN_CAST(underp->dtypep(), BasicDType); + if (!underDtp) underDtp = underp->dtypep()->basicp(); + if (!underDtp) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Size-changing cast on non-basic data type"); + underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType); + } + UASSERT_OBJ(underp == nodep->op1p(), nodep, "Assuming op1 is cast value"); + // A cast propagates its size to the lower expression and is included in the maximum + // width, so 23'(1'b1 + 1'b1) uses 23-bit math, but 1'(2'h2 * 2'h1) uses two-bit math. + // However the output width is exactly that requested. + // So two steps, first do the calculation's width (max of the two widths) + { + int calcWidth = std::max(width, underDtp->width()); + AstNodeDType* calcDtp + = (underDtp->isFourstate() + ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric()) + : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric())); + nodep->dtypep(calcDtp); + // We ignore warnings as that is sort of the point of a cast + iterateCheck(nodep, "Cast expr", underp, CONTEXT, FINAL, calcDtp, EXTEND_EXP, false); + VL_DANGLING(underp); + underp = nodep->op1p(); // Above asserts that op1 was underp pre-relink + } + // if (debug()) nodep->dumpTree(cout, " CastSizeClc: "); + // Next step, make the proper output width + { + AstNodeDType* outDtp = (underDtp->isFourstate() + ? nodep->findLogicDType(width, width, underDtp->numeric()) + : nodep->findBitDType(width, width, underDtp->numeric())); + nodep->dtypep(outDtp); + // We ignore warnings as that is sort of the point of a cast + widthCheckSized(nodep, "Cast expr", underp, outDtp, EXTEND_EXP, false); + VL_DANGLING(underp); + } + } virtual void visit(AstVar* nodep) override { // if (debug()) nodep->dumpTree(cout, " InitPre: "); // Must have deterministic constant width From d78941885b7b213133ca90881ec3ee9a2b74eaab Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 19:07:33 -0500 Subject: [PATCH 67/88] Fix cast width propagation (#2597). --- Changes | 2 + src/V3AstNodes.h | 1 + src/V3Width.cpp | 66 +++++++++++++++------------- test_regress/t/t_math_shift_extend.v | 27 ++++++++++++ 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/Changes b/Changes index bf1928f0c..ca1e6bff2 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett] +**** Fix cast width propagation (#2597). [flex-liu] + **** Fix return from callValueCbs (#2589) (#2605). [Marlon James] **** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 8d77fc54c..24334009d 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5953,6 +5953,7 @@ public: virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } AstNode* lhsp() const { return op1p(); } + void lhsp(AstNode* nodep) { setOp1p(nodep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6555db0f0..d735de1f4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1661,41 +1661,47 @@ private: // Note we don't sign lhsp() that would make the algorithm O(n^2) if lots of casting. AstBasicDType* basicp = nodep->dtypep()->basicp(); UASSERT_OBJ(basicp, nodep, "Unimplemented: Casting non-simple data type"); - // When implement more complicated types need to convert childDTypep to - // dtypep() not as a child - if (!basicp->isDouble() && !nodep->lhsp()->isDouble()) { - // Note widthCheckSized might modify nodep->lhsp() - AstNodeDType* subDTypep = nodep->findLogicDType(nodep->width(), nodep->width(), - nodep->lhsp()->dtypep()->numeric()); - iterateCheck(nodep, "value", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, - false); - } else { - iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), - EXTEND_EXP, false); - } - AstNode* newp = nodep->lhsp()->unlinkFrBack(); - if (basicp->isDouble() && !newp->isDouble()) { - if (newp->isSigned()) { - newp = new AstISToRD(nodep->fileline(), newp); + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); + // When implement more complicated types need to convert childDTypep to + // dtypep() not as a child + if (!basicp->isDouble() && !nodep->lhsp()->isDouble()) { + // Note castSized might modify nodep->lhsp() + int width = nodep->dtypep()->width(); + castSized(nodep, nodep->lhsp(), width); } else { - newp = new AstIToRD(nodep->fileline(), newp); + iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), + EXTEND_EXP, false); } - } else if (!basicp->isDouble() && newp->isDouble()) { - if (basicp->isSigned()) { - newp = new AstRToIRoundS(nodep->fileline(), newp); + AstNode* newp = nodep->lhsp()->unlinkFrBack(); + if (basicp->isDouble() && !newp->isDouble()) { + if (newp->isSigned()) { + newp = new AstISToRD(nodep->fileline(), newp); + } else { + newp = new AstIToRD(nodep->fileline(), newp); + } + } else if (!basicp->isDouble() && newp->isDouble()) { + if (basicp->isSigned()) { + newp = new AstRToIRoundS(nodep->fileline(), newp); + } else { + newp = new AstUnsigned(nodep->fileline(), + new AstRToIS(nodep->fileline(), newp)); + } + } else if (basicp->isSigned() && !newp->isSigned()) { + newp = new AstSigned(nodep->fileline(), newp); + } else if (!basicp->isSigned() && newp->isSigned()) { + newp = new AstUnsigned(nodep->fileline(), newp); } else { - newp = new AstUnsigned(nodep->fileline(), new AstRToIS(nodep->fileline(), newp)); + // newp = newp; // Can just remove cast } - } else if (basicp->isSigned() && !newp->isSigned()) { - newp = new AstSigned(nodep->fileline(), newp); - } else if (!basicp->isSigned() && newp->isSigned()) { - newp = new AstUnsigned(nodep->fileline(), newp); - } else { - // newp = newp; // Can just remove cast + nodep->lhsp(newp); + // if (debug()) nodep->dumpTree(cout, " CastOut: "); + } + if (m_vup->final()) { + AstNode* underp = nodep->lhsp()->unlinkFrBack(); + nodep->replaceWith(underp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - // if (debug()) newp->dumpTree(cout, " CastOut: "); } virtual void visit(AstCastSize* nodep) override { // IEEE: Signedness of result is same as self-determined signedness diff --git a/test_regress/t/t_math_shift_extend.v b/test_regress/t/t_math_shift_extend.v index b0f4707de..8e40234c0 100644 --- a/test_regress/t/t_math_shift_extend.v +++ b/test_regress/t/t_math_shift_extend.v @@ -9,9 +9,14 @@ module t (/*AUTOARG*/); logic in1 = 1; logic [1:0] in2 = 2'b11; logic [31:0] out; + logic [7:0] ones = 8'b11111111; + logic [9:0] ones10 = 10'b1111111111; typedef logic [7:0] data_t; + typedef logic [9:0] ten_t; + ten_t out10; + // verilator lint_off WIDTH initial begin in1 = 1; @@ -31,6 +36,28 @@ module t (/*AUTOARG*/); out = data_t'(in1 << in2); if (out != 8'b1000) $stop; + // Check upper bits get cleared when cast + in2 = 3; + out = data_t'(ones << in2); + if (out != 8'b11111000) $stop; + + in2 = 3; + out = data_t'(ones10 << in2); + if (out != 8'b11111000) $stop; + + // bug2597 + out = data_t'(10'h208 >> 2); + if (out != 8'h82) $stop; + + out = data_t'(10'h208 >> 2); + if (out != 8'h82) $stop; + + out = data_t'('h208 >> 2); + if (out != 8'h82) $stop; + + out10 = ten_t'('h404 >> 2); + if (out10 != 10'h101) $stop; + $write("*-* All Finished *-*\n"); $finish(); end From 67d5b1a11a3a05b0bd3796a1b4cc15f776f0a430 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 19:15:53 -0500 Subject: [PATCH 68/88] Internals: Preserve arrays of modports. Part of #2614. --- src/V3LinkDot.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2356c30a5..f7dc86027 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1866,14 +1866,16 @@ private: } } AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, - AstModport* modportp) { + AstModport* modportp, AstRange* rangep) { // Create iface variable, using duplicate var when under same module scope string varName = cellp->name() + "__Vmp__" + modportp->name() + "__Viftop" + cvtToStr(++m_modportNum); AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(), ifacep->name(), modportp->name()); idtypep->cellp(cellp); - AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep); + AstNodeDType* vdtypep = idtypep; + if (rangep) vdtypep = new AstUnpackArrayDType(fl, VFlagChildDType(), vdtypep, rangep); + AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), vdtypep); varp->isIfaceParent(true); m_modp->addStmtp(varp); return varp; @@ -2277,8 +2279,25 @@ private: m_ds.m_dotSymp = m_statep->getNodeSym(modportp); m_ds.m_dotPos = DP_SCOPE; ok = true; - AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp); - AstVarRef* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ); + auto* cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef); + AstRange* rangep = nullptr; + if (cellarrayrefp) + rangep = new AstRange(nodep->fileline(), + cellarrayrefp->selp()->cloneTree(true), + cellarrayrefp->selp()->cloneTree(true)); + AstVar* varp + = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp, rangep); + AstNode* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ); + if (cellarrayrefp) { + // iface[vec].modport became CellArrayRef(iface, lsb) + // Convert back to SelBit(iface, lsb) + UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl); + refp = new AstSelBit(cellarrayrefp->fileline(), refp, + cellarrayrefp->selp()->unlinkFrBack()); + refp->user3(true); // Don't process again + VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp); + m_ds.m_unlinkedScopep = nullptr; + } nodep->replaceWith(refp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } From 438fb016655ed0b8cb9a9870f876b1a2feeec3aa Mon Sep 17 00:00:00 2001 From: Dan Petrisko Date: Sun, 8 Nov 2020 18:55:33 -0800 Subject: [PATCH 69/88] Fix exited typo (#2634) --- src/Verilator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 16fd4c94e..a676082b5 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -657,7 +657,7 @@ static void execBuildJob() { const string cmdStr = buildMakeCmd(v3Global.opt.prefix() + ".mk", ""); const int exit_code = V3Os::system(cmdStr); if (exit_code != 0) { - v3error(cmdStr << " exitted with " << exit_code << std::endl); + v3error(cmdStr << " exited with " << exit_code << std::endl); exit(exit_code); } } @@ -669,7 +669,7 @@ static void execHierVerilation() { const string cmdStr = buildMakeCmd(makefile, target); const int exit_code = V3Os::system(cmdStr); if (exit_code != 0) { - v3error(cmdStr << " exitted with " << exit_code << std::endl); + v3error(cmdStr << " exited with " << exit_code << std::endl); exit(exit_code); } } From cef7708f38a0b665c7f1458c27a5d72e5b227227 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 22:02:35 -0500 Subject: [PATCH 70/88] Internals: Fix missed access change. No functional change intended. --- src/V3LinkDot.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index f7dc86027..a0af16b9c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1834,7 +1834,7 @@ private: m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*packagep*/); } } - AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, bool lvalue) { + AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) { // Return a variable if possible, auto converting a modport to variable if (!symp) { return nullptr; @@ -1843,7 +1843,7 @@ private: } else if (VN_IS(symp->nodep(), ModportVarRef)) { AstModportVarRef* snodep = VN_CAST(symp->nodep(), ModportVarRef); AstVar* varp = snodep->varp(); - if (lvalue && snodep->direction().isReadOnly()) { + if (access.isWriteOrRW() && snodep->direction().isReadOnly()) { nodep->v3error("Attempt to drive input-only modport: " << nodep->prettyNameQ()); } // else other simulators don't warn about reading, and IEEE doesn't say illegal return varp; @@ -2194,7 +2194,7 @@ private: << cellp->modp()->prettyNameQ()); } } - } else if (AstVar* varp = foundToVarp(foundp, nodep, false)) { + } else if (AstVar* varp = foundToVarp(foundp, nodep, VAccess::READ)) { AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep()); if (ifacerefp) { UASSERT_OBJ(ifacerefp->ifaceViaCellp(), ifacerefp, "Unlinked interface"); From fc52fb90930eecb93cc69695045463fa38ebf3fb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 22:43:32 -0500 Subject: [PATCH 71/88] Fix arrays of modport interfaces (#2614). --- Changes | 2 + src/V3Inst.cpp | 3 ++ src/V3LinkDot.cpp | 61 +++++++++++---------------- src/V3LinkResolve.cpp | 10 +++++ src/V3Scope.cpp | 1 + test_regress/t/t_interface_ar2a.pl | 17 ++++++++ test_regress/t/t_interface_ar2a.v | 30 ++++++++++++++ test_regress/t/t_interface_ar2b.pl | 17 ++++++++ test_regress/t/t_interface_ar2b.v | 35 ++++++++++++++++ test_regress/t/t_interface_ar3.out | 9 ++++ test_regress/t/t_interface_ar3.pl | 23 +++++++++++ test_regress/t/t_interface_ar3.v | 66 ++++++++++++++++++++++++++++++ 12 files changed, 238 insertions(+), 36 deletions(-) create mode 100755 test_regress/t/t_interface_ar2a.pl create mode 100644 test_regress/t/t_interface_ar2a.v create mode 100755 test_regress/t/t_interface_ar2b.pl create mode 100644 test_regress/t/t_interface_ar2b.v create mode 100644 test_regress/t/t_interface_ar3.out create mode 100755 test_regress/t/t_interface_ar3.pl create mode 100644 test_regress/t/t_interface_ar3.v diff --git a/Changes b/Changes index ca1e6bff2..9dc1d5344 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix queue poping wrong value when otherwise unused (#2512). [nanduraj1] +**** Fix arrays of modport interfaces (#2614). [Thierry Tambe] + * Verilator 4.102 2020-10-15 diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index a7dc03ee8..88e6899c3 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -377,7 +377,10 @@ private: return; } string index = AstNode::encodeNumber(constp->toSInt()); + if (VN_IS(arrselp->lhsp(), SliceSel)) + arrselp->lhsp()->v3error("Unsupported: interface slices"); AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef); + UASSERT_OBJ(varrefp, arrselp, "No interface varref under array"); AstVarXRef* newp = new AstVarXRef(nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", VAccess::WRITE); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index a0af16b9c..8274b84fd 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -46,6 +46,8 @@ // #8: Insert modport's symbols under IfaceRefDType (after #7) // ResolveVisitor: // #9: Resolve general variables, which may point into the interface or modport (after #8) +// LinkResolve: +// #10: Unlink modports, not needed later except for XML/Lint //************************************************************************* // TOP // {name-of-top-modulename} @@ -1865,20 +1867,12 @@ private: m_ds.m_dotErr = true; } } - AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, - AstModport* modportp, AstRange* rangep) { - // Create iface variable, using duplicate var when under same module scope - string varName - = cellp->name() + "__Vmp__" + modportp->name() + "__Viftop" + cvtToStr(++m_modportNum); - AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, modportp->fileline(), cellp->name(), - ifacep->name(), modportp->name()); - idtypep->cellp(cellp); - AstNodeDType* vdtypep = idtypep; - if (rangep) vdtypep = new AstUnpackArrayDType(fl, VFlagChildDType(), vdtypep, rangep); - AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), vdtypep); - varp->isIfaceParent(true); - m_modp->addStmtp(varp); - return varp; + AstVar* findIfaceTopVarp(AstNode* nodep, VSymEnt* parentEntp, const string& name) { + string findName = name + "__Viftop"; + VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName); + AstVar* ifaceTopVarp = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr; + UASSERT_OBJ(ifaceTopVarp, nodep, "Can't find interface var ref: " << findName); + return ifaceTopVarp; } void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) { if (refp->user5p() && refp->user5p() != nodep) { @@ -2173,12 +2167,7 @@ private: VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or // generate begin - string findName = nodep->name() + "__Viftop"; - VSymEnt* ifaceSymp = parentEntp->findIdFallback(findName); - AstVar* ifaceRefVarp - = ifaceSymp ? VN_CAST(ifaceSymp->nodep(), Var) : nullptr; - UASSERT_OBJ(ifaceRefVarp, nodep, - "Can't find interface var ref: " << findName); + AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, nodep->name()); // ok = true; m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); @@ -2273,32 +2262,32 @@ private: } else { AstCell* cellp = VN_CAST(m_ds.m_dotSymp->nodep(), Cell); UASSERT_OBJ(cellp, nodep, "Modport not referenced from a cell"); - AstIface* ifacep = VN_CAST(cellp->modp(), Iface); - // string cellName = m_ds.m_dotText; // Use cellp->name - m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); - m_ds.m_dotSymp = m_statep->getNodeSym(modportp); - m_ds.m_dotPos = DP_SCOPE; + VSymEnt* cellEntp = m_statep->getNodeSym(cellp); + UASSERT_OBJ(cellEntp, nodep, "No interface sym entry"); + VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a + // module or generate begin + // We drop __BRA__??__KET__ as cells don't have that naming yet + AstVar* ifaceRefVarp = findIfaceTopVarp(nodep, parentEntp, cellp->name()); + // ok = true; + m_ds.m_dotText = VString::dot(m_ds.m_dotText, ".", nodep->name()); + m_ds.m_dotSymp = foundp; + m_ds.m_dotPos = DP_SCOPE; + UINFO(9, " cell -> iface varref " << foundp->nodep() << endl); + AstNode* newp + = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ); auto* cellarrayrefp = VN_CAST(m_ds.m_unlinkedScopep, CellArrayRef); - AstRange* rangep = nullptr; - if (cellarrayrefp) - rangep = new AstRange(nodep->fileline(), - cellarrayrefp->selp()->cloneTree(true), - cellarrayrefp->selp()->cloneTree(true)); - AstVar* varp - = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp, rangep); - AstNode* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ); if (cellarrayrefp) { // iface[vec].modport became CellArrayRef(iface, lsb) // Convert back to SelBit(iface, lsb) UINFO(9, " Array modport to SelBit " << cellarrayrefp << endl); - refp = new AstSelBit(cellarrayrefp->fileline(), refp, + newp = new AstSelBit(cellarrayrefp->fileline(), newp, cellarrayrefp->selp()->unlinkFrBack()); - refp->user3(true); // Don't process again + newp->user3(true); // Don't process again VL_DO_DANGLING(cellarrayrefp->unlinkFrBack(), cellarrayrefp); m_ds.m_unlinkedScopep = nullptr; } - nodep->replaceWith(refp); + nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } } else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 1f7fdaff7..bd7286e9e 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -502,6 +502,16 @@ private: iterateChildren(nodep); } + virtual void visit(AstIfaceRefDType* nodep) override { + // LinkDot checked modports, now remove references to them + // Keeping them later caused problems with InstDeArray, + // as it needed to make new modport arrays and such + nodep->modportp(nullptr); + iterateChildren(nodep); + } + // virtual void visit(AstModport* nodep) override { ... } + // We keep Modport's themselves around for XML dump purposes + virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 7e54b0a30..9e3d19886 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -377,6 +377,7 @@ private: iterateChildren(nodep); } virtual void visit(AstModportFTaskRef* nodep) override { + // The modport persists only for xml dump // The crossrefs are dealt with in V3LinkDot nodep->ftaskp(nullptr); iterateChildren(nodep); diff --git a/test_regress/t/t_interface_ar2a.pl b/test_regress/t/t_interface_ar2a.pl new file mode 100755 index 000000000..552bd97db --- /dev/null +++ b/test_regress/t/t_interface_ar2a.pl @@ -0,0 +1,17 @@ +#!/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(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_ar2a.v b/test_regress/t/t_interface_ar2a.v new file mode 100644 index 000000000..f0c406843 --- /dev/null +++ b/test_regress/t/t_interface_ar2a.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: SystemVerilog interface test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Thierry Tambe. +// SPDX-License-Identifier: CC0-1.0 + +module t (); + + ahb_slave_intf AHB_S[1](); + + AHB_MEM uMEM(.S(AHB_S[0].source)); +// AHB_MEM V_MEM(.S(AHB_S[0])); + +endmodule + +module AHB_MEM + ( + ahb_slave_intf.source S + ); + +endmodule + +interface ahb_slave_intf + (); + + logic [31:0] HADDR; + + modport source (input HADDR); + +endinterface diff --git a/test_regress/t/t_interface_ar2b.pl b/test_regress/t/t_interface_ar2b.pl new file mode 100755 index 000000000..552bd97db --- /dev/null +++ b/test_regress/t/t_interface_ar2b.pl @@ -0,0 +1,17 @@ +#!/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(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_ar2b.v b/test_regress/t/t_interface_ar2b.v new file mode 100644 index 000000000..b14ae8cbc --- /dev/null +++ b/test_regress/t/t_interface_ar2b.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: SystemVerilog interface test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Thierry Tambe. +// SPDX-License-Identifier: CC0-1.0 + +module t (); + + sub sub [1] (); + + ahb_slave_intf AHB_S[1](); + + AHB_MEM uMEM(.S(AHB_S[0])); +// AHB_MEM uMEM(.S(AHB_S[0].source)); + +endmodule + +module sub; +endmodule + +module AHB_MEM + ( + ahb_slave_intf.source S + ); + +endmodule + +interface ahb_slave_intf + (); + + logic [31:0] HADDR; + + modport source (input HADDR); + +endinterface diff --git a/test_regress/t/t_interface_ar3.out b/test_regress/t/t_interface_ar3.out new file mode 100644 index 000000000..e28530a56 --- /dev/null +++ b/test_regress/t/t_interface_ar3.out @@ -0,0 +1,9 @@ +%Error: t/t_interface_ar3.v:16:36: Unsupported: interface slices + : ... In instance t + 16 | sub sub01 [2] (.clk, .infc(iinst[0:1])); + | ^ +%Error: Internal Error: t/t_interface_ar3.v:16:36: ../V3Inst.cpp:#: No interface varref under array + : ... In instance t + 16 | sub sub01 [2] (.clk, .infc(iinst[0:1])); + | ^ + ... See the manual and https://verilator.org for more assistance. diff --git a/test_regress/t/t_interface_ar3.pl b/test_regress/t/t_interface_ar3.pl new file mode 100755 index 000000000..8d48ddb75 --- /dev/null +++ b/test_regress/t/t_interface_ar3.pl @@ -0,0 +1,23 @@ +#!/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(simulator => 1); + +compile( + fails => $Self->{vlt_all}, # Verilator unsupported, bug546 + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_interface_ar3.v b/test_regress/t/t_interface_ar3.v new file mode 100644 index 000000000..74416a300 --- /dev/null +++ b/test_regress/t/t_interface_ar3.v @@ -0,0 +1,66 @@ +// DESCRIPTION: Verilator: SystemVerilog interface test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Thierry Tambe. +// SPDX-License-Identifier: CC0-1.0 + +module t ( + input logic clk, + output logic HRESETn + ); + + int primsig[3]; + + ahb_slave_intf iinst[3] (primsig[2:0]); + + sub sub01 [2] (.clk, .infc(iinst[0:1])); + sub sub2 (.clk, .infc(iinst[2])); + + initial begin + primsig[0] = 30; + primsig[1] = 31; + primsig[2] = 32; + iinst[0].data = 10; + iinst[1].data = 11; + iinst[2].data = 12; + end + + int cyc = 0; + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + if (iinst[0].primsig != 30) $stop; + if (iinst[1].primsig != 31) $stop; + if (iinst[2].primsig != 32) $stop; + if (iinst[0].data != 10) $stop; + if (iinst[1].data != 11) $stop; + if (iinst[2].data != 12) $stop; + if (sub01[0].internal != 10) $stop; + if (sub01[1].internal != 11) $stop; + if (sub2.internal != 12) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule + +module sub +( + input logic clk, + ahb_slave_intf infc + ); + + int internal; + + always_comb internal = infc.data; + +endmodule + +interface ahb_slave_intf + ( + input int primsig + ); + + int data; + +endinterface From 6965e138aa84a2b3ffc18a26918ef483c6f496d1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 Nov 2020 23:26:58 -0500 Subject: [PATCH 72/88] Add clearer unsupported message for inside on array (#2566) --- src/V3Width.cpp | 3 ++ test_regress/t/t_inside_unpack.out | 4 +++ test_regress/t/t_inside_unpack.pl | 23 +++++++++++++ test_regress/t/t_inside_unpack.v | 54 ++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 test_regress/t/t_inside_unpack.out create mode 100755 test_regress/t/t_inside_unpack.pl create mode 100644 test_regress/t/t_inside_unpack.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d735de1f4..9719b0988 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2134,6 +2134,9 @@ private: // Similar logic in V3Case inewp = irangep->newAndFromInside(nodep->exprp(), irangep->lhsp()->unlinkFrBack(), irangep->rhsp()->unlinkFrBack()); + } else if (auto* irangep = VN_CAST(itemp->dtypep(), UnpackArrayDType)) { + irangep->v3error("Unsupported: inside on unpacked array"); + continue; } else { inewp = new AstEqWild(itemp->fileline(), nodep->exprp()->cloneTree(true), itemp->unlinkFrBack()); diff --git a/test_regress/t/t_inside_unpack.out b/test_regress/t/t_inside_unpack.out new file mode 100644 index 000000000..e7037fc4a --- /dev/null +++ b/test_regress/t/t_inside_unpack.out @@ -0,0 +1,4 @@ +%Error: t/t_inside_unpack.v:13:31: Unsupported: inside on unpacked array + 13 | localparam int CHECKLIST_P [2:0] = '{0, 1, 2}; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_inside_unpack.pl b/test_regress/t/t_inside_unpack.pl new file mode 100755 index 000000000..40f69d41d --- /dev/null +++ b/test_regress/t/t_inside_unpack.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_inside_unpack.v b/test_regress/t/t_inside_unpack.v new file mode 100644 index 000000000..f15184aa5 --- /dev/null +++ b/test_regress/t/t_inside_unpack.v @@ -0,0 +1,54 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + localparam int CHECKLIST_P [2:0] = '{0, 1, 2}; + + localparam HIT_LP = 1; + localparam MISS_LP = 4; + localparam HIT_INSIDE = HIT_LP inside {CHECKLIST_P}; + localparam MISS_INSIDE = MISS_LP inside {CHECKLIST_P}; + + initial begin + if (HIT_INSIDE != 1) $stop; + if (MISS_INSIDE != 0) $stop; + end + + integer cyc=0; + + int array [10]; + logic l; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + // Setup + array[0] = 10; + array[1] = 20; + array[9] = 90; + end + else if (cyc < 99) begin + l = (10 inside {array}); + if (l != 1) $stop; + l = (20 inside {array}); + if (l != 1) $stop; + l = (90 inside {array}); + if (l != 1) $stop; + l = (99 inside {array}); + if (l != 0) $stop; + end + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From 8664aac225d8d92567d7bbd5fc939bab5aa87622 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 9 Nov 2020 18:29:09 -0500 Subject: [PATCH 73/88] Fix missing newlines in emit. --- src/V3EmitC.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 6109ff891..e670b3c47 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3229,13 +3229,13 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n// INTERNAL METHODS\n"); if (modp->isTop()) { - ofp()->putsPrivate(true); // private: + ofp()->putsPrivate(false); // public: as accessed by another VL_MODULE puts("static void " + protect("_eval_initial_loop") + "(" + EmitCBaseVisitor::symClassVar() + ");\n"); if (v3Global.needTraceDumper()) { - if (!optSystemC()) puts("void _traceDump();"); - puts("void _traceDumpOpen();"); - puts("void _traceDumpClose();"); + if (!optSystemC()) puts("void _traceDump();\n"); + puts("void _traceDumpOpen();\n"); + puts("void _traceDumpClose();\n"); } } From 44eb362a18b27393e7370d2008bf18c2ef6cb3f2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 10 Nov 2020 21:40:14 -0500 Subject: [PATCH 74/88] clang-tidy cleanups. No functional change intended. --- Makefile.in | 4 +- include/verilated.cpp | 6 +-- include/verilated_heavy.h | 8 ++- include/verilated_threads.cpp | 6 +-- include/verilated_trace_imp.cpp | 3 ++ include/verilated_vpi.cpp | 86 ++++++++++++++++----------------- src/V3Ast.h | 2 +- src/V3AstNodes.cpp | 14 +++--- src/V3CUse.cpp | 2 +- src/V3Cast.cpp | 2 +- src/V3Cdc.cpp | 5 +- src/V3Const.cpp | 3 +- src/V3EmitC.cpp | 9 ++-- src/V3EmitCMake.cpp | 22 ++++----- src/V3EmitCSyms.cpp | 4 +- src/V3EmitMk.cpp | 1 - src/V3File.cpp | 4 +- src/V3FileLine.cpp | 6 +-- src/V3Gate.cpp | 10 ++-- src/V3GraphDfa.cpp | 4 +- src/V3Hashed.h | 5 +- src/V3HierBlock.cpp | 2 +- src/V3HierBlock.h | 2 +- src/V3Inline.cpp | 2 +- src/V3Inst.cpp | 1 - src/V3Life.cpp | 27 ++++------- src/V3LifePost.cpp | 13 ++--- src/V3LinkResolve.cpp | 14 +++--- src/V3Options.cpp | 2 +- src/V3Options.h | 10 ++-- src/V3Order.cpp | 18 ++++--- src/V3ParseLex.cpp | 2 +- src/V3Partition.cpp | 8 +-- src/V3PreProc.cpp | 28 +++++------ src/V3SplitVar.cpp | 18 +++---- src/V3TSP.cpp | 10 ++-- src/V3Width.cpp | 14 +++--- 37 files changed, 184 insertions(+), 193 deletions(-) diff --git a/Makefile.in b/Makefile.in index 8b89d5d1e..6e2dc2ec7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -442,11 +442,11 @@ cppcheck: $(CPPCHECK_DEP) $(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $< CLANGTIDY = clang-tidy -CLANGTIDY_FLAGS = -config='' +CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables' CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \ $(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP)) -clangtidy: $(CLANGTIDY_DEP) +clang-tidy: $(CLANGTIDY_DEP) %.cpp.tidy: %.cpp $(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@ %.h.tidy: %.h diff --git a/include/verilated.cpp b/include/verilated.cpp index 6d9d7b6e4..d976d45a5 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -556,7 +556,7 @@ WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, W return owp; } } - return 0; + return owp; } return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp); } @@ -1301,8 +1301,8 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE { } // declared in verilated_heavy.h -IData VL_FGETS_NI(std::string& str, IData fpi) VL_MT_SAFE { - return getLine(str, fpi, std::numeric_limits::max()); +IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE { + return getLine(dest, fpi, std::numeric_limits::max()); } IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE { diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 0e58fe4cb..0c4d2eb83 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -854,18 +854,16 @@ extern std::string VL_SUBSTR_N(const std::string& lhs, IData rhs, IData ths) VL_ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool ignoreCase) VL_PURE { // SystemVerilog does not allow a string variable to contain '\0'. // So C functions such as strcmp() can correctly compare strings. - int result; if (ignoreCase) { - result = VL_STRCASECMP(lhs.c_str(), rhs.c_str()); + return VL_STRCASECMP(lhs.c_str(), rhs.c_str()); } else { - result = std::strcmp(lhs.c_str(), rhs.c_str()); + return std::strcmp(lhs.c_str(), rhs.c_str()); } - return result; } extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE; -extern IData VL_FGETS_NI(std::string& destp, IData fpi); +extern IData VL_FGETS_NI(std::string& dest, IData fpi); //====================================================================== // Dumping diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index 1a6d1277e..7318c92de 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -98,10 +98,8 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling) } VlThreadPool::~VlThreadPool() { - for (int i = 0; i < m_workers.size(); ++i) { - // Each ~WorkerThread will wait for its thread to exit. - delete m_workers[i]; - } + // Each ~WorkerThread will wait for its thread to exit. + for (auto& i : m_workers) delete i; if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread(); } diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 5de211590..ee2a31e35 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -19,6 +19,7 @@ // clang-format off +#ifndef VL_CPPCHECK #ifndef VL_DERIVED_T # error "This file should be included in trace format implementations" #endif @@ -641,3 +642,5 @@ inline static void cvtQDataToStr(char* dstp, QData value) { } #define cvtEDataToStr cvtIDataToStr + +#endif // VL_CPPCHECK diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 931df8210..e1a2977a3 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -96,7 +96,7 @@ public: virtual vluint32_t type() const { return 0; } virtual vluint32_t size() const { return 0; } virtual const VerilatedRange* rangep() const { return nullptr; } - virtual vpiHandle dovpi_scan() { return 0; } + virtual vpiHandle dovpi_scan() { return nullptr; } }; typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*); @@ -187,7 +187,7 @@ public: nextp->iterationInc(); return ((nextp)->castVpiHandle()); } - return 0; // End of list - only one deep + return nullptr; // End of list - only one deep } }; @@ -312,14 +312,14 @@ public: m_it = varsp->begin(); m_started = true; } else if (VL_UNLIKELY(m_it == varsp->end())) { - return 0; + return nullptr; } else { ++m_it; } - if (m_it == varsp->end()) return 0; + if (m_it == varsp->end()) return nullptr; return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle()); } - return 0; // End of list - only one deep + return nullptr; // End of list - only one deep } }; @@ -346,7 +346,7 @@ public: } virtual vpiHandle dovpi_scan() override { vpiHandle result; - if (m_done) return 0; + if (m_done) return nullptr; result = vpi_handle_by_index(m_handle, m_iteration); iterationInc(); return result; @@ -387,7 +387,7 @@ public: } virtual vluint32_t type() const override { return vpiIterator; } virtual vpiHandle dovpi_scan() override { - if (m_it == m_vec->end()) return 0; + if (m_it == m_vec->end()) return nullptr; const VerilatedScope* modp = *m_it++; return (new VerilatedVpioModule(modp))->castVpiHandle(); } @@ -1053,10 +1053,10 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) { } } -PLI_INT32 vpi_remove_cb(vpiHandle object) { - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", object);); +PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) { + VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj);); VerilatedVpiImp::assertOneCheck(); - VerilatedVpioCb* vop = VerilatedVpioCb::castp(object); + VerilatedVpioCb* vop = VerilatedVpioCb::castp(cb_obj); _VL_VPI_ERROR_RESET(); if (VL_UNLIKELY(!vop)) return 0; if (vop->cb_datap()->reason == cbAfterDelay) { @@ -1070,7 +1070,7 @@ PLI_INT32 vpi_remove_cb(vpiHandle object) { void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { _VL_VPI_UNIMP(); } vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) { _VL_VPI_UNIMP(); - return 0; + return nullptr; } void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) { _VL_VPI_UNIMP(); @@ -1136,24 +1136,24 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { VerilatedVpioVar* varop = VerilatedVpioVar::castp(object); _VL_VPI_ERROR_RESET(); if (VL_LIKELY(varop)) { - if (varop->varp()->dims() < 2) return 0; + if (varop->varp()->dims() < 2) return nullptr; if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) { if (VL_UNLIKELY(indx > varop->varp()->unpacked().left() || indx < varop->varp()->unpacked().right())) - return 0; + return nullptr; return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx, indx - varop->varp()->unpacked().right())) ->castVpiHandle(); } if (VL_UNLIKELY(indx < varop->varp()->unpacked().left() || indx > varop->varp()->unpacked().right())) - return 0; + return nullptr; return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx, indx - varop->varp()->unpacked().left())) ->castVpiHandle(); } _VL_VPI_INTERNAL(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC); - return 0; + return nullptr; } // for traversing relationships @@ -1165,56 +1165,56 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) { switch (type) { case vpiLeftRange: { if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - if (VL_UNLIKELY(!vop->rangep())) return 0; + if (VL_UNLIKELY(!vop->rangep())) return nullptr; return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle(); } else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) { - if (VL_UNLIKELY(!vop->rangep())) return 0; + if (VL_UNLIKELY(!vop->rangep())) return nullptr; return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle(); } _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned", VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type)); - return 0; + return nullptr; } case vpiRightRange: { if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - if (VL_UNLIKELY(!vop->rangep())) return 0; + if (VL_UNLIKELY(!vop->rangep())) return nullptr; return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle(); } else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) { - if (VL_UNLIKELY(!vop->rangep())) return 0; + if (VL_UNLIKELY(!vop->rangep())) return nullptr; return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle(); } _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned", VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type)); - return 0; + return nullptr; } case vpiIndex: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; return (new VerilatedVpioConst(vop->index()))->castVpiHandle(); } case vpiScope: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle(); } case vpiParent: { VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle(); } default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", VL_FUNC, VerilatedVpiError::strFromVpiMethod(type)); - return 0; + return nullptr; } } vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/, ...) { _VL_VPI_UNIMP(); - return 0; + return nullptr; } vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { @@ -1224,8 +1224,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { switch (type) { case vpiMemoryWord: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); - if (VL_UNLIKELY(!vop)) return 0; - if (vop->varp()->dims() < 2) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; + if (vop->varp()->dims() < 2) return nullptr; if (vop->varp()->dims() > 2) { _VL_VPI_WARNING(__FILE__, __LINE__, "%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC, @@ -1236,8 +1236,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { } case vpiRange: { VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); - if (VL_UNLIKELY(!vop)) return 0; - if (vop->varp()->dims() < 2) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; + if (vop->varp()->dims() < 2) return nullptr; // Unsupported is multidim list if (vop->varp()->dims() > 2) { _VL_VPI_WARNING(__FILE__, __LINE__, @@ -1249,7 +1249,7 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { } case vpiReg: { VerilatedVpioScope* vop = VerilatedVpioScope::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return nullptr; return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle()); } case vpiModule: { @@ -1257,13 +1257,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) { const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap(); const VerilatedScope* mod = vop ? vop->scopep() : nullptr; const auto it = vlstd::as_const(map)->find(const_cast(mod)); - if (it == map->end()) return 0; + if (it == map->end()) return nullptr; return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle()); } default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", VL_FUNC, VerilatedVpiError::strFromVpiObjType(type)); - return 0; + return nullptr; } } vpiHandle vpi_scan(vpiHandle object) { @@ -1347,7 +1347,7 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) { default: _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", VL_FUNC, VerilatedVpiError::strFromVpiProp(property)); - return 0; + return nullptr; } } @@ -1644,7 +1644,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_ _VL_VPI_ERROR_RESET(); if (VL_UNLIKELY(!valuep)) { _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer"); - return 0; + return nullptr; } if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { VL_DEBUG_IF_PLI( @@ -1657,9 +1657,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_ "Ignoring vpi_put_value to signal marked read-only," " use public_flat_rw instead: %s", vop->fullname()); - return 0; + return nullptr; } - if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0; + if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr; if (valuep->format == vpiVectorVal) { if (VL_UNLIKELY(!valuep->value.vector)) return nullptr; if (vop->varp()->vltype() == VLVT_UINT8) { @@ -1760,7 +1760,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_ _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s", VL_FUNC, valuep->value.str, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname()); - return 0; + return nullptr; } if (success > 1) { _VL_VPI_WARNING(__FILE__, __LINE__, @@ -1849,11 +1849,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_ } else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) { _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s", VL_FUNC, vop->fullname()); - return 0; + return nullptr; } else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s", VL_FUNC, vop->fullname()); - return 0; + return nullptr; } _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object); return nullptr; @@ -1915,7 +1915,7 @@ PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) { _VL_VPI_UNIMP(); - return 0; + return nullptr; } PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) { @@ -2025,7 +2025,7 @@ PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*num } void* vpi_get_userdata(vpiHandle /*obj*/) { _VL_VPI_UNIMP(); - return 0; + return nullptr; } PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) { _VL_VPI_UNIMP(); @@ -2056,5 +2056,5 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) { vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/, PLI_INT32* /*index_array*/) { _VL_VPI_UNIMP(); - return 0; + return nullptr; } diff --git a/src/V3Ast.h b/src/V3Ast.h index 3f94d53b3..120bb13ad 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2463,7 +2463,7 @@ public: private: class CTypeRecursed; - CTypeRecursed cTypeRecurse(bool forFunc, bool compound) const; + CTypeRecursed cTypeRecurse(bool compound) const; }; class AstNodeUOrStructDType : public AstNodeDType { diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 92a3ac153..d796631e1 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -568,23 +568,23 @@ public: }; string AstNodeDType::cType(const string& name, bool forFunc, bool isRef) const { - CTypeRecursed info = cTypeRecurse(forFunc, false); + CTypeRecursed info = cTypeRecurse(false); return info.render(name, isRef); } -AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool forFunc, bool compound) const { +AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { CTypeRecursed info; const AstNodeDType* dtypep = this->skipRefp(); if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { - const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(false, true); - const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(false, true); + const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true); + const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">"; } else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { - const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, true); + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlQueue<" + sub.m_type + ">"; } else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { - const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, true); + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlQueue<" + sub.m_type; // + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1 if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1); @@ -595,7 +595,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool forFunc, bool compou if (compound) { v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported"); } - const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(false, compound); + const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound); info.m_type = sub.m_type; info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims; } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 88c1cbe20..698378314 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -148,7 +148,7 @@ class CUseVisitor : public AstNVisitor { funcp->isStatic(false); funcp->protect(false); AstNode* exprp = new AstCMath(nodep->fileline(), - "std::string(\"'{\") + to_string_middle() + \"}\"", 0); + R"(std::string("'{") + to_string_middle() + "}")", 0); exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn(nodep->fileline(), exprp)); nodep->addStmtp(funcp); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 2a8173978..faa0eedad 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -73,7 +73,7 @@ private: ensureLower32Cast(castp); nodep->user1(1); // Now must be of known size } - int castSize(AstNode* nodep) { + static int castSize(AstNode* nodep) { if (nodep->isQuad()) { return VL_QUADSIZE; } else if (nodep->width() <= 8) { diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 993f016fd..202ef4001 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -311,13 +311,12 @@ private: } } - string spaces(int level) { + static string spaces(int level) { string out; while (level--) out += " "; return out; } // LCOV_EXCL_LINE - - string pad(unsigned column, const string& in) { + static string pad(unsigned column, const string& in) { string out = in; while (out.length() < column) out += ' '; return out; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index cc05c126c..8f71622b6 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1941,7 +1941,8 @@ private: ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep)); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting + } else if (false // Disabled, as vpm assertions are faster + // without due to short-circuiting && operandIfIf(nodep)) { UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl); AstNodeIf* lowerIfp = VN_CAST(nodep->ifsp(), NodeIf); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index e670b3c47..ee4712910 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1245,7 +1245,6 @@ public: nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName()); } -public: EmitCStmts() { m_suppressSemi = false; m_wideTempRefp = nullptr; @@ -2353,7 +2352,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep, const str //###################################################################### // Internal EmitC -void EmitCImp::emitCoverageDecl(AstNodeModule* modp) { +void EmitCImp::emitCoverageDecl(AstNodeModule*) { if (v3Global.opt.coverage()) { ofp()->putsPrivate(true); putsDecoration("// Coverage\n"); @@ -2400,7 +2399,7 @@ void EmitCImp::emitMTaskVertexCtors(bool* firstp) { void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); bool first = true; - string section(""); + string section; emitParams(modp, true, &first, section /*ref*/); if (VN_IS(modp, Class)) { @@ -2480,7 +2479,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) { splitSizeInc(10); } -void EmitCImp::emitCoverageImp(AstNodeModule* modp) { +void EmitCImp::emitCoverageImp(AstNodeModule*) { if (v3Global.opt.coverage()) { puts("\n// Coverage\n"); // Rather than putting out VL_COVER_INSERT calls directly, we do it via this function @@ -3033,7 +3032,7 @@ void EmitCImp::emitMTaskState() { puts("bool __Vm_even_cycle;\n"); } -void EmitCImp::emitIntTop(AstNodeModule* modp) { +void EmitCImp::emitIntTop(AstNodeModule*) { // Always have this first; gcc has short circuiting if #ifdef is first in a file ofp()->putsGuard(); puts("\n"); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 2b14984fc..ffc4eb31a 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -150,37 +150,37 @@ class CMakeEmitter { } } - global.push_back("${VERILATOR_ROOT}/include/verilated.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated.cpp"); if (v3Global.dpi()) { // - global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp"); } if (v3Global.opt.vpi()) { - global.push_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp"); } if (v3Global.opt.savable()) { - global.push_back("${VERILATOR_ROOT}/include/verilated_save.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated_save.cpp"); } if (v3Global.opt.coverage()) { - global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated_cov.cpp"); } if (v3Global.opt.trace()) { - global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() - + "_c.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() + + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { v3warn(E_UNSUPPORTED, "Unsupported: This trace format is not supported in SystemC, " "use VCD format."); } - global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() - + ".cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() + + ".cpp"); } } if (v3Global.opt.mtasks()) { - global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); + global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); } if (!v3Global.opt.protectLib().empty()) { - global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp"); + global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp"); } *of << "# Global classes, need linked once per executable\n"; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 5c1fb26bd..8d8bc81af 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -296,7 +296,7 @@ class EmitCSyms : EmitCBaseVisitor { if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible nameCheck(nodep); - m_scopes.push_back(make_pair(nodep, m_modp)); + m_scopes.emplace_back(make_pair(nodep, m_modp)); if (v3Global.opt.vpi() && !nodep->isTop()) { string name_dedot = AstNode::dedotName(nodep->shortName()); @@ -331,7 +331,7 @@ class EmitCSyms : EmitCBaseVisitor { virtual void visit(AstVar* nodep) override { nameCheck(nodep); iterateChildren(nodep); - if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); } + if (nodep->isSigUserRdPublic()) { m_modVars.emplace_back(make_pair(m_modp, nodep)); } } virtual void visit(AstCoverDecl* nodep) override { // Assign numbers to all bins, so we know how big of an array to use diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 55312dbe3..813ac0367 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -281,7 +281,6 @@ public: of.putsHeader(); } -public: explicit EmitMk() { emitClassMake(); emitOverallMake(); diff --git a/src/V3File.cpp b/src/V3File.cpp index 465458a72..5acdafa57 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -587,12 +587,12 @@ protected: } return true; } - size_t listSize(StrList& sl) { + static size_t listSize(StrList& sl) { size_t out = 0; for (const string& i : sl) out += i.length(); return out; } - string listString(StrList& sl) { + static string listString(StrList& sl) { string out; for (const string& i : sl) out += i; return out; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 118292375..5d048f101 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -90,8 +90,8 @@ int VFileContent::debug() { void VFileContent::pushText(const string& text) { if (m_lines.size() == 0) { - m_lines.push_back(""); // no such thing as line [0] - m_lines.push_back(""); // start with no leftover + m_lines.emplace_back(""); // no such thing as line [0] + m_lines.emplace_back(""); // start with no leftover } // Any leftover text is stored on largest line (might be "") @@ -112,7 +112,7 @@ void VFileContent::pushText(const string& text) { } } // Keep leftover for next time - m_lines.push_back(string(leftover, line_start)); // Might be "" + m_lines.emplace_back(string(leftover, line_start)); // Might be "" } string VFileContent::getLine(int lineno) const { diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 962baa03d..0276ee97c 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -603,7 +603,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { << " ob" << vvertexp->outBeginp() << " on" << (vvertexp->outBeginp() ? vvertexp->outBeginp()->outNextp() - : 0) + : nullptr) << " " << vvertexp->name() << endl); for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { @@ -940,7 +940,7 @@ private: public: GateDedupeHash() {} - ~GateDedupeHash() { + virtual ~GateDedupeHash() override { if (v3Global.opt.debugCheck()) check(); } @@ -966,7 +966,7 @@ public: } // Callback from V3Hashed::findDuplicate - bool isSame(AstNode* node1p, AstNode* node2p) { + virtual bool isSame(AstNode* node1p, AstNode* node2p) override { // Assignment may have been hashReplaced, if so consider non-match (effectively removed) if (isReplaced(node1p) || isReplaced(node2p)) { // UINFO(9, "isSame hit on replaced "<<(void*)node1p<<" "<<(void*)node2p<(m_graphp); } - bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; } - // bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; } + static bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; } + // static bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; } void nextStep() { m_step++; } diff --git a/src/V3Hashed.h b/src/V3Hashed.h index fd538cadd..0fc0ace5a 100644 --- a/src/V3Hashed.h +++ b/src/V3Hashed.h @@ -75,8 +75,9 @@ public: void check(); // Check assertions on structure // Hash the node, and insert into map. Return iterator to inserted iterator hashAndInsert(AstNode* nodep); - void hash(AstNode* nodep); // Only hash the node - bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical + static void hash(AstNode* nodep); // Only hash the node + // After hashing, and tell if identical + static bool sameNodes(AstNode* node1p, AstNode* node2p); void erase(iterator it); // Remove node from structures // Return duplicate in hash, if any, with optional user check for sameness iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr); diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index f1858cdf0..cd76be85f 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -436,6 +436,6 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const { *of << v3Global.opt.allArgsStringForHierBlock(true) << "\n"; } -string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) const { +string V3HierBlockPlan::topCommandArgsFileName(bool forCMake) { return V3HierCommandArgsFileName(v3Global.opt.prefix(), forCMake); } diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index 8a04dd3fb..d5898dc34 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -122,7 +122,7 @@ public: // Write command line arguments to .f files for child Verilation run void writeCommandArgsFiles(bool forCMake) const; - string topCommandArgsFileName(bool forCMake) const; + static string topCommandArgsFileName(bool forCMake); static void createPlan(AstNetlist* nodep); }; diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index b42e14d4c..01ef648fd 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -417,7 +417,7 @@ private: // Track what scope it was originally under so V3LinkDot can resolve it string newdots = VString::dot(m_cellp->name(), ".", nodep->inlinedDots()); nodep->inlinedDots(newdots); - for (string tryname = nodep->dotted(); 1;) { + for (string tryname = nodep->dotted(); true;) { if (m_renamedInterfaces.count(tryname)) { nodep->dotted(m_cellp->name() + "__DOT__" + nodep->dotted()); break; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 88e6899c3..2483deb0e 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -178,7 +178,6 @@ public: } } -public: // CONSTRUCTORS explicit InstDeModVarVisitor() {} void main(AstNodeModule* nodep) { diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 8b9907339..a2ea3efd8 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -49,7 +49,6 @@ public: VDouble0 m_statAssnCon; // Statistic tracking std::vector m_unlinkps; -public: // CONSTRUCTORS LifeState() {} ~LifeState() { @@ -68,35 +67,29 @@ public: // Structure for each variable encountered class LifeVarEntry { - AstNodeAssign* m_assignp; // Last assignment to this varscope, nullptr if no longer relevant - AstConst* m_constp; // Known constant value + // Last assignment to this varscope, nullptr if no longer relevant + AstNodeAssign* m_assignp = nullptr; + AstConst* m_constp = nullptr; // Known constant value // First access was a set (and thus block above may have a set that can be deleted bool m_setBeforeUse; // Was ever assigned (and thus above block may not preserve constant propagation) - bool m_everSet; - - inline void init(bool setBeforeUse) { - m_assignp = nullptr; - m_constp = nullptr; - m_setBeforeUse = setBeforeUse; - m_everSet = false; - } + bool m_everSet = false; public: class SIMPLEASSIGN {}; class COMPLEXASSIGN {}; class CONSUMED {}; - LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) { - init(true); + LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) + : m_setBeforeUse{true} { simpleAssign(assp); } - explicit LifeVarEntry(COMPLEXASSIGN) { - init(false); + explicit LifeVarEntry(COMPLEXASSIGN) + : m_setBeforeUse{false} { complexAssign(); } - explicit LifeVarEntry(CONSUMED) { - init(false); + explicit LifeVarEntry(CONSUMED) + : m_setBeforeUse{false} { consumed(); } ~LifeVarEntry() {} diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index d67f20b96..d3878ffce 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -99,13 +99,11 @@ public: // and a sequence number within the mtask: struct LifeLocation { - const ExecMTask* mtaskp; - uint32_t sequence; + const ExecMTask* mtaskp = nullptr; + uint32_t sequence = 0; public: - LifeLocation() - : mtaskp{nullptr} - , sequence{0} {} + LifeLocation() {} LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_) : mtaskp{mtaskp_} , sequence{sequence_} {} @@ -120,9 +118,8 @@ public: struct LifePostLocation { LifeLocation loc; - AstAssignPost* nodep; - LifePostLocation() - : nodep{nullptr} {} + AstAssignPost* nodep = nullptr; + LifePostLocation() {} LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_) : loc{loc_} , nodep{nodep_} {} diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index bd7286e9e..190c4c4a8 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -172,27 +172,27 @@ private: addwherep->addNext(assignp); } } else { // Old V1995 sensitivity list; we'll probably mostly ignore - bool did = 1; + bool did = true; while (did) { - did = 0; + did = false; if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) { AstNode* fromp = selp->fromp()->unlinkFrBack(); selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); - did = 1; + did = true; } // NodeSel doesn't include AstSel.... if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) { AstNode* fromp = selp->fromp()->unlinkFrBack(); selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); - did = 1; + did = true; } if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) { AstNode* fromp = selp->lhsp()->unlinkFrBack(); selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp); - did = 1; + did = true; } } } @@ -359,7 +359,7 @@ private: if (!inpercent && c == '%') { inpercent = true; } else if (inpercent) { - inpercent = 0; + inpercent = false; switch (c) { case '0': // FALLTHRU case '1': // FALLTHRU @@ -392,7 +392,7 @@ private: return newFormat; } - void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) { + static void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) { if (!filep) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 328554e75..ae18997d9 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -498,7 +498,7 @@ string V3Options::filePathCheckOneDir(const string& modname, const string& dirna // 0: Keep the option including its argument // 1: Delete the option which has no argument // 2: Delete the option and its argument -int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) const { +int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) { if (opt == "Mdir" || opt == "clk" || opt == "f" || opt == "j" || opt == "l2-name" || opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib" || opt == "protect-key" || opt == "threads" || opt == "top-module" || opt == "v") { diff --git a/src/V3Options.h b/src/V3Options.h index 215fc85de..da8bc0eb2 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -410,13 +410,13 @@ private: void optimize(int level); void showVersion(bool verbose); void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; } - bool onoff(const char* sw, const char* arg, bool& flag); - bool onoffb(const char* sw, const char* arg, VOptionBool& flagr); - bool suffixed(const string& sw, const char* arg); - string parseFileArg(const string& optdir, const string& relfilename); + static bool onoff(const char* sw, const char* arg, bool& flag); + static bool onoffb(const char* sw, const char* arg, VOptionBool& flagr); + static bool suffixed(const string& sw, const char* arg); + static string parseFileArg(const string& optdir, const string& relfilename); bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc); string filePathCheckOneDir(const string& modname, const string& dirname); - int stripOptionsForChildRun(const string& opt, bool forTop) const; + static int stripOptionsForChildRun(const string& opt, bool forTop); // CONSTRUCTORS VL_UNCOPYABLE(V3Options); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 5bf687bf5..2d5a80038 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -217,7 +217,6 @@ public: return vertexp; } -public: // CONSTRUCTORS OrderUser() { for (int i = 0; i < WV_MAX; i++) m_vertexp[i] = nullptr; @@ -565,14 +564,15 @@ public: : m_pomGraphp{pomGraphp} , m_pomWaitingp{pomWaitingp} {} // METHODS - OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*, - const AstScope* scopep, const AstSenTree* domainp) { + virtual OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*, + const AstScope* scopep, + const AstSenTree* domainp) override { OrderMoveVertex* resultp = new OrderMoveVertex(m_pomGraphp, lvertexp); resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep)); resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp); return resultp; } - void freeVertexp(OrderMoveVertex* freeMep) { + virtual void freeVertexp(OrderMoveVertex* freeMep) override { freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep); freeMep->unlinkDelete(m_pomGraphp); } @@ -587,14 +587,18 @@ class OrderMTaskMoveVertexMaker : public ProcessMoveBuildGraph: public: explicit OrderMTaskMoveVertexMaker(V3Graph* pomGraphp) : m_pomGraphp{pomGraphp} {} - MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp, - const AstScope* scopep, const AstSenTree* domainp) { + virtual MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, + const OrderEitherVertex* varVertexp, + const AstScope* scopep, + const AstSenTree* domainp) override { // Exclude initial/settle logic from the mtasks graph. // We'll output time-zero logic separately. if (domainp->hasInitial() || domainp->hasSettle()) return nullptr; return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, scopep, domainp); } - void freeVertexp(MTaskMoveVertex* freeMep) { freeMep->unlinkDelete(m_pomGraphp); } + virtual void freeVertexp(MTaskMoveVertex* freeMep) override { + freeMep->unlinkDelete(m_pomGraphp); + } private: VL_UNCOPYABLE(OrderMTaskMoveVertexMaker); diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 9ec3731b2..45f0cfb96 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -37,7 +37,7 @@ public: // CONSTRUCTORS V3Lexer() : V3LexerBase{nullptr} {} - ~V3Lexer() {} + ~V3Lexer() override {} // METHODS void unputString(const char* textp, size_t length) { // Add characters to input stream in back-to-front order diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index e15e06c20..0d840b181 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -284,7 +284,7 @@ private: if (it != m_cp.end()) return it->second; return 0; } - uint32_t cost(const V3GraphVertex*) const { return 1; } + static uint32_t cost(const V3GraphVertex*) { return 1; } void partInitCriticalPaths(bool checkOnly) { // Set up the FORWARD cp's only. This test only looks in one // direction, it assumes REVERSE is symmetrical and would be @@ -726,10 +726,10 @@ class SiblingMC : public MergeCandidate { private: LogicMTask* m_ap; LogicMTask* m_bp; - // CONSTRUCTORS - SiblingMC() = delete; public: + // CONSTRUCTORS + SiblingMC() = delete; SiblingMC(LogicMTask* ap, LogicMTask* bp) { // Assign 'ap' and 'bp' in a canonical order, so we can more easily // compare pairs of SiblingMCs @@ -745,7 +745,7 @@ public: // METHODS LogicMTask* ap() const { return m_ap; } LogicMTask* bp() const { return m_bp; } - bool mergeWouldCreateCycle() const { + bool mergeWouldCreateCycle() const override { return (LogicMTask::pathExistsFrom(m_ap, m_bp, nullptr) || LogicMTask::pathExistsFrom(m_bp, m_ap, nullptr)); } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index b43db96b9..90ba90ac4 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -202,7 +202,7 @@ private: string commentCleanup(const string& text); bool commentTokenMatch(string& cmdr, const char* strg); - string trimWhitespace(const string& strg, bool trailing); + static string trimWhitespace(const string& strg, bool trailing); void unputString(const string& strg); void unputDefrefString(const string& strg); @@ -238,24 +238,24 @@ private: public: // METHODS, called from upper level shell - void openFile(FileLine* fl, VInFilter* filterp, const string& filename); - bool isEof() const { return m_lexp->curStreamp()->m_eof; } + void openFile(FileLine* fl, VInFilter* filterp, const string& filename) override; + bool isEof() const override { return m_lexp->curStreamp()->m_eof; } void forceEof() { m_lexp->curStreamp()->m_eof = true; } - string getline(); - void insertUnreadback(const string& text) { m_lineCmt += text; } + string getline() override; + void insertUnreadback(const string& text) override { m_lineCmt += text; } void insertUnreadbackAtBol(const string& text); void addLineComment(int enterExit); - void dumpDefines(std::ostream& os); - void candidateDefines(VSpellCheck* spellerp); + void dumpDefines(std::ostream& os) override; + void candidateDefines(VSpellCheck* spellerp) override; // METHODS, callbacks - virtual void comment(const string& text); // Comment detected (if keepComments==2) - virtual void include(const string& filename); // Request a include file be processed - virtual void undef(const string& name); + virtual void comment(const string& text) override; // Comment detected (if keepComments==2) + virtual void include(const string& filename) override; // Request a include file be processed + virtual void undef(const string& name) override; virtual void undefineall(); virtual void define(FileLine* fl, const string& name, const string& value, - const string& params, bool cmdline); - virtual string removeDefines(const string& text); // Remove defines in a text string + const string& params, bool cmdline) override; + virtual string removeDefines(const string& text) override; // Remove defines in a text string // CONSTRUCTORS V3PreProcImp() { @@ -274,7 +274,7 @@ public: m_lexp->m_pedantic = pedantic(); m_lexp->debug(debug() >= 5 ? debug() : 0); // See also V3PreProc::debug() method } - ~V3PreProcImp() { + ~V3PreProcImp() override { if (m_lexp) VL_DO_CLEAR(delete m_lexp, m_lexp = nullptr); } }; @@ -764,7 +764,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { //********************************************************************** // Parser routines -void V3PreProcImp::openFile(FileLine* fl, VInFilter* filterp, const string& filename) { +void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filename) { // Open a new file, possibly overriding the current one which is active. if (m_incError) return; V3File::addSrcDepend(filename); diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index bc635a42a..51717f15d 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -767,7 +767,7 @@ public: : m_refs{} { iterate(nodep); } - ~SplitUnpackedVarVisitor() { + ~SplitUnpackedVarVisitor() override { UASSERT(m_refs.empty(), "Don't forget to call split()"); V3Stats::addStat("SplitVar, Split unpacked arrays", m_numSplit); } @@ -916,8 +916,8 @@ public: std::vector> points; // points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry for (const_iterator it = m_lhs.begin(), itend = m_lhs.end(); it != itend; ++it) { - points.push_back(std::make_pair(it->lsb(), false)); // Start of a region - points.push_back(std::make_pair(it->msb() + 1, true)); // End of a region + points.emplace_back(std::make_pair(it->lsb(), false)); // Start of a region + points.emplace_back(std::make_pair(it->msb() + 1, true)); // End of a region } if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here int lsb = m_basicp->msb() + 1; @@ -927,12 +927,12 @@ public: msb = std::max(msb, m_rhs[i].msb()); } UASSERT_OBJ(lsb <= msb, m_basicp, "lsb:" << lsb << " msb:" << msb << " are wrong"); - points.push_back(std::make_pair(lsb, false)); - points.push_back(std::make_pair(msb + 1, true)); + points.emplace_back(std::make_pair(lsb, false)); + points.emplace_back(std::make_pair(msb + 1, true)); } if (!skipUnused) { // All bits are necessary - points.push_back(std::make_pair(m_basicp->lsb(), false)); - points.push_back(std::make_pair(m_basicp->msb() + 1, true)); + points.emplace_back(std::make_pair(m_basicp->lsb(), false)); + points.emplace_back(std::make_pair(m_basicp->msb() + 1, true)); } std::sort(points.begin(), points.end(), SortByFirst()); @@ -947,7 +947,7 @@ public: } UASSERT(refcount >= 0, "refcounut must not be negative"); if (bitwidth == 0 || refcount == 0) continue; // Vacant region - plan.push_back(SplitNewVar(points[i].first, bitwidth)); + plan.emplace_back(SplitNewVar(points[i].first, bitwidth)); } return plan; @@ -1216,7 +1216,7 @@ public: m_modp = nullptr; } } - ~SplitPackedVarVisitor() { + ~SplitPackedVarVisitor() override { UASSERT(m_refs.empty(), "Forgot to call split()"); V3Stats::addStat("SplitVar, Split packed variables", m_numSplit); } diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 6625acf91..9be68d1d7 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -645,11 +645,11 @@ void V3TSP::selfTestString() { minGraph.findEulerTour(&result); std::vector expect; - expect.push_back("0"); - expect.push_back("2"); - expect.push_back("1"); - expect.push_back("2"); - expect.push_back("3"); + expect.emplace_back("0"); + expect.emplace_back("2"); + expect.emplace_back("1"); + expect.emplace_back("2"); + expect.emplace_back("3"); if (VL_UNCOVERABLE(expect != result)) { for (const string& i : result) cout << i << " "; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9719b0988..3b98eb02e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2673,7 +2673,7 @@ private: if (!nodep->firstAbovep()) { newp->makeStatement(); } } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { - AstWith* withp = NULL; + AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); } @@ -2804,7 +2804,7 @@ private: if (!nodep->firstAbovep()) { newp->makeStatement(); } } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { - AstWith* withp = NULL; + AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); } @@ -2958,7 +2958,7 @@ private: nodep->dtypeFrom(adtypep->subDTypep()); // Best guess } } - void methodCallEvent(AstMethodCall* nodep, AstBasicDType* adtypep) { + void methodCallEvent(AstMethodCall* nodep, AstBasicDType*) { // Method call on event if (nodep->name() == "triggered") { // We represent events as numbers, so can just return number @@ -2970,7 +2970,7 @@ private: nodep->v3error("Unknown built-in event method " << nodep->prettyNameQ()); } } - void methodCallString(AstMethodCall* nodep, AstBasicDType* adtypep) { + void methodCallString(AstMethodCall* nodep, AstBasicDType*) { // Method call on string if (nodep->name() == "len") { // Constant value @@ -3399,7 +3399,7 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } - void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember* defaultp) { + void patternDynArray(AstPattern* nodep, AstDynArrayDType* arrayp, AstPatMember*) { AstNode* newp = new AstConsDynArray(nodep->fileline()); newp->dtypeFrom(arrayp); for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; @@ -3414,7 +3414,7 @@ private: // if (debug() >= 9) newp->dumpTree("-apat-out: "); VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present } - void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) { + void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember*) { AstNode* newp = new AstConsQueue(nodep->fileline()); newp->dtypeFrom(arrayp); for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp; @@ -5007,7 +5007,7 @@ private: return false; // No change } - bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) { + static bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) { return node1p->skipRefp()->similarDType(node2p->skipRefp()); } void iterateCheckFileDesc(AstNode* nodep, AstNode* underp, Stage stage) { From 79d33bf1ee42e65fb5f7ac2761f8e24f2a189399 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 10 Nov 2020 22:10:38 -0500 Subject: [PATCH 75/88] Use C++11 for loops, from clang-migrate. No functional change intended --- src/V3AstNodes.cpp | 12 +++++------- src/V3Case.cpp | 2 +- src/V3Cdc.cpp | 6 +++--- src/V3Combine.cpp | 4 ++-- src/V3Config.cpp | 16 +++++----------- src/V3Coverage.cpp | 8 ++++---- src/V3Dead.cpp | 7 +++---- src/V3EmitC.cpp | 15 +++++++-------- src/V3EmitCMake.cpp | 8 ++++---- src/V3EmitCSyms.cpp | 8 ++++---- src/V3EmitMk.cpp | 5 +---- src/V3EmitV.cpp | 6 +++--- src/V3File.cpp | 13 ++++++------- src/V3Gate.cpp | 4 ++-- src/V3GraphAcyc.cpp | 7 ++----- src/V3GraphDfa.cpp | 5 ++--- src/V3GraphPathChecker.cpp | 2 +- src/V3Hashed.cpp | 16 ++++++++-------- src/V3HierBlock.cpp | 22 ++++++++-------------- src/V3Inst.cpp | 5 ++--- src/V3LifePost.cpp | 4 ++-- src/V3LinkDot.cpp | 6 +++--- src/V3LinkLevel.cpp | 6 +++--- src/V3Options.cpp | 3 +-- src/V3Order.cpp | 6 ++---- src/V3Param.cpp | 14 ++++++-------- src/V3ParseImp.cpp | 15 +++++---------- src/V3Partition.cpp | 10 ++++------ src/V3PreProc.cpp | 4 ++-- src/V3Scope.cpp | 7 +++---- src/V3Split.cpp | 18 +++++++++--------- src/V3SplitVar.cpp | 4 +--- src/V3Stats.cpp | 6 +++--- src/V3StatsReport.cpp | 20 ++++++++++---------- src/V3TSP.cpp | 4 +--- src/V3Table.cpp | 5 +---- src/V3Task.cpp | 12 ++++++------ src/V3Tristate.cpp | 6 ++---- src/V3Width.cpp | 30 +++++++++++++++--------------- 39 files changed, 152 insertions(+), 199 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d796631e1..3074722cf 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -846,9 +846,7 @@ bool AstSenTree::hasCombo() const { void AstTypeTable::clearCache() { // When we mass-change widthMin in V3WidthCommit, we need to correct the table. // Just clear out the maps; the search functions will be used to rebuild the map - for (int i = 0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { - m_basicps[i] = nullptr; - } + for (auto& itr : m_basicps) itr = nullptr; m_detailedMap.clear(); // Clear generic()'s so dead detection will work for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) { @@ -1176,12 +1174,12 @@ void AstInitArray::dump(std::ostream& str) const { this->AstNode::dump(str); int n = 0; const AstInitArray::KeyItemMap& mapr = map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { + for (const auto& itr : mapr) { if (n++ > 5) { str << " ..."; break; } - str << " [" << it->first << "]=" << (void*)it->second; + str << " [" << itr.first << "]=" << (void*)itr.second; } } void AstJumpGo::dump(std::ostream& str) const { @@ -1406,8 +1404,8 @@ void AstTypeTable::dump(std::ostream& str) const { } { const DetailedMap& mapr = m_detailedMap; - for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { - AstBasicDType* dtypep = it->second; + for (const auto& itr : mapr) { + AstBasicDType* dtypep = itr.second; str << endl; // Newline from caller, so newline first str << "\t\tdetailed -> "; dtypep->dump(str); diff --git a/src/V3Case.cpp b/src/V3Case.cpp index ac15870f7..a9a0a3511 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -486,7 +486,7 @@ private: public: // CONSTRUCTORS explicit CaseVisitor(AstNetlist* nodep) { - for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = nullptr; + for (auto& itr : m_valueItem) itr = nullptr; iterate(nodep); } virtual ~CaseVisitor() override { diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 202ef4001..60e85be33 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -587,15 +587,15 @@ private: // Convert list of senses into one sense node AstSenTree* senoutp = nullptr; bool senedited = false; - for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) { + for (const auto& itr : senouts) { if (!senoutp) { - senoutp = *it; + senoutp = itr; } else { if (!senedited) { senedited = true; senoutp = senoutp->cloneTree(true); } - senoutp->addSensesp((*it)->sensesp()->cloneTree(true)); + senoutp->addSensesp(itr->sensesp()->cloneTree(true)); } } // If multiple domains need to do complicated optimizations diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index bc82a812d..ad2bcc690 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -203,8 +203,8 @@ private: } #endif void walkEmptyFuncs() { - for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { - AstNode* node1p = it->second; + for (const auto& itr : m_hashed) { + AstNode* node1p = itr.second; AstCFunc* oldfuncp = VN_CAST(node1p, CFunc); if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) { UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " diff --git a/src/V3Config.cpp b/src/V3Config.cpp index d36880697..7a29b21fd 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -282,15 +282,9 @@ public: } void update(const V3ConfigFile& file) { // Copy in all Attributes - for (LineAttrMap::const_iterator it = file.m_lineAttrs.begin(); - it != file.m_lineAttrs.end(); ++it) { - m_lineAttrs[it->first] |= it->second; - } + for (const auto& itr : file.m_lineAttrs) { m_lineAttrs[itr.first] |= itr.second; } // Copy in all ignores - for (IgnLines::const_iterator it = file.m_ignLines.begin(); it != file.m_ignLines.end(); - ++it) { - m_ignLines.insert(*it); - } + for (const auto& ignLine : file.m_ignLines) m_ignLines.insert(ignLine); // Update the iterator after the list has changed m_lastIgnore.it = m_ignLines.begin(); m_waivers.reserve(m_waivers.size() + file.m_waivers.size()); @@ -338,9 +332,9 @@ public: } } bool waive(V3ErrorCode code, const string& match) { - for (Waivers::const_iterator it = m_waivers.begin(); it != m_waivers.end(); ++it) { - if (((it->first == code) || (it->first == V3ErrorCode::I_LINT)) - && VString::wildmatch(match, it->second)) { + for (const auto& itr : m_waivers) { + if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT)) + && VString::wildmatch(match, itr.second)) { return true; } } diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 344d24d28..a216b385c 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -188,15 +188,15 @@ private: const LinenoSet& lines = m_handleLines[state.m_handle]; int first = 0; int last = 0; - for (LinenoSet::iterator it = lines.begin(); it != lines.end(); ++it) { + for (int linen : lines) { if (!first) { - first = last = *it; - } else if (*it == last + 1) { + first = last = linen; + } else if (linen == last + 1) { ++last; } else { if (!out.empty()) out += ","; out += linesFirstLast(first, last); - first = last = *it; + first = last = linen; } } if (first) { diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 9f709f5ab..7b75e4bdb 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -367,14 +367,13 @@ private: void deadCheckClasses() { for (bool retry = true; retry;) { retry = false; - for (std::vector::iterator it = m_classesp.begin(); it != m_classesp.end(); - ++it) { - if (AstClass* nodep = *it) { // nullptr if deleted earlier + for (auto& itr : m_classesp) { + if (AstClass* nodep = itr) { // nullptr if deleted earlier if (nodep->user1() == 0) { if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1); if (nodep->packagep()) nodep->packagep()->user1Inc(-1); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); - *it = nullptr; + itr = nullptr; retry = true; } } diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index ee4712910..79a11f158 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1294,8 +1294,8 @@ public: // Returns the number of elements in set_a that don't appear in set_b static int diffs(const MTaskIdSet& set_a, const MTaskIdSet& set_b) { int diffs = 0; - for (MTaskIdSet::iterator it = set_a.begin(); it != set_a.end(); ++it) { - if (set_b.find(*it) == set_b.end()) ++diffs; + for (int i : set_a) { + if (set_b.find(i) == set_b.end()) ++diffs; } return diffs; } @@ -1731,10 +1731,9 @@ class EmitCImp : EmitCStmts { puts("}\n"); } const AstInitArray::KeyItemMap& mapr = initarp->map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); - ++it) { - AstNode* valuep = it->second->valuep(); - emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(it->first) + "]", + for (const auto& itr : mapr) { + AstNode* valuep = itr.second->valuep(); + emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]", VN_CAST(valuep, Const)); } } else { @@ -2902,8 +2901,8 @@ void EmitCStmts::emitVarSort(const VarSortMap& vmap, VarVec* sortedp) { if (!v3Global.opt.mtasks()) { // Plain old serial mode. Sort by size, from small to large, // to optimize for both packing and small offsets in code. - for (VarSortMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) { - for (VarVec::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { + for (const auto& itr : vmap) { + for (VarVec::const_iterator jt = itr.second.begin(); jt != itr.second.end(); ++jt) { sortedp->push_back(*jt); } } diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index ffc4eb31a..0b7e0f52e 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -71,8 +71,8 @@ class CMakeEmitter { // Swap all backslashes for forward slashes, because of Windows static string deslash(const string& s) { std::string res = s; - for (string::iterator it = res.begin(); it != res.end(); ++it) { - if (*it == '\\') *it = '/'; + for (char& c : res) { + if (c == '\\') c = '/'; } return res; } @@ -243,9 +243,9 @@ class CMakeEmitter { *of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE " << v3Global.rootp()->topModulep()->name() << " DIRECTORY " << deslash(v3Global.opt.makeDir()) << " SOURCES "; - for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) { + for (const auto& itr : *planp) { *of << " " - << deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true)); + << deslash(v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true)); } *of << " " << deslash(cmake_list(v3Global.opt.vFiles())); *of << " VERILATOR_ARGS "; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 8d8bc81af..f0e63fa1d 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -398,8 +398,8 @@ void EmitCSyms::emitSymHdr() { if (v3Global.dpi()) { puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n"); std::map types; // Remove duplicates and sort - for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) { - AstCFunc* funcp = it->second.m_cfuncp; + for (const auto& itr : m_scopeFuncs) { + AstCFunc* funcp = itr.second.m_cfuncp; if (funcp->dpiExport()) { string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t"); types["typedef void (*" + cbtype + ") (" + cFuncArgs(funcp) + ");\n"] = 1; @@ -455,8 +455,8 @@ void EmitCSyms::emitSymHdr() { if (!m_scopeNames.empty()) { // Scope names puts("\n// SCOPE NAMES\n"); - for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) { - puts("VerilatedScope " + protect("__Vscope_" + it->second.m_symName) + ";\n"); + for (const auto& itr : m_scopeNames) { + puts("VerilatedScope " + protect("__Vscope_" + itr.second.m_symName) + ";\n"); } } diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 813ac0367..0a55a2ef9 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -362,10 +362,7 @@ class EmitMkHierVerilation { of.puts(v3Global.opt.prefix() + ".mk: $(VM_HIER_INPUT_FILES) $(VM_HIER_VERILOG_LIBS) "); of.puts(V3Os::filenameNonDir(argsFile) + " "); - for (V3HierBlockPlan::const_iterator it = m_planp->begin(); it != m_planp->end(); - ++it) { - of.puts(it->second->hierWrapper(true) + " "); - } + for (const auto& itr : *m_planp) of.puts(itr.second->hierWrapper(true) + " "); of.puts("\n"); emitLaunchVerilator(of, argsFile); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 27e8b3d21..aa53317dd 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -493,11 +493,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putfs(nodep, "'{"); int comma = 0; const AstInitArray::KeyItemMap& mapr = nodep->map(); - for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) { + for (const auto& itr : mapr) { if (comma++) putbs(", "); - puts(cvtToStr(it->first)); + puts(cvtToStr(itr.first)); puts(":"); - AstNode* valuep = it->second->valuep(); + AstNode* valuep = itr.second->valuep(); iterate(valuep); } puts("}"); diff --git a/src/V3File.cpp b/src/V3File.cpp index 5acdafa57..ed7749481 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -172,9 +172,8 @@ inline void V3FileDependImp::writeDepend(const string& filename) { inline std::vector V3FileDependImp::getAllDeps() const { std::vector r; - for (std::set::const_iterator iter = m_filenameList.begin(); - iter != m_filenameList.end(); ++iter) { - if (!iter->target() && iter->exists()) { r.push_back(iter->filename()); } + for (const auto& itr : m_filenameList) { + if (!itr.target() && itr.exists()) r.push_back(itr.filename()); } return r; } @@ -942,8 +941,8 @@ void V3OutCFile::putsGuard() { UASSERT(!m_guard, "Already called putsGuard in emit file"); m_guard = true; string var = VString::upcase(string("_") + V3Os::filenameNonDir(filename()) + "_"); - for (string::iterator pos = var.begin(); pos != var.end(); ++pos) { - if (!isalnum(*pos)) *pos = '_'; + for (char& c : var) { + if (!isalnum(c)) c = '_'; } puts("\n#ifndef " + var + "\n"); puts("#define " + var + " // guard\n"); @@ -1046,8 +1045,8 @@ public: "IPTION: Verilator output: XML representation of netlist -->\n"); of.puts("\n"); { - for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) { - of.puts("second + "\" to=\"" + it->first + "\"/>\n"); + for (const auto& itr : m_nameMap) { + of.puts("\n"); } } of.puts("\n"); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 0276ee97c..3d53fb356 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -1002,8 +1002,8 @@ public: void check() { m_hashed.check(); - for (V3Hashed::HashMmap::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { - AstNode* nodep = it->second; + for (const auto& itr : m_hashed) { + AstNode* nodep = itr.second; AstNode* activep = nodep->user3p(); AstNode* condVarp = nodep->user5p(); if (!isReplaced(nodep)) { diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 393b74754..57fc442e6 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -143,9 +143,7 @@ private: } OrigEdgeList* oEListp = static_cast(toEdgep->userp()); if (OrigEdgeList* addListp = static_cast(addEdgep->userp())) { - for (OrigEdgeList::iterator it = addListp->begin(); it != addListp->end(); ++it) { - oEListp->push_back(*it); - } + for (const auto& itr : *addListp) oEListp->push_back(itr); addListp->clear(); // Done with it } else { oEListp->push_back(addEdgep); @@ -160,8 +158,7 @@ private: v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl); } // The breakGraph edge may represent multiple real edges; cut them all - for (OrigEdgeList::iterator it = oEListp->begin(); it != oEListp->end(); ++it) { - V3GraphEdge* origEdgep = *it; + for (const auto& origEdgep : *oEListp) { origEdgep->cut(); UINFO(8, " " << why << " " << origEdgep->fromp() << " ->" << origEdgep->top() << endl); diff --git a/src/V3GraphDfa.cpp b/src/V3GraphDfa.cpp index 97f66ef3a..2c8f0bb48 100644 --- a/src/V3GraphDfa.cpp +++ b/src/V3GraphDfa.cpp @@ -317,9 +317,8 @@ private: } // Foreach input state (NFA inputs of this DFA state) - for (std::set::const_iterator inIt = inputs.begin(); inIt != inputs.end(); - ++inIt) { - DfaInput input = *inIt; + for (int inIt : inputs) { + DfaInput input = inIt; UINFO(9, " ===" << ++i << "=======================\n"); UINFO(9, " On input " << cvtToHex(input.toNodep()) << endl); diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index d0242f9dc..2497f35ca 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -42,7 +42,7 @@ struct GraphPCNode { // CONSTRUCTORS GraphPCNode() { - for (int w = 0; w < GraphWay::NUM_WAYS; w++) m_cp[w] = 0; + for (unsigned int& w : m_cp) w = 0; } ~GraphPCNode() {} }; diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp index 22758e288..14579bc87 100644 --- a/src/V3Hashed.cpp +++ b/src/V3Hashed.cpp @@ -139,8 +139,8 @@ void V3Hashed::erase(iterator it) { } void V3Hashed::check() { - for (HashMmap::iterator it = begin(); it != end(); ++it) { - AstNode* nodep = it->second; + for (const auto& itr : *this) { + AstNode* nodep = itr.second; UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node"); } } @@ -179,15 +179,15 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { } *logp << "\n*** Dump:\n" << endl; - for (HashMmap::iterator it = begin(); it != end(); ++it) { - if (lasthash != it->first) { - lasthash = it->first; - *logp << " " << it->first << endl; + for (const auto& itr : *this) { + if (lasthash != itr.first) { + lasthash = itr.first; + *logp << " " << itr.first << endl; } - *logp << "\t" << it->second << endl; + *logp << "\t" << itr.second << endl; // Dumping the entire tree may make nearly N^2 sized dumps, // because the nodes under this one may also be in the hash table! - if (tree) it->second->dumpTree(*logp, " "); + if (tree) itr.second->dumpTree(*logp, " "); } } diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index cd76be85f..f605723fc 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -107,9 +107,8 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, bool forGOption) { StrGParams strParams; - for (V3HierBlock::GParams::const_iterator gparamIt = gparams.begin(); - gparamIt != gparams.end(); ++gparamIt) { - if (const AstConst* constp = VN_CAST((*gparamIt)->valuep(), Const)) { + for (const auto& gparam : gparams) { + if (const AstConst* constp = VN_CAST(gparam->valuep(), Const)) { string s; // Only constant parameter needs to be set to -G because already checked in // V3Param.cpp. See also ParamVisitor::checkSupportedParam() in the file. @@ -131,7 +130,7 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo s = constp->num().ascii(true, true); s = VString::quoteAny(s, '\'', '\\'); } - strParams.push_back(std::make_pair((*gparamIt)->name(), s)); + strParams.push_back(std::make_pair(gparam->name(), s)); } } return strParams; @@ -139,9 +138,8 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const GParams& gparams, boo V3HierBlock::~V3HierBlock() { UASSERT(m_children.empty(), "at least one module must be a leaf"); - for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end(); - ++child) { - const bool deleted = (*child)->m_children.erase(this); + for (const auto& hierblockp : m_children) { + const bool deleted = hierblockp->m_children.erase(this); UASSERT_OBJ(deleted, m_modp, " is not registered"); } } @@ -214,9 +212,8 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const { *of << "--cc\n"; if (!forCMake) { - for (V3HierBlock::HierBlockSet::const_iterator child = m_children.begin(); - child != m_children.end(); ++child) { - *of << v3Global.opt.makeDir() << "/" << (*child)->hierWrapper(true) << "\n"; + for (const auto& hierblockp : m_children) { + *of << v3Global.opt.makeDir() << "/" << hierblockp->hierWrapper(true) << "\n"; } *of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n"; } @@ -224,10 +221,7 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const { const V3StringList& commandOpts = commandArgs(false); for (const string& opt : commandOpts) *of << opt << "\n"; *of << hierBlockArgs().front() << "\n"; - for (HierBlockSet::const_iterator child = m_children.begin(); child != m_children.end(); - ++child) { - *of << (*child)->hierBlockArgs().front() << "\n"; - } + for (const auto& hierblockp : m_children) *of << hierblockp->hierBlockArgs().front() << "\n"; // Hierarchical blocks should not use multi-threading, // but needs to be thread safe when top is multi-threaded. if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 2483deb0e..1c016ac8f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -172,9 +172,8 @@ public: } } void dump() { - for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end(); - ++it) { - cout << "-namemap: " << it->first << " -> " << it->second << endl; + for (const auto& itr : m_modVarNameMap) { + cout << "-namemap: " << itr.first << " -> " << itr.second << endl; } } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index d3878ffce..4e254a991 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -186,8 +186,8 @@ private: return true; } void squashAssignposts() { - for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) { - LifePostLocation* app = &it->second; + for (auto& itr : m_assignposts) { + LifePostLocation* app = &itr.second; AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var AstVarScope* dlyVarp = rhsp->varScopep(); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 8274b84fd..b8dce26fe 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1726,9 +1726,9 @@ public: }; void LinkDotState::computeIfaceModSyms() { - for (IfaceModSyms::iterator it = m_ifaceModSyms.begin(); it != m_ifaceModSyms.end(); ++it) { - AstIface* nodep = it->first; - VSymEnt* symp = it->second; + for (const auto& itr : m_ifaceModSyms) { + AstIface* nodep = itr.first; + VSymEnt* symp = itr.second; LinkDotIfaceVisitor(nodep, symp, this); } m_ifaceModSyms.clear(); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index e59d87ffe..da3904efb 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -89,9 +89,9 @@ void V3LinkLevel::timescaling(const ModVec& mods) { AstNodeModule* modTimedp = nullptr; VTimescale unit(VTimescale::NONE); // Use highest level module as default unit - already sorted in proper order - for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) { - if (!modTimedp && !(*it)->timeunit().isNone()) { - modTimedp = *it; + for (const auto& modp : mods) { + if (!modTimedp && !modp->timeunit().isNone()) { + modTimedp = modp; unit = modTimedp->timeunit(); break; } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ae18997d9..799c7ed87 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -392,8 +392,7 @@ string V3Options::allArgsString() const { // Delete some options for Verilation of the hierarchical blocks. string V3Options::allArgsStringForHierBlock(bool forTop) const { std::set vFiles; - for (V3StringList::const_iterator it = m_vFiles.begin(); it != m_vFiles.end(); ++it) - vFiles.insert(*it); + for (const auto& vFile : m_vFiles) vFiles.insert(vFile); string out; for (std::list::const_iterator it = m_impp->m_allArgs.begin(); it != m_impp->m_allArgs.end(); ++it) { diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 2d5a80038..7c555cd7f 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -153,9 +153,7 @@ public: OrderMoveVertex* vertexp); // Mark one vertex as finished, remove from ready list if done // STATIC MEMBERS (for lookup) static void clear() { - for (DomScopeMap::iterator it = s_dsMap.begin(); it != s_dsMap.end(); ++it) { - delete it->second; - } + for (const auto& itr : s_dsMap) delete itr.second; s_dsMap.clear(); } V3List& readyVertices() { return m_readyVertices; } @@ -219,7 +217,7 @@ public: // CONSTRUCTORS OrderUser() { - for (int i = 0; i < WV_MAX; i++) m_vertexp[i] = nullptr; + for (auto& vertexp : m_vertexp) vertexp = nullptr; } ~OrderUser() {} }; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index e8ae9d7a0..8b03ed87a 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -119,10 +119,11 @@ class ParameterizedHierBlocks { public: ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) { - for (V3HierBlockOptSet::const_iterator it = hierOpts.begin(); it != hierOpts.end(); ++it) { - m_hierBlockOptsByOrigName.insert(std::make_pair(it->second.origName(), &it->second)); - const V3HierarchicalBlockOption::ParamStrMap& params = it->second.params(); - ParamConstMap& consts = m_params[&it->second]; + for (const auto& hierOpt : hierOpts) { + m_hierBlockOptsByOrigName.insert( + std::make_pair(hierOpt.second.origName(), &hierOpt.second)); + const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params(); + ParamConstMap& consts = m_params[&hierOpt.second]; for (V3HierarchicalBlockOption::ParamStrMap::const_iterator pIt = params.begin(); pIt != params.end(); ++pIt) { AstConst* constp = AstConst::parseParamLiteral( @@ -141,10 +142,7 @@ public: } ~ParameterizedHierBlocks() { for (ParamsMap::const_iterator it = m_params.begin(); it != m_params.end(); ++it) { - for (ParamConstMap::const_iterator pIt = it->second.begin(); pIt != it->second.end(); - ++pIt) { - delete pIt->second; - } + for (const auto& pItr : it->second) { delete pItr.second; } } } AstNodeModule* findByParams(const string& origName, AstPin* firstPinp, diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index c4b1766a4..e7800e0fd 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -49,13 +49,9 @@ int V3ParseSym::s_anonNum = 0; // Parser constructor V3ParseImp::~V3ParseImp() { - for (std::deque::iterator it = m_stringps.begin(); it != m_stringps.end(); ++it) { - VL_DO_DANGLING(delete *it, *it); - } + for (auto& itr : m_stringps) VL_DO_DANGLING(delete itr, itr); m_stringps.clear(); - for (std::deque::iterator it = m_numberps.begin(); it != m_numberps.end(); ++it) { - VL_DO_DANGLING(delete *it, *it); - } + for (auto& itr : m_numberps) VL_DO_DANGLING(delete itr, itr); m_numberps.clear(); lexDestroy(); parserClear(); @@ -252,11 +248,10 @@ void V3ParseImp::preprocDumps(std::ostream& os) { V3PreShell::dumpDefines(os); } else { bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine(); - for (std::deque::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end(); - ++it) { + for (auto& buf : m_ppBuffers) { if (noblanks) { bool blank = true; - for (string::iterator its = it->begin(); its != it->end(); ++its) { + for (string::iterator its = buf.begin(); its != buf.end(); ++its) { if (!isspace(*its) && *its != '\n') { blank = false; break; @@ -264,7 +259,7 @@ void V3ParseImp::preprocDumps(std::ostream& os) { } if (blank) continue; } - os << *it; + os << buf; } } } diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 0d840b181..abfb6ce0d 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -308,7 +308,7 @@ private: // Generate a pseudo-random graph vluint64_t rngState[2] = {0x12345678ULL, 0x9abcdef0ULL}; // Create 50 vertices - for (unsigned i = 0; i < 50; ++i) m_vx[i] = new V3GraphVertex(&m_graph); + for (auto& i : m_vx) i = new V3GraphVertex(&m_graph); // Create 250 edges at random. Edges must go from // lower-to-higher index vertices, so we get a DAG. for (unsigned i = 0; i < 250; ++i) { @@ -328,10 +328,8 @@ private: // Seed the propagator with every input node; // This should result in the complete graph getting all CP's assigned. - for (unsigned i = 0; i < 50; ++i) { - if (!m_vx[i]->inBeginp()) { - prop.cpHasIncreased(m_vx[i], 1 /* inclusive CP starts at 1 */); - } + for (const auto& i : m_vx) { + if (!i->inBeginp()) prop.cpHasIncreased(i, 1 /* inclusive CP starts at 1 */); } // Run the propagator. @@ -451,7 +449,7 @@ public: // CONSTRUCTORS LogicMTask(V3Graph* graphp, MTaskMoveVertex* mtmvVxp) : AbstractLogicMTask{graphp} { - for (int i = 0; i < GraphWay::NUM_WAYS; ++i) m_critPathCost[i] = 0; + for (unsigned int& i : m_critPathCost) i = 0; if (mtmvVxp) { // Else null for test m_vertices.push_back(mtmvVxp); if (OrderLogicVertex* olvp = mtmvVxp->logicp()) { diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 90ba90ac4..0b1b0d782 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -1549,8 +1549,8 @@ int V3PreProcImp::getFinalToken(string& buf) { } } // Track newlines in prep for next token - for (string::iterator cp = buf.begin(); cp != buf.end(); ++cp) { - if (*cp == '\n') { + for (char& c : buf) { + if (c == '\n') { m_finAtBol = true; m_finFilelinep->linenoInc(); } else { diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 9e3d19886..1922c7c80 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -65,10 +65,9 @@ private: VL_DEBUG_FUNC; // Declare debug() void cleanupVarRefs() { - for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); it != m_varRefScopes.end(); - ++it) { - AstVarRef* nodep = it->first; - AstScope* scopep = it->second; + for (const auto& itr : m_varRefScopes) { + AstVarRef* nodep = itr.first; + AstScope* scopep = itr.second; if (nodep->packagep() && !nodep->varp()->isClassMember()) { const auto it2 = m_packageScopes.find(nodep->packagep()); UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope"); diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 31ddbd268..bb528c0ae 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -291,10 +291,10 @@ private: if (!m_pliVertexp) { m_pliVertexp = new SplitPliVertex(&m_graph, nodep); // m_graph.clear() will delete it } - for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) { + for (const auto& vtxp : m_stmtStackps) { // Both ways... - new SplitScorebdEdge(&m_graph, *it, m_pliVertexp); - new SplitScorebdEdge(&m_graph, m_pliVertexp, *it); + new SplitScorebdEdge(&m_graph, vtxp, m_pliVertexp); + new SplitScorebdEdge(&m_graph, m_pliVertexp, vtxp); } } void scoreboardPushStmt(AstNode* nodep) { @@ -709,7 +709,7 @@ public: void go() { // Create a new always for each color const ColorSet& colors = m_ifColorp->colors(); - for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { + for (unsigned int color : colors) { // We don't need to clone m_origAlwaysp->sensesp() here; // V3Activate already moved it to a parent node. AstAlways* alwaysp @@ -718,7 +718,7 @@ public: // We'll strip these out after the blocks are fully cloned. AstSplitPlaceholder* placeholderp = makePlaceholderp(); alwaysp->addStmtp(placeholderp); - m_addAfter[*color] = placeholderp; + m_addAfter[color] = placeholderp; m_newBlocksp->push_back(alwaysp); } // Scan the body of the always. We'll handle if/else @@ -761,7 +761,7 @@ protected: typedef std::unordered_map CloneMap; CloneMap clones; - for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) { + for (unsigned int color : colors) { // Clone this if into its set of split blocks AstSplitPlaceholder* if_placeholderp = makePlaceholderp(); AstSplitPlaceholder* else_placeholderp = makePlaceholderp(); @@ -775,9 +775,9 @@ protected: clonep->unique0Pragma(origp->unique0Pragma()); clonep->priorityPragma(origp->priorityPragma()); } - clones[*color] = clonep; - m_addAfter[*color]->addNextHere(clonep); - m_addAfter[*color] = if_placeholderp; + clones[color] = clonep; + m_addAfter[color]->addNextHere(clonep); + m_addAfter[color] = if_placeholderp; } iterateAndNextNull(nodep->ifsp()); diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 51717f15d..9e29743e0 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -361,9 +361,7 @@ public: v.iterate(nodep); } void visit(AstNVisitor* visitor) { - for (VarSet::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; ++it) { - visitor->iterate(*it); - } + for (const auto& varp : m_vars) visitor->iterate(varp); for (SelSet::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; ++it) { // If m_refs includes VarRef from ArraySel, remove it // because the VarRef would not be visited in SplitPackedVarVisitor::visit(AstSel*). diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index 1e9669da6..9562aa8a0 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -234,10 +234,10 @@ public: if (count != 0.0) { if (v3Global.opt.statsVars()) { NameMap& nameMapr = m_statVarWidthNames.at(i); - for (NameMap::iterator it = nameMapr.begin(); it != nameMapr.end(); ++it) { + for (const auto& itr : nameMapr) { std::ostringstream os; - os << "Vars, width " << std::setw(5) << std::dec << i << " " << it->first; - V3Stats::addStat(m_stage, os.str(), it->second); + os << "Vars, width " << std::setw(5) << std::dec << i << " " << itr.first; + V3Stats::addStat(m_stage, os.str(), itr.second); } } else { std::ostringstream os; diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index ae45f6f00..71db187a3 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -53,15 +53,15 @@ class StatsReport { typedef std::multimap ByName; ByName byName; // * is always first - for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) { - V3Statistic* repp = &(*it); + for (auto& itr : s_allStats) { + V3Statistic* repp = &itr; byName.insert(make_pair(repp->name(), repp)); } // Process duplicates V3Statistic* lastp = nullptr; - for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) { - V3Statistic* repp = it->second; + for (const auto& itr : byName) { + V3Statistic* repp = itr.second; if (lastp && lastp->sumit() && lastp->printit() && lastp->name() == repp->name() && lastp->stage() == repp->stage()) { repp->combineWith(lastp); @@ -76,8 +76,8 @@ class StatsReport { typedef std::multimap ByName; ByName byName; // * is always first - for (StatColl::iterator it = s_allStats.begin(); it != s_allStats.end(); ++it) { - const V3Statistic* repp = &(*it); + for (const auto& itr : s_allStats) { + const V3Statistic* repp = &itr; if (repp->stage() == "*" && repp->printit()) { if (maxWidth < repp->name().length()) maxWidth = repp->name().length(); byName.insert(make_pair(repp->name(), repp)); @@ -87,8 +87,8 @@ class StatsReport { // Print organized by stage os << "Global Statistics:\n"; os << endl; - for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) { - const V3Statistic* repp = it->second; + for (const auto& itr : byName) { + const V3Statistic* repp = itr.second; if (repp->perf()) continue; os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); @@ -99,8 +99,8 @@ class StatsReport { // Print organized by stage os << "Performance Statistics:\n"; os << endl; - for (ByName::iterator it = byName.begin(); it != byName.end(); ++it) { - const V3Statistic* repp = it->second; + for (const auto& itr : byName) { + const V3Statistic* repp = itr.second; if (!repp->perf()) continue; os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 9be68d1d7..3cd98df8d 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -411,9 +411,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Build the initial graph from the starting state set. typedef TspGraphTmpl Graph; Graph graph; - for (V3TSP::StateVec::const_iterator it = states.begin(); it != states.end(); ++it) { - graph.addVertex(*it); - } + for (const auto& state : states) graph.addVertex(state); for (V3TSP::StateVec::const_iterator it = states.begin(); it != states.end(); ++it) { for (V3TSP::StateVec::const_iterator jt = it; jt != states.end(); ++jt) { if (it == jt) continue; diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 76428dc32..dcec7c663 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -200,10 +200,7 @@ private: // Collapse duplicate tables chgVscp = findDuplicateTable(chgVscp); - for (std::deque::iterator it = m_tableVarps.begin(); - it != m_tableVarps.end(); ++it) { - *it = findDuplicateTable(*it); - } + for (auto& vscp : m_tableVarps) vscp = findDuplicateTable(vscp); createOutputAssigns(nodep, stmtsp, indexVscp, chgVscp); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 2f58f79f0..f6a0c4a3c 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -402,9 +402,9 @@ private: // Create input variables AstNode::user2ClearTree(); V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& itr : tconnects) { + AstVar* portp = itr.first; + AstArg* argp = itr.second; AstNode* pinp = argp->exprp(); portp->unlinkFrBack(); pushDeletep(portp); // Remove it from the clone (not original) @@ -536,9 +536,9 @@ private: // Convert complicated outputs to temp signals V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstNode* pinp = it->second->exprp(); + for (const auto& itr : tconnects) { + AstVar* portp = itr.first; + AstNode* pinp = itr.second->exprp(); if (!pinp) { // Too few arguments in function call } else { diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 92131f735..922fac45b 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -480,8 +480,7 @@ class TristateVisitor : public TristateBaseVisitor { // or inouts without high-Z logic and put a 1'bz driver on them and add // them to the lhs map so they get expanded correctly. TristateGraph::VarVec vars = m_tgraph.tristateVars(); - for (TristateGraph::VarVec::iterator ii = vars.begin(); ii != vars.end(); ++ii) { - AstVar* varp = (*ii); + for (auto varp : vars) { if (m_tgraph.isTristate(varp)) { const auto it = m_lhsmap.find(varp); if (it == m_lhsmap.end()) { @@ -557,8 +556,7 @@ class TristateVisitor : public TristateBaseVisitor { AstNode* undrivenp = nullptr; // loop through the lhs drivers to build the driver resolution logic - for (RefVec::iterator ii = refsp->begin(); ii != refsp->end(); ++ii) { - AstVarRef* refp = (*ii); + for (auto refp : *refsp) { int w = lhsp->width(); // create the new lhs driver for this var diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 3b98eb02e..7afd7a905 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4246,9 +4246,9 @@ private: do { reloop: V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& tconnect : tconnects) { + AstVar* portp = tconnect.first; + AstArg* argp = tconnect.second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later // Prelim may cause the node to get replaced; we've lost our @@ -4301,9 +4301,9 @@ private: // Stage 2 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& tconnect : tconnects) { + AstVar* portp = tconnect.first; + AstArg* argp = tconnect.second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later // Change data types based on above accept completion @@ -4313,9 +4313,9 @@ private: // Stage 3 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& tconnect : tconnects) { + AstVar* portp = tconnect.first; + AstArg* argp = tconnect.second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later // Do PRELIM again, because above accept may have exited early @@ -4328,9 +4328,9 @@ private: // Stage 4 { V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& tconnect : tconnects) { + AstVar* portp = tconnect.first; + AstArg* argp = tconnect.second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later if (portp->direction() == VDirection::REF @@ -5777,9 +5777,9 @@ private: nodep->name(nodep->taskp()->name()); // Replace open array arguments with the callee's task V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); - for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { - AstVar* portp = it->first; - AstArg* argp = it->second; + for (const auto& tconnect : tconnects) { + AstVar* portp = tconnect.first; + AstArg* argp = tconnect.second; AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later if (hasOpenArrayIterateDType(portp->dtypep())) portp->dtypep(pinp->dtypep()); From 6dfce882a1d8b0823e032badcb4b44c98decfd23 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 10 Nov 2020 22:42:45 -0500 Subject: [PATCH 76/88] Support $exit as alias of $finish --- bin/verilator | 5 +++-- src/verilog.l | 1 + src/verilog.y | 3 +++ test_regress/t/t_exit.pl | 21 +++++++++++++++++++++ test_regress/t/t_exit.v | 12 ++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_exit.pl create mode 100644 test_regress/t/t_exit.v diff --git a/bin/verilator b/bin/verilator index e685664d7..3f921dc02 100755 --- a/bin/verilator +++ b/bin/verilator @@ -4075,9 +4075,10 @@ is ignored, only a single trace file may be active at once. $dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and $dumplimit/$dumpportlimit are currently ignored. -=item $finish, $stop +=item $exit, $finish, $stop -The rarely used optional parameter to $finish and $stop is ignored. +The rarely used optional parameter to $finish and $stop is ignored. $exit +is aliased to $finish. =item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite, $fscanf, $sscanf diff --git a/src/verilog.l b/src/verilog.l index a357f122c..0b7301475 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -191,6 +191,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$dumpportsoff" { FL; return yD_DUMPOFF; } "$dumpportson" { FL; return yD_DUMPON; } "$dumpvars" { FL; return yD_DUMPVARS; } + "$exit" { FL; return yD_EXIT; } "$exp" { FL; return yD_EXP; } "$fclose" { FL; return yD_FCLOSE; } "$fdisplay" { FL; return yD_FDISPLAY; } diff --git a/src/verilog.y b/src/verilog.y index ef4e4a045..4c6a9c5a4 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -724,6 +724,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_DUMPPORTS "$dumpports" %token yD_DUMPVARS "$dumpvars" %token yD_ERROR "$error" +%token yD_EXIT "$exit" %token yD_EXP "$exp" %token yD_FATAL "$fatal" %token yD_FCLOSE "$fclose" @@ -3553,6 +3554,8 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCStmt($1,$3)); } | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); } // + | yD_EXIT parenE { $$ = new AstFinish($1); } + // | yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); } | yD_FFLUSH parenE { $$ = new AstFFlush($1, nullptr); } | yD_FFLUSH '(' expr ')' { $$ = new AstFFlush($1, $3); } diff --git a/test_regress/t/t_exit.pl b/test_regress/t/t_exit.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_exit.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_exit.v b/test_regress/t/t_exit.v new file mode 100644 index 000000000..6dd666415 --- /dev/null +++ b/test_regress/t/t_exit.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +program t(/*AUTOARG*/); + initial begin + $write("*-* All Finished *-*\n"); + $exit; // Must be in program block + end +endprogram From b84c9bb4c0b2b6cbf672a800c1b228958a88e269 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 11 Nov 2020 19:00:10 -0500 Subject: [PATCH 77/88] Internals: Show scope debug information. --- src/V3Ast.cpp | 4 ++-- src/V3Ast.h | 3 ++- src/V3AstNodes.cpp | 11 +++++++++-- src/V3AstNodes.h | 1 + test_regress/t/t_lint_inherit.v | 2 ++ 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 6444ae0e4..f1b146440 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1113,7 +1113,7 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep } } -void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) { +void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, bool doCheck) { // Not const function as calls checkTree if (doDump) { { // Write log & close @@ -1131,7 +1131,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) { } } } - if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) { + if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) { // Error check checkTree(); // Broken isn't part of check tree because it can munge iterp's diff --git a/src/V3Ast.h b/src/V3Ast.h index 120bb13ad..0c37dde78 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1821,7 +1821,8 @@ public: void dumpTreeGdb(); // For GDB only void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ", int maxDepth = 0) const; - void dumpTreeFile(const string& filename, bool append = false, bool doDump = true); + void dumpTreeFile(const string& filename, bool append = false, bool doDump = true, + bool doCheck = true); static void dumpTreeFileGdb(const char* filenamep = nullptr); // METHODS - queries diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3074722cf..c620cb432 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1090,6 +1090,7 @@ void AstCell::dump(std::ostream& str) const { void AstCellInline::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << origModName(); + str << " [scopep=" << reinterpret_cast(scopep()) << "]"; } const char* AstClassPackage::broken() const { BROKEN_BASE_RTN(AstNodeModule::broken()); @@ -1179,7 +1180,7 @@ void AstInitArray::dump(std::ostream& str) const { str << " ..."; break; } - str << " [" << itr.first << "]=" << (void*)itr.second; + str << " [" << itr.first << "]=" << reinterpret_cast(itr.second); } } void AstJumpGo::dump(std::ostream& str) const { @@ -1415,7 +1416,7 @@ void AstTypeTable::dump(std::ostream& str) const { } void AstAssocArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); - str << "[assoc-" << (void*)keyDTypep() << "]"; + str << "[assoc-" << reinterpret_cast(keyDTypep()) << "]"; } string AstAssocArrayDType::prettyDTypeName() const { return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]"; @@ -1503,6 +1504,12 @@ void AstVar::dump(std::ostream& str) const { if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; str << " " << varType(); } +void AstScope::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " [abovep=" << reinterpret_cast(aboveScopep()) << "]"; + str << " [cellp=" << reinterpret_cast(aboveCellp()) << "]"; + str << " [modp=" << reinterpret_cast(modp()) << "]"; +} void AstSenTree::dump(std::ostream& str) const { this->AstNode::dump(str); if (isMulti()) str << " [MULTI]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 24334009d..94cbc43e2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2248,6 +2248,7 @@ public: virtual bool maybePointedTo() const override { return true; } virtual string name() const override { return m_name; } // * = Scope name virtual void name(const string& name) override { m_name = name; } + virtual void dump(std::ostream& str) const override; string nameDotless() const; string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } AstNodeModule* modp() const { return m_modp; } diff --git a/test_regress/t/t_lint_inherit.v b/test_regress/t/t_lint_inherit.v index cfee91136..01674a6b4 100644 --- a/test_regress/t/t_lint_inherit.v +++ b/test_regress/t/t_lint_inherit.v @@ -45,8 +45,10 @@ module m2 input d, // Due to bug the below disable used to be ignored. // verilator lint_off UNOPT + // verilator lint_off UNOPTFLAT output reg [1:0] q // verilator lint_on UNOPT + // verilator lint_on UNOPTFLAT ); always @* begin From 5634a18f780fbb32ba15f20f0658c36c3197800c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 11 Nov 2020 20:57:24 -0500 Subject: [PATCH 78/88] Tests: Smaller t_vpi_var test --- test_regress/t/t_vpi_var.cpp | 4 ++-- test_regress/t/t_vpi_var.v | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 17f943535..93802d6a7 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -456,7 +456,7 @@ int _mon_check_putget_str(p_cb_data cb_data) { t.type = vpiSimTime; t.high = 0; t.low = 0; - for (int i = 2; i <= 128; i++) { + for (int i = 2; i <= 6; i++) { static s_vpi_value v; int words = (i + 31) >> 5; TEST_MSG("========== %d ==========\n", i); @@ -532,7 +532,7 @@ int _mon_check_putget_str(p_cb_data cb_data) { }; } else { // setup and install - for (int i = 1; i <= 128; i++) { + for (int i = 1; i <= 6; i++) { char buf[32]; snprintf(buf, sizeof(buf), TestSimulator::rooted("arr[%d].arr"), i); CHECK_RESULT_NZ(data[i].scope = vpi_handle_by_name((PLI_BYTE8*)buf, NULL)); diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 206b38584..34b94b34e 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -91,7 +91,7 @@ extern "C" int mon_check(); genvar i; generate - for (i=1; i<=128; i=i+1) begin : arr + for (i=1; i<=6; i=i+1) begin : arr arr #(.LENGTH(i)) arr(); end endgenerate From 87b2adb6a1fa69b5d0b92a9437dd08ea990ee30d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 Nov 2020 18:49:49 -0500 Subject: [PATCH 79/88] With --debug, turn off address space layout randomization. --- bin/verilator | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/bin/verilator b/bin/verilator index 3f921dc02..213d90e34 100755 --- a/bin/verilator +++ b/bin/verilator @@ -76,7 +76,8 @@ if ($opt_gdbbt && !gdb_works()) { my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw; if ($opt_gdb) { # Generic GDB interactive - run (($ENV{VERILATOR_GDB}||"gdb") + run (aslr_off() + .($ENV{VERILATOR_GDB}||"gdb") ." ".verilator_bin() # Note, uncomment to set breakpoints before running: # ." -ex 'break main'" @@ -91,16 +92,22 @@ if ($opt_gdb) { ." -ex 'bt'"); } elsif ($opt_rr) { # Record with rr - run ("rr record ".verilator_bin() + run (aslr_off() + ."rr record ".verilator_bin() ." ".join(' ', @quoted_sw)); } elsif ($opt_gdbbt && $Debug) { # Run under GDB to get gdbbt - run ("gdb" + run (aslr_off() + ."gdb" ." ".verilator_bin() ." --batch --quiet --return-child-result" ." -ex \"run ".join(' ', @quoted_sw)."\"" ." -ex 'set width 0'" ." -ex 'bt' -ex 'quit'"); +} elsif ($Debug) { + # Debug + run(aslr_off() + .verilator_bin()." ".join(' ',@quoted_sw)); } else { # Normal, non gdb run(verilator_bin()." ".join(' ',@quoted_sw)); @@ -165,6 +172,15 @@ sub gdb_works { return $status==0; } +sub aslr_off { + my $ok = `setarch --addr-no-randomize echo ok 2>/dev/null` || ""; + if ($ok =~ /ok/) { + return "setarch --addr-no-randomize "; + } else { + return ""; + } +} + sub run { # Run command, check errors my $command = shift; From b49be06a5a67bd7e0e932b546a0be0dccb47b004 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 Nov 2020 18:50:05 -0500 Subject: [PATCH 80/88] Tests: Standard wording. --- test_regress/driver.pl | 8 ++++---- test_regress/t/t_EXAMPLE.v | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 6367b69bd..f2c23f8da 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1628,7 +1628,7 @@ sub _run { if (!$ok) { #print "**BAD $self->{name} $param{logfile} MT $moretry $try\n"; next if $moretry; - $self->error("Mismatch in output from $param{cmd}[0]\n"); + $self->error("Miscompares in output from $param{cmd}[0]\n"); $self->error("Might be error in regexp format\n") if $ok<1; print "GOT:\n"; print $wholefile; @@ -2102,7 +2102,7 @@ sub files_identical { for (my $l=0; $l<=$nl; ++$l) { if (($l1[$l]||"") ne ($l2[$l]||"")) { next try if $moretry; - $self->error("Line ".($l+1)." mismatches; $fn1 != $fn2"); + $self->error("Line ".($l+1)." miscompares; $fn1 != $fn2"); warn("F1: ".($l1[$l]||"*EOF*\n") ."F2: ".($l2[$l]||"*EOF*\n")); if ($ENV{HARNESS_UPDATE_GOLDEN}) { # Update golden files with current @@ -2163,7 +2163,7 @@ sub vcd_identical { $out = `$cmd`; if ($out ne '') { print $out; - $self->error("VCD miscompare $fn1 $fn2\n"); + $self->error("VCD miscompares $fn1 $fn2\n"); $self->copy_if_golden($fn1, $fn2); return 0; } @@ -2178,7 +2178,7 @@ sub vcd_identical { my $b = Dumper($h2); if ($a ne $b) { print "$a\n$b\n" if $::Debug; - $self->error("VCD hier mismatch $fn1 $fn2\n"); + $self->error("VCD hier miscompares $fn1 $fn2\n"); $self->copy_if_golden($fn1, $fn2); return 0; } diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 4e1051614..3a7373cc0 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2020 ____YOUR_NAME_HERE____. +// any use, without warranty, 2020 by ____YOUR_NAME_HERE____. // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/ From 6a58e676994895e01a84670977798ef9d244af14 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 Nov 2020 19:31:53 -0500 Subject: [PATCH 81/88] Commentary --- nodist/invoke_atsim | 4 ++-- nodist/invoke_iccr | 4 ++-- nodist/invoke_ncverilog | 4 ++-- nodist/invoke_vcs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nodist/invoke_atsim b/nodist/invoke_atsim index d7dd44268..0d5c61751 100755 --- a/nodist/invoke_atsim +++ b/nodist/invoke_atsim @@ -9,7 +9,7 @@ use strict; # main eval `modulecmd perl add axiom-athdl`; -exec('atsim',@ARGV); +exec('atsim', @ARGV); ####################################################################### __END__ @@ -22,7 +22,7 @@ invoke_atsim - Invoke tool under "modules" command =head1 SYNOPSIS - invoke_atsim {ncv arguments} + invoke_atsim {arguments} =head1 DESCRIPTION diff --git a/nodist/invoke_iccr b/nodist/invoke_iccr index 883b9ad9a..3a109a041 100755 --- a/nodist/invoke_iccr +++ b/nodist/invoke_iccr @@ -9,7 +9,7 @@ use strict; # main eval `modulecmd perl add cds-ius`; -exec('iccr',@ARGV); +exec('iccr', @ARGV); ####################################################################### __END__ @@ -22,7 +22,7 @@ invoke_iccr - Invoke tool under "modules" command =head1 SYNOPSIS - invoke_iccr {ncv arguments} + invoke_iccr {arguments} =head1 DESCRIPTION diff --git a/nodist/invoke_ncverilog b/nodist/invoke_ncverilog index 08eb51889..16d4f0492 100755 --- a/nodist/invoke_ncverilog +++ b/nodist/invoke_ncverilog @@ -9,7 +9,7 @@ use strict; # main eval `modulecmd perl add cds-ius/latest`; -exec('ncverilog',@ARGV); +exec('ncverilog', @ARGV); ####################################################################### __END__ @@ -22,7 +22,7 @@ invoke_ncverilog - Invoke tool under "modules" command =head1 SYNOPSIS - invoke_ncverilog {ncv arguments} + invoke_ncverilog {arguments} =head1 DESCRIPTION diff --git a/nodist/invoke_vcs b/nodist/invoke_vcs index 1e708e9ad..08ede75ec 100755 --- a/nodist/invoke_vcs +++ b/nodist/invoke_vcs @@ -9,7 +9,7 @@ use strict; # main eval `modulecmd perl add synopsys-sim/latest`; -exec('vcs',@ARGV); +exec('vcs', @ARGV); ####################################################################### __END__ @@ -22,7 +22,7 @@ invoke_vcs - Invoke tool under "modules" command =head1 SYNOPSIS - invoke_vcs {ncv arguments} + invoke_vcs {arguments} =head1 DESCRIPTION From 7eac788306e4a816def8821e15497584e160ebbb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 Nov 2020 19:45:12 -0500 Subject: [PATCH 82/88] Add error on using :: with module --- src/V3LinkDot.cpp | 9 ++++++--- test_regress/t/t_class_mod_bad.out | 5 +++++ test_regress/t/t_class_mod_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_class_mod_bad.v | 25 +++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_class_mod_bad.out create mode 100755 test_regress/t/t_class_mod_bad.pl create mode 100644 test_regress/t/t_class_mod_bad.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index b8dce26fe..7877f7b17 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2807,9 +2807,12 @@ private: nodep->packagep(cpackagerefp->packagep()); } else { nodep->packagep(cpackagerefp->classOrPackagep()); - // if (cpackagerefp->paramsp()) { - // nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); - // } + if (!VN_IS(nodep->packagep(), Class) && !VN_IS(nodep->packagep(), Package)) { + cpackagerefp->v3error( + "'::' expected to reference a class/package but referenced " + << nodep->packagep()->prettyTypeName() << endl + << cpackagerefp->warnMore() + "... Suggest '.' instead of '::'"); + } } } else { cpackagep->v3warn(E_UNSUPPORTED, diff --git a/test_regress/t/t_class_mod_bad.out b/test_regress/t/t_class_mod_bad.out new file mode 100644 index 000000000..8a24ba164 --- /dev/null +++ b/test_regress/t/t_class_mod_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_mod_bad.v:21:7: '::' expected to reference a class/package but referenced MODULE 'M' + : ... Suggest '.' instead of '::' + 21 | M::Cls p; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_mod_bad.pl b/test_regress/t/t_class_mod_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_mod_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_mod_bad.v b/test_regress/t/t_class_mod_bad.v new file mode 100644 index 000000000..05194f7a6 --- /dev/null +++ b/test_regress/t/t_class_mod_bad.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// verilator lint_off MULTITOP + +module M; +class Cls; + function string name; + return $sformatf("m %m"); + endfunction +endclass +endmodule + +module t (/*AUTOARG*/); + string s; + + initial begin + M::Cls p; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From e8c03650aea592b7058015df77f91377b3c67b3e Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Fri, 13 Nov 2020 23:50:09 +0900 Subject: [PATCH 83/88] Fix internal error if always block without begin-end has concat (#2640) (#2641) --- src/V3SplitVar.cpp | 8 ++++++-- test_regress/t/t_split_var_0.v | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 9e29743e0..38ea0da47 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -460,13 +460,17 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { if (nodep->sensesp()) { // When visiting sensitivity list, always is the context setContextAndIterate(nodep, nodep->sensesp()); } - if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp); + for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) { + iterate(bodysp); + } }; virtual void visit(AstAlwaysPublic* nodep) override { if (nodep->sensesp()) { // When visiting sensitivity list, always is the context setContextAndIterate(nodep, nodep->sensesp()); } - if (AstNode* bodysp = nodep->bodysp()) iterate(bodysp); + for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) { + iterate(bodysp); + } } virtual void visit(AstNodeFTaskRef* nodep) override { VL_RESTORER(m_contextp); diff --git a/test_regress/t/t_split_var_0.v b/test_regress/t/t_split_var_0.v index 08295706a..c317d5f9e 100644 --- a/test_regress/t/t_split_var_0.v +++ b/test_regress/t/t_split_var_0.v @@ -166,7 +166,8 @@ module barshift_1d_unpacked_struct1 #(parameter DEPTH = 2, localparam WIDTH = 2* end endgenerate assign tmp[0+OFFSET] = {pad, in}; - assign out = tmp[DEPTH+OFFSET][WIDTH-1:0]; + logic _dummy; + always_comb {_dummy, out[WIDTH-1:1], out[0]} = tmp[DEPTH+OFFSET][WIDTH:0]; endmodule From 5d3482734a12a7ba0034c16ac025a41121a69bb8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 13 Nov 2020 18:49:34 -0500 Subject: [PATCH 84/88] Fix precision in verilator_gantt. --- bin/verilator_gantt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 46f70dfaf..cc7f0fbba 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -198,14 +198,18 @@ sub report { } print "\nStatistics:\n"; - print " min log(p2e) = $min_p2e from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict}, elapsed $Mtasks{$min_mtask}{elapsed})\n"; - print " max log(p2e) = $max_p2e from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict}, elapsed $Mtasks{$max_mtask}{elapsed})\n"; + printf " min log(p2e) = %0.3f", $min_p2e; + print " from mtask $min_mtask (predict $Mtasks{$min_mtask}{predict},"; + print " elapsed $Mtasks{$min_mtask}{elapsed})\n"; + printf " max log(p2e) = %0.3f", $max_p2e; + print " from mtask $max_mtask (predict $Mtasks{$max_mtask}{predict},"; + print " elapsed $Mtasks{$max_mtask}{elapsed})\n"; my $stddev = stddev(\@p2e_ratios); my $mean = mean(\@p2e_ratios); - print " mean = " . ($mean) . "\n"; - print " stddev = " . ($stddev) . "\n"; - print " e ^ stddev = " . exp($stddev). "\n"; + printf " mean = %0.3f\n", $mean; + printf " stddev = %0.3f\n", $stddev; + printf " e ^ stddev = %0.3f\n", exp($stddev); print "\n"; if ($nthreads > $ncpus) { From f7a5883205ba24f5cdde528bb3939ca80280ae1c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 13 Nov 2020 21:12:03 -0500 Subject: [PATCH 85/88] Internals: assert not double adding. No functional change intended. --- src/V3Ast.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index f1b146440..f7bf4eccd 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -394,6 +394,7 @@ void AstNode::setOp4p(AstNode* newp) { void AstNode::addOp1p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp1p"); + UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node");); if (!m_op1p) { op1p(newp); } else { @@ -403,6 +404,7 @@ void AstNode::addOp1p(AstNode* newp) { void AstNode::addOp2p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp2p"); + UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node");); if (!m_op2p) { op2p(newp); } else { @@ -412,6 +414,7 @@ void AstNode::addOp2p(AstNode* newp) { void AstNode::addOp3p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp3p"); + UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node");); if (!m_op3p) { op3p(newp); } else { @@ -421,6 +424,7 @@ void AstNode::addOp3p(AstNode* newp) { void AstNode::addOp4p(AstNode* newp) { UASSERT(newp, "Null item passed to addOp4p"); + UDEBUGONLY(UASSERT_OBJ(!newp->m_backp, newp, "Adding already linked node");); if (!m_op4p) { op4p(newp); } else { From 3e7013af3109a98a803d6a94281081098d2f2db5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 13 Nov 2020 21:12:18 -0500 Subject: [PATCH 86/88] Internal scope cleanup. No functional change. --- src/V3Inst.cpp | 4 ++-- src/V3Scope.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 1c016ac8f..adc210e24 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -193,8 +193,8 @@ class InstDeVisitor : public AstNVisitor { // Find all cells with arrays, and convert to non-arrayed private: // STATE - AstRange* m_cellRangep - = nullptr; // Range for arrayed instantiations, nullptr for normal instantiations + // Range for arrayed instantiations, nullptr for normal instantiations + AstRange* m_cellRangep = nullptr; int m_instSelNum = 0; // Current instantiation count 0..N-1 InstDeModVarVisitor m_deModVars; // State of variables for current cell module diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 1922c7c80..6195ffc98 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -116,7 +116,8 @@ private: // Now for each child cell, iterate the module this cell points to for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) { if (AstCell* cellp = VN_CAST(cellnextp, Cell)) { - VL_RESTORER(m_scopep); + VL_RESTORER(m_scopep); // Protects m_scopep set in called module + // which is "above" in this code, but later in code execution order VL_RESTORER(m_aboveCellp); VL_RESTORER(m_aboveScopep); { @@ -329,9 +330,11 @@ private: // VISITORS virtual void visit(AstScope* nodep) override { // Want to ignore blocks under it - m_scopep = nodep; - iterateChildren(nodep); - m_scopep = nullptr; + VL_RESTORER(m_scopep); + { + m_scopep = nodep; + iterateChildren(nodep); + } } virtual void movedDeleteOrIterate(AstNode* nodep) { From c3cfaf55ed806d2b7c5b12b2c1bcb5ba8546ddc0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Nov 2020 09:26:38 -0500 Subject: [PATCH 87/88] Commentary --- Changes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changes b/Changes index 9dc1d5344..482e6ccce 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Report error on typedef referencing self (#2539). [Cody Piersall] +**** With --debug, turn off address space layout randomization. + **** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett] **** Fix cast width propagation (#2597). [flex-liu] @@ -30,6 +32,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix arrays of modport interfaces (#2614). [Thierry Tambe] +**** Fix split_var internal error (#2640) (#2641). [Yutetsu TAKATSUKASA] + * Verilator 4.102 2020-10-15 From 02cb3d17a2782429a3f09d991391d6342301aa66 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 Nov 2020 09:50:30 -0500 Subject: [PATCH 88/88] Version bump --- Changes | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 482e6ccce..98a47d3a3 100644 --- a/Changes +++ b/Changes @@ -2,7 +2,7 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! -* Verilator 4.103 devel +* Verilator 4.104 2020-11-14 *** Support queue and associative array 'with' statements. (#2616) diff --git a/configure.ac b/configure.ac index 040a50165..6b165fcc0 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.103 devel], +AC_INIT([Verilator],[4.104 2020-11-14], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file