From 30783e6a79f0e5ec13ab7dd7a13e03d13aab83ad Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 2 May 2022 22:23:05 -0400 Subject: [PATCH 01/68] devel release --- Changes | 7 +++++++ configure.ac | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index b1760a0d8..2d24b7418 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,13 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 4.223 devel +========================== + +**Minor:** + + + Verilator 4.222 2022-05-02 ========================== diff --git a/configure.ac b/configure.ac index 5ec247c2a..f0abbb265 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.222 2022-05-02], +AC_INIT([Verilator],[4.223 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From 3d762282b9fde1c53c5439a95309a6a437412f14 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 5 May 2022 07:02:52 -0400 Subject: [PATCH 02/68] Fix hang with large case statement optimization (#3405). --- Changes | 1 + src/V3Const.cpp | 17 ++++++--- test_regress/t/t_concat_or.pl | 18 +++++++++ test_regress/t/t_concat_or.v | 72 +++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 6 deletions(-) create mode 100755 test_regress/t/t_concat_or.pl create mode 100644 test_regress/t/t_concat_or.v diff --git a/Changes b/Changes index 2d24b7418..1c9166ce4 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 4.223 devel **Minor:** +* Fix hang with large case statement optimization (#3405). [Mike Urbach] Verilator 4.222 2022-05-02 diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 9152d8cd6..759033185 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -769,6 +769,9 @@ public: class ConstVisitor final : public VNVisitor { private: + // CONSTANTS + static constexpr unsigned CONCAT_MERGABLE_MAX_DEPTH = 10; // Limit alg recursion + // NODE STATE // ** only when m_warn/m_doExpensive is set. If state is needed other times, // ** must track down everywhere V3Const is called and make sure no overlaps. @@ -1420,11 +1423,12 @@ private: if (rend == rfromp->width() && lstart->toSInt() == 0) return true; return false; } - bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp) { + bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp, unsigned depth) { // determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantageous if (!v3Global.opt.oAssemble()) return false; // opt disabled if (lhsp->type() != rhsp->type()) return false; if (!ifConcatMergeableBiop(lhsp)) return false; + if (depth > CONCAT_MERGABLE_MAX_DEPTH) return false; // As worse case O(n^2) algorithm const AstNodeBiop* const lp = VN_CAST(lhsp, NodeBiop); const AstNodeBiop* const rp = VN_CAST(rhsp, NodeBiop); @@ -1434,11 +1438,12 @@ private: const bool rad = ifMergeAdjacent(lp->rhsp(), rp->rhsp()); if (lad && rad) return true; // {a[] & b[]&c[], a[] & b[]&c[]} - if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true; + if (lad && concatMergeable(lp->rhsp(), rp->rhsp(), depth + 1)) return true; // {a[]&b[] & c[], a[]&b[] & c[]} - if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true; + if (rad && concatMergeable(lp->lhsp(), rp->lhsp(), depth + 1)) return true; // {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])} - if (concatMergeable(lp->lhsp(), rp->lhsp()) && concatMergeable(lp->rhsp(), rp->rhsp())) { + if (concatMergeable(lp->lhsp(), rp->lhsp(), depth + 1) + && concatMergeable(lp->rhsp(), rp->rhsp(), depth + 1)) { return true; } return false; @@ -1698,7 +1703,7 @@ private: AstNode* const lrp = lp->rhsp()->cloneTree(false); AstNode* const rlp = rp->lhsp()->cloneTree(false); AstNode* const rrp = rp->rhsp()->cloneTree(false); - if (concatMergeable(lp, rp)) { + if (concatMergeable(lp, rp, 0)) { AstConcat* const newlp = new AstConcat(rlp->fileline(), llp, rlp); AstConcat* const newrp = new AstConcat(rrp->fileline(), lrp, rrp); // use the lhs to replace the parent concat @@ -3368,7 +3373,7 @@ private: TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())"); // CONCAT(a[1],a[0]) -> a[1:0] TREEOPV("AstConcat{$lhsp.castSel, $rhsp.castSel, ifAdjacentSel(VN_AS($lhsp,,Sel),,VN_AS($rhsp,,Sel))}", "replaceConcatSel(nodep)"); - TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)"); + TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp,,0)}", "replaceConcatMerge(nodep)"); // Common two-level operations that can be simplified TREEOP ("AstAnd {$lhsp.castConst,matchAndCond(nodep)}", "DONE"); TREEOP ("AstAnd {$lhsp.castConst, $rhsp.castOr, matchMaskedOr(nodep)}", "DONE"); diff --git a/test_regress/t/t_concat_or.pl b/test_regress/t/t_concat_or.pl new file mode 100755 index 000000000..4409f8046 --- /dev/null +++ b/test_regress/t/t_concat_or.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 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"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_concat_or.v b/test_regress/t/t_concat_or.v new file mode 100644 index 000000000..17b05cb4b --- /dev/null +++ b/test_regress/t/t_concat_or.v @@ -0,0 +1,72 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Outputs + i299, + // Inputs + i190, i191, i192, i193, i194, i195, i196, i197, i198, i199, i200, i201, i202, + i203, i204, i205, i182, i183, i184, i185, i186, i187, i188, i189, i206, i282, + i284, i286, i287, i289, i290, i294, i34, i288, i31, i296, i37, i38 + ); + input [3:0] i190; + input [3:0] i191; + input [3:0] i192; + input [3:0] i193; + input [3:0] i194; + input [3:0] i195; + input [3:0] i196; + input [3:0] i197; + input [3:0] i198; + input [3:0] i199; + input [3:0] i200; + input [3:0] i201; + input [3:0] i202; + input [3:0] i203; + input [3:0] i204; + input [3:0] i205; + input [3:0] i182; + input [3:0] i183; + input [3:0] i184; + input [3:0] i185; + input [3:0] i186; + input [3:0] i187; + input [3:0] i188; + input [3:0] i189; + input [3:0] i206; + input [3:0] i282; + input [3:0] i284; + input [3:0] i286; + input [3:0] i287; + input [3:0] i289; + input [3:0] i290; + input [3:0] i294; + input [3:0] i34; + input [3:0] i288; + input [3:0] i31; + input [3:0] i296; + input [3:0] i37; + input [3:0] i38; + + output [3:0] i299; + assign i299 = { i296[2:0] | i31[3:1] | i282[3:1] | i284[3:1] | i34[3:1] + | i286[3:1] | i287[3:1] | i37[3:1] | i38[3:1] + | i288[3:1] | i289[3:1] | i290[3:1] | i182[3:1] + | i183[3:1] | i184[3:1] | i185[3:1] | i186[3:1] + | i187[3:1] | i188[3:1] | i189[3:1] | i190[3:1] + | i191[3:1] | i192[3:1] | i193[3:1] | i194[3:1] + | i195[3:1] | i196[3:1] | i197[3:1] | i198[3:1] + | i199[3:1] | i200[3:1] | i201[3:1] | i202[3:1] + | i203[3:1] | i204[3:1] | i205[3:1] | i206[3:1] + , + i294[0] | i289[0] | i290[0] | i182[0] | i183[0] + | i184[0] | i185[0] | i186[0] | i187[0] | i188[0] + | i189[0] | i190[0] | i191[0] | i192[0] | i193[0] + | i194[0] | i195[0] | i196[0] | i197[0] | i198[0] + | i199[0] | i200[0] | i201[0] | i202[0] | i203[0] + | i204[0] | i205[0] | i206[0] }; + +endmodule From 93782597791ba1de8dc517d6f63c49a78ebf668d Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 6 May 2022 10:24:03 +0200 Subject: [PATCH 03/68] Fix UNOPTFLAT warning from initial static var (#3406) Signed-off-by: Kamil Rakoczy --- src/V3Order.cpp | 7 ++++-- test_regress/t/t_initialstatic_circ.pl | 21 +++++++++++++++++ test_regress/t/t_initialstatic_circ.v | 31 ++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_initialstatic_circ.pl create mode 100644 test_regress/t/t_initialstatic_circ.v diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 9007ce8f2..4f2890be6 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1133,6 +1133,10 @@ class OrderProcess final : VNDeleter { return name; } + bool nodeIsInitial(const OrderLogicVertex* LVtxp) { + return LVtxp && (VN_IS(LVtxp->nodep(), Initial) || VN_IS(LVtxp->nodep(), InitialStatic)); + } + void nodeMarkCircular(OrderVarVertex* vertexp, OrderEdge* edgep) { // To be marked circular requires being a clock assigned in a delayed assignment, or // having a cutable in or out edge, none of which is true for the DPI export trigger. @@ -1146,8 +1150,7 @@ class OrderProcess final : VNDeleter { toLVtxp = dynamic_cast(edgep->top()); } // - if ((fromLVtxp && VN_IS(fromLVtxp->nodep(), Initial)) - || (toLVtxp && VN_IS(toLVtxp->nodep(), Initial))) { + if (nodeIsInitial(fromLVtxp) || nodeIsInitial(toLVtxp)) { // IEEE does not specify ordering between initial blocks, so we // can do whatever we want. We especially do not want to // evaluate multiple times, so do not mark the edge circular diff --git a/test_regress/t/t_initialstatic_circ.pl b/test_regress/t/t_initialstatic_circ.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_initialstatic_circ.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 2022 by Antmicro Ltd. 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_initialstatic_circ.v b/test_regress/t/t_initialstatic_circ.v new file mode 100644 index 000000000..31325cad5 --- /dev/null +++ b/test_regress/t/t_initialstatic_circ.v @@ -0,0 +1,31 @@ +// DESCRIPTION::Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +package pkg; + int unsigned id = 0; + + function int unsigned func(); + int unsigned local_id; + local_id = id + 1; + id = local_id; + return local_id; + endfunction : func +endpackage + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + import pkg::*; + int unsigned func_id = func(); + + always @ (posedge clk) begin + $display(id); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 5b2755d28d92de13d418e707731ba80548405f40 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 8 May 2022 20:46:08 -0400 Subject: [PATCH 04/68] Untabify verilog.y (#3412). No functional change. --- src/verilog.y | 8910 ++++++++++++++++++++++++------------------------- 1 file changed, 4455 insertions(+), 4455 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 7c660fc62..21e8a0956 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1006,1396 +1006,1396 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //********************************************************************** // Files -source_text: // ==IEEE: source_text - /* empty */ { } - // // timeunits_declaration moved into description:package_item - | descriptionList { } - ; +source_text: // ==IEEE: source_text + /* empty */ { } + // // timeunits_declaration moved into description:package_item + | descriptionList { } + ; -descriptionList: // IEEE: part of source_text - description { } - | descriptionList description { } - ; +descriptionList: // IEEE: part of source_text + description { } + | descriptionList description { } + ; -description: // ==IEEE: description - module_declaration { } - // // udp_declaration moved into module_declaration - | interface_declaration { } - | program_declaration { } - | package_declaration { } - | package_item { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } - | bind_directive { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } - // unsupported // IEEE: config_declaration - // // Verilator only - | yaT_RESETALL { } // Else, under design, and illegal based on IEEE 22.3 - | yaT_NOUNCONNECTED { PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); } - | yaT_UNCONNECTED_PULL0 { PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); } - | yaT_UNCONNECTED_PULL1 { PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); } - | vltItem { } - | error { } - ; +description: // ==IEEE: description + module_declaration { } + // // udp_declaration moved into module_declaration + | interface_declaration { } + | program_declaration { } + | package_declaration { } + | package_item { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } + | bind_directive { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } + // unsupported // IEEE: config_declaration + // // Verilator only + | yaT_RESETALL { } // Else, under design, and illegal based on IEEE 22.3 + | yaT_NOUNCONNECTED { PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); } + | yaT_UNCONNECTED_PULL0 { PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); } + | yaT_UNCONNECTED_PULL1 { PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); } + | vltItem { } + | error { } + ; -timeunits_declaration: // ==IEEE: timeunits_declaration - yTIMEUNIT yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, false, 0); $$ = nullptr; } - | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, true, $4); $$ = nullptr; } - | yTIMEPRECISION yaTIMENUM ';' - { PARSEP->timescaleMod($2, GRAMMARP->m_modp, false, 0, true, $2); $$ = nullptr; } - ; +timeunits_declaration: // ==IEEE: timeunits_declaration + yTIMEUNIT yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, false, 0); $$ = nullptr; } + | yTIMEUNIT yaTIMENUM '/' yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, true, $2, true, $4); $$ = nullptr; } + | yTIMEPRECISION yaTIMENUM ';' + { PARSEP->timescaleMod($2, GRAMMARP->m_modp, false, 0, true, $2); $$ = nullptr; } + ; //********************************************************************** // Packages -package_declaration: // ==IEEE: package_declaration - packageFront package_itemListE yENDPACKAGE endLabelE - { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - GRAMMARP->m_modp = nullptr; - SYMP->popScope($1); - GRAMMARP->endLabel($4,$1,$4); } - ; +package_declaration: // ==IEEE: package_declaration + packageFront package_itemListE yENDPACKAGE endLabelE + { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc + if ($2) $1->addStmtp($2); + GRAMMARP->m_modp = nullptr; + SYMP->popScope($1); + GRAMMARP->endLabel($4,$1,$4); } + ; packageFront: - yPACKAGE lifetimeE idAny ';' - { $$ = new AstPackage($3, *$3); - $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" - $$->lifetime($2); - $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); - $$->timeunit(PARSEP->timeLastUnit()); - PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } - ; + yPACKAGE lifetimeE idAny ';' + { $$ = new AstPackage($3, *$3); + $$->inLibrary(true); // packages are always libraries; don't want to make them a "top" + $$->lifetime($2); + $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } + ; -package_itemListE: // IEEE: [{ package_item }] - /* empty */ { $$ = nullptr; } - | package_itemList { $$ = $1; } - ; +package_itemListE: // IEEE: [{ package_item }] + /* empty */ { $$ = nullptr; } + | package_itemList { $$ = $1; } + ; -package_itemList: // IEEE: { package_item } - package_item { $$ = $1; } - | package_itemList package_item { $$ = $1->addNextNull($2); } - ; +package_itemList: // IEEE: { package_item } + package_item { $$ = $1; } + | package_itemList package_item { $$ = $1->addNextNull($2); } + ; -package_item: // ==IEEE: package_item - package_or_generate_item_declaration { $$ = $1; } - | anonymous_program { $$ = $1; } - | package_export_declaration { $$ = $1; } - | timeunits_declaration { $$ = $1; } - ; +package_item: // ==IEEE: package_item + package_or_generate_item_declaration { $$ = $1; } + | anonymous_program { $$ = $1; } + | package_export_declaration { $$ = $1; } + | timeunits_declaration { $$ = $1; } + ; -package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration - net_declaration { $$ = $1; } - | data_declaration { $$ = $1; } - | task_declaration { $$ = $1; } - | function_declaration { $$ = $1; } - //UNSUP checker_declaration { $$ = $1; } - | dpi_import_export { $$ = $1; } - //UNSUP extern_constraint_declaration { $$ = $1; } - | class_declaration { $$ = $1; } - // // class_constructor_declaration is part of function_declaration - // // local_parameter_declaration under parameter_declaration - | parameter_declaration ';' { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } - //UNSUP assertion_item_declaration { $$ = $1; } - | ';' { $$ = nullptr; } - ; +package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration + net_declaration { $$ = $1; } + | data_declaration { $$ = $1; } + | task_declaration { $$ = $1; } + | function_declaration { $$ = $1; } + //UNSUP checker_declaration { $$ = $1; } + | dpi_import_export { $$ = $1; } + //UNSUP extern_constraint_declaration { $$ = $1; } + | class_declaration { $$ = $1; } + // // class_constructor_declaration is part of function_declaration + // // local_parameter_declaration under parameter_declaration + | parameter_declaration ';' { $$ = $1; } + //UNSUP covergroup_declaration { $$ = $1; } + //UNSUP assertion_item_declaration { $$ = $1; } + | ';' { $$ = nullptr; } + ; package_import_declarationList: - package_import_declaration { $$ = $1; } - | package_import_declarationList package_import_declaration { $$ = $1->addNextNull($2); } - ; + package_import_declaration { $$ = $1; } + | package_import_declarationList package_import_declaration { $$ = $1->addNextNull($2); } + ; -package_import_declaration: // ==IEEE: package_import_declaration - yIMPORT package_import_itemList ';' { $$ = $2; } - ; +package_import_declaration: // ==IEEE: package_import_declaration + yIMPORT package_import_itemList ';' { $$ = $2; } + ; package_import_itemList: - package_import_item { $$ = $1; } - | package_import_itemList ',' package_import_item { $$ = $1->addNextNull($3); } - ; + package_import_item { $$ = $1; } + | package_import_itemList ',' package_import_item { $$ = $1->addNextNull($3); } + ; -package_import_item: // ==IEEE: package_import_item - idCC/*package_identifier*/ yP_COLONCOLON package_import_itemObj - { - if (!VN_IS($1, Package)) { - $$ = nullptr; - $1->v3error("Importing from missing package '" << *$1 << "'"); - } else { - $$ = new AstPackageImport($2, VN_CAST($1, Package), *$3); - SYMP->importItem($1,*$3); - } } - ; +package_import_item: // ==IEEE: package_import_item + idCC/*package_identifier*/ yP_COLONCOLON package_import_itemObj + { + if (!VN_IS($1, Package)) { + $$ = nullptr; + $1->v3error("Importing from missing package '" << *$1 << "'"); + } else { + $$ = new AstPackageImport($2, VN_CAST($1, Package), *$3); + SYMP->importItem($1,*$3); + } } + ; -package_import_itemObj: // IEEE: part of package_import_item - idAny/*package_identifier*/ { $$ = $1; $$ = $1; } - | '*' { $$ = $1; static string star = "*"; $$ = ☆ } - ; +package_import_itemObj: // IEEE: part of package_import_item + idAny/*package_identifier*/ { $$ = $1; $$ = $1; } + | '*' { $$ = $1; static string star = "*"; $$ = ☆ } + ; package_export_declaration: // IEEE: package_export_declaration - yEXPORT '*' yP_COLONCOLON '*' ';' { $$ = new AstPackageExportStarStar($2); SYMP->exportStarStar($1); } - | yEXPORT package_export_itemList ';' { $$ = $2; } - ; + yEXPORT '*' yP_COLONCOLON '*' ';' { $$ = new AstPackageExportStarStar($2); SYMP->exportStarStar($1); } + | yEXPORT package_export_itemList ';' { $$ = $2; } + ; package_export_itemList: - package_export_item { $$ = $1; } - | package_export_itemList ',' package_export_item { $$ = $1->addNextNull($3); } - ; + package_export_item { $$ = $1; } + | package_export_itemList ',' package_export_item { $$ = $1->addNextNull($3); } + ; -package_export_item: // ==IEEE: package_export_item - idCC yP_COLONCOLON package_import_itemObj - { $$ = new AstPackageExport($3, VN_CAST($1, Package), *$3); - SYMP->exportItem($1,*$3); } - ; +package_export_item: // ==IEEE: package_export_item + idCC yP_COLONCOLON package_import_itemObj + { $$ = new AstPackageExport($3, VN_CAST($1, Package), *$3); + SYMP->exportItem($1,*$3); } + ; //********************************************************************** // Module headers -module_declaration: // ==IEEE: module_declaration - // // timeunits_declaration instead in module_item - // // IEEE: module_nonansi_header + module_ansi_header - modFront importsAndParametersE portsStarE ';' - /*cont*/ module_itemListE yENDMODULE endLabelE - { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); - GRAMMARP->m_modp = nullptr; - SYMP->popScope($1); - GRAMMARP->endLabel($7,$1,$7); } - | udpFront parameter_port_listE portsStarE ';' - /*cont*/ module_itemListE yENDPRIMITIVE endLabelE - { $1->modTrace(false); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); - GRAMMARP->m_tracingParse = true; - GRAMMARP->m_modp = nullptr; - SYMP->popScope($1); - GRAMMARP->endLabel($7,$1,$7); } - // - | yEXTERN modFront parameter_port_listE portsStarE ';' - { BBUNSUP($1, "Unsupported: extern module"); } - ; +module_declaration: // ==IEEE: module_declaration + // // timeunits_declaration instead in module_item + // // IEEE: module_nonansi_header + module_ansi_header + modFront importsAndParametersE portsStarE ';' + /*cont*/ module_itemListE yENDMODULE endLabelE + { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc + if ($2) $1->addStmtp($2); + if ($3) $1->addStmtp($3); + if ($5) $1->addStmtp($5); + GRAMMARP->m_modp = nullptr; + SYMP->popScope($1); + GRAMMARP->endLabel($7,$1,$7); } + | udpFront parameter_port_listE portsStarE ';' + /*cont*/ module_itemListE yENDPRIMITIVE endLabelE + { $1->modTrace(false); // Stash for implicit wires, etc + if ($2) $1->addStmtp($2); + if ($3) $1->addStmtp($3); + if ($5) $1->addStmtp($5); + GRAMMARP->m_tracingParse = true; + GRAMMARP->m_modp = nullptr; + SYMP->popScope($1); + GRAMMARP->endLabel($7,$1,$7); } + // + | yEXTERN modFront parameter_port_listE portsStarE ';' + { BBUNSUP($1, "Unsupported: extern module"); } + ; modFront: - // // General note: all *Front functions must call symPushNew before - // // any formal arguments, as the arguments must land in the new scope. - yMODULE lifetimeE idAny - { $$ = new AstModule($3,*$3); - $$->lifetime($2); - $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); - $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); - $$->timeunit(PARSEP->timeLastUnit()); - $$->unconnectedDrive(PARSEP->unconnectedDrive()); - PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } - ; + // // General note: all *Front functions must call symPushNew before + // // any formal arguments, as the arguments must land in the new scope. + yMODULE lifetimeE idAny + { $$ = new AstModule($3,*$3); + $$->lifetime($2); + $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); + $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); + $$->unconnectedDrive(PARSEP->unconnectedDrive()); + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } + ; -importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration - // // { package_import_declaration } [ parameter_port_list ] - parameter_port_listE { $$ = $1; } - | package_import_declarationList parameter_port_listE { $$ = $1->addNextNull($2); } - ; +importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration + // // { package_import_declaration } [ parameter_port_list ] + parameter_port_listE { $$ = $1; } + | package_import_declarationList parameter_port_listE { $$ = $1->addNextNull($2); } + ; udpFront: - yPRIMITIVE lifetimeE idAny - { $$ = new AstPrimitive($3, *$3); $$->inLibrary(true); - $$->lifetime($2); - $$->modTrace(false); - $$->addStmtp(new AstPragma($3, VPragmaType::INLINE_MODULE)); - GRAMMARP->m_tracingParse = false; - PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); } - ; + yPRIMITIVE lifetimeE idAny + { $$ = new AstPrimitive($3, *$3); $$->inLibrary(true); + $$->lifetime($2); + $$->modTrace(false); + $$->addStmtp(new AstPragma($3, VPragmaType::INLINE_MODULE)); + GRAMMARP->m_tracingParse = false; + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); } + ; -parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] - /* empty */ { $$ = nullptr; } - | parameter_value_assignment { $$ = $1; } - ; +parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] + /* empty */ { $$ = nullptr; } + | parameter_value_assignment { $$ = $1; } + ; -parameter_value_assignment: // IEEE: parameter_value_assignment - '#' '(' cellparamList ')' { $$ = $3; } - // // Parentheses are optional around a single parameter - | '#' yaINTNUM { $$ = new AstPin($2, 1, "", new AstConst($2, *$2)); } - | '#' yaFLOATNUM { $$ = new AstPin($2, 1, "", - new AstConst($2, AstConst::Unsized32(), - (int)(($2<0)?($2-0.5):($2+0.5)))); } - | '#' timeNumAdjusted { $$ = new AstPin($2, 1, "", $2); } - | '#' idClassSel { $$ = new AstPin($2, 1, "", $2); } - // // Not needed in Verilator: - // // Side effect of combining *_instantiations - // // '#' delay_value { UNSUP } - ; +parameter_value_assignment: // IEEE: parameter_value_assignment + '#' '(' cellparamList ')' { $$ = $3; } + // // Parentheses are optional around a single parameter + | '#' yaINTNUM { $$ = new AstPin($2, 1, "", new AstConst($2, *$2)); } + | '#' yaFLOATNUM { $$ = new AstPin($2, 1, "", + new AstConst($2, AstConst::Unsized32(), + (int)(($2<0)?($2-0.5):($2+0.5)))); } + | '#' timeNumAdjusted { $$ = new AstPin($2, 1, "", $2); } + | '#' idClassSel { $$ = new AstPin($2, 1, "", $2); } + // // Not needed in Verilator: + // // Side effect of combining *_instantiations + // // '#' delay_value { UNSUP } + ; -parameter_value_assignmentClass: // IEEE: [ parameter_value_assignment ] (for classes) - // // Like parameter_value_assignment, but for classes only, which always have #() - '#' '(' cellparamList ')' { $$ = $3; } - ; +parameter_value_assignmentClass: // IEEE: [ parameter_value_assignment ] (for classes) + // // Like parameter_value_assignment, but for classes only, which always have #() + '#' '(' cellparamList ')' { $$ = $3; } + ; -parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment - /* empty */ { $$ = nullptr; } - | '#' '(' ')' { $$ = nullptr; } - // // IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')' - // // IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')' - // // Can't just do that as "," conflicts with between vars and between stmts, so - // // split into pre-comma and post-comma parts - | '#' '(' {VARRESET_LIST(GPARAM);} paramPortDeclOrArgList ')' { $$ = $4; VARRESET_NONLIST(UNKNOWN); } - // // Note legal to start with "a=b" with no parameter statement - ; +parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment + /* empty */ { $$ = nullptr; } + | '#' '(' ')' { $$ = nullptr; } + // // IEEE: '#' '(' list_of_param_assignments { ',' parameter_port_declaration } ')' + // // IEEE: '#' '(' parameter_port_declaration { ',' parameter_port_declaration } ')' + // // Can't just do that as "," conflicts with between vars and between stmts, so + // // split into pre-comma and post-comma parts + | '#' '(' {VARRESET_LIST(GPARAM);} paramPortDeclOrArgList ')' { $$ = $4; VARRESET_NONLIST(UNKNOWN); } + // // Note legal to start with "a=b" with no parameter statement + ; -paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } - paramPortDeclOrArg { $$ = $1; } - | paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); } - ; +paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } + paramPortDeclOrArg { $$ = $1; } + | paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); } + ; -paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration - // // We combine the two as we can't tell which follows a comma - parameter_port_declarationFrontE param_assignment { $$ = $2; } - | parameter_port_declarationTypeFrontE type_assignment { $$ = $2; } - | vlTag { $$ = nullptr; } - ; +paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration + // // We combine the two as we can't tell which follows a comma + parameter_port_declarationFrontE param_assignment { $$ = $2; } + | parameter_port_declarationTypeFrontE type_assignment { $$ = $2; } + | vlTag { $$ = nullptr; } + ; -portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty - /* empty */ { $$ = nullptr; } - | '(' ')' { $$ = nullptr; } - // // .* expanded from module_declaration - //UNSUP '(' yP_DOTSTAR ')' { UNSUP } - | '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); } - ; +portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty + /* empty */ { $$ = nullptr; } + | '(' ')' { $$ = nullptr; } + // // .* expanded from module_declaration + //UNSUP '(' yP_DOTSTAR ')' { UNSUP } + | '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); } + ; -list_of_portsE: // IEEE: list_of_ports + list_of_port_declarations - portAndTagE { $$ = $1; } - | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } - ; +list_of_portsE: // IEEE: list_of_ports + list_of_port_declarations + portAndTagE { $$ = $1; } + | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } + ; -list_of_ports: // IEEE: list_of_ports + list_of_port_declarations - portAndTag { $$ = $1; } - | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } - ; +list_of_ports: // IEEE: list_of_ports + list_of_port_declarations + portAndTag { $$ = $1; } + | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } + ; portAndTagE: - /* empty */ - { int p = PINNUMINC(); - const string name = "__pinNumber" + cvtToStr(p); - $$ = new AstPort{CRELINE(), p, name}; - AstVar* varp = new AstVar{CRELINE(), VVarType::PORT, name, VFlagChildDType{}, - new AstBasicDType{CRELINE(), LOGIC_IMPLICIT}}; - varp->declDirection(VDirection::INPUT); - varp->direction(VDirection::INPUT); - varp->ansi(false); - varp->declTyped(true); - varp->trace(false); - $$ = $$->addNext(varp); - $$->v3warn(NULLPORT, "Null port on module (perhaps extraneous comma)"); } - | portAndTag { $$ = $1; } - ; + /* empty */ + { int p = PINNUMINC(); + const string name = "__pinNumber" + cvtToStr(p); + $$ = new AstPort{CRELINE(), p, name}; + AstVar* varp = new AstVar{CRELINE(), VVarType::PORT, name, VFlagChildDType{}, + new AstBasicDType{CRELINE(), LOGIC_IMPLICIT}}; + varp->declDirection(VDirection::INPUT); + varp->direction(VDirection::INPUT); + varp->ansi(false); + varp->declTyped(true); + varp->trace(false); + $$ = $$->addNext(varp); + $$->v3warn(NULLPORT, "Null port on module (perhaps extraneous comma)"); } + | portAndTag { $$ = $1; } + ; portAndTag: - port { $$ = $1; } - | vlTag port { $$ = $2; } // Tag will associate with previous port - ; + port { $$ = $1; } + | vlTag port { $$ = $2; } // Tag will associate with previous port + ; -port: // ==IEEE: port - // // SEE ALSO port_declaration, tf_port_declaration, - // // data_declarationVarFront - // - // // Though not type for interfaces, we factor out the port direction and type - // // so we can handle it in one place - // - // // IEEE: interface_port_header port_identifier { unpacked_dimension } - // // Expanded interface_port_header - // // We use instantCb here because the non-port form looks just like a module instantiation - portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE - { $$ = $3; VARDECL(IFACEREF); VARIO(NONE); - VARDTYPE(new AstIfaceRefDType($2,"",*$2)); - $$->addNextNull(VARDONEP($$,$4,$5)); } - | portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE - { $$ = $5; VARDECL(IFACEREF); VARIO(NONE); - VARDTYPE(new AstIfaceRefDType($2, $4, "", *$2, *$4)); - $$->addNextNull(VARDONEP($$,$6,$7)); } - | portDirNetE yINTERFACE portSig rangeListE sigAttrListE - { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } - | portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE - { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } - // - // // IEEE: ansi_port_declaration, with [port_direction] removed - // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ] - // // IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')' - // // IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ] - // // Substitute net_port_header = [ port_direction ] net_port_type - // // Substitute variable_port_header = [ port_direction ] variable_port_type - // // Substitute net_port_type = [ net_type ] data_type_or_implicit - // // Substitute variable_port_type = var_data_type - // // Substitute var_data_type = data_type | yVAR data_type_or_implicit - // // [ [ port_direction ] net_port_type | interface_port_header ] port_identifier { unpacked_dimension } - // // [ [ port_direction ] var_data_type ] port_identifier variable_dimensionListE [ '=' constant_expression ] - // // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')' - // - // // Remove optional '[...] id' is in portAssignment - // // Remove optional '[port_direction]' is in port - // // net_port_type | interface_port_header port_identifier { unpacked_dimension } - // // net_port_type | interface_port_header port_identifier { unpacked_dimension } - // // var_data_type port_identifier variable_dimensionListE [ '=' constExpr ] - // // net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')' - // // Expand implicit_type - // - // // variable_dimensionListE instead of rangeListE to avoid conflicts - // - // // Note implicit rules looks just line declaring additional followon port - // // No VARDECL("port") for implicit, as we don't want to declare variables for them - //UNSUP portDirNetE data_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE yVAR data_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - // - | portDirNetE data_type portSig variable_dimensionListE sigAttrListE - { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } - | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } - | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } - | portDirNetE signing portSig variable_dimensionListE sigAttrListE - { $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); $$->addNextNull(VARDONEP($$,$4,$5)); } - | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); } - | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE - { $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } - // - | portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$3; VARDTYPE($2); if (AstVar* vp = VARDONEP($$, $4, $5)) { $$->addNextNull(vp); vp->valuep($7); } } - | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } - | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } - | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$2; /*VARDTYPE-same*/ if (AstVar* vp = VARDONEP($$, $3, $4)) { $$->addNextNull(vp); vp->valuep($6); } } - ; +port: // ==IEEE: port + // // SEE ALSO port_declaration, tf_port_declaration, + // // data_declarationVarFront + // + // // Though not type for interfaces, we factor out the port direction and type + // // so we can handle it in one place + // + // // IEEE: interface_port_header port_identifier { unpacked_dimension } + // // Expanded interface_port_header + // // We use instantCb here because the non-port form looks just like a module instantiation + portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE + { $$ = $3; VARDECL(IFACEREF); VARIO(NONE); + VARDTYPE(new AstIfaceRefDType($2,"",*$2)); + $$->addNextNull(VARDONEP($$,$4,$5)); } + | portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE + { $$ = $5; VARDECL(IFACEREF); VARIO(NONE); + VARDTYPE(new AstIfaceRefDType($2, $4, "", *$2, *$4)); + $$->addNextNull(VARDONEP($$,$6,$7)); } + | portDirNetE yINTERFACE portSig rangeListE sigAttrListE + { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } + | portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE + { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } + // + // // IEEE: ansi_port_declaration, with [port_direction] removed + // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ] + // // IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')' + // // IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ] + // // Substitute net_port_header = [ port_direction ] net_port_type + // // Substitute variable_port_header = [ port_direction ] variable_port_type + // // Substitute net_port_type = [ net_type ] data_type_or_implicit + // // Substitute variable_port_type = var_data_type + // // Substitute var_data_type = data_type | yVAR data_type_or_implicit + // // [ [ port_direction ] net_port_type | interface_port_header ] port_identifier { unpacked_dimension } + // // [ [ port_direction ] var_data_type ] port_identifier variable_dimensionListE [ '=' constant_expression ] + // // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')' + // + // // Remove optional '[...] id' is in portAssignment + // // Remove optional '[port_direction]' is in port + // // net_port_type | interface_port_header port_identifier { unpacked_dimension } + // // net_port_type | interface_port_header port_identifier { unpacked_dimension } + // // var_data_type port_identifier variable_dimensionListE [ '=' constExpr ] + // // net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')' + // // Expand implicit_type + // + // // variable_dimensionListE instead of rangeListE to avoid conflicts + // + // // Note implicit rules looks just line declaring additional followon port + // // No VARDECL("port") for implicit, as we don't want to declare variables for them + //UNSUP portDirNetE data_type '.' portSig '(' portAssignExprE ')' sigAttrListE + //UNSUP { UNSUP } + //UNSUP portDirNetE yVAR data_type '.' portSig '(' portAssignExprE ')' sigAttrListE + //UNSUP { UNSUP } + //UNSUP portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE + //UNSUP { UNSUP } + //UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE + //UNSUP { UNSUP } + //UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE + //UNSUP { UNSUP } + // + | portDirNetE data_type portSig variable_dimensionListE sigAttrListE + { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } + | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE + { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } + | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE + { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } + | portDirNetE signing portSig variable_dimensionListE sigAttrListE + { $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); $$->addNextNull(VARDONEP($$,$4,$5)); } + | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE + { $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); } + | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE + { $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } + // + | portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr + { $$=$3; VARDTYPE($2); if (AstVar* vp = VARDONEP($$, $4, $5)) { $$->addNextNull(vp); vp->valuep($7); } } + | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr + { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } + | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr + { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } + | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr + { $$=$2; /*VARDTYPE-same*/ if (AstVar* vp = VARDONEP($$, $3, $4)) { $$->addNextNull(vp); vp->valuep($6); } } + ; -portDirNetE: // IEEE: part of port, optional net type and/or direction - /* empty */ { } - // // Per spec, if direction given default the nettype. - // // The higher level rule may override this VARDTYPE with one later in the parse. - | port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr); } - | port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL - | net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL - ; +portDirNetE: // IEEE: part of port, optional net type and/or direction + /* empty */ { } + // // Per spec, if direction given default the nettype. + // // The higher level rule may override this VARDTYPE with one later in the parse. + | port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr); } + | port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL + | net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL + ; -port_declNetE: // IEEE: part of port_declaration, optional net type - /* empty */ { } - | net_type { } // net_type calls VARDECL - ; +port_declNetE: // IEEE: part of port_declaration, optional net type + /* empty */ { } + | net_type { } // net_type calls VARDECL + ; portSig: - id/*port*/ { $$ = new AstPort($1,PINNUMINC(),*$1); } - | idSVKwd { $$ = new AstPort($1,PINNUMINC(),*$1); } - ; + id/*port*/ { $$ = new AstPort($1,PINNUMINC(),*$1); } + | idSVKwd { $$ = new AstPort($1,PINNUMINC(),*$1); } + ; //********************************************************************** // Interface headers -interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header: - // // timeunits_delcarationE is instead in interface_item - intFront importsAndParametersE portsStarE ';' - interface_itemListE yENDINTERFACE endLabelE - { if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); - SYMP->popScope($1); } - | yEXTERN intFront parameter_port_listE portsStarE ';' - { BBUNSUP($1, "Unsupported: extern interface"); } - ; +interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header: + // // timeunits_delcarationE is instead in interface_item + intFront importsAndParametersE portsStarE ';' + interface_itemListE yENDINTERFACE endLabelE + { if ($2) $1->addStmtp($2); + if ($3) $1->addStmtp($3); + if ($5) $1->addStmtp($5); + SYMP->popScope($1); } + | yEXTERN intFront parameter_port_listE portsStarE ';' + { BBUNSUP($1, "Unsupported: extern interface"); } + ; intFront: - yINTERFACE lifetimeE idAny/*new_interface*/ - { $$ = new AstIface($3, *$3); - $$->inLibrary(true); - $$->lifetime($2); - PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); } - ; + yINTERFACE lifetimeE idAny/*new_interface*/ + { $$ = new AstIface($3, *$3); + $$->inLibrary(true); + $$->lifetime($2); + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); } + ; interface_itemListE: - /* empty */ { $$ = nullptr; } - | interface_itemList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | interface_itemList { $$ = $1; } + ; interface_itemList: - interface_item { $$ = $1; } - | interface_itemList interface_item { $$ = $1->addNextNull($2); } - ; + interface_item { $$ = $1; } + | interface_itemList interface_item { $$ = $1->addNextNull($2); } + ; -interface_item: // IEEE: interface_item + non_port_interface_item - port_declaration ';' { $$ = $1; } - // // IEEE: non_port_interface_item - // // IEEE: generate_region - | interface_generate_region { $$ = $1; } - | interface_or_generate_item { $$ = $1; } - | program_declaration - { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: program decls within interface decls"); } - // // IEEE 1800-2017: modport_item - // // See instead old 2012 position in interface_or_generate_item - | interface_declaration - { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: interface decls within interface decls"); } - | timeunits_declaration { $$ = $1; } - // // See note in interface_or_generate item - | module_common_item { $$ = $1; } - ; +interface_item: // IEEE: interface_item + non_port_interface_item + port_declaration ';' { $$ = $1; } + // // IEEE: non_port_interface_item + // // IEEE: generate_region + | interface_generate_region { $$ = $1; } + | interface_or_generate_item { $$ = $1; } + | program_declaration + { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: program decls within interface decls"); } + // // IEEE 1800-2017: modport_item + // // See instead old 2012 position in interface_or_generate_item + | interface_declaration + { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: interface decls within interface decls"); } + | timeunits_declaration { $$ = $1; } + // // See note in interface_or_generate item + | module_common_item { $$ = $1; } + ; -interface_generate_region: // ==IEEE: generate_region - yGENERATE interface_itemList yENDGENERATE { $$ = $2; } - | yGENERATE yENDGENERATE { $$ = nullptr; } - ; +interface_generate_region: // ==IEEE: generate_region + yGENERATE interface_itemList yENDGENERATE { $$ = $2; } + | yGENERATE yENDGENERATE { $$ = nullptr; } + ; interface_or_generate_item: // ==IEEE: interface_or_generate_item - // // module_common_item in interface_item, as otherwise duplicated - // // with module_or_generate_item's module_common_item - modport_declaration { $$ = $1; } - | extern_tf_declaration { $$ = $1; } - ; + // // module_common_item in interface_item, as otherwise duplicated + // // with module_or_generate_item's module_common_item + modport_declaration { $$ = $1; } + | extern_tf_declaration { $$ = $1; } + ; //********************************************************************** // Program headers -anonymous_program: // ==IEEE: anonymous_program - // // See the spec - this doesn't change the scope, items still go up "top" - yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM - { $$ = nullptr; BBUNSUP($1, "Unsupported: Anonymous programs"); } - ; +anonymous_program: // ==IEEE: anonymous_program + // // See the spec - this doesn't change the scope, items still go up "top" + yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM + { $$ = nullptr; BBUNSUP($1, "Unsupported: Anonymous programs"); } + ; -anonymous_program_itemListE: // IEEE: { anonymous_program_item } - /* empty */ { $$ = nullptr; } - | anonymous_program_itemList { $$ = $1; } - ; +anonymous_program_itemListE: // IEEE: { anonymous_program_item } + /* empty */ { $$ = nullptr; } + | anonymous_program_itemList { $$ = $1; } + ; -anonymous_program_itemList: // IEEE: { anonymous_program_item } - anonymous_program_item { $$ = $1; } - | anonymous_program_itemList anonymous_program_item { $$ = $1->addNextNull($2); } - ; +anonymous_program_itemList: // IEEE: { anonymous_program_item } + anonymous_program_item { $$ = $1; } + | anonymous_program_itemList anonymous_program_item { $$ = $1->addNextNull($2); } + ; -anonymous_program_item: // ==IEEE: anonymous_program_item - task_declaration { $$ = $1; } - | function_declaration { $$ = $1; } - | class_declaration { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } - // // class_constructor_declaration is part of function_declaration - | ';' { $$ = nullptr; } - ; +anonymous_program_item: // ==IEEE: anonymous_program_item + task_declaration { $$ = $1; } + | function_declaration { $$ = $1; } + | class_declaration { $$ = $1; } + //UNSUP covergroup_declaration { $$ = $1; } + // // class_constructor_declaration is part of function_declaration + | ';' { $$ = nullptr; } + ; -program_declaration: // IEEE: program_declaration + program_nonansi_header + program_ansi_header: - // // timeunits_delcarationE is instead in program_item - pgmFront parameter_port_listE portsStarE ';' - /*cont*/ program_itemListE yENDPROGRAM endLabelE - { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); - GRAMMARP->m_modp = nullptr; - SYMP->popScope($1); - GRAMMARP->endLabel($7,$1,$7); } - | yEXTERN pgmFront parameter_port_listE portsStarE ';' - { BBUNSUP($1, "Unsupported: extern program"); - SYMP->popScope($2); } - ; +program_declaration: // IEEE: program_declaration + program_nonansi_header + program_ansi_header: + // // timeunits_delcarationE is instead in program_item + pgmFront parameter_port_listE portsStarE ';' + /*cont*/ program_itemListE yENDPROGRAM endLabelE + { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc + if ($2) $1->addStmtp($2); + if ($3) $1->addStmtp($3); + if ($5) $1->addStmtp($5); + GRAMMARP->m_modp = nullptr; + SYMP->popScope($1); + GRAMMARP->endLabel($7,$1,$7); } + | yEXTERN pgmFront parameter_port_listE portsStarE ';' + { BBUNSUP($1, "Unsupported: extern program"); + SYMP->popScope($2); } + ; pgmFront: - yPROGRAM lifetimeE idAny/*new_program*/ - { $$ = new AstModule($3, *$3, true); - $$->lifetime($2); - $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); - $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); - $$->timeunit(PARSEP->timeLastUnit()); - PARSEP->rootp()->addModulep($$); - SYMP->pushNew($$); - GRAMMARP->m_modp = $$; } - ; + yPROGRAM lifetimeE idAny/*new_program*/ + { $$ = new AstModule($3, *$3, true); + $$->lifetime($2); + $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); + $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->addModulep($$); + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } + ; -program_itemListE: // ==IEEE: [{ program_item }] - /* empty */ { $$ = nullptr; } - | program_itemList { $$ = $1; } - ; +program_itemListE: // ==IEEE: [{ program_item }] + /* empty */ { $$ = nullptr; } + | program_itemList { $$ = $1; } + ; -program_itemList: // ==IEEE: { program_item } - program_item { $$ = $1; } - | program_itemList program_item { $$ = $1->addNextNull($2); } - ; +program_itemList: // ==IEEE: { program_item } + program_item { $$ = $1; } + | program_itemList program_item { $$ = $1->addNextNull($2); } + ; -program_item: // ==IEEE: program_item - port_declaration ';' { $$ = $1; } - | non_port_program_item { $$ = $1; } - ; +program_item: // ==IEEE: program_item + port_declaration ';' { $$ = $1; } + | non_port_program_item { $$ = $1; } + ; -non_port_program_item: // ==IEEE: non_port_program_item - continuous_assign { $$ = $1; } - | module_or_generate_item_declaration { $$ = $1; } - | initial_construct { $$ = $1; } - | final_construct { $$ = $1; } - | concurrent_assertion_item { $$ = $1; } - | timeunits_declaration { $$ = $1; } - | program_generate_item { $$ = $1; } - ; +non_port_program_item: // ==IEEE: non_port_program_item + continuous_assign { $$ = $1; } + | module_or_generate_item_declaration { $$ = $1; } + | initial_construct { $$ = $1; } + | final_construct { $$ = $1; } + | concurrent_assertion_item { $$ = $1; } + | timeunits_declaration { $$ = $1; } + | program_generate_item { $$ = $1; } + ; -program_generate_item: // ==IEEE: program_generate_item - loop_generate_construct { $$ = $1; } - | conditional_generate_construct { $$ = $1; } - | generate_region { $$ = $1; } - | elaboration_system_task { $$ = $1; } - ; +program_generate_item: // ==IEEE: program_generate_item + loop_generate_construct { $$ = $1; } + | conditional_generate_construct { $$ = $1; } + | generate_region { $$ = $1; } + | elaboration_system_task { $$ = $1; } + ; -extern_tf_declaration: // ==IEEE: extern_tf_declaration - yEXTERN task_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern task"); } - | yEXTERN function_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern function"); } - | yEXTERN yFORKJOIN task_prototype ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern forkjoin"); } - ; +extern_tf_declaration: // ==IEEE: extern_tf_declaration + yEXTERN task_prototype ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern task"); } + | yEXTERN function_prototype ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern function"); } + | yEXTERN yFORKJOIN task_prototype ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern forkjoin"); } + ; -modport_declaration: // ==IEEE: modport_declaration - yMODPORT modport_itemList ';' { $$ = $2; } - ; +modport_declaration: // ==IEEE: modport_declaration + yMODPORT modport_itemList ';' { $$ = $2; } + ; -modport_itemList: // IEEE: part of modport_declaration - modport_item { $$ = $1; } - | modport_itemList ',' modport_item { $$ = $1->addNextNull($3); } - ; +modport_itemList: // IEEE: part of modport_declaration + modport_item { $$ = $1; } + | modport_itemList ',' modport_item { $$ = $1->addNextNull($3); } + ; -modport_item: // ==IEEE: modport_item - id/*new-modport*/ '(' - /*mid*/ { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } - /*cont*/ modportPortsDeclList ')' { $$ = new AstModport($1, *$1, $4); } - ; +modport_item: // ==IEEE: modport_item + id/*new-modport*/ '(' + /*mid*/ { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } + /*cont*/ modportPortsDeclList ')' { $$ = new AstModport($1, *$1, $4); } + ; modportPortsDeclList: - modportPortsDecl { $$ = $1; } - | modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); } - ; + modportPortsDecl { $$ = $1; } + | modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); } + ; // IEEE: modport_ports_declaration + modport_simple_ports_declaration -// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration +// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration // We've expanded the lists each take to instead just have standalone ID ports. // We track the type as with the V2k series of defines, then create as each ID is seen. modportPortsDecl: - // // IEEE: modport_simple_ports_declaration - port_direction modportSimplePort { $$ = new AstModportVarRef($2, *$2, GRAMMARP->m_varIO); } - // // IEEE: modport_clocking_declaration - | yCLOCKING idAny/*clocking_identifier*/ - { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport clocking"); } - // // IEEE: yIMPORT modport_tf_port - // // IEEE: yEXPORT modport_tf_port - // // modport_tf_port expanded here - | yIMPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($2, *$2, false); } - | yEXPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($2, *$2, true); } - | yIMPORT method_prototype - { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport import with prototype"); } - | yEXPORT method_prototype - { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport export with prototype"); } - // Continuations of above after a comma. - // // IEEE: modport_simple_ports_declaration - | modportSimplePort { $$ = new AstModportVarRef($1,*$1,GRAMMARP->m_varIO); } - ; + // // IEEE: modport_simple_ports_declaration + port_direction modportSimplePort { $$ = new AstModportVarRef($2, *$2, GRAMMARP->m_varIO); } + // // IEEE: modport_clocking_declaration + | yCLOCKING idAny/*clocking_identifier*/ + { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport clocking"); } + // // IEEE: yIMPORT modport_tf_port + // // IEEE: yEXPORT modport_tf_port + // // modport_tf_port expanded here + | yIMPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($2, *$2, false); } + | yEXPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($2, *$2, true); } + | yIMPORT method_prototype + { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport import with prototype"); } + | yEXPORT method_prototype + { $$ = nullptr; BBUNSUP($1, "Unsupported: Modport export with prototype"); } + // Continuations of above after a comma. + // // IEEE: modport_simple_ports_declaration + | modportSimplePort { $$ = new AstModportVarRef($1,*$1,GRAMMARP->m_varIO); } + ; -modportSimplePort: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier - id { $$ = $1; } - //UNSUP '.' idAny '(' ')' { } - //UNSUP '.' idAny '(' expr ')' { } - ; +modportSimplePort: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier + id { $$ = $1; } + //UNSUP '.' idAny '(' ')' { } + //UNSUP '.' idAny '(' expr ')' { } + ; //************************************************ // Variable Declarations -genvar_declaration: // ==IEEE: genvar_declaration - yGENVAR list_of_genvar_identifiers ';' { $$ = $2; } - ; +genvar_declaration: // ==IEEE: genvar_declaration + yGENVAR list_of_genvar_identifiers ';' { $$ = $2; } + ; -list_of_genvar_identifiers: // IEEE: list_of_genvar_identifiers (for declaration) - genvar_identifierDecl { $$ = $1; } - | list_of_genvar_identifiers ',' genvar_identifierDecl { $$ = $1->addNext($3); } - ; +list_of_genvar_identifiers: // IEEE: list_of_genvar_identifiers (for declaration) + genvar_identifierDecl { $$ = $1; } + | list_of_genvar_identifiers ',' genvar_identifierDecl { $$ = $1->addNext($3); } + ; -genvar_identifierDecl: // IEEE: genvar_identifier (for declaration) - id/*new-genvar_identifier*/ sigAttrListE - { VARRESET_NONLIST(GENVAR); - VARDTYPE(new AstBasicDType($1, VBasicDTypeKwd::INTEGER)); - $$ = VARDONEA($1, *$1, nullptr, $2); } - ; +genvar_identifierDecl: // IEEE: genvar_identifier (for declaration) + id/*new-genvar_identifier*/ sigAttrListE + { VARRESET_NONLIST(GENVAR); + VARDTYPE(new AstBasicDType($1, VBasicDTypeKwd::INTEGER)); + $$ = VARDONEA($1, *$1, nullptr, $2); } + ; -parameter_declaration: // IEEE: local_ or parameter_declaration - // // IEEE: yPARAMETER yTYPE list_of_type_assignments ';' - // // Instead of list_of_type_assignments - // // we use list_of_param_assignments because for port handling - // // it already must accept types, so simpler to have code only one place - // // Front must execute first so VARDTYPE is ready before list of vars - parameter_declarationFront list_of_param_assignments { $$ = $2; } - | parameter_declarationTypeFront list_of_type_assignments { $$ = $2; } - ; +parameter_declaration: // IEEE: local_ or parameter_declaration + // // IEEE: yPARAMETER yTYPE list_of_type_assignments ';' + // // Instead of list_of_type_assignments + // // we use list_of_param_assignments because for port handling + // // it already must accept types, so simpler to have code only one place + // // Front must execute first so VARDTYPE is ready before list of vars + parameter_declarationFront list_of_param_assignments { $$ = $2; } + | parameter_declarationTypeFront list_of_type_assignments { $$ = $2; } + ; -parameter_declarationFront: // IEEE: local_ or parameter_declaration w/o assignment - // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($2); } - | varParamReset data_type { /*VARRESET-in-varParam*/ VARDTYPE($2); } - ; +parameter_declarationFront: // IEEE: local_ or parameter_declaration w/o assignment + // // Front must execute first so VARDTYPE is ready before list of vars + varParamReset implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($2); } + | varParamReset data_type { /*VARRESET-in-varParam*/ VARDTYPE($2); } + ; -parameter_declarationTypeFront: // IEEE: local_ or parameter_declaration w/o assignment - // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($2)); } - ; +parameter_declarationTypeFront: // IEEE: local_ or parameter_declaration w/o assignment + // // Front must execute first so VARDTYPE is ready before list of vars + varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($2)); } + ; parameter_port_declarationFrontE: // IEEE: local_ or parameter_port_declaration w/o assignment - // // IEEE: parameter_declaration (minus assignment) - // // IEEE: local_parameter_declaration (minus assignment) - // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($2); } - | varParamReset data_type { /*VARRESET-in-varParam*/ VARDTYPE($2); } - | implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($1); } - | data_type { /*VARRESET-in-varParam*/ VARDTYPE($1); } - ; + // // IEEE: parameter_declaration (minus assignment) + // // IEEE: local_parameter_declaration (minus assignment) + // // Front must execute first so VARDTYPE is ready before list of vars + varParamReset implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($2); } + | varParamReset data_type { /*VARRESET-in-varParam*/ VARDTYPE($2); } + | implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($1); } + | data_type { /*VARRESET-in-varParam*/ VARDTYPE($1); } + ; parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o assignment - // // IEEE: parameter_declaration (minus assignment) - // // IEEE: local_parameter_declaration (minus assignment) - // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($2)); } - | yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($1)); } - ; + // // IEEE: parameter_declaration (minus assignment) + // // IEEE: local_parameter_declaration (minus assignment) + // // Front must execute first so VARDTYPE is ready before list of vars + varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($2)); } + | yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType($1)); } + ; -net_declaration: // IEEE: net_declaration - excluding implict - net_declarationFront netSigList ';' { $$ = $2; } - ; +net_declaration: // IEEE: net_declaration - excluding implict + net_declarationFront netSigList ';' { $$ = $2; } + ; -net_declarationFront: // IEEE: beginning of net_declaration - net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); } - //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } - ; +net_declarationFront: // IEEE: beginning of net_declaration + net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); } + //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } + ; net_declRESET: - /* empty */ { VARRESET_NONLIST(UNKNOWN); } - ; + /* empty */ { VARRESET_NONLIST(UNKNOWN); } + ; net_scalaredE: - /* empty */ { } - // //UNSUP: ySCALARED/yVECTORED ignored - | ySCALARED { } - | yVECTORED { } - ; + /* empty */ { } + // //UNSUP: ySCALARED/yVECTORED ignored + | ySCALARED { } + | yVECTORED { } + ; net_dataTypeE: - // // If there's a SV data type there shouldn't be a delay on this wire - // // Otherwise #(...) can't be determined to be a delay or parameters - // // Submit this as a footnote to the committee - var_data_type { $$ = $1; } - | signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); } // not implicit - | signing { $$ = new AstBasicDType($1, LOGIC, $1); } // not implicit - | /*implicit*/ delayE { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit - ; + // // If there's a SV data type there shouldn't be a delay on this wire + // // Otherwise #(...) can't be determined to be a delay or parameters + // // Submit this as a footnote to the committee + var_data_type { $$ = $1; } + | signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); } // not implicit + | signing { $$ = new AstBasicDType($1, LOGIC, $1); } // not implicit + | /*implicit*/ delayE { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit + ; -net_type: // ==IEEE: net_type - ySUPPLY0 { VARDECL(SUPPLY0); } - | ySUPPLY1 { VARDECL(SUPPLY1); } - | yTRI { VARDECL(TRIWIRE); } - | yTRI0 { VARDECL(TRI0); } - | yTRI1 { VARDECL(TRI1); } - | yTRIAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: triand"); } - | yTRIOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trior"); } - | yTRIREG { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trireg"); } - | yWAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wand"); } - | yWIRE { VARDECL(WIRE); } - | yWOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wor"); } - // // VAMS - somewhat hackish - | yWREAL { VARDECL(WREAL); } - ; +net_type: // ==IEEE: net_type + ySUPPLY0 { VARDECL(SUPPLY0); } + | ySUPPLY1 { VARDECL(SUPPLY1); } + | yTRI { VARDECL(TRIWIRE); } + | yTRI0 { VARDECL(TRI0); } + | yTRI1 { VARDECL(TRI1); } + | yTRIAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: triand"); } + | yTRIOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trior"); } + | yTRIREG { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trireg"); } + | yWAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wand"); } + | yWIRE { VARDECL(WIRE); } + | yWOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wor"); } + // // VAMS - somewhat hackish + | yWREAL { VARDECL(WREAL); } + ; varParamReset: - yPARAMETER { VARRESET_NONLIST(GPARAM); } - | yLOCALPARAM { VARRESET_NONLIST(LPARAM); } - ; + yPARAMETER { VARRESET_NONLIST(GPARAM); } + | yLOCALPARAM { VARRESET_NONLIST(LPARAM); } + ; -port_direction: // ==IEEE: port_direction + tf_port_direction - // // IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here - // // Only used for ANSI declarations - yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } - | yOUTPUT { GRAMMARP->m_pinAnsi = true; VARIO(OUTPUT); } - | yINOUT { GRAMMARP->m_pinAnsi = true; VARIO(INOUT); } - | yREF { GRAMMARP->m_pinAnsi = true; VARIO(REF); } - | yCONST__REF yREF { GRAMMARP->m_pinAnsi = true; VARIO(CONSTREF); } - ; +port_direction: // ==IEEE: port_direction + tf_port_direction + // // IEEE 19.8 just "input" FIRST forces type to wire - we'll ignore that here + // // Only used for ANSI declarations + yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + | yOUTPUT { GRAMMARP->m_pinAnsi = true; VARIO(OUTPUT); } + | yINOUT { GRAMMARP->m_pinAnsi = true; VARIO(INOUT); } + | yREF { GRAMMARP->m_pinAnsi = true; VARIO(REF); } + | yCONST__REF yREF { GRAMMARP->m_pinAnsi = true; VARIO(CONSTREF); } + ; -port_directionReset: // IEEE: port_direction that starts a port_declaraiton - // // Used only for declarations outside the port list - yINPUT { VARRESET_NONLIST(UNKNOWN); VARIO(INPUT); } - | yOUTPUT { VARRESET_NONLIST(UNKNOWN); VARIO(OUTPUT); } - | yINOUT { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } - | yREF { VARRESET_NONLIST(UNKNOWN); VARIO(REF); } - | yCONST__REF yREF { VARRESET_NONLIST(UNKNOWN); VARIO(CONSTREF); } - ; +port_directionReset: // IEEE: port_direction that starts a port_declaraiton + // // Used only for declarations outside the port list + yINPUT { VARRESET_NONLIST(UNKNOWN); VARIO(INPUT); } + | yOUTPUT { VARRESET_NONLIST(UNKNOWN); VARIO(OUTPUT); } + | yINOUT { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } + | yREF { VARRESET_NONLIST(UNKNOWN); VARIO(REF); } + | yCONST__REF yREF { VARRESET_NONLIST(UNKNOWN); VARIO(CONSTREF); } + ; -port_declaration: // ==IEEE: port_declaration - // // Non-ANSI; used inside block followed by ';' - // // SEE ALSO port, tf_port_declaration, data_declarationVarFront - // - // // IEEE: inout_declaration - // // IEEE: input_declaration - // // IEEE: output_declaration - // // IEEE: ref_declaration - port_directionReset port_declNetE data_type - /*mid*/ { VARDTYPE($3); } - /*cont*/ list_of_variable_decl_assignments { $$ = $5; } - | port_directionReset port_declNetE yVAR data_type - /*mid*/ { VARDTYPE($4); } - /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE yVAR implicit_typeE - /*mid*/ { VARDTYPE($4); } - /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signingE rangeList - /*mid*/ { VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3), $4, true)); } - /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signing - /*mid*/ { VARDTYPE_NDECL(new AstBasicDType($3, LOGIC_IMPLICIT, $3)); } - /*cont*/ list_of_variable_decl_assignments { $$ = $5; } - | port_directionReset port_declNetE /*implicit*/ - /*mid*/ { VARDTYPE_NDECL(nullptr); /*default_nettype*/ } - /*cont*/ list_of_variable_decl_assignments { $$ = $4; } - // // IEEE: interface_declaration - // // Looks just like variable declaration unless has a period - // // See etcInst - ; +port_declaration: // ==IEEE: port_declaration + // // Non-ANSI; used inside block followed by ';' + // // SEE ALSO port, tf_port_declaration, data_declarationVarFront + // + // // IEEE: inout_declaration + // // IEEE: input_declaration + // // IEEE: output_declaration + // // IEEE: ref_declaration + port_directionReset port_declNetE data_type + /*mid*/ { VARDTYPE($3); } + /*cont*/ list_of_variable_decl_assignments { $$ = $5; } + | port_directionReset port_declNetE yVAR data_type + /*mid*/ { VARDTYPE($4); } + /*cont*/ list_of_variable_decl_assignments { $$ = $6; } + | port_directionReset port_declNetE yVAR implicit_typeE + /*mid*/ { VARDTYPE($4); } + /*cont*/ list_of_variable_decl_assignments { $$ = $6; } + | port_directionReset port_declNetE signingE rangeList + /*mid*/ { VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3), $4, true)); } + /*cont*/ list_of_variable_decl_assignments { $$ = $6; } + | port_directionReset port_declNetE signing + /*mid*/ { VARDTYPE_NDECL(new AstBasicDType($3, LOGIC_IMPLICIT, $3)); } + /*cont*/ list_of_variable_decl_assignments { $$ = $5; } + | port_directionReset port_declNetE /*implicit*/ + /*mid*/ { VARDTYPE_NDECL(nullptr); /*default_nettype*/ } + /*cont*/ list_of_variable_decl_assignments { $$ = $4; } + // // IEEE: interface_declaration + // // Looks just like variable declaration unless has a period + // // See etcInst + ; -tf_port_declaration: // ==IEEE: tf_port_declaration - // // Used inside function; followed by ';' - // // SEE ALSO port_declaration, port, data_declarationVarFront - // - port_directionReset data_type { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } - | port_directionReset implicit_typeE { VARDTYPE_NDECL($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } - | port_directionReset yVAR data_type { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } - | port_directionReset yVAR implicit_typeE { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } - ; +tf_port_declaration: // ==IEEE: tf_port_declaration + // // Used inside function; followed by ';' + // // SEE ALSO port_declaration, port, data_declarationVarFront + // + port_directionReset data_type { VARDTYPE($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } + | port_directionReset implicit_typeE { VARDTYPE_NDECL($2); } list_of_tf_variable_identifiers ';' { $$ = $4; } + | port_directionReset yVAR data_type { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } + | port_directionReset yVAR implicit_typeE { VARDTYPE($3); } list_of_tf_variable_identifiers ';' { $$ = $5; } + ; -integer_atom_type: // ==IEEE: integer_atom_type - yBYTE { $$ = new AstBasicDType($1,VBasicDTypeKwd::BYTE); } - | ySHORTINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::SHORTINT); } - | yINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::INT); } - | yLONGINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::LONGINT); } - | yINTEGER { $$ = new AstBasicDType($1,VBasicDTypeKwd::INTEGER); } - | yTIME { $$ = new AstBasicDType($1,VBasicDTypeKwd::TIME); } - ; +integer_atom_type: // ==IEEE: integer_atom_type + yBYTE { $$ = new AstBasicDType($1,VBasicDTypeKwd::BYTE); } + | ySHORTINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::SHORTINT); } + | yINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::INT); } + | yLONGINT { $$ = new AstBasicDType($1,VBasicDTypeKwd::LONGINT); } + | yINTEGER { $$ = new AstBasicDType($1,VBasicDTypeKwd::INTEGER); } + | yTIME { $$ = new AstBasicDType($1,VBasicDTypeKwd::TIME); } + ; -integer_vector_type: // ==IEEE: integer_atom_type - yBIT { $$ = new AstBasicDType($1,VBasicDTypeKwd::BIT); } - | yLOGIC { $$ = new AstBasicDType($1,VBasicDTypeKwd::LOGIC); } - | yREG { $$ = new AstBasicDType($1,VBasicDTypeKwd::LOGIC); } // logic==reg - ; +integer_vector_type: // ==IEEE: integer_atom_type + yBIT { $$ = new AstBasicDType($1,VBasicDTypeKwd::BIT); } + | yLOGIC { $$ = new AstBasicDType($1,VBasicDTypeKwd::LOGIC); } + | yREG { $$ = new AstBasicDType($1,VBasicDTypeKwd::LOGIC); } // logic==reg + ; -non_integer_type: // ==IEEE: non_integer_type - yREAL { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); } - | yREALTIME { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); } - | ySHORTREAL { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); UNSUPREAL($1); } - ; +non_integer_type: // ==IEEE: non_integer_type + yREAL { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); } + | yREALTIME { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); } + | ySHORTREAL { $$ = new AstBasicDType($1,VBasicDTypeKwd::DOUBLE); UNSUPREAL($1); } + ; -signingE: // IEEE: signing - plus empty - /*empty*/ { $$ = VSigning::NOSIGN; } - | signing { $$ = $1; } - ; +signingE: // IEEE: signing - plus empty + /*empty*/ { $$ = VSigning::NOSIGN; } + | signing { $$ = $1; } + ; -signing: // ==IEEE: signing - ySIGNED { $$ = $1; $$ = VSigning::SIGNED; } - | yUNSIGNED { $$ = $1; $$ = VSigning::UNSIGNED; } - ; +signing: // ==IEEE: signing + ySIGNED { $$ = $1; $$ = VSigning::SIGNED; } + | yUNSIGNED { $$ = $1; $$ = VSigning::UNSIGNED; } + ; //************************************************ // Data Types -simple_type: // ==IEEE: simple_type - // // IEEE: integer_type - integer_atom_type { $$ = $1; } - | integer_vector_type { $$ = $1; } - | non_integer_type { $$ = $1; } - // // IEEE: ps_type_identifier - // // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE) - // // Even though we looked up the type and have a AstNode* to it, - // // we can't fully resolve it because it may have been just a forward definition. - | packageClassScopeE idType - { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, nullptr}; - $$ = refp; } - // - // // { generate_block_identifer ... } '.' - // // Need to determine if generate_block_identifier can be lex-detected - ; +simple_type: // ==IEEE: simple_type + // // IEEE: integer_type + integer_atom_type { $$ = $1; } + | integer_vector_type { $$ = $1; } + | non_integer_type { $$ = $1; } + // // IEEE: ps_type_identifier + // // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE) + // // Even though we looked up the type and have a AstNode* to it, + // // we can't fully resolve it because it may have been just a forward definition. + | packageClassScopeE idType + { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, nullptr}; + $$ = refp; } + // + // // { generate_block_identifer ... } '.' + // // Need to determine if generate_block_identifier can be lex-detected + ; -data_type: // ==IEEE: data_type - // // This expansion also replicated elsewhere, IE data_type__AndID - data_typeNoRef { $$ = $1; } - // - // // REFERENCES - // - // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } - // // IEEE: class_type - // // IEEE: ps_covergroup_identifier - // // Don't distinguish between types and classes so all these combined - | packageClassScopeE idType packed_dimensionListE - { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, nullptr}; - $$ = GRAMMARP->createArray(refp, $3, true); } - | packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE - { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, $3}; - $$ = GRAMMARP->createArray(refp, $4, true); } - ; +data_type: // ==IEEE: data_type + // // This expansion also replicated elsewhere, IE data_type__AndID + data_typeNoRef { $$ = $1; } + // + // // REFERENCES + // + // // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension } + // // IEEE: class_type + // // IEEE: ps_covergroup_identifier + // // Don't distinguish between types and classes so all these combined + | packageClassScopeE idType packed_dimensionListE + { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, nullptr}; + $$ = GRAMMARP->createArray(refp, $3, true); } + | packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE + { AstRefDType* const refp = new AstRefDType{$2, *$2, $1, $3}; + $$ = GRAMMARP->createArray(refp, $4, true); } + ; -data_typeBasic: // IEEE: part of data_type - integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); } - | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } - | non_integer_type { $$ = $1; } - ; +data_typeBasic: // IEEE: part of data_type + integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); } + | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } + | non_integer_type { $$ = $1; } + ; -data_typeNoRef: // ==IEEE: data_type, excluding class_type etc references - data_typeBasic { $$ = $1; } - | struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->s_modTypeImpNum++), - SYMP,VFlagChildDType(),$1),$2,true); } - | enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->s_modTypeImpNum++), - SYMP,VFlagChildDType(),$1); } - | ySTRING { $$ = new AstBasicDType($1,VBasicDTypeKwd::STRING); } - | yCHANDLE { $$ = new AstBasicDType($1,VBasicDTypeKwd::CHANDLE); } - | yEVENT { $$ = new AstBasicDType($1,VBasicDTypeKwd::EVENTVALUE); } - // // Rules overlap virtual_interface_declaration - // // Parameters here are SV2009 - // // IEEE has ['.' modport] but that will conflict with port - // // declarations which decode '.' modport themselves, so - // // instead see data_typeVar - | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ - { $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; - BBUNSUP($1, "Unsupported: virtual interface"); } - | yVIRTUAL__anyID id/*interface*/ - { $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; - BBUNSUP($1, "Unsupported: virtual data type"); } - | type_reference { $$ = $1; } - // // IEEE: class_scope: see data_type above - // // IEEE: class_type: see data_type above - // // IEEE: ps_covergroup: see data_type above - ; +data_typeNoRef: // ==IEEE: data_type, excluding class_type etc references + data_typeBasic { $$ = $1; } + | struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->s_modTypeImpNum++), + SYMP,VFlagChildDType(),$1),$2,true); } + | enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->s_modTypeImpNum++), + SYMP,VFlagChildDType(),$1); } + | ySTRING { $$ = new AstBasicDType($1,VBasicDTypeKwd::STRING); } + | yCHANDLE { $$ = new AstBasicDType($1,VBasicDTypeKwd::CHANDLE); } + | yEVENT { $$ = new AstBasicDType($1,VBasicDTypeKwd::EVENTVALUE); } + // // Rules overlap virtual_interface_declaration + // // Parameters here are SV2009 + // // IEEE has ['.' modport] but that will conflict with port + // // declarations which decode '.' modport themselves, so + // // instead see data_typeVar + | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ + { $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; + BBUNSUP($1, "Unsupported: virtual interface"); } + | yVIRTUAL__anyID id/*interface*/ + { $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; + BBUNSUP($1, "Unsupported: virtual data type"); } + | type_reference { $$ = $1; } + // // IEEE: class_scope: see data_type above + // // IEEE: class_type: see data_type above + // // IEEE: ps_covergroup: see data_type above + ; -data_type_or_void: // ==IEEE: data_type_or_void - data_type { $$ = $1; } - //UNSUP yVOID { UNSUP } // No yTAGGED structures - ; +data_type_or_void: // ==IEEE: data_type_or_void + data_type { $$ = $1; } + //UNSUP yVOID { UNSUP } // No yTAGGED structures + ; -var_data_type: // ==IEEE: var_data_type - data_type { $$ = $1; } - | yVAR data_type { $$ = $2; } - | yVAR implicit_typeE { $$ = $2; } - ; +var_data_type: // ==IEEE: var_data_type + data_type { $$ = $1; } + | yVAR data_type { $$ = $2; } + | yVAR implicit_typeE { $$ = $2; } + ; -type_reference: // ==IEEE: type_reference - yTYPE '(' exprOrDataType ')' - { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } - ; +type_reference: // ==IEEE: type_reference + yTYPE '(' exprOrDataType ')' + { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } + ; -struct_unionDecl: // IEEE: part of data_type - // // packedSigningE is NOP for unpacked - ySTRUCT packedSigningE '{' - /*mid*/ { $$ = new AstStructDType($1, $2); SYMP->pushNew($$); } - /*cont*/ struct_union_memberList '}' - { $$ = $4; $$->addMembersp($5); SYMP->popScope($$); } - | yUNION taggedE packedSigningE '{' - /*mid*/ { $$ = new AstUnionDType($1, $3); SYMP->pushNew($$); } - /*cont*/ struct_union_memberList '}' - { $$ = $5; $$->addMembersp($6); SYMP->popScope($$); } - ; +struct_unionDecl: // IEEE: part of data_type + // // packedSigningE is NOP for unpacked + ySTRUCT packedSigningE '{' + /*mid*/ { $$ = new AstStructDType($1, $2); SYMP->pushNew($$); } + /*cont*/ struct_union_memberList '}' + { $$ = $4; $$->addMembersp($5); SYMP->popScope($$); } + | yUNION taggedE packedSigningE '{' + /*mid*/ { $$ = new AstUnionDType($1, $3); SYMP->pushNew($$); } + /*cont*/ struct_union_memberList '}' + { $$ = $5; $$->addMembersp($6); SYMP->popScope($$); } + ; -struct_union_memberList: // IEEE: { struct_union_member } - struct_union_member { $$ = $1; } - | struct_union_memberList struct_union_member { $$ = $1->addNextNull($2); } - ; +struct_union_memberList: // IEEE: { struct_union_member } + struct_union_member { $$ = $1; } + | struct_union_memberList struct_union_member { $$ = $1->addNextNull($2); } + ; -struct_union_member: // ==IEEE: struct_union_member - // // UNSUP random_qualifer not propagagted until have randomize support - random_qualifierE data_type_or_void - /*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. - /*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = nullptr; } - | vlTag { $$ = nullptr; } - ; +struct_union_member: // ==IEEE: struct_union_member + // // UNSUP random_qualifer not propagagted until have randomize support + random_qualifierE data_type_or_void + /*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. + /*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = nullptr; } + | vlTag { $$ = nullptr; } + ; -list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_decl_assignments - member_decl_assignment { $$ = $1; } - | list_of_member_decl_assignments ',' member_decl_assignment { $$ = $1->addNextNull($3); } - ; +list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_decl_assignments + member_decl_assignment { $$ = $1; } + | list_of_member_decl_assignments ',' member_decl_assignment { $$ = $1->addNextNull($3); } + ; -member_decl_assignment: // Derived from IEEE: variable_decl_assignment - // // At present we allow only packed structures/unions. So this is different from variable_decl_assignment - id variable_dimensionListE - { if ($2) $2->v3warn(UNPACKED, "Unsupported: Unpacked array in packed struct/union (struct/union converted to unpacked)"); - $$ = new AstMemberDType($1, *$1, VFlagChildDType(), - AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true)); +member_decl_assignment: // Derived from IEEE: variable_decl_assignment + // // At present we allow only packed structures/unions. So this is different from variable_decl_assignment + id variable_dimensionListE + { if ($2) $2->v3warn(UNPACKED, "Unsupported: Unpacked array in packed struct/union (struct/union converted to unpacked)"); + $$ = new AstMemberDType($1, *$1, VFlagChildDType(), + AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true)); PARSEP->tagNodep($$); } - | id variable_dimensionListE '=' variable_declExpr - { BBUNSUP($4, "Unsupported: Initial values in struct/union members."); - // But still need error if packed according to IEEE 7.2.2 - $$ = nullptr; } - | idSVKwd { $$ = nullptr; } - // - // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" - // // Matches above with variable_dimensionE = "[]" - // // IEEE: "class_variable_identifier [ '=' class_new ]" - // // variable_dimensionE must be empty - // // Pushed into variable_declExpr:dynamic_array_new - // - // // IEEE: "[ covergroup_variable_identifier ] '=' class_new - // // Pushed into variable_declExpr:class_new - | '=' class_new - { $$ = nullptr; BBUNSUP($1, "Unsupported: member declaration assignment with new()"); } - ; + | id variable_dimensionListE '=' variable_declExpr + { BBUNSUP($4, "Unsupported: Initial values in struct/union members."); + // But still need error if packed according to IEEE 7.2.2 + $$ = nullptr; } + | idSVKwd { $$ = nullptr; } + // + // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" + // // Matches above with variable_dimensionE = "[]" + // // IEEE: "class_variable_identifier [ '=' class_new ]" + // // variable_dimensionE must be empty + // // Pushed into variable_declExpr:dynamic_array_new + // + // // IEEE: "[ covergroup_variable_identifier ] '=' class_new + // // Pushed into variable_declExpr:class_new + | '=' class_new + { $$ = nullptr; BBUNSUP($1, "Unsupported: member declaration assignment with new()"); } + ; -list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments - variable_decl_assignment { $$ = $1; } - | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = VN_CAST($1->addNextNull($3), Var); } - ; +list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments + variable_decl_assignment { $$ = $1; } + | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = VN_CAST($1->addNextNull($3), Var); } + ; -variable_decl_assignment: // ==IEEE: variable_decl_assignment - id variable_dimensionListE sigAttrListE - { $$ = VARDONEA($1,*$1,$2,$3); } - | id variable_dimensionListE sigAttrListE '=' variable_declExpr - { $$ = VARDONEA($1,*$1,$2,$3); $$->valuep($5); } - | idSVKwd { $$ = nullptr; } - // - // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" - // // Matches above with variable_dimensionE = "[]" - // // IEEE: "class_variable_identifier [ '=' class_new ]" - // // variable_dimensionE must be empty - // // Pushed into variable_declExpr:dynamic_array_new - // - // // IEEE: "[ covergroup_variable_identifier ] '=' class_new - // // Pushed into variable_declExpr:class_new - | '=' class_new - { $$ = nullptr; BBUNSUP($1, "Unsupported: declaration assignment with new()"); } - ; +variable_decl_assignment: // ==IEEE: variable_decl_assignment + id variable_dimensionListE sigAttrListE + { $$ = VARDONEA($1,*$1,$2,$3); } + | id variable_dimensionListE sigAttrListE '=' variable_declExpr + { $$ = VARDONEA($1,*$1,$2,$3); $$->valuep($5); } + | idSVKwd { $$ = nullptr; } + // + // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" + // // Matches above with variable_dimensionE = "[]" + // // IEEE: "class_variable_identifier [ '=' class_new ]" + // // variable_dimensionE must be empty + // // Pushed into variable_declExpr:dynamic_array_new + // + // // IEEE: "[ covergroup_variable_identifier ] '=' class_new + // // Pushed into variable_declExpr:class_new + | '=' class_new + { $$ = nullptr; BBUNSUP($1, "Unsupported: declaration assignment with new()"); } + ; list_of_tf_variable_identifiers: // ==IEEE: list_of_tf_variable_identifiers - tf_variable_identifier { $$ = $1; } - | list_of_tf_variable_identifiers ',' tf_variable_identifier { $$ = $1->addNext($3); } - ; + tf_variable_identifier { $$ = $1; } + | list_of_tf_variable_identifiers ',' tf_variable_identifier { $$ = $1->addNext($3); } + ; -tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers - id variable_dimensionListE sigAttrListE exprEqE - { $$ = VARDONEA($1,*$1, $2, $3); +tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers + id variable_dimensionListE sigAttrListE exprEqE + { $$ = VARDONEA($1,*$1, $2, $3); if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($1, *$1, VAccess::WRITE), $4)); } - ; + ; -variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr - expr { $$ = $1; } - | dynamic_array_new { $$ = $1; } - | class_new { $$ = $1; } - ; +variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr + expr { $$ = $1; } + | dynamic_array_new { $$ = $1; } + | class_new { $$ = $1; } + ; -variable_dimensionListE: // IEEE: variable_dimension + empty - /*empty*/ { $$ = nullptr; } - | variable_dimensionList { $$ = $1; } - ; +variable_dimensionListE: // IEEE: variable_dimension + empty + /*empty*/ { $$ = nullptr; } + | variable_dimensionList { $$ = $1; } + ; -variable_dimensionList: // IEEE: variable_dimension + empty - variable_dimension { $$ = $1; } - | variable_dimensionList variable_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } - ; +variable_dimensionList: // IEEE: variable_dimension + empty + variable_dimension { $$ = $1; } + | variable_dimensionList variable_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } + ; -variable_dimension: // ==IEEE: variable_dimension - // // IEEE: unsized_dimension - '[' ']' { $$ = new AstUnsizedRange($1); } - // // IEEE: unpacked_dimension - | anyrange { $$ = $1; } - // // IEEE: unpacked_dimension (if const_expr) - // // IEEE: associative_dimension (if data_type) - // // Can't tell which until see if expr is data type or not - | '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); } - | yP_BRASTAR ']' - { $$ = nullptr; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); } - | '[' '*' ']' - { $$ = nullptr; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); } - // // IEEE: queue_dimension - // // '[' '$' ']' -- $ is part of expr, see '[' constExpr ']' - // // '[' '$' ':' expr ']' -- anyrange:expr:$ - ; +variable_dimension: // ==IEEE: variable_dimension + // // IEEE: unsized_dimension + '[' ']' { $$ = new AstUnsizedRange($1); } + // // IEEE: unpacked_dimension + | anyrange { $$ = $1; } + // // IEEE: unpacked_dimension (if const_expr) + // // IEEE: associative_dimension (if data_type) + // // Can't tell which until see if expr is data type or not + | '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); } + | yP_BRASTAR ']' + { $$ = nullptr; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); } + | '[' '*' ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); } + // // IEEE: queue_dimension + // // '[' '$' ']' -- $ is part of expr, see '[' constExpr ']' + // // '[' '$' ':' expr ']' -- anyrange:expr:$ + ; -random_qualifierE: // IEEE: random_qualifier + empty - /*empty*/ { $$ = VMemberQualifiers::none(); } - | random_qualifier { $$ = $1; } - ; +random_qualifierE: // IEEE: random_qualifier + empty + /*empty*/ { $$ = VMemberQualifiers::none(); } + | random_qualifier { $$ = $1; } + ; -random_qualifier: // ==IEEE: random_qualifier - yRAND { $$ = VMemberQualifiers::none(); $$.m_rand = true; } - | yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; } - ; +random_qualifier: // ==IEEE: random_qualifier + yRAND { $$ = VMemberQualifiers::none(); $$.m_rand = true; } + | yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; } + ; taggedE: - /*empty*/ { } - //UNSUP yTAGGED { UNSUP } - ; + /*empty*/ { } + //UNSUP yTAGGED { UNSUP } + ; packedSigningE: - // // VSigning::NOSIGN overloaded to indicate not packed - /*empty*/ { $$ = VSigning::NOSIGN; } - | yPACKED signingE { $$ = $2; if ($$ == VSigning::NOSIGN) $$ = VSigning::UNSIGNED; } - ; + // // VSigning::NOSIGN overloaded to indicate not packed + /*empty*/ { $$ = VSigning::NOSIGN; } + | yPACKED signingE { $$ = $2; if ($$ == VSigning::NOSIGN) $$ = VSigning::UNSIGNED; } + ; //************************************************ // enum // IEEE: part of data_type enumDecl: - yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,VFlagChildDType(),$2,$4); } - ; + yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,VFlagChildDType(),$2,$4); } + ; -enum_base_typeE: // IEEE: enum_base_type - /* empty */ { $$ = new AstBasicDType(CRELINE(), VBasicDTypeKwd::INT); } - // // Not in spec, but obviously "enum [1:0]" should work - // // implicit_type expanded, without empty - // // Note enum base types are always packed data types - | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } - | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } - // - | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } - | integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); } - // // below can be idAny or yaID__aTYPE - // // IEEE requires a type, though no shift conflict if idAny - // // IEEE: type_identifier [ packed_dimension ] - // // however other simulators allow [ class_scope | package_scope ] type_identifier - | idAny rangeListE - { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2, true); } - | packageClassScope idAny rangeListE - { AstRefDType* refp = new AstRefDType($2, *$2, $1, nullptr); - $$ = GRAMMARP->createArray(refp, $3, true); } - ; +enum_base_typeE: // IEEE: enum_base_type + /* empty */ { $$ = new AstBasicDType(CRELINE(), VBasicDTypeKwd::INT); } + // // Not in spec, but obviously "enum [1:0]" should work + // // implicit_type expanded, without empty + // // Note enum base types are always packed data types + | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } + | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } + // + | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } + | integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); } + // // below can be idAny or yaID__aTYPE + // // IEEE requires a type, though no shift conflict if idAny + // // IEEE: type_identifier [ packed_dimension ] + // // however other simulators allow [ class_scope | package_scope ] type_identifier + | idAny rangeListE + { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2, true); } + | packageClassScope idAny rangeListE + { AstRefDType* refp = new AstRefDType($2, *$2, $1, nullptr); + $$ = GRAMMARP->createArray(refp, $3, true); } + ; enum_nameList: - enum_name_declaration { $$ = $1; } - | enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); } - ; + enum_name_declaration { $$ = $1; } + | enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); } + ; -enum_name_declaration: // ==IEEE: enum_name_declaration - idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($1, *$1, $2, $3); } - ; +enum_name_declaration: // ==IEEE: enum_name_declaration + idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($1, *$1, $2, $3); } + ; -enumNameRangeE: // IEEE: second part of enum_name_declaration - /* empty */ { $$ = nullptr; } - | '[' intnumAsConst ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstConst($1, $2->toSInt()-1)); } - | '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); } - ; +enumNameRangeE: // IEEE: second part of enum_name_declaration + /* empty */ { $$ = nullptr; } + | '[' intnumAsConst ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstConst($1, $2->toSInt()-1)); } + | '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); } + ; -enumNameStartE: // IEEE: third part of enum_name_declaration - /* empty */ { $$ = nullptr; } - | '=' constExpr { $$ = $2; } - ; +enumNameStartE: // IEEE: third part of enum_name_declaration + /* empty */ { $$ = nullptr; } + | '=' constExpr { $$ = $2; } + ; intnumAsConst: - yaINTNUM { $$ = new AstConst($1,*$1); } - ; + yaINTNUM { $$ = new AstConst($1,*$1); } + ; //************************************************ // Typedef -data_declaration: // ==IEEE: data_declaration - // // VARRESET can't be called here - conflicts - data_declarationVar { $$ = $1; } - | type_declaration { $$ = $1; } - | package_import_declaration { $$ = $1; } - // // IEEE: virtual_interface_declaration - // // "yVIRTUAL yID yID" looks just like a data_declaration - // // Therefore the virtual_interface_declaration term isn't used - // // 1800-2009: - //UNSUP net_type_declaration { $$ = $1; } - | vlTag { $$ = nullptr; } - ; +data_declaration: // ==IEEE: data_declaration + // // VARRESET can't be called here - conflicts + data_declarationVar { $$ = $1; } + | type_declaration { $$ = $1; } + | package_import_declaration { $$ = $1; } + // // IEEE: virtual_interface_declaration + // // "yVIRTUAL yID yID" looks just like a data_declaration + // // Therefore the virtual_interface_declaration term isn't used + // // 1800-2009: + //UNSUP net_type_declaration { $$ = $1; } + | vlTag { $$ = nullptr; } + ; -class_property: // ==IEEE: class_property, which is {property_qualifier} data_declaration - memberQualListE data_declarationVarClass { $$ = $2; $1.applyToNodes($2); } - // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others - | memberQualListE type_declaration { $$ = $2; } - // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others - | memberQualListE package_import_declaration { $$ = $2; } - // // IEEE: virtual_interface_declaration - // // "yVIRTUAL yID yID" looks just like a data_declaration - // // Therefore the virtual_interface_declaration term isn't used - ; +class_property: // ==IEEE: class_property, which is {property_qualifier} data_declaration + memberQualListE data_declarationVarClass { $$ = $2; $1.applyToNodes($2); } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE type_declaration { $$ = $2; } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE package_import_declaration { $$ = $2; } + // // IEEE: virtual_interface_declaration + // // "yVIRTUAL yID yID" looks just like a data_declaration + // // Therefore the virtual_interface_declaration term isn't used + ; -data_declarationVar: // IEEE: part of data_declaration - // // The first declaration has complications between assuming what's the type vs ID declaring - data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; } - ; +data_declarationVar: // IEEE: part of data_declaration + // // The first declaration has complications between assuming what's the type vs ID declaring + data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; } + ; data_declarationVarClass: // IEEE: part of data_declaration (for class_property) - // // The first declaration has complications between assuming what's the type vs ID declaring - data_declarationVarFrontClass list_of_variable_decl_assignments ';' { $$ = $2; } - ; + // // The first declaration has complications between assuming what's the type vs ID declaring + data_declarationVarFrontClass list_of_variable_decl_assignments ';' { $$ = $2; } + ; -data_declarationVarFront: // IEEE: part of data_declaration - // // Non-ANSI; used inside block followed by ';' - // // SEE ALSO port_declaration, tf_port_declaration, port - // - // // Expanded: "constE yVAR lifetimeE data_type" - // // implicit_type expanded into /*empty*/ or "signingE rangeList" - yVAR lifetimeE data_type - { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } - | yVAR lifetimeE - { VARRESET_NONLIST(VAR); VARLIFE($2); - VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } - | yVAR lifetimeE signingE rangeList - { /*VARRESET-in-ddVar*/ VARLIFE($2); - VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } - // - // // implicit_type expanded into /*empty*/ or "signingE rangeList" - | yCONST__ETC yVAR lifetimeE data_type - { VARRESET_NONLIST(VAR); VARLIFE($3); - VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } - | yCONST__ETC yVAR lifetimeE - { VARRESET_NONLIST(VAR); VARLIFE($3); - VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } - | yCONST__ETC yVAR lifetimeE signingE rangeList - { VARRESET_NONLIST(VAR); VARLIFE($3); - VARDTYPE(new AstConstDType($2, VFlagChildDType(), - GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } - // - // // Expanded: "constE lifetimeE data_type" - | /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } - | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARLIFE($1); VARDTYPE($2); } - | yCONST__ETC lifetimeE data_type - { VARRESET_NONLIST(VAR); VARLIFE($2); - VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } - // // = class_new is in variable_decl_assignment - ; +data_declarationVarFront: // IEEE: part of data_declaration + // // Non-ANSI; used inside block followed by ';' + // // SEE ALSO port_declaration, tf_port_declaration, port + // + // // Expanded: "constE yVAR lifetimeE data_type" + // // implicit_type expanded into /*empty*/ or "signingE rangeList" + yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT)); } + | yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARLIFE($2); + VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); } + // + // // implicit_type expanded into /*empty*/ or "signingE rangeList" + | yCONST__ETC yVAR lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), $4)); } + | yCONST__ETC yVAR lifetimeE + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), new AstBasicDType($2, LOGIC_IMPLICIT))); } + | yCONST__ETC yVAR lifetimeE signingE rangeList + { VARRESET_NONLIST(VAR); VARLIFE($3); + VARDTYPE(new AstConstDType($2, VFlagChildDType(), + GRAMMARP->addRange(new AstBasicDType($2, LOGIC_IMPLICIT, $4), $5,true))); } + // + // // Expanded: "constE lifetimeE data_type" + | /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } + | /**/ lifetime data_type { VARRESET_NONLIST(VAR); VARLIFE($1); VARDTYPE($2); } + | yCONST__ETC lifetimeE data_type + { VARRESET_NONLIST(VAR); VARLIFE($2); + VARDTYPE(new AstConstDType($1, VFlagChildDType(), $3)); } + // // = class_new is in variable_decl_assignment + ; -data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_property) - // // VARRESET called before this rule - // // yCONST is removed, added to memberQual rules - // // implicit_type expanded into /*empty*/ or "signingE rangeList" - yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } - | yVAR lifetimeE { VARRESET_NONLIST(VAR); VARLIFE($2); } - | yVAR lifetimeE signingE rangeList - { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); - VARLIFE($2); } - // - // // Expanded: "constE lifetimeE data_type" - | data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } - // // lifetime is removed, added to memberQual rules to avoid conflict - // // yCONST is removed, added to memberQual rules to avoid conflict - // // = class_new is in variable_decl_assignment - ; +data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_property) + // // VARRESET called before this rule + // // yCONST is removed, added to memberQual rules + // // implicit_type expanded into /*empty*/ or "signingE rangeList" + yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } + | yVAR lifetimeE { VARRESET_NONLIST(VAR); VARLIFE($2); } + | yVAR lifetimeE signingE rangeList + { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); + VARLIFE($2); } + // + // // Expanded: "constE lifetimeE data_type" + | data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } + // // lifetime is removed, added to memberQual rules to avoid conflict + // // yCONST is removed, added to memberQual rules to avoid conflict + // // = class_new is in variable_decl_assignment + ; -//UNSUPnet_type_declaration: // IEEE: net_type_declaration -//UNSUP yNETTYPE data_type idAny/*net_type_identifier*/ ';' { } -//UNSUP // // package_scope part of data_type -//UNSUP | yNETTYPE data_type idAny yWITH__ETC packageClassScope id/*tf_identifier*/ ';' { } -//UNSUP | yNETTYPE packageClassScope id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { } -//UNSUP ; +//UNSUPnet_type_declaration: // IEEE: net_type_declaration +//UNSUP yNETTYPE data_type idAny/*net_type_identifier*/ ';' { } +//UNSUP // // package_scope part of data_type +//UNSUP | yNETTYPE data_type idAny yWITH__ETC packageClassScope id/*tf_identifier*/ ';' { } +//UNSUP | yNETTYPE packageClassScope id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { } +//UNSUP ; -implicit_typeE: // IEEE: part of *data_type_or_implicit - // // Also expanded in data_declaration - /* empty */ { $$ = nullptr; } - | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } - | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } - ; +implicit_typeE: // IEEE: part of *data_type_or_implicit + // // Also expanded in data_declaration + /* empty */ { $$ = nullptr; } + | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } + | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } + ; //UNSUPassertion_variable_declaration: // IEEE: assertion_variable_declaration -//UNSUP // // IEEE: var_data_type expanded -//UNSUP var_data_type list_of_variable_decl_assignments ';' { } -//UNSUP ; +//UNSUP // // IEEE: var_data_type expanded +//UNSUP var_data_type list_of_variable_decl_assignments ';' { } +//UNSUP ; -type_declaration: // ==IEEE: type_declaration - // Data_type expanded - yTYPEDEF data_typeNoRef - /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' - { AstNodeDType* dtp = $2; - $$ = GRAMMARP->createTypedef($3, *$3, $5, dtp, $4); } - | yTYPEDEF packageClassScope idType packed_dimensionListE - /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' - { AstRefDType* refp = new AstRefDType($3, *$3, $2, nullptr); - AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); - $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } - | yTYPEDEF packageClassScope idType parameter_value_assignmentClass packed_dimensionListE - /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' - { AstRefDType* refp = new AstRefDType($3, *$3, $2, $4); - AstNodeDType* dtp = GRAMMARP->createArray(refp, $5, true); - $$ = GRAMMARP->createTypedef($6, *$6, $8, dtp, $7); } - | yTYPEDEF idType packed_dimensionListE - /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' - { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, nullptr); - AstNodeDType* dtp = GRAMMARP->createArray(refp, $3, true); - $$ = GRAMMARP->createTypedef($4, *$4, $6, dtp, $5); } - | yTYPEDEF idType parameter_value_assignmentClass packed_dimensionListE - /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' - { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, $3); - AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); - $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } - // // - | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } - // // Allow redeclaring same typedef again - // // Alternative is use of idAny below, but this will cause conflicts with ablve - | yTYPEDEF idType ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } - // // Combines into above "data_type id" rule - // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned - | yTYPEDEF id ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } - | yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } - | yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } - | yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } - | yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } - | yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($4, *$4); } - ; +type_declaration: // ==IEEE: type_declaration + // Data_type expanded + yTYPEDEF data_typeNoRef + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstNodeDType* dtp = $2; + $$ = GRAMMARP->createTypedef($3, *$3, $5, dtp, $4); } + | yTYPEDEF packageClassScope idType packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($3, *$3, $2, nullptr); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); + $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } + | yTYPEDEF packageClassScope idType parameter_value_assignmentClass packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($3, *$3, $2, $4); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $5, true); + $$ = GRAMMARP->createTypedef($6, *$6, $8, dtp, $7); } + | yTYPEDEF idType packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, nullptr); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $3, true); + $$ = GRAMMARP->createTypedef($4, *$4, $6, dtp, $5); } + | yTYPEDEF idType parameter_value_assignmentClass packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, $3); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); + $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } + // // + | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } + // // Allow redeclaring same typedef again + // // Alternative is use of idAny below, but this will cause conflicts with ablve + | yTYPEDEF idType ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } + // // Combines into above "data_type id" rule + // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned + | yTYPEDEF id ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } + | yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($4, *$4); } + ; dtypeAttrListE: - /* empty */ { $$ = nullptr; } - | dtypeAttrList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | dtypeAttrList { $$ = $1; } + ; dtypeAttrList: - dtypeAttr { $$ = $1; } - | dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); } - ; + dtypeAttr { $$ = $1; } + | dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); } + ; dtypeAttr: - yVL_PUBLIC { $$ = new AstAttrOf($1,VAttrType::DT_PUBLIC); } - ; + yVL_PUBLIC { $$ = new AstAttrOf($1,VAttrType::DT_PUBLIC); } + ; -vlTag: // verilator tag handling - yVL_TAG { if (PARSEP->tagNodep()) PARSEP->tagNodep()->tag(*$1); } - ; +vlTag: // verilator tag handling + yVL_TAG { if (PARSEP->tagNodep()) PARSEP->tagNodep()->tag(*$1); } + ; //************************************************ // Module Items -module_itemListE: // IEEE: Part of module_declaration - /* empty */ { $$ = nullptr; } - | module_itemList { $$ = $1; } - ; +module_itemListE: // IEEE: Part of module_declaration + /* empty */ { $$ = nullptr; } + | module_itemList { $$ = $1; } + ; -module_itemList: // IEEE: Part of module_declaration - module_item { $$ = $1; } - | module_itemList module_item { $$ = $1->addNextNull($2); } - ; +module_itemList: // IEEE: Part of module_declaration + module_item { $$ = $1; } + | module_itemList module_item { $$ = $1->addNextNull($2); } + ; -module_item: // ==IEEE: module_item - port_declaration ';' { $$ = $1; } - | non_port_module_item { $$ = $1; } - ; +module_item: // ==IEEE: module_item + port_declaration ';' { $$ = $1; } + | non_port_module_item { $$ = $1; } + ; -non_port_module_item: // ==IEEE: non_port_module_item - generate_region { $$ = $1; } - | module_or_generate_item { $$ = $1; } - | specify_block { $$ = $1; } - | specparam_declaration { $$ = $1; } - | program_declaration - { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: program decls within module decls"); } - | module_declaration - { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: module decls within module decls"); } - | interface_declaration - { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: interface decls within module decls"); } - | timeunits_declaration { $$ = $1; } - // // Verilator specific - | yaSCHDR { $$ = new AstScHdr($1,*$1); v3Global.setHasSCTextSections(); } - | yaSCINT { $$ = new AstScInt($1,*$1); v3Global.setHasSCTextSections(); } - | yaSCIMP { $$ = new AstScImp($1,*$1); v3Global.setHasSCTextSections(); } - | yaSCIMPH { $$ = new AstScImpHdr($1,*$1); v3Global.setHasSCTextSections(); } - | yaSCCTOR { $$ = new AstScCtor($1,*$1); v3Global.setHasSCTextSections(); } - | yaSCDTOR { $$ = new AstScDtor($1,*$1); v3Global.setHasSCTextSections(); } - | yVL_HIER_BLOCK { $$ = new AstPragma($1,VPragmaType::HIER_BLOCK); } - | yVL_INLINE_MODULE { $$ = new AstPragma($1,VPragmaType::INLINE_MODULE); } - | yVL_NO_INLINE_MODULE { $$ = new AstPragma($1,VPragmaType::NO_INLINE_MODULE); } - | yVL_PUBLIC_MODULE { $$ = new AstPragma($1,VPragmaType::PUBLIC_MODULE); v3Global.dpi(true); } - ; +non_port_module_item: // ==IEEE: non_port_module_item + generate_region { $$ = $1; } + | module_or_generate_item { $$ = $1; } + | specify_block { $$ = $1; } + | specparam_declaration { $$ = $1; } + | program_declaration + { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: program decls within module decls"); } + | module_declaration + { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: module decls within module decls"); } + | interface_declaration + { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: interface decls within module decls"); } + | timeunits_declaration { $$ = $1; } + // // Verilator specific + | yaSCHDR { $$ = new AstScHdr($1,*$1); v3Global.setHasSCTextSections(); } + | yaSCINT { $$ = new AstScInt($1,*$1); v3Global.setHasSCTextSections(); } + | yaSCIMP { $$ = new AstScImp($1,*$1); v3Global.setHasSCTextSections(); } + | yaSCIMPH { $$ = new AstScImpHdr($1,*$1); v3Global.setHasSCTextSections(); } + | yaSCCTOR { $$ = new AstScCtor($1,*$1); v3Global.setHasSCTextSections(); } + | yaSCDTOR { $$ = new AstScDtor($1,*$1); v3Global.setHasSCTextSections(); } + | yVL_HIER_BLOCK { $$ = new AstPragma($1,VPragmaType::HIER_BLOCK); } + | yVL_INLINE_MODULE { $$ = new AstPragma($1,VPragmaType::INLINE_MODULE); } + | yVL_NO_INLINE_MODULE { $$ = new AstPragma($1,VPragmaType::NO_INLINE_MODULE); } + | yVL_PUBLIC_MODULE { $$ = new AstPragma($1,VPragmaType::PUBLIC_MODULE); v3Global.dpi(true); } + ; -module_or_generate_item: // ==IEEE: module_or_generate_item - // // IEEE: parameter_override - yDEFPARAM list_of_defparam_assignments ';' { $$ = $2; } - // // IEEE: gate_instantiation + udp_instantiation + module_instantiation - // // not here, see etcInst in module_common_item - // // We joined udp & module definitions, so this goes here - | combinational_body { $$ = $1; } - // // This module_common_item shared with interface_or_generate_item:module_common_item - | module_common_item { $$ = $1; } - ; +module_or_generate_item: // ==IEEE: module_or_generate_item + // // IEEE: parameter_override + yDEFPARAM list_of_defparam_assignments ';' { $$ = $2; } + // // IEEE: gate_instantiation + udp_instantiation + module_instantiation + // // not here, see etcInst in module_common_item + // // We joined udp & module definitions, so this goes here + | combinational_body { $$ = $1; } + // // This module_common_item shared with interface_or_generate_item:module_common_item + | module_common_item { $$ = $1; } + ; -module_common_item: // ==IEEE: module_common_item - module_or_generate_item_declaration { $$ = $1; } - // // IEEE: interface_instantiation - // // + IEEE: program_instantiation - // // + module_instantiation from module_or_generate_item - | etcInst { $$ = $1; } - | assertion_item { $$ = $1; } - | bind_directive { $$ = $1; } - | continuous_assign { $$ = $1; } - // // IEEE: net_alias - | yALIAS variable_lvalue aliasEqList ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: alias statements"); } - | initial_construct { $$ = $1; } - | final_construct { $$ = $1; } - // // IEEE: always_construct - // // Verilator only - event_control attached to always - | yALWAYS stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, nullptr, $2); } - | yALWAYS_FF stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, nullptr, $2); } - | yALWAYS_LATCH stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, nullptr, $2); } - | yALWAYS_COMB stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, nullptr, $2); } - // - | loop_generate_construct { $$ = $1; } - | conditional_generate_construct { $$ = $1; } - | elaboration_system_task { $$ = $1; } - // - | error ';' { $$ = nullptr; } - ; +module_common_item: // ==IEEE: module_common_item + module_or_generate_item_declaration { $$ = $1; } + // // IEEE: interface_instantiation + // // + IEEE: program_instantiation + // // + module_instantiation from module_or_generate_item + | etcInst { $$ = $1; } + | assertion_item { $$ = $1; } + | bind_directive { $$ = $1; } + | continuous_assign { $$ = $1; } + // // IEEE: net_alias + | yALIAS variable_lvalue aliasEqList ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: alias statements"); } + | initial_construct { $$ = $1; } + | final_construct { $$ = $1; } + // // IEEE: always_construct + // // Verilator only - event_control attached to always + | yALWAYS stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, nullptr, $2); } + | yALWAYS_FF stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, nullptr, $2); } + | yALWAYS_LATCH stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, nullptr, $2); } + | yALWAYS_COMB stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, nullptr, $2); } + // + | loop_generate_construct { $$ = $1; } + | conditional_generate_construct { $$ = $1; } + | elaboration_system_task { $$ = $1; } + // + | error ';' { $$ = nullptr; } + ; -continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; } - ; +continuous_assign: // IEEE: continuous_assign + yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; } + ; -initial_construct: // IEEE: initial_construct - yINITIAL stmtBlock { $$ = new AstInitial($1,$2); } - ; +initial_construct: // IEEE: initial_construct + yINITIAL stmtBlock { $$ = new AstInitial($1,$2); } + ; -final_construct: // IEEE: final_construct - yFINAL stmtBlock { $$ = new AstFinal($1,$2); } - ; +final_construct: // IEEE: final_construct + yFINAL stmtBlock { $$ = new AstFinal($1,$2); } + ; -module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_declaration - package_or_generate_item_declaration { $$ = $1; } - | genvar_declaration { $$ = $1; } - | clocking_declaration { $$ = $1; } - | yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: default clocking identifier"); } - //UNSUP yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } - ; +module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_declaration + package_or_generate_item_declaration { $$ = $1; } + | genvar_declaration { $$ = $1; } + | clocking_declaration { $$ = $1; } + | yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: default clocking identifier"); } + //UNSUP yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } + ; -aliasEqList: // IEEE: part of net_alias - '=' variable_lvalue { } - | aliasEqList '=' variable_lvalue { } - ; +aliasEqList: // IEEE: part of net_alias + '=' variable_lvalue { } + | aliasEqList '=' variable_lvalue { } + ; -bind_directive: // ==IEEE: bind_directive + bind_target_scope - // // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation - // // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier - yBIND bind_target_instance bind_instantiation { $$ = new AstBind($2, *$2, $3); } - | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation - { $$ = nullptr; BBUNSUP($1, "Unsupported: Bind with instance list"); } - ; +bind_directive: // ==IEEE: bind_directive + bind_target_scope + // // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation + // // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier + yBIND bind_target_instance bind_instantiation { $$ = new AstBind($2, *$2, $3); } + | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation + { $$ = nullptr; BBUNSUP($1, "Unsupported: Bind with instance list"); } + ; -bind_target_instance_list: // ==IEEE: bind_target_instance_list - bind_target_instance { } - | bind_target_instance_list ',' bind_target_instance { } - ; +bind_target_instance_list: // ==IEEE: bind_target_instance_list + bind_target_instance { } + | bind_target_instance_list ',' bind_target_instance { } + ; -bind_target_instance: // ==IEEE: bind_target_instance - //UNSUP hierarchical_identifierBit { } - idAny { $$ = $1; } - ; +bind_target_instance: // ==IEEE: bind_target_instance + //UNSUP hierarchical_identifierBit { } + idAny { $$ = $1; } + ; -bind_instantiation: // ==IEEE: bind_instantiation - // // IEEE: program_instantiation - // // IEEE: + module_instantiation - // // IEEE: + interface_instantiation - // // Need to get an AstBind instead of AstCell, so have special rules - instDecl { $$ = $1; } - ; +bind_instantiation: // ==IEEE: bind_instantiation + // // IEEE: program_instantiation + // // IEEE: + module_instantiation + // // IEEE: + interface_instantiation + // // Need to get an AstBind instead of AstCell, so have special rules + instDecl { $$ = $1; } + ; //************************************************ // Generates @@ -2405,1772 +2405,1772 @@ bind_instantiation: // ==IEEE: bind_instantiation // identical (minus DEFPARAMs) so we overlap them. Checkers are too // different, so we copy all rules for checkers. -generate_region: // ==IEEE: generate_region - yGENERATE ~c~genItemList yENDGENERATE { $$ = $2; } - | yGENERATE yENDGENERATE { $$ = nullptr; } - ; +generate_region: // ==IEEE: generate_region + yGENERATE ~c~genItemList yENDGENERATE { $$ = $2; } + | yGENERATE yENDGENERATE { $$ = nullptr; } + ; //UNSUPc_generate_region: // IEEE: generate_region (for checkers) -//UNSUP BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} +//UNSUP ; -generate_block_or_null: // IEEE: generate_block_or_null (called from gencase/genif/genfor) - // ';' // is included in - // // IEEE: generate_block - // // Must always return a BEGIN node, or nullptr - see GenFor construction - generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"",$1,true,true)) : nullptr; } - | genItemBegin { $$ = $1; } - ; +generate_block_or_null: // IEEE: generate_block_or_null (called from gencase/genif/genfor) + // ';' // is included in + // // IEEE: generate_block + // // Must always return a BEGIN node, or nullptr - see GenFor construction + generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"",$1,true,true)) : nullptr; } + | genItemBegin { $$ = $1; } + ; -genItemBegin: // IEEE: part of generate_block - yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"",$2,true,false); } - | yBEGIN yEND { $$ = nullptr; } - | id yP_COLON__BEGIN yBEGIN ~c~genItemList yEND endLabelE - { $$ = new AstBegin($1,*$1,$4,true,false); GRAMMARP->endLabel($6,*$1,$6); } - | id yP_COLON__BEGIN yBEGIN yEND endLabelE - { $$ = nullptr; GRAMMARP->endLabel($5,*$1,$5); } - | yBEGIN ':' idAny ~c~genItemList yEND endLabelE - { $$ = new AstBegin($3,*$3,$4,true,false); GRAMMARP->endLabel($6,*$3,$6); } - | yBEGIN ':' idAny yEND endLabelE { $$ = nullptr; GRAMMARP->endLabel($5,*$3,$5); } - ; +genItemBegin: // IEEE: part of generate_block + yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"",$2,true,false); } + | yBEGIN yEND { $$ = nullptr; } + | id yP_COLON__BEGIN yBEGIN ~c~genItemList yEND endLabelE + { $$ = new AstBegin($1,*$1,$4,true,false); GRAMMARP->endLabel($6,*$1,$6); } + | id yP_COLON__BEGIN yBEGIN yEND endLabelE + { $$ = nullptr; GRAMMARP->endLabel($5,*$1,$5); } + | yBEGIN ':' idAny ~c~genItemList yEND endLabelE + { $$ = new AstBegin($3,*$3,$4,true,false); GRAMMARP->endLabel($6,*$3,$6); } + | yBEGIN ':' idAny yEND endLabelE { $$ = nullptr; GRAMMARP->endLabel($5,*$3,$5); } + ; //UNSUPc_genItemBegin: // IEEE: part of generate_block (for checkers) -//UNSUP BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} +//UNSUP ; -genItemOrBegin: // Not in IEEE, but our begin isn't under generate_item - ~c~generate_item { $$ = $1; } - | ~c~genItemBegin { $$ = $1; } - ; +genItemOrBegin: // Not in IEEE, but our begin isn't under generate_item + ~c~generate_item { $$ = $1; } + | ~c~genItemBegin { $$ = $1; } + ; //UNSUPc_genItemOrBegin: // (for checkers) -//UNSUP BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} +//UNSUP ; genItemList: - ~c~genItemOrBegin { $$ = $1; } - | ~c~genItemList ~c~genItemOrBegin { $$ = $1->addNextNull($2); } - ; + ~c~genItemOrBegin { $$ = $1; } + | ~c~genItemList ~c~genItemOrBegin { $$ = $1->addNextNull($2); } + ; //UNSUPc_genItemList: // (for checkers) -//UNSUP BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} +//UNSUP ; -generate_item: // IEEE: module_or_interface_or_generate_item - // // Only legal when in a generate under a module (or interface under a module) - module_or_generate_item { $$ = $1; } - // // Only legal when in a generate under an interface - //UNSUP interface_or_generate_item { $$ = $1; } - // // IEEE: checker_or_generate_item - // // Only legal when in a generate under a checker - // // so below in c_generate_item - ; +generate_item: // IEEE: module_or_interface_or_generate_item + // // Only legal when in a generate under a module (or interface under a module) + module_or_generate_item { $$ = $1; } + // // Only legal when in a generate under an interface + //UNSUP interface_or_generate_item { $$ = $1; } + // // IEEE: checker_or_generate_item + // // Only legal when in a generate under a checker + // // so below in c_generate_item + ; //UNSUPc_generate_item: // IEEE: generate_item (for checkers) -//UNSUP checker_or_generate_item { $$ = $1; } -//UNSUP ; +//UNSUP checker_or_generate_item { $$ = $1; } +//UNSUP ; -conditional_generate_construct: // ==IEEE: conditional_generate_construct - yCASE '(' expr ')' ~c~case_generate_itemListE yENDCASE - { $$ = new AstGenCase($1, $3, $5); } - | yIF '(' expr ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE - { $$ = new AstGenIf($1, $3, $5, nullptr); } - | yIF '(' expr ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null - { $$ = new AstGenIf($1, $3, $5, $7); } - ; +conditional_generate_construct: // ==IEEE: conditional_generate_construct + yCASE '(' expr ')' ~c~case_generate_itemListE yENDCASE + { $$ = new AstGenCase($1, $3, $5); } + | yIF '(' expr ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE + { $$ = new AstGenIf($1, $3, $5, nullptr); } + | yIF '(' expr ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null + { $$ = new AstGenIf($1, $3, $5, $7); } + ; //UNSUPc_conditional_generate_construct: // IEEE: conditional_generate_construct (for checkers) -//UNSUP BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g}) // {copied} +//UNSUP ; -loop_generate_construct: // ==IEEE: loop_generate_construct - yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null - { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar - AstBegin* lowerBegp = VN_CAST($9, Begin); - UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); +loop_generate_construct: // ==IEEE: loop_generate_construct + yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null + { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar + AstBegin* lowerBegp = VN_CAST($9, Begin); + UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); - if (!lowerBegp) lowerBegp = new AstBegin{$1, "", nullptr, true, false}; // Empty body - AstNode* const lowerNoBegp = lowerBegp->stmtsp(); - if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext(); - // - AstBegin* const blkp = new AstBegin{$1, lowerBegp->name(), nullptr, true, true}; - // V3LinkDot detects BEGIN(GENFOR(...)) as a special case - AstNode* initp = $3; - AstNode* const varp = $3; - if (VN_IS(varp, Var)) { // Genvar - initp = varp->nextp(); - initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init - blkp->addStmtsp(varp); - } - // Statements are under 'genforp' as cells under this - // for loop won't get an extra layer of hierarchy tacked on - blkp->addGenforp(new AstGenFor($1, initp, $5, $7, lowerNoBegp)); - $$ = blkp; - VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp); - } - ; + if (!lowerBegp) lowerBegp = new AstBegin{$1, "", nullptr, true, false}; // Empty body + AstNode* const lowerNoBegp = lowerBegp->stmtsp(); + if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext(); + // + AstBegin* const blkp = new AstBegin{$1, lowerBegp->name(), nullptr, true, true}; + // V3LinkDot detects BEGIN(GENFOR(...)) as a special case + AstNode* initp = $3; + AstNode* const varp = $3; + if (VN_IS(varp, Var)) { // Genvar + initp = varp->nextp(); + initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init + blkp->addStmtsp(varp); + } + // Statements are under 'genforp' as cells under this + // for loop won't get an extra layer of hierarchy tacked on + blkp->addGenforp(new AstGenFor($1, initp, $5, $7, lowerNoBegp)); + $$ = blkp; + VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp); + } + ; //UNSUPc_loop_generate_construct: // IEEE: loop_generate_construct (for checkers) -//UNSUP BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g}) // {copied} +//UNSUP ; -genvar_initialization: // ==IEEE: genvar_initialization - varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } - | yGENVAR genvar_identifierDecl '=' constExpr - { $$ = $2; $2->addNext(new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); } - ; +genvar_initialization: // ==IEEE: genvar_initialization + varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } + | yGENVAR genvar_identifierDecl '=' constExpr + { $$ = $2; $2->addNext(new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); } + ; -genvar_iteration: // ==IEEE: genvar_iteration - varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } - | varRefBase yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } - | varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } - // // inc_or_dec_operator - // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt? - | yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } - | yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } - | varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } - | varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } - ; +genvar_iteration: // ==IEEE: genvar_iteration + varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } + | varRefBase yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } + | varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } + // // inc_or_dec_operator + // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt? + | yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } + | yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } + | varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } + | varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } + ; -case_generate_itemListE: // IEEE: [{ case_generate_itemList }] - /* empty */ { $$ = nullptr; } - | case_generate_itemList { $$ = $1; } - ; +case_generate_itemListE: // IEEE: [{ case_generate_itemList }] + /* empty */ { $$ = nullptr; } + | case_generate_itemList { $$ = $1; } + ; -case_generate_itemList: // IEEE: { case_generate_itemList } - ~c~case_generate_item { $$ = $1; } - | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } - ; +case_generate_itemList: // IEEE: { case_generate_itemList } + ~c~case_generate_item { $$ = $1; } + | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } + ; //UNSUPc_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) -//UNSUP BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} +//UNSUP ; -case_generate_item: // ==IEEE: case_generate_item - caseCondList colon generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } - | yDEFAULT colon generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } - | yDEFAULT generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } - ; +case_generate_item: // ==IEEE: case_generate_item + caseCondList colon generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } + | yDEFAULT colon generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } + | yDEFAULT generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } + ; //UNSUPc_case_generate_item: // IEEE: case_generate_item (for checkers) -//UNSUP BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} +//UNSUP ; //************************************************ // Assignments and register declarations assignList: - assignOne { $$ = $1; } - | assignList ',' assignOne { $$ = $1->addNext($3); } - ; + assignOne { $$ = $1; } + | assignList ',' assignOne { $$ = $1->addNext($3); } + ; assignOne: - variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); } - ; + variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); } + ; //UNSUPdelay_or_event_controlE: // IEEE: delay_or_event_control plus empty -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | delay_control { $$ = $1; } -//UNSUP | event_control { $$ = $1; } -//UNSUP | yREPEAT '(' expr ')' event_control { } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | delay_control { $$ = $1; } +//UNSUP | event_control { $$ = $1; } +//UNSUP | yREPEAT '(' expr ')' event_control { } +//UNSUP ; delayE: - /* empty */ { } - | delay { } - ; + /* empty */ { } + | delay { } + ; delay: - delay_control - { $1->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this assignment/primitive."); - DEL($1); } - ; + delay_control + { $1->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this assignment/primitive."); + DEL($1); } + ; -delay_control: //== IEEE: delay_control - '#' delay_value { $$ = $2; } - | '#' '(' minTypMax ')' { $$ = $3; } - | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); } - | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); DEL($7); } - ; +delay_control: //== IEEE: delay_control + '#' delay_value { $$ = $2; } + | '#' '(' minTypMax ')' { $$ = $3; } + | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); } + | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); DEL($7); } + ; -delay_value: // ==IEEE:delay_value - // // IEEE: ps_identifier - packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($2, $1, $2); } - | yaINTNUM { $$ = new AstConst($1, *$1); } - | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } - | timeNumAdjusted { $$ = $1; } - ; +delay_value: // ==IEEE:delay_value + // // IEEE: ps_identifier + packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($2, $1, $2); } + | yaINTNUM { $$ = new AstConst($1, *$1); } + | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } + | timeNumAdjusted { $$ = $1; } + ; delayExpr: - expr { $$ = $1; } - ; + expr { $$ = $1; } + ; -minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression - delayExpr { $$ = $1; } - | delayExpr ':' delayExpr ':' delayExpr { $$ = $3; DEL($1); DEL($5); } - ; +minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression + delayExpr { $$ = $1; } + | delayExpr ':' delayExpr ':' delayExpr { $$ = $3; DEL($1); DEL($5); } + ; -netSigList: // IEEE: list_of_port_identifiers - netSig { $$ = $1; } - | netSigList ',' netSig { $$ = $1; $1->addNext($3); } - ; +netSigList: // IEEE: list_of_port_identifiers + netSig { $$ = $1; } + | netSigList ',' netSig { $$ = $1; $1->addNext($3); } + ; -netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers - netId sigAttrListE { $$ = VARDONEA($1,*$1, nullptr, $2); } - | netId sigAttrListE '=' expr { $$ = VARDONEA($1,*$1, nullptr, $2); - $$->addNext(new AstAssignW($3, new AstVarRef($1, *$1, VAccess::WRITE), $4)); } - | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } - ; +netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers + netId sigAttrListE { $$ = VARDONEA($1,*$1, nullptr, $2); } + | netId sigAttrListE '=' expr { $$ = VARDONEA($1,*$1, nullptr, $2); + $$->addNext(new AstAssignW($3, new AstVarRef($1, *$1, VAccess::WRITE), $4)); } + | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } + ; netId: - id/*new-net*/ { $$ = $1; $$ = $1; } - | idSVKwd { $$ = $1; $$ = $1; } - ; + id/*new-net*/ { $$ = $1; $$ = $1; } + | idSVKwd { $$ = $1; $$ = $1; } + ; sigAttrListE: - /* empty */ { $$ = nullptr; } - | sigAttrList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | sigAttrList { $$ = $1; } + ; sigAttrList: - sigAttr { $$ = $1; } - | sigAttrList sigAttr { $$ = $1->addNextNull($2); } - ; + sigAttr { $$ = $1; } + | sigAttrList sigAttr { $$ = $1->addNextNull($2); } + ; sigAttr: - yVL_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCKER); } - | yVL_NO_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_NO_CLOCKER); } - | yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCK_ENABLE); } - | yVL_FORCEABLE { $$ = new AstAttrOf($1,VAttrType::VAR_FORCEABLE); } - | yVL_PUBLIC { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC); v3Global.dpi(true); } - | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); } - | yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); } - | yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); } - | yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); - $$ = $$->addNext(new AstAlwaysPublic($1,$2,nullptr)); } - | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,VAttrType::VAR_ISOLATE_ASSIGNMENTS); } - | yVL_SC_BV { $$ = new AstAttrOf($1,VAttrType::VAR_SC_BV); } - | yVL_SFORMAT { $$ = new AstAttrOf($1,VAttrType::VAR_SFORMAT); } - | yVL_SPLIT_VAR { $$ = new AstAttrOf($1,VAttrType::VAR_SPLIT_VAR); } - ; + yVL_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCKER); } + | yVL_NO_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_NO_CLOCKER); } + | yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCK_ENABLE); } + | yVL_FORCEABLE { $$ = new AstAttrOf($1,VAttrType::VAR_FORCEABLE); } + | yVL_PUBLIC { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC); v3Global.dpi(true); } + | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); } + | yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); } + | yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); } + | yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); + $$ = $$->addNext(new AstAlwaysPublic($1,$2,nullptr)); } + | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,VAttrType::VAR_ISOLATE_ASSIGNMENTS); } + | yVL_SC_BV { $$ = new AstAttrOf($1,VAttrType::VAR_SC_BV); } + | yVL_SFORMAT { $$ = new AstAttrOf($1,VAttrType::VAR_SFORMAT); } + | yVL_SPLIT_VAR { $$ = new AstAttrOf($1,VAttrType::VAR_SPLIT_VAR); } + ; -rangeListE: // IEEE: [{packed_dimension}] - /* empty */ { $$ = nullptr; } - | rangeList { $$ = $1; } - ; +rangeListE: // IEEE: [{packed_dimension}] + /* empty */ { $$ = nullptr; } + | rangeList { $$ = $1; } + ; -rangeList: // IEEE: {packed_dimension} - anyrange { $$ = $1; } - | rangeList anyrange { $$ = $1; $1->addNext($2); } - ; +rangeList: // IEEE: {packed_dimension} + anyrange { $$ = $1; } + | rangeList anyrange { $$ = $1; $1->addNext($2); } + ; //UNSUPbit_selectE: // IEEE: constant_bit_select (IEEE included empty) -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | '[' constExpr ']' { $$ = $1; $$ = "[" + $2 + "]"; } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | '[' constExpr ']' { $$ = $1; $$ = "[" + $2 + "]"; } +//UNSUP ; // IEEE: select // Merged into more general idArray anyrange: - '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } - ; + '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } + ; -packed_dimensionListE: // IEEE: [{ packed_dimension }] - /* empty */ { $$ = nullptr; } - | packed_dimensionList { $$ = $1; } - ; +packed_dimensionListE: // IEEE: [{ packed_dimension }] + /* empty */ { $$ = nullptr; } + | packed_dimensionList { $$ = $1; } + ; -packed_dimensionList: // IEEE: { packed_dimension } - packed_dimension { $$ = $1; } - | packed_dimensionList packed_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } - ; +packed_dimensionList: // IEEE: { packed_dimension } + packed_dimension { $$ = $1; } + | packed_dimensionList packed_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } + ; -packed_dimension: // ==IEEE: packed_dimension - anyrange { $$ = $1; } - | '[' ']' - { $$ = nullptr; BBUNSUP($1, "Unsupported: [] dimensions"); } - ; +packed_dimension: // ==IEEE: packed_dimension + anyrange { $$ = $1; } + | '[' ']' + { $$ = nullptr; BBUNSUP($1, "Unsupported: [] dimensions"); } + ; //************************************************ // Parameters -param_assignment: // ==IEEE: param_assignment - // // IEEE: constant_param_expression - // // constant_param_expression: '$' is in expr - id/*new-parameter*/ variable_dimensionListE sigAttrListE exprOrDataTypeEqE - { // To handle #(type A=int, B=A) and properly imply B +param_assignment: // ==IEEE: param_assignment + // // IEEE: constant_param_expression + // // constant_param_expression: '$' is in expr + id/*new-parameter*/ variable_dimensionListE sigAttrListE exprOrDataTypeEqE + { // To handle #(type A=int, B=A) and properly imply B // as a type (for parsing) we need to detect "A" is a type - if (AstNodeDType* const refp = VN_CAST($4, NodeDType)) { - if (VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(refp->name())) { - UINFO(9, "declaring type via param assignment" << foundp->nodep() << endl); - VARDTYPE(new AstParseTypeDType{$1}) - SYMP->reinsert(foundp->nodep()->cloneTree(false), nullptr, *$1); }} - $$ = VARDONEA($1, *$1, $2, $3); - if ($4) $$->valuep($4); } - ; + if (AstNodeDType* const refp = VN_CAST($4, NodeDType)) { + if (VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(refp->name())) { + UINFO(9, "declaring type via param assignment" << foundp->nodep() << endl); + VARDTYPE(new AstParseTypeDType{$1}) + SYMP->reinsert(foundp->nodep()->cloneTree(false), nullptr, *$1); }} + $$ = VARDONEA($1, *$1, $2, $3); + if ($4) $$->valuep($4); } + ; -list_of_param_assignments: // ==IEEE: list_of_param_assignments - param_assignment { $$ = $1; } - | list_of_param_assignments ',' param_assignment { $$ = $1; $1->addNext($3); } - ; +list_of_param_assignments: // ==IEEE: list_of_param_assignments + param_assignment { $$ = $1; } + | list_of_param_assignments ',' param_assignment { $$ = $1; $1->addNext($3); } + ; -type_assignment: // ==IEEE: type_assignment - // // note exptOrDataType being a data_type is only for yPARAMETER yTYPE - idAny/*new-parameter*/ sigAttrListE '=' data_type - { $$ = VARDONEA($1, *$1, nullptr, $2); $$->valuep($4); } - ; +type_assignment: // ==IEEE: type_assignment + // // note exptOrDataType being a data_type is only for yPARAMETER yTYPE + idAny/*new-parameter*/ sigAttrListE '=' data_type + { $$ = VARDONEA($1, *$1, nullptr, $2); $$->valuep($4); } + ; -list_of_type_assignments: // ==IEEE: list_of_type_assignments - type_assignment { $$ = $1; } - | list_of_type_assignments ',' type_assignment { $$ = $1; $1->addNext($3); } - ; +list_of_type_assignments: // ==IEEE: list_of_type_assignments + type_assignment { $$ = $1; } + | list_of_type_assignments ',' type_assignment { $$ = $1; $1->addNext($3); } + ; -list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments - defparam_assignment { $$ = $1; } - | list_of_defparam_assignments ',' defparam_assignment { $$ = $1->addNext($3); } - ; +list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments + defparam_assignment { $$ = $1; } + | list_of_defparam_assignments ',' defparam_assignment { $$ = $1->addNext($3); } + ; -defparam_assignment: // ==IEEE: defparam_assignment - idAny '.' idAny '=' expr { $$ = new AstDefParam($4, *$1, *$3, $5); } - | idAny '.' idAny '.' - { $$ = nullptr; BBUNSUP($4, "Unsupported: defparam with more than one dot"); } - ; +defparam_assignment: // ==IEEE: defparam_assignment + idAny '.' idAny '=' expr { $$ = new AstDefParam($4, *$1, *$3, $5); } + | idAny '.' idAny '.' + { $$ = nullptr; BBUNSUP($4, "Unsupported: defparam with more than one dot"); } + ; //************************************************ // Instances // We don't know identifier types, so this matches all module,udp,etc instantiation -// module_id [#(params)] name (pins) [, name ...] ; // module_instantiation -// gate (strong0) [#(delay)] [name] (pins) [, (pins)...] ; // gate_instantiation -// program_id [#(params}] name ; // program_instantiation -// interface_id [#(params}] name ; // interface_instantiation -// checker_id name (pins) ; // checker_instantiation +// module_id [#(params)] name (pins) [, name ...] ; // module_instantiation +// gate (strong0) [#(delay)] [name] (pins) [, (pins)...] ; // gate_instantiation +// program_id [#(params}] name ; // program_instantiation +// interface_id [#(params}] name ; // interface_instantiation +// checker_id name (pins) ; // checker_instantiation -etcInst: // IEEE: module_instantiation + gate_instantiation + udp_instantiation - instDecl { $$ = $1; } - | gateDecl { $$ = $1; } - ; +etcInst: // IEEE: module_instantiation + gate_instantiation + udp_instantiation + instDecl { $$ = $1; } + | gateDecl { $$ = $1; } + ; instDecl: - // // Currently disambiguated from data_declaration based on - // // VARs being type, and cells non-type. - // // IEEE requires a '(' to disambiguate, we need TODO force this - id parameter_value_assignmentE {INSTPREP($1, *$1, $2);} instnameList ';' - { $$ = $4; - GRAMMARP->m_impliedDecl = false; - if (GRAMMARP->m_instParamp) { - VL_DO_CLEAR(GRAMMARP->m_instParamp->deleteTree(), - GRAMMARP->m_instParamp = nullptr); - } } - // // IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers - | id/*interface*/ '.' id/*modport*/ - /*mid*/ { VARRESET_NONLIST(VVarType::IFACEREF); - VARDTYPE(new AstIfaceRefDType($1, $3, "", *$1, *$3)); } - /*cont*/ mpInstnameList ';' - { $$ = VARDONEP($5,nullptr,nullptr); } - //UNSUP: strengthSpecE for udp_instantiations - ; + // // Currently disambiguated from data_declaration based on + // // VARs being type, and cells non-type. + // // IEEE requires a '(' to disambiguate, we need TODO force this + id parameter_value_assignmentE {INSTPREP($1, *$1, $2);} instnameList ';' + { $$ = $4; + GRAMMARP->m_impliedDecl = false; + if (GRAMMARP->m_instParamp) { + VL_DO_CLEAR(GRAMMARP->m_instParamp->deleteTree(), + GRAMMARP->m_instParamp = nullptr); + } } + // // IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers + | id/*interface*/ '.' id/*modport*/ + /*mid*/ { VARRESET_NONLIST(VVarType::IFACEREF); + VARDTYPE(new AstIfaceRefDType($1, $3, "", *$1, *$3)); } + /*cont*/ mpInstnameList ';' + { $$ = VARDONEP($5,nullptr,nullptr); } + //UNSUP: strengthSpecE for udp_instantiations + ; -mpInstnameList: // Similar to instnameList, but for modport instantiations which have no parenthesis - mpInstnameParen { $$ = $1; } - | mpInstnameList ',' mpInstnameParen { $$ = $1->addNext($3); } - ; +mpInstnameList: // Similar to instnameList, but for modport instantiations which have no parenthesis + mpInstnameParen { $$ = $1; } + | mpInstnameList ',' mpInstnameParen { $$ = $1->addNext($3); } + ; -mpInstnameParen: // Similar to instnameParen, but for modport instantiations which have no parenthesis - id instRangeListE sigAttrListE { $$ = VARDONEA($1,*$1,$2,$3); } - ; +mpInstnameParen: // Similar to instnameParen, but for modport instantiations which have no parenthesis + id instRangeListE sigAttrListE { $$ = VARDONEA($1,*$1,$2,$3); } + ; instnameList: - instnameParen { $$ = $1; } - | instnameList ',' instnameParen { $$ = $1->addNext($3); } - ; + instnameParen { $$ = $1; } + | instnameList ',' instnameParen { $$ = $1->addNext($3); } + ; instnameParen: - // // Must clone m_instParamp as may be comma'ed list of instances - id instRangeListE '(' cellpinList ')' { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, $4, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), + // // Must clone m_instParamp as may be comma'ed list of instances + id instRangeListE '(' cellpinList ')' { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, + *$1, GRAMMARP->m_instModule, $4, + AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } - | id instRangeListE { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, nullptr, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), + $$->trace(GRAMMARP->allTracingOn($1)); } + | id instRangeListE { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, + *$1, GRAMMARP->m_instModule, nullptr, + AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } - //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP - // // Adding above and switching to the Verilog-Perl syntax - // // causes a shift conflict due to use of idClassSel inside exprScope. - // // It also breaks allowing "id foo;" instantiation syntax. - ; + $$->trace(GRAMMARP->allTracingOn($1)); } + //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP + // // Adding above and switching to the Verilog-Perl syntax + // // causes a shift conflict due to use of idClassSel inside exprScope. + // // It also breaks allowing "id foo;" instantiation syntax. + ; instRangeListE: - /* empty */ { $$ = nullptr; } - | instRangeList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | instRangeList { $$ = $1; } + ; instRangeList: - instRange { $$ = $1; } - | instRangeList instRange { $$ = VN_CAST($1->addNextNull($2), Range); } - ; + instRange { $$ = $1; } + | instRangeList instRange { $$ = VN_CAST($1->addNextNull($2), Range); } + ; instRange: - '[' constExpr ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstSub($1, $2, new AstConst($1, 1))); } - | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } - ; + '[' constExpr ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstSub($1, $2, new AstConst($1, 1))); } + | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } + ; cellparamList: - { GRAMMARP->pinPush(); } cellparamItList { $$ = $2; GRAMMARP->pinPop(CRELINE()); } - ; + { GRAMMARP->pinPush(); } cellparamItList { $$ = $2; GRAMMARP->pinPop(CRELINE()); } + ; cellpinList: - {VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } - ; + {VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } + ; -cellparamItList: // IEEE: list_of_parameter_assignmente - cellparamItemE { $$ = $1; } - | cellparamItList ',' cellparamItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } - ; +cellparamItList: // IEEE: list_of_parameter_assignmente + cellparamItemE { $$ = $1; } + | cellparamItList ',' cellparamItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } + ; -cellpinItList: // IEEE: list_of_port_connections - cellpinItemE { $$ = $1; } - | cellpinItList ',' cellpinItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } - ; +cellpinItList: // IEEE: list_of_port_connections + cellpinItemE { $$ = $1; } + | cellpinItList ',' cellpinItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } + ; -cellparamItemE: // IEEE: named_parameter_assignment + empty - // // Note empty can match either () or (,); V3LinkCells cleans up () - /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(), PINNUMINC(), "", nullptr); } - | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",nullptr); } - | '.' idSVKwd { $$ = new AstPin($2,PINNUMINC(), *$2, - new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); - $$->svImplicit(true); } - | '.' idAny { $$ = new AstPin($2,PINNUMINC(), *$2, - new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); - $$->svImplicit(true); } - | '.' idAny '(' ')' { $$ = new AstPin($2,PINNUMINC(),*$2,nullptr); } - // // mintypmax is expanded here, as it might be a UDP or gate primitive - // // data_type for 'parameter type' hookups - | '.' idAny '(' exprOrDataType ')' { $$ = new AstPin($2, PINNUMINC(), *$2, $4); } - //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' { } - //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' { } - // // data_type for 'parameter type' hookups - | exprOrDataType { $$ = new AstPin(FILELINE_OR_CRE($1), PINNUMINC(), "", $1); } - //UNSUP exprOrDataType/*expr*/ ':' expr { } - //UNSUP exprOrDataType/*expr*/ ':' expr ':' expr { } - ; +cellparamItemE: // IEEE: named_parameter_assignment + empty + // // Note empty can match either () or (,); V3LinkCells cleans up () + /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(), PINNUMINC(), "", nullptr); } + | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",nullptr); } + | '.' idSVKwd { $$ = new AstPin($2,PINNUMINC(), *$2, + new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); + $$->svImplicit(true); } + | '.' idAny { $$ = new AstPin($2,PINNUMINC(), *$2, + new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); + $$->svImplicit(true); } + | '.' idAny '(' ')' { $$ = new AstPin($2,PINNUMINC(),*$2,nullptr); } + // // mintypmax is expanded here, as it might be a UDP or gate primitive + // // data_type for 'parameter type' hookups + | '.' idAny '(' exprOrDataType ')' { $$ = new AstPin($2, PINNUMINC(), *$2, $4); } + //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' { } + //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' { } + // // data_type for 'parameter type' hookups + | exprOrDataType { $$ = new AstPin(FILELINE_OR_CRE($1), PINNUMINC(), "", $1); } + //UNSUP exprOrDataType/*expr*/ ':' expr { } + //UNSUP exprOrDataType/*expr*/ ':' expr ':' expr { } + ; -cellpinItemE: // IEEE: named_port_connection + empty - // // Note empty can match either () or (,); V3LinkCells cleans up () - /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(), PINNUMINC(), "", nullptr); } - | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",nullptr); } - | '.' idSVKwd { $$ = new AstPin($2,PINNUMINC(),*$2,new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); $$->svImplicit(true);} - | '.' idAny { $$ = new AstPin($2,PINNUMINC(),*$2,new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); $$->svImplicit(true);} - | '.' idAny '(' ')' { $$ = new AstPin($2,PINNUMINC(),*$2,nullptr); } - // // mintypmax is expanded here, as it might be a UDP or gate primitive - //UNSUP pev_expr below - | '.' idAny '(' expr ')' { $$ = new AstPin($2,PINNUMINC(),*$2,$4); } - //UNSUP '.' idAny '(' pev_expr ':' expr ')' { } - //UNSUP '.' idAny '(' pev_expr ':' expr ':' expr ')' { } - // - | expr { $$ = new AstPin(FILELINE_OR_CRE($1),PINNUMINC(),"",$1); } - //UNSUP expr ':' expr { } - //UNSUP expr ':' expr ':' expr { } - ; +cellpinItemE: // IEEE: named_port_connection + empty + // // Note empty can match either () or (,); V3LinkCells cleans up () + /* empty: ',,' is legal */ { $$ = new AstPin(CRELINE(), PINNUMINC(), "", nullptr); } + | yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",nullptr); } + | '.' idSVKwd { $$ = new AstPin($2,PINNUMINC(),*$2,new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); $$->svImplicit(true);} + | '.' idAny { $$ = new AstPin($2,PINNUMINC(),*$2,new AstParseRef($2,VParseRefExp::PX_TEXT,*$2,nullptr,nullptr)); $$->svImplicit(true);} + | '.' idAny '(' ')' { $$ = new AstPin($2,PINNUMINC(),*$2,nullptr); } + // // mintypmax is expanded here, as it might be a UDP or gate primitive + //UNSUP pev_expr below + | '.' idAny '(' expr ')' { $$ = new AstPin($2,PINNUMINC(),*$2,$4); } + //UNSUP '.' idAny '(' pev_expr ':' expr ')' { } + //UNSUP '.' idAny '(' pev_expr ':' expr ':' expr ')' { } + // + | expr { $$ = new AstPin(FILELINE_OR_CRE($1),PINNUMINC(),"",$1); } + //UNSUP expr ':' expr { } + //UNSUP expr ':' expr ':' expr { } + ; //************************************************ // EventControl lists attr_event_controlE: - /* empty */ { $$ = nullptr; } - | attr_event_control { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | attr_event_control { $$ = $1; } + ; -attr_event_control: // ==IEEE: event_control - '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } - | '@' '(' '*' ')' { $$ = nullptr; } - | '@' '*' { $$ = nullptr; } - ; +attr_event_control: // ==IEEE: event_control + '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } + | '@' '(' '*' ')' { $$ = nullptr; } + | '@' '*' { $$ = nullptr; } + ; -event_control: // ==IEEE: event_control - '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } - | '@' '(' '*' ')' { $$ = nullptr; } - | '@' '*' { $$ = nullptr; } - // // IEEE: hierarchical_event_identifier - // // UNSUP below should be idClassSel - | '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */ - // // IEEE: sequence_instance - // // sequence_instance without parens matches idClassSel above. - // // Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr - // // For now we avoid this, as it's very unlikely someone would mix - // // 1995 delay with a sequence with parameters. - // // Alternatively split this out of event_control, and delay_or_event_controlE - // // and anywhere delay_or_event_controlE is called allow two expressions - //UNSUP '@' idClassSel '(' list_of_argumentsE ')' { } - ; +event_control: // ==IEEE: event_control + '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } + | '@' '(' '*' ')' { $$ = nullptr; } + | '@' '*' { $$ = nullptr; } + // // IEEE: hierarchical_event_identifier + // // UNSUP below should be idClassSel + | '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */ + // // IEEE: sequence_instance + // // sequence_instance without parens matches idClassSel above. + // // Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr + // // For now we avoid this, as it's very unlikely someone would mix + // // 1995 delay with a sequence with parameters. + // // Alternatively split this out of event_control, and delay_or_event_controlE + // // and anywhere delay_or_event_controlE is called allow two expressions + //UNSUP '@' idClassSel '(' list_of_argumentsE ')' { } + ; -event_expression: // IEEE: event_expression - split over several - //UNSUP // Below are all removed - senitem { $$ = $1; } - | event_expression yOR senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } - | event_expression ',' senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } /* Verilog 2001 */ - //UNSUP // Above are all removed, replace with: - //UNSUP ev_expr { $$ = $1; } - //UNSUP event_expression ',' ev_expr %prec yOR { $$ = VN_CAST($1->addNextNull($3), SenItem); } - ; +event_expression: // IEEE: event_expression - split over several + //UNSUP // Below are all removed + senitem { $$ = $1; } + | event_expression yOR senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } + | event_expression ',' senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } /* Verilog 2001 */ + //UNSUP // Above are all removed, replace with: + //UNSUP ev_expr { $$ = $1; } + //UNSUP event_expression ',' ev_expr %prec yOR { $$ = VN_CAST($1->addNextNull($3), SenItem); } + ; -senitem: // IEEE: part of event_expression, non-'OR' ',' terms - senitemEdge { $$ = $1; } - | senitemVar { $$ = $1; } - | '(' senitem ')' { $$ = $2; } - //UNSUP expr { UNSUP } - | '{' event_expression '}' { $$ = $2; } - | senitem yP_ANDAND senitem { $$ = new AstSenItem($2, AstSenItem::Illegal()); } - //UNSUP expr yIFF expr { UNSUP } - // Since expr is unsupported we allow and ignore constants (removed in V3Const) - | yaINTNUM { $$ = nullptr; } - | yaFLOATNUM { $$ = nullptr; } - ; +senitem: // IEEE: part of event_expression, non-'OR' ',' terms + senitemEdge { $$ = $1; } + | senitemVar { $$ = $1; } + | '(' senitem ')' { $$ = $2; } + //UNSUP expr { UNSUP } + | '{' event_expression '}' { $$ = $2; } + | senitem yP_ANDAND senitem { $$ = new AstSenItem($2, AstSenItem::Illegal()); } + //UNSUP expr yIFF expr { UNSUP } + // Since expr is unsupported we allow and ignore constants (removed in V3Const) + | yaINTNUM { $$ = nullptr; } + | yaFLOATNUM { $$ = nullptr; } + ; senitemVar: - idClassSel { $$ = new AstSenItem($1->fileline(), VEdgeType::ET_ANYEDGE, $1); } - ; + idClassSel { $$ = new AstSenItem($1->fileline(), VEdgeType::ET_ANYEDGE, $1); } + ; -senitemEdge: // IEEE: part of event_expression - //UNSUP // Below are all removed - yPOSEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $2); } - | yNEGEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $2); } - | yEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $2); } - | yPOSEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $3); } - | yNEGEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $3); } - | yEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $3); } - //UNSUP // Above are all removed, replace with: - //UNSUP yPOSEDGE expr { UNSUP } - //UNSUP yPOSEDGE expr yIFF expr { UNSUP } - //UNSUP yNEGEDGE expr { UNSUP } - //UNSUP yNEGEDGE expr yIFF expr { UNSUP } - //UNSUP yEDGE expr { UNSUP } - //UNSUP yEDGE expr yIFF expr { UNSUP } - ; +senitemEdge: // IEEE: part of event_expression + //UNSUP // Below are all removed + yPOSEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $2); } + | yNEGEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $2); } + | yEDGE idClassSel { $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $2); } + | yPOSEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_POSEDGE, $3); } + | yNEGEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_NEGEDGE, $3); } + | yEDGE '(' idClassSel ')' { $$ = new AstSenItem($1, VEdgeType::ET_BOTHEDGE, $3); } + //UNSUP // Above are all removed, replace with: + //UNSUP yPOSEDGE expr { UNSUP } + //UNSUP yPOSEDGE expr yIFF expr { UNSUP } + //UNSUP yNEGEDGE expr { UNSUP } + //UNSUP yNEGEDGE expr yIFF expr { UNSUP } + //UNSUP yEDGE expr { UNSUP } + //UNSUP yEDGE expr yIFF expr { UNSUP } + ; //************************************************ // Statements -stmtBlock: // IEEE: statement + seq_block + par_block - stmt { $$ = $1; } - ; +stmtBlock: // IEEE: statement + seq_block + par_block + stmt { $$ = $1; } + ; -seq_block: // ==IEEE: seq_block - // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. - // // So need AstBegin's even if unnamed to scope variables down - seq_blockFront blockDeclStmtListE yEND endLabelE - { $$ = $1; $1->addStmtsp($2); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - ; +seq_block: // ==IEEE: seq_block + // // IEEE doesn't allow declarations in unnamed blocks, but several simulators do. + // // So need AstBegin's even if unnamed to scope variables down + seq_blockFront blockDeclStmtListE yEND endLabelE + { $$ = $1; $1->addStmtsp($2); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + ; -seq_blockPreId: // IEEE: seq_block, but called with leading ID - seq_blockFrontPreId blockDeclStmtListE yEND endLabelE - { $$ = $1; $1->addStmtsp($2); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - ; +seq_blockPreId: // IEEE: seq_block, but called with leading ID + seq_blockFrontPreId blockDeclStmtListE yEND endLabelE + { $$ = $1; $1->addStmtsp($2); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + ; -par_block: // ==IEEE: par_block - par_blockFront blockDeclStmtListE yJOIN endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - | par_blockFront blockDeclStmtListE yJOIN_ANY endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_ANY); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - | par_blockFront blockDeclStmtListE yJOIN_NONE endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_NONE); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - ; +par_block: // ==IEEE: par_block + par_blockFront blockDeclStmtListE yJOIN endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + | par_blockFront blockDeclStmtListE yJOIN_ANY endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_ANY); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + | par_blockFront blockDeclStmtListE yJOIN_NONE endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_NONE); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + ; -par_blockPreId: // ==IEEE: par_block but called with leading ID - par_blockFrontPreId blockDeclStmtListE yJOIN endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - | par_blockFrontPreId blockDeclStmtListE yJOIN_ANY endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_ANY); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - | par_blockFrontPreId blockDeclStmtListE yJOIN_NONE endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_NONE); - SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } - ; +par_blockPreId: // ==IEEE: par_block but called with leading ID + par_blockFrontPreId blockDeclStmtListE yJOIN endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + | par_blockFrontPreId blockDeclStmtListE yJOIN_ANY endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_ANY); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + | par_blockFrontPreId blockDeclStmtListE yJOIN_NONE endLabelE + { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_NONE); + SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } + ; -seq_blockFront: // IEEE: part of seq_block - yBEGIN { $$ = new AstBegin($1,"",nullptr); SYMP->pushNew($$); } - | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, nullptr); SYMP->pushNew($$); } - ; +seq_blockFront: // IEEE: part of seq_block + yBEGIN { $$ = new AstBegin($1,"",nullptr); SYMP->pushNew($$); } + | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, nullptr); SYMP->pushNew($$); } + ; -par_blockFront: // IEEE: part of par_block - yFORK { $$ = new AstFork($1, "", nullptr); SYMP->pushNew($$); } - | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstFork($3, *$3, nullptr); SYMP->pushNew($$); } - ; +par_blockFront: // IEEE: part of par_block + yFORK { $$ = new AstFork($1, "", nullptr); SYMP->pushNew($$); } + | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstFork($3, *$3, nullptr); SYMP->pushNew($$); } + ; -seq_blockFrontPreId: // IEEE: part of seq_block/stmt with leading id - id/*block_identifier*/ yP_COLON__BEGIN yBEGIN - { $$ = new AstBegin($3, *$1, nullptr); SYMP->pushNew($$); } - ; +seq_blockFrontPreId: // IEEE: part of seq_block/stmt with leading id + id/*block_identifier*/ yP_COLON__BEGIN yBEGIN + { $$ = new AstBegin($3, *$1, nullptr); SYMP->pushNew($$); } + ; -par_blockFrontPreId: // IEEE: part of par_block/stmt with leading id - id/*block_identifier*/ yP_COLON__FORK yFORK - { $$ = new AstFork($3, *$1, nullptr); SYMP->pushNew($$); } - ; +par_blockFrontPreId: // IEEE: part of par_block/stmt with leading id + id/*block_identifier*/ yP_COLON__FORK yFORK + { $$ = new AstFork($3, *$1, nullptr); SYMP->pushNew($$); } + ; -blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } - // // The spec seems to suggest a empty declaration isn't ok, but most simulators take it - block_item_declarationList { $$ = $1; } - | block_item_declarationList stmtList { $$ = $1->addNextNull($2); } - | stmtList { $$ = $1; } - ; +blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } + // // The spec seems to suggest a empty declaration isn't ok, but most simulators take it + block_item_declarationList { $$ = $1; } + | block_item_declarationList stmtList { $$ = $1->addNextNull($2); } + | stmtList { $$ = $1; } + ; -blockDeclStmtListE: // IEEE: [ { block_item_declaration } { statement or null } ] - /*empty*/ { $$ = nullptr; } - | blockDeclStmtList { $$ = $1; } - ; +blockDeclStmtListE: // IEEE: [ { block_item_declaration } { statement or null } ] + /*empty*/ { $$ = nullptr; } + | blockDeclStmtList { $$ = $1; } + ; -block_item_declarationList: // IEEE: [ block_item_declaration ] - block_item_declaration { $$ = $1; } - | block_item_declarationList block_item_declaration { $$ = $1->addNextNull($2); } - ; +block_item_declarationList: // IEEE: [ block_item_declaration ] + block_item_declaration { $$ = $1; } + | block_item_declarationList block_item_declaration { $$ = $1->addNextNull($2); } + ; -block_item_declaration: // ==IEEE: block_item_declaration - data_declaration { $$ = $1; } - | parameter_declaration ';' { $$ = $1; } - //UNSUP let_declaration { $$ = $1; } - ; +block_item_declaration: // ==IEEE: block_item_declaration + data_declaration { $$ = $1; } + | parameter_declaration ';' { $$ = $1; } + //UNSUP let_declaration { $$ = $1; } + ; stmtList: - stmtBlock { $$ = $1; } - | stmtList stmtBlock { $$ = $2 ? $1->addNext($2) : $1; } - ; + stmtBlock { $$ = $1; } + | stmtList stmtBlock { $$ = $2 ? $1->addNext($2) : $1; } + ; -stmt: // IEEE: statement_or_null == function_statement_or_null - statement_item { $$ = $1; } - // // S05 block creation rule - | id/*block_identifier*/ ':' statement_item { $$ = new AstBegin($1, *$1, $3); } - // // from _or_null - | ';' { $$ = nullptr; } - // // labeled par_block/seq_block with leading ':' - | seq_blockPreId { $$ = $1; } - | par_blockPreId { $$ = $1; } - ; +stmt: // IEEE: statement_or_null == function_statement_or_null + statement_item { $$ = $1; } + // // S05 block creation rule + | id/*block_identifier*/ ':' statement_item { $$ = new AstBegin($1, *$1, $3); } + // // from _or_null + | ';' { $$ = nullptr; } + // // labeled par_block/seq_block with leading ':' + | seq_blockPreId { $$ = $1; } + | par_blockPreId { $$ = $1; } + ; -statement_item: // IEEE: statement_item - // // IEEE: operator_assignment - foperator_assignment ';' { $$ = $1; } - // - // // IEEE: blocking_assignment - // // 1800-2009 restricts LHS of assignment to new to not have a range - // // This is ignored to avoid conflicts - | fexprLvalue '=' class_new ';' { $$ = new AstAssign($2, $1, $3); } - | fexprLvalue '=' dynamic_array_new ';' { $$ = new AstAssign($2, $1, $3); } - // - // // IEEE: nonblocking_assignment - | fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } - //UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } - // - // // IEEE: procedural_continuous_assignment - | yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } - //UNSUP: delay_or_event_controlE above - | yDEASSIGN variable_lvalue ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); } - | yFORCE variable_lvalue '=' expr ';' - { $$ = new AstAssignForce{$1, $2, $4}; v3Global.setHasForceableSignals(); } - | yRELEASE variable_lvalue ';' - { $$ = new AstRelease{$1, $2}; v3Global.setHasForceableSignals(); } - // - // // IEEE: case_statement - | unique_priorityE caseStart caseAttrE case_itemListE yENDCASE { $$ = $2; if ($4) $2->addItemsp($4); - if ($1 == uniq_UNIQUE) $2->uniquePragma(true); - if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); - if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } - //UNSUP caseStart caseAttrE yMATCHES case_patternListE yENDCASE { } - | unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE - { $$ = $2; if ($5) $2->addItemsp($5); - if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez"); - $2->caseInsideSet(); - if ($1 == uniq_UNIQUE) $2->uniquePragma(true); - if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); - if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } - // - // // IEEE: conditional_statement - | unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE - { AstIf* const newp = new AstIf{$2, $4, $6}; - $$ = newp; - if ($1 == uniq_UNIQUE) newp->uniquePragma(true); - if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true); - if ($1 == uniq_PRIORITY) newp->priorityPragma(true); } - | unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock - { AstIf* const newp = new AstIf{$2, $4, $6, $8}; - $$ = newp; - if ($1 == uniq_UNIQUE) newp->uniquePragma(true); - if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true); - if ($1 == uniq_PRIORITY) newp->priorityPragma(true); } - // - | finc_or_dec_expression ';' { $$ = $1; } - // // IEEE: inc_or_dec_expression - // // Below under expr - // - // // IEEE: subroutine_call_statement - // // IEEE says we then expect a function call - // // (function_subroutine_callNoMethod), but rest of - // // the code expects an AstTask when used as a statement, - // // so parse as if task - // // Alternative would be shim with new AstVoidStmt. - | yVOID yP_TICK '(' task_subroutine_callNoMethod ')' ';' - { $$ = $4; - FileLine* const newfl = new FileLine{$$->fileline()}; - newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); - $$->fileline(newfl); } - | yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';' - { $$ = new AstDot{$5, false, $4, $6}; - FileLine* const newfl = new FileLine{$6->fileline()}; - newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); - $6->fileline(newfl); } - // // Expr included here to resolve our not knowing what is a method call - // // Expr here must result in a subroutine_call - | task_subroutine_callNoMethod ';' { $$ = $1; } - //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } - | fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($2, false, $1, $3); } - //UNSUP fexprScope ';' { UNSUP } - // // Not here in IEEE; from class_constructor_declaration - // // Because we've joined class_constructor_declaration into generic functions - // // Way over-permissive; - // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] - | fexpr '.' class_new ';' { $$ = new AstDot($2, false, $1, $3); } - // - | statementVerilatorPragmas { $$ = $1; } - // - // // IEEE: disable_statement - | yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); } - | yDISABLE yFORK ';' { $$ = new AstDisableFork($1); } - // // IEEE: event_trigger - | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' - { // AssignDly because we don't have stratified queue, and need to - // read events, clear next event, THEN apply this set - $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::BitTrue())); } - //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } - // // IEEE remove below - | yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';' - { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::BitTrue())); } - // - // // IEEE: loop_statement - | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1, AstConst::BitTrue()), $2); } - | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat{$1, $3, $5}; } - | yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile{$1, $3, $5}; } - // // for's first ';' is in for_initialization - | statementFor { $$ = $1; } - | yDO stmtBlock yWHILE '(' expr ')' ';' { if ($2) { - $$ = $2->cloneTree(true); - $$->addNext(new AstWhile($1,$5,$2)); - } - else $$ = new AstWhile($1,$5); } - // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 - | yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); } - // - // // IEEE: jump_statement - | yRETURN ';' { $$ = new AstReturn($1); } - | yRETURN expr ';' { $$ = new AstReturn($1,$2); } - | yBREAK ';' { $$ = new AstBreak($1); } - | yCONTINUE ';' { $$ = new AstContinue($1); } - // - | par_block { $$ = $1; } - // // IEEE: procedural_timing_control_statement + procedural_timing_control - | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } - | event_control stmtBlock { $$ = new AstTimingControl(FILELINE_OR_CRE($1), $1, $2); } - //UNSUP cycle_delay stmtBlock { UNSUP } - // - | seq_block { $$ = $1; } - // - // // IEEE: wait_statement - | yWAIT '(' expr ')' stmtBlock { $$ = new AstWait($1, $3, $5); } - | yWAIT yFORK ';' { $$ = new AstWaitFork($1); } - //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP } - // - // // IEEE: procedural_assertion_statement - | procedural_assertion_statement { $$ = $1; } - // - // // IEEE: clocking_drive ';' - // // Pattern w/o cycle_delay handled by nonblocking_assign above - // // clockvar_expression made to fexprLvalue to prevent reduce conflict - // // Note LTE in this context is highest precedence, so first on left wins - //UNSUP cycle_delay fexprLvalue yP_LTE ';' { UNSUP } - //UNSUP fexprLvalue yP_LTE cycle_delay expr ';' { UNSUP } - // - //UNSUP randsequence_statement { $$ = $1; } - // - // // IEEE: randcase_statement - | yRANDCASE case_itemList yENDCASE - { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 randcase statements"); } - // - //UNSUP expect_property_statement { $$ = $1; } - // - | error ';' { $$ = nullptr; } - ; +statement_item: // IEEE: statement_item + // // IEEE: operator_assignment + foperator_assignment ';' { $$ = $1; } + // + // // IEEE: blocking_assignment + // // 1800-2009 restricts LHS of assignment to new to not have a range + // // This is ignored to avoid conflicts + | fexprLvalue '=' class_new ';' { $$ = new AstAssign($2, $1, $3); } + | fexprLvalue '=' dynamic_array_new ';' { $$ = new AstAssign($2, $1, $3); } + // + // // IEEE: nonblocking_assignment + | fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } + //UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } + // + // // IEEE: procedural_continuous_assignment + | yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } + //UNSUP: delay_or_event_controlE above + | yDEASSIGN variable_lvalue ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); } + | yFORCE variable_lvalue '=' expr ';' + { $$ = new AstAssignForce{$1, $2, $4}; v3Global.setHasForceableSignals(); } + | yRELEASE variable_lvalue ';' + { $$ = new AstRelease{$1, $2}; v3Global.setHasForceableSignals(); } + // + // // IEEE: case_statement + | unique_priorityE caseStart caseAttrE case_itemListE yENDCASE { $$ = $2; if ($4) $2->addItemsp($4); + if ($1 == uniq_UNIQUE) $2->uniquePragma(true); + if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); + if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } + //UNSUP caseStart caseAttrE yMATCHES case_patternListE yENDCASE { } + | unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE + { $$ = $2; if ($5) $2->addItemsp($5); + if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez"); + $2->caseInsideSet(); + if ($1 == uniq_UNIQUE) $2->uniquePragma(true); + if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); + if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } + // + // // IEEE: conditional_statement + | unique_priorityE yIF '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE + { AstIf* const newp = new AstIf{$2, $4, $6}; + $$ = newp; + if ($1 == uniq_UNIQUE) newp->uniquePragma(true); + if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true); + if ($1 == uniq_PRIORITY) newp->priorityPragma(true); } + | unique_priorityE yIF '(' expr ')' stmtBlock yELSE stmtBlock + { AstIf* const newp = new AstIf{$2, $4, $6, $8}; + $$ = newp; + if ($1 == uniq_UNIQUE) newp->uniquePragma(true); + if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true); + if ($1 == uniq_PRIORITY) newp->priorityPragma(true); } + // + | finc_or_dec_expression ';' { $$ = $1; } + // // IEEE: inc_or_dec_expression + // // Below under expr + // + // // IEEE: subroutine_call_statement + // // IEEE says we then expect a function call + // // (function_subroutine_callNoMethod), but rest of + // // the code expects an AstTask when used as a statement, + // // so parse as if task + // // Alternative would be shim with new AstVoidStmt. + | yVOID yP_TICK '(' task_subroutine_callNoMethod ')' ';' + { $$ = $4; + FileLine* const newfl = new FileLine{$$->fileline()}; + newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); + $$->fileline(newfl); } + | yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';' + { $$ = new AstDot{$5, false, $4, $6}; + FileLine* const newfl = new FileLine{$6->fileline()}; + newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); + $6->fileline(newfl); } + // // Expr included here to resolve our not knowing what is a method call + // // Expr here must result in a subroutine_call + | task_subroutine_callNoMethod ';' { $$ = $1; } + //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } + | fexpr '.' task_subroutine_callNoMethod ';' { $$ = new AstDot($2, false, $1, $3); } + //UNSUP fexprScope ';' { UNSUP } + // // Not here in IEEE; from class_constructor_declaration + // // Because we've joined class_constructor_declaration into generic functions + // // Way over-permissive; + // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] + | fexpr '.' class_new ';' { $$ = new AstDot($2, false, $1, $3); } + // + | statementVerilatorPragmas { $$ = $1; } + // + // // IEEE: disable_statement + | yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); } + | yDISABLE yFORK ';' { $$ = new AstDisableFork($1); } + // // IEEE: event_trigger + | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' + { // AssignDly because we don't have stratified queue, and need to + // read events, clear next event, THEN apply this set + $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::BitTrue())); } + //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } + // // IEEE remove below + | yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';' + { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::BitTrue())); } + // + // // IEEE: loop_statement + | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1, AstConst::BitTrue()), $2); } + | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat{$1, $3, $5}; } + | yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile{$1, $3, $5}; } + // // for's first ';' is in for_initialization + | statementFor { $$ = $1; } + | yDO stmtBlock yWHILE '(' expr ')' ';' { if ($2) { + $$ = $2->cloneTree(true); + $$->addNext(new AstWhile($1,$5,$2)); + } + else $$ = new AstWhile($1,$5); } + // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 + | yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); } + // + // // IEEE: jump_statement + | yRETURN ';' { $$ = new AstReturn($1); } + | yRETURN expr ';' { $$ = new AstReturn($1,$2); } + | yBREAK ';' { $$ = new AstBreak($1); } + | yCONTINUE ';' { $$ = new AstContinue($1); } + // + | par_block { $$ = $1; } + // // IEEE: procedural_timing_control_statement + procedural_timing_control + | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } + | event_control stmtBlock { $$ = new AstTimingControl(FILELINE_OR_CRE($1), $1, $2); } + //UNSUP cycle_delay stmtBlock { UNSUP } + // + | seq_block { $$ = $1; } + // + // // IEEE: wait_statement + | yWAIT '(' expr ')' stmtBlock { $$ = new AstWait($1, $3, $5); } + | yWAIT yFORK ';' { $$ = new AstWaitFork($1); } + //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP } + // + // // IEEE: procedural_assertion_statement + | procedural_assertion_statement { $$ = $1; } + // + // // IEEE: clocking_drive ';' + // // Pattern w/o cycle_delay handled by nonblocking_assign above + // // clockvar_expression made to fexprLvalue to prevent reduce conflict + // // Note LTE in this context is highest precedence, so first on left wins + //UNSUP cycle_delay fexprLvalue yP_LTE ';' { UNSUP } + //UNSUP fexprLvalue yP_LTE cycle_delay expr ';' { UNSUP } + // + //UNSUP randsequence_statement { $$ = $1; } + // + // // IEEE: randcase_statement + | yRANDCASE case_itemList yENDCASE + { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 randcase statements"); } + // + //UNSUP expect_property_statement { $$ = $1; } + // + | error ';' { $$ = nullptr; } + ; -statementFor: // IEEE: part of statement - yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1, "", $3, false, true); - $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } - | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1, "", $3, false, true); - $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::BitTrue()), $7, $5)); } - ; +statementFor: // IEEE: part of statement + yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock + { $$ = new AstBegin($1, "", $3, false, true); + $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } + | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock + { $$ = new AstBegin($1, "", $3, false, true); + $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::BitTrue()), $7, $5)); } + ; statementVerilatorPragmas: - yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,VPragmaType::COVERAGE_BLOCK_OFF); } - ; + yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,VPragmaType::COVERAGE_BLOCK_OFF); } + ; //UNSUPoperator_assignment: // IEEE: operator_assignment -//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { } -//UNSUP | ~f~exprLvalue yP_PLUSEQ expr { } -//UNSUP | ~f~exprLvalue yP_MINUSEQ expr { } -//UNSUP | ~f~exprLvalue yP_TIMESEQ expr { } -//UNSUP | ~f~exprLvalue yP_DIVEQ expr { } -//UNSUP | ~f~exprLvalue yP_MODEQ expr { } -//UNSUP | ~f~exprLvalue yP_ANDEQ expr { } -//UNSUP | ~f~exprLvalue yP_OREQ expr { } -//UNSUP | ~f~exprLvalue yP_XOREQ expr { } -//UNSUP | ~f~exprLvalue yP_SLEFTEQ expr { } -//UNSUP | ~f~exprLvalue yP_SRIGHTEQ expr { } -//UNSUP | ~f~exprLvalue yP_SSRIGHTEQ expr { } -//UNSUP ; +//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { } +//UNSUP | ~f~exprLvalue yP_PLUSEQ expr { } +//UNSUP | ~f~exprLvalue yP_MINUSEQ expr { } +//UNSUP | ~f~exprLvalue yP_TIMESEQ expr { } +//UNSUP | ~f~exprLvalue yP_DIVEQ expr { } +//UNSUP | ~f~exprLvalue yP_MODEQ expr { } +//UNSUP | ~f~exprLvalue yP_ANDEQ expr { } +//UNSUP | ~f~exprLvalue yP_OREQ expr { } +//UNSUP | ~f~exprLvalue yP_XOREQ expr { } +//UNSUP | ~f~exprLvalue yP_SLEFTEQ expr { } +//UNSUP | ~f~exprLvalue yP_SRIGHTEQ expr { } +//UNSUP | ~f~exprLvalue yP_SSRIGHTEQ expr { } +//UNSUP ; -foperator_assignment: // IEEE: operator_assignment (for first part of expression) - fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); } - | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd($3,$1,$5); } - | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } - // - //UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP } - //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } - | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } - | fexprLvalue yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } - //UNSUP replace above with: - //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} - ; +foperator_assignment: // IEEE: operator_assignment (for first part of expression) + fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); } + | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd($3,$1,$5); } + | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } + // + //UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP } + //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } + | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); } + | fexprLvalue yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } + //UNSUP replace above with: + //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} + ; -inc_or_dec_expression: // ==IEEE: inc_or_dec_expression - // // Need fexprScope instead of variable_lvalue to prevent conflict - ~l~exprScope yP_PLUSPLUS - { $$ = $1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } - | ~l~exprScope yP_MINUSMINUS - { $$ = $1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } - // // Need expr instead of variable_lvalue to prevent conflict - | yP_PLUSPLUS expr - { $$ = $1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } - | yP_MINUSMINUS expr - { $$ = $1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } - ; +inc_or_dec_expression: // ==IEEE: inc_or_dec_expression + // // Need fexprScope instead of variable_lvalue to prevent conflict + ~l~exprScope yP_PLUSPLUS + { $$ = $1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } + | ~l~exprScope yP_MINUSMINUS + { $$ = $1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse(), "'b1"}, $1, $1->cloneTree(true)}; } + // // Need expr instead of variable_lvalue to prevent conflict + | yP_PLUSPLUS expr + { $$ = $1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } + | yP_MINUSMINUS expr + { $$ = $1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse(), "'b1"}, $2, $2->cloneTree(true)}; } + ; -finc_or_dec_expression: // ==IEEE: inc_or_dec_expression - BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} - ; +finc_or_dec_expression: // ==IEEE: inc_or_dec_expression + BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} + ; //UNSUPsinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} +//UNSUP ; //UNSUPpinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} +//UNSUP ; //UNSUPev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for ev_expr) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g}) // {copied} +//UNSUP ; //UNSUPpev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for pev_expr) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g}) // {copied} +//UNSUP ; -class_new: // ==IEEE: class_new - // // Special precence so (...) doesn't match expr - yNEW__ETC { $$ = new AstNew($1, nullptr); } - | yNEW__ETC expr { $$ = new AstNewCopy($1, $2); } - | yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1, $3); } - ; +class_new: // ==IEEE: class_new + // // Special precence so (...) doesn't match expr + yNEW__ETC { $$ = new AstNew($1, nullptr); } + | yNEW__ETC expr { $$ = new AstNewCopy($1, $2); } + | yNEW__PAREN '(' list_of_argumentsE ')' { $$ = new AstNew($1, $3); } + ; -dynamic_array_new: // ==IEEE: dynamic_array_new - yNEW__ETC '[' expr ']' { $$ = new AstNewDynamic($1, $3, nullptr); } - | yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNewDynamic($1, $3, $6); } - ; +dynamic_array_new: // ==IEEE: dynamic_array_new + yNEW__ETC '[' expr ']' { $$ = new AstNewDynamic($1, $3, nullptr); } + | yNEW__ETC '[' expr ']' '(' expr ')' { $$ = new AstNewDynamic($1, $3, $6); } + ; //************************************************ // Case/If -unique_priorityE: // IEEE: unique_priority + empty - /*empty*/ { $$ = uniq_NONE; } - | yPRIORITY { $$ = uniq_PRIORITY; } - | yUNIQUE { $$ = uniq_UNIQUE; } - | yUNIQUE0 { $$ = uniq_UNIQUE0; } - ; +unique_priorityE: // IEEE: unique_priority + empty + /*empty*/ { $$ = uniq_NONE; } + | yPRIORITY { $$ = uniq_PRIORITY; } + | yUNIQUE { $$ = uniq_UNIQUE; } + | yUNIQUE0 { $$ = uniq_UNIQUE0; } + ; -caseStart: // IEEE: part of case_statement - yCASE '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASE,$3,nullptr); } - | yCASEX '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEX,$3,nullptr); } - | yCASEZ '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEZ,$3,nullptr); } - ; +caseStart: // IEEE: part of case_statement + yCASE '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASE,$3,nullptr); } + | yCASEX '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEX,$3,nullptr); } + | yCASEZ '(' expr ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase($1,VCaseType::CT_CASEZ,$3,nullptr); } + ; caseAttrE: - /*empty*/ { } - | caseAttrE yVL_FULL_CASE { GRAMMARP->m_caseAttrp->fullPragma(true); } - | caseAttrE yVL_PARALLEL_CASE { GRAMMARP->m_caseAttrp->parallelPragma(true); } - ; + /*empty*/ { } + | caseAttrE yVL_FULL_CASE { GRAMMARP->m_caseAttrp->fullPragma(true); } + | caseAttrE yVL_PARALLEL_CASE { GRAMMARP->m_caseAttrp->parallelPragma(true); } + ; //UNSUPcase_patternListE: // IEEE: case_pattern_item -//UNSUP // &&& is part of expr so aliases to case_itemList -//UNSUP case_itemListE { $$ = $1; } -//UNSUP ; +//UNSUP // &&& is part of expr so aliases to case_itemList +//UNSUP case_itemListE { $$ = $1; } +//UNSUP ; -case_itemListE: // IEEE: [ { case_item } ] - /* empty */ { $$ = nullptr; } - | case_itemList { $$ = $1; } - ; +case_itemListE: // IEEE: [ { case_item } ] + /* empty */ { $$ = nullptr; } + | case_itemList { $$ = $1; } + ; -case_insideListE: // IEEE: [ { case_inside_item } ] - /* empty */ { $$ = nullptr; } - | case_inside_itemList { $$ = $1; } - ; +case_insideListE: // IEEE: [ { case_inside_item } ] + /* empty */ { $$ = nullptr; } + | case_inside_itemList { $$ = $1; } + ; -case_itemList: // IEEE: { case_item + ... } - caseCondList colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } - | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } - | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } - | case_itemList caseCondList colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } - | case_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } - | case_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } - ; +case_itemList: // IEEE: { case_item + ... } + caseCondList colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } + | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } + | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } + | case_itemList caseCondList colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } + | case_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } + | case_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } + ; -case_inside_itemList: // IEEE: { case_inside_item + open_range_list ... } - open_range_list colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } - | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } - | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } - | case_inside_itemList open_range_list colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } - | case_inside_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } - | case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } - ; +case_inside_itemList: // IEEE: { case_inside_item + open_range_list ... } + open_range_list colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } + | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } + | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } + | case_inside_itemList open_range_list colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } + | case_inside_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } + | case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } + ; -open_range_list: // ==IEEE: open_range_list + open_value_range - open_value_range { $$ = $1; } - | open_range_list ',' open_value_range { $$ = $1; $1->addNext($3); } - ; +open_range_list: // ==IEEE: open_range_list + open_value_range + open_value_range { $$ = $1; } + | open_range_list ',' open_value_range { $$ = $1; $1->addNext($3); } + ; -open_value_range: // ==IEEE: open_value_range - value_range { $$ = $1; } - ; +open_value_range: // ==IEEE: open_value_range + value_range { $$ = $1; } + ; -value_range: // ==IEEE: value_range - expr { $$ = $1; } - | '[' expr ':' expr ']' { $$ = new AstInsideRange($1, $2, $4); } - ; +value_range: // ==IEEE: value_range + expr { $$ = $1; } + | '[' expr ':' expr ']' { $$ = new AstInsideRange($1, $2, $4); } + ; //UNSUPcovergroup_value_range: // ==IEEE-2012: covergroup_value_range -//UNSUP cgexpr { $$ = $1; } -//UNSUP | '[' cgexpr ':' cgexpr ']' { } -//UNSUP ; +//UNSUP cgexpr { $$ = $1; } +//UNSUP | '[' cgexpr ':' cgexpr ']' { } +//UNSUP ; -caseCondList: // IEEE: part of case_item - expr { $$ = $1; } - | caseCondList ',' expr { $$ = $1; $1->addNext($3); } - ; +caseCondList: // IEEE: part of case_item + expr { $$ = $1; } + | caseCondList ',' expr { $$ = $1; $1->addNext($3); } + ; -patternNoExpr: // IEEE: pattern **Excluding Expr* - '.' id/*variable*/ - { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } - | yP_DOTSTAR - { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } - // // IEEE: "expr" excluded; expand in callers - // // "yTAGGED id [expr]" Already part of expr - //UNSUP yTAGGED id/*member_identifier*/ patternNoExpr - //UNSUP { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } - // // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern - ; +patternNoExpr: // IEEE: pattern **Excluding Expr* + '.' id/*variable*/ + { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } + | yP_DOTSTAR + { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } + // // IEEE: "expr" excluded; expand in callers + // // "yTAGGED id [expr]" Already part of expr + //UNSUP yTAGGED id/*member_identifier*/ patternNoExpr + //UNSUP { $$ = nullptr; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } + // // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern + ; -patternList: // IEEE: part of pattern - patternOne { $$ = $1; } - | patternList ',' patternOne { $$ = $1->addNextNull($3); } - ; +patternList: // IEEE: part of pattern + patternOne { $$ = $1; } + | patternList ',' patternOne { $$ = $1->addNextNull($3); } + ; -patternOne: // IEEE: part of pattern - expr - { if ($1) $$ = new AstPatMember{$1->fileline(), $1, nullptr, nullptr}; else $$ = nullptr; } - | expr '{' argsExprList '}' { $$ = new AstPatMember{$2, $3, nullptr, $1}; } - | patternNoExpr { $$ = $1; } - ; +patternOne: // IEEE: part of pattern + expr + { if ($1) $$ = new AstPatMember{$1->fileline(), $1, nullptr, nullptr}; else $$ = nullptr; } + | expr '{' argsExprList '}' { $$ = new AstPatMember{$2, $3, nullptr, $1}; } + | patternNoExpr { $$ = $1; } + ; -patternMemberList: // IEEE: part of pattern and assignment_pattern - patternMemberOne { $$ = $1; } - | patternMemberList ',' patternMemberOne { $$ = $1->addNextNull($3); } - ; +patternMemberList: // IEEE: part of pattern and assignment_pattern + patternMemberOne { $$ = $1; } + | patternMemberList ',' patternMemberOne { $$ = $1->addNextNull($3); } + ; -patternMemberOne: // IEEE: part of pattern and assignment_pattern - patternKey ':' expr { $$ = new AstPatMember($1->fileline(),$3,$1,nullptr); } - | patternKey ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } - // // From assignment_pattern_key - | yDEFAULT ':' expr { $$ = new AstPatMember($1,$3,nullptr,nullptr); $$->isDefault(true); } - | yDEFAULT ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } - ; +patternMemberOne: // IEEE: part of pattern and assignment_pattern + patternKey ':' expr { $$ = new AstPatMember($1->fileline(),$3,$1,nullptr); } + | patternKey ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } + // // From assignment_pattern_key + | yDEFAULT ':' expr { $$ = new AstPatMember($1,$3,nullptr,nullptr); $$->isDefault(true); } + | yDEFAULT ':' patternNoExpr { $$ = nullptr; BBUNSUP($2, "Unsupported: '{} .* patterns"); } + ; -patternKey: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key - // // IEEE: structure_pattern_key - // // id/*member*/ is part of constExpr below - //UNSUP constExpr { $$ = $1; } - // // IEEE: assignment_pattern_key - //UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$ = $1; } - // // simple_type reference looks like constExpr - // // Verilator: - // // The above expressions cause problems because "foo" may be a constant identifier - // // (if array) or a reference to the "foo"member (if structure) - // // So for now we only allow a true constant number, or a identifier which we treat as a structure member name - yaINTNUM { $$ = new AstConst($1,*$1); } - | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } - | id { $$ = new AstText($1,*$1); } - | strAsInt { $$ = $1; } - ; +patternKey: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key + // // IEEE: structure_pattern_key + // // id/*member*/ is part of constExpr below + //UNSUP constExpr { $$ = $1; } + // // IEEE: assignment_pattern_key + //UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$ = $1; } + // // simple_type reference looks like constExpr + // // Verilator: + // // The above expressions cause problems because "foo" may be a constant identifier + // // (if array) or a reference to the "foo"member (if structure) + // // So for now we only allow a true constant number, or a identifier which we treat as a structure member name + yaINTNUM { $$ = new AstConst($1,*$1); } + | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } + | id { $$ = new AstText($1,*$1); } + | strAsInt { $$ = $1; } + ; -assignment_pattern: // ==IEEE: assignment_pattern - // This doesn't match the text of the spec. I think a : is missing, or example code needed - // yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; } - // // "'{ const_expression }" is same as patternList with one entry - // // From patternNoExpr - // // also IEEE: "''{' expression { ',' expression } '}'" - // // matches since patternList includes expr - yP_TICKBRA patternList '}' { $$ = new AstPattern($1,$2); } - // // From patternNoExpr - // // also IEEE "''{' structure_pattern_key ':' ... - // // 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); } - ; +assignment_pattern: // ==IEEE: assignment_pattern + // This doesn't match the text of the spec. I think a : is missing, or example code needed + // yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; } + // // "'{ const_expression }" is same as patternList with one entry + // // From patternNoExpr + // // also IEEE: "''{' expression { ',' expression } '}'" + // // matches since patternList includes expr + yP_TICKBRA patternList '}' { $$ = new AstPattern($1,$2); } + // // From patternNoExpr + // // also IEEE "''{' structure_pattern_key ':' ... + // // 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); } + ; // "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal -for_initialization: // ==IEEE: for_initialization + for_variable_declaration + extra terminating ";" - // // IEEE: for_variable_declaration - for_initializationItemList ';' { $$ = $1; } - // // IEEE: 1800-2017 empty initialization - | ';' { $$ = nullptr; } - ; +for_initialization: // ==IEEE: for_initialization + for_variable_declaration + extra terminating ";" + // // IEEE: for_variable_declaration + for_initializationItemList ';' { $$ = $1; } + // // IEEE: 1800-2017 empty initialization + | ';' { $$ = nullptr; } + ; -for_initializationItemList: // IEEE: [for_variable_declaration...] - for_initializationItem { $$ = $1; } - | for_initializationItemList ',' for_initializationItem - { $$ = $1; BBUNSUP($2, "Unsupported: for loop initialization after the first comma"); } - ; +for_initializationItemList: // IEEE: [for_variable_declaration...] + for_initializationItem { $$ = $1; } + | for_initializationItemList ',' for_initializationItem + { $$ = $1; BBUNSUP($2, "Unsupported: for loop initialization after the first comma"); } + ; -for_initializationItem: // IEEE: variable_assignment + for_variable_declaration - // // IEEE: for_variable_declaration - data_type idAny/*new*/ '=' expr - { VARRESET_NONLIST(VAR); VARDTYPE($1); - $$ = VARDONEA($2,*$2,nullptr,nullptr); - $$->addNext(new AstAssign($3, new AstVarRef($2, *$2, VAccess::WRITE), $4)); } - // // IEEE-2012: - | yVAR data_type idAny/*new*/ '=' expr - { VARRESET_NONLIST(VAR); VARDTYPE($2); - $$ = VARDONEA($3,*$3,nullptr,nullptr); - $$->addNext(new AstAssign($4, new AstVarRef($3, *$3, VAccess::WRITE), $5)); } - // // IEEE: variable_assignment - // // UNSUP variable_lvalue below - | varRefBase '=' expr { $$ = new AstAssign($2, $1, $3); } - ; +for_initializationItem: // IEEE: variable_assignment + for_variable_declaration + // // IEEE: for_variable_declaration + data_type idAny/*new*/ '=' expr + { VARRESET_NONLIST(VAR); VARDTYPE($1); + $$ = VARDONEA($2,*$2,nullptr,nullptr); + $$->addNext(new AstAssign($3, new AstVarRef($2, *$2, VAccess::WRITE), $4)); } + // // IEEE-2012: + | yVAR data_type idAny/*new*/ '=' expr + { VARRESET_NONLIST(VAR); VARDTYPE($2); + $$ = VARDONEA($3,*$3,nullptr,nullptr); + $$->addNext(new AstAssign($4, new AstVarRef($3, *$3, VAccess::WRITE), $5)); } + // // IEEE: variable_assignment + // // UNSUP variable_lvalue below + | varRefBase '=' expr { $$ = new AstAssign($2, $1, $3); } + ; -for_stepE: // IEEE: for_step + empty - /* empty */ { $$ = nullptr; } - | for_step { $$ = $1; } - ; +for_stepE: // IEEE: for_step + empty + /* empty */ { $$ = nullptr; } + | for_step { $$ = $1; } + ; -for_step: // IEEE: for_step - for_step_assignment { $$ = $1; } - | for_step ',' for_step_assignment { $$ = AstNode::addNextNull($1, $3); } - ; +for_step: // IEEE: for_step + for_step_assignment { $$ = $1; } + | for_step ',' for_step_assignment { $$ = AstNode::addNextNull($1, $3); } + ; for_step_assignment: // ==IEEE: for_step_assignment - //UNSUP operator_assignment { $$ = $1; } - // - //UNSUP inc_or_dec_expression { $$ = $1; } - // // IEEE: subroutine_call - //UNSUP function_subroutine_callNoMethod { $$ = $1; } - // // method_call:array_method requires a '.' - //UNSUP expr '.' array_methodNoRoot { } - //UNSUP exprScope { $$ = $1; } - //UNSUP remove below - genvar_iteration { $$ = $1; } - //UNSUP remove above - ; + //UNSUP operator_assignment { $$ = $1; } + // + //UNSUP inc_or_dec_expression { $$ = $1; } + // // IEEE: subroutine_call + //UNSUP function_subroutine_callNoMethod { $$ = $1; } + // // method_call:array_method requires a '.' + //UNSUP expr '.' array_methodNoRoot { } + //UNSUP exprScope { $$ = $1; } + //UNSUP remove below + genvar_iteration { $$ = $1; } + //UNSUP remove above + ; -loop_variables: // IEEE: loop_variables - parseRefBase { $$ = $1; } - | loop_variables ',' parseRefBase { $$ = $1; $$->addNext($3); } - | ',' parseRefBase { $$ = new AstEmpty{$1}; $$->addNext($2); } - ; +loop_variables: // IEEE: loop_variables + parseRefBase { $$ = $1; } + | loop_variables ',' parseRefBase { $$ = $1; $$->addNext($3); } + | ',' parseRefBase { $$ = new AstEmpty{$1}; $$->addNext($2); } + ; //************************************************ // Functions/tasks -taskRef: // IEEE: part of tf_call - id { $$ = new AstTaskRef($1,*$1,nullptr); } - | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } - | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2, *$2, $4)); } - ; +taskRef: // IEEE: part of tf_call + id { $$ = new AstTaskRef($1,*$1,nullptr); } + | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } + | packageClassScope id '(' list_of_argumentsE ')' + { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2, *$2, $4)); } + ; -funcRef: // IEEE: part of tf_call - // // package_scope/hierarchical_... is part of expr, so just need ID - // // making-a id-is-a - // // ----------------- ------------------ - // // tf_call tf_identifier expr (list_of_arguments) - // // method_call(post .) function_identifier expr (list_of_arguments) - // // property_instance property_identifier property_actual_arg - // // sequence_instance sequence_identifier sequence_actual_arg - // // let_expression let_identifier let_actual_arg - // - id '(' list_of_argumentsE ')' - { $$ = new AstFuncRef($1, *$1, $3); } - | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, $1, new AstFuncRef($2, *$2, $4)); } - //UNSUP list_of_argumentE should be pev_list_of_argumentE - //UNSUP: idDotted is really just id to allow dotted method calls - ; +funcRef: // IEEE: part of tf_call + // // package_scope/hierarchical_... is part of expr, so just need ID + // // making-a id-is-a + // // ----------------- ------------------ + // // tf_call tf_identifier expr (list_of_arguments) + // // method_call(post .) function_identifier expr (list_of_arguments) + // // property_instance property_identifier property_actual_arg + // // sequence_instance sequence_identifier sequence_actual_arg + // // let_expression let_identifier let_actual_arg + // + id '(' list_of_argumentsE ')' + { $$ = new AstFuncRef($1, *$1, $3); } + | packageClassScope id '(' list_of_argumentsE ')' + { $$ = AstDot::newIfPkg($2, $1, new AstFuncRef($2, *$2, $4)); } + //UNSUP list_of_argumentE should be pev_list_of_argumentE + //UNSUP: idDotted is really just id to allow dotted method calls + ; -task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) - // // IEEE: tf_call - taskRef { $$ = $1; } - // // funcref below not task ref to avoid conflict, must later handle either - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, $1, $4); } - // // can call as method and yWITH without parenthesis - | 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 - // // IEEE: randomize_call - // // 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 - //UNSUP funcRef yWITH__CUR constraint_block { } - ; +task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) + // // IEEE: tf_call + taskRef { $$ = $1; } + // // funcref below not task ref to avoid conflict, must later handle either + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, true, $1, $4); } + // // can call as method and yWITH without parenthesis + | 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 + // // IEEE: randomize_call + // // 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 + //UNSUP funcRef yWITH__CUR constraint_block { } + ; -function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) - // // IEEE: tf_call - funcRef { $$ = $1; } - | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, $1, $4); } - // // can call as method and yWITH without parenthesis - | 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 - // // IEEE: randomize_call - // // 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 AstWithParse($2, false, $1, nullptr); } - ; +function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) + // // IEEE: tf_call + funcRef { $$ = $1; } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWithParse($2, false, $1, $4); } + // // can call as method and yWITH without parenthesis + | 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 + // // IEEE: randomize_call + // // 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 AstWithParse($2, false, $1, nullptr); } + ; -system_t_call: // IEEE: system_tf_call (as task) - // - yaD_PLI systemDpiArgsE { $$ = new AstTaskRef($1, *$1, $2); VN_CAST($$, TaskRef)->pli(true); } - // - | yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $5); DEL($3); - $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, - new AstConst($1, 1))); } - | yD_DUMPPORTS '(' ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $4); - $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, - new AstConst($1, 1))); } - | yD_DUMPFILE '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $3); } - | yD_DUMPVARS parenE { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, - new AstConst($1, 0)); } - | yD_DUMPVARS '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); } - | yD_DUMPVARS '(' expr ',' idDotted ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); DEL($5); } - | yD_DUMPALL parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); } - | yD_DUMPALL '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); DEL($3); } - | yD_DUMPFLUSH parenE { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); } - | yD_DUMPFLUSH '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); DEL($3); } - | yD_DUMPLIMIT '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); } - | yD_DUMPLIMIT '(' expr ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); DEL($5); } - | yD_DUMPOFF parenE { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); } - | yD_DUMPOFF '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); DEL($3); } - | yD_DUMPON parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ON); } - | yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ON); DEL($3); } - // - | 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 '(' expr ')' { $$ = new AstFClose{$1, $3}; } - | yD_FFLUSH parenE { $$ = new AstFFlush($1, nullptr); } - | yD_FFLUSH '(' expr ')' { $$ = new AstFFlush($1, $3); } - | yD_FINISH parenE { $$ = new AstFinish($1); } - | yD_FINISH '(' expr ')' { $$ = new AstFinish($1); DEL($3); } - | yD_STOP parenE { $$ = new AstStop($1, false); } - | yD_STOP '(' expr ')' { $$ = new AstStop($1, false); DEL($3); } - // - | yD_SFORMAT '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } - | yD_SWRITE '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } - | yD_SWRITEB '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'b'); } - | yD_SWRITEH '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'h'); } - | yD_SWRITEO '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'o'); } - // - | yD_DISPLAY parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr); } - | yD_DISPLAY '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3); } - | yD_DISPLAYB parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'b'); } - | yD_DISPLAYB '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'b'); } - | yD_DISPLAYH parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'h'); } - | yD_DISPLAYH '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'h'); } - | yD_DISPLAYO parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'); } - | yD_DISPLAYO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'o'); } - | yD_MONITOR '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3); } - | yD_MONITORB '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'b'); } - | yD_MONITORH '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'h'); } - | yD_MONITORO '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'o'); } - | yD_STROBE '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3); } - | yD_STROBEB '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'b'); } - | yD_STROBEH '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'h'); } - | yD_STROBEO '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'o'); } - | yD_WRITE parenE { $$ = nullptr; } // NOP - | yD_WRITE '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3); } - | yD_WRITEB parenE { $$ = nullptr; } // NOP - | yD_WRITEB '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'b'); } - | yD_WRITEH parenE { $$ = nullptr; } // NOP - | yD_WRITEH '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'h'); } - | yD_WRITEO parenE { $$ = nullptr; } // NOP - | yD_WRITEO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'o'); } - | yD_FDISPLAY '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr); } - | yD_FDISPLAY '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5); } - | yD_FDISPLAYB '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'b'); } - | yD_FDISPLAYB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'b'); } - | yD_FDISPLAYH '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'h'); } - | yD_FDISPLAYH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'h'); } - | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'o'); } - | yD_FDISPLAYO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'o'); } - | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5); } - | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'b'); } - | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'h'); } - | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'o'); } - | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5); } - | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'b'); } - | yD_FSTROBEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'h'); } - | yD_FSTROBEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'o'); } - | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5); } - | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'b'); } - | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'h'); } - | yD_FWRITEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'o'); } - | yD_INFO parenE { $$ = new AstDisplay($1,VDisplayType::DT_INFO, nullptr, nullptr); } - | yD_INFO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_INFO, nullptr, $3); } - | yD_WARNING parenE { $$ = new AstDisplay($1,VDisplayType::DT_WARNING, nullptr, nullptr); } - | yD_WARNING '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WARNING, nullptr, $3); } - | yD_ERROR parenE { $$ = GRAMMARP->createDisplayError($1); } - | yD_ERROR '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_ERROR, nullptr, $3); $$->addNext(new AstStop($1, true)); } - | yD_FATAL parenE { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); } - | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); DEL($3); } - | yD_FATAL '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, $5); $$->addNext(new AstStop($1, false)); DEL($3); } - // - | yD_MONITOROFF parenE { $$ = new AstMonitorOff($1, true); } - | yD_MONITORON parenE { $$ = new AstMonitorOff($1, false); } - // - | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale($1); } - | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale($1); } - | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale($1); DEL($3); } - | yD_TIMEFORMAT '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstTimeFormat($1, $3, $5, $7, $9); } - // - | yD_READMEMB '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,false,$3,$5,nullptr,nullptr); } - | yD_READMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,nullptr); } - | yD_READMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } - | yD_READMEMH '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,true, $3,$5,nullptr,nullptr); } - | yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,nullptr); } - | yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } - // - | yD_WRITEMEMB '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, false, $3, $5, nullptr, nullptr); } - | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, nullptr); } - | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, $9); } - | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, true, $3, $5, nullptr, nullptr); } - | 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 ')' - { FileLine* const fl_nowarn = new FileLine{$1}; - fl_nowarn->warnOff(V3ErrorCode::WIDTH, true); - $$ = new AstAssertIntrinsic(fl_nowarn, new AstCastDynamic(fl_nowarn, $5, $3), nullptr, nullptr, true); } - // - // Any system function as a task - | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } - ; +system_t_call: // IEEE: system_tf_call (as task) + // + yaD_PLI systemDpiArgsE { $$ = new AstTaskRef($1, *$1, $2); VN_CAST($$, TaskRef)->pli(true); } + // + | yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $5); DEL($3); + $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 1))); } + | yD_DUMPPORTS '(' ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $4); + $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 1))); } + | yD_DUMPFILE '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $3); } + | yD_DUMPVARS parenE { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, + new AstConst($1, 0)); } + | yD_DUMPVARS '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); } + | yD_DUMPVARS '(' expr ',' idDotted ')' { $$ = new AstDumpCtl($1, VDumpCtlType::VARS, $3); DEL($5); } + | yD_DUMPALL parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); } + | yD_DUMPALL '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ALL); DEL($3); } + | yD_DUMPFLUSH parenE { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); } + | yD_DUMPFLUSH '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FLUSH); DEL($3); } + | yD_DUMPLIMIT '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); } + | yD_DUMPLIMIT '(' expr ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::LIMIT, $3); DEL($5); } + | yD_DUMPOFF parenE { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); } + | yD_DUMPOFF '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::OFF); DEL($3); } + | yD_DUMPON parenE { $$ = new AstDumpCtl($1, VDumpCtlType::ON); } + | yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::ON); DEL($3); } + // + | 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 '(' expr ')' { $$ = new AstFClose{$1, $3}; } + | yD_FFLUSH parenE { $$ = new AstFFlush($1, nullptr); } + | yD_FFLUSH '(' expr ')' { $$ = new AstFFlush($1, $3); } + | yD_FINISH parenE { $$ = new AstFinish($1); } + | yD_FINISH '(' expr ')' { $$ = new AstFinish($1); DEL($3); } + | yD_STOP parenE { $$ = new AstStop($1, false); } + | yD_STOP '(' expr ')' { $$ = new AstStop($1, false); DEL($3); } + // + | yD_SFORMAT '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } + | yD_SWRITE '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } + | yD_SWRITEB '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'b'); } + | yD_SWRITEH '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'h'); } + | yD_SWRITEO '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'o'); } + // + | yD_DISPLAY parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr); } + | yD_DISPLAY '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3); } + | yD_DISPLAYB parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'b'); } + | yD_DISPLAYB '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'b'); } + | yD_DISPLAYH parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'h'); } + | yD_DISPLAYH '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'h'); } + | yD_DISPLAYO parenE { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'); } + | yD_DISPLAYO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, nullptr, $3, 'o'); } + | yD_MONITOR '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3); } + | yD_MONITORB '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'b'); } + | yD_MONITORH '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'h'); } + | yD_MONITORO '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, nullptr, $3, 'o'); } + | yD_STROBE '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3); } + | yD_STROBEB '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'b'); } + | yD_STROBEH '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'h'); } + | yD_STROBEO '(' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, nullptr, $3, 'o'); } + | yD_WRITE parenE { $$ = nullptr; } // NOP + | yD_WRITE '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3); } + | yD_WRITEB parenE { $$ = nullptr; } // NOP + | yD_WRITEB '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'b'); } + | yD_WRITEH parenE { $$ = nullptr; } // NOP + | yD_WRITEH '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'h'); } + | yD_WRITEO parenE { $$ = nullptr; } // NOP + | yD_WRITEO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WRITE, nullptr, $3, 'o'); } + | yD_FDISPLAY '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr); } + | yD_FDISPLAY '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5); } + | yD_FDISPLAYB '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'b'); } + | yD_FDISPLAYB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'b'); } + | yD_FDISPLAYH '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'h'); } + | yD_FDISPLAYH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'h'); } + | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, nullptr, 'o'); } + | yD_FDISPLAYO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_DISPLAY, $3, $5, 'o'); } + | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5); } + | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'b'); } + | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'h'); } + | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_MONITOR, $3, $5, 'o'); } + | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5); } + | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'b'); } + | yD_FSTROBEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'h'); } + | yD_FSTROBEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_STROBE, $3, $5, 'o'); } + | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5); } + | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'b'); } + | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'h'); } + | yD_FWRITEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, VDisplayType::DT_WRITE, $3, $5, 'o'); } + | yD_INFO parenE { $$ = new AstDisplay($1,VDisplayType::DT_INFO, nullptr, nullptr); } + | yD_INFO '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_INFO, nullptr, $3); } + | yD_WARNING parenE { $$ = new AstDisplay($1,VDisplayType::DT_WARNING, nullptr, nullptr); } + | yD_WARNING '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_WARNING, nullptr, $3); } + | yD_ERROR parenE { $$ = GRAMMARP->createDisplayError($1); } + | yD_ERROR '(' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_ERROR, nullptr, $3); $$->addNext(new AstStop($1, true)); } + | yD_FATAL parenE { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); } + | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); DEL($3); } + | yD_FATAL '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,VDisplayType::DT_FATAL, nullptr, $5); $$->addNext(new AstStop($1, false)); DEL($3); } + // + | yD_MONITOROFF parenE { $$ = new AstMonitorOff($1, true); } + | yD_MONITORON parenE { $$ = new AstMonitorOff($1, false); } + // + | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale($1); } + | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale($1); } + | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale($1); DEL($3); } + | yD_TIMEFORMAT '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstTimeFormat($1, $3, $5, $7, $9); } + // + | yD_READMEMB '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,false,$3,$5,nullptr,nullptr); } + | yD_READMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,nullptr); } + | yD_READMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); } + | yD_READMEMH '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,true, $3,$5,nullptr,nullptr); } + | yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,nullptr); } + | yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } + // + | yD_WRITEMEMB '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, false, $3, $5, nullptr, nullptr); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, nullptr); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, $9); } + | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, true, $3, $5, nullptr, nullptr); } + | 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 ')' + { FileLine* const fl_nowarn = new FileLine{$1}; + fl_nowarn->warnOff(V3ErrorCode::WIDTH, true); + $$ = new AstAssertIntrinsic(fl_nowarn, new AstCastDynamic(fl_nowarn, $5, $3), nullptr, nullptr, true); } + // + // Any system function as a task + | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } + ; -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, $5, $3); } - | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } - // - | system_f_call_or_t { $$ = $1; } - ; +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, $5, $3); } + | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } + // + | system_f_call_or_t { $$ = $1; } + ; -systemDpiArgsE: // IEEE: part of system_if_call for aruments of $dpi call - parenE { $$ = nullptr; } - | '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); } - ; +systemDpiArgsE: // IEEE: part of system_if_call for aruments of $dpi call + parenE { $$ = nullptr; } + | '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); } + ; -system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) - yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } - | yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); } - | yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); } - | yD_ASINH '(' expr ')' { $$ = new AstAsinhD($1,$3); } - | yD_ATAN '(' expr ')' { $$ = new AstAtanD($1,$3); } - | yD_ATAN2 '(' expr ',' expr ')' { $$ = new AstAtan2D($1,$3,$5); } - | yD_ATANH '(' expr ')' { $$ = new AstAtanhD($1,$3); } - | yD_BITS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_BITS,$3); } - | yD_BITS '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_BITS,$3,$5); } - | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); } - | yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); UNSUPREAL($1); } - | 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"); } - | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } - | yD_COS '(' expr ')' { $$ = new AstCosD($1,$3); } - | yD_COSH '(' expr ')' { $$ = new AstCoshD($1,$3); } - | yD_COUNTBITS '(' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5); } - | yD_COUNTBITS '(' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7); } - | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7,$9); } - | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ',' exprList ')' - { $$ = new AstCountBits($1, $3, $5, $7, $9); - BBUNSUP($11, "Unsupported: $countbits with more than 3 control fields"); } - | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } - | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_DIMENSIONS,$3); } - | yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); } - | yD_FELL '(' expr ')' { $$ = new AstFell($1,$3); } - | yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); } - | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } - | yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError($1, $3, $5); } - | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } - | yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); } - | yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,nullptr,nullptr); } - | yD_FREAD '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,nullptr); } - | yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,$9); } - | yD_FREWIND '(' idClassSel ')' { $$ = new AstFRewind($1, $3); } - | yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); } - | yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); } - | yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek($1,$3,$5,$7); } - | yD_FTELL '(' idClassSel ')' { $$ = new AstFTell($1, $3); } - | yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_HIGH,$3,nullptr); } - | yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_HIGH,$3,$5); } - | yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD($1,$3,$5); } - | yD_INCREMENT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_INCREMENT,$3,nullptr); } - | yD_INCREMENT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_INCREMENT,$3,$5); } - | yD_ISUNBOUNDED '(' expr ')' { $$ = new AstIsUnbounded($1, $3); } - | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1, $3); } - | yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); } - | yD_LEFT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LEFT,$3,nullptr); } - | yD_LEFT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LEFT,$3,$5); } - | yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); } - | yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); } - | yD_LOW '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LOW,$3,nullptr); } - | yD_LOW '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LOW,$3,$5); } - | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); } - | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); } - | yD_PAST '(' expr ')' { $$ = new AstPast($1,$3, nullptr); } - | yD_PAST '(' expr ',' expr ')' { $$ = new AstPast($1,$3, $5); } - | yD_PAST '(' expr ',' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } - | yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } - | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } - | yD_RANDOM '(' expr ')' { $$ = new AstRand($1, $3, false); } - | yD_RANDOM parenE { $$ = new AstRand($1, nullptr, false); } - | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } - | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } - | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } - | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_RIGHT,$3,nullptr); } - | yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_RIGHT,$3,$5); } - | yD_ROSE '(' expr ')' { $$ = new AstRose($1,$3); } - | yD_ROSE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $rose and clock arguments"); } - | yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); } - | yD_SAMPLED '(' expr ')' { $$ = new AstSampled($1, $3); } - | yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF($1, AstSFormatF::NoFormat(), $3, 'd', false); } - | yD_SHORTREALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); UNSUPREAL($1); } - | yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); } - | yD_SIN '(' expr ')' { $$ = new AstSinD($1,$3); } - | yD_SINH '(' expr ')' { $$ = new AstSinhD($1,$3); } - | yD_SIZE '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_SIZE,$3,nullptr); } - | yD_SIZE '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_SIZE,$3,$5); } - | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } - | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } - | yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); } - | yD_STABLE '(' expr ')' { $$ = new AstStable($1,$3); } - | yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); } - | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } - | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } - | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } - | yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); } - | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); } - | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first - | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_UNPK_DIMENSIONS,$3); } - | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1, $3); } - | yD_URANDOM '(' expr ')' { $$ = new AstRand($1, $3, true); } - | yD_URANDOM parenE { $$ = new AstRand($1, nullptr, true); } - | yD_URANDOM_RANGE '(' expr ')' { $$ = new AstURandomRange($1, $3, new AstConst($1, 0)); } - | yD_URANDOM_RANGE '(' expr ',' expr ')' { $$ = new AstURandomRange($1, $3, $5); } - | yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1, $3, $5); } - ; +system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) + yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } + | yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); } + | yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); } + | yD_ASINH '(' expr ')' { $$ = new AstAsinhD($1,$3); } + | yD_ATAN '(' expr ')' { $$ = new AstAtanD($1,$3); } + | yD_ATAN2 '(' expr ',' expr ')' { $$ = new AstAtan2D($1,$3,$5); } + | yD_ATANH '(' expr ')' { $$ = new AstAtanhD($1,$3); } + | yD_BITS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_BITS,$3); } + | yD_BITS '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_BITS,$3,$5); } + | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); } + | yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); UNSUPREAL($1); } + | 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"); } + | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } + | yD_COS '(' expr ')' { $$ = new AstCosD($1,$3); } + | yD_COSH '(' expr ')' { $$ = new AstCoshD($1,$3); } + | yD_COUNTBITS '(' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5); } + | yD_COUNTBITS '(' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7); } + | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7,$9); } + | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ',' exprList ')' + { $$ = new AstCountBits($1, $3, $5, $7, $9); + BBUNSUP($11, "Unsupported: $countbits with more than 3 control fields"); } + | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } + | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_DIMENSIONS,$3); } + | yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); } + | yD_FELL '(' expr ')' { $$ = new AstFell($1,$3); } + | yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); } + | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } + | yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError($1, $3, $5); } + | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } + | yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); } + | yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,nullptr,nullptr); } + | yD_FREAD '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,nullptr); } + | yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,$9); } + | yD_FREWIND '(' idClassSel ')' { $$ = new AstFRewind($1, $3); } + | yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); } + | yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); } + | yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek($1,$3,$5,$7); } + | yD_FTELL '(' idClassSel ')' { $$ = new AstFTell($1, $3); } + | yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_HIGH,$3,nullptr); } + | yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_HIGH,$3,$5); } + | yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD($1,$3,$5); } + | yD_INCREMENT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_INCREMENT,$3,nullptr); } + | yD_INCREMENT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_INCREMENT,$3,$5); } + | yD_ISUNBOUNDED '(' expr ')' { $$ = new AstIsUnbounded($1, $3); } + | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1, $3); } + | yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); } + | yD_LEFT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LEFT,$3,nullptr); } + | yD_LEFT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LEFT,$3,$5); } + | yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); } + | yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); } + | yD_LOW '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LOW,$3,nullptr); } + | yD_LOW '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_LOW,$3,$5); } + | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); } + | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); } + | yD_PAST '(' expr ')' { $$ = new AstPast($1,$3, nullptr); } + | yD_PAST '(' expr ',' expr ')' { $$ = new AstPast($1,$3, $5); } + | yD_PAST '(' expr ',' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } + | yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } + | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } + | yD_RANDOM '(' expr ')' { $$ = new AstRand($1, $3, false); } + | yD_RANDOM parenE { $$ = new AstRand($1, nullptr, false); } + | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } + | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } + | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } + | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_RIGHT,$3,nullptr); } + | yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_RIGHT,$3,$5); } + | yD_ROSE '(' expr ')' { $$ = new AstRose($1,$3); } + | yD_ROSE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $rose and clock arguments"); } + | yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); } + | yD_SAMPLED '(' expr ')' { $$ = new AstSampled($1, $3); } + | yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF($1, AstSFormatF::NoFormat(), $3, 'd', false); } + | yD_SHORTREALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); UNSUPREAL($1); } + | yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); } + | yD_SIN '(' expr ')' { $$ = new AstSinD($1,$3); } + | yD_SINH '(' expr ')' { $$ = new AstSinhD($1,$3); } + | yD_SIZE '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_SIZE,$3,nullptr); } + | yD_SIZE '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_SIZE,$3,$5); } + | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } + | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } + | yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); } + | yD_STABLE '(' expr ')' { $$ = new AstStable($1,$3); } + | yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); } + | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } + | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } + | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } + | yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); } + | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); } + | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first + | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_UNPK_DIMENSIONS,$3); } + | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1, $3); } + | yD_URANDOM '(' expr ')' { $$ = new AstRand($1, $3, true); } + | yD_URANDOM parenE { $$ = new AstRand($1, nullptr, true); } + | yD_URANDOM_RANGE '(' expr ')' { $$ = new AstURandomRange($1, $3, new AstConst($1, 0)); } + | yD_URANDOM_RANGE '(' expr ',' expr ')' { $$ = new AstURandomRange($1, $3, $5); } + | yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1, $3, $5); } + ; -elaboration_system_task: // IEEE: elaboration_system_task (1800-2009) - // // TODO: These currently just make initial statements, should instead give runtime error - elaboration_system_task_guts ';' { $$ = new AstInitial($1, $1); } - ; +elaboration_system_task: // IEEE: elaboration_system_task (1800-2009) + // // TODO: These currently just make initial statements, should instead give runtime error + elaboration_system_task_guts ';' { $$ = new AstInitial($1, $1); } + ; -elaboration_system_task_guts: // IEEE: part of elaboration_system_task (1800-2009) - // // $fatal first argument is exit number, must be constant - yD_INFO parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_INFO, nullptr); } - | yD_INFO '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_INFO, $3); } - | yD_WARNING parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_WARNING, nullptr); } - | yD_WARNING '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_WARNING, $3); } - | yD_ERROR parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_ERROR, nullptr); } - | yD_ERROR '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_ERROR, $3); } - | yD_FATAL parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, nullptr); } - | yD_FATAL '(' expr ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, nullptr); DEL($3); } - | yD_FATAL '(' expr ',' exprListE ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, $5); DEL($3); } - ; +elaboration_system_task_guts: // IEEE: part of elaboration_system_task (1800-2009) + // // $fatal first argument is exit number, must be constant + yD_INFO parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_INFO, nullptr); } + | yD_INFO '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_INFO, $3); } + | yD_WARNING parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_WARNING, nullptr); } + | yD_WARNING '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_WARNING, $3); } + | yD_ERROR parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_ERROR, nullptr); } + | yD_ERROR '(' exprList ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_ERROR, $3); } + | yD_FATAL parenE { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, nullptr); } + | yD_FATAL '(' expr ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, nullptr); DEL($3); } + | yD_FATAL '(' expr ',' exprListE ')' { $$ = new AstElabDisplay($1, VDisplayType::DT_FATAL, $5); DEL($3); } + ; //UNSUPproperty_actual_arg: // ==IEEE: property_actual_arg -//UNSUP // // IEEE: property_expr -//UNSUP // // IEEE: sequence_actual_arg -//UNSUP pev_expr { $$ = $1; } -//UNSUP // // IEEE: sequence_expr -//UNSUP // // property_expr already includes sequence_expr -//UNSUP ; +//UNSUP // // IEEE: property_expr +//UNSUP // // IEEE: sequence_actual_arg +//UNSUP pev_expr { $$ = $1; } +//UNSUP // // IEEE: sequence_expr +//UNSUP // // property_expr already includes sequence_expr +//UNSUP ; -exprOrDataType: // expr | data_type: combined to prevent conflicts - expr { $$ = $1; } - // // data_type includes id that overlaps expr, so special flavor - | data_type { $$ = $1; } - // // not in spec, but needed for $past(sig,1,,@(posedge clk)) - //UNSUP event_control { } - ; +exprOrDataType: // expr | data_type: combined to prevent conflicts + expr { $$ = $1; } + // // data_type includes id that overlaps expr, so special flavor + | data_type { $$ = $1; } + // // not in spec, but needed for $past(sig,1,,@(posedge clk)) + //UNSUP event_control { } + ; //UNSUPexprOrDataTypeOrMinTypMax: // exprOrDataType or mintypmax_expression -//UNSUP expr { $$ = $1; } -//UNSUP | expr ':' expr ':' expr { $$ = $3; } -//UNSUP // // data_type includes id that overlaps expr, so special flavor -//UNSUP | data_type { $$ = $1; } -//UNSUP // // not in spec, but needed for $past(sig,1,,@(posedge clk)) -//UNSUP | event_control { $$ = $1; } -//UNSUP ; +//UNSUP expr { $$ = $1; } +//UNSUP | expr ':' expr ':' expr { $$ = $3; } +//UNSUP // // data_type includes id that overlaps expr, so special flavor +//UNSUP | data_type { $$ = $1; } +//UNSUP // // not in spec, but needed for $past(sig,1,,@(posedge clk)) +//UNSUP | event_control { $$ = $1; } +//UNSUP ; //UNSUPexprOrDataTypeList: -//UNSUP exprOrDataType { $$ = $1; } -//UNSUP | exprOrDataTypeList ',' exprOrDataType { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP exprOrDataType { $$ = $1; } +//UNSUP | exprOrDataTypeList ',' exprOrDataType { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; -list_of_argumentsE: // IEEE: [list_of_arguments] - argsDottedList { $$ = $1; } - | argsExprListE - { if (VN_IS($1, Arg) && VN_CAST($1, Arg)->emptyConnectNoNext()) { - $1->deleteTree(); $$ = nullptr; // Mis-created when have 'func()' - } else { $$ = $1; } } - | argsExprListE ',' argsDottedList { $$ = $1->addNextNull($3); } - ; +list_of_argumentsE: // IEEE: [list_of_arguments] + argsDottedList { $$ = $1; } + | argsExprListE + { if (VN_IS($1, Arg) && VN_CAST($1, Arg)->emptyConnectNoNext()) { + $1->deleteTree(); $$ = nullptr; // Mis-created when have 'func()' + } else { $$ = $1; } } + | argsExprListE ',' argsDottedList { $$ = $1->addNextNull($3); } + ; -task_declaration: // ==IEEE: task_declaration - yTASK lifetimeE taskId tfGuts yENDTASK endLabelE - { $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); - $$->lifetime($2); - GRAMMARP->endLabel($6,$$,$6); } - ; +task_declaration: // ==IEEE: task_declaration + yTASK lifetimeE taskId tfGuts yENDTASK endLabelE + { $$ = $3; $$->addStmtsp($4); SYMP->popScope($$); + $$->lifetime($2); + GRAMMARP->endLabel($6,$$,$6); } + ; -task_prototype: // ==IEEE: task_prototype - yTASK taskId '(' tf_port_listE ')' - { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } - | yTASK taskId - { $$ = $2; $$->prototype(true); SYMP->popScope($$); } - ; +task_prototype: // ==IEEE: task_prototype + yTASK taskId '(' tf_port_listE ')' + { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } + | yTASK taskId + { $$ = $2; $$->prototype(true); SYMP->popScope($$); } + ; -function_declaration: // IEEE: function_declaration + function_body_declaration - yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE - { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); - $$->lifetime($2); - SYMP->popScope($$); - GRAMMARP->endLabel($7,$$,$7); } - | yFUNCTION lifetimeE funcIdNew funcIsolateE tfGuts yENDFUNCTION endLabelE - { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); - $$->lifetime($2); - SYMP->popScope($$); - GRAMMARP->endLabel($7,$$,$7); } - ; +function_declaration: // IEEE: function_declaration + function_body_declaration + yFUNCTION lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE + { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); + SYMP->popScope($$); + GRAMMARP->endLabel($7,$$,$7); } + | yFUNCTION lifetimeE funcIdNew funcIsolateE tfGuts yENDFUNCTION endLabelE + { $$ = $3; $3->attrIsolateAssign($4); $$->addStmtsp($5); + $$->lifetime($2); + SYMP->popScope($$); + GRAMMARP->endLabel($7,$$,$7); } + ; -function_prototype: // IEEE: function_prototype - yFUNCTION funcId '(' tf_port_listE ')' - { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } - | yFUNCTION funcId - { $$ = $2; $$->prototype(true); SYMP->popScope($$); } - ; +function_prototype: // IEEE: function_prototype + yFUNCTION funcId '(' tf_port_listE ')' + { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } + | yFUNCTION funcId + { $$ = $2; $$->prototype(true); SYMP->popScope($$); } + ; -class_constructor_prototype: // ==IEEE: class_constructor_prototype - yFUNCTION funcIdNew '(' tf_port_listE ')' ';' - { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } - | yFUNCTION funcIdNew ';' - { $$ = $2; $$->prototype(true); SYMP->popScope($$); } - ; +class_constructor_prototype: // ==IEEE: class_constructor_prototype + yFUNCTION funcIdNew '(' tf_port_listE ')' ';' + { $$ = $2; $$->addStmtsp($4); $$->prototype(true); SYMP->popScope($$); } + | yFUNCTION funcIdNew ';' + { $$ = $2; $$->prototype(true); SYMP->popScope($$); } + ; funcIsolateE: - /* empty */ { $$ = 0; } - | yVL_ISOLATE_ASSIGNMENTS { $$ = 1; } - ; + /* empty */ { $$ = 0; } + | yVL_ISOLATE_ASSIGNMENTS { $$ = 1; } + ; method_prototype: - task_prototype { $$ = $1; } - | function_prototype { $$ = $1; } - ; + task_prototype { $$ = $1; } + | function_prototype { $$ = $1; } + ; -lifetimeE: // IEEE: [lifetime] - /* empty */ { $$ = VLifetime::NONE; } - | lifetime { $$ = $1; } - ; +lifetimeE: // IEEE: [lifetime] + /* empty */ { $$ = VLifetime::NONE; } + | lifetime { $$ = $1; } + ; -lifetime: // ==IEEE: lifetime - // // Note lifetime used by members is instead under memberQual - ySTATIC__ETC { $$ = VLifetime::STATIC; } - | yAUTOMATIC { $$ = VLifetime::AUTOMATIC; } - ; +lifetime: // ==IEEE: lifetime + // // Note lifetime used by members is instead under memberQual + ySTATIC__ETC { $$ = VLifetime::STATIC; } + | yAUTOMATIC { $$ = VLifetime::AUTOMATIC; } + ; taskId: - id - { $$ = new AstTask($$, *$1, nullptr); - SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } - // - | id/*interface_identifier*/ '.' id - { $$ = new AstTask($$, *$3, nullptr); - BBUNSUP($2, "Unsupported: Out of block function declaration"); - SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } - // - | packageClassScope id - { $$ = new AstTask($$, *$2, nullptr); - $$->classOrPackagep($1); - SYMP->pushNewUnderNodeOrCurrent($$, $1); } - ; + id + { $$ = new AstTask($$, *$1, nullptr); + SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } + // + | id/*interface_identifier*/ '.' id + { $$ = new AstTask($$, *$3, nullptr); + BBUNSUP($2, "Unsupported: Out of block function declaration"); + SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } + // + | packageClassScope id + { $$ = new AstTask($$, *$2, nullptr); + $$->classOrPackagep($1); + SYMP->pushNewUnderNodeOrCurrent($$, $1); } + ; -funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration - // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict - // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID - /**/ fIdScoped - { $$ = $1; - $$->addFvarp(new AstBasicDType($1, LOGIC_IMPLICIT)); - SYMP->pushNewUnderNodeOrCurrent($$, $1); } - | signingE rangeList fIdScoped - { $$ = $3; - $$->addFvarp(GRAMMARP->addRange(new AstBasicDType($3, LOGIC_IMPLICIT, $1), $2,true)); - SYMP->pushNewUnderNodeOrCurrent($$, $3); } - | signing fIdScoped - { $$ = $2; - $$->addFvarp(new AstBasicDType($2, LOGIC_IMPLICIT, $1)); - SYMP->pushNewUnderNodeOrCurrent($$, $2); } - | data_type fIdScoped - { $$ = $2; - $$->addFvarp($1); - SYMP->pushNewUnderNodeOrCurrent($$, $2); } - // // To verilator tasks are the same as void functions (we separately detect time passing) - | yVOID taskId - { $$ = $2; } - ; +funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration + // // IEEE: function_data_type_or_implicit must be expanded here to prevent conflict + // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID + /**/ fIdScoped + { $$ = $1; + $$->addFvarp(new AstBasicDType($1, LOGIC_IMPLICIT)); + SYMP->pushNewUnderNodeOrCurrent($$, $1); } + | signingE rangeList fIdScoped + { $$ = $3; + $$->addFvarp(GRAMMARP->addRange(new AstBasicDType($3, LOGIC_IMPLICIT, $1), $2,true)); + SYMP->pushNewUnderNodeOrCurrent($$, $3); } + | signing fIdScoped + { $$ = $2; + $$->addFvarp(new AstBasicDType($2, LOGIC_IMPLICIT, $1)); + SYMP->pushNewUnderNodeOrCurrent($$, $2); } + | data_type fIdScoped + { $$ = $2; + $$->addFvarp($1); + SYMP->pushNewUnderNodeOrCurrent($$, $2); } + // // To verilator tasks are the same as void functions (we separately detect time passing) + | yVOID taskId + { $$ = $2; } + ; -funcIdNew: // IEEE: from class_constructor_declaration - yNEW__ETC - { $$ = new AstFunc($1, "new", nullptr, nullptr); - $$->isConstructor(true); - SYMP->pushNewUnder($$, nullptr); } - | yNEW__PAREN - { $$ = new AstFunc($1, "new", nullptr, nullptr); - $$->isConstructor(true); - SYMP->pushNewUnder($$, nullptr); } - | packageClassScopeNoId yNEW__PAREN - { $$ = new AstFunc($2, "new", nullptr, nullptr); - $$->classOrPackagep($1); - $$->isConstructor(true); - SYMP->pushNewUnderNodeOrCurrent($$, $1); } - ; +funcIdNew: // IEEE: from class_constructor_declaration + yNEW__ETC + { $$ = new AstFunc($1, "new", nullptr, nullptr); + $$->isConstructor(true); + SYMP->pushNewUnder($$, nullptr); } + | yNEW__PAREN + { $$ = new AstFunc($1, "new", nullptr, nullptr); + $$->isConstructor(true); + SYMP->pushNewUnder($$, nullptr); } + | packageClassScopeNoId yNEW__PAREN + { $$ = new AstFunc($2, "new", nullptr, nullptr); + $$->classOrPackagep($1); + $$->isConstructor(true); + SYMP->pushNewUnderNodeOrCurrent($$, $1); } + ; -fIdScoped: // IEEE: part of function_body_declaration/task_body_declaration - // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier - id - { $$ = $1; - $$ = nullptr; +fIdScoped: // IEEE: part of function_body_declaration/task_body_declaration + // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier + id + { $$ = $1; + $$ = nullptr; $$ = new AstFunc($$, *$1, nullptr, nullptr); } - // - | id/*interface_identifier*/ '.' id - { $$ = $1; - $$ = nullptr; + // + | id/*interface_identifier*/ '.' id + { $$ = $1; + $$ = nullptr; $$ = new AstFunc($$, *$1, nullptr, nullptr); - BBUNSUP($2, "Unsupported: Out of block function declaration"); } - // - | packageClassScope id - { $$ = $1; - $$ = $1; - $$ = new AstFunc($$, *$2, nullptr, nullptr); - $$->classOrPackagep($1); } - ; + BBUNSUP($2, "Unsupported: Out of block function declaration"); } + // + | packageClassScope id + { $$ = $1; + $$ = $1; + $$ = new AstFunc($$, *$2, nullptr, nullptr); + $$->classOrPackagep($1); } + ; tfGuts: - '(' tf_port_listE ')' ';' tfBodyE { $$ = $2->addNextNull($5); } - | ';' tfBodyE { $$ = $2; } - ; + '(' tf_port_listE ')' ';' tfBodyE { $$ = $2->addNextNull($5); } + | ';' tfBodyE { $$ = $2; } + ; -tfBodyE: // IEEE: part of function_body_declaration/task_body_declaration - /* empty */ { $$ = nullptr; } - | tf_item_declarationList { $$ = $1; } - | tf_item_declarationList stmtList { $$ = $1->addNextNull($2); } - | stmtList { $$ = $1; } - ; +tfBodyE: // IEEE: part of function_body_declaration/task_body_declaration + /* empty */ { $$ = nullptr; } + | tf_item_declarationList { $$ = $1; } + | tf_item_declarationList stmtList { $$ = $1->addNextNull($2); } + | stmtList { $$ = $1; } + ; tf_item_declarationList: - tf_item_declaration { $$ = $1; } - | tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); } - ; + tf_item_declaration { $$ = $1; } + | tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); } + ; -tf_item_declaration: // ==IEEE: tf_item_declaration - block_item_declaration { $$ = $1; } - | tf_port_declaration { $$ = $1; } - | tf_item_declarationVerilator { $$ = $1; } - ; +tf_item_declaration: // ==IEEE: tf_item_declaration + block_item_declaration { $$ = $1; } + | tf_port_declaration { $$ = $1; } + | tf_item_declarationVerilator { $$ = $1; } + ; -tf_item_declarationVerilator: // Verilator extensions - yVL_PUBLIC { $$ = new AstPragma($1,VPragmaType::PUBLIC_TASK); v3Global.dpi(true); } - | yVL_NO_INLINE_TASK { $$ = new AstPragma($1,VPragmaType::NO_INLINE_TASK); } - ; +tf_item_declarationVerilator: // Verilator extensions + yVL_PUBLIC { $$ = new AstPragma($1,VPragmaType::PUBLIC_TASK); v3Global.dpi(true); } + | yVL_NO_INLINE_TASK { $$ = new AstPragma($1,VPragmaType::NO_INLINE_TASK); } + ; -tf_port_listE: // IEEE: tf_port_list + empty - // // Empty covered by tf_port_item - /*empty*/ - /*mid*/ { VARRESET_LIST(UNKNOWN); VARIO(INPUT); } - /*cont*/ tf_port_listList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } - ; +tf_port_listE: // IEEE: tf_port_list + empty + // // Empty covered by tf_port_item + /*empty*/ + /*mid*/ { VARRESET_LIST(UNKNOWN); VARIO(INPUT); } + /*cont*/ tf_port_listList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } + ; -tf_port_listList: // IEEE: part of tf_port_list - tf_port_item { $$ = $1; } - | tf_port_listList ',' tf_port_item { $$ = $1->addNextNull($3); } - ; +tf_port_listList: // IEEE: part of tf_port_list + tf_port_item { $$ = $1; } + | tf_port_listList ',' tf_port_item { $$ = $1->addNextNull($3); } + ; -tf_port_item: // ==IEEE: tf_port_item - // // We split tf_port_item into the type and assignment as don't know what follows a comma - /* empty */ { $$ = nullptr; PINNUMINC(); } // For example a ",," port - | tf_port_itemFront tf_port_itemAssignment { $$ = $2; } - | tf_port_itemAssignment { $$ = $1; } - ; +tf_port_item: // ==IEEE: tf_port_item + // // We split tf_port_item into the type and assignment as don't know what follows a comma + /* empty */ { $$ = nullptr; PINNUMINC(); } // For example a ",," port + | tf_port_itemFront tf_port_itemAssignment { $$ = $2; } + | tf_port_itemAssignment { $$ = $1; } + ; -tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type - data_type { VARDTYPE($1); } - | signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, true)); } - | signing { VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT, $1)); } - | yVAR data_type { VARDTYPE($2); } - | yVAR implicit_typeE { VARDTYPE($2); } - // - | tf_port_itemDir /*implicit*/ { VARDTYPE(nullptr); /*default_nettype-see spec*/ } - | tf_port_itemDir data_type { VARDTYPE($2); } - | tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,true)); } - | tf_port_itemDir signing { VARDTYPE(new AstBasicDType($2, LOGIC_IMPLICIT, $2)); } - | tf_port_itemDir yVAR data_type { VARDTYPE($3); } - | tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); } - ; +tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type + data_type { VARDTYPE($1); } + | signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, true)); } + | signing { VARDTYPE(new AstBasicDType($1, LOGIC_IMPLICIT, $1)); } + | yVAR data_type { VARDTYPE($2); } + | yVAR implicit_typeE { VARDTYPE($2); } + // + | tf_port_itemDir /*implicit*/ { VARDTYPE(nullptr); /*default_nettype-see spec*/ } + | tf_port_itemDir data_type { VARDTYPE($2); } + | tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,true)); } + | tf_port_itemDir signing { VARDTYPE(new AstBasicDType($2, LOGIC_IMPLICIT, $2)); } + | tf_port_itemDir yVAR data_type { VARDTYPE($3); } + | tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); } + ; -tf_port_itemDir: // IEEE: part of tf_port_item, direction - port_direction { } // port_direction sets VARIO - ; +tf_port_itemDir: // IEEE: part of tf_port_item, direction + port_direction { } // port_direction sets VARIO + ; -tf_port_itemAssignment: // IEEE: part of tf_port_item, which has assignment - id variable_dimensionListE sigAttrListE exprEqE - { $$ = VARDONEA($1, *$1, $2, $3); if ($4) $$->valuep($4); } - ; +tf_port_itemAssignment: // IEEE: part of tf_port_item, which has assignment + id variable_dimensionListE sigAttrListE exprEqE + { $$ = VARDONEA($1, *$1, $2, $3); if ($4) $$->valuep($4); } + ; parenE: - /* empty */ { } - | '(' ')' { } - ; + /* empty */ { } + | '(' ')' { } + ; -// method_call: // ==IEEE: method_call + method_call_body -// // IEEE: method_call_root '.' method_identifier [ '(' list_of_arguments ')' ] -// // "method_call_root '.' method_identifier" looks just like "expr '.' id" -// // "method_call_root '.' method_identifier (...)" looks just like "expr '.' tf_call" -// // IEEE: built_in_method_call -// // method_call_root not needed, part of expr resolution -// // What's left is below array_methodNoRoot +// method_call: // ==IEEE: method_call + method_call_body +// // IEEE: method_call_root '.' method_identifier [ '(' list_of_arguments ')' ] +// // "method_call_root '.' method_identifier" looks just like "expr '.' id" +// // "method_call_root '.' method_identifier (...)" looks just like "expr '.' tf_call" +// // IEEE: built_in_method_call +// // method_call_root not needed, part of expr resolution +// // What's left is below array_methodNoRoot array_methodNoRoot: - yOR { $$ = new AstFuncRef($1, "or", nullptr); } - | yAND { $$ = new AstFuncRef($1, "and", nullptr); } - | yXOR { $$ = new AstFuncRef($1, "xor", nullptr); } - | yUNIQUE { $$ = new AstFuncRef($1, "unique", nullptr); } - ; + yOR { $$ = new AstFuncRef($1, "or", nullptr); } + | yAND { $$ = new AstFuncRef($1, "and", nullptr); } + | yXOR { $$ = new AstFuncRef($1, "xor", nullptr); } + | yUNIQUE { $$ = new AstFuncRef($1, "unique", nullptr); } + ; array_methodWith: - array_methodNoRoot parenE { $$ = $1; } - | 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(new AstArg($3, "", $3)); } - ; + array_methodNoRoot parenE { $$ = $1; } + | 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(new AstArg($3, "", $3)); } + ; -dpi_import_export: // ==IEEE: dpi_import_export - yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype dpi_tf_TraceInitE ';' - { $$ = $5; - if (*$4 != "") $5->cname(*$4); - $5->dpiContext($3 == iprop_CONTEXT); - $5->pure($3 == iprop_PURE); - $5->dpiImport(true); - $5->dpiTraceInit($6); - GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); - if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding - SYMP->reinsert($$); } - | yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';' - { $$ = $5; - if (*$4 != "") $5->cname(*$4); - $5->dpiContext($3 == iprop_CONTEXT); - $5->pure($3 == iprop_PURE); - $5->dpiImport(true); - $5->dpiTask(true); - GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); - if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding - SYMP->reinsert($$); } - | yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';' - { $$ = new AstDpiExport($5, *$5, *$3); - GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); } - | yEXPORT yaSTRING dpi_importLabelE yTASK idAny ';' - { $$ = new AstDpiExport($5, *$5, *$3); - GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); } - ; +dpi_import_export: // ==IEEE: dpi_import_export + yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype dpi_tf_TraceInitE ';' + { $$ = $5; + if (*$4 != "") $5->cname(*$4); + $5->dpiContext($3 == iprop_CONTEXT); + $5->pure($3 == iprop_PURE); + $5->dpiImport(true); + $5->dpiTraceInit($6); + GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); + if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding + SYMP->reinsert($$); } + | yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';' + { $$ = $5; + if (*$4 != "") $5->cname(*$4); + $5->dpiContext($3 == iprop_CONTEXT); + $5->pure($3 == iprop_PURE); + $5->dpiImport(true); + $5->dpiTask(true); + GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); + if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding + SYMP->reinsert($$); } + | yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';' + { $$ = new AstDpiExport($5, *$5, *$3); + GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); } + | yEXPORT yaSTRING dpi_importLabelE yTASK idAny ';' + { $$ = new AstDpiExport($5, *$5, *$3); + GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); } + ; -dpi_importLabelE: // IEEE: part of dpi_import_export - /* empty */ { static string s; $$ = &s; } - | idAny/*c_identifier*/ '=' { $$ = $1; $$ = $1; } - ; +dpi_importLabelE: // IEEE: part of dpi_import_export + /* empty */ { static string s; $$ = &s; } + | idAny/*c_identifier*/ '=' { $$ = $1; $$ = $1; } + ; -dpi_tf_import_propertyE: // IEEE: [ dpi_function_import_property + dpi_task_import_property ] - /* empty */ { $$ = iprop_NONE; } - | yCONTEXT { $$ = iprop_CONTEXT; } - | yPURE { $$ = iprop_PURE; } - ; +dpi_tf_import_propertyE: // IEEE: [ dpi_function_import_property + dpi_task_import_property ] + /* empty */ { $$ = iprop_NONE; } + | yCONTEXT { $$ = iprop_CONTEXT; } + | yPURE { $$ = iprop_PURE; } + ; -dpi_tf_TraceInitE: // Verilator extension - /* empty */ { $$ = false; } - | yVL_TRACE_INIT_TASK { $$ = true; $$ = $1; } - ; +dpi_tf_TraceInitE: // Verilator extension + /* empty */ { $$ = false; } + | yVL_TRACE_INIT_TASK { $$ = true; $$ = $1; } + ; //************************************************ @@ -4184,1422 +4184,1422 @@ dpi_tf_TraceInitE: // Verilator extension // ~p~ means this is a (p)arenthetized expression // it will get replaced by "", or "s"equence -exprEqE: // IEEE: optional '=' expression (part of param_assignment) - // // constant_param_expression: '$' is in expr - /*empty*/ { $$ = nullptr; } - | '=' expr { $$ = $2; } - ; +exprEqE: // IEEE: optional '=' expression (part of param_assignment) + // // constant_param_expression: '$' is in expr + /*empty*/ { $$ = nullptr; } + | '=' expr { $$ = $2; } + ; -exprOrDataTypeEqE: // IEEE: optional '=' expression (part of param_assignment) - // // constant_param_expression: '$' is in expr - /*empty*/ { $$ = nullptr; } - | '=' exprOrDataType { $$ = $2; } - ; +exprOrDataTypeEqE: // IEEE: optional '=' expression (part of param_assignment) + // // constant_param_expression: '$' is in expr + /*empty*/ { $$ = nullptr; } + | '=' exprOrDataType { $$ = $2; } + ; constExpr: - expr { $$ = $1; } - ; + expr { $$ = $1; } + ; -expr: // IEEE: part of expression/constant_expression/primary - // *SEE BELOW* // IEEE: primary/constant_primary - // - // // IEEE: unary_operator primary - '+' ~r~expr %prec prUNARYARITH { $$ = $2; } - | '-' ~r~expr %prec prUNARYARITH { $$ = new AstNegate ($1,$2); } - | '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); } - | '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); } - | '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); } - | '|' ~r~expr %prec prREDUCTION { $$ = new AstRedOr ($1,$2); } - | '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); } - | yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedAnd($1, $2)); } - | yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedOr($1, $2)); } - | yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedXor($1, $2)); } - // - // // IEEE: inc_or_dec_expression - | ~l~inc_or_dec_expression { $$ = $1; $$ = $1; } - // - // // IEEE: '(' operator_assignment ')' - // // Need exprScope of variable_lvalue to prevent conflict - //UNSUP '(' ~p~exprScope '=' expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_PLUSEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_MINUSEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_TIMESEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_DIVEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_MODEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_ANDEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_OREQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_XOREQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_SLEFTEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_SRIGHTEQ expr ')' { UNSUP } - //UNSUP '(' ~p~exprScope yP_SSRIGHTEQ expr ')' { UNSUP } - // - // // IEEE: expression binary_operator expression - | ~l~expr '+' ~r~expr { $$ = new AstAdd ($2,$1,$3); } - | ~l~expr '-' ~r~expr { $$ = new AstSub ($2,$1,$3); } - | ~l~expr '*' ~r~expr { $$ = new AstMul ($2,$1,$3); } - | ~l~expr '/' ~r~expr { $$ = new AstDiv ($2,$1,$3); } - | ~l~expr '%' ~r~expr { $$ = new AstModDiv ($2,$1,$3); } - | ~l~expr yP_EQUAL ~r~expr { $$ = new AstEq ($2,$1,$3); } - | ~l~expr yP_NOTEQUAL ~r~expr { $$ = new AstNeq ($2,$1,$3); } - | ~l~expr yP_CASEEQUAL ~r~expr { $$ = new AstEqCase ($2,$1,$3); } - | ~l~expr yP_CASENOTEQUAL ~r~expr { $$ = new AstNeqCase ($2,$1,$3); } - | ~l~expr yP_WILDEQUAL ~r~expr { $$ = new AstEqWild ($2,$1,$3); } - | ~l~expr yP_WILDNOTEQUAL ~r~expr { $$ = new AstNeqWild ($2,$1,$3); } - | ~l~expr yP_ANDAND ~r~expr { $$ = new AstLogAnd ($2,$1,$3); } - | ~l~expr yP_OROR ~r~expr { $$ = new AstLogOr ($2,$1,$3); } - | ~l~expr yP_POW ~r~expr { $$ = new AstPow ($2,$1,$3); } - | ~l~expr '<' ~r~expr { $$ = new AstLt ($2,$1,$3); } - | ~l~expr '>' ~r~expr { $$ = new AstGt ($2,$1,$3); } - | ~l~expr yP_GTE ~r~expr { $$ = new AstGte ($2,$1,$3); } - | ~l~expr '&' ~r~expr { $$ = new AstAnd ($2,$1,$3); } - | ~l~expr '|' ~r~expr { $$ = new AstOr ($2,$1,$3); } - | ~l~expr '^' ~r~expr { $$ = new AstXor ($2,$1,$3); } - | ~l~expr yP_XNOR ~r~expr { $$ = new AstNot{$2, new AstXor{$2, $1, $3}}; } - | ~l~expr yP_NOR ~r~expr { $$ = new AstNot{$2, new AstOr{$2, $1, $3}}; } - | ~l~expr yP_NAND ~r~expr { $$ = new AstNot{$2, new AstAnd{$2, $1, $3}}; } - | ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); } - | ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); } - | ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$3); } - | ~l~expr yP_LTMINUSGT ~r~expr { $$ = new AstLogEq ($2,$1,$3); } - // - // // IEEE: expr yP_MINUSGT expr (1800-2009) - // // Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set" - // // To duplicating expr for constraints, just allow the more general form - // // Later Ast processing must ignore constraint terms where inappropriate - //UNSUP ~l~expr yP_MINUSGT constraint_set { $$ = $1; $$ = $1 + $2 + $3; } - //UNSUP remove line below - | ~l~expr yP_MINUSGT ~r~expr { $$ = new AstLogIf($2, $1, $3); } - // - // // <= is special, as we need to disambiguate it with <= assignment - // // We copy all of expr to fexpr and rename this token to a fake one. - | ~l~expr yP_LTE~f__IGNORE~ ~r~expr { $$ = new AstLte($2, $1, $3); } - // - // // IEEE: conditional_expression - | ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); } - // - // // IEEE: inside_expression - | ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); } - // - // // IEEE: tagged_union_expression - //UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP } - //UNSUP yTAGGED id/*member*/ %prec prTAGGED expr { UNSUP } - // - //======================// IEEE: primary/constant_primary - // - // // IEEE: primary_literal (minus string, which is handled specially) - | yaINTNUM { $$ = new AstConst($1,*$1); } - | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } - | timeNumAdjusted { $$ = $1; } - | strAsInt~noStr__IGNORE~ { $$ = $1; } - // - // // IEEE: "... hierarchical_identifier select" see below - // - // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) - | '{' '}' { $$ = new AstEmptyQueue($1); } - // - // // IEEE: concatenation/constant_concatenation - // // Part of exprOkLvalue below - // - // // IEEE: multiple_concatenation/constant_multiple_concatenation - | '{' constExpr '{' cateList '}' '}' { $$ = new AstReplicate($3, $4, $2); } - // // UNSUP some other rules above - // - | function_subroutine_callNoMethod { $$ = $1; } - // // method_call - | ~l~expr '.' function_subroutine_callNoMethod { $$ = new AstDot($2, false, $1, $3); } - // // method_call:array_method requires a '.' - | ~l~expr '.' array_methodWith { $$ = new AstDot($2, false, $1, $3); } - // - // // IEEE: let_expression - // // see funcRef - // - // // IEEE: '(' mintypmax_expression ')' - | ~noPar__IGNORE~'(' expr ')' { $$ = $2; } - | ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' - { $$ = $2; BBUNSUP($1, "Unsupported: min typ max expressions"); } - // // PSL rule - | '_' '(' expr ')' { $$ = $3; } // Arbitrary Verilog inside PSL - // - // // IEEE: cast/constant_cast - // // expanded from casting_type - | simple_type yP_TICK '(' expr ')' { $$ = new AstCast($1->fileline(), $4, VFlagChildDType{}, $1); } - | yTYPE '(' exprOrDataType ')' yP_TICK '(' expr ')' - { $$ = new AstCast($1, $7, VFlagChildDType(), new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3)); } - | ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned($1, $4); } - | yUNSIGNED yP_TICK '(' expr ')' { $$ = new AstUnsigned($1, $4); } - | ySTRING yP_TICK '(' expr ')' { $$ = new AstCvtPackString($1, $4); } - | yCONST__ETC yP_TICK '(' expr ')' { $$ = $4; } // Not linting const presently - // // Spec only allows primary with addition of a type reference - // // We'll be more general, and later assert LHS was a type. - | ~l~expr yP_TICK '(' expr ')' { $$ = new AstCastParse($2, $4, $1); } - // - // // IEEE: assignment_pattern_expression - // // IEEE: streaming_concatenation - // // See exprOkLvalue - // - // // IEEE: sequence_method_call - // // Indistinguishable from function_subroutine_call:method_call - // - | '$' { $$ = new AstUnbounded($1); } - | yNULL { $$ = new AstConst($1, AstConst::Null{}); } - // // IEEE: yTHIS - // // See exprScope - // - //---------------------- - // - // // Part of expr that may also be used as lvalue - | ~l~exprOkLvalue { $$ = $1; } - // - //---------------------- - // - // // IEEE: cond_predicate - here to avoid reduce problems - // // Note expr includes cond_pattern - | ~l~expr yP_ANDANDAND ~r~expr { $$ = new AstConst($2, AstConst::BitFalse()); - BBUNSUP($2, "Unsupported: &&& expression"); } - // - // // IEEE: cond_pattern - here to avoid reduce problems - // // "expr yMATCHES pattern" - // // IEEE: pattern - expanded here to avoid conflicts - //UNSUP ~l~expr yMATCHES patternNoExpr { UNSUP } - //UNSUP ~l~expr yMATCHES ~r~expr { UNSUP } - // - // // IEEE: expression_or_dist - here to avoid reduce problems - // // "expr yDIST '{' dist_list '}'" - | ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); } - ; +expr: // IEEE: part of expression/constant_expression/primary + // *SEE BELOW* // IEEE: primary/constant_primary + // + // // IEEE: unary_operator primary + '+' ~r~expr %prec prUNARYARITH { $$ = $2; } + | '-' ~r~expr %prec prUNARYARITH { $$ = new AstNegate ($1,$2); } + | '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); } + | '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); } + | '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); } + | '|' ~r~expr %prec prREDUCTION { $$ = new AstRedOr ($1,$2); } + | '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); } + | yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedAnd($1, $2)); } + | yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedOr($1, $2)); } + | yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1, new AstRedXor($1, $2)); } + // + // // IEEE: inc_or_dec_expression + | ~l~inc_or_dec_expression { $$ = $1; $$ = $1; } + // + // // IEEE: '(' operator_assignment ')' + // // Need exprScope of variable_lvalue to prevent conflict + //UNSUP '(' ~p~exprScope '=' expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_PLUSEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_MINUSEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_TIMESEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_DIVEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_MODEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_ANDEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_OREQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_XOREQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_SLEFTEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_SRIGHTEQ expr ')' { UNSUP } + //UNSUP '(' ~p~exprScope yP_SSRIGHTEQ expr ')' { UNSUP } + // + // // IEEE: expression binary_operator expression + | ~l~expr '+' ~r~expr { $$ = new AstAdd ($2,$1,$3); } + | ~l~expr '-' ~r~expr { $$ = new AstSub ($2,$1,$3); } + | ~l~expr '*' ~r~expr { $$ = new AstMul ($2,$1,$3); } + | ~l~expr '/' ~r~expr { $$ = new AstDiv ($2,$1,$3); } + | ~l~expr '%' ~r~expr { $$ = new AstModDiv ($2,$1,$3); } + | ~l~expr yP_EQUAL ~r~expr { $$ = new AstEq ($2,$1,$3); } + | ~l~expr yP_NOTEQUAL ~r~expr { $$ = new AstNeq ($2,$1,$3); } + | ~l~expr yP_CASEEQUAL ~r~expr { $$ = new AstEqCase ($2,$1,$3); } + | ~l~expr yP_CASENOTEQUAL ~r~expr { $$ = new AstNeqCase ($2,$1,$3); } + | ~l~expr yP_WILDEQUAL ~r~expr { $$ = new AstEqWild ($2,$1,$3); } + | ~l~expr yP_WILDNOTEQUAL ~r~expr { $$ = new AstNeqWild ($2,$1,$3); } + | ~l~expr yP_ANDAND ~r~expr { $$ = new AstLogAnd ($2,$1,$3); } + | ~l~expr yP_OROR ~r~expr { $$ = new AstLogOr ($2,$1,$3); } + | ~l~expr yP_POW ~r~expr { $$ = new AstPow ($2,$1,$3); } + | ~l~expr '<' ~r~expr { $$ = new AstLt ($2,$1,$3); } + | ~l~expr '>' ~r~expr { $$ = new AstGt ($2,$1,$3); } + | ~l~expr yP_GTE ~r~expr { $$ = new AstGte ($2,$1,$3); } + | ~l~expr '&' ~r~expr { $$ = new AstAnd ($2,$1,$3); } + | ~l~expr '|' ~r~expr { $$ = new AstOr ($2,$1,$3); } + | ~l~expr '^' ~r~expr { $$ = new AstXor ($2,$1,$3); } + | ~l~expr yP_XNOR ~r~expr { $$ = new AstNot{$2, new AstXor{$2, $1, $3}}; } + | ~l~expr yP_NOR ~r~expr { $$ = new AstNot{$2, new AstOr{$2, $1, $3}}; } + | ~l~expr yP_NAND ~r~expr { $$ = new AstNot{$2, new AstAnd{$2, $1, $3}}; } + | ~l~expr yP_SLEFT ~r~expr { $$ = new AstShiftL ($2,$1,$3); } + | ~l~expr yP_SRIGHT ~r~expr { $$ = new AstShiftR ($2,$1,$3); } + | ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS ($2,$1,$3); } + | ~l~expr yP_LTMINUSGT ~r~expr { $$ = new AstLogEq ($2,$1,$3); } + // + // // IEEE: expr yP_MINUSGT expr (1800-2009) + // // Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set" + // // To duplicating expr for constraints, just allow the more general form + // // Later Ast processing must ignore constraint terms where inappropriate + //UNSUP ~l~expr yP_MINUSGT constraint_set { $$ = $1; $$ = $1 + $2 + $3; } + //UNSUP remove line below + | ~l~expr yP_MINUSGT ~r~expr { $$ = new AstLogIf($2, $1, $3); } + // + // // <= is special, as we need to disambiguate it with <= assignment + // // We copy all of expr to fexpr and rename this token to a fake one. + | ~l~expr yP_LTE~f__IGNORE~ ~r~expr { $$ = new AstLte($2, $1, $3); } + // + // // IEEE: conditional_expression + | ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); } + // + // // IEEE: inside_expression + | ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); } + // + // // IEEE: tagged_union_expression + //UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP } + //UNSUP yTAGGED id/*member*/ %prec prTAGGED expr { UNSUP } + // + //======================// IEEE: primary/constant_primary + // + // // IEEE: primary_literal (minus string, which is handled specially) + | yaINTNUM { $$ = new AstConst($1,*$1); } + | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } + | timeNumAdjusted { $$ = $1; } + | strAsInt~noStr__IGNORE~ { $$ = $1; } + // + // // IEEE: "... hierarchical_identifier select" see below + // + // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) + | '{' '}' { $$ = new AstEmptyQueue($1); } + // + // // IEEE: concatenation/constant_concatenation + // // Part of exprOkLvalue below + // + // // IEEE: multiple_concatenation/constant_multiple_concatenation + | '{' constExpr '{' cateList '}' '}' { $$ = new AstReplicate($3, $4, $2); } + // // UNSUP some other rules above + // + | function_subroutine_callNoMethod { $$ = $1; } + // // method_call + | ~l~expr '.' function_subroutine_callNoMethod { $$ = new AstDot($2, false, $1, $3); } + // // method_call:array_method requires a '.' + | ~l~expr '.' array_methodWith { $$ = new AstDot($2, false, $1, $3); } + // + // // IEEE: let_expression + // // see funcRef + // + // // IEEE: '(' mintypmax_expression ')' + | ~noPar__IGNORE~'(' expr ')' { $$ = $2; } + | ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' + { $$ = $2; BBUNSUP($1, "Unsupported: min typ max expressions"); } + // // PSL rule + | '_' '(' expr ')' { $$ = $3; } // Arbitrary Verilog inside PSL + // + // // IEEE: cast/constant_cast + // // expanded from casting_type + | simple_type yP_TICK '(' expr ')' { $$ = new AstCast($1->fileline(), $4, VFlagChildDType{}, $1); } + | yTYPE '(' exprOrDataType ')' yP_TICK '(' expr ')' + { $$ = new AstCast($1, $7, VFlagChildDType(), new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3)); } + | ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned($1, $4); } + | yUNSIGNED yP_TICK '(' expr ')' { $$ = new AstUnsigned($1, $4); } + | ySTRING yP_TICK '(' expr ')' { $$ = new AstCvtPackString($1, $4); } + | yCONST__ETC yP_TICK '(' expr ')' { $$ = $4; } // Not linting const presently + // // Spec only allows primary with addition of a type reference + // // We'll be more general, and later assert LHS was a type. + | ~l~expr yP_TICK '(' expr ')' { $$ = new AstCastParse($2, $4, $1); } + // + // // IEEE: assignment_pattern_expression + // // IEEE: streaming_concatenation + // // See exprOkLvalue + // + // // IEEE: sequence_method_call + // // Indistinguishable from function_subroutine_call:method_call + // + | '$' { $$ = new AstUnbounded($1); } + | yNULL { $$ = new AstConst($1, AstConst::Null{}); } + // // IEEE: yTHIS + // // See exprScope + // + //---------------------- + // + // // Part of expr that may also be used as lvalue + | ~l~exprOkLvalue { $$ = $1; } + // + //---------------------- + // + // // IEEE: cond_predicate - here to avoid reduce problems + // // Note expr includes cond_pattern + | ~l~expr yP_ANDANDAND ~r~expr { $$ = new AstConst($2, AstConst::BitFalse()); + BBUNSUP($2, "Unsupported: &&& expression"); } + // + // // IEEE: cond_pattern - here to avoid reduce problems + // // "expr yMATCHES pattern" + // // IEEE: pattern - expanded here to avoid conflicts + //UNSUP ~l~expr yMATCHES patternNoExpr { UNSUP } + //UNSUP ~l~expr yMATCHES ~r~expr { UNSUP } + // + // // IEEE: expression_or_dist - here to avoid reduce problems + // // "expr yDIST '{' dist_list '}'" + | ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); } + ; -fexpr: // For use as first part of statement (disambiguates <=) - BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} - ; +fexpr: // For use as first part of statement (disambiguates <=) + BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} + ; //UNSUPev_expr: // IEEE: event_expression -//UNSUP // // for yOR/, see event_expression -//UNSUP // -//UNSUP // // IEEE: [ edge_identifier ] expression [ yIFF expression ] -//UNSUP // // expr alone see below -//UNSUP senitemEdge { $$ = $1; } -//UNSUP | ev_expr yIFF expr { } -//UNSUP // -//UNSUP // // IEEE: sequence_instance [ yIFF expression ] -//UNSUP // // seq_inst is in expr, so matches senitem rule above -//UNSUP // -//UNSUP // // IEEE: event_expression yOR event_expression -//UNSUP | ev_expr yOR ev_expr { } -//UNSUP // // IEEE: event_expression ',' event_expression -//UNSUP // // See real event_expression rule -//UNSUP // -//UNSUP //--------------------- -//UNSUP // // IEEE: expr -//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g;}) // {copied} -//UNSUP // -//UNSUP // // IEEE: '(' event_expression ')' -//UNSUP // // expr:'(' x ')' conflicts with event_expression:'(' event_expression ')' -//UNSUP // // so we use a special expression class -//UNSUP | '(' event_expression ')' { $$ = $1; $$ = "(...)"; } -//UNSUP // // IEEE: From normal expr: '(' expr ':' expr ':' expr ')' -//UNSUP // // But must avoid conflict -//UNSUP | '(' event_expression ':' expr ':' expr ')' { $$ = $1; $$ = "(...)"; } -//UNSUP ; +//UNSUP // // for yOR/, see event_expression +//UNSUP // +//UNSUP // // IEEE: [ edge_identifier ] expression [ yIFF expression ] +//UNSUP // // expr alone see below +//UNSUP senitemEdge { $$ = $1; } +//UNSUP | ev_expr yIFF expr { } +//UNSUP // +//UNSUP // // IEEE: sequence_instance [ yIFF expression ] +//UNSUP // // seq_inst is in expr, so matches senitem rule above +//UNSUP // +//UNSUP // // IEEE: event_expression yOR event_expression +//UNSUP | ev_expr yOR ev_expr { } +//UNSUP // // IEEE: event_expression ',' event_expression +//UNSUP // // See real event_expression rule +//UNSUP // +//UNSUP //--------------------- +//UNSUP // // IEEE: expr +//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g;}) // {copied} +//UNSUP // +//UNSUP // // IEEE: '(' event_expression ')' +//UNSUP // // expr:'(' x ')' conflicts with event_expression:'(' event_expression ')' +//UNSUP // // so we use a special expression class +//UNSUP | '(' event_expression ')' { $$ = $1; $$ = "(...)"; } +//UNSUP // // IEEE: From normal expr: '(' expr ':' expr ':' expr ')' +//UNSUP // // But must avoid conflict +//UNSUP | '(' event_expression ':' expr ':' expr ')' { $$ = $1; $$ = "(...)"; } +//UNSUP ; -exprNoStr: // expression with string removed - BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} - ; +exprNoStr: // expression with string removed + BISONPRE_COPY(expr,{s/~noStr__IGNORE~/Ignore/g;}) // {copied} + ; -exprOkLvalue: // expression that's also OK to use as a variable_lvalue - ~l~exprScope { $$ = $1; } - // // IEEE: concatenation/constant_concatenation - // // Replicate(1) required as otherwise "{a}" would not be self-determined - | '{' cateList '}' { $$ = new AstReplicate($1,$2,1); } - | '{' cateList '}' '[' expr ']' { $$ = new AstSelBit($4, new AstReplicate($1,$2,1), $5); } - | '{' cateList '}' '[' constExpr ':' constExpr ']' - { $$ = new AstSelExtract($4, new AstReplicate($1,$2,1), $5, $7); } - | '{' cateList '}' '[' expr yP_PLUSCOLON constExpr ']' - { $$ = new AstSelPlus($4, new AstReplicate($1,$2,1), $5, $7); } - | '{' cateList '}' '[' expr yP_MINUSCOLON constExpr ']' - { $$ = new AstSelMinus($4, new AstReplicate($1,$2,1), $5, $7); } - // // IEEE: assignment_pattern_expression - // // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type] - // // We allow more here than the spec requires - //UNSUP ~l~exprScope assignment_pattern { UNSUP } - | data_type assignment_pattern { $$ = $2; if ($2) $2->childDTypep($1); } - | assignment_pattern { $$ = $1; } - // - | streaming_concatenation { $$ = $1; } - ; +exprOkLvalue: // expression that's also OK to use as a variable_lvalue + ~l~exprScope { $$ = $1; } + // // IEEE: concatenation/constant_concatenation + // // Replicate(1) required as otherwise "{a}" would not be self-determined + | '{' cateList '}' { $$ = new AstReplicate($1,$2,1); } + | '{' cateList '}' '[' expr ']' { $$ = new AstSelBit($4, new AstReplicate($1,$2,1), $5); } + | '{' cateList '}' '[' constExpr ':' constExpr ']' + { $$ = new AstSelExtract($4, new AstReplicate($1,$2,1), $5, $7); } + | '{' cateList '}' '[' expr yP_PLUSCOLON constExpr ']' + { $$ = new AstSelPlus($4, new AstReplicate($1,$2,1), $5, $7); } + | '{' cateList '}' '[' expr yP_MINUSCOLON constExpr ']' + { $$ = new AstSelMinus($4, new AstReplicate($1,$2,1), $5, $7); } + // // IEEE: assignment_pattern_expression + // // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type] + // // We allow more here than the spec requires + //UNSUP ~l~exprScope assignment_pattern { UNSUP } + | data_type assignment_pattern { $$ = $2; if ($2) $2->childDTypep($1); } + | assignment_pattern { $$ = $1; } + // + | streaming_concatenation { $$ = $1; } + ; -fexprOkLvalue: // exprOkLValue, For use as first part of statement (disambiguates <=) - BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} - ; +fexprOkLvalue: // exprOkLValue, For use as first part of statement (disambiguates <=) + BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} + ; //UNSUPsexprOkLvalue: // exprOkLValue, For use by sequence_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} +//UNSUP ; //UNSUPpexprOkLvalue: // exprOkLValue, For use by property_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} +//UNSUP ; //UNSUPev_exprOkLvalue: // exprOkLValue, For use by ev_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g}) // {copied} +//UNSUP ; //UNSUPpev_exprOkLvalue: // exprOkLValue, For use by ev_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} +//UNSUP ; -fexprLvalue: // For use as first part of statement (disambiguates <=) - fexprOkLvalue { $$ = $1; $$ = $1; } - ; +fexprLvalue: // For use as first part of statement (disambiguates <=) + fexprOkLvalue { $$ = $1; $$ = $1; } + ; -exprScope: // scope and variable for use to inside an expression - // // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope - // // from the object being called and let expr's "." deal with resolving it. - // // (note method_call_root was simplified to require a primary in 1800-2009) - // - // // IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select - // // Or method_call_body without parenthesis - // // See also varRefClassBit, which is the non-expr version of most of this - yTHIS { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "this"); } - | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } - | idArrayed { $$ = $1; } - | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } - | ~l~expr '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } - // // expr below must be a "yTHIS" - | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } - // // Part of implicit_class_handle - | ySUPER { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "super"); } - ; +exprScope: // scope and variable for use to inside an expression + // // Here we've split method_call_root | implicit_class_handle | class_scope | package_scope + // // from the object being called and let expr's "." deal with resolving it. + // // (note method_call_root was simplified to require a primary in 1800-2009) + // + // // IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select + // // Or method_call_body without parenthesis + // // See also varRefClassBit, which is the non-expr version of most of this + yTHIS { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "this"); } + | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } + | idArrayed { $$ = $1; } + | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } + | ~l~expr '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } + // // expr below must be a "yTHIS" + | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } + // // Part of implicit_class_handle + | ySUPER { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "super"); } + ; -fexprScope: // exprScope, For use as first part of statement (disambiguates <=) - BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} - ; +fexprScope: // exprScope, For use as first part of statement (disambiguates <=) + BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} + ; //UNSUPsexprScope: // exprScope, For use by sequence_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} +//UNSUP ; //UNSUPpexprScope: // exprScope, For use by property_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} +//UNSUP ; //UNSUPev_exprScope: // exprScope, For use by ev_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/ev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprScope,{s/~l~/ev_/g}) // {copied} +//UNSUP ; //UNSUPpev_exprScope: // exprScope, For use by ev_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/pev_/g}) // {copied} -//UNSUP ; +//UNSUP BISONPRE_COPY(exprScope,{s/~l~/pev_/g}) // {copied} +//UNSUP ; // PLI calls exclude "" as integers, they're strings // For $c("foo","bar") we want "bar" as a string, not a Verilog integer. exprStrText: - exprNoStr { $$ = $1; } - | strAsText { $$ = $1; } - ; + exprNoStr { $$ = $1; } + | strAsText { $$ = $1; } + ; cStrList: - exprStrText { $$ = $1; } - | exprStrText ',' cStrList { $$ = $1; $1->addNext($3); } - ; + exprStrText { $$ = $1; } + | exprStrText ',' cStrList { $$ = $1; $1->addNext($3); } + ; cateList: - // // Not just 'expr' to prevent conflict via stream_concOrExprOrType - stream_expression { $$ = $1; } - | cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); } - ; + // // Not just 'expr' to prevent conflict via stream_concOrExprOrType + stream_expression { $$ = $1; } + | cateList ',' stream_expression { $$ = new AstConcat($2,$1,$3); } + ; exprListE: - /* empty */ { $$ = nullptr; } - | exprList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | exprList { $$ = $1; } + ; exprList: - expr { $$ = $1; } - | exprList ',' expr { $$ = $1; $1->addNext($3); } - ; + expr { $$ = $1; } + | exprList ',' expr { $$ = $1; $1->addNext($3); } + ; -exprDispList: // exprList for within $display - expr { $$ = $1; } - | exprDispList ',' expr { $$ = $1; $1->addNext($3); } - // // ,, creates a space in $display - | exprDispList ',' /*empty*/ - { $$ = $1; $1->addNext(new AstConst($2, AstConst::VerilogStringLiteral(), " ")); } - ; +exprDispList: // exprList for within $display + expr { $$ = $1; } + | exprDispList ',' expr { $$ = $1; $1->addNext($3); } + // // ,, creates a space in $display + | exprDispList ',' /*empty*/ + { $$ = $1; $1->addNext(new AstConst($2, AstConst::VerilogStringLiteral(), " ")); } + ; vrdList: - idClassSel { $$ = $1; } - | vrdList ',' idClassSel { $$ = $1; $1->addNext($3); } - ; + idClassSel { $$ = $1; } + | vrdList ',' idClassSel { $$ = $1; $1->addNext($3); } + ; commaVRDListE: - /* empty */ { $$ = nullptr; } - | ',' vrdList { $$ = $2; } - ; + /* empty */ { $$ = nullptr; } + | ',' vrdList { $$ = $2; } + ; -argsExprList: // IEEE: part of list_of_arguments (used where ,, isn't legal) - expr { $$ = $1; } - | argsExprList ',' expr { $$ = $1->addNext($3); } - ; +argsExprList: // IEEE: part of list_of_arguments (used where ,, isn't legal) + expr { $$ = $1; } + | argsExprList ',' expr { $$ = $1->addNext($3); } + ; -argsExprListE: // IEEE: part of list_of_arguments - argsExprOneE { $$ = $1; } - | argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); } - ; +argsExprListE: // IEEE: part of list_of_arguments + argsExprOneE { $$ = $1; } + | argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); } + ; //UNSUPpev_argsExprListE: // IEEE: part of list_of_arguments - pev_expr at bottom -//UNSUP pev_argsExprOneE { $$ = $1; } -//UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP pev_argsExprOneE { $$ = $1; } +//UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; -argsExprOneE: // IEEE: part of list_of_arguments - /*empty*/ { $$ = new AstArg(CRELINE(), "", nullptr); } - | expr { $$ = new AstArg($1->fileline(), "", $1); } - ; +argsExprOneE: // IEEE: part of list_of_arguments + /*empty*/ { $$ = new AstArg(CRELINE(), "", nullptr); } + | expr { $$ = new AstArg($1->fileline(), "", $1); } + ; //UNSUPpev_argsExprOneE: // IEEE: part of list_of_arguments - pev_expr at bottom -//UNSUP /*empty*/ { $$ = nullptr; } // ,, is legal in list_of_arguments -//UNSUP | pev_expr { $$ = $1; } -//UNSUP ; +//UNSUP /*empty*/ { $$ = nullptr; } // ,, is legal in list_of_arguments +//UNSUP | pev_expr { $$ = $1; } +//UNSUP ; -argsDottedList: // IEEE: part of list_of_arguments - argsDotted { $$ = $1; } - | argsDottedList ',' argsDotted { $$ = $1->addNextNull($3); } - ; +argsDottedList: // IEEE: part of list_of_arguments + argsDotted { $$ = $1; } + | argsDottedList ',' argsDotted { $$ = $1->addNextNull($3); } + ; //UNSUPpev_argsDottedList: // IEEE: part of list_of_arguments - pev_expr at bottom -//UNSUP pev_argsDotted { $$ = $1; } -//UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP pev_argsDotted { $$ = $1; } +//UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; -argsDotted: // IEEE: part of list_of_arguments - '.' idAny '(' ')' { $$ = new AstArg($2, *$2, nullptr); } - | '.' idAny '(' expr ')' { $$ = new AstArg($2, *$2, $4); } - ; +argsDotted: // IEEE: part of list_of_arguments + '.' idAny '(' ')' { $$ = new AstArg($2, *$2, nullptr); } + | '.' idAny '(' expr ')' { $$ = new AstArg($2, *$2, $4); } + ; //UNSUPpev_argsDotted: // IEEE: part of list_of_arguments - pev_expr at bottom -//UNSUP '.' idAny '(' ')' { $$ = new AstArg($2, *$2, nullptr); } -//UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($2, *$2, $4); } -//UNSUP ; +//UNSUP '.' idAny '(' ')' { $$ = new AstArg($2, *$2, nullptr); } +//UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg($2, *$2, $4); } +//UNSUP ; -streaming_concatenation: // ==IEEE: streaming_concatenation - // // Need to disambiguate {<< expr-{ ... expr-} stream_concat } - // // From {<< stream-{ ... stream-} } - // // Likewise simple_type's idScoped from constExpr's idScope - // // Thus we allow always any two operations. Sorry - // // IEEE: "'{' yP_SL/R stream_concatenation '}'" - // // IEEE: "'{' yP_SL/R simple_type stream_concatenation '}'" - // // IEEE: "'{' yP_SL/R constExpr stream_concatenation '}'" - '{' yP_SLEFT stream_concatenation '}' - { $$ = new AstStreamL($2, $3, new AstConst($2, 1)); } - | '{' yP_SRIGHT stream_concatenation '}' - { $$ = new AstStreamR($2, $3, new AstConst($2, 1)); } - | '{' yP_SLEFT stream_expressionOrDataType stream_concatenation '}' - { $$ = new AstStreamL($2, $4, $3); } - | '{' yP_SRIGHT stream_expressionOrDataType stream_concatenation '}' - { $$ = new AstStreamR($2, $4, $3); } - ; +streaming_concatenation: // ==IEEE: streaming_concatenation + // // Need to disambiguate {<< expr-{ ... expr-} stream_concat } + // // From {<< stream-{ ... stream-} } + // // Likewise simple_type's idScoped from constExpr's idScope + // // Thus we allow always any two operations. Sorry + // // IEEE: "'{' yP_SL/R stream_concatenation '}'" + // // IEEE: "'{' yP_SL/R simple_type stream_concatenation '}'" + // // IEEE: "'{' yP_SL/R constExpr stream_concatenation '}'" + '{' yP_SLEFT stream_concatenation '}' + { $$ = new AstStreamL($2, $3, new AstConst($2, 1)); } + | '{' yP_SRIGHT stream_concatenation '}' + { $$ = new AstStreamR($2, $3, new AstConst($2, 1)); } + | '{' yP_SLEFT stream_expressionOrDataType stream_concatenation '}' + { $$ = new AstStreamL($2, $4, $3); } + | '{' yP_SRIGHT stream_expressionOrDataType stream_concatenation '}' + { $$ = new AstStreamR($2, $4, $3); } + ; -stream_concatenation: // ==IEEE: stream_concatenation - // // '{' { stream_expression } '}' - '{' cateList '}' { $$ = $2; } - ; +stream_concatenation: // ==IEEE: stream_concatenation + // // '{' { stream_expression } '}' + '{' cateList '}' { $$ = $2; } + ; -stream_expression: // ==IEEE: stream_expression - // // IEEE: array_range_expression expanded below - expr { $$ = $1; } - //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } - ; +stream_expression: // ==IEEE: stream_expression + // // IEEE: array_range_expression expanded below + expr { $$ = $1; } + //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } + ; -stream_expressionOrDataType: // IEEE: from streaming_concatenation - exprOrDataType { $$ = $1; } - //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } - ; +stream_expressionOrDataType: // IEEE: from streaming_concatenation + exprOrDataType { $$ = $1; } + //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } + //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } + ; //************************************************ // Gate declarations gateDecl: - yBUF delayE gateBufList ';' { $$ = $3; } - | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; } - | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; } - | yNOT delayE gateNotList ';' { $$ = $3; } - | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; } - | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; } - | yAND delayE gateAndList ';' { $$ = $3; } - | yNAND delayE gateNandList ';' { $$ = $3; } - | yOR delayE gateOrList ';' { $$ = $3; } - | yNOR delayE gateNorList ';' { $$ = $3; } - | yXOR delayE gateXorList ';' { $$ = $3; } - | yXNOR delayE gateXnorList ';' { $$ = $3; } - | yPULLUP delayE gatePullupList ';' { $$ = $3; } - | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; } - | yNMOS delayE gateBufif1List ';' { $$ = $3; } // ~=bufif1, as don't have strengths yet - | yPMOS delayE gateBufif0List ';' { $$ = $3; } // ~=bufif0, as don't have strengths yet - // - | yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported - | yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported - | yCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported - | yRNMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported - | yRPMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported - | yRTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported - | yRTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported - | yRTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported - | yTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported - | yTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported - ; + yBUF delayE gateBufList ';' { $$ = $3; } + | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; } + | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; } + | yNOT delayE gateNotList ';' { $$ = $3; } + | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; } + | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; } + | yAND delayE gateAndList ';' { $$ = $3; } + | yNAND delayE gateNandList ';' { $$ = $3; } + | yOR delayE gateOrList ';' { $$ = $3; } + | yNOR delayE gateNorList ';' { $$ = $3; } + | yXOR delayE gateXorList ';' { $$ = $3; } + | yXNOR delayE gateXnorList ';' { $$ = $3; } + | yPULLUP delayE gatePullupList ';' { $$ = $3; } + | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; } + | yNMOS delayE gateBufif1List ';' { $$ = $3; } // ~=bufif1, as don't have strengths yet + | yPMOS delayE gateBufif0List ';' { $$ = $3; } // ~=bufif0, as don't have strengths yet + // + | yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported + | yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported + | yCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported + | yRNMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported + | yRPMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported + | yRTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported + | yRTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported + | yRTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported + | yTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported + | yTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported + ; gateBufList: - gateBuf { $$ = $1; } - | gateBufList ',' gateBuf { $$ = $1->addNext($3); } - ; + gateBuf { $$ = $1; } + | gateBufList ',' gateBuf { $$ = $1->addNext($3); } + ; gateBufif0List: - gateBufif0 { $$ = $1; } - | gateBufif0List ',' gateBufif0 { $$ = $1->addNext($3); } - ; + gateBufif0 { $$ = $1; } + | gateBufif0List ',' gateBufif0 { $$ = $1->addNext($3); } + ; gateBufif1List: - gateBufif1 { $$ = $1; } - | gateBufif1List ',' gateBufif1 { $$ = $1->addNext($3); } - ; + gateBufif1 { $$ = $1; } + | gateBufif1List ',' gateBufif1 { $$ = $1->addNext($3); } + ; gateNotList: - gateNot { $$ = $1; } - | gateNotList ',' gateNot { $$ = $1->addNext($3); } - ; + gateNot { $$ = $1; } + | gateNotList ',' gateNot { $$ = $1->addNext($3); } + ; gateNotif0List: - gateNotif0 { $$ = $1; } - | gateNotif0List ',' gateNotif0 { $$ = $1->addNext($3); } - ; + gateNotif0 { $$ = $1; } + | gateNotif0List ',' gateNotif0 { $$ = $1->addNext($3); } + ; gateNotif1List: - gateNotif1 { $$ = $1; } - | gateNotif1List ',' gateNotif1 { $$ = $1->addNext($3); } - ; + gateNotif1 { $$ = $1; } + | gateNotif1List ',' gateNotif1 { $$ = $1->addNext($3); } + ; gateAndList: - gateAnd { $$ = $1; } - | gateAndList ',' gateAnd { $$ = $1->addNext($3); } - ; + gateAnd { $$ = $1; } + | gateAndList ',' gateAnd { $$ = $1->addNext($3); } + ; gateNandList: - gateNand { $$ = $1; } - | gateNandList ',' gateNand { $$ = $1->addNext($3); } - ; + gateNand { $$ = $1; } + | gateNandList ',' gateNand { $$ = $1->addNext($3); } + ; gateOrList: - gateOr { $$ = $1; } - | gateOrList ',' gateOr { $$ = $1->addNext($3); } - ; + gateOr { $$ = $1; } + | gateOrList ',' gateOr { $$ = $1->addNext($3); } + ; gateNorList: - gateNor { $$ = $1; } - | gateNorList ',' gateNor { $$ = $1->addNext($3); } - ; + gateNor { $$ = $1; } + | gateNorList ',' gateNor { $$ = $1->addNext($3); } + ; gateXorList: - gateXor { $$ = $1; } - | gateXorList ',' gateXor { $$ = $1->addNext($3); } - ; + gateXor { $$ = $1; } + | gateXorList ',' gateXor { $$ = $1->addNext($3); } + ; gateXnorList: - gateXnor { $$ = $1; } - | gateXnorList ',' gateXnor { $$ = $1->addNext($3); } - ; + gateXnor { $$ = $1; } + | gateXnorList ',' gateXnor { $$ = $1->addNext($3); } + ; gatePullupList: - gatePullup { $$ = $1; } - | gatePullupList ',' gatePullup { $$ = $1->addNext($3); } - ; + gatePullup { $$ = $1; } + | gatePullupList ',' gatePullup { $$ = $1->addNext($3); } + ; gatePulldownList: - gatePulldown { $$ = $1; } - | gatePulldownList ',' gatePulldown { $$ = $1->addNext($3); } - ; + gatePulldown { $$ = $1; } + | gatePulldownList ',' gatePulldown { $$ = $1->addNext($3); } + ; gateUnsupList: - gateUnsup { $$ = $1; } - | gateUnsupList ',' gateUnsup { $$ = $1->addNext($3); } - ; + gateUnsup { $$ = $1; } + | gateUnsupList ',' gateUnsup { $$ = $1->addNext($3); } + ; gateRangeE: - instRangeListE { $$ = $1; GATERANGE(GRAMMARP->scrubRange($1)); } - ; + instRangeListE { $$ = $1; GATERANGE(GRAMMARP->scrubRange($1)); } + ; gateBuf: - gateFront variable_lvalue ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, $4); DEL($1); } - // UNSUP // IEEE: Multiple output variable_lvalues - // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr - ; + gateFront variable_lvalue ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, $4); DEL($1); } + // UNSUP // IEEE: Multiple output variable_lvalues + // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr + ; gateBufif0: - gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, new AstBufIf1($1, new AstNot($1, $6), $4)); DEL($1); } - ; + gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, new AstBufIf1($1, new AstNot($1, $6), $4)); DEL($1); } + ; gateBufif1: - gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, new AstBufIf1($1, $6, $4)); DEL($1); } - ; + gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, new AstBufIf1($1, $6, $4)); DEL($1); } + ; gateNot: - gateFront variable_lvalue ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } - // UNSUP // IEEE: Multiple output variable_lvalues - // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr - ; + gateFront variable_lvalue ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } + // UNSUP // IEEE: Multiple output variable_lvalues + // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr + ; gateNotif0: - gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, new AstBufIf1($1, new AstNot($1, $6), - new AstNot($1, $4))); DEL($1); } - ; + gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, new AstBufIf1($1, new AstNot($1, $6), + new AstNot($1, $4))); DEL($1); } + ; gateNotif1: - gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' - { $$ = new AstAssignW($1, $2, new AstBufIf1($1, $6, new AstNot($1, $4))); DEL($1); } - ; + gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' + { $$ = new AstAssignW($1, $2, new AstBufIf1($1, $6, new AstNot($1, $4))); DEL($1); } + ; gateAnd: - gateFront variable_lvalue ',' gateAndPinList ')' - { $$ = new AstAssignW($1, $2, $4); DEL($1); } - ; + gateFront variable_lvalue ',' gateAndPinList ')' + { $$ = new AstAssignW($1, $2, $4); DEL($1); } + ; gateNand: - gateFront variable_lvalue ',' gateAndPinList ')' - { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } - ; + gateFront variable_lvalue ',' gateAndPinList ')' + { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } + ; gateOr: - gateFront variable_lvalue ',' gateOrPinList ')' - { $$ = new AstAssignW($1, $2, $4); DEL($1); } - ; + gateFront variable_lvalue ',' gateOrPinList ')' + { $$ = new AstAssignW($1, $2, $4); DEL($1); } + ; gateNor: - gateFront variable_lvalue ',' gateOrPinList ')' - { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } - ; + gateFront variable_lvalue ',' gateOrPinList ')' + { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } + ; gateXor: - gateFront variable_lvalue ',' gateXorPinList ')' - { $$ = new AstAssignW($1, $2, $4); DEL($1); } - ; + gateFront variable_lvalue ',' gateXorPinList ')' + { $$ = new AstAssignW($1, $2, $4); DEL($1); } + ; gateXnor: - gateFront variable_lvalue ',' gateXorPinList ')' - { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } - ; + gateFront variable_lvalue ',' gateXorPinList ')' + { $$ = new AstAssignW($1, $2, new AstNot($1, $4)); DEL($1); } + ; gatePullup: - gateFront variable_lvalue ')' { $$ = new AstPull($1, $2, true); DEL($1); } - ; + gateFront variable_lvalue ')' { $$ = new AstPull($1, $2, true); DEL($1); } + ; gatePulldown: - gateFront variable_lvalue ')' { $$ = new AstPull($1, $2, false); DEL($1); } - ; + gateFront variable_lvalue ')' { $$ = new AstPull($1, $2, false); DEL($1); } + ; gateUnsup: - gateFront gateUnsupPinList ')' { $$ = new AstImplicit($1, $2); DEL($1); } - ; + gateFront gateUnsupPinList ')' { $$ = new AstImplicit($1, $2); DEL($1); } + ; gateFront: - id/*gate*/ gateRangeE '(' { $$ = $2; $$ = $1; } - | gateRangeE '(' { $$ = $1; $$ = $2; } - ; + id/*gate*/ gateRangeE '(' { $$ = $2; $$ = $1; } + | gateRangeE '(' { $$ = $1; $$ = $2; } + ; gateAndPinList: - gatePinExpr { $$ = $1; } - | gateAndPinList ',' gatePinExpr { $$ = new AstAnd($2,$1,$3); } - ; + gatePinExpr { $$ = $1; } + | gateAndPinList ',' gatePinExpr { $$ = new AstAnd($2,$1,$3); } + ; gateOrPinList: - gatePinExpr { $$ = $1; } - | gateOrPinList ',' gatePinExpr { $$ = new AstOr($2,$1,$3); } - ; + gatePinExpr { $$ = $1; } + | gateOrPinList ',' gatePinExpr { $$ = new AstOr($2,$1,$3); } + ; gateXorPinList: - gatePinExpr { $$ = $1; } - | gateXorPinList ',' gatePinExpr { $$ = new AstXor($2,$1,$3); } - ; + gatePinExpr { $$ = $1; } + | gateXorPinList ',' gatePinExpr { $$ = new AstXor($2,$1,$3); } + ; gateUnsupPinList: - gatePinExpr { $$ = $1; } - | gateUnsupPinList ',' gatePinExpr { $$ = $1->addNext($3); } - ; + gatePinExpr { $$ = $1; } + | gateUnsupPinList ',' gatePinExpr { $$ = $1->addNext($3); } + ; gatePinExpr: - expr { $$ = GRAMMARP->createGatePin($1); } - ; + expr { $$ = GRAMMARP->createGatePin($1); } + ; // This list is also hardcoded in VParseLex.l -strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE - ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - ; +strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE + ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } + | ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } + | ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } + ; -strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - /* empty */ { } - | strengthSpec { } - ; +strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty + /* empty */ { } + | strengthSpec { } + ; -strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - yP_PAR__STRENGTH strength ')' { } - | yP_PAR__STRENGTH strength ',' strength ')' { } - ; +strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty + yP_PAR__STRENGTH strength ')' { } + | yP_PAR__STRENGTH strength ',' strength ')' { } + ; //************************************************ // Tables -combinational_body: // IEEE: combinational_body + sequential_body - yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable($1,$2); } - ; +combinational_body: // IEEE: combinational_body + sequential_body + yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable($1,$2); } + ; -tableEntryList: // IEEE: { combinational_entry | sequential_entry } - tableEntry { $$ = $1; } - | tableEntryList tableEntry { $$ = $1->addNextNull($2); } - ; +tableEntryList: // IEEE: { combinational_entry | sequential_entry } + tableEntry { $$ = $1; } + | tableEntryList tableEntry { $$ = $1->addNextNull($2); } + ; -tableEntry: // IEEE: combinational_entry + sequential_entry - yaTABLELINE { $$ = new AstUdpTableLine($1,*$1); } - | error { $$ = nullptr; } - ; +tableEntry: // IEEE: combinational_entry + sequential_entry + yaTABLELINE { $$ = new AstUdpTableLine($1,*$1); } + | error { $$ = nullptr; } + ; //************************************************ // Specify -specify_block: // ==IEEE: specify_block - ySPECIFY specifyJunkList yENDSPECIFY { $$ = nullptr; } - | ySPECIFY yENDSPECIFY { $$ = nullptr; } - ; +specify_block: // ==IEEE: specify_block + ySPECIFY specifyJunkList yENDSPECIFY { $$ = nullptr; } + | ySPECIFY yENDSPECIFY { $$ = nullptr; } + ; specifyJunkList: - specifyJunk { } /* ignored */ - | specifyJunkList specifyJunk { } /* ignored */ - ; + specifyJunk { } /* ignored */ + | specifyJunkList specifyJunk { } /* ignored */ + ; specifyJunk: - BISONPRE_NOT(ySPECIFY,yENDSPECIFY) { } - | ySPECIFY specifyJunk yENDSPECIFY { } - | error {} - ; + BISONPRE_NOT(ySPECIFY,yENDSPECIFY) { } + | ySPECIFY specifyJunk yENDSPECIFY { } + | error {} + ; -specparam_declaration: // ==IEEE: specparam_declaration - ySPECPARAM junkToSemiList ';' { $$ = nullptr; } - ; +specparam_declaration: // ==IEEE: specparam_declaration + ySPECPARAM junkToSemiList ';' { $$ = nullptr; } + ; junkToSemiList: - junkToSemi { } /* ignored */ - | junkToSemiList junkToSemi { } /* ignored */ - ; + junkToSemi { } /* ignored */ + | junkToSemiList junkToSemi { } /* ignored */ + ; junkToSemi: - BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { } - | error {} - ; + BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { } + | error {} + ; //************************************************ // IDs id: - yaID__ETC { $$ = $1; $$ = $1; } - | idRandomize { $$ = $1; $$ = $1; } - ; + yaID__ETC { $$ = $1; $$ = $1; } + | idRandomize { $$ = $1; $$ = $1; } + ; -idAny: // Any kind of identifier - yaID__ETC { $$ = $1; $$ = $1; } - | yaID__aTYPE { $$ = $1; $$ = $1; } - | idRandomize { $$ = $1; $$ = $1; } - ; +idAny: // Any kind of identifier + yaID__ETC { $$ = $1; $$ = $1; } + | yaID__aTYPE { $$ = $1; $$ = $1; } + | idRandomize { $$ = $1; $$ = $1; } + ; -idType: // IEEE: class_identifier or other type identifier - // // Used where reference is needed - yaID__aTYPE { $$ = $1; $$ = $1; } - ; +idType: // IEEE: class_identifier or other type identifier + // // Used where reference is needed + yaID__aTYPE { $$ = $1; $$ = $1; } + ; -idCC: // IEEE: class/package then :: - // lexer matches this: yaID_LEX [ '#' '(' ... ')' ] yP_COLONCOLON - yaID__CC { $$ = $1; $$ = $1; } - ; +idCC: // IEEE: class/package then :: + // lexer matches this: yaID_LEX [ '#' '(' ... ')' ] yP_COLONCOLON + yaID__CC { $$ = $1; $$ = $1; } + ; -idRandomize: // Keyword as an identifier - yRANDOMIZE { static string s = "randomize"; $$ = &s; $$ = $1; } - ; +idRandomize: // Keyword as an identifier + yRANDOMIZE { static string s = "randomize"; $$ = &s; $$ = $1; } + ; -idSVKwd: // Warn about non-forward compatible Verilog 2001 code - // // yBIT, yBYTE won't work here as causes conflicts - yDO - { static string s = "do" ; $$ = &s; ERRSVKWD($1,*$$); $$ = $1; } - | yFINAL - { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $$ = $1; } - ; +idSVKwd: // Warn about non-forward compatible Verilog 2001 code + // // yBIT, yBYTE won't work here as causes conflicts + yDO + { static string s = "do" ; $$ = &s; ERRSVKWD($1,*$$); $$ = $1; } + | yFINAL + { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); $$ = $1; } + ; -variable_lvalue: // IEEE: variable_lvalue or net_lvalue - // // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist - idClassSel { $$ = $1; } - | '{' variable_lvalueConcList '}' { $$ = $2; } - // // IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue - // // We allow more assignment_pattern_expression_types then strictly required - //UNSUP data_type yP_TICKBRA variable_lvalueList '}' { UNSUP } - //UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP } - //UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP } - | streaming_concatenation { $$ = $1; } - ; +variable_lvalue: // IEEE: variable_lvalue or net_lvalue + // // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist + idClassSel { $$ = $1; } + | '{' variable_lvalueConcList '}' { $$ = $2; } + // // IEEE: [ assignment_pattern_expression_type ] assignment_pattern_variable_lvalue + // // We allow more assignment_pattern_expression_types then strictly required + //UNSUP data_type yP_TICKBRA variable_lvalueList '}' { UNSUP } + //UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP } + //UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP } + | streaming_concatenation { $$ = $1; } + ; -variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' - variable_lvalue { $$ = $1; } - | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); } - ; +variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}' + variable_lvalue { $$ = $1; } + | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat($2,$1,$3); } + ; //UNSUPvariable_lvalueList: // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue } -//UNSUP variable_lvalue { $$ = $1; } -//UNSUP | variable_lvalueList ',' variable_lvalue { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP variable_lvalue { $$ = $1; } +//UNSUP | variable_lvalueList ',' variable_lvalue { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; // VarRef to dotted, and/or arrayed, and/or bit-ranged variable -idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable - idDotted { $$ = $1; } - // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select - | yTHIS '.' idDotted - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } - | ySUPER '.' idDotted - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } - | yTHIS '.' ySUPER '.' idDotted { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } - // // Expanded: package_scope idDotted - | packageClassScope idDotted { $$ = new AstDot($2, true, $1, $2); } - ; +idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable + idDotted { $$ = $1; } + // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select + | yTHIS '.' idDotted + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } + | ySUPER '.' idDotted + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } + | yTHIS '.' ySUPER '.' idDotted { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + // // Expanded: package_scope idDotted + | packageClassScope idDotted { $$ = new AstDot($2, true, $1, $2); } + ; idClassSelForeach: - idDottedForeach { $$ = $1; } - // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select - | yTHIS '.' idDottedForeach - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } - | ySUPER '.' idDottedForeach - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } - | yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } - // // Expanded: package_scope idForeach - | packageClassScope idDottedForeach { $$ = new AstDot($2, true, $1, $2); } - ; + idDottedForeach { $$ = $1; } + // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select + | yTHIS '.' idDottedForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } + | ySUPER '.' idDottedForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } + | yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + // // Expanded: package_scope idForeach + | packageClassScope idDottedForeach { $$ = new AstDot($2, true, $1, $2); } + ; idDotted: - yD_ROOT '.' idDottedMore - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } - | idDottedMore { $$ = $1; } - ; + yD_ROOT '.' idDottedMore + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } + | idDottedMore { $$ = $1; } + ; idDottedForeach: - yD_ROOT '.' idDottedMoreForeach - { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } - | idDottedMoreForeach { $$ = $1; } - ; + yD_ROOT '.' idDottedMoreForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } + | idDottedMoreForeach { $$ = $1; } + ; idDottedMore: - idArrayed { $$ = $1; } - | idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } - ; + idArrayed { $$ = $1; } + | idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } + ; idDottedMoreForeach: - idArrayedForeach { $$ = $1; } - | idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot($2, false, $1, $3); } - ; + idArrayedForeach { $$ = $1; } + | idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot($2, false, $1, $3); } + ; // Single component of dotted path, maybe [#]. // Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part), // we'll assume so and cleanup later. // id below includes: -// enum_identifier -idArrayed: // IEEE: id + select - id - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } - // // IEEE: id + part_select_range/constant_part_select_range - | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. - | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } - // // IEEE: id + indexed_range/constant_indexed_range - | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } - | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } - ; +// enum_identifier +idArrayed: // IEEE: id + select + id + { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } + // // IEEE: id + part_select_range/constant_part_select_range + | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. + | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } + // // IEEE: id + indexed_range/constant_indexed_range + | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } + | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } + ; -idArrayedForeach: // IEEE: id + select (under foreach expression) - id - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } - // // IEEE: id + part_select_range/constant_part_select_range - | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. - | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } - // // IEEE: id + indexed_range/constant_indexed_range - | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } - | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } - // // IEEE: loop_variables (under foreach expression) - // // To avoid conflicts we allow expr as first element, must post-check - | idArrayed '[' expr ',' loop_variables ']' - { $3 = AstNode::addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } - | idArrayed '[' ',' loop_variables ']' - { $4 = AstNode::addNextNull(new AstEmpty{$3}, $4); $$ = new AstSelLoopVars($2, $1, $4); } - ; +idArrayedForeach: // IEEE: id + select (under foreach expression) + id + { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr); } + // // IEEE: id + part_select_range/constant_part_select_range + | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. + | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } + // // IEEE: id + indexed_range/constant_indexed_range + | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } + | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } + // // IEEE: loop_variables (under foreach expression) + // // To avoid conflicts we allow expr as first element, must post-check + | idArrayed '[' expr ',' loop_variables ']' + { $3 = AstNode::addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } + | idArrayed '[' ',' loop_variables ']' + { $4 = AstNode::addNextNull(new AstEmpty{$3}, $4); $$ = new AstSelLoopVars($2, $1, $4); } + ; // VarRef without any dots or vectorizaion varRefBase: - id { $$ = new AstVarRef($1, *$1, VAccess::READ); } - ; + id { $$ = new AstVarRef($1, *$1, VAccess::READ); } + ; // ParseRef parseRefBase: - id - { $$ = new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr}; } - ; + id + { $$ = new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1, nullptr, nullptr}; } + ; // yaSTRING shouldn't be used directly, instead via an abstraction below -str: // yaSTRING but with \{escapes} need decoded - yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($1,*$1)); } - ; +str: // yaSTRING but with \{escapes} need decoded + yaSTRING { $$ = PARSEP->newString(GRAMMARP->deQuote($1,*$1)); } + ; strAsInt: - yaSTRING - { if ($1->empty()) { - // else "" is not representable as number as is width 0 + yaSTRING + { if ($1->empty()) { + // else "" is not representable as number as is width 0 // TODO all strings should be represented this way - // until V3Width converts as/if needed to a numerical constant - $$ = new AstConst{$1, AstConst::String{}, GRAMMARP->deQuote($1, *$1)}; - } else { - $$ = new AstConst{$1, AstConst::VerilogStringLiteral(), GRAMMARP->deQuote($1, *$1)}; - } - } - ; + // until V3Width converts as/if needed to a numerical constant + $$ = new AstConst{$1, AstConst::String{}, GRAMMARP->deQuote($1, *$1)}; + } else { + $$ = new AstConst{$1, AstConst::VerilogStringLiteral(), GRAMMARP->deQuote($1, *$1)}; + } + } + ; -strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings - yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); } - ; +strAsIntIgnore: // strAsInt, but never matches for when expr shouldn't parse strings + yaSTRING__IGNORE { $$ = nullptr; yyerror("Impossible token"); } + ; strAsText: - yaSTRING { $$ = GRAMMARP->createTextQuoted($1, *$1); } - ; + yaSTRING { $$ = GRAMMARP->createTextQuoted($1, *$1); } + ; endLabelE: - /* empty */ { $$ = nullptr; $$ = nullptr; } - | ':' idAny { $$ = $2; $$ = $2; } - | ':' yNEW__ETC { static string n = "new"; $$ = &n; $$ = $2; } - ; + /* empty */ { $$ = nullptr; $$ = nullptr; } + | ':' idAny { $$ = $2; $$ = $2; } + | ':' yNEW__ETC { static string n = "new"; $$ = &n; $$ = $2; } + ; //************************************************ // Clocking -clocking_declaration: // IEEE: clocking_declaration (INCOMPLETE) - //UNSUP: vvv remove this -- vastly simplified grammar: - yDEFAULT yCLOCKING '@' '(' senitemEdge ')' ';' yENDCLOCKING - { $$ = new AstClocking($2, $5, nullptr); } - //UNSUP: ^^^ remove this -- vastly simplified grammar: - //UNSUP clockingFront clocking_event ';' - //UNSUP clocking_itemListE yENDCLOCKING endLabelE { SYMP->popScope($$); } - ; +clocking_declaration: // IEEE: clocking_declaration (INCOMPLETE) + //UNSUP: vvv remove this -- vastly simplified grammar: + yDEFAULT yCLOCKING '@' '(' senitemEdge ')' ';' yENDCLOCKING + { $$ = new AstClocking($2, $5, nullptr); } + //UNSUP: ^^^ remove this -- vastly simplified grammar: + //UNSUP clockingFront clocking_event ';' + //UNSUP clocking_itemListE yENDCLOCKING endLabelE { SYMP->popScope($$); } + ; //UNSUPclockingFront: // IEEE: part of class_declaration -//UNSUP yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } -//UNSUP | yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } -//UNSUP | yDEFAULT yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } -//UNSUP | yDEFAULT yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } -//UNSUP | yGLOBAL__CLOCKING yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } -//UNSUP | yGLOBAL__CLOCKING yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } -//UNSUP ; +//UNSUP yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } +//UNSUP | yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } +//UNSUP | yDEFAULT yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } +//UNSUP | yDEFAULT yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } +//UNSUP | yGLOBAL__CLOCKING yCLOCKING { PARSEP->symPushNewAnon(VAstType::CLOCKING); } +//UNSUP | yGLOBAL__CLOCKING yCLOCKING idAny/*clocking_identifier*/ { SYMP->pushNew($$); } +//UNSUP ; //UNSUPclocking_event: // ==IEEE: clocking_event -//UNSUP '@' id { } -//UNSUP | '@' '(' event_expression ')' { } -//UNSUP ; +//UNSUP '@' id { } +//UNSUP | '@' '(' event_expression ')' { } +//UNSUP ; //UNSUPclocking_itemListE: -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | clocking_itemList { $$ = $1; } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | clocking_itemList { $$ = $1; } +//UNSUP ; //UNSUPclocking_itemList: // IEEE: [ clocking_item ] -//UNSUP clocking_item { $$ = $1; } -//UNSUP | clocking_itemList clocking_item { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP clocking_item { $$ = $1; } +//UNSUP | clocking_itemList clocking_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPclocking_item: // ==IEEE: clocking_item -//UNSUP yDEFAULT default_skew ';' { } -//UNSUP | clocking_direction list_of_clocking_decl_assign ';' { } -//UNSUP | assertion_item_declaration { } -//UNSUP ; +//UNSUP yDEFAULT default_skew ';' { } +//UNSUP | clocking_direction list_of_clocking_decl_assign ';' { } +//UNSUP | assertion_item_declaration { } +//UNSUP ; //UNSUPdefault_skew: // ==IEEE: default_skew -//UNSUP yINPUT clocking_skew { } -//UNSUP | yOUTPUT clocking_skew { } -//UNSUP | yINPUT clocking_skew yOUTPUT clocking_skew { } -//UNSUP ; +//UNSUP yINPUT clocking_skew { } +//UNSUP | yOUTPUT clocking_skew { } +//UNSUP | yINPUT clocking_skew yOUTPUT clocking_skew { } +//UNSUP ; //UNSUPclocking_direction: // ==IEEE: clocking_direction -//UNSUP yINPUT clocking_skewE { } -//UNSUP | yOUTPUT clocking_skewE { } -//UNSUP | yINPUT clocking_skewE yOUTPUT clocking_skewE { } -//UNSUP | yINOUT { } -//UNSUP ; +//UNSUP yINPUT clocking_skewE { } +//UNSUP | yOUTPUT clocking_skewE { } +//UNSUP | yINPUT clocking_skewE yOUTPUT clocking_skewE { } +//UNSUP | yINOUT { } +//UNSUP ; //UNSUPlist_of_clocking_decl_assign: // ==IEEE: list_of_clocking_decl_assign -//UNSUP clocking_decl_assign { $$ = $1; } -//UNSUP | list_of_clocking_decl_assign ',' clocking_decl_assign { } -//UNSUP ; +//UNSUP clocking_decl_assign { $$ = $1; } +//UNSUP | list_of_clocking_decl_assign ',' clocking_decl_assign { } +//UNSUP ; //UNSUPclocking_decl_assign: // ==IEEE: clocking_decl_assign -//UNSUP idAny/*new-signal_identifier*/ exprEqE { $$ = $1; } -//UNSUP ; +//UNSUP idAny/*new-signal_identifier*/ exprEqE { $$ = $1; } +//UNSUP ; //UNSUPclocking_skewE: // IEEE: [clocking_skew] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | clocking_skew { $$ = $1; } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | clocking_skew { $$ = $1; } +//UNSUP ; //UNSUPclocking_skew: // ==IEEE: clocking_skew -//UNSUP yPOSEDGE { } -//UNSUP | yPOSEDGE delay_control { } -//UNSUP | yNEGEDGE { } -//UNSUP | yNEGEDGE delay_control { } -//UNSUP | yEDGE { NEED_S09($1,"edge"); } -//UNSUP | yEDGE delay_control { NEED_S09($1,"edge"); } -//UNSUP | delay_control { $$ = $1; } -//UNSUP ; +//UNSUP yPOSEDGE { } +//UNSUP | yPOSEDGE delay_control { } +//UNSUP | yNEGEDGE { } +//UNSUP | yNEGEDGE delay_control { } +//UNSUP | yEDGE { NEED_S09($1,"edge"); } +//UNSUP | yEDGE delay_control { NEED_S09($1,"edge"); } +//UNSUP | delay_control { $$ = $1; } +//UNSUP ; //UNSUPcycle_delay: // ==IEEE: cycle_delay -//UNSUP yP_POUNDPOUND yaINTNUM { } -//UNSUP | yP_POUNDPOUND id { } -//UNSUP | yP_POUNDPOUND '(' expr ')' { } -//UNSUP ; +//UNSUP yP_POUNDPOUND yaINTNUM { } +//UNSUP | yP_POUNDPOUND id { } +//UNSUP | yP_POUNDPOUND '(' expr ')' { } +//UNSUP ; //************************************************ // Asserts //UNSUPassertion_item_declaration: // ==IEEE: assertion_item_declaration -//UNSUP property_declaration { $$ = $1; } -//UNSUP | sequence_declaration { $$ = $1; } -//UNSUP | let_declaration { $$ = $1; } -//UNSUP ; +//UNSUP property_declaration { $$ = $1; } +//UNSUP | sequence_declaration { $$ = $1; } +//UNSUP | let_declaration { $$ = $1; } +//UNSUP ; -assertion_item: // ==IEEE: assertion_item - concurrent_assertion_item { $$ = $1; } - | deferred_immediate_assertion_item - { $$ = $1 ? new AstAlways($1->fileline(), VAlwaysKwd::ALWAYS_COMB, nullptr, $1) : nullptr; } - ; +assertion_item: // ==IEEE: assertion_item + concurrent_assertion_item { $$ = $1; } + | deferred_immediate_assertion_item + { $$ = $1 ? new AstAlways($1->fileline(), VAlwaysKwd::ALWAYS_COMB, nullptr, $1) : nullptr; } + ; -deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item - deferred_immediate_assertion_statement { $$ = $1; } - | id/*block_identifier*/ ':' deferred_immediate_assertion_statement - { $$ = new AstBegin($1, *$1, $3, false, true); } - ; +deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item + deferred_immediate_assertion_statement { $$ = $1; } + | id/*block_identifier*/ ':' deferred_immediate_assertion_statement + { $$ = new AstBegin($1, *$1, $3, false, true); } + ; -procedural_assertion_statement: // ==IEEE: procedural_assertion_statement - concurrent_assertion_statement { $$ = $1; } - | immediate_assertion_statement { $$ = $1; } - // // IEEE: checker_instantiation - // // Unlike modules, checkers are the only "id id (...)" form in statements. - //UNSUP checker_instantiation { $$ = $1; } - ; +procedural_assertion_statement: // ==IEEE: procedural_assertion_statement + concurrent_assertion_statement { $$ = $1; } + | immediate_assertion_statement { $$ = $1; } + // // IEEE: checker_instantiation + // // Unlike modules, checkers are the only "id id (...)" form in statements. + //UNSUP checker_instantiation { $$ = $1; } + ; -immediate_assertion_statement: // ==IEEE: immediate_assertion_statement - simple_immediate_assertion_statement { $$ = $1; } - | deferred_immediate_assertion_statement { $$ = $1; } - ; +immediate_assertion_statement: // ==IEEE: immediate_assertion_statement + simple_immediate_assertion_statement { $$ = $1; } + | deferred_immediate_assertion_statement { $$ = $1; } + ; -simple_immediate_assertion_statement: // ==IEEE: simple_immediate_assertion_statement - // // action_block expanded here, for compatibility with AstAssert - yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $3, $5, nullptr, true); } - | yASSERT '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $3, nullptr, $6, true); } - | yASSERT '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $3, $5, $7, true); } - // // action_block expanded here, for compatibility with AstAssert - | yASSUME '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $3, $5, nullptr, true); } - | yASSUME '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $3, nullptr, $6, true); } - | yASSUME '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $3, $5, $7, true); } - // // IEEE: simple_immediate_cover_statement - | yCOVER '(' expr ')' stmt { $$ = new AstCover($1, $3, $5, true); } - ; +simple_immediate_assertion_statement: // ==IEEE: simple_immediate_assertion_statement + // // action_block expanded here, for compatibility with AstAssert + yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $3, $5, nullptr, true); } + | yASSERT '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $3, nullptr, $6, true); } + | yASSERT '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $3, $5, $7, true); } + // // action_block expanded here, for compatibility with AstAssert + | yASSUME '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $3, $5, nullptr, true); } + | yASSUME '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $3, nullptr, $6, true); } + | yASSUME '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $3, $5, $7, true); } + // // IEEE: simple_immediate_cover_statement + | yCOVER '(' expr ')' stmt { $$ = new AstCover($1, $3, $5, true); } + ; -final_zero: // IEEE: part of deferred_immediate_assertion_statement - '#' yaINTNUM - { if ($2->isNeqZero()) { $2->v3error("Deferred assertions must use '#0' (IEEE 1800-2017 16.4)"); } } - // // 1800-2012: - | yFINAL { } - ; +final_zero: // IEEE: part of deferred_immediate_assertion_statement + '#' yaINTNUM + { if ($2->isNeqZero()) { $2->v3error("Deferred assertions must use '#0' (IEEE 1800-2017 16.4)"); } } + // // 1800-2012: + | yFINAL { } + ; -deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_assertion_statement - // // IEEE: deferred_immediate_assert_statement - yASSERT final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $4, $6, nullptr, true); } - | yASSERT final_zero '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $4, nullptr, $7, true); } - | yASSERT final_zero '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $4, $6, $8, true); } - // // IEEE: deferred_immediate_assume_statement - | yASSUME final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $4, $6, nullptr, true); } - | yASSUME final_zero '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $4, nullptr, $7, true); } - | yASSUME final_zero '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $4, $6, $8, true); } - // // IEEE: deferred_immediate_cover_statement - | yCOVER final_zero '(' expr ')' stmt { $$ = new AstCover($1, $4, $6, true); } - ; +deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_assertion_statement + // // IEEE: deferred_immediate_assert_statement + yASSERT final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $4, $6, nullptr, true); } + | yASSERT final_zero '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $4, nullptr, $7, true); } + | yASSERT final_zero '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $4, $6, $8, true); } + // // IEEE: deferred_immediate_assume_statement + | yASSUME final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert($1, $4, $6, nullptr, true); } + | yASSUME final_zero '(' expr ')' yELSE stmtBlock { $$ = new AstAssert($1, $4, nullptr, $7, true); } + | yASSUME final_zero '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert($1, $4, $6, $8, true); } + // // IEEE: deferred_immediate_cover_statement + | yCOVER final_zero '(' expr ')' stmt { $$ = new AstCover($1, $4, $6, true); } + ; //UNSUPexpect_property_statement: // ==IEEE: expect_property_statement -//UNSUP yEXPECT '(' property_spec ')' action_block { } -//UNSUP ; +//UNSUP yEXPECT '(' property_spec ')' action_block { } +//UNSUP ; -concurrent_assertion_item: // IEEE: concurrent_assertion_item - concurrent_assertion_statement { $$ = $1; } - | id/*block_identifier*/ ':' concurrent_assertion_statement - { $$ = new AstBegin($1, *$1, $3, false, true); } - // // IEEE: checker_instantiation - // // identical to module_instantiation; see etcInst - ; +concurrent_assertion_item: // IEEE: concurrent_assertion_item + concurrent_assertion_statement { $$ = $1; } + | id/*block_identifier*/ ':' concurrent_assertion_statement + { $$ = new AstBegin($1, *$1, $3, false, true); } + // // IEEE: checker_instantiation + // // identical to module_instantiation; see etcInst + ; -concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement - // // IEEE: assert_property_statement - //UNSUP remove below: - yASSERT yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert($1, $4, nullptr, $6, false); } - //UNSUP yASSERT yPROPERTY '(' property_spec ')' action_block { } - // // IEEE: assume_property_statement - | yASSUME yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert($1, $4, nullptr, $6, false); } - //UNSUP yASSUME yPROPERTY '(' property_spec ')' action_block { } - // // IEEE: cover_property_statement - | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover($1, $4, $6, false); } - // // IEEE: cover_sequence_statement - //UNSUP yCOVER ySEQUENCE '(' sexpr ')' stmt { } - // // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt - // // sexpr already includes "clocking_event sexpr" - //UNSUP yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } - //UNSUP yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } - // // IEEE: restrict_property_statement - | yRESTRICT yPROPERTY '(' property_spec ')' ';' { $$ = new AstRestrict($1, $4); } - ; +concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement + // // IEEE: assert_property_statement + //UNSUP remove below: + yASSERT yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert($1, $4, nullptr, $6, false); } + //UNSUP yASSERT yPROPERTY '(' property_spec ')' action_block { } + // // IEEE: assume_property_statement + | yASSUME yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert($1, $4, nullptr, $6, false); } + //UNSUP yASSUME yPROPERTY '(' property_spec ')' action_block { } + // // IEEE: cover_property_statement + | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover($1, $4, $6, false); } + // // IEEE: cover_sequence_statement + //UNSUP yCOVER ySEQUENCE '(' sexpr ')' stmt { } + // // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt + // // sexpr already includes "clocking_event sexpr" + //UNSUP yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } + //UNSUP yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } + // // IEEE: restrict_property_statement + | yRESTRICT yPROPERTY '(' property_spec ')' ';' { $$ = new AstRestrict($1, $4); } + ; -elseStmtBlock: // Part of concurrent_assertion_statement - ';' { $$ = nullptr; } - | yELSE stmtBlock { $$ = $2; } - ; +elseStmtBlock: // Part of concurrent_assertion_statement + ';' { $$ = nullptr; } + | yELSE stmtBlock { $$ = $2; } + ; //UNSUPproperty_declaration: // ==IEEE: property_declaration -//UNSUP property_declarationFront property_port_listE ';' property_declarationBody -//UNSUP yENDPROPERTY endLabelE -//UNSUP { SYMP->popScope($$); } -//UNSUP ; +//UNSUP property_declarationFront property_port_listE ';' property_declarationBody +//UNSUP yENDPROPERTY endLabelE +//UNSUP { SYMP->popScope($$); } +//UNSUP ; //UNSUPproperty_declarationFront: // IEEE: part of property_declaration -//UNSUP yPROPERTY idAny/*property_identifier*/ -//UNSUP { SYMP->pushNew($$); } -//UNSUP ; +//UNSUP yPROPERTY idAny/*property_identifier*/ +//UNSUP { SYMP->pushNew($$); } +//UNSUP ; //UNSUPproperty_port_listE: // IEEE: [ ( [ property_port_list ] ) ] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | '(' {VARRESET_LIST(""); VARIO("input"); } property_port_list ')' -//UNSUP { VARRESET_NONLIST(""); } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | '(' {VARRESET_LIST(""); VARIO("input"); } property_port_list ')' +//UNSUP { VARRESET_NONLIST(""); } +//UNSUP ; //UNSUPproperty_port_list: // ==IEEE: property_port_list -//UNSUP property_port_item { $$ = $1; } -//UNSUP | property_port_list ',' property_port_item { } -//UNSUP ; +//UNSUP property_port_item { $$ = $1; } +//UNSUP | property_port_list ',' property_port_item { } +//UNSUP ; //UNSUPproperty_port_item: // IEEE: property_port_item/sequence_port_item -//UNSUP // // Merged in sequence_port_item -//UNSUP // // IEEE: property_lvar_port_direction ::= yINPUT -//UNSUP // // prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type -//UNSUP // // id {variable_dimension} [ '=' property_actual_arg ] -//UNSUP // // seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type -//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] -//UNSUP property_port_itemFront property_port_itemAssignment { } -//UNSUP ; +//UNSUP // // Merged in sequence_port_item +//UNSUP // // IEEE: property_lvar_port_direction ::= yINPUT +//UNSUP // // prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type +//UNSUP // // id {variable_dimension} [ '=' property_actual_arg ] +//UNSUP // // seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type +//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] +//UNSUP property_port_itemFront property_port_itemAssignment { } +//UNSUP ; -//UNSUPproperty_port_itemFront: // IEEE: part of property_port_item/sequence_port_item -//UNSUP property_port_itemDirE property_formal_typeNoDt { VARDTYPE($2); } -//UNSUP // // data_type_or_implicit -//UNSUP | property_port_itemDirE data_type { VARDTYPE($2); } -//UNSUP | property_port_itemDirE yVAR data_type { VARDTYPE($3); } -//UNSUP | property_port_itemDirE yVAR implicit_typeE { VARDTYPE($3); } -//UNSUP | property_port_itemDirE signingE rangeList { VARDTYPE(SPACED($2,$3)); } -//UNSUP | property_port_itemDirE /*implicit*/ { /*VARDTYPE-same*/ } -//UNSUP ; +//UNSUPproperty_port_itemFront: // IEEE: part of property_port_item/sequence_port_item +//UNSUP property_port_itemDirE property_formal_typeNoDt { VARDTYPE($2); } +//UNSUP // // data_type_or_implicit +//UNSUP | property_port_itemDirE data_type { VARDTYPE($2); } +//UNSUP | property_port_itemDirE yVAR data_type { VARDTYPE($3); } +//UNSUP | property_port_itemDirE yVAR implicit_typeE { VARDTYPE($3); } +//UNSUP | property_port_itemDirE signingE rangeList { VARDTYPE(SPACED($2,$3)); } +//UNSUP | property_port_itemDirE /*implicit*/ { /*VARDTYPE-same*/ } +//UNSUP ; //UNSUPproperty_port_itemAssignment: // IEEE: part of property_port_item/sequence_port_item/checker_port_direction -//UNSUP portSig variable_dimensionListE { VARDONE($1, $1, $2, ""); PINNUMINC(); } -//UNSUP | portSig variable_dimensionListE '=' property_actual_arg -//UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } -//UNSUP ; +//UNSUP portSig variable_dimensionListE { VARDONE($1, $1, $2, ""); PINNUMINC(); } +//UNSUP | portSig variable_dimensionListE '=' property_actual_arg +//UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } +//UNSUP ; //UNSUPproperty_port_itemDirE: -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | yLOCAL__ETC { } -//UNSUP | yLOCAL__ETC port_direction { } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | yLOCAL__ETC { } +//UNSUP | yLOCAL__ETC port_direction { } +//UNSUP ; //UNSUPproperty_declarationBody: // IEEE: part of property_declaration -//UNSUP assertion_variable_declarationList property_statement_spec { } -//UNSUP // // IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here. -//UNSUP // // Fixed in IEEE 1800-2017 -//UNSUP | property_statement_spec { $$ = $1; } -//UNSUP ; +//UNSUP assertion_variable_declarationList property_statement_spec { } +//UNSUP // // IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here. +//UNSUP // // Fixed in IEEE 1800-2017 +//UNSUP | property_statement_spec { $$ = $1; } +//UNSUP ; //UNSUPassertion_variable_declarationList: // IEEE: part of assertion_variable_declaration -//UNSUP assertion_variable_declaration { $$ = $1; } -//UNSUP | assertion_variable_declarationList assertion_variable_declaration { } -//UNSUP ; +//UNSUP assertion_variable_declaration { $$ = $1; } +//UNSUP | assertion_variable_declarationList assertion_variable_declaration { } +//UNSUP ; //UNSUPsequence_declaration: // ==IEEE: sequence_declaration -//UNSUP sequence_declarationFront sequence_port_listE ';' sequence_declarationBody -//UNSUP yENDSEQUENCE endLabelE -//UNSUP { SYMP->popScope($$); } -//UNSUP ; +//UNSUP sequence_declarationFront sequence_port_listE ';' sequence_declarationBody +//UNSUP yENDSEQUENCE endLabelE +//UNSUP { SYMP->popScope($$); } +//UNSUP ; //UNSUPsequence_declarationFront: // IEEE: part of sequence_declaration -//UNSUP ySEQUENCE idAny/*new_sequence*/ -//UNSUP { SYMP->pushNew($$); } -//UNSUP ; +//UNSUP ySEQUENCE idAny/*new_sequence*/ +//UNSUP { SYMP->pushNew($$); } +//UNSUP ; //UNSUPsequence_port_listE: // IEEE: [ ( [ sequence_port_list ] ) ] -//UNSUP // // IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT -//UNSUP // // IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type -//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] -//UNSUP // // All this is almost identically the same as a property. -//UNSUP // // Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012) -//UNSUP // // and yPROPERTY. So save some work. -//UNSUP property_port_listE { $$ = $1; } -//UNSUP ; +//UNSUP // // IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT +//UNSUP // // IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type +//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] +//UNSUP // // All this is almost identically the same as a property. +//UNSUP // // Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012) +//UNSUP // // and yPROPERTY. So save some work. +//UNSUP property_port_listE { $$ = $1; } +//UNSUP ; //UNSUPproperty_formal_typeNoDt: // IEEE: property_formal_type (w/o implicit) -//UNSUP sequence_formal_typeNoDt { $$ = $1; } -//UNSUP | yPROPERTY { } -//UNSUP ; +//UNSUP sequence_formal_typeNoDt { $$ = $1; } +//UNSUP | yPROPERTY { } +//UNSUP ; //UNSUPsequence_formal_typeNoDt: // ==IEEE: sequence_formal_type (w/o data_type_or_implicit) -//UNSUP // // IEEE: data_type_or_implicit -//UNSUP // // implicit expanded where used -//UNSUP ySEQUENCE { } -//UNSUP // // IEEE-2009: yEVENT -//UNSUP // // already part of data_type. Removed in 1800-2012. -//UNSUP | yUNTYPED { } -//UNSUP ; +//UNSUP // // IEEE: data_type_or_implicit +//UNSUP // // implicit expanded where used +//UNSUP ySEQUENCE { } +//UNSUP // // IEEE-2009: yEVENT +//UNSUP // // already part of data_type. Removed in 1800-2012. +//UNSUP | yUNTYPED { } +//UNSUP ; //UNSUPsequence_declarationBody: // IEEE: part of sequence_declaration -//UNSUP // // 1800-2012 makes ';' optional -//UNSUP assertion_variable_declarationList sexpr { } -//UNSUP | assertion_variable_declarationList sexpr ';' { } -//UNSUP | sexpr { $$ = $1; } -//UNSUP | sexpr ';' { $$ = $1; } -//UNSUP ; +//UNSUP // // 1800-2012 makes ';' optional +//UNSUP assertion_variable_declarationList sexpr { } +//UNSUP | assertion_variable_declarationList sexpr ';' { } +//UNSUP | sexpr { $$ = $1; } +//UNSUP | sexpr ';' { $$ = $1; } +//UNSUP ; -property_spec: // IEEE: property_spec - //UNSUP: This rule has been super-specialized to what is supported now - //UNSUP remove below - '@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' pexpr - { $$ = new AstPropClocked($1, $3, $8, $10); } - | '@' '(' senitemEdge ')' pexpr { $$ = new AstPropClocked($1, $3, nullptr, $5); } - //UNSUP remove above - | yDISABLE yIFF '(' expr ')' pexpr { $$ = new AstPropClocked($4->fileline(), nullptr, $4, $6); } - | pexpr { $$ = new AstPropClocked($1->fileline(), nullptr, nullptr, $1); } - ; +property_spec: // IEEE: property_spec + //UNSUP: This rule has been super-specialized to what is supported now + //UNSUP remove below + '@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' pexpr + { $$ = new AstPropClocked($1, $3, $8, $10); } + | '@' '(' senitemEdge ')' pexpr { $$ = new AstPropClocked($1, $3, nullptr, $5); } + //UNSUP remove above + | yDISABLE yIFF '(' expr ')' pexpr { $$ = new AstPropClocked($4->fileline(), nullptr, $4, $6); } + | pexpr { $$ = new AstPropClocked($1->fileline(), nullptr, nullptr, $1); } + ; //UNSUPproperty_statement_spec: // ==IEEE: property_statement_spec -//UNSUP // // IEEE: [ clocking_event ] [ yDISABLE yIFF '(' expression_or_dist ')' ] property_statement -//UNSUP property_statement { $$ = $1; } -//UNSUP | yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement { } -//UNSUP // // IEEE: clocking_event property_statement -//UNSUP // // IEEE: clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement -//UNSUP // // Both overlap pexpr:"clocking_event pexpr" the difference is -//UNSUP // // property_statement:property_statementCaseIf so replicate it -//UNSUP | clocking_event property_statementCaseIf { } -//UNSUP | clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statementCaseIf { } -//UNSUP ; +//UNSUP // // IEEE: [ clocking_event ] [ yDISABLE yIFF '(' expression_or_dist ')' ] property_statement +//UNSUP property_statement { $$ = $1; } +//UNSUP | yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement { } +//UNSUP // // IEEE: clocking_event property_statement +//UNSUP // // IEEE: clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statement +//UNSUP // // Both overlap pexpr:"clocking_event pexpr" the difference is +//UNSUP // // property_statement:property_statementCaseIf so replicate it +//UNSUP | clocking_event property_statementCaseIf { } +//UNSUP | clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' property_statementCaseIf { } +//UNSUP ; //UNSUPproperty_statement: // ==IEEE: property_statement -//UNSUP // // Doesn't make sense to have "pexpr ;" in pexpr rule itself, so we split out case/if -//UNSUP pexpr ';' { $$ = $1; } -//UNSUP // // Note this term replicated in property_statement_spec -//UNSUP // // If committee adds terms, they may need to be there too. -//UNSUP | property_statementCaseIf { $$ = $1; } -//UNSUP ; +//UNSUP // // Doesn't make sense to have "pexpr ;" in pexpr rule itself, so we split out case/if +//UNSUP pexpr ';' { $$ = $1; } +//UNSUP // // Note this term replicated in property_statement_spec +//UNSUP // // If committee adds terms, they may need to be there too. +//UNSUP | property_statementCaseIf { $$ = $1; } +//UNSUP ; //UNSUPproperty_statementCaseIf: // IEEE: property_statement - minus pexpr -//UNSUP yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE { } -//UNSUP | yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE { } -//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE { } -//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr { } -//UNSUP ; +//UNSUP yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE { } +//UNSUP | yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE { } +//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE { } +//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr { } +//UNSUP ; //UNSUPproperty_case_itemList: // IEEE: {property_case_item} -//UNSUP property_case_item { $$ = $1; } -//UNSUP | property_case_itemList ',' property_case_item { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP property_case_item { $$ = $1; } +//UNSUP | property_case_itemList ',' property_case_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; //UNSUPproperty_case_item: // ==IEEE: property_case_item -//UNSUP // // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement -//UNSUP // // IEEE 1800-2012 changed from property_statement to property_expr -//UNSUP // // IEEE 1800-2017 changed to require the semicolon -//UNSUP caseCondList ':' pexpr { } -//UNSUP | caseCondList ':' pexpr ';' { } -//UNSUP | yDEFAULT pexpr { } -//UNSUP | yDEFAULT ':' pexpr ';' { } -//UNSUP ; +//UNSUP // // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement +//UNSUP // // IEEE 1800-2012 changed from property_statement to property_expr +//UNSUP // // IEEE 1800-2017 changed to require the semicolon +//UNSUP caseCondList ':' pexpr { } +//UNSUP | caseCondList ':' pexpr ';' { } +//UNSUP | yDEFAULT pexpr { } +//UNSUP | yDEFAULT ':' pexpr ';' { } +//UNSUP ; //UNSUPpev_expr: // IEEE: property_actual_arg | expr -//UNSUP // // which expands to pexpr | event_expression -//UNSUP // // Used in port and function calls, when we can't know yet if something -//UNSUP // // is a function/sequence/property or instance/checker pin. -//UNSUP // -//UNSUP // // '(' pev_expr ')' -//UNSUP // // Already in pexpr -//UNSUP // // IEEE: event_expression ',' event_expression -//UNSUP // // ','s are legal in event_expressions, but parens required to avoid conflict with port-sep-, -//UNSUP // // IEEE: event_expression yOR event_expression -//UNSUP // // Already in pexpr - needs removal there -//UNSUP // // IEEE: event_expression yIFF expr -//UNSUP // // Already in pexpr - needs removal there -//UNSUP // -//UNSUP senitemEdge { $$ = $1; } -//UNSUP // -//UNSUP //============= pexpr rules copied for pev_expr -//UNSUP | BISONPRE_COPY_ONCE(pexpr,{s/~o~p/pev_/g; }) // {copied} -//UNSUP // -//UNSUP //============= sexpr rules copied for pev_expr -//UNSUP | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/pev_/g; }) // {copied} -//UNSUP // -//UNSUP //============= expr rules copied for pev_expr -//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} -//UNSUP ; +//UNSUP // // which expands to pexpr | event_expression +//UNSUP // // Used in port and function calls, when we can't know yet if something +//UNSUP // // is a function/sequence/property or instance/checker pin. +//UNSUP // +//UNSUP // // '(' pev_expr ')' +//UNSUP // // Already in pexpr +//UNSUP // // IEEE: event_expression ',' event_expression +//UNSUP // // ','s are legal in event_expressions, but parens required to avoid conflict with port-sep-, +//UNSUP // // IEEE: event_expression yOR event_expression +//UNSUP // // Already in pexpr - needs removal there +//UNSUP // // IEEE: event_expression yIFF expr +//UNSUP // // Already in pexpr - needs removal there +//UNSUP // +//UNSUP senitemEdge { $$ = $1; } +//UNSUP // +//UNSUP //============= pexpr rules copied for pev_expr +//UNSUP | BISONPRE_COPY_ONCE(pexpr,{s/~o~p/pev_/g; }) // {copied} +//UNSUP // +//UNSUP //============= sexpr rules copied for pev_expr +//UNSUP | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/pev_/g; }) // {copied} +//UNSUP // +//UNSUP //============= expr rules copied for pev_expr +//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} +//UNSUP ; pexpr: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.) - //UNSUP: This rule has been super-specialized to what is supported now - //UNSUP remove below - expr yP_ORMINUSGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); } - | expr yP_OREQGT pexpr { $$ = new AstImplication($2, $1, $3); } - | expr { $$ = $1; } - //UNSUP remove above, use below: - // - // // IEEE: sequence_expr - // // Expanded below - // - // // IEEE: '(' pexpr ')' - // // Expanded below - // - //UNSUP yNOT pexpr %prec prNEGATION { } - //UNSUP ySTRONG '(' sexpr ')' { } - //UNSUP yWEAK '(' sexpr ')' { } - // // IEEE: pexpr yOR pexpr - // // IEEE: pexpr yAND pexpr - // // Under ~p~sexpr and/or ~p~sexpr - // - // // IEEE: "sequence_expr yP_ORMINUSGT pexpr" - // // Instead we use pexpr to prevent conflicts - //UNSUP ~o~pexpr yP_ORMINUSGT pexpr { } - //UNSUP ~o~pexpr yP_OREQGT pexpr { } - // - // // IEEE-2009: property_statement - // // IEEE-2012: yIF and yCASE - //UNSUP property_statementCaseIf { } - // - //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr { } - //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr { } - //UNSUP yNEXTTIME pexpr { } - //UNSUP yS_NEXTTIME pexpr { } - //UNSUP yNEXTTIME '[' expr/*const*/ ']' pexpr %prec yNEXTTIME { } - //UNSUP yS_NEXTTIME '[' expr/*const*/ ']' pexpr %prec yS_NEXTTIME { } - //UNSUP yALWAYS pexpr { } - //UNSUP yALWAYS '[' cycle_delay_const_range_expression ']' pexpr %prec yALWAYS { } - //UNSUP yS_ALWAYS '[' constant_range ']' pexpr %prec yS_ALWAYS { } - //UNSUP yS_EVENTUALLY pexpr { } - //UNSUP yEVENTUALLY '[' constant_range ']' pexpr %prec yEVENTUALLY { } - //UNSUP yS_EVENTUALLY '[' cycle_delay_const_range_expression ']' pexpr %prec yS_EVENTUALLY { } - //UNSUP ~o~pexpr yUNTIL pexpr { } - //UNSUP ~o~pexpr yS_UNTIL pexpr { } - //UNSUP ~o~pexpr yUNTIL_WITH pexpr { } - //UNSUP ~o~pexpr yS_UNTIL_WITH pexpr { } - //UNSUP ~o~pexpr yIMPLIES pexpr { } - // // yIFF also used by event_expression - //UNSUP ~o~pexpr yIFF ~o~pexpr { } - //UNSUP yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON { } - //UNSUP yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON { } - //UNSUP ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON { } - //UNSUP ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON { } - // - // // IEEE: "property_instance" - // // Looks just like a function/method call - // - // // Note "clocking_event pexpr" overlaps property_statement_spec: clocking_event property_statement - // - // // Include property_specDisable to match property_spec rule - //UNSUP clocking_event yDISABLE yIFF '(' expr ')' pexpr %prec prSEQ_CLOCKING { } - // - //============= sexpr rules copied for property_expr - //UNSUP BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} - // - //============= expr rules copied for property_expr - //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} - ; + //UNSUP: This rule has been super-specialized to what is supported now + //UNSUP remove below + expr yP_ORMINUSGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); } + | expr yP_OREQGT pexpr { $$ = new AstImplication($2, $1, $3); } + | expr { $$ = $1; } + //UNSUP remove above, use below: + // + // // IEEE: sequence_expr + // // Expanded below + // + // // IEEE: '(' pexpr ')' + // // Expanded below + // + //UNSUP yNOT pexpr %prec prNEGATION { } + //UNSUP ySTRONG '(' sexpr ')' { } + //UNSUP yWEAK '(' sexpr ')' { } + // // IEEE: pexpr yOR pexpr + // // IEEE: pexpr yAND pexpr + // // Under ~p~sexpr and/or ~p~sexpr + // + // // IEEE: "sequence_expr yP_ORMINUSGT pexpr" + // // Instead we use pexpr to prevent conflicts + //UNSUP ~o~pexpr yP_ORMINUSGT pexpr { } + //UNSUP ~o~pexpr yP_OREQGT pexpr { } + // + // // IEEE-2009: property_statement + // // IEEE-2012: yIF and yCASE + //UNSUP property_statementCaseIf { } + // + //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr { } + //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr { } + //UNSUP yNEXTTIME pexpr { } + //UNSUP yS_NEXTTIME pexpr { } + //UNSUP yNEXTTIME '[' expr/*const*/ ']' pexpr %prec yNEXTTIME { } + //UNSUP yS_NEXTTIME '[' expr/*const*/ ']' pexpr %prec yS_NEXTTIME { } + //UNSUP yALWAYS pexpr { } + //UNSUP yALWAYS '[' cycle_delay_const_range_expression ']' pexpr %prec yALWAYS { } + //UNSUP yS_ALWAYS '[' constant_range ']' pexpr %prec yS_ALWAYS { } + //UNSUP yS_EVENTUALLY pexpr { } + //UNSUP yEVENTUALLY '[' constant_range ']' pexpr %prec yEVENTUALLY { } + //UNSUP yS_EVENTUALLY '[' cycle_delay_const_range_expression ']' pexpr %prec yS_EVENTUALLY { } + //UNSUP ~o~pexpr yUNTIL pexpr { } + //UNSUP ~o~pexpr yS_UNTIL pexpr { } + //UNSUP ~o~pexpr yUNTIL_WITH pexpr { } + //UNSUP ~o~pexpr yS_UNTIL_WITH pexpr { } + //UNSUP ~o~pexpr yIMPLIES pexpr { } + // // yIFF also used by event_expression + //UNSUP ~o~pexpr yIFF ~o~pexpr { } + //UNSUP yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON { } + //UNSUP yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON { } + //UNSUP ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON { } + //UNSUP ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON { } + // + // // IEEE: "property_instance" + // // Looks just like a function/method call + // + // // Note "clocking_event pexpr" overlaps property_statement_spec: clocking_event property_statement + // + // // Include property_specDisable to match property_spec rule + //UNSUP clocking_event yDISABLE yIFF '(' expr ')' pexpr %prec prSEQ_CLOCKING { } + // + //============= sexpr rules copied for property_expr + //UNSUP BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} + // + //============= expr rules copied for property_expr + //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} + ; //UNSUPsexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) -//UNSUP // // ********* RULES COPIED IN sequence_exprProp -//UNSUP // // For precedence, see IEEE 17.7.1 -//UNSUP // -//UNSUP // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" -//UNSUP // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" -//UNSUP // // Both rules basically mean we can repeat sequences, so make it simpler: -//UNSUP cycle_delay_range sexpr %prec yP_POUNDPOUND { } -//UNSUP | ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } -//UNSUP // -//UNSUP // // IEEE: expression_or_dist [ boolean_abbrev ] -//UNSUP // // Note expression_or_dist includes "expr"! -//UNSUP // // sexpr/*sexpression_or_dist*/ --- Hardcoded below -//UNSUP | ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } -//UNSUP // -//UNSUP // // IEEE: "sequence_instance [ sequence_abbrev ]" -//UNSUP // // version without sequence_abbrev looks just like normal function call -//UNSUP // // version w/sequence_abbrev matches above; expression_or_dist:expr:func boolean_abbrev:sequence_abbrev -//UNSUP // -//UNSUP // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] -//UNSUP // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] -//UNSUP // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: -//UNSUP // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] -//UNSUP // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it -//UNSUP | '(' ~p~sexpr ')' { $$ = $1; $$ = ...; } -//UNSUP | '(' ~p~sexpr ',' sequence_match_itemList ')' { } -//UNSUP // -//UNSUP // // AND/OR are between pexprs OR sexprs -//UNSUP | ~p~sexpr yAND ~p~sexpr { $$ = $1; $$ = ...; } -//UNSUP | ~p~sexpr yOR ~p~sexpr { $$ = $1; $$ = ...; } -//UNSUP // // Intersect always has an sexpr rhs -//UNSUP | ~p~sexpr yINTERSECT sexpr { $$ = $1; $$ = ...; } -//UNSUP // -//UNSUP | yFIRST_MATCH '(' sexpr ')' { } -//UNSUP | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } -//UNSUP | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } -//UNSUP // // Below pexpr's are really sequence_expr, but avoid conflict -//UNSUP // // IEEE: sexpr yWITHIN sexpr -//UNSUP | ~p~sexpr yWITHIN sexpr { $$ = $1; $$ = ...; } -//UNSUP // // Note concurrent_assertion had duplicate rule for below -//UNSUP | clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } -//UNSUP // -//UNSUP //============= expr rules copied for sequence_expr -//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} -//UNSUP ; +//UNSUP // // ********* RULES COPIED IN sequence_exprProp +//UNSUP // // For precedence, see IEEE 17.7.1 +//UNSUP // +//UNSUP // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" +//UNSUP // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" +//UNSUP // // Both rules basically mean we can repeat sequences, so make it simpler: +//UNSUP cycle_delay_range sexpr %prec yP_POUNDPOUND { } +//UNSUP | ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } +//UNSUP // +//UNSUP // // IEEE: expression_or_dist [ boolean_abbrev ] +//UNSUP // // Note expression_or_dist includes "expr"! +//UNSUP // // sexpr/*sexpression_or_dist*/ --- Hardcoded below +//UNSUP | ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } +//UNSUP // +//UNSUP // // IEEE: "sequence_instance [ sequence_abbrev ]" +//UNSUP // // version without sequence_abbrev looks just like normal function call +//UNSUP // // version w/sequence_abbrev matches above; expression_or_dist:expr:func boolean_abbrev:sequence_abbrev +//UNSUP // +//UNSUP // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] +//UNSUP // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] +//UNSUP // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: +//UNSUP // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] +//UNSUP // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it +//UNSUP | '(' ~p~sexpr ')' { $$ = $1; $$ = ...; } +//UNSUP | '(' ~p~sexpr ',' sequence_match_itemList ')' { } +//UNSUP // +//UNSUP // // AND/OR are between pexprs OR sexprs +//UNSUP | ~p~sexpr yAND ~p~sexpr { $$ = $1; $$ = ...; } +//UNSUP | ~p~sexpr yOR ~p~sexpr { $$ = $1; $$ = ...; } +//UNSUP // // Intersect always has an sexpr rhs +//UNSUP | ~p~sexpr yINTERSECT sexpr { $$ = $1; $$ = ...; } +//UNSUP // +//UNSUP | yFIRST_MATCH '(' sexpr ')' { } +//UNSUP | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } +//UNSUP | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } +//UNSUP // // Below pexpr's are really sequence_expr, but avoid conflict +//UNSUP // // IEEE: sexpr yWITHIN sexpr +//UNSUP | ~p~sexpr yWITHIN sexpr { $$ = $1; $$ = ...; } +//UNSUP // // Note concurrent_assertion had duplicate rule for below +//UNSUP | clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } +//UNSUP // +//UNSUP //============= expr rules copied for sequence_expr +//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} +//UNSUP ; //UNSUPcycle_delay_range: // IEEE: ==cycle_delay_range -//UNSUP // // These three terms in 1800-2005 ONLY -//UNSUP yP_POUNDPOUND yaINTNUM { } -//UNSUP | yP_POUNDPOUND id { } -//UNSUP | yP_POUNDPOUND '(' constExpr ')' { } -//UNSUP // // In 1800-2009 ONLY: -//UNSUP // // IEEE: yP_POUNDPOUND constant_primary -//UNSUP // // UNSUP: This causes a big grammer ambiguity -//UNSUP // // as ()'s mismatch between primary and the following statement -//UNSUP // // the sv-ac committee has been asked to clarify (Mantis 1901) -//UNSUP | yP_POUNDPOUND '[' cycle_delay_const_range_expression ']' { } -//UNSUP | yP_POUNDPOUND yP_BRASTAR ']' { } -//UNSUP | yP_POUNDPOUND yP_BRAPLUSKET { } -//UNSUP ; +//UNSUP // // These three terms in 1800-2005 ONLY +//UNSUP yP_POUNDPOUND yaINTNUM { } +//UNSUP | yP_POUNDPOUND id { } +//UNSUP | yP_POUNDPOUND '(' constExpr ')' { } +//UNSUP // // In 1800-2009 ONLY: +//UNSUP // // IEEE: yP_POUNDPOUND constant_primary +//UNSUP // // UNSUP: This causes a big grammer ambiguity +//UNSUP // // as ()'s mismatch between primary and the following statement +//UNSUP // // the sv-ac committee has been asked to clarify (Mantis 1901) +//UNSUP | yP_POUNDPOUND '[' cycle_delay_const_range_expression ']' { } +//UNSUP | yP_POUNDPOUND yP_BRASTAR ']' { } +//UNSUP | yP_POUNDPOUND yP_BRAPLUSKET { } +//UNSUP ; //UNSUPsequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr -//UNSUP sequence_match_item { $$ = $1; } -//UNSUP | sequence_match_itemList ',' sequence_match_item { } -//UNSUP ; +//UNSUP sequence_match_item { $$ = $1; } +//UNSUP | sequence_match_itemList ',' sequence_match_item { } +//UNSUP ; //UNSUPsequence_match_item: // ==IEEE: sequence_match_item -//UNSUP // // IEEE says: operator_assignment -//UNSUP // // IEEE says: inc_or_dec_expression -//UNSUP // // IEEE says: subroutine_call -//UNSUP // // This is the same list as... -//UNSUP for_step_assignment { $$ = $1; } -//UNSUP ; +//UNSUP // // IEEE says: operator_assignment +//UNSUP // // IEEE says: inc_or_dec_expression +//UNSUP // // IEEE says: subroutine_call +//UNSUP // // This is the same list as... +//UNSUP for_step_assignment { $$ = $1; } +//UNSUP ; //UNSUPboolean_abbrev: // ==IEEE: boolean_abbrev -//UNSUP // // IEEE: consecutive_repetition -//UNSUP yP_BRASTAR const_or_range_expression ']' { } -//UNSUP | yP_BRASTAR ']' { } -//UNSUP | yP_BRAPLUSKET { $$ = $1; } -//UNSUP // // IEEE: non_consecutive_repetition -//UNSUP | yP_BRAEQ const_or_range_expression ']' { } -//UNSUP // // IEEE: goto_repetition -//UNSUP | yP_BRAMINUSGT const_or_range_expression ']' { } -//UNSUP ; +//UNSUP // // IEEE: consecutive_repetition +//UNSUP yP_BRASTAR const_or_range_expression ']' { } +//UNSUP | yP_BRASTAR ']' { } +//UNSUP | yP_BRAPLUSKET { $$ = $1; } +//UNSUP // // IEEE: non_consecutive_repetition +//UNSUP | yP_BRAEQ const_or_range_expression ']' { } +//UNSUP // // IEEE: goto_repetition +//UNSUP | yP_BRAMINUSGT const_or_range_expression ']' { } +//UNSUP ; //UNSUPconst_or_range_expression: // ==IEEE: const_or_range_expression -//UNSUP constExpr { $$ = $1; } -//UNSUP | cycle_delay_const_range_expression { } -//UNSUP ; +//UNSUP constExpr { $$ = $1; } +//UNSUP | cycle_delay_const_range_expression { } +//UNSUP ; //UNSUPconstant_range: // ==IEEE: constant_range -//UNSUP constExpr ':' constExpr { } -//UNSUP ; +//UNSUP constExpr ':' constExpr { } +//UNSUP ; //UNSUPcycle_delay_const_range_expression: // ==IEEE: cycle_delay_const_range_expression -//UNSUP // // Note '$' is part of constExpr -//UNSUP constExpr ':' constExpr { } -//UNSUP ; +//UNSUP // // Note '$' is part of constExpr +//UNSUP constExpr ':' constExpr { } +//UNSUP ; //************************************************ // Let @@ -5608,522 +5608,522 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regexps j // Covergroup //UNSUPcovergroup_declaration: // ==IEEE: covergroup_declaration -//UNSUP covergroup_declarationFront coverage_eventE ';' coverage_spec_or_optionListE -//UNSUP yENDGROUP endLabelE -//UNSUP { PARSEP->endgroupCb($5,$5); -//UNSUP SYMP->popScope($$); } -//UNSUP | covergroup_declarationFront '(' tf_port_listE ')' coverage_eventE ';' coverage_spec_or_optionListE -//UNSUP yENDGROUP endLabelE -//UNSUP { PARSEP->endgroupCb($8,$8); -//UNSUP SYMP->popScope($$); } -//UNSUP ; +//UNSUP covergroup_declarationFront coverage_eventE ';' coverage_spec_or_optionListE +//UNSUP yENDGROUP endLabelE +//UNSUP { PARSEP->endgroupCb($5,$5); +//UNSUP SYMP->popScope($$); } +//UNSUP | covergroup_declarationFront '(' tf_port_listE ')' coverage_eventE ';' coverage_spec_or_optionListE +//UNSUP yENDGROUP endLabelE +//UNSUP { PARSEP->endgroupCb($8,$8); +//UNSUP SYMP->popScope($$); } +//UNSUP ; //UNSUPcovergroup_declarationFront: // IEEE: part of covergroup_declaration -//UNSUP yCOVERGROUP idAny -//UNSUP { SYMP->pushNew($$); -//UNSUP PARSEP->covergroupCb($1,$1,$2); } -//UNSUP ; +//UNSUP yCOVERGROUP idAny +//UNSUP { SYMP->pushNew($$); +//UNSUP PARSEP->covergroupCb($1,$1,$2); } +//UNSUP ; //UNSUPcgexpr: // IEEE-2012: covergroup_expression, before that just expression -//UNSUP expr { $$ = $1; } -//UNSUP ; +//UNSUP expr { $$ = $1; } +//UNSUP ; //UNSUPcoverage_spec_or_optionListE: // IEEE: [{coverage_spec_or_option}] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | coverage_spec_or_optionList { $$ = $1; } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | coverage_spec_or_optionList { $$ = $1; } +//UNSUP ; //UNSUPcoverage_spec_or_optionList: // IEEE: {coverage_spec_or_option} -//UNSUP coverage_spec_or_option { $$ = $1; } -//UNSUP | coverage_spec_or_optionList coverage_spec_or_option { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP coverage_spec_or_option { $$ = $1; } +//UNSUP | coverage_spec_or_optionList coverage_spec_or_option { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPcoverage_spec_or_option: // ==IEEE: coverage_spec_or_option -//UNSUP // // IEEE: coverage_spec -//UNSUP cover_point { $$ = $1; } -//UNSUP | cover_cross { $$ = $1; } -//UNSUP | coverage_option ';' { $$ = $1; } -//UNSUP | error { $$ = nullptr; } -//UNSUP ; +//UNSUP // // IEEE: coverage_spec +//UNSUP cover_point { $$ = $1; } +//UNSUP | cover_cross { $$ = $1; } +//UNSUP | coverage_option ';' { $$ = $1; } +//UNSUP | error { $$ = nullptr; } +//UNSUP ; //UNSUPcoverage_option: // ==IEEE: coverage_option -//UNSUP // // option/type_option aren't really keywords -//UNSUP id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr { } -//UNSUP ; +//UNSUP // // option/type_option aren't really keywords +//UNSUP id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr { } +//UNSUP ; //UNSUPcover_point: // ==IEEE: cover_point -//UNSUP /**/ yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP // // IEEE-2012: class_scope before an ID -//UNSUP | /**/ /**/ /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id id data_type id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | /**/ id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP // // IEEE-2012: -//UNSUP | bins_or_empty { $$ = $1; } -//UNSUP ; +//UNSUP /**/ yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP // // IEEE-2012: class_scope before an ID +//UNSUP | /**/ /**/ /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP | class_scope_id ':' yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP | class_scope_id id data_type id ':' yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP | class_scope_id id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP | /**/ id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } +//UNSUP // // IEEE-2012: +//UNSUP | bins_or_empty { $$ = $1; } +//UNSUP; //UNSUPiffE: // IEEE: part of cover_point, others -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | yIFF '(' expr ')' { } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | yIFF '(' expr ')' { } +//UNSUP ; //UNSUPbins_or_empty: // ==IEEE: bins_or_empty -//UNSUP '{' bins_or_optionsList '}' { $$ = $2; } -//UNSUP | '{' '}' { $$ = nullptr; } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +//UNSUP '{' bins_or_optionsList '}' { $$ = $2; } +//UNSUP | '{' '}' { $$ = nullptr; } +//UNSUP | ';' { $$ = nullptr; } +//UNSUP ; //UNSUPbins_or_optionsList: // IEEE: { bins_or_options ';' } -//UNSUP bins_or_options ';' { $$ = $1; } -//UNSUP | bins_or_optionsList bins_or_options ';' { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP bins_or_options ';' { $$ = $1; } +//UNSUP | bins_or_optionsList bins_or_options ';' { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPbins_or_options: // ==IEEE: bins_or_options -//UNSUP // // Superset of IEEE - we allow []'s in more places -//UNSUP coverage_option { $$ = $1; } -//UNSUP // // Can't use wildcardE as results in conflicts -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } -//UNSUP // -//UNSUP // // cgexpr part of trans_list -//UNSUP // -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } -//UNSUP // -//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE { } -//UNSUP // -//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE { } -//UNSUP ; +//UNSUP // // Superset of IEEE - we allow []'s in more places +//UNSUP coverage_option { $$ = $1; } +//UNSUP // // Can't use wildcardE as results in conflicts +//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } +//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } +//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } +//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } +//UNSUP // +//UNSUP // // cgexpr part of trans_list +//UNSUP // +//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } +//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } +//UNSUP // +//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE { } +//UNSUP // +//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE { } +//UNSUP ; //UNSUPbins_orBraE: // IEEE: part of bins_or_options: -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | '[' ']' { } -//UNSUP | '[' cgexpr ']' { } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | '[' ']' { } +//UNSUP | '[' cgexpr ']' { } +//UNSUP ; //UNSUPbins_keyword: // ==IEEE: bins_keyword -//UNSUP yBINS { } -//UNSUP | yILLEGAL_BINS { } -//UNSUP | yIGNORE_BINS { } -//UNSUP ; +//UNSUP yBINS { } +//UNSUP | yILLEGAL_BINS { } +//UNSUP | yIGNORE_BINS { } +//UNSUP ; //UNSUPcovergroup_range_list: // ==IEEE: covergroup_range_list -//UNSUP covergroup_value_range { $$ = $1; } -//UNSUP | covergroup_range_list ',' covergroup_value_range { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP covergroup_value_range { $$ = $1; } +//UNSUP | covergroup_range_list ',' covergroup_value_range { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; //UNSUPtrans_list: // ==IEEE: trans_list -//UNSUP '(' trans_set ')' { $$ = $2; } -//UNSUP | trans_list ',' '(' trans_set ')' { } -//UNSUP ; +//UNSUP '(' trans_set ')' { $$ = $2; } +//UNSUP | trans_list ',' '(' trans_set ')' { } +//UNSUP ; //UNSUPtrans_set: // ==IEEE: trans_set -//UNSUP trans_range_list { $$ = $1; } -//UNSUP // // Note the { => } in the grammer, this is really a list -//UNSUP | trans_set yP_EQGT trans_range_list { } -//UNSUP ; +//UNSUP trans_range_list { $$ = $1; } +//UNSUP // // Note the { => } in the grammer, this is really a list +//UNSUP | trans_set yP_EQGT trans_range_list { } +//UNSUP ; //UNSUPtrans_range_list: // ==IEEE: trans_range_list -//UNSUP trans_item { $$ = $1; } -//UNSUP | trans_item yP_BRASTAR repeat_range ']' { } -//UNSUP | trans_item yP_BRAMINUSGT repeat_range ']' { } -//UNSUP | trans_item yP_BRAEQ repeat_range ']' { } -//UNSUP ; +//UNSUP trans_item { $$ = $1; } +//UNSUP | trans_item yP_BRASTAR repeat_range ']' { } +//UNSUP | trans_item yP_BRAMINUSGT repeat_range ']' { } +//UNSUP | trans_item yP_BRAEQ repeat_range ']' { } +//UNSUP ; //UNSUPtrans_item: // ==IEEE: range_list -//UNSUP covergroup_range_list { $$ = $1; } -//UNSUP ; +//UNSUP covergroup_range_list { $$ = $1; } +//UNSUP ; //UNSUPrepeat_range: // ==IEEE: repeat_range -//UNSUP cgexpr { $$ = $1; } -//UNSUP | cgexpr ':' cgexpr { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP cgexpr { $$ = $1; } +//UNSUP | cgexpr ':' cgexpr { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; //UNSUPcover_cross: // ==IEEE: cover_cross -//UNSUP id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body { } -//UNSUP | /**/ yCROSS list_of_cross_items iffE cross_body { } -//UNSUP ; +//UNSUP id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body { } +//UNSUP | /**/ yCROSS list_of_cross_items iffE cross_body { } +//UNSUP ; //UNSUPlist_of_cross_items: // ==IEEE: list_of_cross_items -//UNSUP cross_item ',' cross_item { $$ = AstNode::addNextNull($1, $3); } -//UNSUP | cross_item ',' cross_item ',' cross_itemList { } -//UNSUP ; +//UNSUP cross_item ',' cross_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | cross_item ',' cross_item ',' cross_itemList { } +//UNSUP ; //UNSUPcross_itemList: // IEEE: part of list_of_cross_items -//UNSUP cross_item { $$ = nullptr; } -//UNSUP | cross_itemList ',' cross_item { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP cross_item { $$ = nullptr; } +//UNSUP | cross_itemList ',' cross_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; //UNSUPcross_item: // ==IEEE: cross_item -//UNSUP idAny/*cover_point_identifier or variable_identifier*/ { $$ = $1; } -//UNSUP ; +//UNSUP idAny/*cover_point_identifier or variable_identifier*/ { $$ = $1; } +//UNSUP ; //UNSUPcross_body: // ==IEEE: cross_body -//UNSUP '{' '}' { $$ = nullptr; } -//UNSUP // // IEEE-2012: No semicolon here, mistake in spec -//UNSUP | '{' cross_body_itemSemiList '}' { $$ = $1; } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +//UNSUP '{' '}' { $$ = nullptr; } +//UNSUP // // IEEE-2012: No semicolon here, mistake in spec +//UNSUP | '{' cross_body_itemSemiList '}' { $$ = $1; } +//UNSUP | ';' { $$ = nullptr; } +//UNSUP ; //UNSUPcross_body_itemSemiList: // IEEE: part of cross_body -//UNSUP cross_body_item ';' { $$ = $1; } -//UNSUP | cross_body_itemSemiList cross_body_item ';' { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP cross_body_item ';' { $$ = $1; } +//UNSUP | cross_body_itemSemiList cross_body_item ';' { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPcross_body_item: // ==IEEE: cross_body_item -//UNSUP // // IEEE: our semicolon is in the list -//UNSUP bins_selection_or_option { $$ = $1; } -//UNSUP | function_declaration { $$ = $1; } -//UNSUP ; +//UNSUP // // IEEE: our semicolon is in the list +//UNSUP bins_selection_or_option { $$ = $1; } +//UNSUP | function_declaration { $$ = $1; } +//UNSUP ; //UNSUPbins_selection_or_option: // ==IEEE: bins_selection_or_option -//UNSUP coverage_option { $$ = $1; } -//UNSUP | bins_selection { $$ = $1; } -//UNSUP ; +//UNSUP coverage_option { $$ = $1; } +//UNSUP | bins_selection { $$ = $1; } +//UNSUP ; //UNSUPbins_selection: // ==IEEE: bins_selection -//UNSUP bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE { } -//UNSUP ; +//UNSUP bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE { } +//UNSUP ; //UNSUPselect_expression: // ==IEEE: select_expression -//UNSUP // // IEEE: select_condition expanded here -//UNSUP yBINSOF '(' bins_expression ')' { } -//UNSUP | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } -//UNSUP | yWITH__PAREN '(' cgexpr ')' { } -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } -//UNSUP | '!' yBINSOF '(' bins_expression ')' { } -//UNSUP | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } -//UNSUP | '!' yWITH__PAREN '(' cgexpr ')' { } -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP '!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } -//UNSUP | select_expression yP_ANDAND select_expression { } -//UNSUP | select_expression yP_OROR select_expression { } -//UNSUP | '(' select_expression ')' { $$ = $2; } -//UNSUP // // IEEE-2012: cross_identifier -//UNSUP // // Part of covergroup_expression - generic identifier -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP covergroup_expression [ yMATCHES covergroup_expression ] -//UNSUP ; +//UNSUP // // IEEE: select_condition expanded here +//UNSUP yBINSOF '(' bins_expression ')' { } +//UNSUP | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } +//UNSUP | yWITH__PAREN '(' cgexpr ')' { } +//UNSUP // // IEEE-2012: Need clarification as to precedence +//UNSUP //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } +//UNSUP | '!' yBINSOF '(' bins_expression ')' { } +//UNSUP | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } +//UNSUP | '!' yWITH__PAREN '(' cgexpr ')' { } +//UNSUP // // IEEE-2012: Need clarification as to precedence +//UNSUP //UNSUP '!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } +//UNSUP | select_expression yP_ANDAND select_expression { } +//UNSUP | select_expression yP_OROR select_expression { } +//UNSUP | '(' select_expression ')' { $$ = $2; } +//UNSUP // // IEEE-2012: cross_identifier +//UNSUP // // Part of covergroup_expression - generic identifier +//UNSUP // // IEEE-2012: Need clarification as to precedence +//UNSUP //UNSUP covergroup_expression [ yMATCHES covergroup_expression ] +//UNSUP ; //UNSUPbins_expression: // ==IEEE: bins_expression -//UNSUP // // "cover_point_identifier" and "variable_identifier" look identical -//UNSUP id/*variable_identifier or cover_point_identifier*/ { $$ = $1; } -//UNSUP | id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/ { } -//UNSUP ; +//UNSUP // // "cover_point_identifier" and "variable_identifier" look identical +//UNSUP id/*variable_identifier or cover_point_identifier*/ { $$ = $1; } +//UNSUP | id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/ { } +//UNSUP ; //UNSUPcoverage_eventE: // IEEE: [ coverage_event ] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | clocking_event { $$ = $1; } -//UNSUP | yWITH__ETC function idAny/*"sample"*/ '(' tf_port_listE ')' { } -//UNSUP | yP_ATAT '(' block_event_expression ')' { } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | clocking_event { $$ = $1; } +//UNSUP | yWITH__ETC function idAny/*"sample"*/ '(' tf_port_listE ')' { } +//UNSUP | yP_ATAT '(' block_event_expression ')' { } +//UNSUP ; //UNSUPblock_event_expression: // ==IEEE: block_event_expression -//UNSUP block_event_expressionTerm { $$ = $1; } -//UNSUP | block_event_expression yOR block_event_expressionTerm { } -//UNSUP ; +//UNSUP block_event_expressionTerm { $$ = $1; } +//UNSUP | block_event_expression yOR block_event_expressionTerm { } +//UNSUP ; //UNSUPblock_event_expressionTerm: // IEEE: part of block_event_expression -//UNSUP yBEGIN hierarchical_btf_identifier { } -//UNSUP | yEND hierarchical_btf_identifier { } -//UNSUP ; +//UNSUP yBEGIN hierarchical_btf_identifier { } +//UNSUP | yEND hierarchical_btf_identifier { } +//UNSUP ; //UNSUPhierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier -//UNSUP // // hierarchical_tf_identifier + hierarchical_block_identifier -//UNSUP hierarchical_identifier/*tf_or_block*/ { $$ = $1; } -//UNSUP // // method_identifier -//UNSUP | hierarchical_identifier class_scope_id { } -//UNSUP | hierarchical_identifier id { } -//UNSUP ; +//UNSUP // // hierarchical_tf_identifier + hierarchical_block_identifier +//UNSUP hierarchical_identifier/*tf_or_block*/ { $$ = $1; } +//UNSUP // // method_identifier +//UNSUP | hierarchical_identifier class_scope_id { } +//UNSUP | hierarchical_identifier id { } +//UNSUP ; //********************************************************************** // Randsequence //UNSUPrandsequence_statement: // ==IEEE: randsequence_statement -//UNSUP yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE { } -//UNSUP | yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE { } -//UNSUP ; +//UNSUP yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE { } +//UNSUP | yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE { } +//UNSUP ; //UNSUPproductionList: // IEEE: production+ -//UNSUP production { $$ = $1; } -//UNSUP | productionList production { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP production { $$ = $1; } +//UNSUP | productionList production { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPproduction: // ==IEEE: production -//UNSUP productionFront ':' rs_ruleList ';' { } -//UNSUP ; +//UNSUP productionFront ':' rs_ruleList ';' { } +//UNSUP ; //UNSUPproductionFront: // IEEE: part of production -//UNSUP function_data_type id/*production_identifier*/ { } -//UNSUP | /**/ id/*production_identifier*/ { $$ = $1; } -//UNSUP | function_data_type id/*production_identifier*/ '(' tf_port_listE ')' { } -//UNSUP | /**/ id/*production_identifier*/ '(' tf_port_listE ')' { } -//UNSUP ; +//UNSUP function_data_type id/*production_identifier*/ { } +//UNSUP | /**/ id/*production_identifier*/ { $$ = $1; } +//UNSUP | function_data_type id/*production_identifier*/ '(' tf_port_listE ')' { } +//UNSUP | /**/ id/*production_identifier*/ '(' tf_port_listE ')' { } +//UNSUP ; //UNSUPrs_ruleList: // IEEE: rs_rule+ part of production -//UNSUP rs_rule { $$ = $1; } -//UNSUP | rs_ruleList '|' rs_rule { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +//UNSUP rs_rule { $$ = $1; } +//UNSUP | rs_ruleList '|' rs_rule { $$ = AstNode::addNextNull($1, $3); } +//UNSUP ; //UNSUPrs_rule: // ==IEEE: rs_rule -//UNSUP rs_production_list { $$ = $1; } -//UNSUP | rs_production_list yP_COLONEQ weight_specification { } -//UNSUP | rs_production_list yP_COLONEQ weight_specification rs_code_block { } -//UNSUP ; +//UNSUP rs_production_list { $$ = $1; } +//UNSUP | rs_production_list yP_COLONEQ weight_specification { } +//UNSUP | rs_production_list yP_COLONEQ weight_specification rs_code_block { } +//UNSUP ; //UNSUPrs_production_list: // ==IEEE: rs_production_list -//UNSUP rs_prodList { $$ = $1; } -//UNSUP | yRAND yJOIN /**/ production_item production_itemList { } -//UNSUP | yRAND yJOIN '(' expr ')' production_item production_itemList { } -//UNSUP ; +//UNSUP rs_prodList { $$ = $1; } +//UNSUP | yRAND yJOIN /**/ production_item production_itemList { } +//UNSUP | yRAND yJOIN '(' expr ')' production_item production_itemList { } +//UNSUP ; //UNSUPweight_specification: // ==IEEE: weight_specification -//UNSUP yaINTNUM { $$ = $1; } -//UNSUP | idClassSel/*ps_identifier*/ { $$ = $1; } -//UNSUP | '(' expr ')' { $$ = $2; } -//UNSUP ; +//UNSUP yaINTNUM { $$ = $1; } +//UNSUP | idClassSel/*ps_identifier*/ { $$ = $1; } +//UNSUP | '(' expr ')' { $$ = $2; } +//UNSUP ; //UNSUPrs_code_block: // ==IEEE: rs_code_block -//UNSUP '{' '}' { $$ = nullptr; } -//UNSUP | '{' rs_code_blockItemList '}' { $$ = $2; } -//UNSUP ; +//UNSUP '{' '}' { $$ = nullptr; } +//UNSUP | '{' rs_code_blockItemList '}' { $$ = $2; } +//UNSUP ; //UNSUPrs_code_blockItemList: // IEEE: part of rs_code_block -//UNSUP rs_code_blockItem { $$ = $1; } -//UNSUP | rs_code_blockItemList rs_code_blockItem { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP rs_code_blockItem { $$ = $1; } +//UNSUP | rs_code_blockItemList rs_code_blockItem { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPrs_code_blockItem: // IEEE: part of rs_code_block -//UNSUP data_declaration { $$ = $1; } -//UNSUP | stmt { $$ = $1; } -//UNSUP ; +//UNSUP data_declaration { $$ = $1; } +//UNSUP | stmt { $$ = $1; } +//UNSUP ; //UNSUPrs_prodList: // IEEE: rs_prod+ -//UNSUP rs_prod { $$ = $1; } -//UNSUP | rs_prodList rs_prod { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP rs_prod { $$ = $1; } +//UNSUP | rs_prodList rs_prod { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPrs_prod: // ==IEEE: rs_prod -//UNSUP production_item { $$ = $1; } -//UNSUP | rs_code_block { $$ = $1; } -//UNSUP // // IEEE: rs_if_else -//UNSUP | yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE { } -//UNSUP | yIF '(' expr ')' production_item yELSE production_item { } -//UNSUP // // IEEE: rs_repeat -//UNSUP | yREPEAT '(' expr ')' production_item { } -//UNSUP // // IEEE: rs_case -//UNSUP | yCASE '(' expr ')' rs_case_itemList yENDCASE { } -//UNSUP ; +//UNSUP production_item { $$ = $1; } +//UNSUP | rs_code_block { $$ = $1; } +//UNSUP // // IEEE: rs_if_else +//UNSUP | yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE { } +//UNSUP | yIF '(' expr ')' production_item yELSE production_item { } +//UNSUP // // IEEE: rs_repeat +//UNSUP | yREPEAT '(' expr ')' production_item { } +//UNSUP // // IEEE: rs_case +//UNSUP | yCASE '(' expr ')' rs_case_itemList yENDCASE { } +//UNSUP ; //UNSUPproduction_itemList: // IEEE: production_item+ -//UNSUP production_item { $$ = $1; } -//UNSUP | production_itemList production_item { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP production_item { $$ = $1; } +//UNSUP | production_itemList production_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPproduction_item: // ==IEEE: production_item -//UNSUP id/*production_identifier*/ { $$ = $1; } -//UNSUP | id/*production_identifier*/ '(' list_of_argumentsE ')' { } -//UNSUP ; +//UNSUP id/*production_identifier*/ { $$ = $1; } +//UNSUP | id/*production_identifier*/ '(' list_of_argumentsE ')' { } +//UNSUP ; //UNSUPrs_case_itemList: // IEEE: rs_case_item+ -//UNSUP rs_case_item { $$ = $1; } -//UNSUP | rs_case_itemList rs_case_item { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP rs_case_item { $$ = $1; } +//UNSUP | rs_case_itemList rs_case_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPrs_case_item: // ==IEEE: rs_case_item -//UNSUP caseCondList ':' production_item ';' { } -//UNSUP | yDEFAULT production_item ';' { } -//UNSUP | yDEFAULT ':' production_item ';' { } -//UNSUP ; +//UNSUP caseCondList ':' production_item ';' { } +//UNSUP | yDEFAULT production_item ';' { } +//UNSUP | yDEFAULT ':' production_item ';' { } +//UNSUP ; //********************************************************************** // Checker //UNSUPchecker_declaration: // ==IEEE: part of checker_declaration -//UNSUP checkerFront checker_port_listE ';' -//UNSUP checker_or_generate_itemListE yENDCHECKER endLabelE -//UNSUP { SYMP->popScope($$); } -//UNSUP ; +//UNSUP checkerFront checker_port_listE ';' +//UNSUP checker_or_generate_itemListE yENDCHECKER endLabelE +//UNSUP { SYMP->popScope($$); } +//UNSUP ; //UNSUPcheckerFront: // IEEE: part of checker_declaration -//UNSUP yCHECKER idAny/*checker_identifier*/ -//UNSUP { SYMP->pushNew($$); } -//UNSUP ; +//UNSUP yCHECKER idAny/*checker_identifier*/ +//UNSUP { SYMP->pushNew($$); } +//UNSUP ; //UNSUPchecker_port_listE: // IEEE: [ ( [ checker_port_list ] ) ] -//UNSUP // // checker_port_item is basically the same as property_port_item, minus yLOCAL:: -//UNSUP // // Want to bet 1800-2012 adds local to checkers? -//UNSUP property_port_listE { $$ = $1; } -//UNSUP ; +//UNSUP // // checker_port_item is basically the same as property_port_item, minus yLOCAL:: +//UNSUP // // Want to bet 1800-2012 adds local to checkers? +//UNSUP property_port_listE { $$ = $1; } +//UNSUP ; //UNSUPchecker_or_generate_itemListE: // IEEE: [{ checker_or_generate_itemList }] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | checker_or_generate_itemList { $$ = $1; } -//UNSUP ; +//UNSUP /* empty */ { $$ = nullptr; } +//UNSUP | checker_or_generate_itemList { $$ = $1; } +//UNSUP ; //UNSUPchecker_or_generate_itemList: // IEEE: { checker_or_generate_itemList } -//UNSUP checker_or_generate_item { $$ = $1; } -//UNSUP | checker_or_generate_itemList checker_or_generate_item { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +//UNSUP checker_or_generate_item { $$ = $1; } +//UNSUP | checker_or_generate_itemList checker_or_generate_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP ; //UNSUPchecker_or_generate_item: // ==IEEE: checker_or_generate_item -//UNSUP checker_or_generate_item_declaration { $$ = $1; } -//UNSUP | initial_construct { $$ = $1; } -//UNSUP // // IEEE: checker_construct -//UNSUP | yALWAYS stmtBlock { } -//UNSUP | final_construct { $$ = $1; } -//UNSUP | assertion_item { $$ = $1; } -//UNSUP | continuous_assign { $$ = $1; } -//UNSUP | checker_generate_item { $$ = $1; } -//UNSUP ; +//UNSUP checker_or_generate_item_declaration { $$ = $1; } +//UNSUP | initial_construct { $$ = $1; } +//UNSUP // // IEEE: checker_construct +//UNSUP | yALWAYS stmtBlock { } +//UNSUP | final_construct { $$ = $1; } +//UNSUP | assertion_item { $$ = $1; } +//UNSUP | continuous_assign { $$ = $1; } +//UNSUP | checker_generate_item { $$ = $1; } +//UNSUP ; //UNSUPchecker_or_generate_item_declaration: // ==IEEE: checker_or_generate_item_declaration -//UNSUP data_declaration { $$ = $1; } -//UNSUP | yRAND data_declaration { } -//UNSUP | function_declaration { $$ = $1; } -//UNSUP | checker_declaration { $$ = $1; } -//UNSUP | assertion_item_declaration { $$ = $1; } -//UNSUP | covergroup_declaration { $$ = $1; } -//UNSUP // // IEEE deprecated: overload_declaration -//UNSUP | genvar_declaration { $$ = $1; } -//UNSUP | clocking_declaration { $$ = $1; } -//UNSUP | yDEFAULT yCLOCKING id/*clocking_identifier*/ ';' { } -//UNSUP | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +//UNSUP data_declaration { $$ = $1; } +//UNSUP | yRAND data_declaration { } +//UNSUP | function_declaration { $$ = $1; } +//UNSUP | checker_declaration { $$ = $1; } +//UNSUP | assertion_item_declaration { $$ = $1; } +//UNSUP | covergroup_declaration { $$ = $1; } +//UNSUP // // IEEE deprecated: overload_declaration +//UNSUP | genvar_declaration { $$ = $1; } +//UNSUP | clocking_declaration { $$ = $1; } +//UNSUP | yDEFAULT yCLOCKING id/*clocking_identifier*/ ';' { } +//UNSUP | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } +//UNSUP | ';' { $$ = nullptr; } +//UNSUP ; //UNSUPchecker_generate_item: // ==IEEE: checker_generate_item -//UNSUP // // Specialized for checker so need "c_" prefixes here -//UNSUP c_loop_generate_construct { $$ = $1; } -//UNSUP | c_conditional_generate_construct { $$ = $1; } -//UNSUP | c_generate_region { $$ = $1; } -//UNSUP // -//UNSUP | elaboration_system_task { $$ = $1; } -//UNSUP ; +//UNSUP // // Specialized for checker so need "c_" prefixes here +//UNSUP c_loop_generate_construct { $$ = $1; } +//UNSUP | c_conditional_generate_construct { $$ = $1; } +//UNSUP | c_generate_region { $$ = $1; } +//UNSUP // +//UNSUP | elaboration_system_task { $$ = $1; } +//UNSUP ; //UNSUPchecker_instantiation: -//UNSUP // // Only used for procedural_assertion_item's -//UNSUP // // Version in concurrent_assertion_item looks like etcInst -//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinList -//UNSUP id/*checker_identifier*/ id '(' cellpinList ')' ';' { } -//UNSUP ; +//UNSUP // // Only used for procedural_assertion_item's +//UNSUP // // Version in concurrent_assertion_item looks like etcInst +//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinList +//UNSUP id/*checker_identifier*/ id '(' cellpinList ')' ';' { } +//UNSUP ; //********************************************************************** // Class -class_declaration: // ==IEEE: part of class_declaration - // // IEEE-2012: using this also for interface_class_declaration - // // The classExtendsE rule relys on classFront having the - // // new class scope correct via classFront - classFront parameter_port_listE classExtendsE classImplementsE ';' - /*mid*/ { // Allow resolving types declared in base extends class - if ($3) SYMP->importExtends($3); - } - /*cont*/ class_itemListE yENDCLASS endLabelE - { $$ = $1; $1->addMembersp($2); - $1->extendsp($3); - $1->addMembersp($4); - $1->addMembersp($7); - SYMP->popScope($$); - GRAMMARP->endLabel($7, $1, $9); } - ; +class_declaration: // ==IEEE: part of class_declaration + // // IEEE-2012: using this also for interface_class_declaration + // // The classExtendsE rule relys on classFront having the + // // new class scope correct via classFront + classFront parameter_port_listE classExtendsE classImplementsE ';' + /*mid*/ { // Allow resolving types declared in base extends class + if ($3) SYMP->importExtends($3); + } + /*cont*/ class_itemListE yENDCLASS endLabelE + { $$ = $1; $1->addMembersp($2); + $1->extendsp($3); + $1->addMembersp($4); + $1->addMembersp($7); + SYMP->popScope($$); + GRAMMARP->endLabel($7, $1, $9); } + ; -classFront: // IEEE: part of class_declaration - classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ - { $$ = new AstClass($2, *$4); - $$->isVirtual($1); - $$->lifetime($3); - SYMP->pushNew($$); } - // // IEEE: part of interface_class_declaration - | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ - { $$ = new AstClass($2, *$4); - $$->lifetime($3); - SYMP->pushNew($$); - BBUNSUP($2, "Unsupported: interface classes"); } - ; +classFront: // IEEE: part of class_declaration + classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ + { $$ = new AstClass($2, *$4); + $$->isVirtual($1); + $$->lifetime($3); + SYMP->pushNew($$); } + // // IEEE: part of interface_class_declaration + | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ + { $$ = new AstClass($2, *$4); + $$->lifetime($3); + SYMP->pushNew($$); + BBUNSUP($2, "Unsupported: interface classes"); } + ; classVirtualE: - /* empty */ { $$ = false; } - | yVIRTUAL__CLASS { $$ = true; } - ; + /* empty */ { $$ = false; } + | yVIRTUAL__CLASS { $$ = true; } + ; -classExtendsE: // IEEE: part of class_declaration - // // The classExtendsE rule relys on classFront having the - // // new class scope correct via classFront - /* empty */ { $$ = nullptr; $$ = nullptr; } - | yEXTENDS classExtendsList { $$ = $2; $$ = $2; } - ; +classExtendsE: // IEEE: part of class_declaration + // // The classExtendsE rule relys on classFront having the + // // new class scope correct via classFront + /* empty */ { $$ = nullptr; $$ = nullptr; } + | yEXTENDS classExtendsList { $$ = $2; $$ = $2; } + ; -classExtendsList: // IEEE: part of class_declaration - classExtendsOne { $$ = $1; $$ = $1; } - | classExtendsList ',' classExtendsOne - { $$ = $3; $$ = $3; - BBUNSUP($3, "Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), " - "and unsupported for interface classes."); } - ; +classExtendsList: // IEEE: part of class_declaration + classExtendsOne { $$ = $1; $$ = $1; } + | classExtendsList ',' classExtendsOne + { $$ = $3; $$ = $3; + BBUNSUP($3, "Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), " + "and unsupported for interface classes."); } + ; -classExtendsOne: // IEEE: part of class_declaration - class_typeExtImpList - { $$ = new AstClassExtends($1->fileline(), $1); +classExtendsOne: // IEEE: part of class_declaration + class_typeExtImpList + { $$ = new AstClassExtends($1->fileline(), $1); $$ = $1; } - // - | class_typeExtImpList '(' list_of_argumentsE ')' - { $$ = new AstClassExtends($1->fileline(), $1); + // + | class_typeExtImpList '(' list_of_argumentsE ')' + { $$ = new AstClassExtends($1->fileline(), $1); $$ = $1; - if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); } - ; + if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); } + ; -classImplementsE: // IEEE: part of class_declaration - // // All 1800-2012 - /* empty */ { $$ = nullptr; } - | yIMPLEMENTS classImplementsList { $$ = $2; } - ; +classImplementsE: // IEEE: part of class_declaration + // // All 1800-2012 + /* empty */ { $$ = nullptr; } + | yIMPLEMENTS classImplementsList { $$ = $2; } + ; -classImplementsList: // IEEE: part of class_declaration - // // All 1800-2012 - class_typeExtImpList { $$ = nullptr; BBUNSUP($1, "Unsupported: implements class"); } - | classImplementsList ',' class_typeExtImpList { $$ = AstNode::addNextNull($1, $3); } - ; +classImplementsList: // IEEE: part of class_declaration + // // All 1800-2012 + class_typeExtImpList { $$ = nullptr; BBUNSUP($1, "Unsupported: implements class"); } + | classImplementsList ',' class_typeExtImpList { $$ = AstNode::addNextNull($1, $3); } + ; -class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" - // // but allow yaID__aTYPE for extends/implements - // // If you follow the rules down, class_type is really a list via ps_class_identifier - class_typeExtImpOne { $$ = $1; $$ = $1; } - | class_typeExtImpList yP_COLONCOLON class_typeExtImpOne - { $$ = $3; $$ = $1; - // Cannot just add as next() as that breaks implements lists - //UNSUP $$ = new AstDot($1, true, $1, $3); - BBUNSUP($2, "Unsupported: Hierarchical class references"); } - ; +class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" + // // but allow yaID__aTYPE for extends/implements + // // If you follow the rules down, class_type is really a list via ps_class_identifier + class_typeExtImpOne { $$ = $1; $$ = $1; } + | class_typeExtImpList yP_COLONCOLON class_typeExtImpOne + { $$ = $3; $$ = $1; + // Cannot just add as next() as that breaks implements lists + //UNSUP $$ = new AstDot($1, true, $1, $3); + BBUNSUP($2, "Unsupported: Hierarchical class references"); } + ; -class_typeExtImpOne: // part of IEEE: class_type, where we either get a package_scope component or class - // // If you follow the rules down, class_type is really a list via ps_class_identifier - // // Not listed in IEEE, but see bug627 any parameter type maybe a class - // // If idAny below is a class, parameter_value is legal - // // If idAny below is a package, parameter_value is not legal - // // If idAny below is otherwise, not legal - idAny - /*mid*/ { /* no nextId as not refing it above this*/ } - /*cont*/ parameter_value_assignmentE - { $$ = new AstClassOrPackageRef($1, *$1, $1, $3); - $$ = $1; } - // - // // package_sopeIdFollows expanded - | yD_UNIT yP_COLONCOLON - { $$ = new AstClassOrPackageRef($1, "$unit", nullptr, nullptr); +class_typeExtImpOne: // part of IEEE: class_type, where we either get a package_scope component or class + // // If you follow the rules down, class_type is really a list via ps_class_identifier + // // Not listed in IEEE, but see bug627 any parameter type maybe a class + // // If idAny below is a class, parameter_value is legal + // // If idAny below is a package, parameter_value is not legal + // // If idAny below is otherwise, not legal + idAny + /*mid*/ { /* no nextId as not refing it above this*/ } + /*cont*/ parameter_value_assignmentE + { $$ = new AstClassOrPackageRef($1, *$1, $1, $3); + $$ = $1; } + // + // // package_sopeIdFollows expanded + | yD_UNIT yP_COLONCOLON + { $$ = new AstClassOrPackageRef($1, "$unit", nullptr, nullptr); $$ = nullptr; // No purpose otherwise, every symtab can see root - SYMP->nextId(PARSEP->rootp()); } - // - | yLOCAL__COLONCOLON yP_COLONCOLON - { $$ = new AstClassOrPackageRef($1, "local::", nullptr, nullptr); + SYMP->nextId(PARSEP->rootp()); } + // + | yLOCAL__COLONCOLON yP_COLONCOLON + { $$ = new AstClassOrPackageRef($1, "local::", nullptr, nullptr); $$ = nullptr; // UNSUP - SYMP->nextId(PARSEP->rootp()); - BBUNSUP($1, "Unsupported: Randomize 'local::'"); } - ; + SYMP->nextId(PARSEP->rootp()); + BBUNSUP($1, "Unsupported: Randomize 'local::'"); } + ; //========= // Package scoping - to traverse the symbol table properly, the final identifer @@ -6132,358 +6132,358 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p //=== Below rules assume special scoping per above -packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID - packageClassScope { $$ = $1; $$ = $1; SYMP->nextId(nullptr); } - ; +packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID + packageClassScope { $$ = $1; $$ = $1; SYMP->nextId(nullptr); } + ; -packageClassScopeE: // IEEE: [package_scope] - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // TODO: To support classes should return generic type, not packagep - // // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' class_scope ] - /* empty */ { $$ = nullptr; $$ = nullptr; } - | packageClassScope { $$ = $1; $$ = $1; } - ; +packageClassScopeE: // IEEE: [package_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // TODO: To support classes should return generic type, not packagep + // // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' class_scope ] + /* empty */ { $$ = nullptr; $$ = nullptr; } + | packageClassScope { $$ = $1; $$ = $1; } + ; -packageClassScope: // IEEE: class_scope - // // IEEE: "class_type yP_COLONCOLON" - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // In this parser :: and :: are indistinguishible - // // This copies to document it is important - packageClassScopeList { $$ = $1; $$ = $1; } - | localNextId yP_COLONCOLON { $$ = $1; $$ = $1; } - | dollarUnitNextId yP_COLONCOLON { $$ = $1; $$ = $1; } - | dollarUnitNextId yP_COLONCOLON packageClassScopeList - { $$ = new AstDot($2, true, $1, $3); $$ = $3; } - ; +packageClassScope: // IEEE: class_scope + // // IEEE: "class_type yP_COLONCOLON" + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // In this parser :: and :: are indistinguishible + // // This copies to document it is important + packageClassScopeList { $$ = $1; $$ = $1; } + | localNextId yP_COLONCOLON { $$ = $1; $$ = $1; } + | dollarUnitNextId yP_COLONCOLON { $$ = $1; $$ = $1; } + | dollarUnitNextId yP_COLONCOLON packageClassScopeList + { $$ = new AstDot($2, true, $1, $3); $$ = $3; } + ; -packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE - // // Or IEEE: [package_scope] - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // In this parser :: and :: are indistinguishible - // // If you follow the rules down, class_type is really a list via ps_class_identifier - packageClassScopeItem { $$ = $1; $$ = $1; } - | packageClassScopeList packageClassScopeItem - { $$ = new AstDot($2, true, $1, $2); $$ = $2; } - ; +packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE + // // Or IEEE: [package_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // In this parser :: and :: are indistinguishible + // // If you follow the rules down, class_type is really a list via ps_class_identifier + packageClassScopeItem { $$ = $1; $$ = $1; } + | packageClassScopeList packageClassScopeItem + { $$ = new AstDot($2, true, $1, $2); $$ = $2; } + ; -packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE - // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token - idCC - /*mid*/ { SYMP->nextId($1); } - /*cont*/ yP_COLONCOLON - { $$ = new AstClassOrPackageRef($1, *$1, $1, nullptr); $$ = $1; } - // - | idCC parameter_value_assignment - /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before - /*cont*/ yP_COLONCOLON - { $$ = new AstClassOrPackageRef($1, *$1, $1, $2); $$ = $1; } - ; +packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE + // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token + idCC + /*mid*/ { SYMP->nextId($1); } + /*cont*/ yP_COLONCOLON + { $$ = new AstClassOrPackageRef($1, *$1, $1, nullptr); $$ = $1; } + // + | idCC parameter_value_assignment + /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before + /*cont*/ yP_COLONCOLON + { $$ = new AstClassOrPackageRef($1, *$1, $1, $2); $$ = $1; } + ; -dollarUnitNextId: // $unit - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // Must call nextId without any additional tokens following - yD_UNIT - { $$ = new AstClassOrPackageRef{$1, "$unit", PARSEP->unitPackage($1), nullptr}; +dollarUnitNextId: // $unit + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // Must call nextId without any additional tokens following + yD_UNIT + { $$ = new AstClassOrPackageRef{$1, "$unit", PARSEP->unitPackage($1), nullptr}; SYMP->nextId(PARSEP->rootp()); } - ; + ; -localNextId: // local - // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // if not needed must use packageClassScopeNoId - // // Must call nextId without any additional tokens following - yLOCAL__COLONCOLON - { $$ = new AstClassOrPackageRef{$1, "local::", PARSEP->unitPackage($1), nullptr}; +localNextId: // local + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // Must call nextId without any additional tokens following + yLOCAL__COLONCOLON + { $$ = new AstClassOrPackageRef{$1, "local::", PARSEP->unitPackage($1), nullptr}; SYMP->nextId(PARSEP->rootp()); - BBUNSUP($1, "Unsupported: Randomize 'local::'"); } - ; + BBUNSUP($1, "Unsupported: Randomize 'local::'"); } + ; //^^^========= class_itemListE: - /* empty */ { $$ = nullptr; } - | class_itemList { $$ = $1; } - ; + /* empty */ { $$ = nullptr; } + | class_itemList { $$ = $1; } + ; class_itemList: - class_item { $$ = $1; } - | class_itemList class_item { $$ = AstNode::addNextNull($1, $2); } - ; + class_item { $$ = $1; } + | class_itemList class_item { $$ = AstNode::addNextNull($1, $2); } + ; -class_item: // ==IEEE: class_item - class_property { $$ = $1; } - | class_method { $$ = $1; } - | class_constraint { $$ = $1; } - // - | class_declaration - { $$ = nullptr; BBUNSUP($1, "Unsupported: class within class"); } - | timeunits_declaration { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } - // // local_parameter_declaration under parameter_declaration - | parameter_declaration ';' { $$ = $1; } - | ';' { $$ = nullptr; } - // - | error ';' { $$ = nullptr; } - ; +class_item: // ==IEEE: class_item + class_property { $$ = $1; } + | class_method { $$ = $1; } + | class_constraint { $$ = $1; } + // + | class_declaration + { $$ = nullptr; BBUNSUP($1, "Unsupported: class within class"); } + | timeunits_declaration { $$ = $1; } + //UNSUP covergroup_declaration { $$ = $1; } + // // local_parameter_declaration under parameter_declaration + | parameter_declaration ';' { $$ = $1; } + | ';' { $$ = nullptr; } + // + | error ';' { $$ = nullptr; } + ; -class_method: // ==IEEE: class_method - memberQualListE task_declaration { $$ = $2; $1.applyToNodes($2); } - | memberQualListE function_declaration { $$ = $2; $1.applyToNodes($2); } - | yPURE yVIRTUAL__ETC memberQualListE method_prototype ';' - { $$ = $4; $3.applyToNodes($4); $4->pureVirtual(true); $4->isVirtual(true); } - | yEXTERN memberQualListE method_prototype ';' - { $$ = $3; $2.applyToNodes($3); $3->isExternProto(true); } - // // IEEE: "method_qualifierE class_constructor_declaration" - // // part of function_declaration - | yEXTERN memberQualListE class_constructor_prototype - { $$ = $3; $2.applyToNodes($3); $3->isExternProto(true); } - ; +class_method: // ==IEEE: class_method + memberQualListE task_declaration { $$ = $2; $1.applyToNodes($2); } + | memberQualListE function_declaration { $$ = $2; $1.applyToNodes($2); } + | yPURE yVIRTUAL__ETC memberQualListE method_prototype ';' + { $$ = $4; $3.applyToNodes($4); $4->pureVirtual(true); $4->isVirtual(true); } + | yEXTERN memberQualListE method_prototype ';' + { $$ = $3; $2.applyToNodes($3); $3->isExternProto(true); } + // // IEEE: "method_qualifierE class_constructor_declaration" + // // part of function_declaration + | yEXTERN memberQualListE class_constructor_prototype + { $$ = $3; $2.applyToNodes($3); $3->isExternProto(true); } + ; // IEEE: class_constructor_prototype // See function_declaration -memberQualListE: // Called from class_property for all qualifiers before yVAR - // // Also before method declarations, to prevent grammar conflict - // // Thus both types of qualifiers (method/property) are here - /*empty*/ { $$ = VMemberQualifiers::none(); } - | memberQualList { $$ = $1; } - ; +memberQualListE: // Called from class_property for all qualifiers before yVAR + // // Also before method declarations, to prevent grammar conflict + // // Thus both types of qualifiers (method/property) are here + /*empty*/ { $$ = VMemberQualifiers::none(); } + | memberQualList { $$ = $1; } + ; memberQualList: - memberQualOne { $$ = $1; } - | memberQualList memberQualOne { $$ = VMemberQualifiers::combine($1, $2); } - ; + memberQualOne { $$ = $1; } + | memberQualList memberQualOne { $$ = VMemberQualifiers::combine($1, $2); } + ; -memberQualOne: // IEEE: property_qualifier + method_qualifier - // // Part of method_qualifier and property_qualifier - // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule - yPROTECTED { $$ = VMemberQualifiers::none(); $$.m_protected = true; } - | yLOCAL__ETC { $$ = VMemberQualifiers::none(); $$.m_local = true; } - | ySTATIC__ETC { $$ = VMemberQualifiers::none(); $$.m_static = true; } - // // Part of method_qualifier only - | yVIRTUAL__ETC { $$ = VMemberQualifiers::none(); $$.m_virtual = true; } - // // Part of property_qualifier only - | random_qualifier { $$ = $1; } - // // Part of lifetime, but here as ySTATIC can be in different positions - | yAUTOMATIC { $$ = VMemberQualifiers::none(); $$.m_automatic = true; } - // // Part of data_declaration, but not in data_declarationVarFrontClass - | yCONST__ETC { $$ = VMemberQualifiers::none(); $$.m_const = true; } - ; +memberQualOne: // IEEE: property_qualifier + method_qualifier + // // Part of method_qualifier and property_qualifier + // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule + yPROTECTED { $$ = VMemberQualifiers::none(); $$.m_protected = true; } + | yLOCAL__ETC { $$ = VMemberQualifiers::none(); $$.m_local = true; } + | ySTATIC__ETC { $$ = VMemberQualifiers::none(); $$.m_static = true; } + // // Part of method_qualifier only + | yVIRTUAL__ETC { $$ = VMemberQualifiers::none(); $$.m_virtual = true; } + // // Part of property_qualifier only + | random_qualifier { $$ = $1; } + // // Part of lifetime, but here as ySTATIC can be in different positions + | yAUTOMATIC { $$ = VMemberQualifiers::none(); $$.m_automatic = true; } + // // Part of data_declaration, but not in data_declarationVarFrontClass + | yCONST__ETC { $$ = VMemberQualifiers::none(); $$.m_const = true; } + ; //********************************************************************** // Constraints class_constraint: // ==IEEE: class_constraint - // // IEEE: constraint_declaration - // // UNSUP: We have the unsupported warning on the randomize() call, so don't bother on - // // constraint blocks. When we support randomize we need to make AST nodes for below rules - constraintStaticE yCONSTRAINT idAny constraint_block { $$ = nullptr; /*UNSUP*/ } - // // IEEE: constraint_prototype + constraint_prototype_qualifier - | constraintStaticE yCONSTRAINT idAny ';' { $$ = nullptr; } - | yEXTERN constraintStaticE yCONSTRAINT idAny ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: extern constraint"); } - | yPURE constraintStaticE yCONSTRAINT idAny ';' - { $$ = nullptr; BBUNSUP($1, "Unsupported: pure constraint"); } - ; + // // IEEE: constraint_declaration + // // UNSUP: We have the unsupported warning on the randomize() call, so don't bother on + // // constraint blocks. When we support randomize we need to make AST nodes for below rules + constraintStaticE yCONSTRAINT idAny constraint_block { $$ = nullptr; /*UNSUP*/ } + // // IEEE: constraint_prototype + constraint_prototype_qualifier + | constraintStaticE yCONSTRAINT idAny ';' { $$ = nullptr; } + | yEXTERN constraintStaticE yCONSTRAINT idAny ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: extern constraint"); } + | yPURE constraintStaticE yCONSTRAINT idAny ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: pure constraint"); } + ; constraint_block: // ==IEEE: constraint_block - '{' constraint_block_itemList '}' { $$ = $2; } - ; + '{' constraint_block_itemList '}' { $$ = $2; } + ; constraint_block_itemList: // IEEE: { constraint_block_item } - constraint_block_item { $$ = $1; } - | constraint_block_itemList constraint_block_item { $$ = AstNode::addNextNull($1, $2); } - ; + constraint_block_item { $$ = $1; } + | constraint_block_itemList constraint_block_item { $$ = AstNode::addNextNull($1, $2); } + ; constraint_block_item: // ==IEEE: constraint_block_item - constraint_expression { $$ = $1; } - | ySOLVE solve_before_list yBEFORE solve_before_list ';' - { $$ = nullptr; BBUNSUP($2, "Unsupported: solve before"); } - ; + constraint_expression { $$ = $1; } + | ySOLVE solve_before_list yBEFORE solve_before_list ';' + { $$ = nullptr; BBUNSUP($2, "Unsupported: solve before"); } + ; solve_before_list: // ==IEEE: solve_before_list - constraint_primary { $$ = $1; } - | solve_before_list ',' constraint_primary { $$ = AstNode::addNextNull($1, $3); } - ; + constraint_primary { $$ = $1; } + | solve_before_list ',' constraint_primary { $$ = AstNode::addNextNull($1, $3); } + ; constraint_primary: // ==IEEE: constraint_primary - // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select - exprScope { $$ = $1; } - ; + // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select + exprScope { $$ = $1; } + ; constraint_expressionList: // ==IEEE: { constraint_expression } - constraint_expression { $$ = $1; } - | constraint_expressionList constraint_expression { $$ = AstNode::addNextNull($1, $2); } - ; + constraint_expression { $$ = $1; } + | constraint_expressionList constraint_expression { $$ = AstNode::addNextNull($1, $2); } + ; constraint_expression: // ==IEEE: constraint_expression - expr/*expression_or_dist*/ ';' { $$ = $1; } - // // 1800-2012: - | ySOFT expr/*expression_or_dist*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ } - // // 1800-2012: - // // IEEE: uniqueness_constraint ';' - | yUNIQUE '{' open_range_list '}' { $$ = nullptr; /*UNSUP-no-UVM*/ } - // // IEEE: expr yP_MINUSGT constraint_set - // // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there - // - | yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$ = nullptr; /*UNSUP-UVM*/ } - | yIF '(' expr ')' constraint_set yELSE constraint_set { $$ = nullptr; /*UNSUP-UVM*/ } - // // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009 - | yFOREACH '(' idClassSelForeach ')' constraint_set { $$ = nullptr; /*UNSUP-UVM*/ } - // // soft is 1800-2012 - | yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ } - ; + expr/*expression_or_dist*/ ';' { $$ = $1; } + // // 1800-2012: + | ySOFT expr/*expression_or_dist*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ } + // // 1800-2012: + // // IEEE: uniqueness_constraint ';' + | yUNIQUE '{' open_range_list '}' { $$ = nullptr; /*UNSUP-no-UVM*/ } + // // IEEE: expr yP_MINUSGT constraint_set + // // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there + // + | yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$ = nullptr; /*UNSUP-UVM*/ } + | yIF '(' expr ')' constraint_set yELSE constraint_set { $$ = nullptr; /*UNSUP-UVM*/ } + // // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009 + | yFOREACH '(' idClassSelForeach ')' constraint_set { $$ = nullptr; /*UNSUP-UVM*/ } + // // soft is 1800-2012 + | yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$ = nullptr; /*UNSUP-no-UVM*/ } + ; constraint_set: // ==IEEE: constraint_set - constraint_expression { $$ = $1; } - | '{' constraint_expressionList '}' { $$ = $2; } - ; + constraint_expression { $$ = $1; } + | '{' constraint_expressionList '}' { $$ = $2; } + ; dist_list: // ==IEEE: dist_list - dist_item { $$ = $1; } - | dist_list ',' dist_item { $$ = AstNode::addNextNull($1, $3); } - ; + dist_item { $$ = $1; } + | dist_list ',' dist_item { $$ = AstNode::addNextNull($1, $3); } + ; dist_item: // ==IEEE: dist_item + dist_weight - value_range { $$ = $1; /* Same as := 1 */ } - | value_range yP_COLONEQ expr { $$ = $1; /*UNSUP-no-UVM*/ } - | value_range yP_COLONDIV expr { $$ = $1; /*UNSUP-no-UVM*/ } - ; + value_range { $$ = $1; /* Same as := 1 */ } + | value_range yP_COLONEQ expr { $$ = $1; /*UNSUP-no-UVM*/ } + | value_range yP_COLONDIV expr { $$ = $1; /*UNSUP-no-UVM*/ } + ; //UNSUPextern_constraint_declaration: // ==IEEE: extern_constraint_declaration -//UNSUP constraintStaticE yCONSTRAINT class_scope_id constraint_block { } -//UNSUP ; +//UNSUP constraintStaticE yCONSTRAINT class_scope_id constraint_block { } +//UNSUP ; constraintStaticE: // IEEE: part of extern_constraint_declaration - /* empty */ { $$ = false; } - | ySTATIC__CONSTRAINT { $$ = true; } - ; + /* empty */ { $$ = false; } + | ySTATIC__CONSTRAINT { $$ = true; } + ; //********************************************************************** // Constants -timeNumAdjusted: // Time constant, adjusted to module's time units/precision - yaTIMENUM - { $$ = new AstTimeImport($1, new AstConst($1, AstConst::RealDouble(), $1)); } - ; +timeNumAdjusted: // Time constant, adjusted to module's time units/precision + yaTIMENUM + { $$ = new AstTimeImport($1, new AstConst($1, AstConst::RealDouble(), $1)); } + ; //********************************************************************** // Generic tokens -colon: // Generic colon that isn't making a label (e.g. in a case_item) - ':' { $$ = $1; } - | yP_COLON__BEGIN { $$ = $1; } - | yP_COLON__FORK { $$ = $1; } - ; +colon: // Generic colon that isn't making a label (e.g. in a case_item) + ':' { $$ = $1; } + | yP_COLON__BEGIN { $$ = $1; } + | yP_COLON__FORK { $$ = $1; } + ; //********************************************************************** // VLT Files vltItem: - vltOffFront { V3Config::addIgnore($1, false, "*", 0, 0); } - | vltOffFront yVLT_D_FILE yaSTRING - { V3Config::addIgnore($1, false, *$3, 0, 0); } - | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt()+1); } - | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM - { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); } - | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_MATCH yaSTRING - { if (($1 == V3ErrorCode::I_COVERAGE) || ($1 == V3ErrorCode::I_TRACING)) { - $1->v3error("Argument -match only supported for lint_off"); - } else { - V3Config::addWaiver($1,*$3,*$5); - }} - | vltOnFront { V3Config::addIgnore($1, true, "*", 0, 0); } - | vltOnFront yVLT_D_FILE yaSTRING - { V3Config::addIgnore($1, true, *$3, 0, 0); } - | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt()+1); } - | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM - { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt()+1); } - | vltVarAttrFront vltDModuleE vltDFTaskE vltVarAttrVarE attr_event_controlE - { V3Config::addVarAttr($1, *$2, *$3, *$4, $1, $5); } - | vltInlineFront vltDModuleE vltDFTaskE - { V3Config::addInline($1, *$2, *$3, $1); } - | yVLT_COVERAGE_BLOCK_OFF yVLT_D_FILE yaSTRING - { V3Config::addCoverageBlockOff(*$3, 0); } - | yVLT_COVERAGE_BLOCK_OFF yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addCoverageBlockOff(*$3, $5->toUInt()); } - | yVLT_COVERAGE_BLOCK_OFF yVLT_D_MODULE yaSTRING yVLT_D_BLOCK yaSTRING - { V3Config::addCoverageBlockOff(*$3, *$5); } - | yVLT_FULL_CASE yVLT_D_FILE yaSTRING - { V3Config::addCaseFull(*$3, 0); } - | yVLT_FULL_CASE yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addCaseFull(*$3, $5->toUInt()); } - | yVLT_HIER_BLOCK vltDModuleE - { V3Config::addModulePragma(*$2, VPragmaType::HIER_BLOCK); } - | yVLT_PARALLEL_CASE yVLT_D_FILE yaSTRING - { V3Config::addCaseParallel(*$3, 0); } - | yVLT_PARALLEL_CASE yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM - { V3Config::addCaseParallel(*$3, $5->toUInt()); } - | yVLT_PROFILE_DATA yVLT_D_MODEL yaSTRING yVLT_D_MTASK yaSTRING yVLT_D_COST yaINTNUM - { V3Config::addProfileData($1, *$3, *$5, $7->toUQuad()); } - ; + vltOffFront { V3Config::addIgnore($1, false, "*", 0, 0); } + | vltOffFront yVLT_D_FILE yaSTRING + { V3Config::addIgnore($1, false, *$3, 0, 0); } + | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM + { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt()+1); } + | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM + { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); } + | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_MATCH yaSTRING + { if (($1 == V3ErrorCode::I_COVERAGE) || ($1 == V3ErrorCode::I_TRACING)) { + $1->v3error("Argument -match only supported for lint_off"); + } else { + V3Config::addWaiver($1,*$3,*$5); + }} + | vltOnFront { V3Config::addIgnore($1, true, "*", 0, 0); } + | vltOnFront yVLT_D_FILE yaSTRING + { V3Config::addIgnore($1, true, *$3, 0, 0); } + | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM + { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt()+1); } + | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM + { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt()+1); } + | vltVarAttrFront vltDModuleE vltDFTaskE vltVarAttrVarE attr_event_controlE + { V3Config::addVarAttr($1, *$2, *$3, *$4, $1, $5); } + | vltInlineFront vltDModuleE vltDFTaskE + { V3Config::addInline($1, *$2, *$3, $1); } + | yVLT_COVERAGE_BLOCK_OFF yVLT_D_FILE yaSTRING + { V3Config::addCoverageBlockOff(*$3, 0); } + | yVLT_COVERAGE_BLOCK_OFF yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM + { V3Config::addCoverageBlockOff(*$3, $5->toUInt()); } + | yVLT_COVERAGE_BLOCK_OFF yVLT_D_MODULE yaSTRING yVLT_D_BLOCK yaSTRING + { V3Config::addCoverageBlockOff(*$3, *$5); } + | yVLT_FULL_CASE yVLT_D_FILE yaSTRING + { V3Config::addCaseFull(*$3, 0); } + | yVLT_FULL_CASE yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM + { V3Config::addCaseFull(*$3, $5->toUInt()); } + | yVLT_HIER_BLOCK vltDModuleE + { V3Config::addModulePragma(*$2, VPragmaType::HIER_BLOCK); } + | yVLT_PARALLEL_CASE yVLT_D_FILE yaSTRING + { V3Config::addCaseParallel(*$3, 0); } + | yVLT_PARALLEL_CASE yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM + { V3Config::addCaseParallel(*$3, $5->toUInt()); } + | yVLT_PROFILE_DATA yVLT_D_MODEL yaSTRING yVLT_D_MTASK yaSTRING yVLT_D_COST yaINTNUM + { V3Config::addProfileData($1, *$3, *$5, $7->toUQuad()); } + ; vltOffFront: - yVLT_COVERAGE_OFF { $$ = V3ErrorCode::I_COVERAGE; } - | yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; } - | yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; } - | yVLT_LINT_OFF yVLT_D_RULE idAny - { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } - ; + yVLT_COVERAGE_OFF { $$ = V3ErrorCode::I_COVERAGE; } + | yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; } + | yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; } + | yVLT_LINT_OFF yVLT_D_RULE idAny + { $$ = V3ErrorCode((*$3).c_str()); + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } + ; vltOnFront: - yVLT_COVERAGE_ON { $$ = V3ErrorCode::I_COVERAGE; } - | yVLT_TRACING_ON { $$ = V3ErrorCode::I_TRACING; } - | yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; } - | yVLT_LINT_ON yVLT_D_RULE idAny - { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } - ; + yVLT_COVERAGE_ON { $$ = V3ErrorCode::I_COVERAGE; } + | yVLT_TRACING_ON { $$ = V3ErrorCode::I_TRACING; } + | yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; } + | yVLT_LINT_ON yVLT_D_RULE idAny + { $$ = V3ErrorCode((*$3).c_str()); + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } + ; vltDModuleE: - /* empty */ { static string unit = "__024unit"; $$ = &unit; } - | yVLT_D_MODULE str { $$ = $2; } - ; + /* empty */ { static string unit = "__024unit"; $$ = &unit; } + | yVLT_D_MODULE str { $$ = $2; } + ; vltDFTaskE: - /* empty */ { static string empty; $$ = ∅ } - | yVLT_D_FUNCTION str { $$ = $2; } - | yVLT_D_TASK str { $$ = $2; } - ; + /* empty */ { static string empty; $$ = ∅ } + | yVLT_D_FUNCTION str { $$ = $2; } + | yVLT_D_TASK str { $$ = $2; } + ; vltInlineFront: - yVLT_INLINE { $$ = true; } - | yVLT_NO_INLINE { $$ = false; } - ; + yVLT_INLINE { $$ = true; } + | yVLT_NO_INLINE { $$ = false; } + ; vltVarAttrVarE: - /* empty */ { static string empty; $$ = ∅ } - | yVLT_D_VAR str { $$ = $2; } - ; + /* empty */ { static string empty; $$ = ∅ } + | yVLT_D_VAR str { $$ = $2; } + ; vltVarAttrFront: - yVLT_CLOCK_ENABLE { $$ = VAttrType::VAR_CLOCK_ENABLE; } - | yVLT_CLOCKER { $$ = VAttrType::VAR_CLOCKER; } - | yVLT_ISOLATE_ASSIGNMENTS { $$ = VAttrType::VAR_ISOLATE_ASSIGNMENTS; } - | yVLT_NO_CLOCKER { $$ = VAttrType::VAR_NO_CLOCKER; } - | yVLT_FORCEABLE { $$ = VAttrType::VAR_FORCEABLE; } - | yVLT_PUBLIC { $$ = VAttrType::VAR_PUBLIC; v3Global.dpi(true); } - | yVLT_PUBLIC_FLAT { $$ = VAttrType::VAR_PUBLIC_FLAT; v3Global.dpi(true); } - | yVLT_PUBLIC_FLAT_RD { $$ = VAttrType::VAR_PUBLIC_FLAT_RD; v3Global.dpi(true); } - | yVLT_PUBLIC_FLAT_RW { $$ = VAttrType::VAR_PUBLIC_FLAT_RW; v3Global.dpi(true); } - | yVLT_SC_BV { $$ = VAttrType::VAR_SC_BV; } - | yVLT_SFORMAT { $$ = VAttrType::VAR_SFORMAT; } - | yVLT_SPLIT_VAR { $$ = VAttrType::VAR_SPLIT_VAR; } - ; + yVLT_CLOCK_ENABLE { $$ = VAttrType::VAR_CLOCK_ENABLE; } + | yVLT_CLOCKER { $$ = VAttrType::VAR_CLOCKER; } + | yVLT_ISOLATE_ASSIGNMENTS { $$ = VAttrType::VAR_ISOLATE_ASSIGNMENTS; } + | yVLT_NO_CLOCKER { $$ = VAttrType::VAR_NO_CLOCKER; } + | yVLT_FORCEABLE { $$ = VAttrType::VAR_FORCEABLE; } + | yVLT_PUBLIC { $$ = VAttrType::VAR_PUBLIC; v3Global.dpi(true); } + | yVLT_PUBLIC_FLAT { $$ = VAttrType::VAR_PUBLIC_FLAT; v3Global.dpi(true); } + | yVLT_PUBLIC_FLAT_RD { $$ = VAttrType::VAR_PUBLIC_FLAT_RD; v3Global.dpi(true); } + | yVLT_PUBLIC_FLAT_RW { $$ = VAttrType::VAR_PUBLIC_FLAT_RW; v3Global.dpi(true); } + | yVLT_SC_BV { $$ = VAttrType::VAR_SC_BV; } + | yVLT_SFORMAT { $$ = VAttrType::VAR_SFORMAT; } + | yVLT_SPLIT_VAR { $$ = VAttrType::VAR_SPLIT_VAR; } + ; //********************************************************************** %% From 9583f152eeb0f65bca673f18619bf7004ebdc943 Mon Sep 17 00:00:00 2001 From: HungMingWu Date: Mon, 9 May 2022 08:49:13 +0800 Subject: [PATCH 05/68] Fix compile error when enable VL_LEAK_CHECKS (#3411). Signed-off-by: HungMingWu --- src/V3Ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 1bd2cc14e..a48f701e6 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -758,7 +758,7 @@ void AstNode::deleteTree() { #ifdef VL_LEAK_CHECKS void* AstNode::operator new(size_t size) { // Optimization note: Aligning to cache line is a loss, due to lost packing - const AstNode* const objp = static_cast(::operator new(size)); + AstNode* const objp = static_cast(::operator new(size)); V3Broken::addNewed(objp); return objp; } From 3d045c3aee5d675da310d2e5ff1bd30e91b1ac59 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 9 May 2022 00:37:51 -0400 Subject: [PATCH 06/68] Internals: Cleanup some verilog.y formatting. No functional change. --- src/verilog.y | 193 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 65 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 21e8a0956..2d4762799 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1134,7 +1134,8 @@ package_import_itemObj: // IEEE: part of package_import_item ; package_export_declaration: // IEEE: package_export_declaration - yEXPORT '*' yP_COLONCOLON '*' ';' { $$ = new AstPackageExportStarStar($2); SYMP->exportStarStar($1); } + yEXPORT '*' yP_COLONCOLON '*' ';' + { $$ = new AstPackageExportStarStar{$2}; SYMP->exportStarStar($1); } | yEXPORT package_export_itemList ';' { $$ = $2; } ; @@ -1322,23 +1323,31 @@ port: // ==IEEE: port { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } // // // IEEE: ansi_port_declaration, with [port_direction] removed - // // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ] + // // IEEE: [ net_port_header | interface_port_header ] + // // port_identifier { unpacked_dimension } [ '=' constant_expression ] // // IEEE: [ net_port_header | variable_port_header ] '.' port_identifier '(' [ expression ] ')' - // // IEEE: [ variable_port_header ] port_identifier { variable_dimension } [ '=' constant_expression ] + // // IEEE: [ variable_port_header ] port_identifier + // // { variable_dimension } [ '=' constant_expression ] // // Substitute net_port_header = [ port_direction ] net_port_type // // Substitute variable_port_header = [ port_direction ] variable_port_type // // Substitute net_port_type = [ net_type ] data_type_or_implicit // // Substitute variable_port_type = var_data_type // // Substitute var_data_type = data_type | yVAR data_type_or_implicit - // // [ [ port_direction ] net_port_type | interface_port_header ] port_identifier { unpacked_dimension } - // // [ [ port_direction ] var_data_type ] port_identifier variable_dimensionListE [ '=' constant_expression ] - // // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] '.' port_identifier '(' [ expression ] ')' + // // [ [ port_direction ] net_port_type | interface_port_header] + // // port_identifier { unpacked_dimension } + // // [ [ port_direction ] var_data_type ] + // // port_identifier variable_dimensionListE [ '=' constant_expression ] + // // [ [ port_direction ] net_port_type | [ port_direction ] var_data_type ] + // // '.' port_identifier '(' [ expression ] ')' // // // Remove optional '[...] id' is in portAssignment // // Remove optional '[port_direction]' is in port - // // net_port_type | interface_port_header port_identifier { unpacked_dimension } - // // net_port_type | interface_port_header port_identifier { unpacked_dimension } - // // var_data_type port_identifier variable_dimensionListE [ '=' constExpr ] + // // net_port_type | interface_port_header + // // port_identifier { unpacked_dimension } + // // net_port_type | interface_port_header + // // port_identifier { unpacked_dimension } + // // var_data_type + // // port_identifier variable_dimensionListE [ '=' constExpr ] // // net_port_type | [ port_direction ] var_data_type '.' port_identifier '(' [ expr ] ')' // // Expand implicit_type // @@ -1364,9 +1373,12 @@ port: // ==IEEE: port | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } | portDirNetE signing portSig variable_dimensionListE sigAttrListE - { $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); $$->addNextNull(VARDONEP($$,$4,$5)); } + { $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); + $$->addNextNull(VARDONEP($$, $4, $5)); } | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); } + { $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange( + new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2}, $3, true)); + $$->addNextNull(VARDONEP($$, $5, $6)); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE { $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } // @@ -1692,9 +1704,13 @@ net_dataTypeE: // // Otherwise #(...) can't be determined to be a delay or parameters // // Submit this as a footnote to the committee var_data_type { $$ = $1; } - | signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); } // not implicit - | signing { $$ = new AstBasicDType($1, LOGIC, $1); } // not implicit - | /*implicit*/ delayE { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit + | signingE rangeList delayE + { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC, $1}, + $2, true); } // not implicit + | signing + { $$ = new AstBasicDType{$1, LOGIC, $1}; } // not implicit + | /*implicit*/ delayE + { $$ = new AstBasicDType{CRELINE(), LOGIC}; } // not implicit ; net_type: // ==IEEE: net_type @@ -1855,10 +1871,15 @@ data_typeBasic: // IEEE: part of data_type data_typeNoRef: // ==IEEE: data_type, excluding class_type etc references data_typeBasic { $$ = $1; } - | struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->s_modTypeImpNum++), - SYMP,VFlagChildDType(),$1),$2,true); } - | enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->s_modTypeImpNum++), - SYMP,VFlagChildDType(),$1); } + | struct_unionDecl packed_dimensionListE + { $$ = GRAMMARP->createArray( + new AstDefImplicitDType{$1->fileline(), + "__typeimpsu" + cvtToStr(GRAMMARP->s_modTypeImpNum++), + SYMP, VFlagChildDType{}, $1}, $2, true); } + | enumDecl + { $$ = new AstDefImplicitDType{$1->fileline(), + "__typeimpenum" + cvtToStr(GRAMMARP->s_modTypeImpNum++), + SYMP, VFlagChildDType{}, $1}; } | ySTRING { $$ = new AstBasicDType($1,VBasicDTypeKwd::STRING); } | yCHANDLE { $$ = new AstBasicDType($1,VBasicDTypeKwd::CHANDLE); } | yEVENT { $$ = new AstBasicDType($1,VBasicDTypeKwd::EVENTVALUE); } @@ -1926,9 +1947,11 @@ list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_d ; member_decl_assignment: // Derived from IEEE: variable_decl_assignment - // // At present we allow only packed structures/unions. So this is different from variable_decl_assignment + // // At present we allow only packed structures/unions. + // // So this is different from variable_decl_assignment id variable_dimensionListE - { if ($2) $2->v3warn(UNPACKED, "Unsupported: Unpacked array in packed struct/union (struct/union converted to unpacked)"); + { if ($2) $2->v3warn(UNPACKED, "Unsupported: Unpacked array in packed struct/union" + " (struct/union converted to unpacked)"); $$ = new AstMemberDType($1, *$1, VFlagChildDType(), AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true)); PARSEP->tagNodep($$); @@ -2046,19 +2069,25 @@ packedSigningE: // IEEE: part of data_type enumDecl: - yENUM enum_base_typeE '{' enum_nameList '}' { $$ = new AstEnumDType($1,VFlagChildDType(),$2,$4); } + yENUM enum_base_typeE '{' enum_nameList '}' + { $$ = new AstEnumDType{$1, VFlagChildDType{}, $2, $4}; } ; enum_base_typeE: // IEEE: enum_base_type - /* empty */ { $$ = new AstBasicDType(CRELINE(), VBasicDTypeKwd::INT); } + /* empty */ + { $$ = new AstBasicDType(CRELINE(), VBasicDTypeKwd::INT); } // // Not in spec, but obviously "enum [1:0]" should work // // implicit_type expanded, without empty // // Note enum base types are always packed data types - | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } - | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } + | signingE rangeList + { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC_IMPLICIT, $1}, $2, true); } + | signing + { $$ = new AstBasicDType{$1, LOGIC_IMPLICIT, $1}; } // - | integer_atom_type signingE { $1->setSignedState($2); $$ = $1; } - | integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); } + | integer_atom_type signingE + { $1->setSignedState($2); $$ = $1; } + | integer_vector_type signingE rangeListE + { $1->setSignedState($2); $$ = GRAMMARP->addRange($1, $3, true); } // // below can be idAny or yaID__aTYPE // // IEEE requires a type, though no shift conflict if idAny // // IEEE: type_identifier [ packed_dimension ] @@ -2076,13 +2105,17 @@ enum_nameList: ; enum_name_declaration: // ==IEEE: enum_name_declaration - idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($1, *$1, $2, $3); } + idAny/*enum_identifier*/ enumNameRangeE enumNameStartE + { $$ = new AstEnumItem($1, *$1, $2, $3); } ; enumNameRangeE: // IEEE: second part of enum_name_declaration - /* empty */ { $$ = nullptr; } - | '[' intnumAsConst ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstConst($1, $2->toSInt()-1)); } - | '[' intnumAsConst ':' intnumAsConst ']' { $$ = new AstRange($1,$2,$4); } + /* empty */ + { $$ = nullptr; } + | '[' intnumAsConst ']' + { $$ = new AstRange{$1, new AstConst($1, 0), new AstConst($1, $2->toSInt() - 1)}; } + | '[' intnumAsConst ':' intnumAsConst ']' + { $$ = new AstRange{$1, $2, $4}; } ; enumNameStartE: // IEEE: third part of enum_name_declaration @@ -2091,7 +2124,7 @@ enumNameStartE: // IEEE: third part of enum_name_declaration ; intnumAsConst: - yaINTNUM { $$ = new AstConst($1,*$1); } + yaINTNUM { $$ = new AstConst{$1, *$1}; } ; //************************************************ @@ -2122,12 +2155,14 @@ class_property: // ==IEEE: class_property, which is {property_qu ; data_declarationVar: // IEEE: part of data_declaration - // // The first declaration has complications between assuming what's the type vs ID declaring + // // The first declaration has complications between assuming what's + // // the type vs ID declaring data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; } ; data_declarationVarClass: // IEEE: part of data_declaration (for class_property) - // // The first declaration has complications between assuming what's the type vs ID declaring + // // The first declaration has complications between assuming what's + // // the type vs ID declaring data_declarationVarFrontClass list_of_variable_decl_assignments ';' { $$ = $2; } ; @@ -2174,8 +2209,9 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_pro yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARLIFE($2); VARDTYPE($3); } | yVAR lifetimeE { VARRESET_NONLIST(VAR); VARLIFE($2); } | yVAR lifetimeE signingE rangeList - { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($1, LOGIC_IMPLICIT, $3), $4,true)); - VARLIFE($2); } + { /*VARRESET-in-ddVar*/ + VARDTYPE(GRAMMARP->addRange(new AstBasicDType{$1, LOGIC_IMPLICIT, $3}, $4, true)); + VARLIFE($2); } // // // Expanded: "constE lifetimeE data_type" | data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); } @@ -2193,9 +2229,12 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_pro implicit_typeE: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration - /* empty */ { $$ = nullptr; } - | signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); } - | signing { $$ = new AstBasicDType($1, LOGIC_IMPLICIT, $1); } + /* empty */ + { $$ = nullptr; } + | signingE rangeList + { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC_IMPLICIT, $1}, $2, true); } + | signing + { $$ = new AstBasicDType{$1, LOGIC_IMPLICIT, $1}; } ; //UNSUPassertion_variable_declaration: // IEEE: assertion_variable_declaration @@ -2236,7 +2275,8 @@ type_declaration: // ==IEEE: type_declaration // // Alternative is use of idAny below, but this will cause conflicts with ablve | yTYPEDEF idType ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } // // Combines into above "data_type id" rule - // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned + // // Verilator: Not important what it is in the AST, just need + // // to make sure the yaID__aTYPE gets returned | yTYPEDEF id ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } | yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } | yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } @@ -2313,7 +2353,8 @@ module_or_generate_item: // ==IEEE: module_or_generate_item // // not here, see etcInst in module_common_item // // We joined udp & module definitions, so this goes here | combinational_body { $$ = $1; } - // // This module_common_item shared with interface_or_generate_item:module_common_item + // // This module_common_item shared with + // // interface_or_generate_item:module_common_item | module_common_item { $$ = $1; } ; @@ -2372,8 +2413,10 @@ aliasEqList: // IEEE: part of net_alias ; bind_directive: // ==IEEE: bind_directive + bind_target_scope - // // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation - // // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier + // // ';' - Note IEEE grammar is wrong, includes extra ';' + // // - it's already in module_instantiation + // // We merged the rules - id may be a bind_target_instance or + // // module_identifier or interface_identifier yBIND bind_target_instance bind_instantiation { $$ = new AstBind($2, *$2, $3); } | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation { $$ = nullptr; BBUNSUP($1, "Unsupported: Bind with instance list"); } @@ -2535,10 +2578,18 @@ genvar_iteration: // ==IEEE: genvar_iteration | varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); } // // inc_or_dec_operator // When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeMathStmt? - | yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } - | yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true), new AstConst($1, AstConst::StringToParse(), "'b1"))); } - | varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } - | varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true), new AstConst($2, AstConst::StringToParse(), "'b1"))); } + | yP_PLUSPLUS varRefBase + { $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTree(true), + new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } + | yP_MINUSMINUS varRefBase + { $$ = new AstAssign{$1, $2, new AstSub{$1, $2->cloneTree(true), + new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; } + | varRefBase yP_PLUSPLUS + { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), + new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } + | varRefBase yP_MINUSMINUS + { $$ = new AstAssign{$2, $1, new AstSub{$2, $1->cloneTree(true), + new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } ; case_generate_itemListE: // IEEE: [{ case_generate_itemList }] @@ -2625,10 +2676,13 @@ netSigList: // IEEE: list_of_port_identifiers ; netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers - netId sigAttrListE { $$ = VARDONEA($1,*$1, nullptr, $2); } - | netId sigAttrListE '=' expr { $$ = VARDONEA($1,*$1, nullptr, $2); - $$->addNext(new AstAssignW($3, new AstVarRef($1, *$1, VAccess::WRITE), $4)); } - | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } + netId sigAttrListE + { $$ = VARDONEA($1,*$1, nullptr, $2); } + | netId sigAttrListE '=' expr + { $$ = VARDONEA($1, *$1, nullptr, $2); + $$->addNext(new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}); } + | netId variable_dimensionList sigAttrListE + { $$ = VARDONEA($1,*$1, $2, $3); } ; netId: @@ -2650,7 +2704,7 @@ sigAttr: yVL_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCKER); } | yVL_NO_CLOCKER { $$ = new AstAttrOf($1,VAttrType::VAR_NO_CLOCKER); } | yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,VAttrType::VAR_CLOCK_ENABLE); } - | yVL_FORCEABLE { $$ = new AstAttrOf($1,VAttrType::VAR_FORCEABLE); } + | yVL_FORCEABLE { $$ = new AstAttrOf($1,VAttrType::VAR_FORCEABLE); } | yVL_PUBLIC { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC); v3Global.dpi(true); } | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); } | yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,VAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); } @@ -2823,8 +2877,10 @@ instRangeList: ; instRange: - '[' constExpr ']' { $$ = new AstRange($1, new AstConst($1, 0), new AstSub($1, $2, new AstConst($1, 1))); } - | '[' constExpr ':' constExpr ']' { $$ = new AstRange($1,$2,$4); } + '[' constExpr ']' + { $$ = new AstRange{$1, new AstConst{$1, 0}, new AstSub{$1, $2, new AstConst{$1, 1}}}; } + | '[' constExpr ':' constExpr ']' + { $$ = new AstRange{$1, $2, $4}; } ; cellparamList: @@ -2908,7 +2964,8 @@ event_control: // ==IEEE: event_control | '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */ // // IEEE: sequence_instance // // sequence_instance without parens matches idClassSel above. - // // Ambiguity: "'@' sequence (-for-sequence" versus expr:delay_or_event_controlE "'@' id (-for-expr + // // Ambiguity: "'@' sequence (-for-sequence" versus + // // expr:delay_or_event_controlE "'@' id (-for-expr // // For now we avoid this, as it's very unlikely someone would mix // // 1995 delay with a sequence with parameters. // // Alternatively split this out of event_control, and delay_or_event_controlE @@ -3226,15 +3283,16 @@ statement_item: // IEEE: statement_item statementFor: // IEEE: part of statement yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1, "", $3, false, true); - $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } + { $$ = new AstBegin{$1, "", $3, false, true}; + $$->addStmtsp(new AstWhile{$1, $4, $8, $6}); } | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1, "", $3, false, true); - $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::BitTrue()), $7, $5)); } + { $$ = new AstBegin{$1, "", $3, false, true}; + $$->addStmtsp(new AstWhile{$1, new AstConst{$1, AstConst::BitTrue()}, $7, $5}); } ; statementVerilatorPragmas: - yVL_COVERAGE_BLOCK_OFF { $$ = new AstPragma($1,VPragmaType::COVERAGE_BLOCK_OFF); } + yVL_COVERAGE_BLOCK_OFF + { $$ = new AstPragma{$1, VPragmaType::COVERAGE_BLOCK_OFF}; } ; //UNSUPoperator_assignment: // IEEE: operator_assignment @@ -3443,9 +3501,11 @@ patternKey: // IEEE: merge structure_pattern_key, array_patt //UNSUP simple_type { $1->v3error("Unsupported: '{} with data type as key"); $$ = $1; } // // simple_type reference looks like constExpr // // Verilator: - // // The above expressions cause problems because "foo" may be a constant identifier - // // (if array) or a reference to the "foo"member (if structure) - // // So for now we only allow a true constant number, or a identifier which we treat as a structure member name + // // The above expressions cause problems because "foo" may be + // // a constant identifier (if array) or a reference to the + // // "foo"member (if structure) + // // So for now we only allow a true constant number, or an + // // identifier which we treat as a structure member name yaINTNUM { $$ = new AstConst($1,*$1); } | yaFLOATNUM { $$ = new AstConst($1,AstConst::RealDouble(),$1); } | id { $$ = new AstText($1,*$1); } @@ -5490,7 +5550,8 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regexps j // // IEEE: "property_instance" // // Looks just like a function/method call // - // // Note "clocking_event pexpr" overlaps property_statement_spec: clocking_event property_statement + // // Note "clocking_event pexpr" overlaps + // // property_statement_spec: clocking_event property_statement // // // Include property_specDisable to match property_spec rule //UNSUP clocking_event yDISABLE yIFF '(' expr ')' pexpr %prec prSEQ_CLOCKING { } @@ -5519,7 +5580,8 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regexps j //UNSUP // //UNSUP // // IEEE: "sequence_instance [ sequence_abbrev ]" //UNSUP // // version without sequence_abbrev looks just like normal function call -//UNSUP // // version w/sequence_abbrev matches above; expression_or_dist:expr:func boolean_abbrev:sequence_abbrev +//UNSUP // // version w/sequence_abbrev matches above; +//UNSUP // // expression_or_dist:expr:func boolean_abbrev:sequence_abbrev //UNSUP // //UNSUP // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] //UNSUP // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] @@ -6313,7 +6375,8 @@ solve_before_list: // ==IEEE: solve_before_list ; constraint_primary: // ==IEEE: constraint_primary - // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select + // // exprScope more general than: + // // [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select exprScope { $$ = $1; } ; From bdfdc737a0fb46ac1320c4c9be9899c537527246 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 11 May 2022 00:47:52 -0400 Subject: [PATCH 07/68] Internals: Cleanup V3Config. No functional change intended. --- src/V3Config.cpp | 28 +++++++++++----------------- src/V3Config.h | 4 ++-- src/verilog.y | 6 ++++-- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/V3Config.cpp b/src/V3Config.cpp index b8128eaa9..8ffaa21d6 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -44,13 +44,8 @@ public: /// Update into maps from other void update(const V3ConfigWildcardResolver& other) { - typename Map::const_iterator it; - for (it = other.m_mapResolved.begin(); it != other.m_mapResolved.end(); ++it) { - m_mapResolved[it->first].update(it->second); - } - for (it = other.m_mapWildcard.begin(); it != other.m_mapWildcard.end(); ++it) { - m_mapWildcard[it->first].update(it->second); - } + for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second); + for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second); } // Access and create a (wildcard) entity @@ -68,12 +63,12 @@ public: // Cannot be resolved, create if matched // Update this entity with all matches in the wildcards - for (it = m_mapWildcard.begin(); it != m_mapWildcard.end(); ++it) { - if (VString::wildmatch(name, it->first)) { + for (const auto& wildent : m_mapWildcard) { + if (VString::wildmatch(name, wildent.first)) { if (!newp) { newp = &m_mapResolved[name]; // Emplace and get pointer } - newp->update(it->second); + newp->update(wildent.second); } } return newp; @@ -198,8 +193,8 @@ public: AstNode* const nodep = new AstPragma(modp->fileline(), type); modp->addStmtp(nodep); } - for (auto it = m_modPragmas.cbegin(); it != m_modPragmas.cend(); ++it) { - AstNode* const nodep = new AstPragma(modp->fileline(), *it); + for (const auto& itr : m_modPragmas) { + AstNode* const nodep = new AstPragma{modp->fileline(), itr}; modp->addStmtp(nodep); } } @@ -354,13 +349,14 @@ class V3ConfigResolver final { m_profileData; // Access to profile_data records FileLine* m_profileFileLine = nullptr; - static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow) V3ConfigResolver() = default; ~V3ConfigResolver() = default; public: - static V3ConfigResolver& s() { return s_singleton; } - + static V3ConfigResolver& s() { + static V3ConfigResolver s_singleton; + return s_singleton; + } V3ConfigModuleResolver& modules() { return m_modules; } V3ConfigFileResolver& files() { return m_files; } @@ -379,8 +375,6 @@ public: FileLine* getProfileDataFileLine() const { return m_profileFileLine; } // Maybe null }; -V3ConfigResolver V3ConfigResolver::s_singleton; - //###################################################################### // V3Config diff --git a/src/V3Config.h b/src/V3Config.h index 750d152fd..add53c11b 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -37,15 +37,15 @@ public: static void addModulePragma(const string& module, VPragmaType pragma); static void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost); - static void addWaiver(V3ErrorCode code, const string& filename, const string& message); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, VAttrType type, AstSenTree* nodep); + static void addWaiver(V3ErrorCode code, const string& filename, const string& message); static void applyCase(AstCase* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); + static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyIgnores(FileLine* filelinep); static void applyModule(AstNodeModule* modulep); - static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp); static uint64_t getProfileData(const string& model, const string& key); diff --git a/src/verilog.y b/src/verilog.y index 2d4762799..bca9397e1 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -6450,7 +6450,8 @@ colon: // Generic colon that isn't making a label (e.g. vltItem: - vltOffFront { V3Config::addIgnore($1, false, "*", 0, 0); } + vltOffFront + { V3Config::addIgnore($1, false, "*", 0, 0); } | vltOffFront yVLT_D_FILE yaSTRING { V3Config::addIgnore($1, false, *$3, 0, 0); } | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM @@ -6463,7 +6464,8 @@ vltItem: } else { V3Config::addWaiver($1,*$3,*$5); }} - | vltOnFront { V3Config::addIgnore($1, true, "*", 0, 0); } + | vltOnFront + { V3Config::addIgnore($1, true, "*", 0, 0); } | vltOnFront yVLT_D_FILE yaSTRING { V3Config::addIgnore($1, true, *$3, 0, 0); } | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM From cddbe4642fb4cc1f9bf705636e0e18030dfe1d38 Mon Sep 17 00:00:00 2001 From: Martin Stadler Date: Thu, 12 May 2022 03:33:05 +0200 Subject: [PATCH 08/68] Fix cmake rules to support higher-level targest (#3377) (#3386). Don't add linker flags as generator expression to support linking `TARGET` to higher-level targets in a top-level CMakeLists.txt file. --- docs/CONTRIBUTORS | 1 + verilator-config.cmake.in | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index d4dd640f7..8079639e2 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -71,6 +71,7 @@ Markus Krause Marlon James Marshal Qiao Martin Schmidt +Martin Stadler Matthew Ballance Michael Killough Michaël Lefebvre diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index f408721c4..7573d29ae 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -334,9 +334,14 @@ function(verilate TARGET) target_link_libraries(${TARGET} PUBLIC ${${VERILATE_PREFIX}_USER_LDLIBS} - "$<$>:${VERILATOR_MT_CFLAGS}>" ) + if (${VERILATE_PREFIX}_THREADS OR ${VERILATE_PREFIX}_TRACE_THREADS) + target_link_libraries(${TARGET} PUBLIC + ${VERILATOR_MT_CFLAGS} + ) + endif() + target_compile_features(${TARGET} PRIVATE cxx_std_11) endfunction() From 71dedccbbeb11935afe41cf2535e5d78a9d449af Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 May 2022 22:27:38 -0400 Subject: [PATCH 09/68] Support compile time trace signal selection with tracing_on/off (#3323). --- Changes | 1 + docs/guide/exe_verilator.rst | 29 ++++- src/V3Config.cpp | 105 ++++++++++++++++++ src/V3Config.h | 2 + src/V3TraceDecl.cpp | 12 +- src/verilog.l | 2 + src/verilog.y | 26 +++++ test_regress/t/t_trace_scope_vlt.out | 157 +++++++++++++++++++++++++++ test_regress/t/t_trace_scope_vlt.pl | 26 +++++ test_regress/t/t_trace_scope_vlt.v | 42 +++++++ test_regress/t/t_trace_scope_vlt.vlt | 13 +++ test_regress/t/t_vlt_syntax_bad.out | 19 +++- test_regress/t/t_vlt_syntax_bad.vlt | 8 ++ 13 files changed, 431 insertions(+), 11 deletions(-) create mode 100644 test_regress/t/t_trace_scope_vlt.out create mode 100755 test_regress/t/t_trace_scope_vlt.pl create mode 100644 test_regress/t/t_trace_scope_vlt.v create mode 100644 test_regress/t/t_trace_scope_vlt.vlt diff --git a/Changes b/Changes index 1c9166ce4..acf6dcee5 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 4.223 devel **Minor:** +* Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index d129c4a55..53b66550b 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1676,9 +1676,28 @@ The grammar of configuration commands is as follows: .. option:: tracing_off [-file "" [-lines [ - ]]] - Enable/disable waveform tracing for all future signals declared in the - specified filename (or wildcard with '\*' or '?', or all files if - omitted) and range of line numbers (or all lines if omitted). +.. option:: tracing_on [-scope "" [-levels ]] - For tracing_off, instances below any module in the files/ranges - specified will also not be traced. +.. option:: tracing_off [-scope "" [-levels ]] + + Enable/disable waveform tracing for all future signals declared in + all files. + + With -file, enable/disable waveform tracing in the specified + filename (or wildcard with '\*' or '?'), and -line range of line + numbers (or all lines if omitted). + + For tracing_off with -file, instances below any module in the + files/ranges specified will also not be traced. To overcome this + feature, use tracing_on on the upper module declaration and on any + cells, or use the -scope flavor of the command. + + With -scope enable/disable waveform tracing for the specified scope (or + wildcard with '\*' or '?'), and optional --levels number of levels + below. These controls only take place after other file/line/module + based controls have indicated the signal should be traced. + + With -levels (used with -scope), the number of levels below that + scope which the rule is to match, where 0 means all levels below, 1 + the exact level as the provided scope, and 2 meaning an additional + level of children below the provided scope, etc. diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 8ffaa21d6..d27db65ca 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -339,12 +339,109 @@ public: using V3ConfigFileResolver = V3ConfigWildcardResolver; +//###################################################################### +// ScopeTrace tracking + +class V3ConfigScopeTraceEntry final { +public: + const string m_scope; // Scope or regexp to match + const bool m_on = false; // True to enable message + int m_levels = 0; // # levels, 0 = all, 1 = only this, ... + // CONSTRUCTORS + V3ConfigScopeTraceEntry(const string& scope, bool on, int levels) + : m_scope{scope} + , m_on{on} + , m_levels{levels} {} + ~V3ConfigScopeTraceEntry() = default; + bool operator<(const V3ConfigScopeTraceEntry& other) const { + if (m_on < other.m_on) return true; + if (m_on > other.m_on) return false; + if (m_levels < other.m_levels) return true; + if (m_levels > other.m_levels) return false; + return m_scope < other.m_scope; + } +}; + +// Tracks what matches are known to hit against V3ConfigScopeTraceEntries +class V3ConfigScopeTraceEntryMatch final { +public: + const V3ConfigScopeTraceEntry* m_entryp; + const string m_scopepart; + V3ConfigScopeTraceEntryMatch(const V3ConfigScopeTraceEntry* entryp, const string& scopepart) + : m_entryp{entryp} + , m_scopepart{scopepart} {} + bool operator<(const V3ConfigScopeTraceEntryMatch& other) const { + if (m_entryp < other.m_entryp) return true; + if (m_entryp > other.m_entryp) return false; + return m_scopepart < other.m_scopepart; + } +}; + +class V3ConfigScopeTraceResolver final { + std::vector m_entries; // User specified on/offs and levels + std::map m_matchCache; // Matching entries for speed + +public: + void addScopeTraceOn(bool on, const string& scope, int levels) { + UINFO(9, "addScopeTraceOn " << on << " '" << scope << "' " + << " levels=" << levels << endl); + m_entries.emplace_back(V3ConfigScopeTraceEntry{scope, on, levels}); + m_matchCache.clear(); + } + + bool getEntryMatch(const V3ConfigScopeTraceEntry* entp, const string& scopepart) { + // Return if a entry matches the scopepart, with memoization + const auto& key = V3ConfigScopeTraceEntryMatch{entp, scopepart}; + const auto& it = m_matchCache.find(key); + if (it != m_matchCache.end()) return it->second; // Cached + const bool matched = VString::wildmatch(scopepart, entp->m_scope); + m_matchCache.emplace(key, matched); + return matched; + } + + bool getScopeTraceOn(const string& scope) { + // Apply in the order the user provided them, so they can choose on/off preferencing + int maxLevel = 1; + for (const auto& ch : scope) { + if (ch == '.') ++maxLevel; + } + UINFO(9, "getScopeTraceOn " << scope << " maxLevel=" << maxLevel << endl); + + bool enabled = true; + for (const auto& ent : m_entries) { + // We apply shortest match first for each rule component + // (Otherwise the levels would be useless as "--scope top* --levels 1" would + // always match at every scopepart, and we wound't know how to count levels) + int partLevel = 1; + for (string::size_type partEnd = 0; true;) { + partEnd = scope.find('.', partEnd + 1); + if (partEnd == string::npos) partEnd = scope.length(); + const std::string scopepart = scope.substr(0, partEnd); + if (getEntryMatch(&ent, scopepart)) { + const bool levelMatch + = !ent.m_levels || (ent.m_levels >= maxLevel - partLevel); + if (levelMatch) enabled = ent.m_on; + UINFO(9, "getScopeTraceOn-part " << scope << " enabled=" << enabled + << " @ lev=" << partLevel + << (levelMatch ? "[match]" : "[miss]") + << " from scopepart=" << scopepart << endl); + break; + } + if (partEnd == scope.length()) break; + ++partLevel; + } + } + return enabled; + } +}; + //###################################################################### // Resolve modules and files in the design class V3ConfigResolver final { V3ConfigModuleResolver m_modules; // Access to module names (with wildcards) V3ConfigFileResolver m_files; // Access to file names (with wildcards) + V3ConfigScopeTraceResolver m_scopeTraces; // Regexp to trace enables std::unordered_map> m_profileData; // Access to profile_data records FileLine* m_profileFileLine = nullptr; @@ -359,6 +456,7 @@ public: } V3ConfigModuleResolver& modules() { return m_modules; } V3ConfigFileResolver& files() { return m_files; } + V3ConfigScopeTraceResolver& scopeTraces() { return m_scopeTraces; } void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost) { if (!m_profileFileLine) m_profileFileLine = fl; @@ -428,6 +526,10 @@ void V3Config::addProfileData(FileLine* fl, const string& model, const string& k V3ConfigResolver::s().addProfileData(fl, model, key, cost); } +void V3Config::addScopeTraceOn(bool on, const string& scope, int levels) { + V3ConfigResolver::s().scopeTraces().addScopeTraceOn(on, scope, levels); +} + void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& var, VAttrType attr, AstSenTree* sensep) { // Semantics: sensep only if public_flat_rw @@ -534,6 +636,9 @@ uint64_t V3Config::getProfileData(const string& model, const string& key) { FileLine* V3Config::getProfileDataFileLine() { return V3ConfigResolver::s().getProfileDataFileLine(); } +bool V3Config::getScopeTraceOn(const string& scope) { + return V3ConfigResolver::s().scopeTraces().getScopeTraceOn(scope); +} bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) { V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename()); diff --git a/src/V3Config.h b/src/V3Config.h index add53c11b..80d1fb9f2 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -37,6 +37,7 @@ public: static void addModulePragma(const string& module, VPragmaType pragma); static void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost); + static void addScopeTraceOn(bool on, const string& scope, int levels); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, VAttrType type, AstSenTree* nodep); static void addWaiver(V3ErrorCode code, const string& filename, const string& message); @@ -50,6 +51,7 @@ public: static uint64_t getProfileData(const string& model, const string& key); static FileLine* getProfileDataFileLine(); + static bool getScopeTraceOn(const string& scope); static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message); }; diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 15669c0d1..a3f0643e0 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -25,9 +25,10 @@ #include "verilated_trace_defs.h" // For VLT_TRACE_SCOPE_* #include "V3Global.h" -#include "V3TraceDecl.h" +#include "V3Config.h" #include "V3EmitCBase.h" #include "V3Stats.h" +#include "V3TraceDecl.h" #include #include @@ -140,10 +141,13 @@ private: return "Verilator trace_off"; } else if (!nodep->isTrace()) { return "Verilator instance trace_off"; - } else if (!v3Global.opt.traceUnderscore()) { + } else { const string prettyName = varp->prettyName(); - if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore"; - if (prettyName.find("._") != string::npos) return "Inlined leading underscore"; + if (!v3Global.opt.traceUnderscore()) { + if (!prettyName.empty() && prettyName[0] == '_') return "Leading underscore"; + if (prettyName.find("._") != string::npos) return "Inlined leading underscore"; + } + if (!V3Config::getScopeTraceOn(prettyName)) return "Vlt scope trace_off"; } return nullptr; } diff --git a/src/verilog.l b/src/verilog.l index 588da6073..c3eb40f4c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -138,12 +138,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} -?"-cost" { FL; return yVLT_D_COST; } -?"-file" { FL; return yVLT_D_FILE; } -?"-function" { FL; return yVLT_D_FUNCTION; } + -?"-levels" { FL; return yVLT_D_LEVELS; } -?"-lines" { FL; return yVLT_D_LINES; } -?"-match" { FL; return yVLT_D_MATCH; } -?"-model" { FL; return yVLT_D_MODEL; } -?"-module" { FL; return yVLT_D_MODULE; } -?"-mtask" { FL; return yVLT_D_MTASK; } -?"-rule" { FL; return yVLT_D_RULE; } + -?"-scope" { FL; return yVLT_D_SCOPE; } -?"-task" { FL; return yVLT_D_TASK; } -?"-var" { FL; return yVLT_D_VAR; } diff --git a/src/verilog.y b/src/verilog.y index bca9397e1..84c778b45 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -366,12 +366,14 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yVLT_D_COST "--cost" %token yVLT_D_FILE "--file" %token yVLT_D_FUNCTION "--function" +%token yVLT_D_LEVELS "--levels" %token yVLT_D_LINES "--lines" %token yVLT_D_MATCH "--match" %token yVLT_D_MODEL "--model" %token yVLT_D_MODULE "--module" %token yVLT_D_MTASK "--mtask" %token yVLT_D_RULE "--rule" +%token yVLT_D_SCOPE "--scope" %token yVLT_D_TASK "--task" %token yVLT_D_VAR "--var" @@ -6458,6 +6460,18 @@ vltItem: { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $5->toUInt()+1); } | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); } + | vltOffFront yVLT_D_SCOPE yaSTRING + { if ($1 != V3ErrorCode::I_TRACING) { + $1->v3error("Argument -scope only supported for tracing_on/off"); + } else { + V3Config::addScopeTraceOn(false, *$3, 0); + }} + | vltOffFront yVLT_D_SCOPE yaSTRING yVLT_D_LEVELS yaINTNUM + { if ($1 != V3ErrorCode::I_TRACING) { + $1->v3error("Argument -scope only supported for tracing_on/off_off"); + } else { + V3Config::addScopeTraceOn(false, *$3, $5->toUInt()); + }} | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_MATCH yaSTRING { if (($1 == V3ErrorCode::I_COVERAGE) || ($1 == V3ErrorCode::I_TRACING)) { $1->v3error("Argument -match only supported for lint_off"); @@ -6472,6 +6486,18 @@ vltItem: { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $5->toUInt()+1); } | vltOnFront yVLT_D_FILE yaSTRING yVLT_D_LINES yaINTNUM '-' yaINTNUM { V3Config::addIgnore($1, true, *$3, $5->toUInt(), $7->toUInt()+1); } + | vltOnFront yVLT_D_SCOPE yaSTRING + { if ($1 != V3ErrorCode::I_TRACING) { + $1->v3error("Argument -scope only supported for tracing_on/off"); + } else { + V3Config::addScopeTraceOn(true, *$3, 0); + }} + | vltOnFront yVLT_D_SCOPE yaSTRING yVLT_D_LEVELS yaINTNUM + { if ($1 != V3ErrorCode::I_TRACING) { + $1->v3error("Argument -scope only supported for tracing_on/off_off"); + } else { + V3Config::addScopeTraceOn(true, *$3, $5->toUInt()); + }} | vltVarAttrFront vltDModuleE vltDFTaskE vltVarAttrVarE attr_event_controlE { V3Config::addVarAttr($1, *$2, *$3, *$4, $1, $5); } | vltInlineFront vltDModuleE vltDFTaskE diff --git a/test_regress/t/t_trace_scope_vlt.out b/test_regress/t/t_trace_scope_vlt.out new file mode 100644 index 000000000..94628f611 --- /dev/null +++ b/test_regress/t/t_trace_scope_vlt.out @@ -0,0 +1,157 @@ +$version Generated by VerilatedVcd $end +$date Thu May 12 22:13:21 2022 $end +$timescale 1ps $end + + $scope module top $end + $var wire 1 ) clk $end + $scope module t $end + $var wire 1 ) clk $end + $scope module sub1a $end + $var wire 32 * ADD [31:0] $end + $var wire 32 # cyc [31:0] $end + $var wire 32 $ value [31:0] $end + $upscope $end + $scope module sub1b $end + $var wire 32 + ADD [31:0] $end + $var wire 32 # cyc [31:0] $end + $var wire 32 % value [31:0] $end + $scope module sub2a $end + $var wire 32 # cyc [31:0] $end + $var wire 32 & value [31:0] $end + $upscope $end + $scope module sub2b $end + $var wire 32 , ADD [31:0] $end + $var wire 32 # cyc [31:0] $end + $var wire 32 ' value [31:0] $end + $upscope $end + $scope module sub2c $end + $var wire 32 - ADD [31:0] $end + $var wire 32 # cyc [31:0] $end + $var wire 32 ( value [31:0] $end + $upscope $end + $upscope $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +b00000000000000000000000000000000 # +b00000000000000000000000000001010 $ +b00000000000000000000000000010100 % +b00000000000000000000000000010101 & +b00000000000000000000000000010110 ' +b00000000000000000000000000010111 ( +0) +b00000000000000000000000000001010 * +b00000000000000000000000000010100 + +b00000000000000000000000000010110 , +b00000000000000000000000000010111 - +#10 +b00000000000000000000000000000001 # +b00000000000000000000000000001011 $ +b00000000000000000000000000010101 % +b00000000000000000000000000010110 & +b00000000000000000000000000010111 ' +b00000000000000000000000000011000 ( +1) +#15 +0) +#20 +b00000000000000000000000000000010 # +b00000000000000000000000000001100 $ +b00000000000000000000000000010110 % +b00000000000000000000000000010111 & +b00000000000000000000000000011000 ' +b00000000000000000000000000011001 ( +1) +#25 +0) +#30 +b00000000000000000000000000000011 # +b00000000000000000000000000001101 $ +b00000000000000000000000000010111 % +b00000000000000000000000000011000 & +b00000000000000000000000000011001 ' +b00000000000000000000000000011010 ( +1) +#35 +0) +#40 +b00000000000000000000000000000100 # +b00000000000000000000000000001110 $ +b00000000000000000000000000011000 % +b00000000000000000000000000011001 & +b00000000000000000000000000011010 ' +b00000000000000000000000000011011 ( +1) +#45 +0) +#50 +b00000000000000000000000000000101 # +b00000000000000000000000000001111 $ +b00000000000000000000000000011001 % +b00000000000000000000000000011010 & +b00000000000000000000000000011011 ' +b00000000000000000000000000011100 ( +1) +#55 +0) +#60 +b00000000000000000000000000000110 # +b00000000000000000000000000010000 $ +b00000000000000000000000000011010 % +b00000000000000000000000000011011 & +b00000000000000000000000000011100 ' +b00000000000000000000000000011101 ( +1) +#65 +0) +#70 +b00000000000000000000000000000111 # +b00000000000000000000000000010001 $ +b00000000000000000000000000011011 % +b00000000000000000000000000011100 & +b00000000000000000000000000011101 ' +b00000000000000000000000000011110 ( +1) +#75 +0) +#80 +b00000000000000000000000000001000 # +b00000000000000000000000000010010 $ +b00000000000000000000000000011100 % +b00000000000000000000000000011101 & +b00000000000000000000000000011110 ' +b00000000000000000000000000011111 ( +1) +#85 +0) +#90 +b00000000000000000000000000001001 # +b00000000000000000000000000010011 $ +b00000000000000000000000000011101 % +b00000000000000000000000000011110 & +b00000000000000000000000000011111 ' +b00000000000000000000000000100000 ( +1) +#95 +0) +#100 +b00000000000000000000000000001010 # +b00000000000000000000000000010100 $ +b00000000000000000000000000011110 % +b00000000000000000000000000011111 & +b00000000000000000000000000100000 ' +b00000000000000000000000000100001 ( +1) +#105 +0) +#110 +b00000000000000000000000000001011 # +b00000000000000000000000000010101 $ +b00000000000000000000000000011111 % +b00000000000000000000000000100000 & +b00000000000000000000000000100001 ' +b00000000000000000000000000100010 ( +1) diff --git a/test_regress/t/t_trace_scope_vlt.pl b/test_regress/t/t_trace_scope_vlt.pl new file mode 100755 index 000000000..9847c375d --- /dev/null +++ b/test_regress/t/t_trace_scope_vlt.pl @@ -0,0 +1,26 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +top_filename("t/t_trace_scope_vlt.v"); + +compile( + v_flags2 => ["--trace t/t_trace_scope_vlt.vlt"], + ); + +execute( + check_finished => 1, + ); + +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_scope_vlt.v b/test_regress/t/t_trace_scope_vlt.v new file mode 100644 index 000000000..dfeaa16dd --- /dev/null +++ b/test_regress/t/t_trace_scope_vlt.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, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + int cyc; + + sub1 #(10) sub1a (.*); + sub1 #(20) sub1b (.*); + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module sub1 #(parameter int ADD) + (input int cyc); + + wire int value = cyc + ADD; + + sub2 #(ADD + 1) sub2a(.*); + sub2 #(ADD + 2) sub2b(.*); + sub2 #(ADD + 3) sub2c(.*); +endmodule + +module sub2 #(parameter int ADD) + (input int cyc); + + wire int value = cyc + ADD; +endmodule diff --git a/test_regress/t/t_trace_scope_vlt.vlt b/test_regress/t/t_trace_scope_vlt.vlt new file mode 100644 index 000000000..cd7dd85ab --- /dev/null +++ b/test_regress/t/t_trace_scope_vlt.vlt @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +tracing_off -scope "t*" -levels 0 +tracing_on -scope "t.clk" +tracing_on -scope "t.sub1a" -levels 1 +tracing_on -scope "t.sub1b" -levels 2 +tracing_off -scope "*.sub2a.ADD" diff --git a/test_regress/t/t_vlt_syntax_bad.out b/test_regress/t/t_vlt_syntax_bad.out index 7db02e54b..ebe31f2ce 100644 --- a/test_regress/t/t_vlt_syntax_bad.out +++ b/test_regress/t/t_vlt_syntax_bad.out @@ -1,7 +1,22 @@ %Error: t/t_vlt_syntax_bad.vlt:9:20: sensitivity not expected for attribute 9 | public -module "t" @(posedge clk) | ^ -%Error: t/t_vlt_syntax_bad.vlt:10:1: isolate_assignments only applies to signals or functions/tasks - 10 | isolate_assignments -module "t" +%Error: t/t_vlt_syntax_bad.vlt:11:1: isolate_assignments only applies to signals or functions/tasks + 11 | isolate_assignments -module "t" | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_vlt_syntax_bad.vlt:13:1: Argument -match only supported for lint_off + 13 | tracing_off --file "*" -match "nothing" + | ^~~~~~~~~~~ +%Error: t/t_vlt_syntax_bad.vlt:15:1: Argument -scope only supported for tracing_on/off + 15 | lint_off --rule UNOPTFLAT -scope "top*" + | ^~~~~~~~ +%Error: t/t_vlt_syntax_bad.vlt:16:1: Argument -scope only supported for tracing_on/off_off + 16 | lint_off --rule UNOPTFLAT -scope "top*" -levels 0 + | ^~~~~~~~ +%Error: t/t_vlt_syntax_bad.vlt:17:1: Argument -scope only supported for tracing_on/off + 17 | lint_on --rule UNOPTFLAT -scope "top*" + | ^~~~~~~ +%Error: t/t_vlt_syntax_bad.vlt:18:1: Argument -scope only supported for tracing_on/off_off + 18 | lint_on --rule UNOPTFLAT -scope "top*" -levels 0 + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_vlt_syntax_bad.vlt b/test_regress/t/t_vlt_syntax_bad.vlt index df7bda927..7f1d2d092 100644 --- a/test_regress/t/t_vlt_syntax_bad.vlt +++ b/test_regress/t/t_vlt_syntax_bad.vlt @@ -7,4 +7,12 @@ `verilator_config public -module "t" @(posedge clk) +// only signals/functions/tasks isolate_assignments -module "t" +// -match not supported +tracing_off --file "*" -match "nothing" +// -scope not supported +lint_off --rule UNOPTFLAT -scope "top*" +lint_off --rule UNOPTFLAT -scope "top*" -levels 0 +lint_on --rule UNOPTFLAT -scope "top*" +lint_on --rule UNOPTFLAT -scope "top*" -levels 0 From 38438b33733f6acdc008dfa929de9bf86388ea6c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 12 May 2022 23:30:39 -0400 Subject: [PATCH 10/68] Internals: Cleanup some defaults. No functional change. --- include/verilated_cov.h | 4 ++-- src/V3Active.cpp | 2 +- test_regress/t/TestSimulator.h | 2 +- test_regress/t/t_extend_class_c.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/verilated_cov.h b/include/verilated_cov.h index d7bc1b993..c55d32cd8 100644 --- a/include/verilated_cov.h +++ b/include/verilated_cov.h @@ -157,8 +157,8 @@ protected: friend class VerilatedCovImp; // CONSTRUCTORS // Internal: Only made as part of VerilatedCovImp - VerilatedCovContext() {} - virtual ~VerilatedCovContext() {} + VerilatedCovContext() = default; + virtual ~VerilatedCovContext() = default; // METHODS // Internal: access to implementation class diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 9f1758bbb..1b9e9534c 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -317,7 +317,7 @@ public: iterate(nodep); m_graph.latchCheck(nodep, kwd == VAlwaysKwd::ALWAYS_LATCH); } - virtual ~ActiveLatchCheckVisitor() {} + virtual ~ActiveLatchCheckVisitor() = default; }; //###################################################################### diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index ba4735542..2e0098e73 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -40,7 +40,7 @@ public: __LINE__, m_info.product); } } - ~TestSimulator() {} + ~TestSimulator() = default; // METHORS private: static TestSimulator& singleton() { diff --git a/test_regress/t/t_extend_class_c.h b/test_regress/t/t_extend_class_c.h index 87e21d29c..c5e98001b 100644 --- a/test_regress/t/t_extend_class_c.h +++ b/test_regress/t/t_extend_class_c.h @@ -9,8 +9,8 @@ class t_extend_class_c { public: // CONSTRUCTORS - t_extend_class_c() {} - ~t_extend_class_c() {} + t_extend_class_c() = default; + ~t_extend_class_c() = default; // METHODS // This function will be called from a instance created in Verilog inline uint32_t my_math(uint32_t in) { return in + 1; } From f6035447aeebe509936075a28f9915ddb5ab89d0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 13 May 2022 07:21:39 -0400 Subject: [PATCH 11/68] Internals: Use mutable for mutexes. No functional change. --- include/verilated_cov.cpp | 2 +- include/verilated_imp.h | 2 +- include/verilated_profiler.h | 2 +- include/verilated_threads.h | 2 +- include/verilated_trace.h | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index dd559427a..bb1893fd8 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -103,7 +103,7 @@ private: using ItemList = std::deque; // MEMBERS - VerilatedMutex m_mutex; // Protects all members + mutable VerilatedMutex m_mutex; // Protects all members ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); // Unique arbitrary value for values IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); // Unique arbitrary value for keys ItemList m_items VL_GUARDED_BY(m_mutex); // List of all items diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 24456e646..48bd6c42c 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -91,7 +91,7 @@ class VerilatedEvalMsgQueue final { std::atomic m_depth; // Current depth of queue (see comments below) - VerilatedMutex m_mutex; // Mutex protecting queue + mutable VerilatedMutex m_mutex; // Mutex protecting queue VerilatedThreadQueue m_queue VL_GUARDED_BY(m_mutex); // Message queue public: // CONSTRUCTORS diff --git a/include/verilated_profiler.h b/include/verilated_profiler.h index 86bfd3d13..b85bd0eb5 100644 --- a/include/verilated_profiler.h +++ b/include/verilated_profiler.h @@ -155,7 +155,7 @@ class VlExecutionProfiler final { // STATE static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers - VerilatedMutex m_mutex; + mutable VerilatedMutex m_mutex; // Map from thread id to &t_trace of given thread std::map m_traceps VL_GUARDED_BY(m_mutex); diff --git a/include/verilated_threads.h b/include/verilated_threads.h index e69ac8929..257c87162 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -150,7 +150,7 @@ private: }; // MEMBERS - VerilatedMutex m_mutex; + mutable VerilatedMutex m_mutex; std::condition_variable_any m_cv; // Only notify the condition_variable if the worker is waiting bool m_waiting VL_GUARDED_BY(m_mutex) = false; diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 8069174ee..de000e611 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -47,7 +47,7 @@ // A simple synchronized first in first out queue template class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug private: - VerilatedMutex m_mutex; // Protects m_queue + mutable VerilatedMutex m_mutex; // Protects m_queue std::condition_variable_any m_cv; std::deque m_queue VL_GUARDED_BY(m_mutex); @@ -208,7 +208,7 @@ protected: //========================================================================= // Internals available to format specific implementations - VerilatedMutex m_mutex; // Ensure dump() etc only called from single thread + mutable VerilatedMutex m_mutex; // Ensure dump() etc only called from single thread uint32_t nextCode() const { return m_nextCode; } uint32_t numSignals() const { return m_numSignals; } From c2328ef46aff5e4b484fed29606d2ef5c23af918 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 May 2022 16:12:57 -0400 Subject: [PATCH 12/68] Spelling fixes. --- Changes | 16 +++++------ docs/.gitignore | 1 + docs/Makefile | 2 ++ docs/guide/exe_verilator.rst | 4 +-- docs/guide/extensions.rst | 2 +- docs/guide/languages.rst | 2 +- docs/guide/simulating.rst | 2 +- docs/guide/warnings.rst | 2 +- docs/spelling.txt | 53 ++++++++++++++++++++++++++++++++++++ 9 files changed, 70 insertions(+), 14 deletions(-) diff --git a/Changes b/Changes index acf6dcee5..c3958d189 100644 --- a/Changes +++ b/Changes @@ -52,7 +52,7 @@ Verilator 4.220 2022-03-12 * Add VERILATOR_VERSION_INTEGER for determining API (#3343). [Larry Doolittle] * Improve various V3Combine algorithm details (#3328). [Yutetsu TAKATSUKASA] * Improve various V3Order algorithm details. [Geza Lore] -* Fix macOS arm64 build (#3285) (#3291). [Guokai Chen] +* Fix MacOS arm64 build (#3285) (#3291). [Guokai Chen] * Fix signed number operation (#3294) (#3308). [Raynard Qiao] * Fix FST traces to include vector range (#3296) (#3297). [Jamie Iles] * Fix skipping public enum values with four-state values (#3303). @@ -117,7 +117,7 @@ Verilator 4.216 2021-12-05 **Minor:** * Internal code cleanups and improvements. [Geza Lore] -* Improve --thread verilation-time performance. +* Improve --thread Verilation-time performance. * Support task name in $display %m (#3211). [Julie Schwartz] * Make 'bit', 'logic' and 'time' types unsigned by default. [Geza Lore] * Optimize $random concatenates/selects (#3114). @@ -141,7 +141,7 @@ Verilator 4.214 2021-10-17 **Major:** -* Add profile-guided optmization of mtasks (#3150). +* Add profile-guided optimization of mtasks (#3150). **Minor:** @@ -207,7 +207,7 @@ Verilator 4.210 2021-07-07 * Add --prof-c to pass profiling to compiler (#3059). [Alexander Grobman] * Optimize a lot more model variables into function locals (#3027). [Geza Lore] -* Support middle-of-design nested topmodules (#3026). [Dan Petrisko] +* Support middle-of-design nested top modules (#3026). [Dan Petrisko] * Remove deprecated --no-relative-cfuncs option (#3024). [Geza Lore] * Remove deprecated --inhibit-sim option (#3035). [Geza Lore] * Merge const static data globally into a new constant pool (#3013). [Geza Lore] @@ -249,7 +249,7 @@ Verilator 4.204 2021-06-12 * Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] * Fix unused variable warnings (#2991). [Pieter Kapsenberg] * Fix --protect-ids when using SV classes (#2994). [Geza Lore] -* Fix constant function calls with uninit value (#2995). [yanx21] +* Fix constant function calls with uninitialized value (#2995). [yanx21] * Fix Makefiles to support Windows EXEEXT usage (#3008). [Miodrag Milanovic] @@ -287,7 +287,7 @@ Verilator 4.202 2021-04-24 * Fix Cygwin example compile issues (#2856). [Mark Shaw] * Fix select of with index variable (#2880). [Alexander Grobman] * Fix cmake version number to be numeric (#2881). [Yuri Victorovich] -* Fix MinGW not supportting 'localtime_r' (#2882). [HyungKi Jeong] +* Fix MinGW not supporting 'localtime_r' (#2882). [HyungKi Jeong] * Fix cast from packed, typedef'ed interface signal (#2884). [Todd Strader] * Fix VPI package reported as vpiModule (#2885). [Todd Strader] * Fix dumping waveforms to multiple FST files (#2889). [David Metz] @@ -434,7 +434,7 @@ Verilator 4.102 2020-10-15 * Support # as a comment in -f files (#2497). [phantom-killua] * Support 'this' (#2585). [Rafal Kapuscik] * Support defines for FST tracing (#2592). [Markus Krause] -* Support non-overapping implication inside properties (#1292). [Peter Monsson] +* Support non-overlapping implication inside properties (#1292). [Peter Monsson] * Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA] * Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA] * Fix -G dropping public indication (#2561). [Andrew Goessling] @@ -460,7 +460,7 @@ Verilator 4.100 2020-09-07 * Support (with limitations) class extern, class extends, virtual class. * Support $urandom, $urandom_range without stability. * Support assume property. [Peter Monsson] -* Support non-overapping implication inside properties (#1292). [Peter Monsson] +* Support non-overlapping implication inside properties (#1292). [Peter Monsson] * Fix false DECLFILENAME on black-boxed modules (#2430). [Philipp Wagner] * Fix naming of "id : begin" blocks. * Fix class constructor error on assignments to const. diff --git a/docs/.gitignore b/docs/.gitignore index 4e1217655..3a270f863 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -2,3 +2,4 @@ *.html *.pdf _build +guide/spelling.txt diff --git a/docs/Makefile b/docs/Makefile index 7e4a96d69..8a5d1af7d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -35,6 +35,7 @@ default: # Intermediate rules vl-extract: ../bin/verilator ../Changes + ln -sf ../spelling.txt guide/spelling.txt mkdir -p _build/gen $(PYTHON3) bin/vl_sphinx_extract ../bin/verilator sed 's/`/\&96;/g' < ../Changes > _build/gen/Changes @@ -77,6 +78,7 @@ clean mostlyclean distclean maintainer-clean:: rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas rm -f *.tex + rm -f guide/spelling.txt distclean maintainer-clean:: rm -f *.info* *.1 *.html *.pdf $(INFOS) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 53b66550b..00e101ed0 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -847,12 +847,12 @@ Summary: .. option:: --prof-exec - Enable collection of execution trace, that can be convered into a gantt + Enable collection of execution trace, that can be converted into a gantt chart with verilator_gantt See :ref:`Execution Profiling`. .. option:: --prof-pgo - Enable collection of profiling data for profile guided verilation. Currently + Enable collection of profiling data for profile guided Verilation. Currently this is only useful with :vlopt:`--threads`. See :ref:`Thread PGO`. .. option:: --prof-threads diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 491ff18fc..bd5171c52 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -217,7 +217,7 @@ or "`ifdef`"'s may break other tools. :option:`public_flat` signals. To force a marked signal from C++, set the corresponding `__VforceVal` - variable to the desired value, and the `__VforceEn` signal to the bitmask + variable to the desired value, and the `__VforceEn` signal to the bit-mask indicating which bits of the signal to force. To force all bits of the target signal, set `__VforceEn` to all ones. To release the signal (or part thereof), set appropriate bits of the `__VforceEn` signal to zero. diff --git a/docs/guide/languages.rst b/docs/guide/languages.rst index c4c714351..074f91d31 100644 --- a/docs/guide/languages.rst +++ b/docs/guide/languages.rst @@ -343,7 +343,7 @@ Verilator supports the procedural `force` (and corresponding `release`) statement. The behavior of the `force` statement however does not entirely comply with the IEEE 1800 SystemVerilog standard. According to the standard, when a procedural statement of the form `force a = b;` is executed, the -simulation should behave as if from that point onwards, a continuous +simulation should behave as if from that point forwards, a continuous assignment `assign a = b;` have been added to override the drivers of `a`. More specifically: the value of `a` should be updated, whenever the value of `b` changes, all the way until a `release a;` statement is executed. diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index c6c5fba7b..01dd7f844 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -405,7 +405,7 @@ others as they prove beneficial. Thread Profile-Guided Optimization ---------------------------------- -Verilator supports profile-guided optimization (verilation) of multi-threaded +Verilator supports profile-guided optimization (Verilation) of multi-threaded models (Thread PGO) to improve performance. When using multithreading, Verilator computes how long macro tasks take and diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index e122fec90..55206295c 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1506,7 +1506,7 @@ List Of Warnings Error that a construct might be legal according to IEEE but is not currently supported by Verilator. - A typical workaround is to recode the construct into a simpler and more + A typical workaround is to rewrite the construct into a simpler and more common alternative language construct. Alternatively, check if the construct is supported by other tools, and diff --git a/docs/spelling.txt b/docs/spelling.txt index 82c6984da..c0c5e738d 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -2,9 +2,11 @@ ABCp Accellera Affe Aleksander +Alexandre Ami Amir Anastasiadis +Anikin Antonin Antwerpen Arasanipalai @@ -70,6 +72,7 @@ Eda Eddleston Egbert Egil +Ehab Eiler Eivind El @@ -82,6 +85,7 @@ Fabrizio Fekete Ferrandi Flachs +Flavien Foletto Forker Francillon @@ -104,6 +108,7 @@ Goessling Gonnen Goorah Gossner +Graybeal Grobman Gunter Guo @@ -121,6 +126,7 @@ Hornung Hossell Hsu Hyperthreading +Ibrahim Iles Inlines Inout @@ -134,6 +140,7 @@ Jannis Jens Jeras Jiuyang +Joannou Joly Jullien Junji @@ -147,6 +154,7 @@ Kamendje Kandadi Kaplan Karge +Karlsson Katz Katzman Keren @@ -161,6 +169,7 @@ Kolecki Koonce Korteland Koszek +Kouping Kravitz Krolnik Kruse @@ -194,6 +203,7 @@ Mednick Michiels Microsystems Milanovic +Millis MinW Mindspeed Miodrag @@ -224,12 +234,14 @@ Petr Piechotka Piersall Plunkett +Popolon Popov Prabhat Prabhu Prateek Pre Preprocess +Pretet Priyadharshini Pullup Pulver @@ -245,6 +257,7 @@ Rodionov Rolfe Roodselaar Runtime +Ruper Ruud Rystsov STandarD @@ -262,12 +275,15 @@ Shi Shinkarovsky Shirakawa Shuba +Shunyao Slatter SoC Sobhan Sokorac Solaris Solomatnikov +Solt +Southwell Srini Stamness Stephane @@ -286,6 +302,7 @@ SystemVerilog Takatsukasa Tambe Tariq +Tejada Tengstrand Terpstra Thiede @@ -293,8 +310,10 @@ Thierry Thyer Tichelaar Tomov +Tood Topa Tota +Trefor Tresidder Tri Tristate @@ -304,11 +323,13 @@ Ubixum Uints Undefines Unsized +Urbach Uselib Usha Usuario VERILATOR Vasu +Vdeeptemp Vdly Vemumtab Vemuri @@ -351,7 +372,9 @@ Zhang abirkmanis accessor accessors +adrienlemasle agrobman +ahouska al ala andit @@ -372,8 +395,12 @@ backtrace backtraces basename bbox +benchmarking biguint biops +bitOpTree +bitOpTree +bitop bitstoreal blackbox bokke @@ -389,6 +416,7 @@ casez casted cb ccache +ccall cdc ceil celldefine @@ -411,6 +439,8 @@ concat concats config const +constexpr +constpool coredump countbits countones @@ -426,6 +456,7 @@ da dat datadir datafiles +david ddd deassign debugi @@ -434,6 +465,7 @@ defname defparam demangling der +dereference desassign destructor detections @@ -462,6 +494,7 @@ dumpvars dut dx elab +elike elsif endcase endcelldefine @@ -480,15 +513,18 @@ enums env envvar eof +errae erroring et eval +evals exe executables expr extern fanin fasttrace +fauto fbranch fclose fdisplay @@ -503,6 +539,7 @@ filt flto flushCall fopen +forceable foreach fprintf fprofile @@ -521,6 +558,7 @@ funcs fwrite gantt gcc +gcda gdb genblk genvar @@ -552,6 +590,7 @@ incdir includer inferfaces inhibitSim +initarray initializer initializers inits @@ -570,6 +609,7 @@ killua lang lcov ld +leavinel len libext libgoogle @@ -584,6 +624,7 @@ ln loc localparam localparams +localtime logicals longint lsb @@ -618,6 +659,7 @@ multithreaded multithreading mutexes mux +myftptoyman mysignal namespace nand @@ -646,11 +688,14 @@ param parameterized params parens +pawel pc pdf perf perftools +pgo picoChip +pinIndex pinout plusargs pmos @@ -676,6 +721,7 @@ prev printf printtimescale profcfunc +profiler prototyptes ps pthread @@ -703,12 +749,14 @@ regs reloop resetall respecified +rodata rr rst runtime runtimes rw sVerilator +sawatzke sc scalared sccanf @@ -743,6 +791,7 @@ subcells subexpressions submodule submodules +substring sv svBitVal svBitVecVal @@ -777,6 +826,7 @@ trunc txt typ typedef +typedef'ed typedefed typedefs typename @@ -790,6 +840,7 @@ uniquified unistd unlink unlinked +unnamedblk unopt unoptflat unoptimizable @@ -845,5 +896,7 @@ xnor xout xuejiazidi yanx +ypq yurivict zdave +Øyvind From 560efb2c9ebc5a4ed0405bd64f61d2e958ed66c0 Mon Sep 17 00:00:00 2001 From: HungMingWu Date: Sun, 15 May 2022 06:15:38 +0800 Subject: [PATCH 13/68] Internals: Fix memory leak in V3FileLine (#3407) (#3408). No functional change intended. --- src/V3FileLine.cpp | 2 +- src/V3FileLine.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index fa5e324fe..90e3c85e7 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -155,7 +155,7 @@ FileLine::FileLine(FileLine::EmptySecret) { } void FileLine::newContent() { - m_contentp = new VFileContent; + m_contentp = std::make_shared(); m_contentLineno = 1; } diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 1928e8f5a..1ff0c06a4 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,7 @@ class FileLine final { int m_lastColumn = 0; // `line corrected token's last column number int m_filenameno; // `line corrected filename number int m_contentLineno = 0; // Line number within source stream - VFileContent* m_contentp = nullptr; // Source text contents line is within + std::shared_ptr m_contentp = nullptr; // Source text contents line is within FileLine* m_parent = nullptr; // Parent line that included this line std::bitset m_warnOn; bool m_waive = false; // Waive warning @@ -180,7 +181,7 @@ public: int firstColumn() const { return m_firstColumn; } int lastLineno() const { return m_lastLineno; } int lastColumn() const { return m_lastColumn; } - VFileContent* contentp() const { return m_contentp; } + std::shared_ptr contentp() const { return m_contentp; } // If not otherwise more specific, use last lineno for errors etc, // as the parser errors etc generally make more sense pointing at the last parse point int lineno() const { return m_lastLineno; } From 7602c983c5fd542549f45ae2b679b8b885e3813b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 14 May 2022 18:16:30 -0400 Subject: [PATCH 14/68] Commentary --- README.rst | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index caf5678b9..8dd636245 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ Welcome to Verilator .. list-table:: * - **Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.** - * Accepts synthesizable Verilog or SystemVerilog + * Accepts Verilog or SystemVerilog * Performs lint code-quality checks * Compiles into multithreaded C++, or SystemC * Creates XML to front-end your own tools @@ -57,17 +57,18 @@ files, the "Verilated" code. The user writes a little C++/SystemC wrapper file, which instantiates the "Verilated" model of the user's top level module. These C++/SystemC files -are then compiled by a C++ compiler (gcc/clang/MSVC++). The resulting -executable performs the design simulation. Verilator also supports linking -its generated libraries, optionally encrypted, into other simulators. +are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the +resulting executable performs the design simulation. Verilator also +supports linking Verilated generated libraries, optionally encrypted, into +other simulators. Verilator may not be the best choice if you are expecting a full featured -replacement for NC-Verilog, VCS or another commercial Verilog simulator, or -if you are looking for a behavioral Verilog simulator e.g. for a quick -class project (we recommend `Icarus Verilog`_ for this.) However, if you -are looking for a path to migrate SystemVerilog to C++ or SystemC, or your -team is comfortable writing just a touch of C++ code, Verilator is the tool -for you. +replacement for Incisive, ModelSim/Questa, VCS or another commercial +Verilog simulator, or if you are looking for a behavioral Verilog simulator +e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.) +However, if you are looking for a path to migrate SystemVerilog to C++ or +SystemC, or your team is comfortable writing just a touch of C++ code, +Verilator is the tool for you. Performance From 89ec3d16dc3f43a006fb5c7acf5a345789a8918e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 15 May 2022 13:30:04 +0100 Subject: [PATCH 15/68] Allow const nodes in VNRef No functional change. --- src/V3Ast.h | 2 +- src/V3Hasher.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 4c306da80..ca00b8040 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2150,7 +2150,7 @@ static_assert(sizeof(VNRef) == sizeof(std::reference_wrapper), // without having to copy nodes into the collections. // Forward declaration to avoid including V3Hasher.h which needs V3Ast.h (this file). -size_t V3HasherUncachedHash(AstNode&); +size_t V3HasherUncachedHash(const AstNode&); // Specialization of std::hash for VNRef template // diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 10c53d4c8..7cf3672b6 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -530,6 +530,6 @@ V3Hash V3Hasher::uncachedHash(const AstNode* nodep) { // This is used by the std::hash specialization for VNRef. // Declared separately to avoid a circular header dependency. -size_t V3HasherUncachedHash(AstNode& node) { +size_t V3HasherUncachedHash(const AstNode& node) { return static_cast(V3Hasher::uncachedHash(&node).value()); } From ae8d8ee1ac85c248105f9fda00a7f7d1a73a91e1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 09:29:15 -0400 Subject: [PATCH 16/68] Fix crash with misuse of display. --- src/V3EmitCFunc.cpp | 3 ++- test_regress/t/t_with.v | 36 ++++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 786b8368c..2aa4f2342 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -308,7 +308,8 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const } emitDispState.pushFormat(pfmt); if (!ignore) { - if (argp->dtypep()->basicp()->keyword() == VBasicDTypeKwd::STRING) { + if (argp->dtypep()->basicp() + && argp->dtypep()->basicp()->keyword() == VBasicDTypeKwd::STRING) { // string in SystemVerilog is std::string in C++ which is not POD emitDispState.pushArg(' ', nullptr, "-1"); } else { diff --git a/test_regress/t/t_with.v b/test_regress/t/t_with.v index 3a3da8ff2..64684e46c 100644 --- a/test_regress/t/t_with.v +++ b/test_regress/t/t_with.v @@ -6,40 +6,52 @@ // 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); + module t (/*AUTOARG*/); initial begin int tofind; int aliases[$]; int found[$]; - int id; int i; aliases = '{ 1, 4, 6, 8}; tofind = 6; found = aliases.find with (item == 1); + `checkh(found.size, 1); found = aliases.find(j) with (j == tofind); + `checkh(found.size, 1); // And as function aliases.find(i) with (i == tofind); // No parenthesis - found = aliases.find with (item == i); - aliases.find with (item == i); + tofind = 0; + found = aliases.find with (item == tofind); + `checkh(found.size, 0); + aliases.find with (item == tofind); -`ifdef VERILATOR - // No expression (e.g. x.randomize() with {}) - // Hack until randomize() supported - found = aliases.sort() with {}; -`endif + // bug3387 + i = aliases.sum(); + `checkh(i, 'h13); + i = aliases.sum() with (2'(item)); + `checkh(i, 'h3); // Unique (array method) - id = 4; - found = aliases.find with (id); - found = aliases.find() with (item == id); - found = aliases.find(i) with (i == id); + tofind = 4; + found = aliases.find with (tofind); // "true" match + `checkh(found.size, 4); + found = aliases.find() with (item == tofind); + `checkh(found.size, 1); + found = aliases.find(i) with (i == tofind); + `checkh(found.size, 1); i = aliases.or(v) with (v); + `checkh(i, 'hf); i = aliases.and(v) with (v); + `checkh(i, 0); i = aliases.xor(v) with (v); + `checkh(i, 'hb); $write("*-* All Finished *-*\n"); $finish; From 3c4131d45dc2be40e21494ca44664abd0ab14071 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 09:53:48 -0400 Subject: [PATCH 17/68] Fix 'with' operator with type casting (#3387). --- Changes | 1 + src/V3LinkDot.cpp | 1 - src/V3Width.cpp | 4 ++-- test_regress/t/t_with.v | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Changes b/Changes index c3958d189..85b3f62bb 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 4.223 devel * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] +* Fix 'with' operator with type casting (#3387). [xiak95] Verilator 4.222 2022-05-02 diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 535f57b40..22f4d97ca 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1729,7 +1729,6 @@ class LinkDotScopeVisitor final : public VNVisitor { // Note we allow AstNodeStmt's as generates may be under them virtual void visit(AstCell*) override {} virtual void visit(AstVar*) override {} - virtual void visit(AstNodeMath*) override {} virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 17e302ccc..f5e16ec21 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2725,7 +2725,7 @@ private: methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); - newp->dtypeFrom(adtypep->subDTypep()); + newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { @@ -2949,7 +2949,7 @@ private: methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); - newp->dtypeFrom(adtypep->subDTypep()); + newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { diff --git a/test_regress/t/t_with.v b/test_regress/t/t_with.v index 64684e46c..64f6485c5 100644 --- a/test_regress/t/t_with.v +++ b/test_regress/t/t_with.v @@ -16,6 +16,7 @@ module t (/*AUTOARG*/); int aliases[$]; int found[$]; int i; + byte byteq[$] = {2, -1, 127}; aliases = '{ 1, 4, 6, 8}; tofind = 6; @@ -35,8 +36,8 @@ module t (/*AUTOARG*/); // bug3387 i = aliases.sum(); `checkh(i, 'h13); - i = aliases.sum() with (2'(item)); - `checkh(i, 'h3); + i = byteq.sum() with (int'(item)); + `checkh(i, 128); // Unique (array method) tofind = 4; From 829437b20b2f37dd597b9dd2be927e79995c2073 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 15 May 2022 15:25:46 +0100 Subject: [PATCH 18/68] Commentary - dependencies --- docs/guide/install.rst | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 753215d68..2c0a1134f 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -87,7 +87,7 @@ compiles under all the options above, plus using MSVC++. Install Prerequisites --------------------- -To build or run Verilator you need these standard packages: +To build or run Verilator, you need these standard packages: :: @@ -98,13 +98,20 @@ To build or run Verilator you need these standard packages: sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error) -To build or run the following are optional but should be installed for good -performance: +To build or run Verilator, the following are optional but should be installed +for good performance: :: sudo apt-get install ccache # If present at build, needed for run - sudo apt-get install libgoogle-perftools-dev numactl perl-doc + sudo apt-get install libgoogle-perftools-dev numactl + +The following is optional but is recommended for nicely rendered command line +help when running Verilator: + +:: + + sudo apt-get install perl-doc To build Verilator you will need to install these packages; these do not need to be present to run Verilator: @@ -118,7 +125,7 @@ Those developing Verilator itself may also want these (see internals.rst): :: sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov - sudo pip3 install sphinx sphinx_rtd_theme breathe + sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe cpan install Pod::Perldoc cpan install Parallel::Forker From 5aa12e9b511e2fbd1338c7f242da313ad39355c9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 10:50:44 -0400 Subject: [PATCH 19/68] Add assert when VerilatedContext is mis-deleted (#3121). --- Changes | 1 + docs/guide/connecting.rst | 3 +++ examples/make_tracing_c/sim_main.cpp | 2 ++ include/verilated.cpp | 14 ++++++++++- include/verilated.h | 7 ++++++ test_regress/driver.pl | 1 + test_regress/t/t_wrapper_del_context_bad.cpp | 22 +++++++++++++++++ test_regress/t/t_wrapper_del_context_bad.out | 2 ++ test_regress/t/t_wrapper_del_context_bad.pl | 25 ++++++++++++++++++++ test_regress/t/t_wrapper_del_context_bad.v | 9 +++++++ 10 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_wrapper_del_context_bad.cpp create mode 100644 test_regress/t/t_wrapper_del_context_bad.out create mode 100755 test_regress/t/t_wrapper_del_context_bad.pl create mode 100644 test_regress/t/t_wrapper_del_context_bad.v diff --git a/Changes b/Changes index 85b3f62bb..615f7088f 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,7 @@ Verilator 4.223 devel **Minor:** * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] +* Add assert when VerilatedContext is mis-deleted (#3121). [Ruptert Swarbrick] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 8259447b3..edfc3d67b 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -110,6 +110,9 @@ model. Here is a simple example: Verilated::commandArgs(argc, argv); // Remember args top = new Vtop; // Create model + // Do not instead make Vtop as a file-scope static + // variable, as the "C++ static initialization order fiasco" + // may cause a crash top->reset_l = 0; // Set some inputs diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index 04181850a..06d399901 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -34,6 +34,8 @@ int main(int argc, char** argv, char** env) { // Using unique_ptr is similar to // "VerilatedContext* contextp = new VerilatedContext" then deleting at end. const std::unique_ptr contextp{new VerilatedContext}; + // Do not instead make Vtop as a file-scope static variable, as the + // "C++ static initialization order fiasco" may cause a crash // Set debug level, 0 is off, 9 is highest presently used // May be overridden by commandArgs argument parsing diff --git a/include/verilated.cpp b/include/verilated.cpp index 782b8cf39..1f6fe3b4c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2289,7 +2289,17 @@ VerilatedContext::VerilatedContext() } // Must declare here not in interface, as otherwise forward declarations not known -VerilatedContext::~VerilatedContext() {} +VerilatedContext::~VerilatedContext() { + checkMagic(this); + m_magic = 0x1; // Arbitrary but 0x1 is what Verilator src uses for a deleted pointer +} + +void VerilatedContext::checkMagic(const VerilatedContext* contextp) { + if (VL_UNLIKELY(!contextp || contextp->m_magic != MAGIC)) { + VL_FATAL_MT("", 0, "", // LCOV_EXCL_LINE + "Attempt to create model using a bad/deleted VerilatedContext pointer"); + } +} VerilatedContext::Serialized::Serialized() { m_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure @@ -2657,6 +2667,7 @@ const VerilatedScopeNameMap* VerilatedContext::scopeNameMap() VL_MT_SAFE { VerilatedSyms::VerilatedSyms(VerilatedContext* contextp) : _vm_contextp__(contextp ? contextp : Verilated::threadContextp()) { + VerilatedContext::checkMagic(_vm_contextp__); Verilated::threadContextp(_vm_contextp__); #ifdef VL_THREADED __Vm_evalMsgQp = new VerilatedEvalMsgQueue; @@ -2664,6 +2675,7 @@ VerilatedSyms::VerilatedSyms(VerilatedContext* contextp) } VerilatedSyms::~VerilatedSyms() { + VerilatedContext::checkMagic(_vm_contextp__); #ifdef VL_THREADED delete __Vm_evalMsgQp; #endif diff --git a/include/verilated.h b/include/verilated.h index 889f59c7b..aa1a582be 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -374,6 +374,10 @@ protected: // List of free descriptors in the MCT region [4, 32) std::vector m_fdFreeMct VL_GUARDED_BY(m_fdMutex); + // Magic to check for bad construction + static constexpr uint64_t MAGIC = 0xC35F9A6E5298EE6EULL; // SHA256 "VerilatedContext" + uint64_t m_magic = MAGIC; + private: // CONSTRUCTORS VL_UNCOPYABLE(VerilatedContext); @@ -535,6 +539,9 @@ public: // But for internal use only // Internal: Serialization setup static constexpr size_t serialized1Size() VL_PURE { return sizeof(m_s); } void* serialized1Ptr() VL_MT_UNSAFE { return &m_s; } + + // Internal: Check magic number + static void checkMagic(const VerilatedContext* contextp); }; //=========================================================================== diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 3f4db9538..ffcfac4a8 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1892,6 +1892,7 @@ sub _make_main { $fh->print(" if (save_time && ${time} == save_time) {\n"); $fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n"); $fh->print(" printf(\"Exiting after save_model\\n\");\n"); + $fh->print(" topp.reset(nullptr);\n"); $fh->print(" return 0;\n"); $fh->print(" }\n"); } diff --git a/test_regress/t/t_wrapper_del_context_bad.cpp b/test_regress/t/t_wrapper_del_context_bad.cpp new file mode 100644 index 000000000..e6e33decd --- /dev/null +++ b/test_regress/t/t_wrapper_del_context_bad.cpp @@ -0,0 +1,22 @@ +// +// DESCRIPTION: Verilator: Verilog Multiple Model Test Module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include + +#include VM_PREFIX_INCLUDE + +int main(int argc, char** argv, char** env) { + // Create contexts + VerilatedContext* contextp{new VerilatedContext}; + + delete contextp; // Test mistake - deleting contextp + + // instantiate verilated design + std::unique_ptr topp{new VM_PREFIX{contextp, "TOP"}}; + + return 0; +} diff --git a/test_regress/t/t_wrapper_del_context_bad.out b/test_regress/t/t_wrapper_del_context_bad.out new file mode 100644 index 000000000..6344c8d00 --- /dev/null +++ b/test_regress/t/t_wrapper_del_context_bad.out @@ -0,0 +1,2 @@ +%Error: Attempt to create model using a bad/deleted VerilatedContext pointer +Aborting... diff --git a/test_regress/t/t_wrapper_del_context_bad.pl b/test_regress/t/t_wrapper_del_context_bad.pl new file mode 100755 index 000000000..82a4ea9cf --- /dev/null +++ b/test_regress/t/t_wrapper_del_context_bad.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use strict; use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Multiple Model Test Module +# +# Copyright 2020-2021 by Andreas Kuster. 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 $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_wrapper_del_context_bad.v b/test_regress/t/t_wrapper_del_context_bad.v new file mode 100644 index 000000000..f4ae87f02 --- /dev/null +++ b/test_regress/t/t_wrapper_del_context_bad.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module top; + initial $finish; +endmodule From c8102c8ffebd3bed85f6bd0647f453ce6319f05d Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 15 May 2022 16:00:52 +0100 Subject: [PATCH 20/68] Fix typo --- Changes | 2 +- docs/spelling.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Changes b/Changes index 615f7088f..14236dae9 100644 --- a/Changes +++ b/Changes @@ -248,7 +248,7 @@ Verilator 4.204 2021-06-12 * Fix to emit 'else if' without nesting (#2944). [Geza Lore] * Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] * Fix to not emit empty files with low split limits (#2961). [Geza Lore] -* Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] +* Fix merging of assignments in C++ code (#2970). [Rupert Swarbrick] * Fix unused variable warnings (#2991). [Pieter Kapsenberg] * Fix --protect-ids when using SV classes (#2994). [Geza Lore] * Fix constant function calls with uninitialized value (#2995). [yanx21] diff --git a/docs/spelling.txt b/docs/spelling.txt index c0c5e738d..9014a6af6 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -257,7 +257,6 @@ Rodionov Rolfe Roodselaar Runtime -Ruper Ruud Rystsov STandarD From 7f1a9239abcc73aa4eca27d8d828f60f686e9dc1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 11:14:07 -0400 Subject: [PATCH 21/68] Commentary, fix typo (#3121) --- Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changes b/Changes index 14236dae9..5c4e6c01b 100644 --- a/Changes +++ b/Changes @@ -14,7 +14,7 @@ Verilator 4.223 devel **Minor:** * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] -* Add assert when VerilatedContext is mis-deleted (#3121). [Ruptert Swarbrick] +* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] From c3c46967dcc7c196f37248416a5626b43c26801c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 11:50:52 -0400 Subject: [PATCH 22/68] Tests: Appease sanitizer (#3121). --- include/verilated.h | 1 + test_regress/t/t_wrapper_del_context_bad.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/verilated.h b/include/verilated.h index aa1a582be..804d7363a 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -542,6 +542,7 @@ public: // But for internal use only // Internal: Check magic number static void checkMagic(const VerilatedContext* contextp); + void selfTestClearMagic() { m_magic = 0x2; } }; //=========================================================================== diff --git a/test_regress/t/t_wrapper_del_context_bad.cpp b/test_regress/t/t_wrapper_del_context_bad.cpp index e6e33decd..28f80eee4 100644 --- a/test_regress/t/t_wrapper_del_context_bad.cpp +++ b/test_regress/t/t_wrapper_del_context_bad.cpp @@ -13,7 +13,9 @@ int main(int argc, char** argv, char** env) { // Create contexts VerilatedContext* contextp{new VerilatedContext}; - delete contextp; // Test mistake - deleting contextp + // Ideally we'd do this, but then address sanitizer blows up + // delete contextp; // Test mistake - deleting contextp + contextp->selfTestClearMagic(); // instantiate verilated design std::unique_ptr topp{new VM_PREFIX{contextp, "TOP"}}; From 99bdc27be323d4bd14e5d13efaffd8fdcba65c5e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 15 May 2022 14:26:55 -0400 Subject: [PATCH 23/68] Internals: Cleanup some statics, trivial part towards (#3419) --- include/verilated_cov.cpp | 4 ---- include/verilated_profiler.h | 2 +- include/verilated_types.h | 4 ++-- include/verilated_vpi.cpp | 7 ++++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index bb1893fd8..fb0609be5 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -123,10 +123,6 @@ public: protected: friend class VerilatedCovContext; virtual ~VerilatedCovImp() override { clearGuts(); } - static VerilatedCovImp& imp() VL_MT_SAFE { - static VerilatedCovImp s_singleton; - return s_singleton; - } private: // PRIVATE METHODS diff --git a/include/verilated_profiler.h b/include/verilated_profiler.h index b85bd0eb5..d47be4da4 100644 --- a/include/verilated_profiler.h +++ b/include/verilated_profiler.h @@ -228,7 +228,7 @@ void VlPgoProfiler::write(const char* modelp, const std::string& file // So when we have multiple models in an executable, possibly even // running on different threads, each will have a different symtab so // each will collect is own data correctly. However when each is - // destroid we need to get all the data, not keep overwriting and only + // destroyed we need to get all the data, not keep overwriting and only // get the last model's data. static bool s_firstCall = true; diff --git a/include/verilated_types.h b/include/verilated_types.h index 8e8da1941..d45477d00 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -289,7 +289,7 @@ public: // 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(int32_t index) { - static T_Value s_throwAway; + static VL_THREAD_LOCAL 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(); @@ -300,7 +300,7 @@ public: } // Accessing. Verilog: v = assoc[index] const T_Value& at(int32_t index) const { - static T_Value s_throwAway; + static VL_THREAD_LOCAL 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(); diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 479a9cb59..277230720 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -81,8 +81,9 @@ public: // To simplify our free list, we use a size large enough for all derived types // We reserve word zero for the next pointer, as that's safer in case a // dangling reference to the original remains around. - static const size_t chunk = 96; - if (VL_UNCOVERABLE(size > chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk"); + static constexpr size_t CHUNK_SIZE = 96; + if (VL_UNCOVERABLE(size > CHUNK_SIZE)) + VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE"); if (VL_LIKELY(t_freeHead)) { uint8_t* const newp = t_freeHead; t_freeHead = *(reinterpret_cast(newp)); @@ -90,7 +91,7 @@ public: return newp + 8; } // +8: 8 bytes for next - uint8_t* newp = reinterpret_cast(::operator new(chunk + 8)); + uint8_t* newp = reinterpret_cast(::operator new(CHUNK_SIZE + 8)); *(reinterpret_cast(newp)) = activeMagic(); return newp + 8; } From ecaa07a72a177dd6487a0b20d2ae090510d669a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 16 May 2022 21:44:41 +0200 Subject: [PATCH 24/68] Rename AstTimingControl to AstEventControl (#3425) Signed-off-by: Krzysztof Bieganski --- src/V3AstNodes.h | 8 ++++---- src/V3LinkParse.cpp | 4 ++-- src/V3Width.cpp | 6 +++--- src/verilog.y | 2 +- test_regress/t/t_event_control_unsup.out | 8 ++++---- test_regress/t/t_lint_comb_bad.out | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 5082ae08d..80ae000cc 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5243,15 +5243,15 @@ public: } }; -class AstTimingControl final : public AstNodeStmt { +class AstEventControl final : public AstNodeStmt { // Parents: stmtlist public: - AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) - : ASTGEN_SUPER_TimingControl(fl) { + AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_EventControl(fl) { setNOp1p(sensesp); setNOp2p(stmtsp); } - ASTNODE_NODE_FUNCS(TimingControl) + ASTNODE_NODE_FUNCS(EventControl) virtual string verilogKwd() const override { return "@(%l) %r"; } virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index df1e36436..79be8fd05 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -582,12 +582,12 @@ private: iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstTimingControl* nodep) override { + virtual void visit(AstEventControl* nodep) override { cleanFileline(nodep); iterateChildren(nodep); AstAlways* const alwaysp = VN_CAST(nodep->backp(), Always); if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) { - alwaysp->v3error("Timing control statements not legal under always_comb " + alwaysp->v3error("Event control statements not legal under always_comb " "(IEEE 1800-2017 9.2.2.2.2)\n" << nodep->warnMore() << "... Suggest use a normal 'always'"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f5e16ec21..6118bcff4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1323,10 +1323,10 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstTimingControl* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: timing control statement in this location\n" + virtual void visit(AstEventControl* nodep) override { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: event control statement in this location\n" << nodep->warnMore() - << "... Suggest have one timing control statement " + << "... Suggest have one event control statement " << "per procedure, at the top of the procedure"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } diff --git a/src/verilog.y b/src/verilog.y index 84c778b45..3175ee9d0 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3252,7 +3252,7 @@ statement_item: // IEEE: statement_item | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } - | event_control stmtBlock { $$ = new AstTimingControl(FILELINE_OR_CRE($1), $1, $2); } + | event_control stmtBlock { $$ = new AstEventControl(FILELINE_OR_CRE($1), $1, $2); } //UNSUP cycle_delay stmtBlock { UNSUP } // | seq_block { $$ = $1; } diff --git a/test_regress/t/t_event_control_unsup.out b/test_regress/t/t_event_control_unsup.out index 1b0a26e28..7c40c182e 100644 --- a/test_regress/t/t_event_control_unsup.out +++ b/test_regress/t/t_event_control_unsup.out @@ -1,12 +1,12 @@ -%Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: timing control statement in this location +%Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: event control statement in this location : ... In instance t - : ... Suggest have one timing control statement per procedure, at the top of the procedure + : ... Suggest have one event control statement per procedure, at the top of the procedure 14 | @(clk); | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: timing control statement in this location +%Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: event control statement in this location : ... In instance t - : ... Suggest have one timing control statement per procedure, at the top of the procedure + : ... Suggest have one event control statement per procedure, at the top of the procedure 16 | @(clk); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_comb_bad.out b/test_regress/t/t_lint_comb_bad.out index 176774ef6..ffdca1f17 100644 --- a/test_regress/t/t_lint_comb_bad.out +++ b/test_regress/t/t_lint_comb_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_comb_bad.v:14:4: Timing control statements not legal under always_comb (IEEE 1800-2017 9.2.2.2.2) +%Error: t/t_lint_comb_bad.v:14:4: Event control statements not legal under always_comb (IEEE 1800-2017 9.2.2.2.2) : ... Suggest use a normal 'always' 14 | always_comb @(*) begin | ^~~~~~~~~~~ From 3f7a248ed4280e51ace8a1496721a5df845806e3 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 16 May 2022 21:45:33 +0200 Subject: [PATCH 25/68] Refactor some of the Begin handling to a separate function (#3426) Signed-off-by: Krzysztof Bieganski --- src/V3Begin.cpp | 51 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 75efa0f03..f2d74b678 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -76,6 +76,33 @@ private: return a + "__DOT__" + b; } + void dotNames(const AstNodeBlock* const nodep, const char* const blockName) { + UINFO(8, "nname " << m_namedScope << endl); + if (nodep->name() != "") { // Else unneeded unnamed block + // Create data for dotted variable resolution + string dottedname = nodep->name() + "__DOT__"; // So always found + string::size_type pos; + while ((pos = dottedname.find("__DOT__")) != string::npos) { + const string ident = dottedname.substr(0, pos); + dottedname = dottedname.substr(pos + strlen("__DOT__")); + if (nodep->name() != "") { + m_displayScope = dot(m_displayScope, ident); + m_namedScope = dot(m_namedScope, ident); + } + m_unnamedScope = dot(m_unnamedScope, ident); + // Create CellInline for dotted var resolution + if (!m_ftaskp) { + AstCellInline* const inlinep = new AstCellInline( + nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit()); + m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells + } + } + } + + // Remap var names and replace lower Begins + iterateAndNextNull(nodep->stmtsp()); + } + void liftNode(AstNode* nodep) { nodep->unlinkFrBack(); if (m_ftaskp) { @@ -141,30 +168,8 @@ private: VL_RESTORER(m_namedScope); VL_RESTORER(m_unnamedScope); { - UINFO(8, "nname " << m_namedScope << endl); - if (nodep->name() != "") { // Else unneeded unnamed block - // Create data for dotted variable resolution - string dottedname = nodep->name() + "__DOT__"; // So always found - string::size_type pos; - while ((pos = dottedname.find("__DOT__")) != string::npos) { - const string ident = dottedname.substr(0, pos); - dottedname = dottedname.substr(pos + strlen("__DOT__")); - if (nodep->name() != "") { - m_displayScope = dot(m_displayScope, ident); - m_namedScope = dot(m_namedScope, ident); - } - m_unnamedScope = dot(m_unnamedScope, ident); - // Create CellInline for dotted var resolution - if (!m_ftaskp) { - AstCellInline* const inlinep = new AstCellInline( - nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit()); - m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells - } - } - } + dotNames(nodep, "__BEGIN__"); - // Remap var names and replace lower Begins - iterateAndNextNull(nodep->stmtsp()); UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier"); // Cleanup From 561eaa311de62df59e7d7339fc7a77ca76606abc Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 17 May 2022 15:19:06 +0200 Subject: [PATCH 26/68] Tests: Enable CI testing with GCC 10 (#3432) This is a pre-PR to #3363. Signed-off-by: Krzysztof Bieganski --- .github/workflows/build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cced10dc..47b5f70b2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,11 @@ jobs: - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-20.04 - {os: ubuntu-18.04, m32: 1} + include: + # Build GCC 10 on ubuntu-20.04 + - os: ubuntu-20.04 + compiler: { cc: gcc-10, cxx: g++-10 } + m32: 0 runs-on: ${{ matrix.os }} name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} ${{ matrix.m32 && '| -m32' || '' }} env: @@ -102,6 +107,13 @@ jobs: - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-20.04 - {os: ubuntu-18.04, m32: 1} + include: + # Test with GCC 10 on ubuntu-20.04 without m32 + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-1} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-2} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-0} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-1} runs-on: ${{ matrix.os }} name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} ${{ matrix.m32 && '| -m32' || '' }} env: From 67bb2c640ef4887b4798c066177b09fe8fb5c94a Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 17 May 2022 15:19:51 +0200 Subject: [PATCH 27/68] Tests: Rename t_timing_clkgen to t_timing_clkgen1 (#3430) This is a pre-PR to #3363, which will introduce more clock gen tests. Signed-off-by: Krzysztof Bieganski --- test_regress/t/{t_timing_clkgen.pl => t_timing_clkgen1.pl} | 0 test_regress/t/{t_timing_clkgen.v => t_timing_clkgen1.v} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test_regress/t/{t_timing_clkgen.pl => t_timing_clkgen1.pl} (100%) rename test_regress/t/{t_timing_clkgen.v => t_timing_clkgen1.v} (100%) diff --git a/test_regress/t/t_timing_clkgen.pl b/test_regress/t/t_timing_clkgen1.pl similarity index 100% rename from test_regress/t/t_timing_clkgen.pl rename to test_regress/t/t_timing_clkgen1.pl diff --git a/test_regress/t/t_timing_clkgen.v b/test_regress/t/t_timing_clkgen1.v similarity index 100% rename from test_regress/t/t_timing_clkgen.v rename to test_regress/t/t_timing_clkgen1.v From 0a91ddf38a2d585868a54338e28923b92b07b39b Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 17 May 2022 15:20:59 +0200 Subject: [PATCH 28/68] Tests: Better grep check in t_foreach (#3435) This is a pre-PR to #3363. Signed-off-by: Krzysztof Bieganski --- test_regress/t/t_foreach.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_foreach.pl b/test_regress/t/t_foreach.pl index cb80916f1..3ff192bbd 100755 --- a/test_regress/t/t_foreach.pl +++ b/test_regress/t/t_foreach.pl @@ -28,7 +28,7 @@ for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { # have been evaluated inside the compiler. So there should be # no references to 'sum' in the .cpp. for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { - file_grep_not($file, qr/sum/); + file_grep_not($file, qr/[^a-zA-Z]sum[^a-zA-Z]/); } ok(1); From e018eb7bacbc8095cd33fa0ef0dd1a7494453a9d Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 17 May 2022 15:22:43 +0200 Subject: [PATCH 29/68] Support AstClass::repairCache() after V3Class (#3431) This is a pre-PR to #3363. Signed-off-by: Krzysztof Bieganski --- src/V3AstNodes.cpp | 12 ++++++++++-- src/V3Class.cpp | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index fc6999853..33d275e4e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1309,7 +1309,8 @@ void AstClassPackage::cloneRelink() { } void AstClass::insertCache(AstNode* nodep) { const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef) - || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto())); + || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()) + || VN_IS(nodep, CFunc)); if (doit) { if (m_members.find(nodep->name()) != m_members.end()) { nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ()); @@ -1320,7 +1321,14 @@ void AstClass::insertCache(AstNode* nodep) { } void AstClass::repairCache() { clearCache(); - for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); } + for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) { + if (const auto* const scopep = VN_CAST(itemp, Scope)) { + for (auto* itemp = scopep->blocksp(); itemp; itemp = itemp->nextp()) + insertCache(itemp); + } else { + insertCache(itemp); + } + } } bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) { // TAIL RECURSIVE diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 6a7a3ce4f..5b29eccd6 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -97,6 +97,7 @@ private: m_prefix = nodep->name() + "__02e"; // . iterateChildren(nodep); } + nodep->repairCache(); } virtual void visit(AstNodeModule* nodep) override { // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) From 1a056f6db9e6ed74f0912ec30b8031c4336d51a6 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 15 May 2022 16:34:04 +0100 Subject: [PATCH 30/68] Fix invalid conditional merging when starting at 'c = c ? a : b' Fixes #3409. --- src/V3MergeCond.cpp | 26 ++++--- test_regress/t/t_merge_cond_bug_3409.pl | 29 ++++++++ test_regress/t/t_merge_cond_bug_3409.v | 93 +++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_merge_cond_bug_3409.pl create mode 100644 test_regress/t/t_merge_cond_bug_3409.v diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 77b2ea935..673326f27 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -382,15 +382,24 @@ private: return false; } - void addToList(AstNode* nodep, AstNode* condp, int line) { + bool addToList(AstNode* nodep, AstNode* condp, int line) { // Set up head of new list if node is first in list if (!m_mgFirstp) { UASSERT_OBJ(condp, nodep, "Cannot start new list without condition " << line); + // Mark variable references in the condition + condp->foreach([](const AstVarRef* nodep) { nodep->varp()->user1(1); }); + // Now check again if mergeable. We need this to pick up assignments to conditions, + // e.g.: 'c = c ? a : b' at the beginning of the list, which is in fact not mergeable + // because it updates the condition. We simply bail on these. + if (m_checkMergeable(nodep) != Mergeable::YES) { + // Clear marked variables + AstNode::user1ClearTree(); + // We did not add to the list + return false; + } m_mgFirstp = nodep; m_mgCondp = condp; m_listLenght = 0; - // Mark variable references in the condition - condp->foreach([](const AstVarRef* nodep) { nodep->varp()->user1(1); }); // Add any preceding nodes to the list that would allow us to extend the merge range for (;;) { AstNode* const backp = m_mgFirstp->backp(); @@ -416,6 +425,8 @@ private: m_mgNextp = nodep->nextp(); // If last under parent, done with current list if (!m_mgNextp) mergeEnd(__LINE__); + // We did add to the list + return true; } // If this node is the next expected node and is helpful to add to the list, do so, @@ -424,13 +435,10 @@ private: UASSERT_OBJ(m_mgFirstp, nodep, "List must be open"); if (m_mgNextp == nodep) { if (isSimplifiableNode(nodep)) { - addToList(nodep, nullptr, __LINE__); - return true; - } - if (isCheapNode(nodep)) { + if (addToList(nodep, nullptr, __LINE__)) return true; + } else if (isCheapNode(nodep)) { nodep->user2(1); - addToList(nodep, nullptr, __LINE__); - return true; + if (addToList(nodep, nullptr, __LINE__)) return true; } } // Not added to list, so we are done with the current list diff --git a/test_regress/t/t_merge_cond_bug_3409.pl b/test_regress/t/t_merge_cond_bug_3409.pl new file mode 100755 index 000000000..bb6c1fab4 --- /dev/null +++ b/test_regress/t/t_merge_cond_bug_3409.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. 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( + verilator_flags2=> ["--stats"] + ); + +execute(); + +if ($Self->{vlt_all}) { + file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i, + 0); + file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, + 0); + file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, + 0); +} + +ok(1); +1; diff --git a/test_regress/t/t_merge_cond_bug_3409.v b/test_regress/t/t_merge_cond_bug_3409.v new file mode 100644 index 000000000..71e0ccf48 --- /dev/null +++ b/test_regress/t/t_merge_cond_bug_3409.v @@ -0,0 +1,93 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Raynard Qiao. +// 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 [3:0] din = crc[3:0]; + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire row_found; // From test of Test.v + wire [1:0] row_idx; // From test of Test.v + // End of automatics + + Test test(/*AUTOINST*/ + // Outputs + .row_idx (row_idx[1:0]), + .row_found (row_found), + // Inputs + .din (din)); + + // Aggregate outputs into a single result vector + wire [63:0] result = {48'b0, din, 7'b0, row_found, 2'b0, row_idx}; + + // 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'h8b61595b704e511f + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test(/*AUTOARG*/ + // Outputs + row_idx, row_found, + // Inputs + din + ); + + input din; + output [1:0] row_idx; + output row_found; + + reg [3:0] din; + reg [3:0] wide_din; + reg row_found; + reg [1:0] row_idx; + + always_comb begin + integer x; + row_idx = {2{1'b0}}; + row_found = 1'b0; + // Bug #3409: After unrolling, these conditionals should not be merged + // as row_found is assigned. + for (x = 0; $unsigned(x) < 4; x = x + 1) begin + row_idx = !row_found ? x[1:0] : row_idx; + row_found = !row_found ? din[x] : row_found; + end + end + +endmodule From 9edccfdffa3ea180bf9429bb50d52ac5e436ba4f Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 17 May 2022 20:19:44 +0200 Subject: [PATCH 31/68] Initial support for intra-assignment timing controls, net delays (#3427) This is a pre-PR to #3363. Signed-off-by: Krzysztof Bieganski --- src/V3Ast.h | 7 +- src/V3AstNodes.h | 18 ++- src/V3ParseGrammar.cpp | 2 + src/V3Width.cpp | 6 + src/verilog.y | 106 ++++++++++-------- test_regress/t/t_delay_stmtdly_bad.out | 14 ++- test_regress/t/t_gate_delay_unsup.out | 12 ++ test_regress/t/t_gate_delay_unsup.pl | 22 ++++ .../t/t_timing_intra_assign_delay.out | 31 +++++ test_regress/t/t_timing_intra_assign_delay.pl | 20 ++++ test_regress/t/t_timing_intra_assign_delay.v | 24 ++++ .../t/t_timing_intra_assign_event.out | 32 ++++++ test_regress/t/t_timing_intra_assign_event.pl | 20 ++++ test_regress/t/t_timing_intra_assign_event.v | 34 ++++++ test_regress/t/t_timing_net_delay.out | 11 ++ test_regress/t/t_timing_net_delay.pl | 20 ++++ test_regress/t/t_timing_net_delay.v | 30 +++++ 17 files changed, 351 insertions(+), 58 deletions(-) create mode 100644 test_regress/t/t_gate_delay_unsup.out create mode 100755 test_regress/t/t_gate_delay_unsup.pl create mode 100644 test_regress/t/t_timing_intra_assign_delay.out create mode 100755 test_regress/t/t_timing_intra_assign_delay.pl create mode 100644 test_regress/t/t_timing_intra_assign_delay.v create mode 100644 test_regress/t/t_timing_intra_assign_event.out create mode 100755 test_regress/t/t_timing_intra_assign_event.pl create mode 100644 test_regress/t/t_timing_intra_assign_event.v create mode 100644 test_regress/t/t_timing_net_delay.out create mode 100755 test_regress/t/t_timing_net_delay.pl create mode 100644 test_regress/t/t_timing_net_delay.v diff --git a/src/V3Ast.h b/src/V3Ast.h index ca00b8040..47ae4dcc0 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2488,10 +2488,12 @@ public: class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { protected: - AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, + AstNode* timingControlp = nullptr) : AstNodeStmt{t, fl} { setOp1p(rhsp); setOp2p(lhsp); + addNOp3p(timingControlp); dtypeFrom(lhsp); } @@ -2502,6 +2504,9 @@ public: // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 AstNode* rhsp() const { return op1p(); } // op1 = Assign from AstNode* lhsp() const { return op2p(); } // op2 = Assign to + // op3 = Timing controls (delays, event controls) + AstNode* timingControlp() const { return op3p(); } + void addTimingControlp(AstNode* const np) { addNOp3p(np); } void rhsp(AstNode* np) { setOp1p(np); } void lhsp(AstNode* np) { setOp2p(np); } virtual bool hasDType() const override { return true; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 80ae000cc..404eff633 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2142,6 +2142,9 @@ public: virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } + // op2 = Net delay + AstNode* delayp() const { return op2p(); } + void delayp(AstNode* const nodep) { setNOp2p(nodep); } AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - // AstVar isn't a NodeDType) @@ -3481,8 +3484,8 @@ public: class AstAssign final : public AstNodeAssign { public: - AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Assign(fl, lhsp, rhsp) { + AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Assign) @@ -3507,8 +3510,8 @@ public: class AstAssignDly final : public AstNodeAssign { public: - AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp) {} + AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} ASTNODE_NODE_FUNCS(AssignDly) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignDly(this->fileline(), lhsp, rhsp); @@ -3817,15 +3820,18 @@ public: class AstDelay final : public AstNodeStmt { // Delay statement public: - AstDelay(FileLine* fl, AstNode* lhsp) + AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp) : ASTGEN_SUPER_Delay(fl) { setOp1p(lhsp); + setNOp2p(stmtsp); } ASTNODE_NODE_FUNCS(Delay) virtual bool same(const AstNode* samep) const override { return true; } // - AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate + AstNode* lhsp() const { return op1p(); } // op1 = delay value void lhsp(AstNode* nodep) { setOp1p(nodep); } + void stmtsp(AstNode* nodep) { setOp2p(nodep); } // op2 = statements under delay + AstNode* stmtsp() const { return op2p(); } }; class AstGenCase final : public AstNodeCase { diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 3f3d06909..2cc65af6a 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -189,6 +189,8 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, nodep->ansi(m_pinAnsi); nodep->declTyped(m_varDeclTyped); nodep->lifetime(m_varLifetime); + nodep->delayp(m_netDelayp); + m_netDelayp = nullptr; if (GRAMMARP->m_varDecl != VVarType::UNKNOWN) nodep->combineType(GRAMMARP->m_varDecl); if (GRAMMARP->m_varIO != VDirection::NONE) { nodep->declDirection(GRAMMARP->m_varIO); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6118bcff4..69cee08f6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -595,6 +595,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; } + if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBack()); nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } @@ -3984,6 +3985,11 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type"); } } + if (nodep->timingControlp()) { + nodep->timingControlp()->v3warn( + ASSIGNDLY, "Unsupported: Ignoring timing control on this assignment."); + nodep->timingControlp()->unlinkFrBackWithNext()->deleteTree(); + } if (VN_IS(nodep->rhsp(), EmptyQueue)) { UINFO(9, "= {} -> .delete(): " << nodep); if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), QueueDType)) { diff --git a/src/verilog.y b/src/verilog.y index 3175ee9d0..a31704545 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -40,6 +40,13 @@ #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) #define GATEUNSUP(fl, tok) \ { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } +#define PRIMDLYUNSUP(nodep) \ + { \ + if (nodep) { \ + nodep->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this primitive."); \ + nodep->deleteTree(); \ + } \ + } //====================================================================== // Statics (for here only) @@ -60,6 +67,7 @@ public: AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration + AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration AstNodeModule* m_modp = nullptr; // Last module for timeunits bool m_pinAnsi = false; // In ANSI port list FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations @@ -138,6 +146,7 @@ public: if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = nullptr); m_varDTypep = dtypep; } + void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; } void pinPush() { m_pinStack.push(m_pinNum); m_pinNum = 1; @@ -1708,11 +1717,13 @@ net_dataTypeE: var_data_type { $$ = $1; } | signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC, $1}, - $2, true); } // not implicit + $2, true); + GRAMMARP->setNetDelay($3); } // not implicit | signing { $$ = new AstBasicDType{$1, LOGIC, $1}; } // not implicit | /*implicit*/ delayE - { $$ = new AstBasicDType{CRELINE(), LOGIC}; } // not implicit + { $$ = new AstBasicDType{CRELINE(), LOGIC}; + GRAMMARP->setNetDelay($1); } // not implicit ; net_type: // ==IEEE: net_type @@ -2389,7 +2400,15 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delayE assignList ';' { $$ = $4; } + yASSIGN strengthSpecE delayE assignList ';' + { + $$ = $4; + if ($3) + for (auto* nodep = $$; nodep; nodep = nodep->nextp()) { + auto* const assignp = VN_AS(nodep, NodeAssign); + assignp->addTimingControlp(nodep == $$ ? $3 : $3->cloneTree(false)); + } + } ; initial_construct: // IEEE: initial_construct @@ -2630,22 +2649,21 @@ assignOne: variable_lvalue '=' expr { $$ = new AstAssignW($2,$1,$3); } ; -//UNSUPdelay_or_event_controlE: // IEEE: delay_or_event_control plus empty -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | delay_control { $$ = $1; } -//UNSUP | event_control { $$ = $1; } +delay_or_event_controlE: // IEEE: delay_or_event_control plus empty + /* empty */ { $$ = nullptr; } + | delay_control { $$ = $1; } + | event_control { $$ = $1; } //UNSUP | yREPEAT '(' expr ')' event_control { } -//UNSUP ; - -delayE: - /* empty */ { } - | delay { } ; -delay: +delayE: + /* empty */ { $$ = nullptr; } + | delay { $$ = $1; } + ; + +delay: delay_control - { $1->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this assignment/primitive."); - DEL($1); } + { $$ = $1; } ; delay_control: //== IEEE: delay_control @@ -2682,8 +2700,9 @@ netSig: // IEEE: net_decl_assignment - one element from { $$ = VARDONEA($1,*$1, nullptr, $2); } | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); - $$->addNext(new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}); } - | netId variable_dimensionList sigAttrListE + auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; + if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 + $$->addNext(assignp); } | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } ; @@ -3141,12 +3160,10 @@ statement_item: // IEEE: statement_item | fexprLvalue '=' dynamic_array_new ';' { $$ = new AstAssign($2, $1, $3); } // // // IEEE: nonblocking_assignment - | fexprLvalue yP_LTE delayE expr ';' { $$ = new AstAssignDly($2,$1,$4); } - //UNSUP fexprLvalue yP_LTE delay_or_event_controlE expr ';' { UNSUP } - // - // // IEEE: procedural_continuous_assignment - | yASSIGN idClassSel '=' delayE expr ';' { $$ = new AstAssign($1,$2,$5); } - //UNSUP: delay_or_event_controlE above + | fexprLvalue yP_LTE delay_or_event_controlE expr ';' + { $$ = new AstAssignDly{$2, $1, $4, $3}; } + | yASSIGN idClassSel '=' delay_or_event_controlE expr ';' + { $$ = new AstAssign{$1, $2, $5, $4}; } | yDEASSIGN variable_lvalue ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: Verilog 1995 deassign"); } | yFORCE variable_lvalue '=' expr ';' @@ -3224,10 +3241,8 @@ statement_item: // IEEE: statement_item { // AssignDly because we don't have stratified queue, and need to // read events, clear next event, THEN apply this set $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::BitTrue())); } - //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } - // // IEEE remove below - | yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';' - { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::BitTrue())); } + | yP_MINUSGTGT delay_or_event_controlE idDotted/*hierarchical_identifier-event*/ ';' + { $$ = new AstAssignDly{$1, $3, new AstConst{$1, AstConst::BitTrue()}, $2}; } // // // IEEE: loop_statement | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1, AstConst::BitTrue()), $2); } @@ -3251,7 +3266,7 @@ statement_item: // IEEE: statement_item // | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control - | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } + | delay_control stmtBlock { $$ = new AstDelay{$1->fileline(), $1, $2}; } | event_control stmtBlock { $$ = new AstEventControl(FILELINE_OR_CRE($1), $1, $2); } //UNSUP cycle_delay stmtBlock { UNSUP } // @@ -3313,11 +3328,10 @@ statementVerilatorPragmas: //UNSUP ; foperator_assignment: // IEEE: operator_assignment (for first part of expression) - fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); } + fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; } | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd($3,$1,$5); } | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); } // - //UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP } //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); } | fexprLvalue yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); } @@ -4687,22 +4701,22 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation // Gate declarations gateDecl: - yBUF delayE gateBufList ';' { $$ = $3; } - | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; } - | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; } - | yNOT delayE gateNotList ';' { $$ = $3; } - | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; } - | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; } - | yAND delayE gateAndList ';' { $$ = $3; } - | yNAND delayE gateNandList ';' { $$ = $3; } - | yOR delayE gateOrList ';' { $$ = $3; } - | yNOR delayE gateNorList ';' { $$ = $3; } - | yXOR delayE gateXorList ';' { $$ = $3; } - | yXNOR delayE gateXnorList ';' { $$ = $3; } - | yPULLUP delayE gatePullupList ';' { $$ = $3; } - | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; } - | yNMOS delayE gateBufif1List ';' { $$ = $3; } // ~=bufif1, as don't have strengths yet - | yPMOS delayE gateBufif0List ';' { $$ = $3; } // ~=bufif0, as don't have strengths yet + yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); } + | yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet + | yPMOS delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif0, as don't have strengths yet // | yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported | yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index 87c088ddc..fe957acdb 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,17 +1,21 @@ -%Warning-ASSIGNDLY: t/t_delay.v:22:13: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:22:13: Unsupported: Ignoring timing control on this assignment. + : ... In instance t 22 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; | ^~~~~~~~~~~~~~~~~~ ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_delay.v:27:19: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:27:19: Unsupported: Ignoring timing control on this assignment. + : ... In instance t 27 | dly0 <= #0 32'h11; | ^ -%Warning-ASSIGNDLY: t/t_delay.v:30:19: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:30:19: Unsupported: Ignoring timing control on this assignment. + : ... In instance t 30 | dly0 <= #0.12 dly0 + 32'h12; | ^~~~ -%Warning-ASSIGNDLY: t/t_delay.v:38:25: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:38:26: Unsupported: Ignoring timing control on this assignment. + : ... In instance t 38 | dly0 <= #(dly_s.dly) 32'h55; - | ^ + | ^~~ %Warning-STMTDLY: t/t_delay.v:43:11: Unsupported: Ignoring delay on this delayed statement. : ... In instance t 43 | #100 $finish; diff --git a/test_regress/t/t_gate_delay_unsup.out b/test_regress/t/t_gate_delay_unsup.out new file mode 100644 index 000000000..7a1697074 --- /dev/null +++ b/test_regress/t/t_gate_delay_unsup.out @@ -0,0 +1,12 @@ +%Warning-ASSIGNDLY: t/t_gate_basic.v:23:12: Unsupported: Ignoring delay on this primitive. + 23 | not #(0.108) NT0 (nt0, a[0]); + | ^~~~~ + ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest + ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. +%Warning-ASSIGNDLY: t/t_gate_basic.v:24:11: Unsupported: Ignoring delay on this primitive. + 24 | and #1 AN0 (an0, a[0], b[0]); + | ^ +%Warning-ASSIGNDLY: t/t_gate_basic.v:25:12: Unsupported: Ignoring delay on this primitive. + 25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_gate_delay_unsup.pl b/test_regress/t/t_gate_delay_unsup.pl new file mode 100755 index 000000000..2f885e5ae --- /dev/null +++ b/test_regress/t/t_gate_delay_unsup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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); + +top_filename("t/t_gate_basic.v"); + +lint( + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -Wno-UNUSED"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_intra_assign_delay.out b/test_regress/t/t_timing_intra_assign_delay.out new file mode 100644 index 000000000..f726ad4b4 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_delay.out @@ -0,0 +1,31 @@ +%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:12:11: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 12 | assign #10 val2 = val1; + | ^~ + ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest + ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. +%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:16:6: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t + 16 | #10 val1 = 2; + | ^~ +%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:17:5: Unsupported: fork statements + : ... In instance t + 17 | fork #5 val1 = 3; join_none + | ^~~~ +%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:18:13: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 18 | val1 = #10 val1 + 2; + | ^~ +%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:19:14: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 19 | val1 <= #10 val1 + 2; + | ^~ +%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:20:5: Unsupported: fork statements + : ... In instance t + 20 | fork #5 val1 = 5; join_none + | ^~~~ +%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:21:6: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t + 21 | #20 $write("*-* All Finished *-*\n"); + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_delay.pl b/test_regress/t/t_timing_intra_assign_delay.pl new file mode 100755 index 000000000..d61820774 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_delay.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 2022 by Antmicro Ltd. 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); + +lint( + verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_intra_assign_delay.v b/test_regress/t/t_timing_intra_assign_delay.v new file mode 100644 index 000000000..4ddc2461d --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_delay.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + int val1, val2; + + always @val1 $write("[%0t] val1=%0d val2=%0d\n", $time, val1, val2); + + assign #10 val2 = val1; + + initial begin + val1 = 1; + #10 val1 = 2; + fork #5 val1 = 3; join_none + val1 = #10 val1 + 2; + val1 <= #10 val1 + 2; + fork #5 val1 = 5; join_none + #20 $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_intra_assign_event.out b/test_regress/t/t_timing_intra_assign_event.out new file mode 100644 index 000000000..3fd9349f3 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_event.out @@ -0,0 +1,32 @@ +%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:15:5: Unsupported: event control statement in this location + : ... In instance t + : ... Suggest have one event control statement per procedure, at the top of the procedure + 15 | @e val = 2; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:16:5: Unsupported: fork statements + : ... In instance t + 16 | fork begin + | ^~~~ +%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:21:11: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 21 | val = @e val + 2; + | ^ + ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. +%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:22:12: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 22 | val <= @e val + 2; + | ^ +%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:23:5: Unsupported: fork statements + : ... In instance t + 23 | fork begin + | ^~~~ +%Warning-STMTDLY: t/t_timing_intra_assign_event.v:29:6: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t + 29 | #1 $write("*-* All Finished *-*\n"); + | ^ +%Warning-STMTDLY: t/t_timing_intra_assign_event.v:33:12: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t + 33 | initial #1 ->e; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_event.pl b/test_regress/t/t_timing_intra_assign_event.pl new file mode 100755 index 000000000..d61820774 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_event.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 2022 by Antmicro Ltd. 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); + +lint( + verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_intra_assign_event.v b/test_regress/t/t_timing_intra_assign_event.v new file mode 100644 index 000000000..d98da3a66 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign_event.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + int val; + event e; + + always @val $write("val=%0d\n", val); + + initial begin + val = 1; + @e val = 2; + fork begin + @e #1 val = 3; + ->e; + end join_none + ->e; + val = @e val + 2; + val <= @e val + 2; + fork begin + @e val = 5; + ->e; + end join_none + ->e; + ->e; + #1 $write("*-* All Finished *-*\n"); + $finish; + end + + initial #1 ->e; +endmodule diff --git a/test_regress/t/t_timing_net_delay.out b/test_regress/t/t_timing_net_delay.out new file mode 100644 index 000000000..116ccc0a0 --- /dev/null +++ b/test_regress/t/t_timing_net_delay.out @@ -0,0 +1,11 @@ +%Warning-ASSIGNDLY: t/t_timing_net_delay.v:13:15: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 13 | wire[3:0] #4 val1 = cyc; + | ^ + ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest + ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. +%Warning-ASSIGNDLY: t/t_timing_net_delay.v:17:12: Unsupported: Ignoring timing control on this assignment. + : ... In instance t + 17 | assign #4 val2 = cyc; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_net_delay.pl b/test_regress/t/t_timing_net_delay.pl new file mode 100755 index 000000000..d61820774 --- /dev/null +++ b/test_regress/t/t_timing_net_delay.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 2022 by Antmicro Ltd. 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); + +lint( + verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_net_delay.v b/test_regress/t/t_timing_net_delay.v new file mode 100644 index 000000000..aa125ca8c --- /dev/null +++ b/test_regress/t/t_timing_net_delay.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + wire[3:0] #4 val1 = cyc; + wire[3:0] #4 val2; + reg[3:0] cyc = 0; + + assign #4 val2 = cyc; + + always @(posedge clk) begin + cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $write("[%0t] cyc=%0d, val1=%0d, val2=%0d\n", $time, cyc, val1, val2); +`endif + if (cyc >= 4 && val1 != cyc-1 && val2 != cyc-3) $stop; + if (cyc == 15) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From 551bd284dd16097d006bea90124bb47f626b9ea3 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 20 May 2022 15:28:25 +0100 Subject: [PATCH 32/68] Rename some internals related to multi-threaded tracing Rename the implementation internals of current multi-threaded tracing to be "offload mode". No functional change, nor user interface change intended. --- include/verilated_trace.h | 124 +++++++++++++------------- include/verilated_trace_imp.cpp | 153 ++++++++++++++++---------------- include/verilated_vcd_c.cpp | 2 +- src/V3EmitCImp.cpp | 2 +- src/V3EmitMk.cpp | 2 +- src/V3Options.h | 2 +- src/V3Trace.cpp | 2 +- 7 files changed, 146 insertions(+), 141 deletions(-) diff --git a/include/verilated_trace.h b/include/verilated_trace.h index de000e611..a88ce6b50 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -22,6 +22,10 @@ #ifndef VERILATOR_VERILATED_TRACE_H_ #define VERILATOR_VERILATED_TRACE_H_ +#ifdef VL_TRACE_THREADED +#define VL_TRACE_OFFLOAD +#endif + // clang-format off #include "verilated.h" @@ -32,7 +36,7 @@ #include #include -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD # include # include # include @@ -40,9 +44,9 @@ // clang-format on -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD //============================================================================= -// Threaded tracing +// Offloaded tracing // A simple synchronized first in first out queue template class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug @@ -88,7 +92,7 @@ public: // Commands used by thread tracing. Anonymous enum in class, as we want // it scoped, but we also want the automatic conversion to integer types. -class VerilatedTraceCommand final { +class VerilatedTraceOffloadCommand final { public: // These must all fit in 4 bit at the moment, as the tracing routines // pack parameters in the top bits. @@ -172,33 +176,33 @@ private: // Close the file on termination static void onExit(void* selfp) VL_MT_UNSAFE_ONE; -#ifdef VL_TRACE_THREADED - // Number of total trace buffers that have been allocated - uint32_t m_numTraceBuffers; - // Size of trace buffers - size_t m_traceBufferSize; +#ifdef VL_TRACE_OFFLOAD + // Number of total offload buffers that have been allocated + uint32_t m_numOffloadBuffers; + // Size of offload buffers + size_t m_offloadBufferSize; // Buffers handed to worker for processing - VerilatedThreadQueue m_buffersToWorker; + VerilatedThreadQueue m_offloadBuffersToWorker; // Buffers returned from worker after processing - VerilatedThreadQueue m_buffersFromWorker; + VerilatedThreadQueue m_offloadBuffersFromWorker; // Write pointer into current buffer - uint32_t* m_traceBufferWritep; - // End of trace buffer - uint32_t* m_traceBufferEndp; - // The worker thread itself + uint32_t* m_offloadBufferWritep; + // End of offload buffer + uint32_t* m_offloadBufferEndp; + // The offload worker thread itself std::unique_ptr m_workerThread; - // Get a new trace buffer that can be populated. May block if none available - uint32_t* getTraceBuffer(); + // Get a new offload buffer that can be populated. May block if none available + uint32_t* getOffloadBuffer(); - // The function executed by the worker thread - void workerThreadMain(); + // The function executed by the offload worker thread + void offloadWorkerThreadMain(); - // Wait until given buffer is placed in m_buffersFromWorker - void waitForBuffer(const uint32_t* bufferp); + // Wait until given offload buffer is placed in m_offloadBuffersFromWorker + void waitForOffloadBuffer(const uint32_t* bufferp); // Shut down and join worker, if it's running, otherwise do nothing - void shutdownWorker(); + void shutdownOffloadWorker(); #endif // CONSTRUCTORS @@ -307,56 +311,56 @@ public: void fullWData(uint32_t* oldp, const WData* newvalp, int bits); void fullDouble(uint32_t* oldp, double newval); -#ifdef VL_TRACE_THREADED - // Threaded tracing. Just dump everything in the trace buffer +#ifdef VL_TRACE_OFFLOAD + // Offloaded tracing. Just dump everything in the offload buffer inline void chgBit(uint32_t code, CData newval) { - m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval; - m_traceBufferWritep[1] = code; - m_traceBufferWritep += 2; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval; + m_offloadBufferWritep[1] = code; + m_offloadBufferWritep += 2; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgCData(uint32_t code, CData newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_CDATA; - m_traceBufferWritep[1] = code; - m_traceBufferWritep[2] = newval; - m_traceBufferWritep += 3; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA; + m_offloadBufferWritep[1] = code; + m_offloadBufferWritep[2] = newval; + m_offloadBufferWritep += 3; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgSData(uint32_t code, SData newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_SDATA; - m_traceBufferWritep[1] = code; - m_traceBufferWritep[2] = newval; - m_traceBufferWritep += 3; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA; + m_offloadBufferWritep[1] = code; + m_offloadBufferWritep[2] = newval; + m_offloadBufferWritep += 3; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgIData(uint32_t code, IData newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_IDATA; - m_traceBufferWritep[1] = code; - m_traceBufferWritep[2] = newval; - m_traceBufferWritep += 3; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA; + m_offloadBufferWritep[1] = code; + m_offloadBufferWritep[2] = newval; + m_offloadBufferWritep += 3; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgQData(uint32_t code, QData newval, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QDATA; - m_traceBufferWritep[1] = code; - *reinterpret_cast(m_traceBufferWritep + 2) = newval; - m_traceBufferWritep += 4; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA; + m_offloadBufferWritep[1] = code; + *reinterpret_cast(m_offloadBufferWritep + 2) = newval; + m_offloadBufferWritep += 4; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgWData(uint32_t code, const WData* newvalp, int bits) { - m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_WDATA; - m_traceBufferWritep[1] = code; - m_traceBufferWritep += 2; - for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; } - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA; + m_offloadBufferWritep[1] = code; + m_offloadBufferWritep += 2; + for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; } + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } inline void chgDouble(uint32_t code, double newval) { - m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE; - m_traceBufferWritep[1] = code; + m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE; + m_offloadBufferWritep[1] = code; // cppcheck-suppress invalidPointerCast - *reinterpret_cast(m_traceBufferWritep + 2) = newval; - m_traceBufferWritep += 4; - VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); + *reinterpret_cast(m_offloadBufferWritep + 2) = newval; + m_offloadBufferWritep += 4; + VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } #define CHG(name) chg##name##Impl @@ -364,8 +368,8 @@ public: #define CHG(name) chg##name #endif - // In non-threaded mode, these are called directly by the trace callbacks, - // and are called chg*. In threaded mode, they are called by the worker + // In non-offload mode, these are called directly by the trace callbacks, + // and are called chg*. In offload mode, they are called by the worker // thread and are called chg*Impl // Check previous dumped value of signal. If changed, then emit trace entry diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index e5dd41fcd..7a98b7abf 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -33,9 +33,9 @@ #if 0 # include -# define VL_TRACE_THREAD_DEBUG(msg) std::cout << "TRACE THREAD: " << msg << std::endl +# define VL_TRACE_OFFLOAD_DEBUG(msg) std::cout << "TRACE OFFLOAD THREAD: " << msg << std::endl #else -# define VL_TRACE_THREAD_DEBUG(msg) +# define VL_TRACE_OFFLOAD_DEBUG(msg) #endif // clang-format on @@ -78,37 +78,37 @@ static std::string doubleToTimescale(double value) { return valuestr; // Gets converted to string, so no ref to stack } -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD //========================================================================= // Buffer management -template <> uint32_t* VerilatedTrace::getTraceBuffer() { +template <> uint32_t* VerilatedTrace::getOffloadBuffer() { uint32_t* bufferp; - // Some jitter is expected, so some number of alternative trace buffers are + // Some jitter is expected, so some number of alternative offlaod buffers are // required, but don't allocate more than 8 buffers. - if (m_numTraceBuffers < 8) { + if (m_numOffloadBuffers < 8) { // Allocate a new buffer if none is available - if (!m_buffersFromWorker.tryGet(bufferp)) { - ++m_numTraceBuffers; + if (!m_offloadBuffersFromWorker.tryGet(bufferp)) { + ++m_numOffloadBuffers; // Note: over allocate a bit so pointer comparison is well defined // if we overflow only by a small amount - bufferp = new uint32_t[m_traceBufferSize + 16]; + bufferp = new uint32_t[m_offloadBufferSize + 16]; } } else { // Block until a buffer becomes available - bufferp = m_buffersFromWorker.get(); + bufferp = m_offloadBuffersFromWorker.get(); } return bufferp; } -template <> void VerilatedTrace::waitForBuffer(const uint32_t* buffp) { +template <> void VerilatedTrace::waitForOffloadBuffer(const uint32_t* buffp) { // Slow path code only called on flush/shutdown, so use a simple algorithm. // Collect buffers from worker and stash them until we get the one we want. std::deque stash; - do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp); + do { stash.push_back(m_offloadBuffersFromWorker.get()); } while (stash.back() != buffp); // Now put them back in the queue, in the original order. while (!stash.empty()) { - m_buffersFromWorker.put_front(stash.back()); + m_offloadBuffersFromWorker.put_front(stash.back()); stash.pop_back(); } } @@ -116,14 +116,14 @@ template <> void VerilatedTrace::waitForBuffer(const uint32_t* buf //========================================================================= // Worker thread -template <> void VerilatedTrace::workerThreadMain() { +template <> void VerilatedTrace::offloadWorkerThreadMain() { bool shutdown = false; do { - uint32_t* const bufferp = m_buffersToWorker.get(); + uint32_t* const bufferp = m_offloadBuffersToWorker.get(); - VL_TRACE_THREAD_DEBUG(""); - VL_TRACE_THREAD_DEBUG("Got buffer: " << bufferp); + VL_TRACE_OFFLOAD_DEBUG(""); + VL_TRACE_OFFLOAD_DEBUG("Got buffer: " << bufferp); const uint32_t* readp = bufferp; @@ -139,53 +139,53 @@ template <> void VerilatedTrace::workerThreadMain() { switch (cmd & 0xF) { //=== // CHG_* commands - case VerilatedTraceCommand::CHG_BIT_0: - VL_TRACE_THREAD_DEBUG("Command CHG_BIT_0 " << top); + case VerilatedTraceOffloadCommand::CHG_BIT_0: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_0 " << top); chgBitImpl(oldp, 0); continue; - case VerilatedTraceCommand::CHG_BIT_1: - VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top); + case VerilatedTraceOffloadCommand::CHG_BIT_1: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_1 " << top); chgBitImpl(oldp, 1); continue; - case VerilatedTraceCommand::CHG_CDATA: - VL_TRACE_THREAD_DEBUG("Command CHG_CDATA " << top); + case VerilatedTraceOffloadCommand::CHG_CDATA: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_CDATA " << top); // Bits stored in bottom byte of command chgCDataImpl(oldp, *readp, top); readp += 1; continue; - case VerilatedTraceCommand::CHG_SDATA: - VL_TRACE_THREAD_DEBUG("Command CHG_SDATA " << top); + case VerilatedTraceOffloadCommand::CHG_SDATA: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_SDATA " << top); // Bits stored in bottom byte of command chgSDataImpl(oldp, *readp, top); readp += 1; continue; - case VerilatedTraceCommand::CHG_IDATA: - VL_TRACE_THREAD_DEBUG("Command CHG_IDATA " << top); + case VerilatedTraceOffloadCommand::CHG_IDATA: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_IDATA " << top); // Bits stored in bottom byte of command chgIDataImpl(oldp, *readp, top); readp += 1; continue; - case VerilatedTraceCommand::CHG_QDATA: - VL_TRACE_THREAD_DEBUG("Command CHG_QDATA " << top); + case VerilatedTraceOffloadCommand::CHG_QDATA: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_QDATA " << top); // Bits stored in bottom byte of command chgQDataImpl(oldp, *reinterpret_cast(readp), top); readp += 2; continue; - case VerilatedTraceCommand::CHG_WDATA: - VL_TRACE_THREAD_DEBUG("Command CHG_WDATA " << top); + case VerilatedTraceOffloadCommand::CHG_WDATA: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_WDATA " << top); chgWDataImpl(oldp, readp, top); readp += VL_WORDS_I(top); continue; - case VerilatedTraceCommand::CHG_DOUBLE: - VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top); + case VerilatedTraceOffloadCommand::CHG_DOUBLE: + VL_TRACE_OFFLOAD_DEBUG("Command CHG_DOUBLE " << top); chgDoubleImpl(oldp, *reinterpret_cast(readp)); readp += 2; continue; //=== // Rare commands - case VerilatedTraceCommand::TIME_CHANGE: - VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE " << top); + case VerilatedTraceOffloadCommand::TIME_CHANGE: + VL_TRACE_OFFLOAD_DEBUG("Command TIME_CHANGE " << top); readp -= 1; // No code in this command, undo increment emitTimeChange(*reinterpret_cast(readp)); readp += 2; @@ -193,16 +193,16 @@ template <> void VerilatedTrace::workerThreadMain() { //=== // Commands ending this buffer - case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break; - case VerilatedTraceCommand::SHUTDOWN: - VL_TRACE_THREAD_DEBUG("Command SHUTDOWN"); + case VerilatedTraceOffloadCommand::END: VL_TRACE_OFFLOAD_DEBUG("Command END"); break; + case VerilatedTraceOffloadCommand::SHUTDOWN: + VL_TRACE_OFFLOAD_DEBUG("Command SHUTDOWN"); shutdown = true; break; //=== // Unknown command default: { // LCOV_EXCL_START - VL_TRACE_THREAD_DEBUG("Command UNKNOWN"); + VL_TRACE_OFFLOAD_DEBUG("Command UNKNOWN"); VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); break; @@ -214,23 +214,23 @@ template <> void VerilatedTrace::workerThreadMain() { break; } - VL_TRACE_THREAD_DEBUG("Returning buffer"); + VL_TRACE_OFFLOAD_DEBUG("Returning buffer"); // Return buffer - m_buffersFromWorker.put(bufferp); + m_offloadBuffersFromWorker.put(bufferp); } while (VL_LIKELY(!shutdown)); } -template <> void VerilatedTrace::shutdownWorker() { +template <> void VerilatedTrace::shutdownOffloadWorker() { // If the worker thread is not running, done.. if (!m_workerThread) return; // Hand an buffer with a shutdown command to the worker thread - uint32_t* const bufferp = getTraceBuffer(); - bufferp[0] = VerilatedTraceCommand::SHUTDOWN; - m_buffersToWorker.put(bufferp); + uint32_t* const bufferp = getOffloadBuffer(); + bufferp[0] = VerilatedTraceOffloadCommand::SHUTDOWN; + m_offloadBuffersToWorker.put(bufferp); // Wait for it to return - waitForBuffer(bufferp); + waitForOffloadBuffer(bufferp); // Join the thread and delete it m_workerThread->join(); m_workerThread.reset(nullptr); @@ -242,24 +242,24 @@ template <> void VerilatedTrace::shutdownWorker() { // Life cycle template <> void VerilatedTrace::closeBase() { -#ifdef VL_TRACE_THREADED - shutdownWorker(); - while (m_numTraceBuffers) { - delete[] m_buffersFromWorker.get(); - --m_numTraceBuffers; +#ifdef VL_TRACE_OFFLOAD + shutdownOffloadWorker(); + while (m_numOffloadBuffers) { + delete[] m_offloadBuffersFromWorker.get(); + --m_numOffloadBuffers; } #endif } template <> void VerilatedTrace::flushBase() { -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD // Hand an empty buffer to the worker thread - uint32_t* const bufferp = getTraceBuffer(); - *bufferp = VerilatedTraceCommand::END; - m_buffersToWorker.put(bufferp); + uint32_t* const bufferp = getOffloadBuffer(); + *bufferp = VerilatedTraceOffloadCommand::END; + m_offloadBuffersToWorker.put(bufferp); // Wait for it to be returned. As the processing is in-order, // this ensures all previous buffers have been processed. - waitForBuffer(bufferp); + waitForOffloadBuffer(bufferp); #endif } @@ -293,8 +293,8 @@ VerilatedTrace::VerilatedTrace() , m_timeUnit { 1e-9 } -#ifdef VL_TRACE_THREADED -, m_numTraceBuffers { 0 } +#ifdef VL_TRACE_OFFLOAD +, m_numOffloadBuffers { 0 } #endif { set_time_unit(Verilated::threadContextp()->timeunitString()); @@ -306,7 +306,7 @@ template <> VerilatedTrace::~VerilatedTrace() { if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr); Verilated::removeFlushCb(VerilatedTrace::onFlush, this); Verilated::removeExitCb(VerilatedTrace::onExit, this); -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD closeBase(); #endif } @@ -362,16 +362,17 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { Verilated::addFlushCb(VerilatedTrace::onFlush, this); Verilated::addExitCb(VerilatedTrace::onExit, this); -#ifdef VL_TRACE_THREADED - // Compute trace buffer size. we need to be able to store a new value for +#ifdef VL_TRACE_OFFLOAD + // Compute offload buffer size. we need to be able to store a new value for // each signal, which is 'nextCode()' entries after the init callbacks // above have been run, plus up to 2 more words of metadata per signal, // plus fixed overhead of 1 for a termination flag and 3 for a time stamp // update. - m_traceBufferSize = nextCode() + numSignals() * 2 + 4; + m_offloadBufferSize = nextCode() + numSignals() * 2 + 4; // Start the worker thread - m_workerThread.reset(new std::thread{&VerilatedTrace::workerThreadMain, this}); + m_workerThread.reset( + new std::thread{&VerilatedTrace::offloadWorkerThreadMain, this}); #endif } @@ -477,19 +478,19 @@ template <> void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_ if (!preChangeDump()) return; } -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD // Currently only incremental dumps run on the worker thread uint32_t* bufferp = nullptr; if (VL_LIKELY(!m_fullDump)) { - // Get the trace buffer we are about to fill - bufferp = getTraceBuffer(); - m_traceBufferWritep = bufferp; - m_traceBufferEndp = bufferp + m_traceBufferSize; + // Get the offload buffer we are about to fill + bufferp = getOffloadBuffer(); + m_offloadBufferWritep = bufferp; + m_offloadBufferEndp = bufferp + m_offloadBufferSize; // Tell worker to update time point - m_traceBufferWritep[0] = VerilatedTraceCommand::TIME_CHANGE; - *reinterpret_cast(m_traceBufferWritep + 1) = timeui; - m_traceBufferWritep += 3; + m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::TIME_CHANGE; + *reinterpret_cast(m_offloadBufferWritep + 1) = timeui; + m_offloadBufferWritep += 3; } else { // Update time point flushBase(); @@ -519,16 +520,16 @@ template <> void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_ cbr.m_dumpCb(cbr.m_userp, self()); } -#ifdef VL_TRACE_THREADED +#ifdef VL_TRACE_OFFLOAD if (VL_LIKELY(bufferp)) { - // Mark end of the trace buffer we just filled - *m_traceBufferWritep++ = VerilatedTraceCommand::END; + // Mark end of the offload buffer we just filled + *m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::END; // Assert no buffer overflow - assert(m_traceBufferWritep - bufferp <= m_traceBufferSize); + assert(m_offloadBufferWritep - bufferp <= m_offloadBufferSize); // Pass it to the worker thread - m_buffersToWorker.put(bufferp); + m_offloadBuffersToWorker.put(bufferp); } #endif } diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 855f51634..78383befc 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -292,7 +292,7 @@ void VerilatedVcd::bufferResize(uint64_t minsize) { } void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE { - // This function can be called from the trace thread + // This function can be called from the trace offload thread // This function is on the flush() call path // We add output data to m_writep. // When it gets nearly full we dump it using this routine which calls write() diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index f5da29d61..0d979b143 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -770,7 +770,7 @@ class EmitCTrace final : EmitCFunc { const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t code = nodep->declp()->code() + offset; - puts(v3Global.opt.trueTraceThreads() && !nodep->full() ? "(base+" : "(oldp+"); + puts(v3Global.opt.useTraceOffloadThread() && !nodep->full() ? "(base+" : "(oldp+"); puts(cvtToStr(code - nodep->baseCode())); puts(","); emitTraceValue(nodep, arrayindex); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index ce75cb136..52aec9a54 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -71,7 +71,7 @@ public: of.puts("\n"); of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); of.puts("VM_TRACE_THREADS = "); - of.puts(cvtToStr(v3Global.opt.trueTraceThreads())); + of.puts(cvtToStr(v3Global.opt.useTraceOffloadThread())); of.puts("\n"); of.puts("# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)\n"); of.puts("VM_TRACE_FST_WRITER_THREAD = "); diff --git a/src/V3Options.h b/src/V3Options.h index f9cf8f5d5..8c185d4ea 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -517,7 +517,7 @@ public: int traceMaxArray() const { return m_traceMaxArray; } int traceMaxWidth() const { return m_traceMaxWidth; } int traceThreads() const { return m_traceThreads; } - bool trueTraceThreads() const { + bool useTraceOffloadThread() const { return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst(); } int unrollCount() const { return m_unrollCount; } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index cffd498f4..61d009b6f 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -520,7 +520,7 @@ private: "tracep->oldp(vlSymsp->__Vm_baseCode);\n"); } else { // Change dump sub function - if (v3Global.opt.trueTraceThreads()) { + if (v3Global.opt.useTraceOffloadThread()) { addInitStr("const uint32_t base VL_ATTR_UNUSED = " "vlSymsp->__Vm_baseCode + " + cvtToStr(baseCode) + ";\n"); From b130a8cfebd08cabbfe589e756019c688f49d85c Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 20 May 2022 16:02:43 +0100 Subject: [PATCH 33/68] Add -DVM_TRACE_VCD in model builds with Make with --trace --- Changes | 1 + include/verilated.mk.in | 1 + src/V3EmitCMake.cpp | 10 +++------- src/V3EmitMk.cpp | 4 ++++ src/V3Options.h | 1 + 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Changes b/Changes index 5c4e6c01b..7473530d0 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 4.223 devel * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] +* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 4e32df566..34e975bcc 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -56,6 +56,7 @@ VK_CPPFLAGS_ALWAYS += \ -DVM_SC=$(VM_SC) \ -DVM_TRACE=$(VM_TRACE) \ -DVM_TRACE_FST=$(VM_TRACE_FST) \ + -DVM_TRACE_VCD=$(VM_TRACE_VCD) \ $(CFG_CXXFLAGS_NO_UNUSED) \ ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 926228c83..26f42e803 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -119,14 +119,10 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; cmake_set_raw(*of, name + "_TRACE_VCD", - (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) - ? "1" - : "0"); - *of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n"; + (v3Global.opt.trace() && v3Global.opt.traceFormat().vcd()) ? "1" : "0"); + *of << "# FST Tracing output mode? 0/1 (from --trace-fst)\n"; cmake_set_raw(*of, name + "_TRACE_FST", - (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) - ? "1" - : "0"); + (v3Global.opt.trace() && v3Global.opt.traceFormat().fst()) ? "1" : "0"); *of << "\n### Sources...\n"; std::vector classes_fast; diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 52aec9a54..429b78d33 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -65,6 +65,10 @@ public: of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace() ? "1" : "0"); of.puts("\n"); + of.puts("# Tracing output mode in VCD format? 0/1 (from --trace)\n"); + of.puts("VM_TRACE_VCD = "); + of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().vcd() ? "1" : "0"); + of.puts("\n"); of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n"); of.puts("VM_TRACE_FST = "); of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0"); diff --git a/src/V3Options.h b/src/V3Options.h index 8c185d4ea..35a71ed31 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -137,6 +137,7 @@ public: : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning operator en() const { return m_e; } bool fst() const { return m_e == FST; } + bool vcd() const { return m_e == VCD; } string classBase() const { static const char* const names[] = {"VerilatedVcd", "VerilatedFst"}; return names[m_e]; From ffc1c515266b2ddffd2356560a0812ade3523e06 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 20 May 2022 16:06:38 +0100 Subject: [PATCH 34/68] Commentary --- Changes | 1 + 1 file changed, 1 insertion(+) diff --git a/Changes b/Changes index 7473530d0..10a8f44fe 100644 --- a/Changes +++ b/Changes @@ -18,6 +18,7 @@ Verilator 4.223 devel * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] +* Fix incorrect conditional merging (#3409). [Raynard Qiao] Verilator 4.222 2022-05-02 From c7610ed0448ec151b8a0ed2d299264d96715898e Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 20 May 2022 16:58:12 +0100 Subject: [PATCH 35/68] Fix FST tracing thread in CMake build --- Changes | 1 + src/V3EmitCMake.cpp | 5 ++++- verilator-config.cmake.in | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 10a8f44fe..390606387 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 4.223 devel * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] +* Fix passing VL_TRACE_FST_WRITER_THREAD in CMake build. [Geza Lore, Shunyao CAD] Verilator 4.222 2022-05-02 diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 26f42e803..67e8a741c 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -114,7 +114,10 @@ class CMakeEmitter final { *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; - cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.traceThreads())); + cmake_set_raw(*of, name + "_TRACE_THREADS", + cvtToStr(v3Global.opt.useTraceOffloadThread())); + cmake_set_raw(*of, name + "_TRACE_FST_WRITER_THREAD", + v3Global.opt.traceThreads() && v3Global.opt.traceFormat().fst() ? "1" : "0"); *of << "# Struct output mode? 0/1 (from --trace-structs)\n"; cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index 7573d29ae..7f9ece972 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -266,6 +266,10 @@ function(verilate TARGET) set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_THREADED ON) endif() + if (${VERILATE_PREFIX}_TRACE_FST_WRITER_THREAD) + set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_FST_WRITER_TRHEAD ON) + endif() + if (${VERILATE_PREFIX}_COVERAGE) # If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build set_property(TARGET ${TARGET} PROPERTY VERILATOR_COVERAGE ON) @@ -327,6 +331,7 @@ function(verilate TARGET) VM_SC=$> $<$>:VL_THREADED> $<$>:VL_TRACE_THREADED> + $<$>:VL_TRACE_FST_WRITER_THREAD> VM_TRACE=$> VM_TRACE_VCD=$> VM_TRACE_FST=$> From 1282548a1c4d89f95e720892c00895010f61b1e4 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 20 May 2022 17:55:34 +0100 Subject: [PATCH 36/68] Only consider definitions in t_flag_csplit --- test_regress/t/t_flag_csplit.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_flag_csplit.pl b/test_regress/t/t_flag_csplit.pl index bef212f13..c35017122 100755 --- a/test_regress/t/t_flag_csplit.pl +++ b/test_regress/t/t_flag_csplit.pl @@ -87,7 +87,7 @@ sub check_cpp { my $fh = IO::File->new("<$filename") or error("$! $filenme"); my @funcs; while (defined(my $line = $fh->getline)) { - if ($line =~ /^(void|IData)\s+(.*::.*)/) { + if ($line =~ /^(void|IData)\s+(.*::.*){/) { my $func = $2; $func =~ s/\(.*$//; print "\tFunc $func\n" if $Self->{verbose}; From 530817191e88adbafe5152e85621abedd136399a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 25 May 2022 00:50:50 -0400 Subject: [PATCH 37/68] Support non-ANSI interface port declarations (#3439). --- Changes | 1 + src/V3LinkDot.cpp | 6 ++-- src/verilog.y | 44 ++++++++++++++++++++--------- test_regress/t/t_interface_nansi.pl | 21 ++++++++++++++ test_regress/t/t_interface_nansi.v | 37 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 17 deletions(-) create mode 100755 test_regress/t/t_interface_nansi.pl create mode 100644 test_regress/t/t_interface_nansi.v diff --git a/Changes b/Changes index 390606387..d6067565d 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 4.223 devel * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] +* Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 22f4d97ca..63a4eb301 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1478,11 +1478,11 @@ private: // Need to set pin numbers after varnames are created // But before we do the final resolution based on names VSymEnt* const foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name()); - AstVar* const refp = foundp ? VN_AS(foundp->nodep(), Var) : nullptr; - if (!refp) { + AstVar* const refp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr; + if (!foundp) { nodep->v3error( "Input/output/inout declaration not found for port: " << nodep->prettyNameQ()); - } else if (!refp->isIO() && !refp->isIfaceRef()) { + } else if (!refp || (!refp->isIO() && !refp->isIfaceRef())) { nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ()); } else { if (refp->user4()) { diff --git a/src/verilog.y b/src/verilog.y index a31704545..af2b427d3 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -104,6 +104,27 @@ public: string newtext = deQuote(fileline, text); return new AstText(fileline, newtext); } + AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, AstNodeRange* rangelistp) { + // Must clone m_instParamp as may be comma'ed list of instances + VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(name); + if (foundp && VN_IS(foundp->nodep(), Port)) { + // It's a non-ANSI interface, not a cell declaration + m_varAttrp = nullptr; + m_varDecl = VVarType::IFACEREF; + m_varIO = VDirection::NONE; + m_varLifetime = VLifetime::NONE; + setDType(new AstIfaceRefDType{fileline, "", GRAMMARP->m_instModule}); + m_varDeclTyped = true; + AstVar* const nodep = createVariable(fileline, name, rangelistp, nullptr); + return nodep; + } + AstCell* const nodep = new AstCell{fileline, GRAMMARP->m_instModuleFl, + name, GRAMMARP->m_instModule, pinlistp, + AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), + GRAMMARP->scrubRange(rangelistp)}; + nodep->trace(GRAMMARP->allTracingOn(fileline)); + return nodep; + } AstDisplay* createDisplayError(FileLine* fileline) { AstDisplay* nodep = new AstDisplay(fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr); nodep->addNext(new AstStop(fileline, true)); @@ -1418,8 +1439,10 @@ port_declNetE: // IEEE: part of port_declaration, optional net ; portSig: - id/*port*/ { $$ = new AstPort($1,PINNUMINC(),*$1); } - | idSVKwd { $$ = new AstPort($1,PINNUMINC(),*$1); } + id/*port*/ + { $$ = new AstPort{$1, PINNUMINC(), *$1}; SYMP->reinsert($$); } + | idSVKwd + { $$ = new AstPort{$1, PINNUMINC(), *$1}; SYMP->reinsert($$); } ; //********************************************************************** @@ -2869,18 +2892,11 @@ instnameList: | instnameList ',' instnameParen { $$ = $1->addNext($3); } ; -instnameParen: - // // Must clone m_instParamp as may be comma'ed list of instances - id instRangeListE '(' cellpinList ')' { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, $4, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), - GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } - | id instRangeListE { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, nullptr, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), - GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } +instnameParen: + id instRangeListE '(' cellpinList ')' + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2); } + | id instRangeListE + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2); } //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP // // Adding above and switching to the Verilog-Perl syntax // // causes a shift conflict due to use of idClassSel inside exprScope. diff --git a/test_regress/t/t_interface_nansi.pl b/test_regress/t/t_interface_nansi.pl new file mode 100755 index 000000000..f60fd309f --- /dev/null +++ b/test_regress/t/t_interface_nansi.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-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_nansi.v b/test_regress/t/t_interface_nansi.v new file mode 100644 index 000000000..ef9d2d418 --- /dev/null +++ b/test_regress/t/t_interface_nansi.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +interface iface(input logic clk); + logic [31:0] d = 0; + logic [31:0] q = 0; +endinterface + +module mod(a); + iface a; // This is not a CELL, it is a port declaration + always @(posedge a.clk) a.q <= a.d; +endmodule + +module t(clk); + input clk; + + iface iface_inst(clk); + mod mod_inst(iface_inst); + + int cyc = 0; + + always @(posedge clk) begin + iface_inst.d <= cyc; + if (cyc > 1 && iface_inst.q != cyc - 2) $stop; + end + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 100) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From a372e010bda869f0768c2de86729ea2103001a87 Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 25 May 2022 04:51:51 +0000 Subject: [PATCH 38/68] Apply 'make format' --- src/verilog.y | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index af2b427d3..ea4161500 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -104,7 +104,8 @@ public: string newtext = deQuote(fileline, text); return new AstText(fileline, newtext); } - AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, AstNodeRange* rangelistp) { + AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, + AstNodeRange* rangelistp) { // Must clone m_instParamp as may be comma'ed list of instances VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(name); if (foundp && VN_IS(foundp->nodep(), Port)) { @@ -118,9 +119,12 @@ public: AstVar* const nodep = createVariable(fileline, name, rangelistp, nullptr); return nodep; } - AstCell* const nodep = new AstCell{fileline, GRAMMARP->m_instModuleFl, - name, GRAMMARP->m_instModule, pinlistp, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), + AstCell* const nodep = new AstCell{fileline, + GRAMMARP->m_instModuleFl, + name, + GRAMMARP->m_instModule, + pinlistp, + AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), GRAMMARP->scrubRange(rangelistp)}; nodep->trace(GRAMMARP->allTracingOn(fileline)); return nodep; From 0722f47539113382db67d94f46e28cb8b22c2a37 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 27 May 2022 16:57:51 +0100 Subject: [PATCH 39/68] Improve V3MergeCond by reordering statements (#3125) V3MergeCond merges consecutive conditional `_ = cond ? _ : _` and `if (cond) ...` statements. This patch adds an analysis and ordering phase that moves statements with identical conditions closer to each other, in order to enable more merging opportunities. This in turn eliminates a lot of repeated conditionals which reduced dynamic branch count and branch misprediction rate. Observed 6.5% improvement on multi-threaded large designs, at the cost of less than 2% increase in Verilation speed. --- Changes | 1 + src/V3AstUserAllocator.h | 2 +- src/V3MergeCond.cpp | 666 ++++++++++++++++++++------ test_regress/t/t_merge_cond.pl | 4 +- test_regress/t/t_merge_cond_blowup.pl | 34 ++ test_regress/t/t_merge_cond_blowup.v | 55 +++ 6 files changed, 602 insertions(+), 160 deletions(-) create mode 100755 test_regress/t/t_merge_cond_blowup.pl create mode 100644 test_regress/t/t_merge_cond_blowup.v diff --git a/Changes b/Changes index d6067565d..a0eb2b1d1 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 4.223 devel * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] +* Improve conditional merging optimization (#3125). [Geza Lore, Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] diff --git a/src/V3AstUserAllocator.h b/src/V3AstUserAllocator.h index d230f0829..8d63ad5a9 100644 --- a/src/V3AstUserAllocator.h +++ b/src/V3AstUserAllocator.h @@ -106,7 +106,7 @@ public: } // Get a reference to the user data - T_Data& operator()(const T_Node* nodep) { + T_Data& operator()(const T_Node* nodep) const { T_Data* const userp = getUserp(nodep); UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode"); return *userp; diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 673326f27..3881c48df 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -42,6 +42,34 @@ // // Also merges consecutive AstNodeIf statements with the same condition. // +// Because this optimization has notable performance impact, we go further +// and perform code motion to try to move mergeable conditionals next to each +// other, which in turn enable us to merge more conditionals. To do this, we +// perform an analysis pass, followed by an optimization pass on the whole +// AstCFunc we are optimizing. +// +// The analysis pass gathers, for each statement in the tree, the information +// relevant for determining whether two statements can be swapped, and some +// other additional information that is useful during optimization. +// +// The optimization pass tries to move conditionals near each other, first by +// trying to move a conditional node backwards in the list, so it becomes the +// direct successor of another earlier conditional with the same condition. +// If this is not possible due to variable interference, then we additionally +// try to pull earlier conditionals with the same condition closer forward to +// be the immediate predecessor of the conditional node. We limit maximum +// distance a node can travel to an empirically chosen but otherwise arbitrary +// constant. This limits worst case complexity to be O(n) rather than O(n^2). +// The worst case complexity manifests when N/2 conditionals, all with unique +// conditions are succeeded by N/2 conditionals with the same unique +// conditions, such that each unique condition is used by exactly 2 +// conditionals. In this case N/2 all nodes need to travel approx N/2 distance. +// Limiting the distance bounds the latter, hence limiting complexity. +// +// Once the analysis and optimization passes have been applied to the whole +// function, any merged conditionals will then undergo the same analysis, +// optimization, and merging again in their individual branches. +// //************************************************************************* #include "config_build.h" @@ -51,71 +79,364 @@ #include "V3MergeCond.h" #include "V3Stats.h" #include "V3Ast.h" +#include "V3AstUserAllocator.h" +#include "V3Hasher.h" +#include "V3DupFinder.h" + +#include +#include + +namespace { //###################################################################### +// Utilities -enum class Mergeable { - YES, // Tree can be merged - NO_COND_ASSIGN, // Tree cannot be merged because it contains an assignment to a condition - NO_IMPURE // Tree cannot be merged because it contains an impure node +// This function extracts the Cond node from the RHS of an assignment, +// if there is one and it is in a supported position, which are: +// - RHS is the Cond +// - RHS is And(Const, Cond). This And is inserted often by V3Clean. +AstNodeCond* extractCondFromRhs(AstNode* rhsp) { + if (AstNodeCond* const condp = VN_CAST(rhsp, NodeCond)) { + return condp; + } else if (const AstAnd* const andp = VN_CAST(rhsp, And)) { + if (AstNodeCond* const condp = VN_CAST(andp->rhsp(), NodeCond)) { + if (VN_IS(andp->lhsp(), Const)) return condp; + } + } + return nullptr; +} + +// Predicate to check if two sets are disjoint. This is stable, as we only need +// to determine if the sets contain a shared element, which is a boolean +// property. It is also efficient as we use sorted sets, and therefore can +// enumerate elements in order (what the ordering is, is unimportant), meaning +// the worst case complexity is O(size of smaller set). +bool areDisjoint(const std::set& a, const std::set& b) { + if (a.empty() || b.empty()) return true; + const auto endA = a.end(); + const auto endB = b.end(); + auto itA = a.begin(); + auto itB = b.begin(); + while (true) { + if (*itA == *itB) return false; + if (std::less{}(*itA, *itB)) { + itA = std::lower_bound(++itA, endA, *itB); + if (itA == endA) return true; + } else { + itB = std::lower_bound(++itB, endB, *itA); + if (itB == endB) return true; + } + } +} + +//###################################################################### +// Structure containing information required for code motion/merging + +struct StmtProperties { + AstNode* m_condp = nullptr; // The condition expression, if a conditional node + std::set m_rdVars; // Variables read by this statement + std::set m_wrVars; // Variables writen by this statement + bool m_isFence = false; // Nothing should move across this statement, nor should it be merged + AstNodeStmt* m_prevWithSameCondp = nullptr; // Previous node in same list, with same condition + bool writesConditionVar() const { + // This relies on MarkVarsVisitor having been called on the condition node + for (const AstVar* const varp : m_wrVars) { + if (varp->user1()) return true; + } + return false; + } }; -class CheckMergeableVisitor final : public VNVisitor { -private: - // STATE - bool m_condAssign = false; // Does this tree contain an assignment to a condition variable?? - bool m_impure = false; // Does this tree contain an impure node? +// We store the statement properties in user3 via AstUser3Allocator +using StmtPropertiesAllocator = AstUser3Allocator; - // METHODS - VL_DEBUG_FUNC; // Declare debug() +//###################################################################### +// Code motion analysis and implementation - // VISITORS - virtual void visit(AstNode* nodep) override { - if (m_impure) return; - // Clear if node is impure - if (!nodep->isPure()) { - UINFO(9, "Not mergeable due to impure node" << nodep << endl); - m_impure = true; - return; +// Pure analysis visitor that build the StmtProperties for each statement in the given +// AstNode list (following AstNode::nextp()) +class CodeMotionAnalysisVisitor final : public VNVisitor { + // NODE STATE + // AstNodeStmt::user3 -> StmtProperties (accessed via m_stmtProperties, managed externally, + // see MergeCondVisitor::process) + // AstNode::user4 -> Used by V3Hasher + // AstNode::user5 -> AstNode*: Set on a condition node, points to the last conditional + // with that condition so far encountered in the same AstNode list + + VNUser5InUse m_user5InUse; + + StmtPropertiesAllocator& m_stmtProperties; + + // MEMBERS + V3Hasher m_hasher; // Used by V3DupFinder + // Stack of a V3DupFinder used for finding identical condition expressions within one + // statement list. + std::vector m_stack; + StmtProperties* m_propsp = nullptr; // StmtProperties structure of current AstNodeStmt + + // Extract condition expression from a megeable conditional statement, if any + static AstNode* extractCondition(const AstNodeStmt* nodep) { + AstNode* conditionp = nullptr; + if (const AstNodeAssign* const assignp = VN_CAST(nodep, NodeAssign)) { + if (AstNodeCond* const conditionalp = extractCondFromRhs(assignp->rhsp())) { + conditionp = conditionalp->condp(); + } + } else if (const AstNodeIf* const ifp = VN_CAST(nodep, NodeIf)) { + conditionp = ifp->condp(); } + while (AstCCast* const castp = VN_CAST(conditionp, CCast)) conditionp = castp->lhsp(); + return conditionp; + } + + void analyzeStmt(AstNodeStmt* nodep, bool tryCondMatch) { + VL_RESTORER(m_propsp); + // Keep hold of props of enclosing statement + StmtProperties* const outerPropsp = m_propsp; + // Grab the props of this statement + m_propsp = &m_stmtProperties(nodep); + + // Extract condition from statement + if (AstNode* const condp = extractCondition(nodep)) { + // Remember condition node. We always need this as it is used in the later + // traversal. + m_propsp->m_condp = condp; + // If this is a conditional statement, try to find an earlier one with the same + // condition in the same list (unless we have been told not to bother because we know + // this node is in a singleton list). + if (tryCondMatch) { + // Grab the duplicate finder of this list + V3DupFinder& dupFinder = m_stack.back(); + // Find a duplicate condition + const V3DupFinder::iterator& dit = dupFinder.findDuplicate(condp); + if (dit == dupFinder.end()) { + // First time seeing this condition in the current list + dupFinder.insert(condp); + // Remember last statement with this condition (which is this statement) + condp->user5p(nodep); + } else { + // Seen a conditional with the same condition earlier in the current list + AstNode* const firstp = dit->second; + // Add to properties for easy retrieval during optimization + m_propsp->m_prevWithSameCondp = static_cast(firstp->user5p()); + // Remember last statement with this condition (which is this statement) + firstp->user5p(nodep); + } + } + } + + // Analyse this statement + analyzeNode(nodep); + + // If there is an enclosing statement, propagate properties upwards + if (outerPropsp) { + // Add all rd/wr vars to outer statement + outerPropsp->m_rdVars.insert(m_propsp->m_rdVars.cbegin(), m_propsp->m_rdVars.cend()); + outerPropsp->m_wrVars.insert(m_propsp->m_wrVars.cbegin(), m_propsp->m_wrVars.cend()); + // If this statement is impure, the enclosing statement is also impure + if (m_propsp->m_isFence) outerPropsp->m_isFence = true; + } + } + + void analyzeVarRef(AstVarRef* nodep) { + const VAccess access = nodep->access(); + AstVar* const varp = nodep->varp(); + // Gather read and written variables + if (access.isReadOrRW()) m_propsp->m_rdVars.insert(varp); + if (access.isWriteOrRW()) m_propsp->m_wrVars.insert(varp); + } + + void analyzeNode(AstNode* nodep) { + // If an impure node under a statement, mark that statement as impure + if (m_propsp && !nodep->isPure()) m_propsp->m_isFence = true; + // Analyze children iterateChildrenConst(nodep); } - virtual void visit(AstVarRef* nodep) override { - if (m_impure || m_condAssign) return; - // Clear if it's an LValue referencing a marked variable - if (nodep->access().isWriteOrRW() && nodep->varp()->user1()) { - UINFO(9, "Not mergeable due assignment to condition" << nodep << endl); - m_condAssign = true; + + // VISITORS + void visit(AstNode* nodep) override { + // Push a new stack entry at the start of a list, but only if the list is not a + // single element (this saves a lot of allocations in expressions) + bool singletonListStart = false; + if (nodep->backp()->nextp() != nodep) { // If at head of list + singletonListStart = nodep->nextp() == nullptr; + if (!singletonListStart) m_stack.emplace_back(m_hasher); } + + // Analyse node + if (AstNodeStmt* const stmtp = VN_CAST(nodep, NodeStmt)) { + analyzeStmt(stmtp, /*tryCondMatch:*/ !singletonListStart); + } else if (AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) { + analyzeVarRef(vrefp); + } else { + analyzeNode(nodep); + } + + // Pop the stack at the end of a list + if (!singletonListStart && !nodep->nextp()) m_stack.pop_back(); + } + + // CONSTRUCTOR + CodeMotionAnalysisVisitor(AstNode* nodep, StmtPropertiesAllocator& stmtProperties) + : m_stmtProperties(stmtProperties) { + iterateAndNextConstNull(nodep); } public: - CheckMergeableVisitor() = default; - - // Return false if this node should not be merged at all because: - // - It contains an impure expression - // - It contains an LValue referencing the condition - Mergeable operator()(const AstNode* node) { - m_condAssign = false; - m_impure = false; - iterateChildrenConst(const_cast(node)); - if (m_impure) { // Impure is stronger than cond assign - return Mergeable::NO_IMPURE; - } else if (m_condAssign) { - return Mergeable::NO_COND_ASSIGN; - } else { - return Mergeable::YES; - } + // Analyse the statement list starting at nodep, filling in stmtProperties. + static void analyze(AstNode* nodep, StmtPropertiesAllocator& stmtProperties) { + CodeMotionAnalysisVisitor{nodep, stmtProperties}; } }; +class CodeMotionOptimizeVisitor final : public VNVisitor { + // Do not move a node more than this many statements. + // This bounds complexity at O(N), rather than O(N^2). + static constexpr unsigned MAX_DISTANCE = 500; + + // NODE STATE + // AstNodeStmt::user3 -> StmtProperties (accessed via m_stmtProperties, managed externally, + // see MergeCondVisitor::process) + // AstNodeStmt::user4 -> bool: Already processed this node + + VNUser4InUse m_user4InUse; + + const StmtPropertiesAllocator& m_stmtProperties; + + // MEMBERS + + // Predicate that checks if the order of two statements can be swapped + bool areSwappable(const AstNodeStmt* ap, const AstNodeStmt* bp) const { + const StmtProperties& aProps = m_stmtProperties(ap); + const StmtProperties& bProps = m_stmtProperties(bp); + // Don't move across fences + if (aProps.m_isFence) return false; + if (bProps.m_isFence) return false; + // If either statement writes a variable that the other reads, they are not swappable + if (!areDisjoint(aProps.m_rdVars, bProps.m_wrVars)) return false; + if (!areDisjoint(bProps.m_rdVars, aProps.m_wrVars)) return false; + // If they both write to the same variable, they are not swappable + if (!areDisjoint(aProps.m_wrVars, bProps.m_wrVars)) return false; + // Otherwise good to go + return true; + } + + // VISITORS + void visit(AstNodeStmt* nodep) override { + // Process only on first encounter + if (nodep->user4SetOnce()) return; + // First re-order children + iterateChildren(nodep); + // Grab hold of previous node with same condition + AstNodeStmt* prevp = m_stmtProperties(nodep).m_prevWithSameCondp; + // If no previous node with same condition, we are done + if (!prevp) return; +#ifdef VL_DEBUG + { // Sanity check, only in debug build, otherwise expensive + const AstNode* currp = prevp; + while (currp && currp != nodep) currp = currp->nextp(); + UASSERT_OBJ(currp, nodep, "Predecessor not in same list as " << currp); + } +#endif + // Otherwise try to move this node backwards, as close as we can to the previous node + // with the same condition + if (AstNodeStmt* predp = VN_CAST(nodep->backp(), NodeStmt)) { + // 'predp' is the newly computed predecessor node of 'nodep', which is initially + // (without movement) the 'backp' of the node. + for (unsigned i = MAX_DISTANCE; i; --i) { + // If the predecessor is the previous node with the same condition, job done + if (predp == prevp) break; + // Don't move past a non-statement (e.g.: AstVar), or end of list + AstNodeStmt* const backp = VN_CAST(predp->backp(), NodeStmt); + if (!backp) break; + // Don't swap statements if doing so would change program semantics + if (!areSwappable(predp, nodep)) break; + // Otherwise move 'nodep' back + predp = backp; + } + + // If we decided that 'nodep' should be moved back + if (nodep->backp() != predp) { + // Move the current node to directly follow the computed predecessor + nodep->unlinkFrBack(); + predp->addNextHere(nodep); + // If the predecessor is the previous node with the same condition, job done + if (predp == prevp) return; + } + } + // If we reach here, it means we were unable to move the current node all the way back + // such that it immediately follows the previous statement with the same condition. Now + // try to move all previous statements with the same condition forward, in the hope of + // compacting the list further. + for (AstNodeStmt* currp = nodep; prevp; + currp = prevp, prevp = m_stmtProperties(currp).m_prevWithSameCondp) { + // Move prevp (previous statement with same condition) towards currp + if (AstNodeStmt* succp = VN_CAST(prevp->nextp(), NodeStmt)) { + // 'succp' is the newly computed successor node of 'prevp', which is initially + // (without movement) the 'nextp' of the node. + for (unsigned i = MAX_DISTANCE; --i;) { + // If the successor of the previous statement with same condition is the + // target node, we are done with this predecessor + if (succp == currp) break; + // Don't move past a non-statement (e.g.: AstVar), or end of list + AstNodeStmt* const nextp = VN_CAST(succp->nextp(), NodeStmt); + if (!nextp) break; + // Don't swap statements if doing so would change program semantics + if (!areSwappable(prevp, succp)) break; + // Otherwise move further forward + succp = nextp; + } + + // If we decided that 'prevp' should be moved forward + if (prevp->nextp() != succp) { + // Move the current node to directly before the computed successor + prevp->unlinkFrBack(); + succp->addHereThisAsNext(prevp); + } + } + } + } + + void visit(AstNode* nodep) override {} // Ignore all non-statements + + // CONSTRUCTOR + CodeMotionOptimizeVisitor(AstNode* nodep, const StmtPropertiesAllocator& stmtProperties) + : m_stmtProperties(stmtProperties) { + // We assert the given node is at the head of the list otherwise we might move a node + // before the given node. This is easy to fix in the above iteration with a check on a + // boundary node we should not move past, if we ever need to do so. + // Note: we will do iterateAndNextNull which requires nodep->backp() != nullptr anyway + UASSERT_OBJ(nodep->backp()->nextp() != nodep, nodep, "Must be at head of list"); + // Optimize the list + iterateAndNextNull(nodep); + } + +public: + // Given an AstNode list (held via AstNode::nextp()), move conditional statements as close + // together as possible + static AstNode* optimize(AstNode* nodep, const StmtPropertiesAllocator& stmtProperties) { + CodeMotionOptimizeVisitor{nodep, stmtProperties}; + // It is possible for the head of the list to be moved later such that it is no longer + // in head position. If so, rewind the list and return the new head. + while (nodep->backp()->nextp() == nodep) nodep = nodep->backp(); + return nodep; + } +}; + +//###################################################################### +// Conditional merging + class MergeCondVisitor final : public VNVisitor { private: // NODE STATE - // AstVar::user1 -> Flag set for variables referenced by m_mgCondp - // AstNode::user2 -> Flag marking node as included in merge because cheap to duplicate - const VNUser1InUse m_user1InUse; - const VNUser2InUse m_user2InUse; + // AstVar::user1 -> bool: Set for variables referenced by m_mgCondp + // (Only below MergeCondVisitor::process). + // AstNode::user2 -> bool: Marking node as included in merge because cheap to + // duplicate + // (Only below MergeCondVisitor::process). + // AstNodeStmt::user3 -> StmtProperties + // (Only below MergeCondVisitor::process). + // AstNode::user4 -> See CodeMotionAnalysisVisitor/CodeMotionOptimizeVisitor + // AstNode::user5 -> See CodeMotionAnalysisVisitor // STATE VDouble0 m_statMerges; // Statistic tracking @@ -128,24 +449,84 @@ private: const AstNode* m_mgNextp = nullptr; // Next node in list being examined uint32_t m_listLenght = 0; // Length of current list - CheckMergeableVisitor m_checkMergeable; // Sub visitor for encapsulation & speed + std::queue* m_workQueuep = nullptr; // Node lists (via AstNode::nextp()) to merge + // Statement properties for code motion and merging + StmtPropertiesAllocator* m_stmtPropertiesp = nullptr; // METHODS VL_DEBUG_FUNC; // Declare debug() - // This function extracts the Cond node from the RHS, if there is one and - // it is in a supported position, which are: - // - RHS is the Cond - // - RHS is And(Const, Cond). This And is inserted often by V3Clean. - static AstNodeCond* extractCond(AstNode* rhsp) { - if (AstNodeCond* const condp = VN_CAST(rhsp, NodeCond)) { - return condp; - } else if (const AstAnd* const andp = VN_CAST(rhsp, And)) { - if (AstNodeCond* const condp = VN_CAST(andp->rhsp(), NodeCond)) { - if (VN_IS(andp->lhsp(), Const)) return condp; - } + // Function that processes a whole sub-tree + void process(AstNode* nodep) { + // Set up work queue + std::queue workQueue; + m_workQueuep = &workQueue; + m_workQueuep->push(nodep); + + do { + // Set up user* for this iteration + const VNUser1InUse user1InUse; + const VNUser2InUse user2InUse; + const VNUser3InUse user3InUse; + // Statement properties only preserved for this iteration, + // then memory is released immediately. + StmtPropertiesAllocator stmtProperties; + m_stmtPropertiesp = &stmtProperties; + + // Pop off current work item + AstNode* currp = m_workQueuep->front(); + m_workQueuep->pop(); + + // Analyse sub-tree list for code motion + CodeMotionAnalysisVisitor::analyze(currp, stmtProperties); + // Perform the code motion within the whole sub-tree list + currp = CodeMotionOptimizeVisitor::optimize(currp, stmtProperties); + + // Merge conditionals in the whole sub-tree list (this might create new work items) + iterateAndNextNull(currp); + + // Close pending merge, if there is one at the end of the whole sub-tree list + if (m_mgFirstp) mergeEnd(); + } while (!m_workQueuep->empty()); + } + + // Skip past AstArraySel and AstWordSel with const index + static AstNode* skipConstSels(AstNode* nodep) { + while (const AstArraySel* const aselp = VN_CAST(nodep, ArraySel)) { + // ArraySel index is not constant, so might be expensive + if (!VN_IS(aselp->bitp(), Const)) return nodep; + nodep = aselp->fromp(); } - return nullptr; + while (const AstWordSel* const wselp = VN_CAST(nodep, WordSel)) { + // WordSel index is not constant, so might be expensive + if (!VN_IS(wselp->bitp(), Const)) return nodep; + nodep = wselp->fromp(); + } + return nodep; + } + + // Check if this node is cheap enough that duplicating it in two branches of an + // AstIf is not likely to cause a performance degradation. + static bool isCheapNode(AstNode* nodep) { + // Comments are cheap + if (VN_IS(nodep, Comment)) return true; + // So are some assignments + if (const AstNodeAssign* const assignp = VN_CAST(nodep, NodeAssign)) { + // Check LHS + AstNode* const lhsp = skipConstSels(assignp->lhsp()); + // LHS is not a VarRef, so might be expensive + if (!VN_IS(lhsp, VarRef)) return false; + + // Check RHS + AstNode* const rhsp = skipConstSels(assignp->rhsp()); + // RHS is not a VarRef or Constant so might be expensive + if (!VN_IS(rhsp, VarRef) && !VN_IS(rhsp, Const)) return false; + + // Otherwise it is a cheap assignment + return true; + } + // Others are not + return false; } // Predicate to check if an expression yields only 0 or 1 (i.e.: a 1-bit value) @@ -196,23 +577,21 @@ private: static AstNode* maskLsb(AstNode* nodep) { if (yieldsOneOrZero(nodep)) return nodep; // Otherwise apply masking - AstNode* const maskp = new AstConst(nodep->fileline(), AstConst::BitTrue()); + AstNode* const maskp = new AstConst{nodep->fileline(), AstConst::BitTrue()}; // Mask on left, as conventional - return new AstAnd(nodep->fileline(), maskp, nodep); + return new AstAnd{nodep->fileline(), maskp, nodep}; } - // Fold the RHS expression assuming the given condition state. Unlink bits - // from the RHS which is only used once, and can be reused. What remains - // of the RHS is expected to be deleted by the caller. + // Fold the RHS expression of an assignment assuming the given condition state. + // Unlink bits from the RHS which is only used once, and can be reused (is an unomdified + // sub-tree). What remains of the RHS is expected to be deleted by the caller. AstNode* foldAndUnlink(AstNode* rhsp, bool condTrue) { if (rhsp->sameTree(m_mgCondp)) { - return new AstConst(rhsp->fileline(), AstConst::BitTrue{}, condTrue); - } else if (const AstNodeCond* const condp = extractCond(rhsp)) { + return new AstConst{rhsp->fileline(), AstConst::BitTrue{}, condTrue}; + } else if (const AstNodeCond* const condp = extractCondFromRhs(rhsp)) { AstNode* const resp = condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack(); - if (condp == rhsp) { // - return resp; - } + if (condp == rhsp) return resp; if (const AstAnd* const andp = VN_CAST(rhsp, And)) { UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this"); return new AstAnd{andp->fileline(), andp->lhsp()->cloneTree(false), resp}; @@ -227,17 +606,18 @@ private: return condTrue ? maskLsb(andp->lhsp()->unlinkFrBack()) : new AstConst{rhsp->fileline(), AstConst::BitFalse()}; } - } else if (VN_IS(rhsp, WordSel) || VN_IS(rhsp, VarRef) || VN_IS(rhsp, Const)) { + } else if (VN_IS(rhsp, ArraySel) || VN_IS(rhsp, WordSel) || VN_IS(rhsp, VarRef) + || VN_IS(rhsp, Const)) { return rhsp->cloneTree(false); } - rhsp->dumpTree("Don't know how to fold expression: "); - rhsp->v3fatalSrc("Don't know how to fold expression"); + // LCOV_EXCL_START + if (debug()) rhsp->dumpTree("Don't know how to fold expression: "); + rhsp->v3fatalSrc("Should not try to fold this during conditional merging"); + // LCOV_EXCL_STOP } - void mergeEnd(int lineno) { - UASSERT(m_mgFirstp, "mergeEnd without list " << lineno); - // We might want to recursively merge an AstIf. We stash it in this variable. - const AstNodeIf* recursivep = nullptr; + void mergeEnd() { + UASSERT(m_mgFirstp, "mergeEnd without list"); // Drop leading cheap nodes. These were only added in the hope of finding // an earlier reduced form, but we failed to do so. while (m_mgFirstp->user2() && m_mgFirstp != m_mgLastp) { @@ -254,8 +634,11 @@ private: m_mgLastp = m_mgLastp->backp(); --m_listLenght; UASSERT_OBJ(m_mgLastp && m_mgLastp->nextp() == nextp, m_mgFirstp, - "Cheap assignment should not be at the front of the list"); + "Cheap statement should not be at the front of the list"); } + // If the list contains a single AstNodeIf, we will want to merge its branches. + // If so, keep hold of the AstNodeIf in this variable. + AstNodeIf* recursivep = nullptr; // Merge if list is longer than one node if (m_mgFirstp != m_mgLastp) { UINFO(6, "MergeCond - First: " << m_mgFirstp << " Last: " << m_mgLastp << endl); @@ -266,7 +649,7 @@ private: // and we also need to keep track of it for comparisons later. m_mgCondp = m_mgCondp->cloneTree(false); // Create equivalent 'if' statement and insert it before the first node - AstIf* const resultp = new AstIf(m_mgCondp->fileline(), m_mgCondp); + AstIf* const resultp = new AstIf{m_mgCondp->fileline(), m_mgCondp}; m_mgFirstp->addHereThisAsNext(resultp); // Unzip the list and insert under branches AstNode* nextp = m_mgFirstp; @@ -308,10 +691,12 @@ private: VL_DO_DANGLING(ifp->deleteTree(), ifp); } } while (nextp); - // Recursively merge the resulting AstIf - recursivep = resultp; - } else if (const AstNodeIf* const ifp = VN_CAST(m_mgFirstp, NodeIf)) { - // There was nothing to merge this AstNodeIf with, but try to merge it's branches + // Merge the branches of the resulting AstIf after re-analysis + if (resultp->ifsp()) m_workQueuep->push(resultp->ifsp()); + if (resultp->elsesp()) m_workQueuep->push(resultp->elsesp()); + } else if (AstNodeIf* const ifp = VN_CAST(m_mgFirstp, NodeIf)) { + // There was nothing to merge this AstNodeIf with, so try to merge its branches. + // No re-analysis is required for this, so do it directly below recursivep = ifp; } // Reset state @@ -321,14 +706,13 @@ private: m_mgNextp = nullptr; AstNode::user1ClearTree(); // Clear marked variables AstNode::user2ClearTree(); - // Merge recursively within the branches + // Merge recursively within the branches of an un-merged AstNodeIF if (recursivep) { iterateAndNextNull(recursivep->ifsp()); - // Close list, if there is one at the end of the then branch - if (m_mgFirstp) mergeEnd(__LINE__); iterateAndNextNull(recursivep->elsesp()); - // Close list, if there is one at the end of the else branch - if (m_mgFirstp) mergeEnd(__LINE__); + // Close a pending merge to ensure merge state is + // reset as expected at the end of this function + if (m_mgFirstp) mergeEnd(); } } @@ -351,47 +735,16 @@ private: return false; } - // Check if this node is cheap enough that duplicating it in two branches of an - // AstIf and is hence not likely to cause a performance degradation if doing so. - bool isCheapNode(AstNode* nodep) const { - if (VN_IS(nodep, Comment)) return true; - if (const AstNodeAssign* const assignp = VN_CAST(nodep, NodeAssign)) { - // Check LHS - AstNode* lhsp = assignp->lhsp(); - while (AstWordSel* const wselp = VN_CAST(lhsp, WordSel)) { - // WordSel index is not constant, so might be expensive - if (!VN_IS(wselp->bitp(), Const)) return false; - lhsp = wselp->fromp(); - } - // LHS is not a VarRef, so might be expensive - if (!VN_IS(lhsp, VarRef)) return false; - - // Check RHS - AstNode* rhsp = assignp->rhsp(); - while (AstWordSel* const wselp = VN_CAST(rhsp, WordSel)) { - // WordSel index is not constant, so might be expensive - if (!VN_IS(wselp->bitp(), Const)) return false; - rhsp = wselp->fromp(); - } - // RHS is not a VarRef or Constant so might be expensive - if (!VN_IS(rhsp, VarRef) && !VN_IS(rhsp, Const)) return false; - - // Otherwise it is a cheap assignment - return true; - } - return false; - } - - bool addToList(AstNode* nodep, AstNode* condp, int line) { + bool addToList(AstNodeStmt* nodep, AstNode* condp) { // Set up head of new list if node is first in list if (!m_mgFirstp) { - UASSERT_OBJ(condp, nodep, "Cannot start new list without condition " << line); + UASSERT_OBJ(condp, nodep, "Cannot start new list without condition"); // Mark variable references in the condition condp->foreach([](const AstVarRef* nodep) { nodep->varp()->user1(1); }); // Now check again if mergeable. We need this to pick up assignments to conditions, // e.g.: 'c = c ? a : b' at the beginning of the list, which is in fact not mergeable // because it updates the condition. We simply bail on these. - if (m_checkMergeable(nodep) != Mergeable::YES) { + if ((*m_stmtPropertiesp)(nodep).writesConditionVar()) { // Clear marked variables AstNode::user1ClearTree(); // We did not add to the list @@ -400,11 +753,13 @@ private: m_mgFirstp = nodep; m_mgCondp = condp; m_listLenght = 0; - // Add any preceding nodes to the list that would allow us to extend the merge range - for (;;) { - AstNode* const backp = m_mgFirstp->backp(); + // Add any preceding nodes to the list that would allow us to extend the merge + // range + while (true) { + AstNodeStmt* const backp = VN_CAST(m_mgFirstp->backp(), NodeStmt); if (!backp || backp->nextp() != m_mgFirstp) break; // Don't move up the tree - if (m_checkMergeable(backp) != Mergeable::YES) break; + const StmtProperties& props = (*m_stmtPropertiesp)(backp); + if (props.m_isFence || props.writesConditionVar()) break; if (isSimplifiableNode(backp)) { ++m_listLenght; m_mgFirstp = backp; @@ -424,59 +779,53 @@ private: // Set up expected next node in list. m_mgNextp = nodep->nextp(); // If last under parent, done with current list - if (!m_mgNextp) mergeEnd(__LINE__); + if (!m_mgNextp) mergeEnd(); // We did add to the list return true; } // If this node is the next expected node and is helpful to add to the list, do so, // otherwise end the current merge. Return ture if added, false if ended merge. - bool addIfHelpfulElseEndMerge(AstNode* nodep) { + bool addIfHelpfulElseEndMerge(AstNodeStmt* nodep) { UASSERT_OBJ(m_mgFirstp, nodep, "List must be open"); if (m_mgNextp == nodep) { if (isSimplifiableNode(nodep)) { - if (addToList(nodep, nullptr, __LINE__)) return true; + if (addToList(nodep, nullptr)) return true; } else if (isCheapNode(nodep)) { nodep->user2(1); - if (addToList(nodep, nullptr, __LINE__)) return true; + if (addToList(nodep, nullptr)) return true; } } // Not added to list, so we are done with the current list - mergeEnd(__LINE__); + mergeEnd(); return false; } - bool checkOrMakeMergeable(AstNode* nodep) { - const Mergeable reason = m_checkMergeable(nodep); - // If meregeable, we are done - if (reason == Mergeable::YES) return true; - // Node not mergeable. - // If no current list, then this node is just special, move on. - if (!m_mgFirstp) return false; - // Otherwise finish current list - mergeEnd(__LINE__); - // If a tree was not mergeable due to an assignment to a condition, - // then finishing the current list makes it mergeable again. - return reason == Mergeable::NO_COND_ASSIGN; + bool checkOrMakeMergeable(const AstNodeStmt* nodep) { + const StmtProperties& props = (*m_stmtPropertiesp)(nodep); + if (props.m_isFence) return false; // Fence node never mergeable + // If the statement writes a condition variable of a pending merge, + // we must end the pending merge + if (m_mgFirstp && props.writesConditionVar()) mergeEnd(); + return true; // Now surely mergeable } - void mergeEndIfIncompatible(AstNode* nodep, AstNode* condp) { + void mergeEndIfIncompatible(const AstNode* nodep, const AstNode* condp) { if (m_mgFirstp && (m_mgNextp != nodep || !condp->sameTree(m_mgCondp))) { // Node in different list, or has different condition. Finish current list. - mergeEnd(__LINE__); + mergeEnd(); } } // VISITORS virtual void visit(AstNodeAssign* nodep) override { - AstNode* const rhsp = nodep->rhsp(); - if (const AstNodeCond* const condp = extractCond(rhsp)) { + if (AstNode* const condp = (*m_stmtPropertiesp)(nodep).m_condp) { // Check if mergeable if (!checkOrMakeMergeable(nodep)) return; // Close potentially incompatible pending merge - mergeEndIfIncompatible(nodep, condp->condp()); + mergeEndIfIncompatible(nodep, condp); // Add current node - addToList(nodep, condp->condp(), __LINE__); + addToList(nodep, condp); } else if (m_mgFirstp) { addIfHelpfulElseEndMerge(nodep); } @@ -493,21 +842,22 @@ private: // Close potentially incompatible pending merge mergeEndIfIncompatible(nodep, nodep->condp()); // Add current node - addToList(nodep, nodep->condp(), __LINE__); + addToList(nodep, nodep->condp()); + } + + virtual void visit(AstNodeStmt* nodep) override { + if (m_mgFirstp && addIfHelpfulElseEndMerge(nodep)) return; + iterateChildren(nodep); + } + + virtual void visit(AstCFunc* nodep) override { + // Merge function body + if (nodep->stmtsp()) process(nodep->stmtsp()); } // For speed, only iterate what is necessary. virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); } virtual void visit(AstNodeModule* nodep) override { iterateAndNextNull(nodep->stmtsp()); } - virtual void visit(AstCFunc* nodep) override { - iterateChildren(nodep); - // Close list, if there is one at the end of the function - if (m_mgFirstp) mergeEnd(__LINE__); - } - virtual void visit(AstNodeStmt* nodep) override { - if (m_mgFirstp && addIfHelpfulElseEndMerge(nodep)) return; - iterateChildren(nodep); - } virtual void visit(AstNode* nodep) override {} public: @@ -520,6 +870,8 @@ public: } }; +} // namespace + //###################################################################### // MergeConditionals class functions diff --git a/test_regress/t/t_merge_cond.pl b/test_regress/t/t_merge_cond.pl index 51f97242d..971a808af 100755 --- a/test_regress/t/t_merge_cond.pl +++ b/test_regress/t/t_merge_cond.pl @@ -21,11 +21,11 @@ execute( if ($Self->{vlt}) { # Note, with vltmt this might be split differently, so only checking vlt file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i, - 10); + 9); file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, 580); file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, - 64); + 128); } ok(1); diff --git a/test_regress/t/t_merge_cond_blowup.pl b/test_regress/t/t_merge_cond_blowup.pl new file mode 100755 index 000000000..aa9e8e1fe --- /dev/null +++ b/test_regress/t/t_merge_cond_blowup.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. 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); + +# TODO: This takes excessively long on vltmt, this should be fixed + +compile( + verilator_flags2 => ["--unroll-count 1000000000", "--output-split 0", "--stats"], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i, + 500); # V3MergeCond.cpp MAX_DISTANCE + file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, + 1000); # V3MergeCond.cpp MAX_DISTANCE *2 + file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, + 2); +} + +ok(1); +1; diff --git a/test_regress/t/t_merge_cond_blowup.v b/test_regress/t/t_merge_cond_blowup.v new file mode 100644 index 000000000..aa97f8f26 --- /dev/null +++ b/test_regress/t/t_merge_cond_blowup.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + localparam int N = 4096; + + integer cyc = 0; + reg [63:0] crc= 64'h5aef0c8d_d70a4497; + + always @ (posedge clk) begin + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + + if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + reg a [N-1:0]; + reg b [N-1:0]; + + // This yields pathological complexity for the current conditional merging + // algorithm. Note in practice, other parts of the compiler blow up on this + // code far earlier than the conditional merging, but here we go anyway. + generate + genvar i; + for (i = 0 ; i < N ; i = i + 1) begin + always @(posedge clk) a[i] <= (crc + 64'(i)) == 0 ? crc[(i+16)%64] : crc[(i+32)%64]; + end + for (i = 0 ; i < N ; i = i + 1) begin + always @(posedge clk) b[i] <= (crc + 64'(i)) == 0 ? crc[(i+16)%64] : crc[(i+32)%64]; + end + endgenerate + + always @(posedge clk) begin + if (cyc >= 2) begin + for (int i = 0 ; i < N ; i = i + 1) begin + if (a[i] !== b[i]) begin + $write("%%Error: %s:%0d: cyc=%0d i=%0d a[i]='h%x b[i]='h%x\n", `__FILE__,`__LINE__, cyc, i, a[i], b[i]); + $stop; + end + end + end + end + +endmodule From d45caca011b70e3468289254ccbb000604e8e603 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 28 May 2022 12:07:24 +0100 Subject: [PATCH 40/68] Remove legacy VCD tracing API This has not been used by Verilator for a while, but was kept for compatibility with some external code. Now removed. --- include/verilated_trace_imp.cpp | 37 --- include/verilated_vcd_c.cpp | 279 ---------------------- include/verilated_vcd_c.h | 160 ------------- test_regress/t/t_trace_c_api.cpp | 24 -- test_regress/t/t_trace_c_api.pl | 30 --- test_regress/t/t_trace_c_api.v | 8 - test_regress/t/t_trace_complex_old_api.pl | 39 --- 7 files changed, 577 deletions(-) delete mode 100644 test_regress/t/t_trace_c_api.cpp delete mode 100755 test_regress/t/t_trace_c_api.pl delete mode 100644 test_regress/t/t_trace_c_api.v delete mode 100755 test_regress/t/t_trace_complex_old_api.pl diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 7a98b7abf..dac31ddac 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -725,41 +725,4 @@ static inline void cvtQDataToStr(char* dstp, QData value) { #define cvtEDataToStr cvtIDataToStr -//============================================================================= - -#ifdef VERILATED_VCD_TEST - -void verilated_trace_imp_selftest() { -#define SELF_CHECK(got, exp) \ - do { \ - if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest"); \ - } while (0) - -#define SELF_CHECK_TS(scale) \ - SELF_CHECK(doubleToTimescale(timescaleToDouble(scale)), std::string{scale}); - SELF_CHECK_TS("100s"); - SELF_CHECK_TS("10s"); - SELF_CHECK_TS("1s"); - SELF_CHECK_TS("100ms"); - SELF_CHECK_TS("10ms"); - SELF_CHECK_TS("1ms"); - SELF_CHECK_TS("100us"); - SELF_CHECK_TS("10us"); - SELF_CHECK_TS("1us"); - SELF_CHECK_TS("100ns"); - SELF_CHECK_TS("10ns"); - SELF_CHECK_TS("1ns"); - SELF_CHECK_TS("100ps"); - SELF_CHECK_TS("10ps"); - SELF_CHECK_TS("1ps"); - SELF_CHECK_TS("100fs"); - SELF_CHECK_TS("10fs"); - SELF_CHECK_TS("1fs"); - SELF_CHECK_TS("100as"); - SELF_CHECK_TS("10as"); - SELF_CHECK_TS("1as"); -} - -#endif - #endif // VL_CPPCHECK diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 78383befc..d2417bc3e 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -562,23 +562,6 @@ void VerilatedVcd::declArray(uint32_t code, const char* name, bool array, int ar void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int arraynum) { declare(code, name, "real", array, arraynum, false, false, 63, 0); } -#ifdef VL_TRACE_VCD_OLD_API -void VerilatedVcd::declTriBit(uint32_t code, const char* name, bool array, int arraynum) { - declare(code, name, "wire", array, arraynum, true, false, 0, 0); -} -void VerilatedVcd::declTriBus(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { - declare(code, name, "wire", array, arraynum, true, true, msb, lsb); -} -void VerilatedVcd::declTriQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { - declare(code, name, "wire", array, arraynum, true, true, msb, lsb); -} -void VerilatedVcd::declTriArray(uint32_t code, const char* name, bool array, int arraynum, int msb, - int lsb) { - declare(code, name, "wire", array, arraynum, true, true, msb, lsb); -} -#endif // VL_TRACE_VCD_OLD_API //============================================================================= // Trace rendering prinitives @@ -689,265 +672,3 @@ void VerilatedVcd::emitDouble(uint32_t code, double newval) { wp += std::strlen(wp); finishLine(code, wp); } - -#ifdef VL_TRACE_VCD_OLD_API - -void VerilatedVcd::fullBit(uint32_t code, const uint32_t newval) { - // Note the &1, so we don't require clean input -- makes more common no change case faster - *oldp(code) = newval; - *m_writep++ = ('0' + static_cast(newval & 1)); - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullBus(uint32_t code, const uint32_t newval, int bits) { - *oldp(code) = newval; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval & (1L << bit)) ? '1' : '0'); - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullQuad(uint32_t code, const uint64_t newval, int bits) { - (*(reinterpret_cast(oldp(code)))) = newval; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval & (1ULL << bit)) ? '1' : '0'); - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullArray(uint32_t code, const uint32_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { oldp(code)[word] = newval[word]; } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0'); - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullArray(uint32_t code, const uint64_t* newval, int bits) { - for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = ((newval[(bit / 64)] & (1ULL << (bit & 0x3f))) ? '1' : '0'); - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullTriBit(uint32_t code, const uint32_t newval, const uint32_t newtri) { - oldp(code)[0] = newval; - oldp(code)[1] = newtri; - *m_writep++ = "01zz"[newval | (newtri << 1)]; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullTriBus(uint32_t code, const uint32_t newval, const uint32_t newtri, - int bits) { - oldp(code)[0] = newval; - oldp(code)[1] = newtri; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)]; - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullTriQuad(uint32_t code, const uint64_t newval, const uint64_t newtri, - int bits) { - (*(reinterpret_cast(oldp(code)))) = newval; - (*(reinterpret_cast(oldp(code + 1)))) = newtri; - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - *m_writep++ = "01zz"[((newval >> bit) & 1ULL) | (((newtri >> bit) & 1ULL) << 1ULL)]; - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullTriArray(uint32_t code, const uint32_t* newvalp, const uint32_t* newtrip, - int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - oldp(code)[word * 2] = newvalp[word]; - oldp(code)[word * 2 + 1] = newtrip[word]; - } - *m_writep++ = 'b'; - for (int bit = bits - 1; bit >= 0; --bit) { - uint32_t valbit = (newvalp[(bit / 32)] >> (bit & 0x1f)) & 1; - uint32_t tribit = (newtrip[(bit / 32)] >> (bit & 0x1f)) & 1; - *m_writep++ = "01zz"[valbit | (tribit << 1)]; - } - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} -void VerilatedVcd::fullDouble(uint32_t code, const double newval) { - // cppcheck-suppress invalidPointerCast - (*(reinterpret_cast(oldp(code)))) = newval; - // Buffer can't overflow before VL_SNPRINTF; we sized during declaration - VL_SNPRINTF(m_writep, m_wrChunkSize, "r%.16g", newval); - m_writep += std::strlen(m_writep); - *m_writep++ = ' '; - m_writep = writeCode(m_writep, code); - *m_writep++ = '\n'; - bufferCheck(); -} - -#endif // VL_TRACE_VCD_OLD_API - -//====================================================================== -//====================================================================== -//====================================================================== - -#ifdef VERILATED_VCD_TEST -#include - -extern void verilated_trace_imp_selftest(); - -uint32_t v1, v2, s1, s2[3]; -uint32_t tri96[3]; -uint32_t tri96__tri[3]; -uint64_t quad96[2]; -uint64_t tquad; -uint64_t tquad__tri; -uint8_t ch; -uint64_t timestamp = 1; -double doub = 0.0; -float flo = 0.0f; - -void vcdInit(void*, VerilatedVcd* vcdp, uint32_t) { - vcdp->scopeEscape('.'); - vcdp->pushNamePrefix("top."); - /**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1); - /**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1); - /**/ vcdp->pushNamePrefix("sub1."); - /***/ vcdp->declBit(0x4, "s1", -1, 0); - /***/ vcdp->declBit(0x5, "ch", -1, 0); - /**/ vcdp->popNamePrefix(); - /**/ vcdp->pushNamePrefix("sub2."); - /***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3); - /**/ vcdp->popNamePrefix(); - vcdp->popNamePrefix(); - // Note need to add 3 for next code. - vcdp->pushNamePrefix("top2."); - /**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1); - /**/ vcdp->declTriBit(0x10, "io1", -1, 0); - /**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0); - /**/ vcdp->declTriArray(0x16, "io96", -1, 0, 95, 0); - /**/ // Note need to add 6 for next code. - /**/ vcdp->declDouble(0x1c, "doub", -1, 0); - /**/ // Note need to add 2 for next code. - /**/ vcdp->declArray(0x20, "q2", -1, 0, 95, 0); - /**/ // Note need to add 4 for next code. - /**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0); - /**/ // Note need to add 4 for next code. - vcdp->popNamePrefix(); -} - -void vcdFull(void*, VerilatedVcd* vcdp) { - vcdp->fullBus(0x2, v1, 5); - vcdp->fullBus(0x3, v2, 7); - vcdp->fullBit(0x4, s1); - vcdp->fullBus(0x5, ch, 2); - vcdp->fullArray(0x6, &s2[0], 38); - vcdp->fullTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1); - vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); - vcdp->fullTriArray(0x16, tri96, tri96__tri, 96); - vcdp->fullDouble(0x1c, doub); - vcdp->fullArray(0x20, &quad96[0], 96); - vcdp->fullTriQuad(0x24, tquad, tquad__tri, 64); -} - -void vcdChange(void*, VerilatedVcd* vcdp) { - vcdp->chgBus(0x2, v1, 5); - vcdp->chgBus(0x3, v2, 7); - vcdp->chgBit(0x4, s1); - vcdp->chgBus(0x5, ch, 2); - vcdp->chgArray(0x6, &s2[0], 38); - vcdp->chgTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1); - vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); - vcdp->chgTriArray(0x16, tri96, tri96__tri, 96); - vcdp->chgDouble(0x1c, doub); - vcdp->chgArray(0x20, &quad96[0], 96); - vcdp->chgTriQuad(0x24, tquad, tquad__tri, 64); -} - -// clang-format off -void vcdTestMain(const char* filenamep) { - verilated_trace_imp_selftest(); - - v1 = v2 = s1 = 0; - s2[0] = s2[1] = s2[2] = 0; - tri96[2] = tri96[1] = tri96[0] = 0; - tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; - quad96[1] = quad96[0] = 0; - ch = 0; - doub = 0; - tquad = tquad__tri = 0; - { - VerilatedVcdC* vcdp = new VerilatedVcdC; - vcdp->evcd(true); - vcdp->set_time_unit("1ms"); - vcdp->set_time_unit(std::string{"1ms"}); - vcdp->set_time_resolution("1ns"); - vcdp->set_time_resolution(std::string{"1ns"}); - vcdp->spTrace()->addInitCb(&vcdInit, 0); - vcdp->spTrace()->addFullCb(&vcdFull, 0); - vcdp->spTrace()->addChgCb(&vcdChange, 0); - vcdp->open(filenamep); - // Dumping - vcdp->dump(++timestamp); - v1 = 0xfff; - tri96[2] = 4; tri96[1] = 2; tri96[0] = 1; - tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri - quad96[1] = 0xffffffff; quad96[0] = 0; - doub = 1.5; - flo = 1.4f; - vcdp->dump(++timestamp); - v2 = 0x1; - s2[1] = 2; - tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change - quad96[1] = 0; quad96[0] = ~0; - doub = -1.66e13; - flo = 0.123f; - tquad = 0x00ff00ff00ff00ffULL; - tquad__tri = 0x0000fffff0000ffffULL; - vcdp->dump(++timestamp); - ch = 2; - tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1; - doub = -3.33e-13; - vcdp->dump(++timestamp); - vcdp->dump(++timestamp); -# ifdef VERILATED_VCD_TEST_64BIT - const uint64_t bytesPerDump = 15ULL; - for (uint64_t i = 0; i < ((1ULL << 32) / bytesPerDump); i++) { - v1 = i; - vcdp->dump(++timestamp); - } -# endif - vcdp->close(); - VL_DO_CLEAR(delete vcdp, vcdp = nullptr); - } -} -#endif -// clang-format on - -//******************************************************************** -// ;compile-command: "v4make test_regress/t/t_trace_c_api.pl" -// -// Local Variables: -// End: diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 5fbb6022c..b1485e13b 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -164,156 +164,6 @@ public: void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declDouble(uint32_t code, const char* name, bool array, int arraynum); - -#ifdef VL_TRACE_VCD_OLD_API - //========================================================================= - // Note: These are only for testing for backward compatibility with foreign - // code and is not used by Verilator. Do not use these as there is no - // guarantee of functionality. - - void declTriBit(uint32_t code, const char* name, bool array, int arraynum); - void declTriBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declTriQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - void declTriArray(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); - - void fullBit(uint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); } - void fullCData(uint32_t* oldp, CData newval, int bits) { - fullBus(oldp - this->oldp(0), newval, bits); - } - void fullSData(uint32_t* oldp, SData newval, int bits) { - fullBus(oldp - this->oldp(0), newval, bits); - } - void fullIData(uint32_t* oldp, IData newval, int bits) { - fullBus(oldp - this->oldp(0), newval, bits); - } - void fullQData(uint32_t* oldp, QData newval, int bits) { - fullQuad(oldp - this->oldp(0), newval, bits); - } - void fullWData(uint32_t* oldp, const WData* newvalp, int bits) { - fullArray(oldp - this->oldp(0), newvalp, bits); - } - void fullDouble(uint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); } - - inline void chgBit(uint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); } - inline void chgCData(uint32_t* oldp, CData newval, int bits) { - chgBus(oldp - this->oldp(0), newval, bits); - } - inline void chgSData(uint32_t* oldp, SData newval, int bits) { - chgBus(oldp - this->oldp(0), newval, bits); - } - inline void chgIData(uint32_t* oldp, IData newval, int bits) { - chgBus(oldp - this->oldp(0), newval, bits); - } - inline void chgQData(uint32_t* oldp, QData newval, int bits) { - chgQuad(oldp - this->oldp(0), newval, bits); - } - inline void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { - chgArray(oldp - this->oldp(0), newvalp, bits); - } - inline void chgDouble(uint32_t* oldp, double newval) { - chgDouble(oldp - this->oldp(0), newval); - } - - // Inside dumping routines, dump one signal, faster when not inlined - // due to code size reduction. - void fullBit(uint32_t code, const uint32_t newval); - void fullBus(uint32_t code, const uint32_t newval, int bits); - void fullQuad(uint32_t code, const uint64_t newval, int bits); - void fullArray(uint32_t code, const uint32_t* newvalp, int bits); - void fullArray(uint32_t code, const uint64_t* newvalp, int bits); - void fullTriBit(uint32_t code, const uint32_t newval, const uint32_t newtri); - void fullTriBus(uint32_t code, const uint32_t newval, const uint32_t newtri, int bits); - void fullTriQuad(uint32_t code, const uint64_t newval, const uint64_t newtri, int bits); - void fullTriArray(uint32_t code, const uint32_t* newvalp, const uint32_t* newtrip, int bits); - void fullDouble(uint32_t code, const double newval); - - // Inside dumping routines, dump one signal if it has changed. - // We do want to inline these to avoid calls when the value did not change. - inline void chgBit(uint32_t code, const uint32_t newval) { - const uint32_t diff = oldp(code)[0] ^ newval; - if (VL_UNLIKELY(diff)) fullBit(code, newval); - } - inline void chgBus(uint32_t code, const uint32_t newval, int bits) { - const uint32_t diff = oldp(code)[0] ^ newval; - if (VL_UNLIKELY(diff)) { - if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) { - fullBus(code, newval, bits); - } - } - } - inline void chgQuad(uint32_t code, const uint64_t newval, int bits) { - const uint64_t diff = (*(reinterpret_cast(oldp(code)))) ^ newval; - if (VL_UNLIKELY(diff)) { - if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) { - fullQuad(code, newval, bits); - } - } - } - inline void chgArray(uint32_t code, const uint32_t* newvalp, int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) { - fullArray(code, newvalp, bits); - return; - } - } - } - inline void chgArray(uint32_t code, const uint64_t* newvalp, int bits) { - for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { - if (VL_UNLIKELY(*(reinterpret_cast(oldp(code + 2 * word))) - ^ newvalp[word])) { - fullArray(code, newvalp, bits); - return; - } - } - } - inline void chgTriBit(uint32_t code, const uint32_t newval, const uint32_t newtri) { - const uint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri)); - if (VL_UNLIKELY(diff)) { - // Verilator 3.510 and newer provide clean input, so the below - // is only for back compatibility - if (VL_UNLIKELY(diff & 1)) { // Change after clean? - fullTriBit(code, newval, newtri); - } - } - } - inline void chgTriBus(uint32_t code, const uint32_t newval, const uint32_t newtri, int bits) { - const uint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri)); - if (VL_UNLIKELY(diff)) { - if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) { - fullTriBus(code, newval, newtri, bits); - } - } - } - inline void chgTriQuad(uint32_t code, const uint64_t newval, const uint64_t newtri, int bits) { - const uint64_t diff = (((*(reinterpret_cast(oldp(code)))) ^ newval) - | ((*(reinterpret_cast(oldp(code + 1)))) ^ newtri)); - if (VL_UNLIKELY(diff)) { - if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) { - fullTriQuad(code, newval, newtri, bits); - } - } - } - inline void chgTriArray(uint32_t code, const uint32_t* newvalp, const uint32_t* newtrip, - int bits) { - for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { - if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word]) - | (oldp(code)[word * 2 + 1] ^ newtrip[word]))) { - fullTriArray(code, newvalp, newtrip, bits); - return; - } - } - } - inline void chgDouble(uint32_t code, const double newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY((*(reinterpret_cast(oldp(code)))) != newval)) { - fullDouble(code, newval); - } - } - - // METHODS - // Old/standalone API only - void evcd(bool flag) { m_evcd = flag; } -#endif // VL_TRACE_VCD_OLD_API }; #ifndef DOXYGEN @@ -396,16 +246,6 @@ public: // Internal class access inline VerilatedVcd* spTrace() { return &m_sptrace; } - -#ifdef VL_TRACE_VCD_OLD_API - //========================================================================= - // Note: These are only for testing for backward compatibility with foreign - // code and is not used by Verilator. Do not use these as there is no - // guarantee of functionality. - - // Use evcd format - void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); } -#endif }; #endif // guard diff --git a/test_regress/t/t_trace_c_api.cpp b/test_regress/t/t_trace_c_api.cpp deleted file mode 100644 index d2d3f0921..000000000 --- a/test_regress/t/t_trace_c_api.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -// -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2008 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -#include -#include - -#include VM_PREFIX_INCLUDE - -double sc_time_stamp() { return 0; } - -extern void vcdTestMain(const char* filenamep); - -int main(int argc, char** argv, char** env) { - const char* filenamep = VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"; - printf("Writing %s\n", filenamep); - vcdTestMain(filenamep); - printf("*-* All Finished *-*\n"); - return 0; -} diff --git a/test_regress/t/t_trace_c_api.pl b/test_regress/t/t_trace_c_api.pl deleted file mode 100755 index 541970008..000000000 --- a/test_regress/t/t_trace_c_api.pl +++ /dev/null @@ -1,30 +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 2003-2013 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); - -compile( - make_top_shell => 0, - make_main => 0, - v_flags2 => ["--trace --exe $Self->{t_dir}/t_trace_c_api.cpp", - "-CFLAGS -DVERILATED_VCD_TEST", - "-CFLAGS -DVL_TRACE_VCD_OLD_API"], - ); - -execute( - check_finished => 1, - ); - -# vcddiff bug crashes -#vcd_identical("$Self->{obj_dir}/simx.vcd", -# $Self->{golden_filename}); - -ok(1); -1; diff --git a/test_regress/t/t_trace_c_api.v b/test_regress/t/t_trace_c_api.v deleted file mode 100644 index 7b440cb91..000000000 --- a/test_regress/t/t_trace_c_api.v +++ /dev/null @@ -1,8 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2013 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t; -endmodule diff --git a/test_regress/t/t_trace_complex_old_api.pl b/test_regress/t/t_trace_complex_old_api.pl deleted file mode 100755 index 8136d3f79..000000000 --- a/test_regress/t/t_trace_complex_old_api.pl +++ /dev/null @@ -1,39 +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 2003-2009 by Wilson Snyder. This program is free software; you -# can redistribute it and/or modify it under the terms of either the GNU -# Lesser General Public License Version 3 or the Perl Artistic License -# Version 2.0. -# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -# Same test as t_trace_complex, but exercising the old VCD tracing API - -scenarios(vlt => 1); - -top_filename("t/t_trace_complex.v"); -golden_filename("t/t_trace_complex.out"); - -compile( - verilator_flags2 => ['--cc --trace -CFLAGS -DVL_TRACE_VCD_OLD_API'], - ); - -execute( - check_finished => 1, - ); - -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_strp /); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_strp_strp /); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arrp /); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_arrp /); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_strp /); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arru\[/); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\[/); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\[/); -file_grep("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\[/); - -vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); - -ok(1); -1; From cf1eccc24f3d5f2224a37ec18a2590b2868fdc79 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 28 May 2022 12:17:39 +0100 Subject: [PATCH 41/68] Make local function 'static' in verilated_profiler.h --- include/verilated_profiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_profiler.cpp b/include/verilated_profiler.cpp index 1a5f16a36..ed25093d1 100644 --- a/include/verilated_profiler.cpp +++ b/include/verilated_profiler.cpp @@ -60,7 +60,7 @@ uint16_t VlExecutionRecord::getcpu() { //============================================================================= // VlExecutionProfiler implementation -template size_t roundUptoMultipleOf(size_t value) { +template static size_t roundUptoMultipleOf(size_t value) { static_assert((N & (N - 1)) == 0, "'N' must be a power of 2"); size_t mask = N - 1; return (value + mask) & ~mask; From a48c779367417115e194adbdd3acf7818beeb0f5 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 28 May 2022 12:20:35 +0100 Subject: [PATCH 42/68] Rename verilated_trace_imp.cpp -> verilated_trace_imp.h Also fix file header to describe purpose of this file. --- include/verilated_fst_c.cpp | 4 ++-- ...rilated_trace_imp.cpp => verilated_trace_imp.h} | 14 +++++--------- include/verilated_vcd_c.cpp | 4 ++-- 3 files changed, 9 insertions(+), 13 deletions(-) rename include/{verilated_trace_imp.cpp => verilated_trace_imp.h} (99%) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 68431db71..3e1b27744 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -84,7 +84,7 @@ static_assert(static_cast(FST_ST_VCD_PROGRAM) == static_cast(VLT_TRACE // Specialization of the generics for this trace format #define VL_DERIVED_T VerilatedFst -#include "verilated_trace_imp.cpp" +#include "verilated_trace_imp.h" #undef VL_DERIVED_T //============================================================================= @@ -246,7 +246,7 @@ void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fst } // Note: emit* are only ever called from one place (full* in -// verilated_trace_imp.cpp, which is included in this file at the top), +// verilated_trace_imp.h, which is included in this file at the top), // so always inline them. VL_ATTR_ALWINLINE diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.h similarity index 99% rename from include/verilated_trace_imp.cpp rename to include/verilated_trace_imp.h index dac31ddac..ed0503fcb 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.h @@ -10,15 +10,11 @@ // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //============================================================================= -/// -/// \file -/// \brief Verilated common-format tracing implementation code -/// -/// This file must be compiled and linked against all Verilated objects -/// that use --trace. -/// -/// Use "verilator --trace" to add this to the Makefile for the linker. -/// +// +// Verilated tracing implementation code template common to all formats. +// This file is included by the format specific implementations and +// should not be used otherwise. +// //============================================================================= // clang-format off diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index d2417bc3e..8e0008e3f 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -66,7 +66,7 @@ constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry // Specialization of the generics for this trace format #define VL_DERIVED_T VerilatedVcd -#include "verilated_trace_imp.cpp" +#include "verilated_trace_imp.h" #undef VL_DERIVED_T //============================================================================= @@ -604,7 +604,7 @@ void VerilatedVcd::finishLine(uint32_t code, char* writep) { // emit* trace routines // Note: emit* are only ever called from one place (full* in -// verilated_trace_imp.cpp, which is included in this file at the top), +// verilated_trace_imp.h, which is included in this file at the top), // so always inline them. VL_ATTR_ALWINLINE From a7cd7a1ed989bf4fc2d220bd3ea09c87b5b08c78 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 28 May 2022 12:29:36 +0100 Subject: [PATCH 43/68] Initialize VerilatedTrace members in class --- include/verilated_trace.h | 28 ++++++++++++++-------------- include/verilated_trace_imp.h | 19 +------------------ 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/include/verilated_trace.h b/include/verilated_trace.h index a88ce6b50..622cb936e 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -146,23 +146,23 @@ private: , m_userp{userp} {} }; - uint32_t* m_sigs_oldvalp; // Old value store - EData* m_sigs_enabledp; // Bit vector of enabled codes (nullptr = all on) - uint64_t m_timeLastDump; // Last time we did a dump + uint32_t* m_sigs_oldvalp = nullptr; // Old value store + EData* m_sigs_enabledp = nullptr; // Bit vector of enabled codes (nullptr = all on) + uint64_t m_timeLastDump = 0; // Last time we did a dump std::vector m_sigs_enabledVec; // Staging for m_sigs_enabledp std::vector m_initCbs; // Routines to initialize traciong std::vector m_fullCbs; // Routines to perform full dump std::vector m_chgCbs; // Routines to perform incremental dump std::vector m_cleanupCbs; // Routines to call at the end of dump - bool m_fullDump; // Whether a full dump is required on the next call to 'dump' - uint32_t m_nextCode; // Next code number to assign - uint32_t m_numSignals; // Number of distinct signals - uint32_t m_maxBits; // Number of bits in the widest signal + bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump' + uint32_t m_nextCode = 0; // Next code number to assign + uint32_t m_numSignals = 0; // Number of distinct signals + uint32_t m_maxBits = 0; // Number of bits in the widest signal std::vector m_namePrefixStack{""}; // Path prefixes to add to signal names std::vector> m_dumpvars; // dumpvar() entries - char m_scopeEscape; - double m_timeRes; // Time resolution (ns/ms etc) - double m_timeUnit; // Time units (ns/ms etc) + char m_scopeEscape = '.'; + double m_timeRes = 1e-9; // Time resolution (ns/ms etc) + double m_timeUnit = 1e-0; // Time units (ns/ms etc) void addCallbackRecord(std::vector& cbVec, CallbackRecord& cbRec) VL_MT_SAFE_EXCLUDES(m_mutex); @@ -178,17 +178,17 @@ private: #ifdef VL_TRACE_OFFLOAD // Number of total offload buffers that have been allocated - uint32_t m_numOffloadBuffers; + uint32_t m_numOffloadBuffers = 0; // Size of offload buffers - size_t m_offloadBufferSize; + size_t m_offloadBufferSize = 0; // Buffers handed to worker for processing VerilatedThreadQueue m_offloadBuffersToWorker; // Buffers returned from worker after processing VerilatedThreadQueue m_offloadBuffersFromWorker; // Write pointer into current buffer - uint32_t* m_offloadBufferWritep; + uint32_t* m_offloadBufferWritep = nullptr; // End of offload buffer - uint32_t* m_offloadBufferEndp; + uint32_t* m_offloadBufferEndp = nullptr; // The offload worker thread itself std::unique_ptr m_workerThread; diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index ed0503fcb..e62e40cab 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -275,24 +275,7 @@ template <> void VerilatedTrace::onExit(void* selfp) { //============================================================================= // VerilatedTrace -template <> -VerilatedTrace::VerilatedTrace() - : m_sigs_oldvalp{nullptr} - , m_sigs_enabledp{nullptr} - , m_timeLastDump{0} - , m_fullDump{true} - , m_nextCode{0} - , m_numSignals{0} - , m_maxBits{0} - , m_scopeEscape{'.'} - , m_timeRes{1e-9} - , m_timeUnit { - 1e-9 -} -#ifdef VL_TRACE_OFFLOAD -, m_numOffloadBuffers { 0 } -#endif -{ +template <> VerilatedTrace::VerilatedTrace() { set_time_unit(Verilated::threadContextp()->timeunitString()); set_time_resolution(Verilated::threadContextp()->timeprecisionString()); } From c4b8675d77870489d1acf1e5b5a0fb8eb9b2f7e2 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sat, 28 May 2022 12:33:11 +0100 Subject: [PATCH 44/68] Always inline some small, hot trace routines --- include/verilated_trace.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 622cb936e..3174ff7c1 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -300,7 +300,7 @@ public: // duck-typed void emitWData(uint32_t code, const WData* newvalp, int bits) = 0; // duck-typed void emitDouble(uint32_t code, double newval) = 0; - uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; } + VL_ATTR_ALWINLINE inline uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; } // Write to previous value buffer value and emit trace entry. void fullBit(uint32_t* oldp, CData newval); @@ -373,23 +373,23 @@ public: // thread and are called chg*Impl // Check previous dumped value of signal. If changed, then emit trace entry - inline void CHG(Bit)(uint32_t* oldp, CData newval) { + VL_ATTR_ALWINLINE inline void CHG(Bit)(uint32_t* oldp, CData newval) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - inline void CHG(CData)(uint32_t* oldp, CData newval, int bits) { + VL_ATTR_ALWINLINE inline void CHG(CData)(uint32_t* oldp, CData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); } - inline void CHG(SData)(uint32_t* oldp, SData newval, int bits) { + VL_ATTR_ALWINLINE inline void CHG(SData)(uint32_t* oldp, SData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); } - inline void CHG(IData)(uint32_t* oldp, IData newval, int bits) { + VL_ATTR_ALWINLINE inline void CHG(IData)(uint32_t* oldp, IData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); } - inline void CHG(QData)(uint32_t* oldp, QData newval, int bits) { + VL_ATTR_ALWINLINE inline void CHG(QData)(uint32_t* oldp, QData newval, int bits) { const uint64_t diff = *reinterpret_cast(oldp) ^ newval; if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); } @@ -401,7 +401,7 @@ public: } } } - inline void CHG(Double)(uint32_t* oldp, double newval) { + VL_ATTR_ALWINLINE inline void CHG(Double)(uint32_t* oldp, double newval) { // cppcheck-suppress invalidPointerCast if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); } From b51f887567814a3353e95c7fa7d5e14186c1ab39 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 29 May 2022 19:08:39 +0100 Subject: [PATCH 45/68] Perform VCD tracing in parallel when using --threads (#3449) VCD tracing is now parallelized using the same thread pool as the model. We achieve this by breaking the top level trace functions into multiple top level functions (as many as --threads), and after emitting the time stamp to the VCD file on the main thread, we execute the tracing functions in parallel on the same thread pool as the model (which we pass to the trace file during registration), tracing into a secondary per thread buffer. The main thread will then stitch (memcpy) the buffers together into the output file. This makes the `--trace-threads` option redundant with `--trace`, which now only affects `--trace-fst`. FST tracing uses the previous offloading scheme. This obviously helps a lot in VCD tracing performance, and I have seen better than Amdahl speedup, namely I get 3.9x on XiangShan 4T (2.7x on OpenTitan 4T). --- Changes | 4 + bin/verilator | 2 +- docs/guide/exe_verilator.rst | 18 +- docs/guide/verilating.rst | 24 ++- include/verilated.h | 2 +- include/verilated_fst_c.cpp | 52 +++-- include/verilated_fst_c.h | 81 +++++--- include/verilated_trace.h | 182 +++++++++++++---- include/verilated_trace_imp.h | 365 +++++++++++++++++++++++----------- include/verilated_vcd_c.cpp | 158 ++++++++++++--- include/verilated_vcd_c.h | 156 ++++++++++----- include/verilatedos.h | 4 + src/V3EmitCImp.cpp | 16 +- src/V3EmitCMake.cpp | 5 +- src/V3EmitMk.cpp | 5 +- src/V3Options.cpp | 14 +- src/V3Options.h | 6 +- src/V3Trace.cpp | 31 +-- test_regress/driver.pl | 1 - 19 files changed, 811 insertions(+), 315 deletions(-) diff --git a/Changes b/Changes index a0eb2b1d1..8c9418c9f 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,10 @@ contributors that suggested a given feature are shown in []. Thanks! Verilator 4.223 devel ========================== +**Major:** + +* VCD tracing is now parallelized with --threads (#3449). [Geza Lore, Shunyao CAD] + **Minor:** * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] diff --git a/bin/verilator b/bin/verilator index b1ee97e73..40be6ba0f 100755 --- a/bin/verilator +++ b/bin/verilator @@ -405,7 +405,7 @@ detailed descriptions of these arguments. --trace-max-width Maximum array depth for tracing --trace-params Enable tracing of parameters --trace-structs Enable tracing structure names - --trace-threads Enable waveform creation on separate threads + --trace-threads Enable FST waveform creation on separate threads --trace-underscore Enable tracing of _signals -U Undefine preprocessor define --unroll-count Tune maximum loop iterations diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 00e101ed0..6100dcd55 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1041,7 +1041,8 @@ Summary: is not thread safe. With "--threads 1", the generated model is single threaded but may run in a multithreaded environment. With "--threads N", where N >= 2, the model is generated to run multithreaded on up to N - threads. See :ref:`Multithreading`. + threads. See :ref:`Multithreading`. This option also applies to + :vlopt:`--trace` (but not :vlopt:`--trace-fst`). .. option:: --threads-dpi all @@ -1119,7 +1120,8 @@ Summary: Having tracing compiled in may result in some small performance losses, even when tracing is not turned on during model execution. - See also :vlopt:`--trace-threads` option. + When using :vlopt:`--threads`, VCD tracing is parallelized, using the + same number of threads as passed to :vlopt:`--threads`. .. option:: --trace-coverage @@ -1173,12 +1175,12 @@ Summary: .. option:: --trace-threads *threads* Enable waveform tracing using separate threads. This is typically faster - in simulation runtime but uses more total compute. This option is - independent of, and works with, both :vlopt:`--trace` and - :vlopt:`--trace-fst`. Different trace formats can take advantage of - more trace threads to varying degrees. Currently VCD tracing can utilize - at most "--trace-threads 1", and FST tracing can utilize at most - "--trace-threads 2". This overrides :vlopt:`--no-threads` . + in simulation runtime but uses more total compute. This option only + applies to :vlopt:`--trace-fst`. FST tracing can utilize at most + "--trace-threads 2". This overrides :vlopt:`--no-threads`. + + This option is accepted, but has absolutely no effect with + :vlopt:`--trace`, which respects :vlopt:`--threads` instead. .. option:: --trace-underscore diff --git a/docs/guide/verilating.rst b/docs/guide/verilating.rst index f443ca298..2af18c1f0 100644 --- a/docs/guide/verilating.rst +++ b/docs/guide/verilating.rst @@ -221,9 +221,13 @@ model, it may be beneficial to performance to adjust the influences the partitioning of the model by adjusting the assumed execution time of DPI imports. -The :vlopt:`--trace-threads` options can be used to produce trace dumps -using multiple threads. If :vlopt:`--trace-threads` is set without -:vlopt:`--threads`, then :vlopt:`--trace-threads` will imply +When using :vlopt:`--trace` to perform VCD tracing, the VCD trace +construction is parallelized using the same number of threads as specified +with :vlopt:`--threads`, and is executed on the same thread pool as the model. + +The :vlopt:`--trace-threads` options can be used with :vlopt:`--trace-fst` +to offload FST tracing using multiple threads. If :vlopt:`--trace-threads` is +given without :vlopt:`--threads`, then :vlopt:`--trace-threads` will imply :vlopt:`--threads 1 <--threads>`, i.e.: the support libraries will be thread safe. @@ -231,12 +235,12 @@ With :vlopt:`--trace-threads 0 <--trace-threads>`, trace dumps are produced on the main thread. This again gives the highest single thread performance. With :vlopt:`--trace-threads {N} <--trace-threads>`, where N is at least 1, -N additional threads will be created and managed by the trace files (e.g.: -VerilatedVcdC or VerilatedFstC), to generate the trace dump. The main -thread will be released to proceed with execution as soon as possible, -though some blocking of the main thread is still necessary while capturing -the trace. Different trace formats can utilize a various number of -threads. See the :vlopt:`--trace-threads` option. +up to N additional threads will be created and managed by the trace files +(e.g.: VerilatedFstC), to offload construction of the trace dump. The main +thread will be released to proceed with execution as soon as possible, though +some blocking of the main thread is still necessary while capturing the +trace. FST tracing can utilize up to 2 offload threads, so there is no use +of setting :vlopt:`--trace-threads` higher than 2 at the moment. When running a multithreaded model, the default Linux task scheduler often works against the model, by assuming threads are short lived, and thus @@ -441,7 +445,7 @@ SystemC include directories and link to the SystemC libraries. .. describe:: TRACE_THREADS - Optional. Generated multi-threaded trace dumping, same as + Optional. Generated multi-threaded FST trace dumping, same as "--trace-threads". .. describe:: TOP_MODULE diff --git a/include/verilated.h b/include/verilated.h index 804d7363a..f9cf79601 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -147,7 +147,7 @@ extern uint32_t VL_THREAD_ID() VL_MT_SAFE; #if VL_THREADED -#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before relaxing +#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding /// Mutex, wrapped to allow -fthread_safety checks class VL_CAPABILITY("mutex") VerilatedMutex final { diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 3e1b27744..0bc1048cf 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -83,9 +83,11 @@ static_assert(static_cast(FST_ST_VCD_PROGRAM) == static_cast(VLT_TRACE //============================================================================= // Specialization of the generics for this trace format -#define VL_DERIVED_T VerilatedFst +#define VL_SUB_T VerilatedFst +#define VL_BUF_T VerilatedFstBuffer #include "verilated_trace_imp.h" -#undef VL_DERIVED_T +#undef VL_SUB_T +#undef VL_BUF_T //============================================================================= // VerilatedFst @@ -111,7 +113,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { m_curScope.clear(); - VerilatedTrace::traceInit(); + Super::traceInit(); // Clear the scope stack auto it = m_curScope.begin(); @@ -133,14 +135,14 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) { const VerilatedLockGuard lock{m_mutex}; - VerilatedTrace::closeBase(); + Super::closeBase(); fstWriterClose(m_fst); m_fst = nullptr; } void VerilatedFst::flush() VL_MT_SAFE_EXCLUDES(m_mutex) { const VerilatedLockGuard lock{m_mutex}; - VerilatedTrace::flushBase(); + Super::flushBase(); fstWriterFlushContext(m_fst); } @@ -162,7 +164,7 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar int lsb) { const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; - const bool enabled = VerilatedTrace::declCode(code, name, bits, false); + const bool enabled = Super::declCode(code, name, bits, false); if (!enabled) return; std::string nameasstr = namePrefix() + name; @@ -245,18 +247,42 @@ void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fst declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0); } +//============================================================================= +// Get/commit trace buffer + +VerilatedFstBuffer* VerilatedFst::getTraceBuffer() { return new VerilatedFstBuffer{*this}; } + +void VerilatedFst::commitTraceBuffer(VerilatedFstBuffer* bufp) { +#ifdef VL_TRACE_OFFLOAD + if (bufp->m_offloadBufferWritep) { + m_offloadBufferWritep = bufp->m_offloadBufferWritep; + return; // Buffer will be deleted by the offload thread + } +#endif + delete bufp; +} + +//============================================================================= +// VerilatedFstBuffer implementation + +VerilatedFstBuffer::VerilatedFstBuffer(VerilatedFst& owner) + : VerilatedTraceBuffer{owner} {} + +//============================================================================= +// Trace rendering primitives + // Note: emit* are only ever called from one place (full* in // verilated_trace_imp.h, which is included in this file at the top), // so always inline them. VL_ATTR_ALWINLINE -void VerilatedFst::emitBit(uint32_t code, CData newval) { +void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) { VL_DEBUG_IFDEF(assert(m_symbolp[code]);); fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0"); } VL_ATTR_ALWINLINE -void VerilatedFst::emitCData(uint32_t code, CData newval, int bits) { +void VerilatedFstBuffer::emitCData(uint32_t code, CData newval, int bits) { char buf[VL_BYTESIZE]; VL_DEBUG_IFDEF(assert(m_symbolp[code]);); cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits)); @@ -264,7 +290,7 @@ void VerilatedFst::emitCData(uint32_t code, CData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedFst::emitSData(uint32_t code, SData newval, int bits) { +void VerilatedFstBuffer::emitSData(uint32_t code, SData newval, int bits) { char buf[VL_SHORTSIZE]; VL_DEBUG_IFDEF(assert(m_symbolp[code]);); cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits)); @@ -272,7 +298,7 @@ void VerilatedFst::emitSData(uint32_t code, SData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedFst::emitIData(uint32_t code, IData newval, int bits) { +void VerilatedFstBuffer::emitIData(uint32_t code, IData newval, int bits) { char buf[VL_IDATASIZE]; VL_DEBUG_IFDEF(assert(m_symbolp[code]);); cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits)); @@ -280,7 +306,7 @@ void VerilatedFst::emitIData(uint32_t code, IData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedFst::emitQData(uint32_t code, QData newval, int bits) { +void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int bits) { char buf[VL_QUADSIZE]; VL_DEBUG_IFDEF(assert(m_symbolp[code]);); cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits)); @@ -288,7 +314,7 @@ void VerilatedFst::emitQData(uint32_t code, QData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedFst::emitWData(uint32_t code, const WData* newvalp, int bits) { +void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits) { int words = VL_WORDS_I(bits); char* wp = m_strbuf; // Convert the most significant word @@ -304,6 +330,6 @@ void VerilatedFst::emitWData(uint32_t code, const WData* newvalp, int bits) { } VL_ATTR_ALWINLINE -void VerilatedFst::emitDouble(uint32_t code, double newval) { +void VerilatedFstBuffer::emitDouble(uint32_t code, double newval) { fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); } diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index b622a1894..5131cc8cc 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -31,15 +31,19 @@ #include #include +class VerilatedFstBuffer; + //============================================================================= // VerilatedFst // Base class to create a Verilator FST dump // This is an internally used class - see VerilatedFstC for what to call from applications -class VerilatedFst final : public VerilatedTrace { +class VerilatedFst final : public VerilatedTrace { +public: + using Super = VerilatedTrace; + private: - // Give the superclass access to private bits (to avoid virtual functions) - friend class VerilatedTrace; + friend Buffer; // Give the buffer access to the private bits //========================================================================= // FST specific internals @@ -60,31 +64,26 @@ protected: //========================================================================= // Implementation of VerilatedTrace interface - // Implementations of protected virtual methods for VerilatedTrace + // Called when the trace moves forward to a new time point virtual void emitTimeChange(uint64_t timeui) override; // Hooks called from VerilatedTrace virtual bool preFullDump() override { return isOpen(); } virtual bool preChangeDump() override { return isOpen(); } - // Implementations of duck-typed methods for VerilatedTrace. These are - // called from only one place (namely full*) so always inline them. - inline void emitBit(uint32_t code, CData newval); - inline void emitCData(uint32_t code, CData newval, int bits); - inline void emitSData(uint32_t code, SData newval, int bits); - inline void emitIData(uint32_t code, IData newval, int bits); - inline void emitQData(uint32_t code, QData newval, int bits); - inline void emitWData(uint32_t code, const WData* newvalp, int bits); - inline void emitDouble(uint32_t code, double newval); + // Trace buffer management + virtual VerilatedFstBuffer* getTraceBuffer() override; + virtual void commitTraceBuffer(VerilatedFstBuffer*) override; public: //========================================================================= // External interface to client code - // (All must be threadsafe) + // CONSTRUCTOR explicit VerilatedFst(void* fst = nullptr); ~VerilatedFst(); + // METHODS - All must be thread safe // Open the file; call isOpen() to see if errors void open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex); // Close the file @@ -97,11 +96,6 @@ public: //========================================================================= // Internal interface to Verilator generated code - // Inside dumping routines, declare a data type - void declDTypeEnum(int dtypenum, const char* name, uint32_t elements, unsigned int minValbits, - const char** itemNamesp, const char** itemValuesp); - - // Inside dumping routines, declare a signal void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum); void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, @@ -112,18 +106,55 @@ public: fstVarType vartype, bool array, int arraynum, int msb, int lsb); void declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir, fstVarType vartype, bool array, int arraynum); + + void declDTypeEnum(int dtypenum, const char* name, uint32_t elements, unsigned int minValbits, + const char** itemNamesp, const char** itemValuesp); }; #ifndef DOXYGEN // Declare specialization here as it's used in VerilatedFstC just below -template <> void VerilatedTrace::dump(uint64_t timeui); -template <> void VerilatedTrace::set_time_unit(const char* unitp); -template <> void VerilatedTrace::set_time_unit(const std::string& unit); -template <> void VerilatedTrace::set_time_resolution(const char* unitp); -template <> void VerilatedTrace::set_time_resolution(const std::string& unit); -template <> void VerilatedTrace::dumpvars(int level, const std::string& hier); +template <> void VerilatedFst::Super::dump(uint64_t time); +template <> void VerilatedFst::Super::set_time_unit(const char* unitp); +template <> void VerilatedFst::Super::set_time_unit(const std::string& unit); +template <> void VerilatedFst::Super::set_time_resolution(const char* unitp); +template <> void VerilatedFst::Super::set_time_resolution(const std::string& unit); +template <> void VerilatedFst::Super::dumpvars(int level, const std::string& hier); #endif +//============================================================================= +// VerilatedFstBuffer + +class VerilatedFstBuffer final : public VerilatedTraceBuffer { + // Give the trace file access to the private bits + friend VerilatedFst; + friend VerilatedFst::Super; + + // The FST file handle + void* const m_fst = m_owner.m_fst; + // code to fstHande map, as an array + const fstHandle* const m_symbolp = m_owner.m_symbolp; + // String buffer long enough to hold maxBits() chars + char* const m_strbuf = m_owner.m_strbuf; + +public: + // CONSTRUCTOR + explicit VerilatedFstBuffer(VerilatedFst& owner); + ~VerilatedFstBuffer() = default; + + //========================================================================= + // Implementation of VerilatedTraceBuffer interface + + // Implementations of duck-typed methods for VerilatedTraceBuffer. These are + // called from only one place (the full* methods), so always inline them. + VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); + VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); + VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); + VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); + VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); + VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); + VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); +}; + //============================================================================= // VerilatedFstC /// Create a FST dump file in C standalone (no SystemC) simulations. diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 3174ff7c1..7915c3645 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -22,28 +22,43 @@ #ifndef VERILATOR_VERILATED_TRACE_H_ #define VERILATOR_VERILATED_TRACE_H_ -#ifdef VL_TRACE_THREADED -#define VL_TRACE_OFFLOAD +// clang-format off + +// In FST mode, VL_TRACE_THREADED enables offloading, but only if we also have +// the FST writer thread. This means with --trace-threads 1, we get the FST +// writer thread only, and with --trace-threads 2 we get offloading as well +#if defined(VL_TRACE_FST_WRITER_THREAD) && defined(VL_TRACE_THREADED) +# define VL_TRACE_OFFLOAD +#endif +// VCD tracing can happen fully in parallel +#if defined(VM_TRACE_VCD) && VM_TRACE_VCD && defined(VL_TRACE_THREADED) +# define VL_TRACE_PARALLEL #endif -// clang-format off +#if defined(VL_TRACE_PARALLEL) && defined(VL_TRACE_OFFLOAD) +# error "Cannot have VL_TRACE_PARALLEL and VL_TRACE_OFFLOAD together" +#endif #include "verilated.h" #include "verilated_trace_defs.h" #include +#include #include #include +#include #include #ifdef VL_TRACE_OFFLOAD -# include # include # include #endif // clang-format on +class VlThreadPool; +template class VerilatedTraceBuffer; + #ifdef VL_TRACE_OFFLOAD //============================================================================= // Offloaded tracing @@ -106,7 +121,8 @@ public: CHG_WDATA = 0x6, CHG_DOUBLE = 0x8, // TODO: full.. - TIME_CHANGE = 0xd, + TIME_CHANGE = 0xc, + TRACE_BUFFER = 0xd, END = 0xe, // End of buffer SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer }; @@ -116,16 +132,22 @@ public: //============================================================================= // VerilatedTrace -// VerilatedTrace uses F-bounded polymorphism to access duck-typed -// implementations in the format specific derived class, which must be passed -// as the type parameter T_Derived -template class VerilatedTrace VL_NOT_FINAL { +// T_Trace is the format specific subclass of VerilatedTrace. +// T_Buffer is the format specific subclass of VerilatedTraceBuffer. +template class VerilatedTrace VL_NOT_FINAL { + // Give the buffer (both base and derived) access to the private bits + friend VerilatedTraceBuffer; + friend T_Buffer; + public: + using Buffer = T_Buffer; + //========================================================================= // Generic tracing internals - using initCb_t = void (*)(void*, T_Derived*, uint32_t); // Type of init callbacks - using dumpCb_t = void (*)(void*, T_Derived*); // Type of all but init callbacks + using initCb_t = void (*)(void*, T_Trace*, uint32_t); // Type of init callbacks + using dumpCb_t = void (*)(void*, Buffer*); // Type of dump callbacks + using cleanupCb_t = void (*)(void*, T_Trace*); // Type of cleanup callbacks private: struct CallbackRecord { @@ -133,9 +155,10 @@ private: // (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the // assignment operator on inserting into collections, so they don't work // with const fields... - union { - initCb_t m_initCb; // The callback function - dumpCb_t m_dumpCb; // The callback function + union { // The callback + initCb_t m_initCb; + dumpCb_t m_dumpCb; + cleanupCb_t m_cleanupCb; }; void* m_userp; // The user pointer to pass to the callback (the symbol table) CallbackRecord(initCb_t cb, void* userp) @@ -144,16 +167,46 @@ private: CallbackRecord(dumpCb_t cb, void* userp) : m_dumpCb{cb} , m_userp{userp} {} + CallbackRecord(cleanupCb_t cb, void* userp) + : m_cleanupCb{cb} + , m_userp{userp} {} }; - uint32_t* m_sigs_oldvalp = nullptr; // Old value store +#ifdef VL_TRACE_PARALLEL + struct ParallelWorkerData { + const dumpCb_t m_cb; // The callback + void* const m_userp; // The use pointer to pass to the callback + Buffer* const m_bufp; // The buffer pointer to pass to the callback + std::atomic m_ready{false}; // The ready flag + mutable VerilatedMutex m_mutex; // Mutex for suspension until ready + std::condition_variable_any m_cv; // Condition variable for suspension + bool m_waiting VL_GUARDED_BY(m_mutex) = false; // Whether a thread is suspended in wait() + + void wait(); + + ParallelWorkerData(dumpCb_t cb, void* userp, Buffer* bufp) + : m_cb{cb} + , m_userp{userp} + , m_bufp{bufp} {} + }; + + // Passed a ParallelWorkerData*, second argument is ignored + static void parallelWorkerTask(void*, bool); +#endif + + using ParallelCallbackMap = std::unordered_map>; + +protected: + uint32_t* m_sigs_oldvalp = nullptr; // Previous value store EData* m_sigs_enabledp = nullptr; // Bit vector of enabled codes (nullptr = all on) +private: uint64_t m_timeLastDump = 0; // Last time we did a dump std::vector m_sigs_enabledVec; // Staging for m_sigs_enabledp - std::vector m_initCbs; // Routines to initialize traciong - std::vector m_fullCbs; // Routines to perform full dump - std::vector m_chgCbs; // Routines to perform incremental dump + std::vector m_initCbs; // Routines to initialize tracing + ParallelCallbackMap m_fullCbs; // Routines to perform full dump + ParallelCallbackMap m_chgCbs; // Routines to perform incremental dump std::vector m_cleanupCbs; // Routines to call at the end of dump + std::vector m_threadPoolps; // All thread pools, in insertion order bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump' uint32_t m_nextCode = 0; // Next code number to assign uint32_t m_numSignals = 0; // Number of distinct signals @@ -164,12 +217,16 @@ private: double m_timeRes = 1e-9; // Time resolution (ns/ms etc) double m_timeUnit = 1e-0; // Time units (ns/ms etc) + void addThreadPool(VlThreadPool* threadPoolp) VL_MT_SAFE_EXCLUDES(m_mutex); + void addCallbackRecord(std::vector& cbVec, CallbackRecord& cbRec) VL_MT_SAFE_EXCLUDES(m_mutex); - // Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->' + // Equivalent to 'this' but is of the sub-type 'T_Trace*'. Use 'self()->' // to access duck-typed functions to avoid a virtual function call. - T_Derived* self() { return static_cast(this); } + T_Trace* self() { return static_cast(this); } + + void runParallelCallbacks(const ParallelCallbackMap& cbMap); // Flush any remaining data for this file static void onFlush(void* selfp) VL_MT_UNSAFE_ONE; @@ -185,10 +242,14 @@ private: VerilatedThreadQueue m_offloadBuffersToWorker; // Buffers returned from worker after processing VerilatedThreadQueue m_offloadBuffersFromWorker; + +protected: // Write pointer into current buffer uint32_t* m_offloadBufferWritep = nullptr; // End of offload buffer uint32_t* m_offloadBufferEndp = nullptr; + +private: // The offload worker thread itself std::unique_ptr m_workerThread; @@ -250,6 +311,10 @@ protected: virtual bool preFullDump() = 0; virtual bool preChangeDump() = 0; + // Trace buffer management + virtual Buffer* getTraceBuffer() = 0; + virtual void commitTraceBuffer(Buffer*) = 0; + public: //========================================================================= // External interface to client code @@ -270,19 +335,55 @@ public: // Call void dump(uint64_t timeui) VL_MT_SAFE_EXCLUDES(m_mutex); + //========================================================================= + // Internal interface to Verilator generated code + //========================================================================= // Non-hot path internal interface to Verilator generated code void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE; - void addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE; - void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_SAFE; + void addFullCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE; + void addChgCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE; + void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE; void scopeEscape(char flag) { m_scopeEscape = flag; } void pushNamePrefix(const std::string&); void popNamePrefix(unsigned count = 1); +}; +//============================================================================= +// VerilatedTraceBuffer + +// T_Trace is the format specific subclass of VerilatedTrace. +// T_Buffer is the format specific subclass of VerilatedTraceBuffer. +// The format-specific hot-path methods use duck-typing via T_Buffer for performance. +template class VerilatedTraceBuffer VL_NOT_FINAL { + friend T_Trace; // Give the trace file access to the private bits + +protected: + T_Trace& m_owner; // The VerilatedTrace subclass that owns this buffer + + // Previous value store + uint32_t* const m_sigs_oldvalp = m_owner.m_sigs_oldvalp; + // Bit vector of enabled codes (nullptr = all on) + EData* const m_sigs_enabledp = m_owner.m_sigs_enabledp; + +#ifdef VL_TRACE_OFFLOAD + // Write pointer into current buffer + uint32_t* m_offloadBufferWritep = m_owner.m_offloadBufferWritep; + // End of offload buffer + uint32_t* const m_offloadBufferEndp = m_owner.m_offloadBufferEndp; +#endif + + // Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->' + // to access duck-typed functions to avoid a virtual function call. + inline T_Buffer* self() { return static_cast(this); } + + explicit VerilatedTraceBuffer(T_Trace& owner); + virtual ~VerilatedTraceBuffer() = default; + +public: //========================================================================= // Hot path internal interface to Verilator generated code @@ -363,9 +464,13 @@ public: VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } -#define CHG(name) chg##name##Impl -#else -#define CHG(name) chg##name +#define chgBit chgBitImpl +#define chgCData chgCDataImpl +#define chgSData chgSDataImpl +#define chgIData chgIDataImpl +#define chgQData chgQDataImpl +#define chgWData chgWDataImpl +#define chgDouble chgDoubleImpl #endif // In non-offload mode, these are called directly by the trace callbacks, @@ -373,27 +478,27 @@ public: // thread and are called chg*Impl // Check previous dumped value of signal. If changed, then emit trace entry - VL_ATTR_ALWINLINE inline void CHG(Bit)(uint32_t* oldp, CData newval) { + VL_ATTR_ALWINLINE inline void chgBit(uint32_t* oldp, CData newval) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - VL_ATTR_ALWINLINE inline void CHG(CData)(uint32_t* oldp, CData newval, int bits) { + VL_ATTR_ALWINLINE inline void chgCData(uint32_t* oldp, CData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void CHG(SData)(uint32_t* oldp, SData newval, int bits) { + VL_ATTR_ALWINLINE inline void chgSData(uint32_t* oldp, SData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void CHG(IData)(uint32_t* oldp, IData newval, int bits) { + VL_ATTR_ALWINLINE inline void chgIData(uint32_t* oldp, IData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void CHG(QData)(uint32_t* oldp, QData newval, int bits) { + VL_ATTR_ALWINLINE inline void chgQData(uint32_t* oldp, QData newval, int bits) { const uint64_t diff = *reinterpret_cast(oldp) ^ newval; if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); } - inline void CHG(WData)(uint32_t* oldp, const WData* newvalp, int bits) { + VL_ATTR_ALWINLINE inline void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { for (int i = 0; i < (bits + 31) / 32; ++i) { if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { fullWData(oldp, newvalp, bits); @@ -401,11 +506,20 @@ public: } } } - VL_ATTR_ALWINLINE inline void CHG(Double)(uint32_t* oldp, double newval) { + VL_ATTR_ALWINLINE inline void chgDouble(uint32_t* oldp, double newval) { // cppcheck-suppress invalidPointerCast if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); } -#undef CHG +#ifdef VL_TRACE_OFFLOAD +#undef chgBit +#undef chgCData +#undef chgSData +#undef chgIData +#undef chgQData +#undef chgWData +#undef chgDouble +#endif }; + #endif // guard diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index e62e40cab..d2ffa965c 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -20,12 +20,16 @@ // clang-format off #ifndef VL_CPPCHECK -#ifndef VL_DERIVED_T +#if !defined(VL_SUB_T) || !defined(VL_BUF_T) # error "This file should be included in trace format implementations" #endif #include "verilated_intrinsics.h" #include "verilated_trace.h" +#ifdef VL_TRACE_PARALLEL +# include "verilated_threads.h" +# include +#endif #if 0 # include @@ -78,7 +82,7 @@ static std::string doubleToTimescale(double value) { //========================================================================= // Buffer management -template <> uint32_t* VerilatedTrace::getOffloadBuffer() { +template <> uint32_t* VerilatedTrace::getOffloadBuffer() { uint32_t* bufferp; // Some jitter is expected, so some number of alternative offlaod buffers are // required, but don't allocate more than 8 buffers. @@ -97,7 +101,7 @@ template <> uint32_t* VerilatedTrace::getOffloadBuffer() { return bufferp; } -template <> void VerilatedTrace::waitForOffloadBuffer(const uint32_t* buffp) { +template <> void VerilatedTrace::waitForOffloadBuffer(const uint32_t* buffp) { // Slow path code only called on flush/shutdown, so use a simple algorithm. // Collect buffers from worker and stash them until we get the one we want. std::deque stash; @@ -112,7 +116,7 @@ template <> void VerilatedTrace::waitForOffloadBuffer(const uint32 //========================================================================= // Worker thread -template <> void VerilatedTrace::offloadWorkerThreadMain() { +template <> void VerilatedTrace::offloadWorkerThreadMain() { bool shutdown = false; do { @@ -123,6 +127,8 @@ template <> void VerilatedTrace::offloadWorkerThreadMain() { const uint32_t* readp = bufferp; + std::unique_ptr traceBufp; // We own the passed tracebuffer + while (true) { const uint32_t cmd = readp[0]; const uint32_t top = cmd >> 4; @@ -137,44 +143,44 @@ template <> void VerilatedTrace::offloadWorkerThreadMain() { // CHG_* commands case VerilatedTraceOffloadCommand::CHG_BIT_0: VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_0 " << top); - chgBitImpl(oldp, 0); + traceBufp->chgBitImpl(oldp, 0); continue; case VerilatedTraceOffloadCommand::CHG_BIT_1: VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_1 " << top); - chgBitImpl(oldp, 1); + traceBufp->chgBitImpl(oldp, 1); continue; case VerilatedTraceOffloadCommand::CHG_CDATA: VL_TRACE_OFFLOAD_DEBUG("Command CHG_CDATA " << top); // Bits stored in bottom byte of command - chgCDataImpl(oldp, *readp, top); + traceBufp->chgCDataImpl(oldp, *readp, top); readp += 1; continue; case VerilatedTraceOffloadCommand::CHG_SDATA: VL_TRACE_OFFLOAD_DEBUG("Command CHG_SDATA " << top); // Bits stored in bottom byte of command - chgSDataImpl(oldp, *readp, top); + traceBufp->chgSDataImpl(oldp, *readp, top); readp += 1; continue; case VerilatedTraceOffloadCommand::CHG_IDATA: VL_TRACE_OFFLOAD_DEBUG("Command CHG_IDATA " << top); // Bits stored in bottom byte of command - chgIDataImpl(oldp, *readp, top); + traceBufp->chgIDataImpl(oldp, *readp, top); readp += 1; continue; case VerilatedTraceOffloadCommand::CHG_QDATA: VL_TRACE_OFFLOAD_DEBUG("Command CHG_QDATA " << top); // Bits stored in bottom byte of command - chgQDataImpl(oldp, *reinterpret_cast(readp), top); + traceBufp->chgQDataImpl(oldp, *reinterpret_cast(readp), top); readp += 2; continue; case VerilatedTraceOffloadCommand::CHG_WDATA: VL_TRACE_OFFLOAD_DEBUG("Command CHG_WDATA " << top); - chgWDataImpl(oldp, readp, top); + traceBufp->chgWDataImpl(oldp, readp, top); readp += VL_WORDS_I(top); continue; case VerilatedTraceOffloadCommand::CHG_DOUBLE: VL_TRACE_OFFLOAD_DEBUG("Command CHG_DOUBLE " << top); - chgDoubleImpl(oldp, *reinterpret_cast(readp)); + traceBufp->chgDoubleImpl(oldp, *reinterpret_cast(readp)); readp += 2; continue; @@ -187,9 +193,18 @@ template <> void VerilatedTrace::offloadWorkerThreadMain() { readp += 2; continue; + case VerilatedTraceOffloadCommand::TRACE_BUFFER: + VL_TRACE_OFFLOAD_DEBUG("Command TRACE_BUFFER " << top); + readp -= 1; // No code in this command, undo increment + traceBufp.reset(*reinterpret_cast(readp)); + readp += 2; + continue; + //=== // Commands ending this buffer - case VerilatedTraceOffloadCommand::END: VL_TRACE_OFFLOAD_DEBUG("Command END"); break; + case VerilatedTraceOffloadCommand::END: // + VL_TRACE_OFFLOAD_DEBUG("Command END"); + break; case VerilatedTraceOffloadCommand::SHUTDOWN: VL_TRACE_OFFLOAD_DEBUG("Command SHUTDOWN"); shutdown = true; @@ -198,8 +213,7 @@ template <> void VerilatedTrace::offloadWorkerThreadMain() { //=== // Unknown command default: { // LCOV_EXCL_START - VL_TRACE_OFFLOAD_DEBUG("Command UNKNOWN"); - VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); + VL_TRACE_OFFLOAD_DEBUG("Command UNKNOWN " << cmd); VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); break; } // LCOV_EXCL_STOP @@ -217,7 +231,7 @@ template <> void VerilatedTrace::offloadWorkerThreadMain() { } while (VL_LIKELY(!shutdown)); } -template <> void VerilatedTrace::shutdownOffloadWorker() { +template <> void VerilatedTrace::shutdownOffloadWorker() { // If the worker thread is not running, done.. if (!m_workerThread) return; @@ -237,7 +251,7 @@ template <> void VerilatedTrace::shutdownOffloadWorker() { //============================================================================= // Life cycle -template <> void VerilatedTrace::closeBase() { +template <> void VerilatedTrace::closeBase() { #ifdef VL_TRACE_OFFLOAD shutdownOffloadWorker(); while (m_numOffloadBuffers) { @@ -247,7 +261,7 @@ template <> void VerilatedTrace::closeBase() { #endif } -template <> void VerilatedTrace::flushBase() { +template <> void VerilatedTrace::flushBase() { #ifdef VL_TRACE_OFFLOAD // Hand an empty buffer to the worker thread uint32_t* const bufferp = getOffloadBuffer(); @@ -262,29 +276,29 @@ template <> void VerilatedTrace::flushBase() { //============================================================================= // Callbacks to run on global events -template <> void VerilatedTrace::onFlush(void* selfp) { +template <> void VerilatedTrace::onFlush(void* selfp) { // This calls 'flush' on the derived class (which must then get any mutex) - reinterpret_cast(selfp)->flush(); + reinterpret_cast(selfp)->flush(); } -template <> void VerilatedTrace::onExit(void* selfp) { +template <> void VerilatedTrace::onExit(void* selfp) { // This calls 'close' on the derived class (which must then get any mutex) - reinterpret_cast(selfp)->close(); + reinterpret_cast(selfp)->close(); } //============================================================================= // VerilatedTrace -template <> VerilatedTrace::VerilatedTrace() { +template <> VerilatedTrace::VerilatedTrace() { set_time_unit(Verilated::threadContextp()->timeunitString()); set_time_resolution(Verilated::threadContextp()->timeprecisionString()); } -template <> VerilatedTrace::~VerilatedTrace() { +template <> VerilatedTrace::~VerilatedTrace() { if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr); if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr); - Verilated::removeFlushCb(VerilatedTrace::onFlush, this); - Verilated::removeExitCb(VerilatedTrace::onExit, this); + Verilated::removeFlushCb(VerilatedTrace::onFlush, this); + Verilated::removeExitCb(VerilatedTrace::onExit, this); #ifdef VL_TRACE_OFFLOAD closeBase(); #endif @@ -293,7 +307,7 @@ template <> VerilatedTrace::~VerilatedTrace() { //========================================================================= // Internals available to format specific implementations -template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { +template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { // Note: It is possible to re-open a trace file (VCD in particular), // so we must reset the next code here, but it must have the same number // of codes on re-open @@ -338,8 +352,8 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { } // Set callback so flush/abort will flush this file - Verilated::addFlushCb(VerilatedTrace::onFlush, this); - Verilated::addExitCb(VerilatedTrace::onExit, this); + Verilated::addFlushCb(VerilatedTrace::onFlush, this); + Verilated::addExitCb(VerilatedTrace::onExit, this); #ifdef VL_TRACE_OFFLOAD // Compute offload buffer size. we need to be able to store a new value for @@ -351,13 +365,13 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { // Start the worker thread m_workerThread.reset( - new std::thread{&VerilatedTrace::offloadWorkerThreadMain, this}); + new std::thread{&VerilatedTrace::offloadWorkerThreadMain, this}); #endif } template <> -bool VerilatedTrace::declCode(uint32_t code, const char* namep, uint32_t bits, - bool tri) { +bool VerilatedTrace::declCode(uint32_t code, const char* namep, uint32_t bits, + bool tri) { if (VL_UNCOVERABLE(!code)) { VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal"); } @@ -401,28 +415,30 @@ bool VerilatedTrace::declCode(uint32_t code, const char* namep, ui //========================================================================= // Internals available to format specific implementations -template <> std::string VerilatedTrace::timeResStr() const { +template <> std::string VerilatedTrace::timeResStr() const { return doubleToTimescale(m_timeRes); } //========================================================================= // External interface to client code -template <> void VerilatedTrace::set_time_unit(const char* unitp) VL_MT_SAFE { +template <> void VerilatedTrace::set_time_unit(const char* unitp) VL_MT_SAFE { m_timeUnit = timescaleToDouble(unitp); } -template <> void VerilatedTrace::set_time_unit(const std::string& unit) VL_MT_SAFE { +template <> +void VerilatedTrace::set_time_unit(const std::string& unit) VL_MT_SAFE { set_time_unit(unit.c_str()); } -template <> void VerilatedTrace::set_time_resolution(const char* unitp) VL_MT_SAFE { +template <> +void VerilatedTrace::set_time_resolution(const char* unitp) VL_MT_SAFE { m_timeRes = timescaleToDouble(unitp); } template <> -void VerilatedTrace::set_time_resolution(const std::string& unit) VL_MT_SAFE { +void VerilatedTrace::set_time_resolution(const std::string& unit) VL_MT_SAFE { set_time_resolution(unit.c_str()); } template <> -void VerilatedTrace::dumpvars(int level, const std::string& hier) VL_MT_SAFE { +void VerilatedTrace::dumpvars(int level, const std::string& hier) VL_MT_SAFE { if (level == 0) { m_dumpvars.clear(); // empty = everything on } else { @@ -435,7 +451,87 @@ void VerilatedTrace::dumpvars(int level, const std::string& hier) } } -template <> void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_EXCLUDES(m_mutex) { +#ifdef VL_TRACE_PARALLEL +template <> // +void VerilatedTrace::parallelWorkerTask(void* datap, bool) { + ParallelWorkerData* const wdp = reinterpret_cast(datap); + // Run the task + wdp->m_cb(wdp->m_userp, wdp->m_bufp); + // Mark buffer as ready + const VerilatedLockGuard lock{wdp->m_mutex}; + wdp->m_ready.store(true); + if (wdp->m_waiting) wdp->m_cv.notify_one(); +} + +template <> VL_ATTR_NOINLINE void VerilatedTrace::ParallelWorkerData::wait() { + // Spin for a while, waiting for the buffer to become ready + for (int i = 0; i < VL_LOCK_SPINS; ++i) { + if (VL_LIKELY(m_ready.load(std::memory_order_relaxed))) return; + VL_CPU_RELAX(); + } + // We have been spinning for a while, so yield the thread + VerilatedLockGuard lock{m_mutex}; + m_waiting = true; + m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); }); + m_waiting = false; +} +#endif + +template <> +void VerilatedTrace::runParallelCallbacks(const ParallelCallbackMap& cbMap) { + for (VlThreadPool* threadPoolp : m_threadPoolps) { +#ifdef VL_TRACE_PARALLEL + // If tracing in parallel, dispatch to the thread pool (if exists) + if (threadPoolp && threadPoolp->numThreads()) { + // List of work items for thread (std::list, as ParallelWorkerData is not movable) + std::list workerData; + // We use the whole pool + the main thread + const unsigned threads = threadPoolp->numThreads() + 1; + // Main thread executes all jobs with index % threads == 0 + std::vector mainThreadWorkerData; + // The tracing callbacks to execute on this thread-pool + const auto& cbVec = cbMap.at(threadPoolp); + // Enuque all the jobs + for (unsigned i = 0; i < cbVec.size(); ++i) { + const CallbackRecord& cbr = cbVec[i]; + // Always get the trace buffer on the main thread + Buffer* const bufp = getTraceBuffer(); + // Create new work item + workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp); + // Grab the new work item + ParallelWorkerData* const itemp = &workerData.back(); + // Enqueue task to thread pool, or main thread + if (unsigned rem = i % threads) { + threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp, false); + } else { + mainThreadWorkerData.push_back(itemp); + } + } + // Execute main thead jobs + for (ParallelWorkerData* const itemp : mainThreadWorkerData) { + parallelWorkerTask(itemp, false); + } + // Commit all trace buffers in order + for (ParallelWorkerData& item : workerData) { + // Wait until ready + item.wait(); + // Commit the buffer + commitTraceBuffer(item.m_bufp); + } + continue; + } +#endif + // Fall back on sequential execution + for (const CallbackRecord& cbr : cbMap.at(threadPoolp)) { + Buffer* const traceBufferp = getTraceBuffer(); + cbr.m_dumpCb(cbr.m_userp, traceBufferp); + commitTraceBuffer(traceBufferp); + } + } +} + +template <> +void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_EXCLUDES(m_mutex) { // Not really VL_MT_SAFE but more VL_MT_UNSAFE_ONE. // This does get the mutex, but if multiple threads are trying to dump // chances are the data being dumped will have other problems @@ -483,20 +579,14 @@ template <> void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_ // Run the callbacks if (VL_UNLIKELY(m_fullDump)) { m_fullDump = false; // No more need for next dump to be full - for (uint32_t i = 0; i < m_fullCbs.size(); ++i) { - const CallbackRecord& cbr = m_fullCbs[i]; - cbr.m_dumpCb(cbr.m_userp, self()); - } + runParallelCallbacks(m_fullCbs); } else { - for (uint32_t i = 0; i < m_chgCbs.size(); ++i) { - const CallbackRecord& cbr = m_chgCbs[i]; - cbr.m_dumpCb(cbr.m_userp, self()); - } + runParallelCallbacks(m_chgCbs); } for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) { const CallbackRecord& cbr = m_cleanupCbs[i]; - cbr.m_dumpCb(cbr.m_userp, self()); + cbr.m_cleanupCb(cbr.m_userp, self()); } #ifdef VL_TRACE_OFFLOAD @@ -517,8 +607,18 @@ template <> void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_ // Non-hot path internal interface to Verilator generated code template <> -void VerilatedTrace::addCallbackRecord(std::vector& cbVec, - CallbackRecord& cbRec) +void VerilatedTrace::addThreadPool(VlThreadPool* threadPoolp) + VL_MT_SAFE_EXCLUDES(m_mutex) { + const VerilatedLockGuard lock{m_mutex}; + for (VlThreadPool* const poolp : m_threadPoolps) { + if (poolp == threadPoolp) return; + } + m_threadPoolps.push_back(threadPoolp); +} + +template <> +void VerilatedTrace::addCallbackRecord(std::vector& cbVec, + CallbackRecord& cbRec) VL_MT_SAFE_EXCLUDES(m_mutex) { const VerilatedLockGuard lock{m_mutex}; if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START @@ -529,91 +629,40 @@ void VerilatedTrace::addCallbackRecord(std::vector cbVec.push_back(cbRec); } -template <> void VerilatedTrace::addInitCb(initCb_t cb, void* userp) VL_MT_SAFE { +template <> +void VerilatedTrace::addInitCb(initCb_t cb, void* userp) VL_MT_SAFE { CallbackRecord cbr{cb, userp}; addCallbackRecord(m_initCbs, cbr); } -template <> void VerilatedTrace::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE { +template <> +void VerilatedTrace::addFullCb(dumpCb_t cb, void* userp, + VlThreadPool* threadPoolp) VL_MT_SAFE { CallbackRecord cbr{cb, userp}; - addCallbackRecord(m_fullCbs, cbr); + addThreadPool(threadPoolp); + addCallbackRecord(m_fullCbs[threadPoolp], cbr); } -template <> void VerilatedTrace::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE { +template <> +void VerilatedTrace::addChgCb(dumpCb_t cb, void* userp, + VlThreadPool* threadPoolp) VL_MT_SAFE { CallbackRecord cbr{cb, userp}; - addCallbackRecord(m_chgCbs, cbr); + addThreadPool(threadPoolp); + addCallbackRecord(m_chgCbs[threadPoolp], cbr); } -template <> void VerilatedTrace::addCleanupCb(dumpCb_t cb, void* userp) VL_MT_SAFE { +template <> +void VerilatedTrace::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE { CallbackRecord cbr{cb, userp}; addCallbackRecord(m_cleanupCbs, cbr); } -template <> void VerilatedTrace::pushNamePrefix(const std::string& prefix) { +template <> void VerilatedTrace::pushNamePrefix(const std::string& prefix) { m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix); } -template <> void VerilatedTrace::popNamePrefix(unsigned count) { +template <> void VerilatedTrace::popNamePrefix(unsigned count) { while (count--) m_namePrefixStack.pop_back(); assert(!m_namePrefixStack.empty()); } -//========================================================================= -// Hot path internal interface to Verilator generated code - -// These functions must write the new value back into the old value store, -// and subsequently call the format specific emit* implementations. Note -// that this file must be included in the format specific implementation, so -// the emit* functions can be inlined for performance. - -template <> void VerilatedTrace::fullBit(uint32_t* oldp, CData newval) { - const uint32_t code = oldp - m_sigs_oldvalp; - *oldp = newval; // Still copy even if not tracing so chg doesn't call full - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitBit(code, newval); -} - -template <> void VerilatedTrace::fullCData(uint32_t* oldp, CData newval, int bits) { - const uint32_t code = oldp - m_sigs_oldvalp; - *oldp = newval; // Still copy even if not tracing so chg doesn't call full - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitCData(code, newval, bits); -} - -template <> void VerilatedTrace::fullSData(uint32_t* oldp, SData newval, int bits) { - const uint32_t code = oldp - m_sigs_oldvalp; - *oldp = newval; // Still copy even if not tracing so chg doesn't call full - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitSData(code, newval, bits); -} - -template <> void VerilatedTrace::fullIData(uint32_t* oldp, IData newval, int bits) { - const uint32_t code = oldp - m_sigs_oldvalp; - *oldp = newval; // Still copy even if not tracing so chg doesn't call full - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitIData(code, newval, bits); -} - -template <> void VerilatedTrace::fullQData(uint32_t* oldp, QData newval, int bits) { - const uint32_t code = oldp - m_sigs_oldvalp; - *reinterpret_cast(oldp) = newval; - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitQData(code, newval, bits); -} - -template <> -void VerilatedTrace::fullWData(uint32_t* oldp, const WData* newvalp, int bits) { - const uint32_t code = oldp - m_sigs_oldvalp; - for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i]; - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - self()->emitWData(code, newvalp, bits); -} - -template <> void VerilatedTrace::fullDouble(uint32_t* oldp, double newval) { - const uint32_t code = oldp - m_sigs_oldvalp; - *reinterpret_cast(oldp) = newval; - if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; - // cppcheck-suppress invalidPointerCast - self()->emitDouble(code, newval); -} - //========================================================================= // Primitives converting binary values to strings... @@ -704,4 +753,86 @@ static inline void cvtQDataToStr(char* dstp, QData value) { #define cvtEDataToStr cvtIDataToStr +//========================================================================= +// VerilatedTraceBuffer + +template <> // +VerilatedTraceBuffer::VerilatedTraceBuffer(VL_SUB_T& owner) + : m_owner{owner} { +#ifdef VL_TRACE_OFFLOAD + if (m_offloadBufferWritep) { + using This = VerilatedTraceBuffer*; + // Tack on the buffer address + static_assert(2 * sizeof(uint32_t) >= sizeof(This), + "This should be enough on all plafrorms"); + *m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::TRACE_BUFFER; + *reinterpret_cast(m_offloadBufferWritep) = this; + m_offloadBufferWritep += 2; + } +#endif +} + +// These functions must write the new value back into the old value store, +// and subsequently call the format specific emit* implementations. Note +// that this file must be included in the format specific implementation, so +// the emit* functions can be inlined for performance. + +template <> // +void VerilatedTraceBuffer::fullBit(uint32_t* oldp, CData newval) { + const uint32_t code = oldp - m_sigs_oldvalp; + *oldp = newval; // Still copy even if not tracing so chg doesn't call full + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitBit(code, newval); +} + +template <> +void VerilatedTraceBuffer::fullCData(uint32_t* oldp, CData newval, int bits) { + const uint32_t code = oldp - m_sigs_oldvalp; + *oldp = newval; // Still copy even if not tracing so chg doesn't call full + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitCData(code, newval, bits); +} + +template <> +void VerilatedTraceBuffer::fullSData(uint32_t* oldp, SData newval, int bits) { + const uint32_t code = oldp - m_sigs_oldvalp; + *oldp = newval; // Still copy even if not tracing so chg doesn't call full + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitSData(code, newval, bits); +} + +template <> +void VerilatedTraceBuffer::fullIData(uint32_t* oldp, IData newval, int bits) { + const uint32_t code = oldp - m_sigs_oldvalp; + *oldp = newval; // Still copy even if not tracing so chg doesn't call full + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitIData(code, newval, bits); +} + +template <> +void VerilatedTraceBuffer::fullQData(uint32_t* oldp, QData newval, int bits) { + const uint32_t code = oldp - m_sigs_oldvalp; + *reinterpret_cast(oldp) = newval; + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitQData(code, newval, bits); +} + +template <> +void VerilatedTraceBuffer::fullWData(uint32_t* oldp, const WData* newvalp, + int bits) { + const uint32_t code = oldp - m_sigs_oldvalp; + for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i]; + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + self()->emitWData(code, newvalp, bits); +} + +template <> +void VerilatedTraceBuffer::fullDouble(uint32_t* oldp, double newval) { + const uint32_t code = oldp - m_sigs_oldvalp; + *reinterpret_cast(oldp) = newval; + if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; + // cppcheck-suppress invalidPointerCast + self()->emitDouble(code, newval); +} + #endif // VL_CPPCHECK diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 8e0008e3f..9db71aabc 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -62,12 +62,23 @@ constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; // Maximum length of a VCD s // cache-lines. constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry +//============================================================================= +// Utility functions: TODO: put these in a common place and share them. + +template static size_t roundUpToMultipleOf(size_t value) { + static_assert((N & (N - 1)) == 0, "'N' must be a power of 2"); + size_t mask = N - 1; + return (value + mask) & ~mask; +} + //============================================================================= // Specialization of the generics for this trace format -#define VL_DERIVED_T VerilatedVcd +#define VL_SUB_T VerilatedVcd +#define VL_BUF_T VerilatedVcdBuffer #include "verilated_trace_imp.h" -#undef VL_DERIVED_T +#undef VL_SUB_T +#undef VL_BUF_T //============================================================================= //============================================================================= @@ -183,7 +194,7 @@ void VerilatedVcd::makeNameMap() { deleteNameMap(); m_namemapp = new NameMap; - VerilatedTrace::traceInit(); + Super::traceInit(); // Though not speced, it's illegal to generate a vcd with signals // not under any module - it crashes at least two viewers. @@ -218,13 +229,17 @@ VerilatedVcd::~VerilatedVcd() { if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr); deleteNameMap(); if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr); +#ifdef VL_TRACE_PARALLEL + assert(m_numBuffers == m_freeBuffers.size()); + for (auto& pair : m_freeBuffers) VL_DO_CLEAR(delete[] pair.first, pair.first = nullptr); +#endif } void VerilatedVcd::closePrev() { // This function is on the flush() call path if (!isOpen()) return; - VerilatedTrace::flushBase(); + Super::flushBase(); bufferFlush(); m_isOpen = false; m_filep->close(); @@ -251,14 +266,14 @@ void VerilatedVcd::close() VL_MT_SAFE_EXCLUDES(m_mutex) { printStr(" $end\n"); } closePrev(); - // closePrev() called VerilatedTrace::flush(), so we just + // closePrev() called Super::flush(), so we just // need to shut down the tracing thread here. - VerilatedTrace::closeBase(); + Super::closeBase(); } void VerilatedVcd::flush() VL_MT_SAFE_EXCLUDES(m_mutex) { const VerilatedLockGuard lock{m_mutex}; - VerilatedTrace::flushBase(); + Super::flushBase(); bufferFlush(); } @@ -277,12 +292,12 @@ void VerilatedVcd::printQuad(uint64_t n) { printStr(buf); } -void VerilatedVcd::bufferResize(uint64_t minsize) { +void VerilatedVcd::bufferResize(size_t minsize) { // minsize is size of largest write. We buffer at least 8 times as much data, // writing when we are 3/4 full (with thus 2*minsize remaining free) if (VL_UNLIKELY(minsize > m_wrChunkSize)) { const char* oldbufp = m_wrBufp; - m_wrChunkSize = minsize * 2; + m_wrChunkSize = roundUpToMultipleOf<1024>(minsize * 2); m_wrBufp = new char[m_wrChunkSize * 8]; std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp); m_writep = m_wrBufp + (m_writep - oldbufp); @@ -463,14 +478,16 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b int arraynum, bool tri, bool bussed, int msb, int lsb) { const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1; - const bool enabled = VerilatedTrace::declCode(code, name, bits, tri); + const bool enabled = Super::declCode(code, name, bits, tri); if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) { m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0); } - // Make sure write buffer is large enough (one character per bit), plus header - bufferResize(bits + 1024); + // Keep upper bound on bytes a single signal cna emit into the buffer + m_maxSignalBytes = std::max(m_maxSignalBytes, bits + 32); + // Make sure write buffer is large enough, plus header + bufferResize(m_maxSignalBytes + 1024); if (!enabled) return; @@ -564,7 +581,71 @@ void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int a } //============================================================================= -// Trace rendering prinitives +// Get/commit trace buffer + +VerilatedVcdBuffer* VerilatedVcd::getTraceBuffer() { +#ifdef VL_TRACE_PARALLEL + // Note: This is called from VeriltedVcd::dump, which already holds the lock + // If no buffer available, allocate a new one + if (m_freeBuffers.empty()) { + constexpr size_t pageSize = 4096; + // 4 * m_maxSignalBytes, so we can reserve 2 * m_maxSignalBytes at the end for safety + size_t startingSize = roundUpToMultipleOf(4 * m_maxSignalBytes); + m_freeBuffers.emplace_back(new char[startingSize], startingSize); + ++m_numBuffers; + } + // Grab a buffer + const auto pair = m_freeBuffers.back(); + m_freeBuffers.pop_back(); + // Return the buffer + return new VerilatedVcdBuffer{*this, pair.first, pair.second}; +#else + return new VerilatedVcdBuffer{*this}; +#endif +} + +void VerilatedVcd::commitTraceBuffer(VerilatedVcdBuffer* bufp) { +#ifdef VL_TRACE_PARALLEL + // Note: This is called from VeriltedVcd::dump, which already holds the lock + // Resize output buffer. Note, we use the full size of the trace buffer, as + // this is a lot more stable than the actual occupancy of the trace buffer. + // This helps us to avoid re-allocations due to small size changes. + bufferResize(bufp->m_size); + // Compute occupancy of buffer + const size_t usedSize = bufp->m_writep - bufp->m_bufp; + // Copy to output buffer + std::memcpy(m_writep, bufp->m_bufp, usedSize); + // Adjust write pointer + m_writep += usedSize; + // Flush if necessary + bufferCheck(); + // Put buffer back on free list + m_freeBuffers.emplace_back(bufp->m_bufp, bufp->m_size); +#else + // Needs adjusting for emitTimeChange + m_writep = bufp->m_writep; +#endif + delete bufp; +} + +//============================================================================= +// VerilatedVcdBuffer implementation + +#ifdef VL_TRACE_PARALLEL +VerilatedVcdBuffer::VerilatedVcdBuffer(VerilatedVcd& owner, char* bufp, size_t size) + : VerilatedTraceBuffer{owner} + , m_writep{bufp} + , m_bufp{bufp} + , m_size{size} { + adjustGrowp(); +} +#else +VerilatedVcdBuffer::VerilatedVcdBuffer(VerilatedVcd& owner) + : VerilatedTraceBuffer{owner} {} +#endif + +//============================================================================= +// Trace rendering primitives static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; @@ -589,15 +670,44 @@ static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* s #endif } -void VerilatedVcd::finishLine(uint32_t code, char* writep) { - const char* const suffixp = m_suffixes.data() + code * VL_TRACE_SUFFIX_ENTRY_SIZE; +void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) { + const char* const suffixp = m_suffixes + code * VL_TRACE_SUFFIX_ENTRY_SIZE; VL_DEBUG_IFDEF(assert(suffixp[0]);); VerilatedVcdCCopyAndAppendNewLine(writep, suffixp); // Now write back the write pointer incremented by the actual size of the // suffix, which was stored in the last byte of the suffix buffer entry. m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1]; - bufferCheck(); + +#ifdef VL_TRACE_PARALLEL + // Double the size of the buffer if necessary + if (VL_UNLIKELY(m_writep >= m_growp)) { + // Compute occupied size of current buffer + const size_t usedSize = m_writep - m_bufp; + // We are always doubling the size + m_size *= 2; + // Allocate the new buffer + char* const newBufp = new char[m_size]; + // Copy from current buffer to new buffer + std::memcpy(newBufp, m_bufp, usedSize); + // Delete current buffer + delete[] m_bufp; + // Make new buffer the current buffer + m_bufp = newBufp; + // Adjust write pointer + m_writep = m_bufp + usedSize; + // Adjust resize limit + adjustGrowp(); + } +#else + // Flush the write buffer if there's not enough space left for new information + // We only call this once per vector, so we need enough slop for a very wide "b###" line + if (VL_UNLIKELY(m_writep > m_wrFlushp)) { + m_owner.m_writep = m_writep; + m_owner.bufferFlush(); + m_writep = m_owner.m_writep; + } +#endif } //============================================================================= @@ -608,7 +718,7 @@ void VerilatedVcd::finishLine(uint32_t code, char* writep) { // so always inline them. VL_ATTR_ALWINLINE -void VerilatedVcd::emitBit(uint32_t code, CData newval) { +void VerilatedVcdBuffer::emitBit(uint32_t code, CData newval) { // Don't prefetch suffix as it's a bit too late; char* wp = m_writep; *wp++ = '0' | static_cast(newval); @@ -616,7 +726,7 @@ void VerilatedVcd::emitBit(uint32_t code, CData newval) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitCData(uint32_t code, CData newval, int bits) { +void VerilatedVcdBuffer::emitCData(uint32_t code, CData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; cvtCDataToStr(wp, newval << (VL_BYTESIZE - bits)); @@ -624,7 +734,7 @@ void VerilatedVcd::emitCData(uint32_t code, CData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitSData(uint32_t code, SData newval, int bits) { +void VerilatedVcdBuffer::emitSData(uint32_t code, SData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; cvtSDataToStr(wp, newval << (VL_SHORTSIZE - bits)); @@ -632,7 +742,7 @@ void VerilatedVcd::emitSData(uint32_t code, SData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitIData(uint32_t code, IData newval, int bits) { +void VerilatedVcdBuffer::emitIData(uint32_t code, IData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; cvtIDataToStr(wp, newval << (VL_IDATASIZE - bits)); @@ -640,7 +750,7 @@ void VerilatedVcd::emitIData(uint32_t code, IData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitQData(uint32_t code, QData newval, int bits) { +void VerilatedVcdBuffer::emitQData(uint32_t code, QData newval, int bits) { char* wp = m_writep; *wp++ = 'b'; cvtQDataToStr(wp, newval << (VL_QUADSIZE - bits)); @@ -648,7 +758,7 @@ void VerilatedVcd::emitQData(uint32_t code, QData newval, int bits) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitWData(uint32_t code, const WData* newvalp, int bits) { +void VerilatedVcdBuffer::emitWData(uint32_t code, const WData* newvalp, int bits) { int words = VL_WORDS_I(bits); char* wp = m_writep; *wp++ = 'b'; @@ -665,10 +775,10 @@ void VerilatedVcd::emitWData(uint32_t code, const WData* newvalp, int bits) { } VL_ATTR_ALWINLINE -void VerilatedVcd::emitDouble(uint32_t code, double newval) { +void VerilatedVcdBuffer::emitDouble(uint32_t code, double newval) { char* wp = m_writep; // Buffer can't overflow before VL_SNPRINTF; we sized during declaration - VL_SNPRINTF(wp, m_wrChunkSize, "r%.16g", newval); + VL_SNPRINTF(wp, m_maxSignalBytes, "r%.16g", newval); wp += std::strlen(wp); finishLine(code, wp); } diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index b1485e13b..0d83eb25d 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -28,39 +28,20 @@ #include #include -class VerilatedVcd; - -//============================================================================= -// VerilatedFile -/// Class representing a file to write to. These virtual methods can be -/// overrode for e.g. socket I/O. - -class VerilatedVcdFile VL_NOT_FINAL { -private: - int m_fd = 0; // File descriptor we're writing to -public: - // METHODS - /// Construct a (as yet) closed file - VerilatedVcdFile() = default; - /// Close and destruct - virtual ~VerilatedVcdFile() = default; - /// Open a file with given filename - virtual bool open(const std::string& name) VL_MT_UNSAFE; - /// Close object's file - virtual void close() VL_MT_UNSAFE; - /// Write data to file (if it is open) - virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE; -}; +class VerilatedVcdBuffer; +class VerilatedVcdFile; //============================================================================= // VerilatedVcd // Base class to create a Verilator VCD dump // This is an internally used class - see VerilatedVcdC for what to call from applications -class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace { +class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace { +public: + using Super = VerilatedTrace; + private: - // Give the superclass access to private bits (to avoid virtual functions) - friend class VerilatedTrace; + friend Buffer; // Give the buffer access to the private bits //========================================================================= // VCD specific internals @@ -74,9 +55,10 @@ private: int m_modDepth = 0; // Depth of module hierarchy char* m_wrBufp; // Output buffer - const char* m_wrFlushp; // Output buffer flush trigger location + char* m_wrFlushp; // Output buffer flush trigger location char* m_writep; // Write pointer into output buffer - uint64_t m_wrChunkSize; // Output buffer size + size_t m_wrChunkSize; // Output buffer size + size_t m_maxSignalBytes = 0; // Upper bound on number of bytes a single signal can generate uint64_t m_wroteBytes = 0; // Number of bytes written to this file std::vector m_suffixes; // VCD line end string codes + metadata @@ -84,7 +66,13 @@ private: using NameMap = std::map; NameMap* m_namemapp = nullptr; // List of names for the header - void bufferResize(uint64_t minsize); +#ifdef VL_TRACE_PARALLEL + // Vector of free trace buffers as (pointer, size) pairs. + std::vector> m_freeBuffers; + size_t m_numBuffers = 0; // Number of trace buffers allocated +#endif + + void bufferResize(size_t minsize); void bufferFlush() VL_MT_UNSAFE_ONE; inline void bufferCheck() { // Flush the write buffer if there's not enough space left for new information @@ -107,8 +95,6 @@ private: static char* writeCode(char* writep, uint32_t code); - void finishLine(uint32_t code, char* writep); - // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcd); @@ -116,27 +102,22 @@ protected: //========================================================================= // Implementation of VerilatedTrace interface - // Implementations of protected virtual methods for VerilatedTrace + // Called when the trace moves forward to a new time point virtual void emitTimeChange(uint64_t timeui) override; // Hooks called from VerilatedTrace virtual bool preFullDump() override { return isOpen(); } virtual bool preChangeDump() override; - // Implementations of duck-typed methods for VerilatedTrace. These are - // called from only one place (namely full*) so always inline them. - inline void emitBit(uint32_t code, CData newval); - inline void emitCData(uint32_t code, CData newval, int bits); - inline void emitSData(uint32_t code, SData newval, int bits); - inline void emitIData(uint32_t code, IData newval, int bits); - inline void emitQData(uint32_t code, QData newval, int bits); - inline void emitWData(uint32_t code, const WData* newvalp, int bits); - inline void emitDouble(uint32_t code, double newval); + // Trace buffer management + virtual VerilatedVcdBuffer* getTraceBuffer() override; + virtual void commitTraceBuffer(VerilatedVcdBuffer*) override; public: //========================================================================= // External interface to client code + // CONSTRUCTOR explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr); ~VerilatedVcd(); @@ -144,7 +125,7 @@ public: // Set size in megabytes after which new file should be created void rolloverMB(uint64_t rolloverMB) { m_rolloverMB = rolloverMB; } - // METHODS + // METHODS - All must be thread safe // Open the file; call isOpen() to see if errors void open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex); // Open next data-only file @@ -167,15 +148,92 @@ public: }; #ifndef DOXYGEN -// Declare specializations here they are used in VerilatedVcdC just below -template <> void VerilatedTrace::dump(uint64_t timeui); -template <> void VerilatedTrace::set_time_unit(const char* unitp); -template <> void VerilatedTrace::set_time_unit(const std::string& unit); -template <> void VerilatedTrace::set_time_resolution(const char* unitp); -template <> void VerilatedTrace::set_time_resolution(const std::string& unit); -template <> void VerilatedTrace::dumpvars(int level, const std::string& hier); +// Declare specialization here as it's used in VerilatedFstC just below +template <> void VerilatedVcd::Super::dump(uint64_t time); +template <> void VerilatedVcd::Super::set_time_unit(const char* unitp); +template <> void VerilatedVcd::Super::set_time_unit(const std::string& unit); +template <> void VerilatedVcd::Super::set_time_resolution(const char* unitp); +template <> void VerilatedVcd::Super::set_time_resolution(const std::string& unit); +template <> void VerilatedVcd::Super::dumpvars(int level, const std::string& hier); #endif // DOXYGEN +//============================================================================= +// VerilatedVcdBuffer + +class VerilatedVcdBuffer final : public VerilatedTraceBuffer { + // Give the trace file access to the private bits + friend VerilatedVcd; + friend VerilatedVcd::Super; + +#ifdef VL_TRACE_PARALLEL + char* m_writep; // Write pointer into m_bufp + char* m_bufp; // The beginning of the trace buffer + size_t m_size; // The size of the buffer at m_bufp + char* m_growp; // Resize limit pointer +#else + char* m_writep = m_owner.m_writep; // Write pointer into output buffer + char* const m_wrFlushp = m_owner.m_wrFlushp; // Output buffer flush trigger location +#endif + + // VCD line end string codes + metadata + const char* const m_suffixes = m_owner.m_suffixes.data(); + // The maximum number of bytes a single signal can emit + const size_t m_maxSignalBytes = m_owner.m_maxSignalBytes; + + void finishLine(uint32_t code, char* writep); + +#ifdef VL_TRACE_PARALLEL + void adjustGrowp() { + m_growp = (m_bufp + m_size) - (2 * m_maxSignalBytes); + assert(m_growp >= m_bufp + m_maxSignalBytes); + } +#endif + +public: + // CONSTRUCTOR +#ifdef VL_TRACE_PARALLEL + explicit VerilatedVcdBuffer(VerilatedVcd& owner, char* bufp, size_t size); +#else + explicit VerilatedVcdBuffer(VerilatedVcd& owner); +#endif + ~VerilatedVcdBuffer() = default; + + //========================================================================= + // Implementation of VerilatedTraceBuffer interface + + // Implementations of duck-typed methods for VerilatedTraceBuffer. These are + // called from only one place (the full* methods), so always inline them. + VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); + VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); + VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); + VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); + VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); + VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); + VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); +}; + +//============================================================================= +// VerilatedFile +/// Class representing a file to write to. These virtual methods can be +/// overrode for e.g. socket I/O. + +class VerilatedVcdFile VL_NOT_FINAL { +private: + int m_fd = 0; // File descriptor we're writing to +public: + // METHODS + /// Construct a (as yet) closed file + VerilatedVcdFile() = default; + /// Close and destruct + virtual ~VerilatedVcdFile() = default; + /// Open a file with given filename + virtual bool open(const std::string& name) VL_MT_UNSAFE; + /// Close object's file + virtual void close() VL_MT_UNSAFE; + /// Write data to file (if it is open) + virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE; +}; + //============================================================================= // VerilatedVcdC /// Class representing a VCD dump file in C standalone (no SystemC) diff --git a/include/verilatedos.h b/include/verilatedos.h index 28412cac4..6bacfe27b 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -40,6 +40,7 @@ #ifdef __GNUC__ # define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) # define VL_ATTR_ALWINLINE __attribute__((always_inline)) +# define VL_ATTR_NOINLINE __attribute__((noinline)) # define VL_ATTR_COLD __attribute__((cold)) # define VL_ATTR_HOT __attribute__((hot)) # define VL_ATTR_NORETURN __attribute__((noreturn)) @@ -82,6 +83,9 @@ #ifndef VL_ATTR_ALWINLINE # define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing #endif +#ifndef VL_ATTR_NOINLINE +# define VL_ATTR_NOINLINE ///< Attribute to never inline, even when optimizing +#endif #ifndef VL_ATTR_COLD # define VL_ATTR_COLD ///< Attribute that function is rarely executed #endif diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 0d979b143..c88648d3f 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -751,26 +751,26 @@ class EmitCTrace final : EmitCFunc { const string func = nodep->full() ? "full" : "chg"; bool emitWidth = true; if (nodep->dtypep()->basicp()->isDouble()) { - puts("tracep->" + func + "Double"); + puts("bufp->" + func + "Double"); emitWidth = false; } else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) { - puts("tracep->" + func + "WData"); + puts("bufp->" + func + "WData"); } else if (nodep->isQuad()) { - puts("tracep->" + func + "QData"); + puts("bufp->" + func + "QData"); } else if (nodep->declp()->widthMin() > 16) { - puts("tracep->" + func + "IData"); + puts("bufp->" + func + "IData"); } else if (nodep->declp()->widthMin() > 8) { - puts("tracep->" + func + "SData"); + puts("bufp->" + func + "SData"); } else if (nodep->declp()->widthMin() > 1) { - puts("tracep->" + func + "CData"); + puts("bufp->" + func + "CData"); } else { - puts("tracep->" + func + "Bit"); + puts("bufp->" + func + "Bit"); emitWidth = false; } const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords()); const uint32_t code = nodep->declp()->code() + offset; - puts(v3Global.opt.useTraceOffloadThread() && !nodep->full() ? "(base+" : "(oldp+"); + puts(v3Global.opt.useTraceOffload() && !nodep->full() ? "(base+" : "(oldp+"); puts(cvtToStr(code - nodep->baseCode())); puts(","); emitTraceValue(nodep, arrayindex); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 67e8a741c..7df71dfeb 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -113,9 +113,8 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); - *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; - cmake_set_raw(*of, name + "_TRACE_THREADS", - cvtToStr(v3Global.opt.useTraceOffloadThread())); + *of << "# Threaded tracing output mode? 0/1/N threads (from --threads/--trace-threads)\n"; + cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.vmTraceThreads())); cmake_set_raw(*of, name + "_TRACE_FST_WRITER_THREAD", v3Global.opt.traceThreads() && v3Global.opt.traceFormat().fst() ? "1" : "0"); *of << "# Struct output mode? 0/1 (from --trace-structs)\n"; diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 429b78d33..b748d9553 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -73,9 +73,10 @@ public: of.puts("VM_TRACE_FST = "); of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0"); of.puts("\n"); - of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); + of.puts( + "# Tracing threaded output mode? 0/1/N threads (from --threads/--trace-thread)\n"); of.puts("VM_TRACE_THREADS = "); - of.puts(cvtToStr(v3Global.opt.useTraceOffloadThread())); + of.puts(cvtToStr(v3Global.opt.vmTraceThreads())); of.puts("\n"); of.puts("# Separate FST writer thread? 0/1 (from --trace-fst with --trace-thread > 0)\n"); of.puts("VM_TRACE_FST_WRITER_THREAD = "); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1b74f1062..93d23eb5e 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -775,8 +775,16 @@ void V3Options::notify() { && !v3Global.opt.xmlOnly()); } - // --trace-threads implies --threads 1 unless explicitly specified - if (traceThreads() && !threads()) m_threads = 1; + if (trace()) { + // With --trace-fst, --trace-threads implies --threads 1 unless explicitly specified + if (traceFormat().fst() && traceThreads() && !threads()) m_threads = 1; + + // With --trace, --trace-threads is ignored + if (traceFormat().vcd()) m_traceThreads = threads() ? 1 : 0; + } + + UASSERT(!(useTraceParallel() && useTraceOffload()), + "Cannot use both parallel and offloaded tracing"); // Default split limits if not specified if (m_outputSplitCFuncs < 0) m_outputSplitCFuncs = m_outputSplit; @@ -1350,7 +1358,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-trace-threads", CbVal, [this, fl](const char* valp) { m_trace = true; m_traceThreads = std::atoi(valp); - if (m_traceThreads < 0) fl->v3fatal("--trace-threads must be >= 0: " << valp); + if (m_traceThreads < 1) fl->v3fatal("--trace-threads must be >= 1: " << valp); }); DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore); diff --git a/src/V3Options.h b/src/V3Options.h index 35a71ed31..b9b5ef8ff 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -518,8 +518,10 @@ public: int traceMaxArray() const { return m_traceMaxArray; } int traceMaxWidth() const { return m_traceMaxWidth; } int traceThreads() const { return m_traceThreads; } - bool useTraceOffloadThread() const { - return traceThreads() == 0 ? 0 : traceThreads() - traceFormat().fst(); + bool useTraceOffload() const { return trace() && traceFormat().fst() && traceThreads() > 1; } + bool useTraceParallel() const { return trace() && traceFormat().vcd() && threads() > 1; } + unsigned vmTraceThreads() const { + return useTraceParallel() ? threads() : useTraceOffload() ? 1 : 0; } int unrollCount() const { return m_unrollCount; } int unrollStmts() const { return m_unrollStmts; } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 61d009b6f..9fa1b099a 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -180,6 +180,10 @@ private: TraceActivityVertex* const m_alwaysVtxp; // "Always trace" vertex bool m_finding = false; // Pass one of algorithm? + // Trace parallelism. Only VCD tracing can be parallelized at this time. + const uint32_t m_parallelism + = v3Global.opt.useTraceParallel() ? static_cast(v3Global.opt.threads()) : 1; + VDouble0 m_statUniqSigs; // Statistic tracking VDouble0 m_statUniqCodes; // Statistic tracking @@ -388,7 +392,7 @@ private: if (!it->second->duplicatep()) { uint32_t cost = 0; const AstTraceDecl* const declp = it->second->nodep(); - // The number of comparisons required by tracep->chg* + // The number of comparisons required by bufp->chg* cost += declp->isWide() ? declp->codeInc() : 1; // Arrays are traced by element cost *= declp->arrayRange().ranged() ? declp->arrayRange().elements() : 1; @@ -494,7 +498,7 @@ private: }; if (isTopFunc) { // Top functions - funcp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "* tracep"); + funcp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "::Buffer* bufp"); addInitStr(voidSelfAssign(m_topModp)); addInitStr(symClassAssign()); // Add global activity check to change dump functions @@ -508,32 +512,33 @@ private: m_regFuncp->addStmtsp(new AstText(flp, "tracep->addChgCb(", true)); } m_regFuncp->addStmtsp(new AstAddrOfCFunc(flp, funcp)); - m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf);\n", true)); + const string threadPool{m_parallelism > 1 ? "vlSymsp->__Vm_threadPoolp" : "nullptr"}; + m_regFuncp->addStmtsp(new AstText(flp, ", vlSelf, " + threadPool + ");\n", true)); } else { // Sub functions - funcp->argTypes(v3Global.opt.traceClassBase() + "* tracep"); + funcp->argTypes(v3Global.opt.traceClassBase() + "::Buffer* bufp"); // Setup base references. Note in rare occasions we can end up with an empty trace // sub function, hence the VL_ATTR_UNUSED attributes. if (full) { // Full dump sub function addInitStr("uint32_t* const oldp VL_ATTR_UNUSED = " - "tracep->oldp(vlSymsp->__Vm_baseCode);\n"); + "bufp->oldp(vlSymsp->__Vm_baseCode);\n"); } else { // Change dump sub function - if (v3Global.opt.useTraceOffloadThread()) { + if (v3Global.opt.useTraceOffload()) { addInitStr("const uint32_t base VL_ATTR_UNUSED = " "vlSymsp->__Vm_baseCode + " + cvtToStr(baseCode) + ";\n"); - addInitStr("if (false && tracep) {} // Prevent unused\n"); + addInitStr("if (false && bufp) {} // Prevent unused\n"); } else { addInitStr("uint32_t* const oldp VL_ATTR_UNUSED = " - "tracep->oldp(vlSymsp->__Vm_baseCode + " + "bufp->oldp(vlSymsp->__Vm_baseCode + " + cvtToStr(baseCode) + ");\n"); } } // Add call to top function AstCCall* const callp = new AstCCall(funcp->fileline(), funcp); - callp->argTypes("tracep"); + callp->argTypes("bufp"); topFuncp->addStmtsp(callp); } // Done @@ -728,7 +733,7 @@ private: // We will split functions such that each have to dump roughly the same amount of data // for this we need to keep tack of the number of codes used by the trace functions. uint32_t nFullCodes = 0; // Number of non-duplicate codes (need to go into full* dump) - uint32_t nChgCodes = 0; // Number of non-consant codes (need to go in to chg* dump) + uint32_t nChgCodes = 0; // Number of non-constant codes (need to go in to chg* dump) sortTraces(traces, nFullCodes, nChgCodes); UINFO(5, "nFullCodes: " << nFullCodes << " nChgCodes: " << nChgCodes << endl); @@ -747,13 +752,11 @@ private: m_regFuncp->isLoose(true); m_topScopep->addActivep(m_regFuncp); - const int parallelism = 1; // Note: will bump this later, code below works for any value - // Create the full dump functions, also allocates signal numbers - createFullTraceFunction(traces, nFullCodes, parallelism); + createFullTraceFunction(traces, nFullCodes, m_parallelism); // Create the incremental dump functions - createChgTraceFunctions(traces, nChgCodes, parallelism); + createChgTraceFunctions(traces, nChgCodes, m_parallelism); // Remove refs to traced values from TraceDecl nodes, these have now moved under // TraceInc diff --git a/test_regress/driver.pl b/test_regress/driver.pl index ffcfac4a8..fbae94f92 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -924,7 +924,6 @@ sub compile_vlt_flags { unshift @verilator_flags, "--trace" if $opt_trace; my $threads = ::calc_threads($Vltmt_threads); unshift @verilator_flags, "--threads $threads" if $param{vltmt} && $checkflags !~ /-threads /; - unshift @verilator_flags, "--trace-threads 1" if $param{vltmt} && $checkflags =~ /-trace /; unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim; From 26b74521780850ae05bc832200a6e340ba6e4f28 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Mon, 30 May 2022 19:33:06 +0900 Subject: [PATCH 46/68] Fix #3445 of BitOpTreeOpt (#3453) * Tests: Check BitOpTree statistics in t_const_opt. * Tests: Add a test to reproduce #3445 * Fix #3445. Don't forget LSB of frozen node in BitOpTreeOpt. * Apply suggestions from code review Co-authored-by: Geza Lore --- src/V3Const.cpp | 40 +++++++++++++++++++------ test_regress/t/t_const_opt.pl | 3 ++ test_regress/t/t_const_opt.v | 55 +++++++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 759033185..3a3f89a14 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -299,7 +299,8 @@ class ConstBitOpTreeVisitor final : public VNVisitor { LeafInfo* m_leafp = nullptr; // AstConst or AstVarRef that currently looking for const AstNode* const m_rootp; // Root of this AST subtree - std::vector m_frozenNodes; // Nodes that cannot be optimized + std::vector> + m_frozenNodes; // Nodes that cannot be optimized, int is lsb std::vector m_bitPolarities; // Polarity of bits found during iterate() std::vector> m_varInfos; // VarInfo for each variable, [0] is nullptr @@ -487,7 +488,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { restorer.restoreNow(); // Reach past a cast then add to frozen nodes to be added to final reduction if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp(); - m_frozenNodes.push_back(opp); + m_frozenNodes.emplace_back(opp, m_lsb); m_failed = origFailed; continue; } @@ -652,17 +653,21 @@ public: } } + std::map> frozenNodes; // Group by LSB // Check if frozen terms are clean or not - for (AstNode* const termp : visitor.m_frozenNodes) { + for (const std::pair& termAndLsb : visitor.m_frozenNodes) { + AstNode* const termp = termAndLsb.first; // Comparison operators are clean - if (VN_IS(termp, Eq) || VN_IS(termp, Neq) || VN_IS(termp, Lt) || VN_IS(termp, Lte) - || VN_IS(termp, Gt) || VN_IS(termp, Gte)) { + if ((VN_IS(termp, Eq) || VN_IS(termp, Neq) || VN_IS(termp, Lt) || VN_IS(termp, Lte) + || VN_IS(termp, Gt) || VN_IS(termp, Gte)) + && termAndLsb.second == 0) { hasCleanTerm = true; } else { // Otherwise, conservatively assume the frozen term is dirty hasDirtyTerm = true; UINFO(9, "Dirty frozen term: " << termp << endl); } + frozenNodes[termAndLsb.second].push_back(termp); } // Figure out if a final negation is required @@ -672,7 +677,11 @@ public: const bool needsCleaning = visitor.isAndTree() ? !hasCleanTerm : hasDirtyTerm; // Add size of reduction tree to op count - resultOps += termps.size() + visitor.m_frozenNodes.size() - 1; + resultOps += termps.size() - 1; + for (const auto& lsbAndNodes : frozenNodes) { + if (lsbAndNodes.first > 0) ++resultOps; // Needs AstShiftR + resultOps += lsbAndNodes.second.size(); + } // Add final polarity flip in Xor tree if (needsFlip) ++resultOps; // Add final cleaning AND @@ -681,7 +690,9 @@ public: if (debug() >= 9) { // LCOV_EXCL_START cout << "Bitop tree considered: " << endl; for (AstNode* const termp : termps) termp->dumpTree("Reduced term: "); - for (AstNode* const termp : visitor.m_frozenNodes) termp->dumpTree("Frozen term: "); + for (const std::pair& termp : visitor.m_frozenNodes) + termp.first->dumpTree("Frozen term with lsb " + std::to_string(termp.second) + + ": "); cout << "Needs flipping: " << needsFlip << endl; cout << "Needs cleaning: " << needsCleaning << endl; cout << "Size: " << resultOps << " input size: " << visitor.m_ops << endl; @@ -724,8 +735,19 @@ public: resultp = reduce(resultp, termp); } // Add any frozen terms to the reduction - for (AstNode* const frozenp : visitor.m_frozenNodes) { - resultp = reduce(resultp, frozenp->unlinkFrBack()); + for (auto&& lsbAndNodes : frozenNodes) { + AstNode* termp = nullptr; + for (AstNode* const itemp : lsbAndNodes.second) { + termp = reduce(termp, itemp->unlinkFrBack()); + } + if (lsbAndNodes.first > 0) { // LSB is not 0, so shiftR + AstNodeDType* const dtypep = termp->dtypep(); + termp = new AstShiftR{termp->fileline(), termp, + new AstConst(termp->fileline(), AstConst::WidthedValue{}, + termp->width(), lsbAndNodes.first)}; + termp->dtypep(dtypep); + } + resultp = reduce(resultp, termp); } // Set width of masks to expected result width. This is required to prevent later removal diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index 26143eb57..e30cb1cfb 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -18,5 +18,8 @@ execute( check_finished => 1, ); +if ($Self->{vlt}) { + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 10); +} ok(1); 1; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index be1e49c03..dcce9a20b 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -57,7 +57,8 @@ module t(/*AUTOARG*/ $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'hcae926ece668f35d +`define EXPECTED_SUM 64'h194081987b76c71c + if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -79,10 +80,11 @@ module Test(/*AUTOARG*/ logic d0, d1, d2, d3, d4, d5, d6, d7; logic bug3182_out; logic bug3197_out; + logic bug3445_out; output logic o; - logic [6:0] tmp; + logic [7:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -105,10 +107,12 @@ module Test(/*AUTOARG*/ tmp[4] <= i[0] & (i[1] & (i[2] & (i[3] | d[4]))); // ConstBitOpTreeVisitor::m_frozenNodes tmp[5] <= bug3182_out; tmp[6] <= bug3197_out; + tmp[7] <= bug3445_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); bug3197 i_bug3197(.clk(clk), .in(d), .out(bug3197_out)); + bug3445 i_bug3445(.clk(clk), .in(d), .out(bug3445_out)); endmodule @@ -140,3 +144,50 @@ module bug3197(input wire clk, input wire [31:0] in, output out); wire tmp0 = (|d[38:0]); assign out = (d[39] | tmp0); endmodule + + +// Bug #3445 +// An unoptimized node is kept as frozen node, but its LSB were not saved. +// AST of RHS of result0 looks as below: +// AND(SHIFTR(AND(WORDSEL(ARRAYSEL(VARREF)), WORDSEL(ARRAYSEL(VARREF)))), 32'd11) +// ~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~ +// Two of WORDSELs are frozen nodes. They are under SHIFTR of 11 bits. +// +// Fixing #3445 needs to +// 1. Take AstShiftR into op count when diciding optimizable or not +// (result0 in the test) +// 2. Insert AstShiftR if LSB of the frozen node is not 0 (result1 in the test) +module bug3445(input wire clk, input wire [31:0] in, output wire out); + logic [127:0] d; + always_ff @(posedge clk) + d <= {d[95:0], in}; + + typedef struct packed { + logic a; + logic [ 2:0] b; + logic [ 2:0] c; + logic [ 1:0] d; + logic [ 7:0] e; + logic [31:0] f; + logic [ 3:0] g; + logic [31:0] h; + logic i; + logic [41:0] j; + } packed_struct; + packed_struct st[2]; + + always_ff @(posedge clk) begin + st[0] <= d; + st[1] <= st[0]; + end + + logic result0, result1; + always_ff @(posedge clk) begin + // Cannot optimize further. + result0 <= (st[0].g[0] & st[0].h[0]) & (in[0] == 1'b0); + // There are redundant !in[0] terms. They should be simplified. + result1 <= (!in[0] & (st[1].g[0] & st[1].h[0])) & ((in[0] == 1'b0) & !in[0]); + end + + assign out = result0 ^ result1; +endmodule From 606b35853b29ed67be6d8e48f1ac65b72acff8fd Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 30 May 2022 16:44:00 +0100 Subject: [PATCH 47/68] Configure and compile with C++17 on Ubuntu 22.04 The packaged libsystemc on Ubuntu 22.04 uses C++17, so default to that on that platform. Keep C++14 elsewhere. --- configure.ac | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f0abbb265..cea30eb50 100644 --- a/configure.ac +++ b/configure.ac @@ -348,14 +348,18 @@ AC_SUBST(CFG_CXXFLAGS_PROFILE) # Flag to select newest language standard supported # Macros work such that first option that passes is the one we take -# Currently enabled c++14 due to packaged SystemC dependency +# Currently enable c++17/c++14 due to packaged SystemC dependency # c++14 is the newest that Verilator is regressed to support # c++11 is the oldest that Verilator supports # gnu is requried for Cygwin to compile verilated.h successfully #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++20) -#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17) -#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17) +case "$(which lsb_release 2>&1 > /dev/null && lsb_release -d)" in +*Ubuntu*22.04*) +_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17) +_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17) +;; +esac _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++11) From 694919b9d19ea7a838728d3b87afe7ce0e0d32eb Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 30 May 2022 16:51:40 +0100 Subject: [PATCH 48/68] CI: add ubuntu-22.04 regressions --- .github/workflows/build.yml | 8 ++++++-- ci/ci-install.bash | 10 +++++++--- configure.ac | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 47b5f70b2..d122e1e0a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, ubuntu-18.04] + os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04] compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } @@ -37,9 +37,11 @@ jobs: exclude: # Build pull requests only with ubuntu-20.04 and without m32 - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} + - os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }} - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-20.04 - {os: ubuntu-18.04, m32: 1} + - {os: ubuntu-22.04, m32: 1} include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 @@ -95,7 +97,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, ubuntu-18.04] + os: [ubuntu-22.04, ubuntu-20.04, ubuntu-18.04] compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } @@ -104,9 +106,11 @@ jobs: exclude: # Build pull requests only with ubuntu-20.04 and without m32 - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} + - os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }} - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-20.04 - {os: ubuntu-18.04, m32: 1} + - {os: ubuntu-22.04, m32: 1} include: # Test with GCC 10 on ubuntu-20.04 without m32 - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0} diff --git a/ci/ci-install.bash b/ci/ci-install.bash index f258916b4..4f61f06c4 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -54,8 +54,12 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then if [ "$CI_OS_NAME" = "linux" ]; then sudo apt-get update - sudo apt-get install libfl-dev libgoogle-perftools-dev ccache - if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then + sudo apt-get install libfl-dev ccache + if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then + # Some conflict of libunwind verison on 22.04, can live without it for now + sudo apt-get install libgoogle-perftools-dev + fi + if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then sudo apt-get install libsystemc libsystemc-dev fi if [ "$COVERAGE" = 1 ]; then @@ -85,7 +89,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then sudo apt-get update # libfl-dev needed for internal coverage's test runs sudo apt-get install gdb gtkwave lcov libfl-dev ccache - if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then + if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then sudo apt-get install libsystemc-dev fi if [ "$CI_M32" = 1 ]; then diff --git a/configure.ac b/configure.ac index cea30eb50..8c06cfc0a 100644 --- a/configure.ac +++ b/configure.ac @@ -349,7 +349,7 @@ AC_SUBST(CFG_CXXFLAGS_PROFILE) # Flag to select newest language standard supported # Macros work such that first option that passes is the one we take # Currently enable c++17/c++14 due to packaged SystemC dependency -# c++14 is the newest that Verilator is regressed to support +# c++17 is the newest that Verilator is regularly tested to support # c++11 is the oldest that Verilator supports # gnu is requried for Cygwin to compile verilated.h successfully #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20) From c64a07fd098c81382f5bf033dee2fe7e8ebd1c41 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 30 May 2022 18:35:46 +0100 Subject: [PATCH 49/68] CI: fix cache keys in test jobs --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d122e1e0a..87310899f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,7 +126,7 @@ jobs: CI_M32: ${{ matrix.m32 }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${ matrix.suite }} + CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }} CCACHE_MAXSIZE: 64M # Per build matrix entry (2160M in total) VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz steps: From 0c53d191139a717d142dda20921e2160e4c827a1 Mon Sep 17 00:00:00 2001 From: Huanghuang Zhou Date: Tue, 31 May 2022 19:10:58 +0800 Subject: [PATCH 50/68] Commentary: `InstrCountVisitor` documentation (#3457) Signed-off-by: huanghuang.zhou --- docs/CONTRIBUTORS | 1 + docs/internals.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 8079639e2..d598cebd5 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -35,6 +35,7 @@ Guokai Chen Harald Heckmann Howard Su Huang Rui +Huanghuang Zhou HungMingWu HyungKi Jeong Iru Cai diff --git a/docs/internals.rst b/docs/internals.rst index 62358f1d7..499e0fa12 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -274,7 +274,7 @@ path through the graph is the sum of macro-task execution costs. Sarkar does almost the same thing, except that he has nonzero estimates for synchronization costs. -Verilator's cost estimates are assigned by ``InstrCountCostVisitor``. This +Verilator's cost estimates are assigned by ``InstrCountVisitor``. This class is perhaps the most fragile piece of the multithread implementation. It's easy to have a bug where you count something cheap (eg. accessing one element of a huge array) as if it were expensive (eg. From d64f979f996faee3e5a30a0cfc4e97863728cc35 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Wed, 1 Jun 2022 09:26:16 +0900 Subject: [PATCH 51/68] Fix BitOpTree optimization to consider polarity of frozen node (#3445) (#3459) * Tests: add a test to another failing case of #3445 * Consider polarity as lsb in BitOpTree optimization. --- src/V3Const.cpp | 47 ++++++++++++++++++++++++----------- test_regress/t/t_const_opt.pl | 2 +- test_regress/t/t_const_opt.v | 36 ++++++++++++++++++--------- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 3a3f89a14..9f39e2884 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -111,6 +111,15 @@ class ConstBitOpTreeVisitor final : public VNVisitor { BitPolarityEntry() = default; }; + struct FrozenNodeInfo final { // Context when a frozen node is found + bool m_polarity; + int m_lsb; + bool operator<(const FrozenNodeInfo& other) const { + if (m_lsb != other.m_lsb) return m_lsb < other.m_lsb; + return m_polarity < other.m_polarity; + } + }; + class Restorer final { // Restore the original state unless disableRestore() is called ConstBitOpTreeVisitor& m_visitor; const size_t m_polaritiesSize; @@ -299,8 +308,8 @@ class ConstBitOpTreeVisitor final : public VNVisitor { LeafInfo* m_leafp = nullptr; // AstConst or AstVarRef that currently looking for const AstNode* const m_rootp; // Root of this AST subtree - std::vector> - m_frozenNodes; // Nodes that cannot be optimized, int is lsb + std::vector> + m_frozenNodes; // Nodes that cannot be optimized std::vector m_bitPolarities; // Polarity of bits found during iterate() std::vector> m_varInfos; // VarInfo for each variable, [0] is nullptr @@ -488,7 +497,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { restorer.restoreNow(); // Reach past a cast then add to frozen nodes to be added to final reduction if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp(); - m_frozenNodes.emplace_back(opp, m_lsb); + m_frozenNodes.emplace_back(opp, FrozenNodeInfo{m_polarity, m_lsb}); m_failed = origFailed; continue; } @@ -653,21 +662,21 @@ public: } } - std::map> frozenNodes; // Group by LSB + std::map> frozenNodes; // Group by FrozenNodeInfo // Check if frozen terms are clean or not - for (const std::pair& termAndLsb : visitor.m_frozenNodes) { - AstNode* const termp = termAndLsb.first; + for (const auto& frozenInfo : visitor.m_frozenNodes) { + AstNode* const termp = frozenInfo.first; // Comparison operators are clean if ((VN_IS(termp, Eq) || VN_IS(termp, Neq) || VN_IS(termp, Lt) || VN_IS(termp, Lte) || VN_IS(termp, Gt) || VN_IS(termp, Gte)) - && termAndLsb.second == 0) { + && frozenInfo.second.m_lsb == 0) { hasCleanTerm = true; } else { // Otherwise, conservatively assume the frozen term is dirty hasDirtyTerm = true; UINFO(9, "Dirty frozen term: " << termp << endl); } - frozenNodes[termAndLsb.second].push_back(termp); + frozenNodes[frozenInfo.second].push_back(termp); } // Figure out if a final negation is required @@ -679,7 +688,8 @@ public: // Add size of reduction tree to op count resultOps += termps.size() - 1; for (const auto& lsbAndNodes : frozenNodes) { - if (lsbAndNodes.first > 0) ++resultOps; // Needs AstShiftR + if (lsbAndNodes.first.m_lsb > 0) ++resultOps; // Needs AstShiftR + if (!lsbAndNodes.first.m_polarity) ++resultOps; // Needs AstNot resultOps += lsbAndNodes.second.size(); } // Add final polarity flip in Xor tree @@ -690,8 +700,9 @@ public: if (debug() >= 9) { // LCOV_EXCL_START cout << "Bitop tree considered: " << endl; for (AstNode* const termp : termps) termp->dumpTree("Reduced term: "); - for (const std::pair& termp : visitor.m_frozenNodes) - termp.first->dumpTree("Frozen term with lsb " + std::to_string(termp.second) + for (const std::pair& termp : visitor.m_frozenNodes) + termp.first->dumpTree("Frozen term with lsb " + std::to_string(termp.second.m_lsb) + + " polarity " + std::to_string(termp.second.m_polarity) + ": "); cout << "Needs flipping: " << needsFlip << endl; cout << "Needs cleaning: " << needsCleaning << endl; @@ -735,16 +746,22 @@ public: resultp = reduce(resultp, termp); } // Add any frozen terms to the reduction - for (auto&& lsbAndNodes : frozenNodes) { + for (auto&& nodes : frozenNodes) { + // nodes.second has same lsb and polarity AstNode* termp = nullptr; - for (AstNode* const itemp : lsbAndNodes.second) { + for (AstNode* const itemp : nodes.second) { termp = reduce(termp, itemp->unlinkFrBack()); } - if (lsbAndNodes.first > 0) { // LSB is not 0, so shiftR + if (nodes.first.m_lsb > 0) { // LSB is not 0, so shiftR AstNodeDType* const dtypep = termp->dtypep(); termp = new AstShiftR{termp->fileline(), termp, new AstConst(termp->fileline(), AstConst::WidthedValue{}, - termp->width(), lsbAndNodes.first)}; + termp->width(), nodes.first.m_lsb)}; + termp->dtypep(dtypep); + } + if (!nodes.first.m_polarity) { // Polarity is inverted, so append Not + AstNodeDType* const dtypep = termp->dtypep(); + termp = new AstNot{termp->fileline(), termp}; termp->dtypep(dtypep); } resultp = reduce(resultp, termp); diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index e30cb1cfb..83e301744 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -19,7 +19,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 10); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 11); } ok(1); 1; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index dcce9a20b..407fef13c 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -4,6 +4,11 @@ // any use, without warranty, 2021 Yutetsu TAKATSUKASA. // SPDX-License-Identifier: CC0-1.0 +// This function always returns 0, so safe to take bitwise OR with any value. +// Calling this function stops constant folding as Verialtor does not know +// what this function returns. +import "DPI-C" context function int fake_dependency(); + module t(/*AUTOARG*/ // Inputs clk @@ -57,7 +62,7 @@ module t(/*AUTOARG*/ $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'h194081987b76c71c +`define EXPECTED_SUM 64'hdccb9e7b8b638233 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -120,11 +125,6 @@ module bug3182(in, out); input wire [4:0] in; output wire out; - // This function always returns 0, so safe to take bitwise OR with any value. - // Calling this function stops constant folding as Verialtor does not know - // what this function returns. - import "DPI-C" context function int fake_dependency(); - logic [4:0] bit_source; /* verilator lint_off WIDTH */ @@ -147,16 +147,18 @@ endmodule // Bug #3445 -// An unoptimized node is kept as frozen node, but its LSB were not saved. +// An unoptimized node is kept as frozen node, but its LSB and polarity were not saved. // AST of RHS of result0 looks as below: // AND(SHIFTR(AND(WORDSEL(ARRAYSEL(VARREF)), WORDSEL(ARRAYSEL(VARREF)))), 32'd11) // ~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~ // Two of WORDSELs are frozen nodes. They are under SHIFTR of 11 bits. // // Fixing #3445 needs to -// 1. Take AstShiftR into op count when diciding optimizable or not -// (result0 in the test) +// 1. Take AstShiftR and AstNot into op count when diciding optimizable or not +// (result0 and result2 in the test) // 2. Insert AstShiftR if LSB of the frozen node is not 0 (result1 in the test) +// 3. Insert AstNot if polarity of the frozen node is false (resutl3 in the +// test) module bug3445(input wire clk, input wire [31:0] in, output wire out); logic [127:0] d; always_ff @(posedge clk) @@ -174,20 +176,30 @@ module bug3445(input wire clk, input wire [31:0] in, output wire out); logic i; logic [41:0] j; } packed_struct; - packed_struct st[2]; + packed_struct st[4]; + // This is always 1'b0, but Verilator cannot notice it. + // This signal helps to reveal wrong optimization of result2 and result3. + logic zero; always_ff @(posedge clk) begin st[0] <= d; st[1] <= st[0]; + st[2] <= st[1]; + st[3] <= st[2]; + zero <= fake_dependency() > 0; end - logic result0, result1; + logic result0, result1, result2, result3; always_ff @(posedge clk) begin // Cannot optimize further. result0 <= (st[0].g[0] & st[0].h[0]) & (in[0] == 1'b0); // There are redundant !in[0] terms. They should be simplified. result1 <= (!in[0] & (st[1].g[0] & st[1].h[0])) & ((in[0] == 1'b0) & !in[0]); + // Cannot optimize further. + result2 <= !(st[2].g[0] & st[2].h[0]) & (zero == 1'b0); + // There are redundant zero terms. They should be simplified. + result3 <= (!zero & !(st[3].g[0] & st[3].h[0])) & ((zero == 1'b0) & !zero); end - assign out = result0 ^ result1; + assign out = result0 ^ result1 ^ (result2 | result3); endmodule From 6039e9dcc3d2c281279e2a2760887d71adcadda7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 2 Jun 2022 21:32:22 -0400 Subject: [PATCH 52/68] Commentary --- docs/guide/faq.rst | 43 +++++++++++++++++++++++++++++-------------- docs/spelling.txt | 3 +++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index 5cc4acd43..0b70ea289 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -72,23 +72,38 @@ a good thing for getting working silicon. Will Verilator output remain under my own license/copyright? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Yes, it's just like using GCC on your programs; this is why Verilator uses -the "GNU **Lesser** Public License Version 3" instead of the more typical -"GNU Public License". See the licenses for details, but in brief, if you -change Verilator itself or the header files Verilator includes, you must -make the source code available under the GNU Lesser Public License. -However, Verilator output (the Verilated code) only "include"s the licensed -files, and so you are **not** required to open-source release any output -from Verilator. +Your SystemVerilog, VPI/DPI, or main() C++ code remains under your own license. + +It's just like how using GCC on your programs does not change the copyright +of your program; this is why Verilator uses the "GNU **Lesser** Public +License Version 3" instead of the more typical "GNU Public License". See +the licenses for details. + +Some examples: + +* Any SystemVerilog or other input fed into Verilator remain your own. + +* Any of your VPI/DPI C++ routines that Verilator calls remain your own. + +* Any of your main() C++ code that calls into Verilator remain your own. + +* If you change Verilator itself, for example changing or adding a file + under the src/ directory in the repository, you must make the source code + available under the GNU Lesser Public License. + +* If you change a header Verilator provides, for example under include/ in + the repository, you must make the source code available under the GNU + Lesser Public License. You also have the option of using the Perl Artistic License, which again -does not require you to release your Verilog or generated code, and also -allows you to modify Verilator for internal use without distributing the -modified version. But please contribute back to the community! +does not require you to release your Verilog, C++, or generated code. This +license also allows you to modify Verilator for internal use without +distributing the modified version. But please contribute back to the +community! -One limit is that you cannot under either license release a closed-source -Verilog simulation product incorporating Verilator. That is you can have a -commercial product, but must make the source code available. +Under both license you can offer a commercial product that is based on +Verilator either directly or embedded within. However under both licenses, +any changes you make to Verilator for such a product must be open sourced. As is standard with Open Source, contributions back to Verilator will be placed under the Verilator copyright and LGPL/Artistic license. Small test diff --git a/docs/spelling.txt b/docs/spelling.txt index 9014a6af6..0e423ba26 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -683,6 +683,7 @@ onehot ooo oprofile oversubscription +parallelized param parameterized params @@ -771,6 +772,7 @@ specparam splitme spp sqrt +src srcdir srcfile sscanf @@ -889,6 +891,7 @@ writeme writemem writememb writememh +xiak xin xml xnor From 1f3e8640f7eb795438f3e4baa648438ac6d859b2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 3 Jun 2022 18:45:39 -0400 Subject: [PATCH 53/68] Examples: -Os should be a compile flag, not Verilator flag. --- examples/cmake_tracing_c/CMakeLists.txt | 2 +- examples/cmake_tracing_sc/CMakeLists.txt | 2 +- examples/make_protect_lib/Makefile | 2 +- examples/make_tracing_c/Makefile | 2 +- examples/make_tracing_sc/Makefile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/cmake_tracing_c/CMakeLists.txt b/examples/cmake_tracing_c/CMakeLists.txt index 522c20cc5..95fb3dfb2 100644 --- a/examples/cmake_tracing_c/CMakeLists.txt +++ b/examples/cmake_tracing_c/CMakeLists.txt @@ -33,5 +33,5 @@ add_executable(example ../make_tracing_c/sim_main.cpp) # Add the Verilated circuit to the target verilate(example COVERAGE TRACE INCLUDE_DIRS "../make_tracing_c" - VERILATOR_ARGS -f ../make_tracing_c/input.vc -Os -x-assign 0 + VERILATOR_ARGS -f ../make_tracing_c/input.vc -x-assign fast SOURCES ../make_tracing_c/top.v) diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index 4651d1709..0d67a8cf5 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -45,7 +45,7 @@ set_property( # Add the Verilated circuit to the target verilate(example SYSTEMC COVERAGE TRACE INCLUDE_DIRS "../make_tracing_sc" - VERILATOR_ARGS -f ../make_tracing_sc/input.vc -Os -x-assign 0 + VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast SOURCES ../make_tracing_sc/top.v) verilator_link_systemc(example) diff --git a/examples/make_protect_lib/Makefile b/examples/make_protect_lib/Makefile index 215df0396..359ece33e 100644 --- a/examples/make_protect_lib/Makefile +++ b/examples/make_protect_lib/Makefile @@ -33,7 +33,7 @@ VERILATOR_FLAGS = # Generate C++ VERILATOR_FLAGS += -cc # Optimize -VERILATOR_FLAGS += -Os -x-assign 0 +VERILATOR_FLAGS += -x-assign fast # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # This example does not use vl_time_stamp but rather diff --git a/examples/make_tracing_c/Makefile b/examples/make_tracing_c/Makefile index be77c71e4..e7dcaf244 100644 --- a/examples/make_tracing_c/Makefile +++ b/examples/make_tracing_c/Makefile @@ -36,7 +36,7 @@ VERILATOR_FLAGS += -cc --exe # Generate makefile dependencies (not shown as complicates the Makefile) #VERILATOR_FLAGS += -MMD # Optimize -VERILATOR_FLAGS += -Os -x-assign 0 +VERILATOR_FLAGS += -x-assign fast # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # Make waveforms diff --git a/examples/make_tracing_sc/Makefile b/examples/make_tracing_sc/Makefile index 80a6221b2..5f90a5ebf 100644 --- a/examples/make_tracing_sc/Makefile +++ b/examples/make_tracing_sc/Makefile @@ -37,7 +37,7 @@ VERILATOR_FLAGS += -sc --exe # Generate makefile dependencies (not shown as complicates the Makefile) #VERILATOR_FLAGS += -MMD # Optimize -VERILATOR_FLAGS += -Os -x-assign 0 +VERILATOR_FLAGS += -x-assign fast # Warn abount lint issues; may not want this on less solid designs VERILATOR_FLAGS += -Wall # Make waveforms From 173f57c63639d5b4be2a229c468c84ffbfc0ecf8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 3 Jun 2022 19:41:59 -0400 Subject: [PATCH 54/68] Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). --- Changes | 1 + bin/verilator | 2 +- docs/guide/exe_verilator.rst | 15 ++++---- src/V3OptionParser.cpp | 34 ++++++++++++++++--- src/V3OptionParser.h | 16 ++++++--- src/V3Options.cpp | 2 +- src/V3Options.h | 4 +-- src/V3Premit.cpp | 2 +- .../t/t_extract_static_const_no_merge.pl | 2 +- 9 files changed, 56 insertions(+), 22 deletions(-) diff --git a/Changes b/Changes index 8c9418c9f..ec20c6fda 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 4.223 devel **Minor:** +* Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] diff --git a/bin/verilator b/bin/verilator index 40be6ba0f..367651d32 100755 --- a/bin/verilator +++ b/bin/verilator @@ -319,6 +319,7 @@ detailed descriptions of these arguments. -f Parse arguments from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions + --fno-merge-const-pool Disable merging of different types in const pool -G= Overwrite top-level parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace @@ -344,7 +345,6 @@ detailed descriptions of these arguments. --MMD Create .d dependency files --MP Create phony dependency targets --Mdir Name of output object directory - --no-merge-const-pool Disable merging of different types in const pool --mod-prefix Name to prepend to lower classes --no-clk Prevent marking specified signal as clock --no-decoration Disable comments and symbol decorations diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 6100dcd55..70b3752ad 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -431,6 +431,14 @@ Summary: flattening large designs may require significant CPU time, memory and storage. +.. option:: --fno-merge-const-pool + + Rarely needed; only use if recommended by maintainers. In order to + minimize cache footprint, values of different data type, that are yet + emitted identically in C++ are merged in the constant pool. This option + disables this and causes every constant pool entry with a distinct data + type to be emitted separately. + .. option:: -G= Overwrites the given parameter of the toplevel module. The value is @@ -648,13 +656,6 @@ Summary: The directory is created if it does not exist and the parent directories exist; otherwise manually create the Mdir before calling Verilator. -.. option:: --no-merge-const-pool - - Rarely needed. In order to minimize cache footprint, values of different - data type, that are yet emitted identically in C++ are merged in the - constant pool. This option disables this and causes every constant pool - entry with a distinct data type to be emitted separately. - .. option:: --mod-prefix Specifies the name to prepend to all lower level classes. Defaults to diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index 4439ba53d..d98b4fd90 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -30,6 +30,7 @@ struct V3OptionParser::Impl { // Setting for isOnOffAllowed() and isPartialMatchAllowed() enum class en : uint8_t { NONE, // "-opt" + FONOFF, // "-fopt" and "-fno-opt" ONOFF, // "-opt" and "-no-opt" VALUE // "-opt val" }; @@ -39,6 +40,7 @@ struct V3OptionParser::Impl { bool m_undocumented = false; // This option is not documented public: virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } + virtual bool isFOnOffAllowed() const override final { return MODE == en::FONOFF; } virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } virtual bool isUndocumented() const override { return m_undocumented; } @@ -47,6 +49,7 @@ struct V3OptionParser::Impl { // Actual action classes template class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string + template class ActionFOnOff; // "-fopt" and "-fno-opt" for bool-ish template class ActionOnOff; // "-opt" and "-no-opt" for bool-ish class ActionCbCall; // Callback without argument for "-opt" class ActionCbOnOff; // Callback for "-opt" and "-no-opt" @@ -80,6 +83,7 @@ V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, VOptionBool, m_valp->setTrueOrFalse(tru V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, int, *m_valp = std::atoi(argp), en::VALUE); V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, string, *m_valp = argp, en::VALUE); +V3OPTION_PARSER_DEF_ACT_CLASS(ActionFOnOff, bool, *m_valp = !hasPrefixFNo(optp), en::FONOFF); V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, bool, *m_valp = !hasPrefixNo(optp), en::ONOFF); #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(!hasPrefixNo(optp)), @@ -117,12 +121,23 @@ V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbPartialMatchVal, void(const char*, cons V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { const auto it = m_pimpl->m_options.find(optp); - if (it != m_pimpl->m_options.end()) return it->second.get(); + if (it != m_pimpl->m_options.end()) return it->second.get(); // Exact match for (auto&& act : m_pimpl->m_options) { + if (act.second->isFOnOffAllowed()) { // Find starts with "-fno" + if (const char* const nop + = VString::startsWith(optp, "-fno-") ? (optp + strlen("-fno-")) : nullptr) { + if (act.first.substr(strlen("-f"), std::string::npos) + == nop) { // [-f]opt = [-fno-]opt + return act.second.get(); + } + } + } if (act.second->isOnOffAllowed()) { // Find starts with "-no" - const char* const nop = VString::startsWith(optp, "-no") ? (optp + 3) : nullptr; - if (nop && (act.first == nop || act.first == (string{"-"} + nop))) { - return act.second.get(); + if (const char* const nop + = VString::startsWith(optp, "-no") ? (optp + strlen("-no")) : nullptr) { + if (act.first == nop || act.first == (string{"-"} + nop)) { + return act.second.get(); + } } } else if (act.second->isPartialMatchAllowed()) { if (VString::startsWith(optp, act.first)) return act.second.get(); @@ -143,6 +158,12 @@ V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, ARG arg) return *insertedResult.first->second; } +bool V3OptionParser::hasPrefixFNo(const char* strp) { + UASSERT(strp[0] == '-', strp << " does not start with '-'"); + if (strp[1] == '-') ++strp; + return VString::startsWith(strp, "-fno"); +} + bool V3OptionParser::hasPrefixNo(const char* strp) { UASSERT(strp[0] == '-', strp << " does not start with '-'"); if (strp[1] == '-') ++strp; @@ -178,6 +199,10 @@ void V3OptionParser::finalize() { for (auto&& opt : m_pimpl->m_options) { if (opt.second->isUndocumented()) continue; m_pimpl->m_spellCheck.pushCandidate(opt.first); + if (opt.second->isFOnOffAllowed()) { + m_pimpl->m_spellCheck.pushCandidate( + "-fno-" + opt.first.substr(strlen("-f"), std::string::npos)); + } if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); } m_pimpl->m_isFinalized = true; @@ -202,6 +227,7 @@ V3OPTION_PARSER_DEF_OP(Set, VOptionBool*, ActionSet) #endif V3OPTION_PARSER_DEF_OP(Set, int*, ActionSet) V3OPTION_PARSER_DEF_OP(Set, string*, ActionSet) +V3OPTION_PARSER_DEF_OP(FOnOff, bool*, ActionFOnOff) V3OPTION_PARSER_DEF_OP(OnOff, bool*, ActionOnOff) #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL V3OPTION_PARSER_DEF_OP(OnOff, VOptionBool*, ActionOnOff) diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index fc199264f..e77f43a26 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -66,6 +66,7 @@ private: // METHODS ActionIfs* find(const char* optp); template ActionIfs& add(const string& opt, ARG arg); + static bool hasPrefixFNo(const char* strp); // Returns true if strp starts with "-fno" static bool hasPrefixNo(const char* strp); // Returns true if strp starts with "-no" public: @@ -87,6 +88,7 @@ class V3OptionParser::ActionIfs VL_NOT_FINAL { public: virtual ~ActionIfs() = default; virtual bool isValueNeeded() const = 0; // Need val of "-opt val" + virtual bool isFOnOffAllowed() const = 0; // true if "-fno-opt" is allowd virtual bool isOnOffAllowed() const = 0; // true if "-no-opt" is allowd virtual bool isPartialMatchAllowed() const = 0; // true if "-Wno-" matches "-Wno-fatal" virtual bool isUndocumented() const = 0; // Will not be suggested in typo @@ -101,13 +103,15 @@ class V3OptionParser::AppendHelper final { public: // TYPES // Tag to specify which operator() to call - struct Set {}; // For ActionSet + struct FOnOff {}; // For ActionFOnOff struct OnOff {}; // For ActionOnOff + struct Set {}; // For ActionSet + struct CbCall {}; // For ActionCbCall - struct CbOnOff {}; // For ActionOnOff - struct CbVal {}; // For ActionCbVal + struct CbOnOff {}; // For ActionOnOff of ActionFOnOff struct CbPartialMatch {}; // For ActionCbPartialMatch struct CbPartialMatchVal {}; // For ActionCbPartialMatchVal + struct CbVal {}; // For ActionCbVal private: // MEMBERS @@ -122,6 +126,7 @@ public: ActionIfs& operator()(const char* optp, Set, int*) const; ActionIfs& operator()(const char* optp, Set, string*) const; + ActionIfs& operator()(const char* optp, FOnOff, bool*) const; ActionIfs& operator()(const char* optp, OnOff, bool*) const; #ifndef V3OPTION_PARSER_NO_VOPTION_BOOL ActionIfs& operator()(const char* optp, OnOff, VOptionBool*) const; @@ -144,13 +149,14 @@ public: #define V3OPTION_PARSER_DECL_TAGS \ const auto Set VL_ATTR_UNUSED = V3OptionParser::AppendHelper::Set{}; \ + const auto FOnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::FOnOff{}; \ const auto OnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::OnOff{}; \ const auto CbCall VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbCall{}; \ const auto CbOnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbOnOff{}; \ - const auto CbVal VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbVal{}; \ const auto CbPartialMatch VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbPartialMatch{}; \ const auto CbPartialMatchVal VL_ATTR_UNUSED \ - = V3OptionParser::AppendHelper::CbPartialMatchVal {} + = V3OptionParser::AppendHelper::CbPartialMatchVal{}; \ + const auto CbVal VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbVal{}; //###################################################################### diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 93d23eb5e..2a4c3050d 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1082,6 +1082,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char parseOptsFile(fl, parseFileArg(optdir, valp), false); }); DECL_OPTION("-flatten", OnOff, &m_flatten); + DECL_OPTION("-fmerge-const-pool", FOnOff, &m_fMergeConstPool); DECL_OPTION("-G", CbPartialMatch, [this](const char* optp) { addParameter(optp, false); }); DECL_OPTION("-gate-stmts", Set, &m_gateStmts); @@ -1152,7 +1153,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } }); DECL_OPTION("-max-num-width", Set, &m_maxNumWidth); - DECL_OPTION("-merge-const-pool", OnOff, &m_mergeConstPool); DECL_OPTION("-mod-prefix", Set, &m_modPrefix); DECL_OPTION("-O", CbPartialMatch, [this](const char* optp) { diff --git a/src/V3Options.h b/src/V3Options.h index b9b5ef8ff..e1756ab3d 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -239,6 +239,7 @@ private: bool m_dumpDefines = false; // main switch: --dump-defines bool m_dumpTreeAddrids = false; // main switch: --dump-tree-addrids bool m_exe = false; // main switch: --exe + bool m_fMergeConstPool = true; // main switch: --fmerge-const-pool bool m_flatten = false; // main switch: --flatten bool m_hierarchical = false; // main switch: --hierarchical bool m_hierChild = false; // main switch: --hierarchical-child @@ -246,7 +247,6 @@ private: bool m_lintOnly = false; // main switch: --lint-only bool m_gmake = false; // main switch: --make gmake bool m_main = false; // main swithc: --main - bool m_mergeConstPool = true; // main switch: --merge-const-pool bool m_orderClockDly = true; // main switch: --order-clock-delay bool m_outFormatOk = false; // main switch: --cc, --sc or --sp was specified bool m_pedantic = false; // main switch: --Wpedantic @@ -448,6 +448,7 @@ public: bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpDefines; } bool exe() const { return m_exe; } + bool fMergeConstPool() const { return m_fMergeConstPool; } bool flatten() const { return m_flatten; } bool gmake() const { return m_gmake; } bool threadsDpiPure() const { return m_threadsDpiPure; } @@ -459,7 +460,6 @@ public: bool traceStructs() const { return m_traceStructs; } bool traceUnderscore() const { return m_traceUnderscore; } bool main() const { return m_main; } - bool mergeConstPool() const { return m_mergeConstPool; } bool orderClockDly() const { return m_orderClockDly; } bool outFormatOk() const { return m_outFormatOk; } bool keepTempFiles() const { return (V3Error::debugDefault() != 0); } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 7501cd456..836b7c814 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -133,7 +133,7 @@ private: && !constp->num().isString(); // Not a string if (useConstPool) { // Extract into constant pool. - const bool merge = v3Global.opt.mergeConstPool(); + const bool merge = v3Global.opt.fMergeConstPool(); varp = v3Global.rootp()->constPoolp()->findConst(constp, merge)->varp(); nodep->deleteTree(); ++m_extractedToConstPool; diff --git a/test_regress/t/t_extract_static_const_no_merge.pl b/test_regress/t/t_extract_static_const_no_merge.pl index ff9a694d4..f656fe455 100755 --- a/test_regress/t/t_extract_static_const_no_merge.pl +++ b/test_regress/t/t_extract_static_const_no_merge.pl @@ -14,7 +14,7 @@ top_filename("t/t_extract_static_const.v"); golden_filename("t/t_extract_static_const.out"); compile( - verilator_flags2 => ["--stats", "--no-merge-const-pool"], + verilator_flags2 => ["--stats", "--fno-merge-const-pool"], ); execute( From ada58465b2141b2e9b451ca3bf017b1e1dd4bc6b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 3 Jun 2022 20:43:16 -0400 Subject: [PATCH 55/68] Add -f options to replace -O options (#3436). --- Changes | 1 + bin/verilator | 2 +- docs/guide/deprecations.rst | 5 + docs/guide/exe_verilator.rst | 54 +++++-- src/V3Case.cpp | 2 +- src/V3Const.cpp | 10 +- src/V3Gate.cpp | 4 +- src/V3GraphAcyc.cpp | 2 +- src/V3Options.cpp | 133 ++++++++++-------- src/V3Options.h | 85 ++++++----- src/Verilator.cpp | 32 ++--- test_regress/driver.pl | 22 +-- test_regress/t/t_altera_lpm_mult_noinl.pl | 2 +- test_regress/t/t_alw_noreorder.pl | 2 +- test_regress/t/t_assign_inline.pl | 2 +- test_regress/t/t_assign_slice_overflow_ox.pl | 2 +- test_regress/t/t_case_66bits_noexpand.pl | 2 +- test_regress/t/t_case_incrdecr.pl | 2 +- test_regress/t/t_case_write1_noexpand.pl | 2 +- test_regress/t/t_const_no_opt.pl | 2 +- test_regress/t/t_emit_constw.pl | 2 +- test_regress/t/t_func_twocall_noexpand.pl | 2 +- test_regress/t/t_gen_genblk_noinl.pl | 2 +- test_regress/t/t_incr_void.pl | 2 +- test_regress/t/t_inst_slice_noinl.pl | 2 +- test_regress/t/t_interface1_modport_noinl.pl | 2 +- test_regress/t/t_interface1_noinl.pl | 2 +- test_regress/t/t_interface2_noinl.pl | 2 +- test_regress/t/t_interface_array2_noinl.pl | 2 +- test_regress/t/t_interface_array_noinl.pl | 2 +- test_regress/t/t_interface_down_noinl.pl | 2 +- test_regress/t/t_interface_gen10_noinl.pl | 2 +- test_regress/t/t_interface_gen11_noinl.pl | 2 +- test_regress/t/t_interface_gen12_noinl.pl | 2 +- test_regress/t/t_interface_gen2_noinl.pl | 2 +- test_regress/t/t_interface_gen3_noinl.pl | 2 +- test_regress/t/t_interface_gen4_noinl.pl | 2 +- test_regress/t/t_interface_gen5_noinl.pl | 2 +- test_regress/t/t_interface_gen6_noinl.pl | 2 +- test_regress/t/t_interface_gen7_noinl.pl | 2 +- test_regress/t/t_interface_gen8_noinl.pl | 2 +- test_regress/t/t_interface_gen9_noinl.pl | 2 +- test_regress/t/t_interface_gen_noinl.pl | 2 +- test_regress/t/t_interface_inl.pl | 2 +- .../t/t_interface_modport_import_noinl.pl | 2 +- test_regress/t/t_interface_modport_inl.pl | 2 +- test_regress/t/t_interface_modport_noinl.pl | 2 +- test_regress/t/t_interface_mp_func_noinl.pl | 2 +- test_regress/t/t_interface_nest_noinl.pl | 2 +- test_regress/t/t_interface_noinl.pl | 2 +- test_regress/t/t_interface_twod_noinl.pl | 2 +- test_regress/t/t_lint_setout_bad_noinl.pl | 2 +- test_regress/t/t_math_cond_huge_noexpand.pl | 2 +- test_regress/t/t_math_div_noexpand.pl | 2 +- test_regress/t/t_math_eq_noexpand.pl | 2 +- test_regress/t/t_math_red_noexpand.pl | 2 +- test_regress/t/t_math_shift_noexpand.pl | 2 +- test_regress/t/t_math_signed_noexpand.pl | 2 +- test_regress/t/t_math_vliw_noexpand.pl | 2 +- test_regress/t/t_mem_multi_io.pl | 2 +- test_regress/t/t_mem_multi_io2_cc.pl | 2 +- test_regress/t/t_mem_multi_io2_sc.pl | 2 +- test_regress/t/t_mem_multi_io3_cc.pl | 2 +- test_regress/t/t_mem_multi_io3_sc.pl | 2 +- test_regress/t/t_mem_multidim_Ox.pl | 2 +- test_regress/t/t_mem_packed_noexpand.pl | 2 +- .../t/t_mod_interface_array0_noinl.pl | 2 +- .../t/t_mod_interface_array1_noinl.pl | 2 +- .../t/t_mod_interface_array2_noinl.pl | 2 +- .../t/t_mod_interface_array4_noinl.pl | 2 +- .../t/t_mod_interface_array6_noinl.pl | 2 +- test_regress/t/t_optm_if_cond.pl | 2 +- test_regress/t/t_var_assign_landr_noexpand.pl | 2 +- 73 files changed, 260 insertions(+), 214 deletions(-) diff --git a/Changes b/Changes index ec20c6fda..bfbc7dc92 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 4.223 devel **Minor:** +* Add -f options to replace -O options (#3436). * Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] diff --git a/bin/verilator b/bin/verilator index 367651d32..f04e2a593 100755 --- a/bin/verilator +++ b/bin/verilator @@ -319,7 +319,7 @@ detailed descriptions of these arguments. -f Parse arguments from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions - --fno-merge-const-pool Disable merging of different types in const pool + --fno- Disable internal optimization stage -G= Overwrite top-level parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index 33c2ef610..4c2d96592 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -20,6 +20,11 @@ Option `--cdc` The experimental `--cdc` option is believed to be generally unused and is planned for removal no sooner than January 2023. +Option `--O` + The debug `--O` options have been replaced with + `--fno-` debug options to match GCC. The old options are + planned for removal no sooner than June 2023. + Option `--prof-threads` The `--prof-threads` option has been superseded by the `--prof-exec` and `--prof-pgo` options and is planned for removal no sooner than April 2023. diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 70b3752ad..fda5aedb3 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -431,13 +431,51 @@ Summary: flattening large designs may require significant CPU time, memory and storage. +.. option:: --fno-acyc-simp + +.. option:: --fno-assemble + +.. option:: --fno-case + +.. option:: --fno-combine + +.. option:: --fno-const + +.. option:: --fno-const-bit-op-tree + +.. option:: --fno-dedup + +.. option:: --fno-expand + +.. option:: --fno-gate + +.. option:: --fno-inline + +.. option:: --fno-life + +.. option:: --fno-life-post + +.. option:: --fno-localize + +.. option:: --fno-merge-cond + .. option:: --fno-merge-const-pool - Rarely needed; only use if recommended by maintainers. In order to - minimize cache footprint, values of different data type, that are yet - emitted identically in C++ are merged in the constant pool. This option - disables this and causes every constant pool entry with a distinct data - type to be emitted separately. +.. option:: --fno-reloop + +.. option:: --fno-reorder + +.. option:: --fno-split + +.. option:: --fno-subst + +.. option:: --fno-subst-const + +.. option:: --fno-table + + Rarely needed. Disables one of the internal optimization steps. These + are typically used only when recommended by a maintainer to help debug + or work around an issue. .. option:: -G= @@ -704,9 +742,9 @@ Summary: Rarely needed. Enables or disables a specific optimizations, with the optimization selected based on the letter passed. A lowercase letter - disables an optimization, an upper case letter enables it. This is - intended for debugging use only; see the source code for - version-dependent mappings of optimizations to -O letters. + disables an optimization, an upper case letter enables it. This option + is deprecated and the various `-f` arguments should be + used instead. .. option:: -o diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 161f7db7e..c65fb3e7d 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -496,7 +496,7 @@ private: V3Case::caseLint(nodep); iterateChildren(nodep); if (debug() >= 9) nodep->dumpTree(cout, " case_old: "); - if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) { + if (isCaseTreeFast(nodep) && v3Global.opt.fCase()) { // It's a simple priority encoder or complete statement // we can make a tree of statements to avoid extra comparisons ++m_statCaseFast; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 9f39e2884..e246180a2 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1090,7 +1090,7 @@ private: bool matchBitOpTree(AstNode* nodep) { if (nodep->widthMin() != 1) return false; - if (!v3Global.opt.oConstBitOpTree()) return false; + if (!v3Global.opt.fConstBitOpTree()) return false; string debugPrefix; if (debug() >= 9) { // LCOV_EXCL_START @@ -1412,7 +1412,7 @@ private: return (VN_IS(nodep, And) || VN_IS(nodep, Or) || VN_IS(nodep, Xor)); } bool ifAdjacentSel(const AstSel* lhsp, const AstSel* rhsp) { - if (!v3Global.opt.oAssemble()) return false; // opt disabled + if (!v3Global.opt.fAssemble()) return false; // opt disabled if (!lhsp || !rhsp) return false; const AstNode* const lfromp = lhsp->fromp(); const AstNode* const rfromp = rhsp->fromp(); @@ -1427,7 +1427,7 @@ private: } bool ifMergeAdjacent(AstNode* lhsp, AstNode* rhsp) { // called by concatmergeable to determine if {lhsp, rhsp} make sense - if (!v3Global.opt.oAssemble()) return false; // opt disabled + if (!v3Global.opt.fAssemble()) return false; // opt disabled // two same varref if (operandsSame(lhsp, rhsp)) return true; const AstSel* lselp = VN_CAST(lhsp, Sel); @@ -1464,7 +1464,7 @@ private: } bool concatMergeable(const AstNode* lhsp, const AstNode* rhsp, unsigned depth) { // determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantageous - if (!v3Global.opt.oAssemble()) return false; // opt disabled + if (!v3Global.opt.fAssemble()) return false; // opt disabled if (lhsp->type() != rhsp->type()) return false; if (!ifConcatMergeableBiop(lhsp)) return false; if (depth > CONCAT_MERGABLE_MAX_DEPTH) return false; // As worse case O(n^2) algorithm @@ -2550,7 +2550,7 @@ private: if (nodep->access().isReadOnly() && ((!m_params // Can reduce constant wires into equations && m_doNConst - && v3Global.opt.oConst() + && v3Global.opt.fConst() // Default value, not a "known" constant for this usage && !nodep->varp()->isClassMember() && !(nodep->varp()->isFuncLocal() && nodep->varp()->isNonOutput()) diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 4b66c2661..cf3485121 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -397,11 +397,11 @@ private: // Then propagate more complicated equations optimizeSignals(true); // Remove redundant logic - if (v3Global.opt.oDedupe()) { + if (v3Global.opt.fDedupe()) { dedupe(); if (debug() >= 6) m_graph.dumpDotFilePrefixed("gate_dedup"); } - if (v3Global.opt.oAssemble()) { + if (v3Global.opt.fAssemble()) { mergeAssigns(); if (debug() >= 6) m_graph.dumpDotFilePrefixed("gate_assm"); } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index a62fd3d9d..0df758ed1 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -254,7 +254,7 @@ void GraphAcyc::simplify(bool allowCut) { if (allowCut) { // The main algorithm works without these, though slower // So if changing the main algorithm, comment these out for a test run - if (v3Global.opt.oAcycSimp()) { + if (v3Global.opt.fAcycSimp()) { cutBasic(vertexp); cutBackward(vertexp); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 2a4c3050d..7d4b1e846 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1082,7 +1082,28 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char parseOptsFile(fl, parseFileArg(optdir, valp), false); }); DECL_OPTION("-flatten", OnOff, &m_flatten); + + DECL_OPTION("-facyc-simp", FOnOff, &m_fAcycSimp); + DECL_OPTION("-fassemble", FOnOff, &m_fAssemble); + DECL_OPTION("-fcase", FOnOff, &m_fCase); + DECL_OPTION("-fcombine", FOnOff, &m_fCombine); + DECL_OPTION("-fconst", FOnOff, &m_fConst); + DECL_OPTION("-fconst-bit-op-tree", FOnOff, &m_fConstBitOpTree); + DECL_OPTION("-fdedup", FOnOff, &m_fDedupe); + DECL_OPTION("-fexpand", FOnOff, &m_fExpand); + DECL_OPTION("-fgate", FOnOff, &m_fGate); + DECL_OPTION("-finline", FOnOff, &m_fInline); + DECL_OPTION("-flife", FOnOff, &m_fLife); + DECL_OPTION("-flife-post", FOnOff, &m_fLifePost); + DECL_OPTION("-flocalize", FOnOff, &m_fLocalize); + DECL_OPTION("-fmerge-cond", FOnOff, &m_fMergeCond); DECL_OPTION("-fmerge-const-pool", FOnOff, &m_fMergeConstPool); + DECL_OPTION("-freloop", FOnOff, &m_fReloop); + DECL_OPTION("-freorder", FOnOff, &m_fReorder); + DECL_OPTION("-fsplit", FOnOff, &m_fSplit); + DECL_OPTION("-fsubst", FOnOff, &m_fSubst); + DECL_OPTION("-fsubst-const", FOnOff, &m_fSubstConst); + DECL_OPTION("-ftable", FOnOff, &m_fTable); DECL_OPTION("-G", CbPartialMatch, [this](const char* optp) { addParameter(optp, false); }); DECL_OPTION("-gate-stmts", Set, &m_gateStmts); @@ -1155,47 +1176,49 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-max-num-width", Set, &m_maxNumWidth); DECL_OPTION("-mod-prefix", Set, &m_modPrefix); - DECL_OPTION("-O", CbPartialMatch, [this](const char* optp) { - // Optimization + DECL_OPTION("-O0", CbCall, [this]() { optimize(0); }); + DECL_OPTION("-O1", CbCall, [this]() { optimize(1); }); + DECL_OPTION("-O2", CbCall, [this]() { optimize(2); }); + DECL_OPTION("-O3", CbCall, [this]() { optimize(3); }); + + DECL_OPTION("-O", CbPartialMatch, [this, fl](const char* optp) { + // Optimization, e.g. -O1rX + // LCOV_EXCL_START + fl->v3warn(DEPRECATED, "Option -O is deprecated. " + "Use -f or -fno- instead."); for (const char* cp = optp; *cp; ++cp) { const bool flag = isupper(*cp); switch (tolower(*cp)) { - case '0': optimize(0); break; // 0=all off - case '1': optimize(1); break; // 1=all on - case '2': optimize(2); break; // 2=not used - case '3': optimize(3); break; // 3=high - case 'a': m_oTable = flag; break; - case 'b': m_oCombine = flag; break; - case 'c': m_oConst = flag; break; - case 'd': m_oDedupe = flag; break; - case 'e': m_oCase = flag; break; - // f - case 'g': m_oGate = flag; break; - // h - case 'i': m_oInline = flag; break; - // j - case 'k': m_oSubstConst = flag; break; - case 'l': m_oLife = flag; break; - case 'm': m_oAssemble = flag; break; - // n - case 'o': - m_oConstBitOpTree = flag; - break; // Can remove ~2022-01 when stable - // o will be used as an escape for a second character of optimization disables + case '0': optimize(0); break; + case '1': optimize(1); break; + case '2': optimize(2); break; + case '3': optimize(3); break; + case 'a': m_fTable = flag; break; // == -fno-table + case 'b': m_fCombine = flag; break; // == -fno-combine + case 'c': m_fConst = flag; break; // == -fno-const + case 'd': m_fDedupe = flag; break; // == -fno-dedup + case 'e': m_fCase = flag; break; // == -fno-case + case 'g': m_fGate = flag; break; // == -fno-gate + case 'i': m_fInline = flag; break; // == -fno-inline + case 'k': m_fSubstConst = flag; break; // == -fno-subst-const + case 'l': m_fLife = flag; break; // == -fno-life + case 'm': m_fAssemble = flag; break; // == -fno-assemble + case 'o': m_fConstBitOpTree = flag; break; // == -fno-const-bit-op-tree case 'p': m_public = !flag; break; // With -Op so flag=0, we want public on so few optimizations done - // q - case 'r': m_oReorder = flag; break; - case 's': m_oSplit = flag; break; - case 't': m_oLifePost = flag; break; - case 'u': m_oSubst = flag; break; - case 'v': m_oReloop = flag; break; - case 'w': m_oMergeCond = flag; break; - case 'x': m_oExpand = flag; break; - case 'y': m_oAcycSimp = flag; break; - case 'z': m_oLocalize = flag; break; - default: break; // No error, just ignore + case 'r': m_fReorder = flag; break; // == -fno-reorder + case 's': m_fSplit = flag; break; // == -fno-split + case 't': m_fLifePost = flag; break; // == -fno-life-post + case 'u': m_fSubst = flag; break; // == -fno-subst + case 'v': m_fReloop = flag; break; // == -fno-reloop + case 'w': m_fMergeCond = flag; break; // == -fno-merge-cond + case 'x': m_fExpand = flag; break; // == -fno-expand + case 'y': m_fAcycSimp = flag; break; // == -fno-acyc-simp + case 'z': m_fLocalize = flag; break; // == -fno-localize + default: + break; // No error, just ignore + // LCOV_EXCL_STOP } } }); @@ -1787,26 +1810,26 @@ int V3Options::dumpTreeLevel(const string& srcfile_path) { void V3Options::optimize(int level) { // Set all optimizations to on/off const bool flag = level > 0; - m_oAcycSimp = flag; - m_oAssemble = flag; - m_oCase = flag; - m_oCombine = flag; - m_oConst = flag; - m_oConstBitOpTree = flag; - m_oDedupe = flag; - m_oExpand = flag; - m_oGate = flag; - m_oInline = flag; - m_oLife = flag; - m_oLifePost = flag; - m_oLocalize = flag; - m_oMergeCond = flag; - m_oReloop = flag; - m_oReorder = flag; - m_oSplit = flag; - m_oSubst = flag; - m_oSubstConst = flag; - m_oTable = flag; + m_fAcycSimp = flag; + m_fAssemble = flag; + m_fCase = flag; + m_fCombine = flag; + m_fConst = flag; + m_fConstBitOpTree = flag; + m_fDedupe = flag; + m_fExpand = flag; + m_fGate = flag; + m_fInline = flag; + m_fLife = flag; + m_fLifePost = flag; + m_fLocalize = flag; + m_fMergeCond = flag; + m_fReloop = flag; + m_fReorder = flag; + m_fSplit = flag; + m_fSubst = flag; + m_fSubstConst = flag; + m_fTable = flag; // And set specific optimization levels if (level >= 3) { m_inlineMult = -1; // Maximum inlining diff --git a/src/V3Options.h b/src/V3Options.h index e1756ab3d..137580c34 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -239,7 +239,6 @@ private: bool m_dumpDefines = false; // main switch: --dump-defines bool m_dumpTreeAddrids = false; // main switch: --dump-tree-addrids bool m_exe = false; // main switch: --exe - bool m_fMergeConstPool = true; // main switch: --fmerge-const-pool bool m_flatten = false; // main switch: --flatten bool m_hierarchical = false; // main switch: --hierarchical bool m_hierChild = false; // main switch: --hierarchical-child @@ -341,27 +340,27 @@ private: V3LangCode m_defaultLanguage; // main switch: --language // MEMBERS (optimizations) - // // main switch: -Op: --public - bool m_oAcycSimp; // main switch: -Oy: acyclic pre-optimizations - bool m_oAssemble; // main switch: -Om: assign assemble - bool m_oCase; // main switch: -Oe: case tree conversion - bool m_oCombine; // main switch: -Ob: common icode packing - bool m_oConst; // main switch: -Oc: constant folding - bool m_oConstBitOpTree; // main switch: -Oo: constant bit op tree - bool m_oDedupe; // main switch: -Od: logic deduplication - bool m_oExpand; // main switch: -Ox: expansion of C macros - bool m_oGate; // main switch: -Og: gate wire elimination - bool m_oInline; // main switch: -Oi: module inlining - bool m_oLife; // main switch: -Ol: variable lifetime - bool m_oLifePost; // main switch: -Ot: delayed assignment elimination - bool m_oLocalize; // main switch: -Oz: convert temps to local variables - bool m_oMergeCond; // main switch: -Ob: merge conditionals - bool m_oReloop; // main switch: -Ov: reform loops - bool m_oReorder; // main switch: -Or: reorder assignments in blocks - bool m_oSplit; // main switch: -Os: always assignment splitting - bool m_oSubst; // main switch: -Ou: substitute expression temp values - bool m_oSubstConst; // main switch: -Ok: final constant substitution - bool m_oTable; // main switch: -Oa: lookup table creation + bool m_fAcycSimp; // main switch: -fno-acyc-simp: acyclic pre-optimizations + bool m_fAssemble; // main switch: -fno-assemble: assign assemble + bool m_fCase; // main switch: -fno-case: case tree conversion + bool m_fCombine; // main switch: -fno-combine: common icode packing + bool m_fConst; // main switch: -fno-const: constant folding + bool m_fConstBitOpTree; // main switch: -fno-const-bit-op-tree constant bit op tree + bool m_fDedupe; // main switch: -fno-dedupe: logic deduplication + bool m_fExpand; // main switch: -fno-expand: expansion of C macros + bool m_fGate; // main switch: -fno-gate: gate wire elimination + bool m_fInline; // main switch: -fno-inline: module inlining + bool m_fLife; // main switch: -fno-life: variable lifetime + bool m_fLifePost; // main switch: -fno-life-post: delayed assignment elimination + bool m_fLocalize; // main switch: -fno-localize: convert temps to local variables + bool m_fMergeCond; // main switch: -fno-merge-cond: merge conditionals + bool m_fMergeConstPool = true; // main switch: --fmerge-const-pool + bool m_fReloop; // main switch: -fno-reloop: reform loops + bool m_fReorder; // main switch: -fno-reorder: reorder assignments in blocks + bool m_fSplit; // main switch: -fno-split: always assignment splitting + bool m_fSubst; // main switch: -fno-subst: substitute expression temp values + bool m_fSubstConst; // main switch: -fno-subst-const: final constant substitution + bool m_fTable; // main switch: -fno-table: lookup table creation // clang-format on bool m_available = false; // Set to true at the end of option parsing @@ -448,7 +447,6 @@ public: bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpDefines; } bool exe() const { return m_exe; } - bool fMergeConstPool() const { return m_fMergeConstPool; } bool flatten() const { return m_flatten; } bool gmake() const { return m_gmake; } bool threadsDpiPure() const { return m_threadsDpiPure; } @@ -575,26 +573,27 @@ public: bool isNoClocker(const string& signame) const; // ACCESSORS (optimization options) - bool oAcycSimp() const { return m_oAcycSimp; } - bool oAssemble() const { return m_oAssemble; } - bool oCase() const { return m_oCase; } - bool oCombine() const { return m_oCombine; } - bool oConst() const { return m_oConst; } - bool oConstBitOpTree() const { return m_oConstBitOpTree; } - bool oDedupe() const { return m_oDedupe; } - bool oExpand() const { return m_oExpand; } - bool oGate() const { return m_oGate; } - bool oInline() const { return m_oInline; } - bool oLife() const { return m_oLife; } - bool oLifePost() const { return m_oLifePost; } - bool oLocalize() const { return m_oLocalize; } - bool oMergeCond() const { return m_oMergeCond; } - bool oReloop() const { return m_oReloop; } - bool oReorder() const { return m_oReorder; } - bool oSplit() const { return m_oSplit; } - bool oSubst() const { return m_oSubst; } - bool oSubstConst() const { return m_oSubstConst; } - bool oTable() const { return m_oTable; } + bool fAcycSimp() const { return m_fAcycSimp; } + bool fAssemble() const { return m_fAssemble; } + bool fCase() const { return m_fCase; } + bool fCombine() const { return m_fCombine; } + bool fConst() const { return m_fConst; } + bool fConstBitOpTree() const { return m_fConstBitOpTree; } + bool fDedupe() const { return m_fDedupe; } + bool fExpand() const { return m_fExpand; } + bool fGate() const { return m_fGate; } + bool fInline() const { return m_fInline; } + bool fLife() const { return m_fLife; } + bool fLifePost() const { return m_fLifePost; } + bool fLocalize() const { return m_fLocalize; } + bool fMergeCond() const { return m_fMergeCond; } + bool fMergeConstPool() const { return m_fMergeConstPool; } + bool fReloop() const { return m_fReloop; } + bool fReorder() const { return m_fReorder; } + bool fSplit() const { return m_fSplit; } + bool fSubst() const { return m_fSubst; } + bool fSubstConst() const { return m_fSubstConst; } + bool fTable() const { return m_fTable; } string traceClassBase() const { return m_traceFormat.classBase(); } string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index e233a041c..97e3393c4 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -239,7 +239,7 @@ static void process() { // Module inlining // Cannot remove dead variables after this, as alias information for final // V3Scope's V3LinkDot is in the AstVar. - if (v3Global.opt.oInline()) { + if (v3Global.opt.fInline()) { V3Inline::inlineAll(v3Global.rootp()); V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules } @@ -310,11 +310,11 @@ static void process() { // Push constants across variables and remove redundant assignments V3Const::constifyAll(v3Global.rootp()); - if (v3Global.opt.oLife()) V3Life::lifeAll(v3Global.rootp()); + if (v3Global.opt.fLife()) V3Life::lifeAll(v3Global.rootp()); // Make large low-fanin logic blocks into lookup tables // This should probably be done much later, once we have common logic elimination. - if (!v3Global.opt.lintOnly() && v3Global.opt.oTable()) { + if (!v3Global.opt.lintOnly() && v3Global.opt.fTable()) { V3Table::tableAll(v3Global.rootp()); } @@ -328,7 +328,7 @@ static void process() { V3Active::activeAll(v3Global.rootp()); // Split single ALWAYS blocks into multiple blocks for better ordering chances - if (v3Global.opt.oSplit()) V3Split::splitAlwaysAll(v3Global.rootp()); + if (v3Global.opt.fSplit()) V3Split::splitAlwaysAll(v3Global.rootp()); V3SplitAs::splitAsAll(v3Global.rootp()); // Create tracing sample points, before we start eliminating signals @@ -340,11 +340,11 @@ static void process() { // Gate-based logic elimination; eliminate signals and push constant across cell boundaries // Instant propagation makes lots-o-constant reduction possibilities. - if (v3Global.opt.oGate()) { + if (v3Global.opt.fGate()) { V3Gate::gateAll(v3Global.rootp()); // V3Gate calls constant propagation itself. } else { - v3info("Command Line disabled gate optimization with -Og/-O0. " + v3info("Command Line disabled gate optimization with -fno-gate. " "This may cause ordering problems."); } @@ -363,7 +363,7 @@ static void process() { } // Reorder assignments in pipelined blocks - if (v3Global.opt.oReorder()) V3Split::splitReorderAll(v3Global.rootp()); + if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp()); // Create delayed assignments // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step @@ -388,11 +388,11 @@ static void process() { // Cleanup any dly vars or other temps that are simple assignments // Life must be done before Subst, as it assumes each CFunc under // _eval is called only once. - if (v3Global.opt.oLife()) { + if (v3Global.opt.fLife()) { V3Const::constifyAll(v3Global.rootp()); V3Life::lifeAll(v3Global.rootp()); } - if (v3Global.opt.oLifePost()) V3LifePost::lifepostAll(v3Global.rootp()); + if (v3Global.opt.fLifePost()) V3LifePost::lifepostAll(v3Global.rootp()); // Remove unused vars V3Const::constifyAll(v3Global.rootp()); @@ -422,13 +422,13 @@ static void process() { v3Global.assertScoped(false); // Move variables from modules to function local variables where possible - if (v3Global.opt.oLocalize()) V3Localize::localizeAll(v3Global.rootp()); + if (v3Global.opt.fLocalize()) V3Localize::localizeAll(v3Global.rootp()); // Remove remaining scopes; make varrefs/funccalls relative to current module V3Descope::descopeAll(v3Global.rootp()); // Icache packing; combine common code in each module's functions into subroutines - if (v3Global.opt.oCombine()) V3Combine::combineAll(v3Global.rootp()); + if (v3Global.opt.fCombine()) V3Combine::combineAll(v3Global.rootp()); } V3Error::abortIfErrors(); @@ -452,30 +452,30 @@ static void process() { } // Expand macros and wide operators into C++ primitives - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.oExpand()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.fExpand()) { V3Expand::expandAll(v3Global.rootp()); } // Propagate constants across WORDSEL arrayed temporaries - if (!v3Global.opt.xmlOnly() && v3Global.opt.oSubst()) { + if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubst()) { // Constant folding of expanded stuff V3Const::constifyCpp(v3Global.rootp()); V3Subst::substituteAll(v3Global.rootp()); } - if (!v3Global.opt.xmlOnly() && v3Global.opt.oSubstConst()) { + if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubstConst()) { // Constant folding of substitutions V3Const::constifyCpp(v3Global.rootp()); V3Dead::deadifyAll(v3Global.rootp()); } if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { - if (v3Global.opt.oMergeCond()) { + if (v3Global.opt.fMergeCond()) { // Merge conditionals V3MergeCond::mergeAll(v3Global.rootp()); } - if (v3Global.opt.oReloop()) { + if (v3Global.opt.fReloop()) { // Reform loops to reduce code size // Must be after all Sel/array index based optimizations V3Reloop::reloopAll(v3Global.rootp()); diff --git a/test_regress/driver.pl b/test_regress/driver.pl index fbae94f92..541fb296f 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -77,7 +77,6 @@ my $opt_gdbbt; my $opt_gdbsim; my $opt_hashset; my $opt_jobs = 1; -my $opt_optimize; my $opt_quiet; my $opt_rerun; my $opt_rrsim; @@ -104,7 +103,6 @@ if (! GetOptions( "hashset=s" => \$opt_hashset, "help" => \&usage, "j=i" => \$opt_jobs, - "optimize:s" => \$opt_optimize, "quiet!" => \$opt_quiet, "rerun!" => \$opt_rerun, "rr!" => \$opt_rr, @@ -661,7 +659,7 @@ sub new { verilator_define => 'VERILATOR', verilator_flags => ["-cc", "-Mdir $self->{obj_dir}", - "-OD", # As currently disabled unless -O3 + "--fdedup", # As currently disabled unless -O3 "--debug-check", "--comp-limit-members 10", ], verilator_flags2 => [], @@ -934,19 +932,6 @@ sub compile_vlt_flags { $param{make_main} && $param{verilator_make_gmake}; unshift @verilator_flags, "../" . $self->{main_filename} if $param{make_main} && $param{verilator_make_gmake}; - if (defined $opt_optimize) { - my $letters = ""; - if ($opt_optimize =~ /[a-zA-Z]/) { - $letters = $opt_optimize; - } else { # Randomly turn on/off different optimizations - foreach my $l ('a' .. 'z') { - $letters .= ((rand() > 0.5) ? $l : uc $l); - } - unshift @verilator_flags, "--trace" if rand() > 0.5; - unshift @verilator_flags, "--coverage" if rand() > 0.5; - } - unshift @verilator_flags, "--O" . $letters; - } my @cmdargs = ( "--prefix " . $param{VM_PREFIX}, @@ -2906,11 +2891,6 @@ Displays this message and program version and exits. Run number of parallel tests, or 0 to determine the count based on the number of cores installed. Requires Perl's Parallel::Forker package. -=item --optimize - -Randomly turn on/off different optimizations. With specific flags, -use those optimization settings - =item --quiet Suppress all output except for failures and progress messages every 15 diff --git a/test_regress/t/t_altera_lpm_mult_noinl.pl b/test_regress/t/t_altera_lpm_mult_noinl.pl index 2eac39a3a..63f8aa315 100755 --- a/test_regress/t/t_altera_lpm_mult_noinl.pl +++ b/test_regress/t/t_altera_lpm_mult_noinl.pl @@ -15,7 +15,7 @@ top_filename("t/t_altera_lpm.v"); $module =~ s/_noinl//; compile( - verilator_flags2 => ["--top-module ${module}", "-Oi"] + verilator_flags2 => ["--top-module ${module}", "-fno-inline"] ); ok(1); diff --git a/test_regress/t/t_alw_noreorder.pl b/test_regress/t/t_alw_noreorder.pl index 46d021e6b..edc2a6f7b 100755 --- a/test_regress/t/t_alw_noreorder.pl +++ b/test_regress/t/t_alw_noreorder.pl @@ -12,7 +12,7 @@ scenarios(vlt_all => 1); top_filename("t/t_alw_reorder.v"); compile( - verilator_flags2 => ["--stats -Or"], + verilator_flags2 => ["--stats -fno-reorder"], ); file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0); diff --git a/test_regress/t/t_assign_inline.pl b/test_regress/t/t_assign_inline.pl index 27414cae0..1683d1777 100755 --- a/test_regress/t/t_assign_inline.pl +++ b/test_regress/t/t_assign_inline.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["-O0 -OG"], + verilator_flags2 => ["-O0 -fgate"], ); execute( diff --git a/test_regress/t/t_assign_slice_overflow_ox.pl b/test_regress/t/t_assign_slice_overflow_ox.pl index 5251be495..8702b94fe 100755 --- a/test_regress/t/t_assign_slice_overflow_ox.pl +++ b/test_regress/t/t_assign_slice_overflow_ox.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t_assign_slice_overflow.v"); compile( - verilator_flags2 => ["-Ox"], + verilator_flags2 => ["-fno-expand"], ); execute( diff --git a/test_regress/t/t_case_66bits_noexpand.pl b/test_regress/t/t_case_66bits_noexpand.pl index fae2f640f..738da6174 100755 --- a/test_regress/t/t_case_66bits_noexpand.pl +++ b/test_regress/t/t_case_66bits_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_case_66bits.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_case_incrdecr.pl b/test_regress/t/t_case_incrdecr.pl index abbcf936a..729c0cc8a 100755 --- a/test_regress/t/t_case_incrdecr.pl +++ b/test_regress/t/t_case_incrdecr.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--trace --Os -x-assign 0"], + verilator_flags2 => ["--trace --fno-split -x-assign 0"], ); execute( diff --git a/test_regress/t/t_case_write1_noexpand.pl b/test_regress/t/t_case_write1_noexpand.pl index cadb667e6..48c57c39a 100755 --- a/test_regress/t/t_case_write1_noexpand.pl +++ b/test_regress/t/t_case_write1_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_case_write1.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_const_no_opt.pl b/test_regress/t/t_const_no_opt.pl index 33be39810..79bc15076 100755 --- a/test_regress/t/t_const_no_opt.pl +++ b/test_regress/t/t_const_no_opt.pl @@ -13,7 +13,7 @@ top_filename("t/t_const_opt.v"); # Run the same design as t_const_opt.pl without bitopt tree optimization to make sure that the result is same. compile( - verilator_flags2 => ["-Wno-UNOPTTHREADS", "--stats", "-Oo", "$Self->{t_dir}/t_const_opt.cpp"], + verilator_flags2 => ["-Wno-UNOPTTHREADS", "--stats", "-fno-const-bit-op-tree", "$Self->{t_dir}/t_const_opt.cpp"], ); execute( diff --git a/test_regress/t/t_emit_constw.pl b/test_regress/t/t_emit_constw.pl index 9b1487fcd..8f7895804 100755 --- a/test_regress/t/t_emit_constw.pl +++ b/test_regress/t/t_emit_constw.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['--Ox'], + verilator_flags2 => ['--fno-expand'], ); execute( diff --git a/test_regress/t/t_func_twocall_noexpand.pl b/test_regress/t/t_func_twocall_noexpand.pl index 001824bc6..452d4b37a 100755 --- a/test_regress/t/t_func_twocall_noexpand.pl +++ b/test_regress/t/t_func_twocall_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_func_twocall.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_gen_genblk_noinl.pl b/test_regress/t/t_gen_genblk_noinl.pl index 7574a1cfb..ef537cd4d 100755 --- a/test_regress/t/t_gen_genblk_noinl.pl +++ b/test_regress/t/t_gen_genblk_noinl.pl @@ -16,7 +16,7 @@ scenarios(simulator => 1); $Self->{sim_time} = 11000; compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_incr_void.pl b/test_regress/t/t_incr_void.pl index 5b95e5b74..e7d3e18e3 100755 --- a/test_regress/t/t_incr_void.pl +++ b/test_regress/t/t_incr_void.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--Os -x-assign 0"], + verilator_flags2 => ["--fno-split -x-assign 0"], ); execute( diff --git a/test_regress/t/t_inst_slice_noinl.pl b/test_regress/t/t_inst_slice_noinl.pl index 11f75c752..aa56e6155 100755 --- a/test_regress/t/t_inst_slice_noinl.pl +++ b/test_regress/t/t_inst_slice_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_inst_slice.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface1_modport_noinl.pl b/test_regress/t/t_interface1_modport_noinl.pl index b077bef4e..4f4b314ae 100755 --- a/test_regress/t/t_interface1_modport_noinl.pl +++ b/test_regress/t/t_interface1_modport_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface1_modport.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface1_noinl.pl b/test_regress/t/t_interface1_noinl.pl index 3c9d8d316..867b1e993 100755 --- a/test_regress/t/t_interface1_noinl.pl +++ b/test_regress/t/t_interface1_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface1.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface2_noinl.pl b/test_regress/t/t_interface2_noinl.pl index 57b72e7a7..cad1b6e3d 100755 --- a/test_regress/t/t_interface2_noinl.pl +++ b/test_regress/t/t_interface2_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface2.v"); compile( - verilator_flags2 => ["--top-module t -Oi"], + verilator_flags2 => ["--top-module t -fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_array2_noinl.pl b/test_regress/t/t_interface_array2_noinl.pl index ad389d0fb..7bf1518f5 100755 --- a/test_regress/t/t_interface_array2_noinl.pl +++ b/test_regress/t/t_interface_array2_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_array2.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_array_noinl.pl b/test_regress/t/t_interface_array_noinl.pl index 02bf8fd89..df71f77e9 100755 --- a/test_regress/t/t_interface_array_noinl.pl +++ b/test_regress/t/t_interface_array_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_array.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_down_noinl.pl b/test_regress/t/t_interface_down_noinl.pl index fb03fc988..34ce5cb69 100755 --- a/test_regress/t/t_interface_down_noinl.pl +++ b/test_regress/t/t_interface_down_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_down.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen10_noinl.pl b/test_regress/t/t_interface_gen10_noinl.pl index e5c3f22c5..f691c6d0a 100755 --- a/test_regress/t/t_interface_gen10_noinl.pl +++ b/test_regress/t/t_interface_gen10_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen10.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen11_noinl.pl b/test_regress/t/t_interface_gen11_noinl.pl index 82a6a9a27..d1e7dd3c0 100755 --- a/test_regress/t/t_interface_gen11_noinl.pl +++ b/test_regress/t/t_interface_gen11_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen11.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen12_noinl.pl b/test_regress/t/t_interface_gen12_noinl.pl index c3f59ba19..8ebecd448 100755 --- a/test_regress/t/t_interface_gen12_noinl.pl +++ b/test_regress/t/t_interface_gen12_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen12.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen2_noinl.pl b/test_regress/t/t_interface_gen2_noinl.pl index fc7c4bfb1..eb772bab6 100755 --- a/test_regress/t/t_interface_gen2_noinl.pl +++ b/test_regress/t/t_interface_gen2_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen2.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen3_noinl.pl b/test_regress/t/t_interface_gen3_noinl.pl index e49dfc39a..b63c72eb9 100755 --- a/test_regress/t/t_interface_gen3_noinl.pl +++ b/test_regress/t/t_interface_gen3_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen3.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen4_noinl.pl b/test_regress/t/t_interface_gen4_noinl.pl index 4a0b00930..e724c2859 100755 --- a/test_regress/t/t_interface_gen4_noinl.pl +++ b/test_regress/t/t_interface_gen4_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen4.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen5_noinl.pl b/test_regress/t/t_interface_gen5_noinl.pl index 0873ce9c5..5b4852691 100755 --- a/test_regress/t/t_interface_gen5_noinl.pl +++ b/test_regress/t/t_interface_gen5_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen5.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen6_noinl.pl b/test_regress/t/t_interface_gen6_noinl.pl index 4c42c6797..e43d9460a 100755 --- a/test_regress/t/t_interface_gen6_noinl.pl +++ b/test_regress/t/t_interface_gen6_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen6.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen7_noinl.pl b/test_regress/t/t_interface_gen7_noinl.pl index 27cb3ea61..458c5f0f6 100755 --- a/test_regress/t/t_interface_gen7_noinl.pl +++ b/test_regress/t/t_interface_gen7_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen7.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen8_noinl.pl b/test_regress/t/t_interface_gen8_noinl.pl index ba3b2b132..644d9a10e 100755 --- a/test_regress/t/t_interface_gen8_noinl.pl +++ b/test_regress/t/t_interface_gen8_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen8.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen9_noinl.pl b/test_regress/t/t_interface_gen9_noinl.pl index 48f4eb8be..6ac0d6296 100755 --- a/test_regress/t/t_interface_gen9_noinl.pl +++ b/test_regress/t/t_interface_gen9_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen9.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_gen_noinl.pl b/test_regress/t/t_interface_gen_noinl.pl index 5813d42eb..17273106f 100755 --- a/test_regress/t/t_interface_gen_noinl.pl +++ b/test_regress/t/t_interface_gen_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_gen.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_inl.pl b/test_regress/t/t_interface_inl.pl index efb67ed7f..08dfa385c 100755 --- a/test_regress/t/t_interface_inl.pl +++ b/test_regress/t/t_interface_inl.pl @@ -14,7 +14,7 @@ top_filename("t/t_interface.v"); compile( # Avoid inlining so we find bugs in the non-inliner connection code - verilator_flags2 => ["-Oi"], + verilator_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_modport_import_noinl.pl b/test_regress/t/t_interface_modport_import_noinl.pl index 3821fef11..a9e97bee1 100755 --- a/test_regress/t/t_interface_modport_import_noinl.pl +++ b/test_regress/t/t_interface_modport_import_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_modport_import.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_modport_inl.pl b/test_regress/t/t_interface_modport_inl.pl index 9afcd9cdd..eb2ca2181 100755 --- a/test_regress/t/t_interface_modport_inl.pl +++ b/test_regress/t/t_interface_modport_inl.pl @@ -14,7 +14,7 @@ top_filename("t/t_interface_modport.v"); compile( # Avoid inlining so we find bugs in the non-inliner connection code - verilator_flags2 => ["-Oi"], + verilator_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_modport_noinl.pl b/test_regress/t/t_interface_modport_noinl.pl index 4c051df1a..7f1015d23 100755 --- a/test_regress/t/t_interface_modport_noinl.pl +++ b/test_regress/t/t_interface_modport_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_modport.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_mp_func_noinl.pl b/test_regress/t/t_interface_mp_func_noinl.pl index 432a7308a..89f4835b5 100755 --- a/test_regress/t/t_interface_mp_func_noinl.pl +++ b/test_regress/t/t_interface_mp_func_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_mp_func.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_nest_noinl.pl b/test_regress/t/t_interface_nest_noinl.pl index 9d88a39a0..e042d33c1 100755 --- a/test_regress/t/t_interface_nest_noinl.pl +++ b/test_regress/t/t_interface_nest_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_nest.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_noinl.pl b/test_regress/t/t_interface_noinl.pl index 52cb09c98..7be6235ad 100755 --- a/test_regress/t/t_interface_noinl.pl +++ b/test_regress/t/t_interface_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_interface_twod_noinl.pl b/test_regress/t/t_interface_twod_noinl.pl index 18f0adf62..e77089cb0 100755 --- a/test_regress/t/t_interface_twod_noinl.pl +++ b/test_regress/t/t_interface_twod_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_interface_twod.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_lint_setout_bad_noinl.pl b/test_regress/t/t_lint_setout_bad_noinl.pl index 4b5131821..cbbf96bb4 100755 --- a/test_regress/t/t_lint_setout_bad_noinl.pl +++ b/test_regress/t/t_lint_setout_bad_noinl.pl @@ -13,7 +13,7 @@ scenarios(linter => 1); top_filename("t/t_lint_setout_bad.v"); lint( - verilator_flags2 => ["--lint-only -Oi"], + verilator_flags2 => ["--lint-only -fno-inline"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_math_cond_huge_noexpand.pl b/test_regress/t/t_math_cond_huge_noexpand.pl index 0ae4e3ce4..15399cb9f 100755 --- a/test_regress/t/t_math_cond_huge_noexpand.pl +++ b/test_regress/t/t_math_cond_huge_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_cond_huge.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_div_noexpand.pl b/test_regress/t/t_math_div_noexpand.pl index 4dbcba15c..fa7ecd2ec 100755 --- a/test_regress/t/t_math_div_noexpand.pl +++ b/test_regress/t/t_math_div_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_div.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_eq_noexpand.pl b/test_regress/t/t_math_eq_noexpand.pl index f8b2375c0..2c3907b70 100755 --- a/test_regress/t/t_math_eq_noexpand.pl +++ b/test_regress/t/t_math_eq_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_eq.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_red_noexpand.pl b/test_regress/t/t_math_red_noexpand.pl index 89e54c0c9..655ce0246 100755 --- a/test_regress/t/t_math_red_noexpand.pl +++ b/test_regress/t/t_math_red_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_red.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_shift_noexpand.pl b/test_regress/t/t_math_shift_noexpand.pl index e8a59556b..8584197a0 100755 --- a/test_regress/t/t_math_shift_noexpand.pl +++ b/test_regress/t/t_math_shift_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_shift.v"); compile( - verilator_flags2 => ["-Wno-CLKDATA", '-Ox'], + verilator_flags2 => ["-Wno-CLKDATA", '-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_signed_noexpand.pl b/test_regress/t/t_math_signed_noexpand.pl index 336d35594..b086af557 100755 --- a/test_regress/t/t_math_signed_noexpand.pl +++ b/test_regress/t/t_math_signed_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_signed.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_math_vliw_noexpand.pl b/test_regress/t/t_math_vliw_noexpand.pl index fce202e04..5ca1e425f 100755 --- a/test_regress/t/t_math_vliw_noexpand.pl +++ b/test_regress/t/t_math_vliw_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_math_vliw.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_mem_multi_io.pl b/test_regress/t/t_mem_multi_io.pl index 1691d75f1..4e371f1d7 100755 --- a/test_regress/t/t_mem_multi_io.pl +++ b/test_regress/t/t_mem_multi_io.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); compile( # Disable inlining, this test is trivial without it - verilator_flags2 => ["-Oi --trace"], + verilator_flags2 => ["-fno-inline --trace"], verilator_flags3 => [], ); diff --git a/test_regress/t/t_mem_multi_io2_cc.pl b/test_regress/t/t_mem_multi_io2_cc.pl index 3edda698b..bfd551aed 100755 --- a/test_regress/t/t_mem_multi_io2_cc.pl +++ b/test_regress/t/t_mem_multi_io2_cc.pl @@ -15,7 +15,7 @@ top_filename("t/t_mem_multi_io2.v"); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp -Oi"], + verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp -fno-inline"], verilator_flags3 => [], ); diff --git a/test_regress/t/t_mem_multi_io2_sc.pl b/test_regress/t/t_mem_multi_io2_sc.pl index 11ae8cbfc..2fb4bf70c 100755 --- a/test_regress/t/t_mem_multi_io2_sc.pl +++ b/test_regress/t/t_mem_multi_io2_sc.pl @@ -15,7 +15,7 @@ top_filename("t/t_mem_multi_io2.v"); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc -Oi"], + verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc -fno-inline"], ); execute( diff --git a/test_regress/t/t_mem_multi_io3_cc.pl b/test_regress/t/t_mem_multi_io3_cc.pl index 4ad019dbf..b6090a775 100755 --- a/test_regress/t/t_mem_multi_io3_cc.pl +++ b/test_regress/t/t_mem_multi_io3_cc.pl @@ -15,7 +15,7 @@ top_filename("t/t_mem_multi_io3.v"); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp -Oi"], + verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp -fno-inline"], verilator_flags3 => [], ); diff --git a/test_regress/t/t_mem_multi_io3_sc.pl b/test_regress/t/t_mem_multi_io3_sc.pl index 5825c7845..f37d9dedd 100755 --- a/test_regress/t/t_mem_multi_io3_sc.pl +++ b/test_regress/t/t_mem_multi_io3_sc.pl @@ -15,7 +15,7 @@ top_filename("t/t_mem_multi_io3.v"); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp --sc -Oi"], + verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp --sc -fno-inline"], verilator_flags3 => [], ); diff --git a/test_regress/t/t_mem_multidim_Ox.pl b/test_regress/t/t_mem_multidim_Ox.pl index bb4dbc122..ccde0bbbd 100755 --- a/test_regress/t/t_mem_multidim_Ox.pl +++ b/test_regress/t/t_mem_multidim_Ox.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mem_multidim.v"); compile( - verilator_flags2 => ['--Ox'], + verilator_flags2 => ['--fno-expand'], ); execute( diff --git a/test_regress/t/t_mem_packed_noexpand.pl b/test_regress/t/t_mem_packed_noexpand.pl index d5fc2b5da..df4c82d6d 100755 --- a/test_regress/t/t_mem_packed_noexpand.pl +++ b/test_regress/t/t_mem_packed_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_mem_packed.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( diff --git a/test_regress/t/t_mod_interface_array0_noinl.pl b/test_regress/t/t_mod_interface_array0_noinl.pl index 3c74fd016..56032e0d9 100755 --- a/test_regress/t/t_mod_interface_array0_noinl.pl +++ b/test_regress/t/t_mod_interface_array0_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mod_interface_array0.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_mod_interface_array1_noinl.pl b/test_regress/t/t_mod_interface_array1_noinl.pl index 34871282a..651bb1c65 100755 --- a/test_regress/t/t_mod_interface_array1_noinl.pl +++ b/test_regress/t/t_mod_interface_array1_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mod_interface_array1.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_mod_interface_array2_noinl.pl b/test_regress/t/t_mod_interface_array2_noinl.pl index c19612e57..2afa9e020 100755 --- a/test_regress/t/t_mod_interface_array2_noinl.pl +++ b/test_regress/t/t_mod_interface_array2_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mod_interface_array2.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_mod_interface_array4_noinl.pl b/test_regress/t/t_mod_interface_array4_noinl.pl index 6797c1016..62ad2ca24 100755 --- a/test_regress/t/t_mod_interface_array4_noinl.pl +++ b/test_regress/t/t_mod_interface_array4_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mod_interface_array4.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_mod_interface_array6_noinl.pl b/test_regress/t/t_mod_interface_array6_noinl.pl index 5244ac42c..f07ea1917 100755 --- a/test_regress/t/t_mod_interface_array6_noinl.pl +++ b/test_regress/t/t_mod_interface_array6_noinl.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_mod_interface_array6.v"); compile( - v_flags2 => ["-Oi"], + v_flags2 => ["-fno-inline"], ); execute( diff --git a/test_regress/t/t_optm_if_cond.pl b/test_regress/t/t_optm_if_cond.pl index b67f09305..7910f570f 100755 --- a/test_regress/t/t_optm_if_cond.pl +++ b/test_regress/t/t_optm_if_cond.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - verilator_flags2 => ['--stats', "-Ow"], + verilator_flags2 => ['--stats', "-fno-merge-cond"], ); if ($Self->{vlt_all}) { diff --git a/test_regress/t/t_var_assign_landr_noexpand.pl b/test_regress/t/t_var_assign_landr_noexpand.pl index cd058334d..e616f77c3 100755 --- a/test_regress/t/t_var_assign_landr_noexpand.pl +++ b/test_regress/t/t_var_assign_landr_noexpand.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_var_assign_landr.v"); compile( - verilator_flags2 => ['-Ox'], + verilator_flags2 => ['-fno-expand'], ); execute( From 59dc2853e3bc899a079a1022fd955329b41cd769 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 3 Jun 2022 21:32:13 -0400 Subject: [PATCH 56/68] Support concat assignment to packed array (#3446). --- Changes | 5 ++-- src/V3AstNodes.h | 1 + src/V3Width.cpp | 31 ++++++++++++++++++-- test_regress/t/t_concat_unpack.pl | 21 ++++++++++++++ test_regress/t/t_concat_unpack.v | 36 ++++++++++++++++++++++++ test_regress/t/t_unpacked_concat_bad.out | 19 +------------ 6 files changed, 91 insertions(+), 22 deletions(-) create mode 100755 test_regress/t/t_concat_unpack.pl create mode 100755 test_regress/t/t_concat_unpack.v diff --git a/Changes b/Changes index bfbc7dc92..53560e563 100644 --- a/Changes +++ b/Changes @@ -20,10 +20,11 @@ Verilator 4.223 devel * Add -f options to replace -O options (#3436). * Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] -* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] -* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] +* Support concat assignment to packed array (#3446). * Improve conditional merging optimization (#3125). [Geza Lore, Shunyao CAD] +* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] +* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 404eff633..118666c0b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -8538,6 +8538,7 @@ public: AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc + void addItemsp(AstNode* nodep) { addOp2p(nodep); } }; class AstPatMember final : public AstNodeMath { // Verilog '{a} or '{a{b}} diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 69cee08f6..15bdf6f33 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -504,6 +504,7 @@ private: // width: LHS + RHS AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); userIterate(vdtypep, WidthVP(SELF, BOTH).p()); + // Conversions if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* const newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -521,6 +522,16 @@ private: userIterateChildren(newp, m_vup); return; } + if (VN_IS(vdtypep, UnpackArrayDType)) { + auto* const newp = new AstPattern{nodep->fileline(), nullptr}; + patConcatConvertRecurse(newp, nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterate(newp, m_vup); + return; + } + + // Concat handling if (m_vup->prelim()) { if (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // @@ -662,7 +673,8 @@ private: } AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); - if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)) { + if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, UnpackArrayDType)) { if (times != 1) nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form " << vdtypep->prettyDTypeNameQ() @@ -674,7 +686,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, UnpackArrayDType)) { + if (VN_IS(vdtypep, AssocArrayDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); } @@ -6231,6 +6243,21 @@ private: return patmap; } + void patConcatConvertRecurse(AstPattern* patternp, AstConcat* nodep) { + if (AstConcat* lhsp = VN_CAST(nodep->lhsp(), Concat)) { + patConcatConvertRecurse(patternp, lhsp); + } else { + patternp->addItemsp(new AstPatMember{nodep->lhsp()->fileline(), + nodep->lhsp()->unlinkFrBack(), nullptr, nullptr}); + } + if (AstConcat* rhsp = VN_CAST(nodep->rhsp(), Concat)) { + patConcatConvertRecurse(patternp, rhsp); + } else { + patternp->addItemsp(new AstPatMember{nodep->rhsp()->fileline(), + nodep->rhsp()->unlinkFrBack(), nullptr, nullptr}); + } + } + void makeOpenArrayShell(AstNodeFTaskRef* nodep) { UINFO(4, "Replicate openarray function " << nodep->taskp() << endl); AstNodeFTask* const oldTaskp = nodep->taskp(); diff --git a/test_regress/t/t_concat_unpack.pl b/test_regress/t/t_concat_unpack.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_concat_unpack.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 2022 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_concat_unpack.v b/test_regress/t/t_concat_unpack.v new file mode 100755 index 000000000..8d3f4bac2 --- /dev/null +++ b/test_regress/t/t_concat_unpack.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + wire [31:0] arr [0:7]; + assign arr[0:7] = { + {16'hffff, 16'h0000}, + {16'h0000, 16'h0000}, + {16'h0a0a, 16'h0000}, + {16'ha0a0, 16'h0000}, + {16'hffff, 16'h0000}, + {16'h0000, 16'h0000}, + {16'h0a0a, 16'h0000}, + {16'ha0a0, 16'h0000} + }; + + int cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 9) begin + if (arr[0] !== 32'hffff0000) $stop; + if (arr[7] !== 32'ha0a00000) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index 4c89adfe6..1482e7507 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -1,23 +1,6 @@ -%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type +%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Non-1 replication to form 'bit[31:0]$[1:0]' data type : ... In instance t 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:17:47: Unsized numbers/parameters not allowed in replications. - : ... In instance t - 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; - | ^~~~~ - ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. -%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:18:45: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^ -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:18:46: Unsized numbers/parameters not allowed in concatenations. - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^~~~~ -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:18:60: Unsized numbers/parameters not allowed in replications. - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^ %Error: Exiting due to From 67f7432dd7323374023306e71cb11c25fd70e55f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Jun 2022 08:37:42 -0400 Subject: [PATCH 57/68] Commentary (#3436). --- bin/verilator | 2 +- docs/guide/deprecations.rst | 6 ++--- docs/guide/exe_verilator.rst | 42 ++++++++++++++++----------------- test_regress/t/t_case_write1.pl | 2 +- test_regress/t/t_case_write2.pl | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bin/verilator b/bin/verilator index f04e2a593..a50e353bb 100755 --- a/bin/verilator +++ b/bin/verilator @@ -319,7 +319,7 @@ detailed descriptions of these arguments. -f Parse arguments from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions - --fno- Disable internal optimization stage + -fno- Disable internal optimization stage -G= Overwrite top-level parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index 4c2d96592..8c0038453 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -20,9 +20,9 @@ Option `--cdc` The experimental `--cdc` option is believed to be generally unused and is planned for removal no sooner than January 2023. -Option `--O` - The debug `--O` options have been replaced with - `--fno-` debug options to match GCC. The old options are +Option `-O` + The debug `-O` options have been replaced with + `-fno-` debug options to match GCC. The old options are planned for removal no sooner than June 2023. Option `--prof-threads` diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index fda5aedb3..af65fe3ba 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -431,47 +431,47 @@ Summary: flattening large designs may require significant CPU time, memory and storage. -.. option:: --fno-acyc-simp +.. option:: -fno-acyc-simp -.. option:: --fno-assemble +.. option:: -fno-assemble -.. option:: --fno-case +.. option:: -fno-case -.. option:: --fno-combine +.. option:: -fno-combine -.. option:: --fno-const +.. option:: -fno-const -.. option:: --fno-const-bit-op-tree +.. option:: -fno-const-bit-op-tree -.. option:: --fno-dedup +.. option:: -fno-dedup -.. option:: --fno-expand +.. option:: -fno-expand -.. option:: --fno-gate +.. option:: -fno-gate -.. option:: --fno-inline +.. option:: -fno-inline -.. option:: --fno-life +.. option:: -fno-life -.. option:: --fno-life-post +.. option:: -fno-life-post -.. option:: --fno-localize +.. option:: -fno-localize -.. option:: --fno-merge-cond +.. option:: -fno-merge-cond -.. option:: --fno-merge-const-pool +.. option:: -fno-merge-const-pool -.. option:: --fno-reloop +.. option:: -fno-reloop -.. option:: --fno-reorder +.. option:: -fno-reorder -.. option:: --fno-split +.. option:: -fno-split -.. option:: --fno-subst +.. option:: -fno-subst -.. option:: --fno-subst-const +.. option:: -fno-subst-const -.. option:: --fno-table +.. option:: -fno-table Rarely needed. Disables one of the internal optimization steps. These are typically used only when recommended by a maintainer to help debug diff --git a/test_regress/t/t_case_write1.pl b/test_regress/t/t_case_write1.pl index 4fa36576d..33e2bb517 100755 --- a/test_regress/t/t_case_write1.pl +++ b/test_regress/t/t_case_write1.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--stats --O3 -x-assign fast"], + verilator_flags2 => ["--stats -O3 -x-assign fast"], ); execute( diff --git a/test_regress/t/t_case_write2.pl b/test_regress/t/t_case_write2.pl index 4fa36576d..33e2bb517 100755 --- a/test_regress/t/t_case_write2.pl +++ b/test_regress/t/t_case_write2.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--stats --O3 -x-assign fast"], + verilator_flags2 => ["--stats -O3 -x-assign fast"], ); execute( From 32100a3c913133adff55d3a5eccd15552c245ef5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Jun 2022 12:16:42 -0400 Subject: [PATCH 58/68] Tests: Fix racy tests for develop-v5. --- test_regress/t/t_gen_forif.v | 6 +++--- test_regress/t/t_gen_intdot.v | 16 +++++----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/test_regress/t/t_gen_forif.v b/test_regress/t/t_gen_forif.v index 5e70a0ee3..73fa55138 100644 --- a/test_regress/t/t_gen_forif.v +++ b/test_regress/t/t_gen_forif.v @@ -29,7 +29,7 @@ module t (/*AUTOARG*/ always @ (posedge clk) begin `ifdef TEST_VERBOSE - $write("[%0t] cyc==%0d crc=%x %x %x %x\n", $time, cyc, crc, Result, Result2); + $write("[%0t] cyc==%0d crc=%x %x %x\n", $time, cyc, crc, Result, Result2); `endif cyc <= cyc + 1; crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; @@ -62,10 +62,10 @@ module Test (clk, Value, Result); reg Internal; - assign Result = Internal ^ clk; + assign Result = Internal; always @(posedge clk) - Internal <= #1 Value; + Internal <= Value; endmodule module Test_wrap1 (clk, Value, Result); diff --git a/test_regress/t/t_gen_intdot.v b/test_regress/t/t_gen_intdot.v index 240672ccd..249af3417 100644 --- a/test_regress/t/t_gen_intdot.v +++ b/test_regress/t/t_gen_intdot.v @@ -40,14 +40,6 @@ module t (/*AUTOARG*/ end end -//`define WAVES -`ifdef WAVES - initial begin - $dumpfile({`STRINGIFY(`TEST_OBJ_DIR),"/simx.vcd"}); - $dumpvars(12, t); - end -`endif - endmodule module Generate (clk, value, result); @@ -57,10 +49,10 @@ module Generate (clk, value, result); reg Internal; - assign result = Internal ^ clk; + assign result = Internal; always @(posedge clk) - Internal <= #1 value; + Internal <= value; endmodule module Checker (clk, value); @@ -89,7 +81,9 @@ module Genit (clk, value, result); `ifndef ATSIM // else unsupported `ifndef NC // else unsupported - `define WITH_FOR_GENVAR + `ifndef IVERILOG // else unsupported + `define WITH_FOR_GENVAR + `endif `endif `endif From e7dc2de14b62af99c4884d2047ca68e25b3aba91 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Jun 2022 12:43:18 -0400 Subject: [PATCH 59/68] Fix BLKANDNBLK on $readmem/$writemem (#3379). --- Changes | 1 + src/V3Delayed.cpp | 9 ++++++ test_regress/t/t_sys_readmem_assoc.v | 41 +++++++++++++++++++--------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/Changes b/Changes index 53560e563..4908e3d91 100644 --- a/Changes +++ b/Changes @@ -26,6 +26,7 @@ Verilator 4.223 devel * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Fix hang with large case statement optimization (#3405). [Mike Urbach] +* Fix BLKANDNBLK on $readmem/$writemem (#3379). [Alex Solomatnikov] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] * Fix passing VL_TRACE_FST_WRITER_THREAD in CMake build. [Geza Lore, Shunyao CAD] diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 57fe02833..668fff8a4 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -94,6 +94,7 @@ 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 + bool m_ignoreBlkAndNBlk = false; // Suppress delayed assignment BLKANDNBLK using VarMap = std::map, AstVar*>; VarMap m_modVarMap; // Table of new var names created under module VDouble0 m_statSharedSet; // Statistic tracking @@ -105,6 +106,7 @@ private: void markVarUsage(AstNodeVarRef* nodep, bool blocking) { // Ignore if warning is disabled on this reference (used by V3Force). if (nodep->fileline()->warnIsOff(V3ErrorCode::BLKANDNBLK)) return; + if (m_ignoreBlkAndNBlk) return; if (blocking) nodep->user5(true); AstVarScope* const vscp = nodep->varScopep(); // UINFO(4, " MVU " << blocking << " " << nodep << endl); @@ -485,6 +487,13 @@ private: } } + virtual void visit(AstNodeReadWriteMem* nodep) override { + VL_RESTORER(m_ignoreBlkAndNBlk); + m_ignoreBlkAndNBlk = true; // $readmem/$writemem often used in mem models + // so we will suppress BLKANDNBLK warnings + iterateChildren(nodep); + } + virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin"); diff --git a/test_regress/t/t_sys_readmem_assoc.v b/test_regress/t/t_sys_readmem_assoc.v index 9d0654c2e..7d2487f31 100644 --- a/test_regress/t/t_sys_readmem_assoc.v +++ b/test_regress/t/t_sys_readmem_assoc.v @@ -6,22 +6,37 @@ `define STRINGIFY(x) `"x`" -module t; +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + int cyc; reg [5:0] assoc_c[int]; reg [95:0] assoc_w[int]; - initial begin - assoc_c[300] = 10; // See if clearing must happen first - $readmemb("t/t_sys_readmem_b.mem", assoc_c); - $display("assoc_c=%p", assoc_c); - $writememh({`STRINGIFY(`TEST_OBJ_DIR),"/t_sys_writemem_c_b.mem"}, assoc_c); - - $readmemb("t/t_sys_readmem_b.mem", assoc_w); - // Not conditional with TEST_VERBOSE as found bug with wide display - $display("assoc_w=%p", assoc_w); - $writememh({`STRINGIFY(`TEST_OBJ_DIR),"/t_sys_writemem_w_h.mem"}, assoc_w); - $write("*-* All Finished *-*\n"); - $finish; + always_ff @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + assoc_c[300] <= 10; // See if clearing must happen first + // Also checks no BLKANDNBLK due to readmem/writemem + end + else if (cyc == 2) begin + $readmemb("t/t_sys_readmem_b.mem", assoc_c); + $display("assoc_c=%p", assoc_c); + $writememh({`STRINGIFY(`TEST_OBJ_DIR),"/t_sys_writemem_c_b.mem"}, assoc_c); + end + else if (cyc == 3) begin + $readmemb("t/t_sys_readmem_b.mem", assoc_w); + // Not conditional with TEST_VERBOSE as found bug with wide display + $display("assoc_w=%p", assoc_w); + $writememh({`STRINGIFY(`TEST_OBJ_DIR),"/t_sys_writemem_w_h.mem"}, assoc_w); + end + else if (cyc == 4) begin + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule From 660d1059b04ffde699ac2d78f2bf3cbf9b462317 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 10 Jun 2022 13:26:33 +0200 Subject: [PATCH 60/68] With --no-decoration, remove output whitespace (#3460) Signed-off-by: Kamil Rakoczy --- src/V3EmitV.cpp | 4 + src/V3File.cpp | 22 +- src/V3File.h | 2 + test_regress/t/t_dpi_arg_inout_type__Dpi.out | 270 +++++++------- .../t/t_dpi_arg_inout_unpack__Dpi.out | 328 +++++++++--------- test_regress/t/t_dpi_arg_input_type__Dpi.out | 270 +++++++------- .../t/t_dpi_arg_input_unpack__Dpi.out | 328 +++++++++--------- test_regress/t/t_dpi_arg_output_type__Dpi.out | 270 +++++++------- .../t/t_dpi_arg_output_unpack__Dpi.out | 328 +++++++++--------- test_regress/t/t_dpi_result_type__Dpi.out | 138 ++++---- 10 files changed, 987 insertions(+), 973 deletions(-) diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 594795fa5..82015f46d 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -790,6 +790,10 @@ class EmitVPrefixedFormatter final : public V3OutFormatter { } } + virtual void putsOutput(const char* strg) override { + for (const char* cp = strg; *cp; cp++) putcOutput(*cp); + } + public: void prefixFl(FileLine* fl) { m_prefixFl = fl; } FileLine* prefixFl() const { return m_prefixFl; } diff --git a/src/V3File.cpp b/src/V3File.cpp index 1d5062f65..f6b9cf11d 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -700,6 +700,10 @@ int V3OutFormatter::endLevels(const char* strg) { } void V3OutFormatter::puts(const char* strg) { + if (!v3Global.opt.decoration()) { + putsOutput(strg); + return; + } if (m_prependIndent && strg[0] != '\n') { putsNoTracking(indentSpaces(endLevels(strg))); m_prependIndent = false; @@ -759,13 +763,8 @@ void V3OutFormatter::puts(const char* strg) { break; case '(': indentInc(); - if (v3Global.opt.decoration()) { - // Line up continuation with open paren, plus one indent - m_parenVec.push(m_column); - } else { - // Line up continuation with block+1 - m_parenVec.push(m_indentLevel * m_blockIndent); - } + // Line up continuation with open paren, plus one indent + m_parenVec.push(m_column); break; case ')': if (!m_parenVec.empty()) m_parenVec.pop(); @@ -806,6 +805,7 @@ void V3OutFormatter::putBreakExpr() { // Add a line break if too wide void V3OutFormatter::putBreak() { + if (!v3Global.opt.decoration()) return; if (!m_nobreak) { // char s[1000]; sprintf(s, "{%d,%d}", m_column, m_parenVec.top()); putsNoTracking(s); if (exceededWidth()) { @@ -824,11 +824,19 @@ void V3OutFormatter::putsQuoted(const string& strg) { putcNoTracking('"'); } void V3OutFormatter::putsNoTracking(const string& strg) { + if (!v3Global.opt.decoration()) { + putsOutput(strg.c_str()); + return; + } // Don't track {}'s, probably because it's a $display format string for (const char c : strg) putcNoTracking(c); } void V3OutFormatter::putcNoTracking(char chr) { + if (!v3Global.opt.decoration()) { + putcOutput(chr); + return; + } switch (chr) { case '\n': m_lineno++; diff --git a/src/V3File.h b/src/V3File.h index d3d54e4f4..dd337b165 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -176,6 +176,7 @@ public: // CALLBACKS - MUST OVERRIDE virtual void putcOutput(char chr) = 0; + virtual void putsOutput(const char* str) = 0; }; //============================================================================ @@ -193,6 +194,7 @@ public: private: // CALLBACKS virtual void putcOutput(char chr) override { fputc(chr, m_fp); } + virtual void putsOutput(const char* str) override { fputs(str, m_fp); } }; class V3OutCFile VL_NOT_FINAL : public V3OutFile { diff --git a/test_regress/t/t_dpi_arg_inout_type__Dpi.out b/test_regress/t/t_dpi_arg_inout_type__Dpi.out index b800f7d8f..e046f7857 100644 --- a/test_regress/t/t_dpi_arg_inout_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_type__Dpi.out @@ -15,142 +15,142 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_array_2_state_1(svBitVecVal* x); - extern void e_array_2_state_128(svBitVecVal* x); - extern void e_array_2_state_32(svBitVecVal* x); - extern void e_array_2_state_33(svBitVecVal* x); - extern void e_array_2_state_64(svBitVecVal* x); - extern void e_array_2_state_65(svBitVecVal* x); - extern void e_array_4_state_1(svLogicVecVal* x); - extern void e_array_4_state_128(svLogicVecVal* x); - extern void e_array_4_state_32(svLogicVecVal* x); - extern void e_array_4_state_33(svLogicVecVal* x); - extern void e_array_4_state_64(svLogicVecVal* x); - extern void e_array_4_state_65(svLogicVecVal* x); - extern void e_bit(svBit* x); - extern void e_bit_t(svBit* x); - extern void e_byte(char* x); - extern void e_byte_t(char* x); - extern void e_byte_unsigned(unsigned char* x); - extern void e_byte_unsigned_t(unsigned char* x); - extern void e_chandle(void** x); - extern void e_chandle_t(void** x); - extern void e_int(int* x); - extern void e_int_t(int* x); - extern void e_int_unsigned(unsigned int* x); - extern void e_int_unsigned_t(unsigned int* x); - extern void e_integer(svLogicVecVal* x); - extern void e_integer_t(svLogicVecVal* x); - extern void e_logic(svLogic* x); - extern void e_logic_t(svLogic* x); - extern void e_longint(long long* x); - extern void e_longint_t(long long* x); - extern void e_longint_unsigned(unsigned long long* x); - extern void e_longint_unsigned_t(unsigned long long* x); - extern void e_real(double* x); - extern void e_real_t(double* x); - extern void e_shortint(short* x); - extern void e_shortint_t(short* x); - extern void e_shortint_unsigned(unsigned short* x); - extern void e_shortint_unsigned_t(unsigned short* x); - extern void e_string(const char** x); - extern void e_string_t(const char** x); - extern void e_struct_2_state_1(svBitVecVal* x); - extern void e_struct_2_state_128(svBitVecVal* x); - extern void e_struct_2_state_32(svBitVecVal* x); - extern void e_struct_2_state_33(svBitVecVal* x); - extern void e_struct_2_state_64(svBitVecVal* x); - extern void e_struct_2_state_65(svBitVecVal* x); - extern void e_struct_4_state_1(svLogicVecVal* x); - extern void e_struct_4_state_128(svLogicVecVal* x); - extern void e_struct_4_state_32(svLogicVecVal* x); - extern void e_struct_4_state_33(svLogicVecVal* x); - extern void e_struct_4_state_64(svLogicVecVal* x); - extern void e_struct_4_state_65(svLogicVecVal* x); - extern void e_time(svLogicVecVal* x); - extern void e_time_t(svLogicVecVal* x); - extern void e_union_2_state_1(svBitVecVal* x); - extern void e_union_2_state_128(svBitVecVal* x); - extern void e_union_2_state_32(svBitVecVal* x); - extern void e_union_2_state_33(svBitVecVal* x); - extern void e_union_2_state_64(svBitVecVal* x); - extern void e_union_2_state_65(svBitVecVal* x); - extern void e_union_4_state_1(svLogicVecVal* x); - extern void e_union_4_state_128(svLogicVecVal* x); - extern void e_union_4_state_32(svLogicVecVal* x); - extern void e_union_4_state_33(svLogicVecVal* x); - extern void e_union_4_state_64(svLogicVecVal* x); - extern void e_union_4_state_65(svLogicVecVal* x); +// DPI EXPORTS +extern void e_array_2_state_1(svBitVecVal* x); +extern void e_array_2_state_128(svBitVecVal* x); +extern void e_array_2_state_32(svBitVecVal* x); +extern void e_array_2_state_33(svBitVecVal* x); +extern void e_array_2_state_64(svBitVecVal* x); +extern void e_array_2_state_65(svBitVecVal* x); +extern void e_array_4_state_1(svLogicVecVal* x); +extern void e_array_4_state_128(svLogicVecVal* x); +extern void e_array_4_state_32(svLogicVecVal* x); +extern void e_array_4_state_33(svLogicVecVal* x); +extern void e_array_4_state_64(svLogicVecVal* x); +extern void e_array_4_state_65(svLogicVecVal* x); +extern void e_bit(svBit* x); +extern void e_bit_t(svBit* x); +extern void e_byte(char* x); +extern void e_byte_t(char* x); +extern void e_byte_unsigned(unsigned char* x); +extern void e_byte_unsigned_t(unsigned char* x); +extern void e_chandle(void** x); +extern void e_chandle_t(void** x); +extern void e_int(int* x); +extern void e_int_t(int* x); +extern void e_int_unsigned(unsigned int* x); +extern void e_int_unsigned_t(unsigned int* x); +extern void e_integer(svLogicVecVal* x); +extern void e_integer_t(svLogicVecVal* x); +extern void e_logic(svLogic* x); +extern void e_logic_t(svLogic* x); +extern void e_longint(long long* x); +extern void e_longint_t(long long* x); +extern void e_longint_unsigned(unsigned long long* x); +extern void e_longint_unsigned_t(unsigned long long* x); +extern void e_real(double* x); +extern void e_real_t(double* x); +extern void e_shortint(short* x); +extern void e_shortint_t(short* x); +extern void e_shortint_unsigned(unsigned short* x); +extern void e_shortint_unsigned_t(unsigned short* x); +extern void e_string(const char** x); +extern void e_string_t(const char** x); +extern void e_struct_2_state_1(svBitVecVal* x); +extern void e_struct_2_state_128(svBitVecVal* x); +extern void e_struct_2_state_32(svBitVecVal* x); +extern void e_struct_2_state_33(svBitVecVal* x); +extern void e_struct_2_state_64(svBitVecVal* x); +extern void e_struct_2_state_65(svBitVecVal* x); +extern void e_struct_4_state_1(svLogicVecVal* x); +extern void e_struct_4_state_128(svLogicVecVal* x); +extern void e_struct_4_state_32(svLogicVecVal* x); +extern void e_struct_4_state_33(svLogicVecVal* x); +extern void e_struct_4_state_64(svLogicVecVal* x); +extern void e_struct_4_state_65(svLogicVecVal* x); +extern void e_time(svLogicVecVal* x); +extern void e_time_t(svLogicVecVal* x); +extern void e_union_2_state_1(svBitVecVal* x); +extern void e_union_2_state_128(svBitVecVal* x); +extern void e_union_2_state_32(svBitVecVal* x); +extern void e_union_2_state_33(svBitVecVal* x); +extern void e_union_2_state_64(svBitVecVal* x); +extern void e_union_2_state_65(svBitVecVal* x); +extern void e_union_4_state_1(svLogicVecVal* x); +extern void e_union_4_state_128(svLogicVecVal* x); +extern void e_union_4_state_32(svLogicVecVal* x); +extern void e_union_4_state_33(svLogicVecVal* x); +extern void e_union_4_state_64(svLogicVecVal* x); +extern void e_union_4_state_65(svLogicVecVal* x); - // DPI IMPORTS - extern void check_exports(); - extern void i_array_2_state_1(svBitVecVal* x); - extern void i_array_2_state_128(svBitVecVal* x); - extern void i_array_2_state_32(svBitVecVal* x); - extern void i_array_2_state_33(svBitVecVal* x); - extern void i_array_2_state_64(svBitVecVal* x); - extern void i_array_2_state_65(svBitVecVal* x); - extern void i_array_4_state_1(svLogicVecVal* x); - extern void i_array_4_state_128(svLogicVecVal* x); - extern void i_array_4_state_32(svLogicVecVal* x); - extern void i_array_4_state_33(svLogicVecVal* x); - extern void i_array_4_state_64(svLogicVecVal* x); - extern void i_array_4_state_65(svLogicVecVal* x); - extern void i_bit(svBit* x); - extern void i_bit_t(svBit* x); - extern void i_byte(char* x); - extern void i_byte_t(char* x); - extern void i_byte_unsigned(unsigned char* x); - extern void i_byte_unsigned_t(unsigned char* x); - extern void i_chandle(void** x); - extern void i_chandle_t(void** x); - extern void i_int(int* x); - extern void i_int_t(int* x); - extern void i_int_unsigned(unsigned int* x); - extern void i_int_unsigned_t(unsigned int* x); - extern void i_integer(svLogicVecVal* x); - extern void i_integer_t(svLogicVecVal* x); - extern void i_logic(svLogic* x); - extern void i_logic_t(svLogic* x); - extern void i_longint(long long* x); - extern void i_longint_t(long long* x); - extern void i_longint_unsigned(unsigned long long* x); - extern void i_longint_unsigned_t(unsigned long long* x); - extern void i_real(double* x); - extern void i_real_t(double* x); - extern void i_shortint(short* x); - extern void i_shortint_t(short* x); - extern void i_shortint_unsigned(unsigned short* x); - extern void i_shortint_unsigned_t(unsigned short* x); - extern void i_string(const char** x); - extern void i_string_t(const char** x); - extern void i_struct_2_state_1(svBitVecVal* x); - extern void i_struct_2_state_128(svBitVecVal* x); - extern void i_struct_2_state_32(svBitVecVal* x); - extern void i_struct_2_state_33(svBitVecVal* x); - extern void i_struct_2_state_64(svBitVecVal* x); - extern void i_struct_2_state_65(svBitVecVal* x); - extern void i_struct_4_state_1(svLogicVecVal* x); - extern void i_struct_4_state_128(svLogicVecVal* x); - extern void i_struct_4_state_32(svLogicVecVal* x); - extern void i_struct_4_state_33(svLogicVecVal* x); - extern void i_struct_4_state_64(svLogicVecVal* x); - extern void i_struct_4_state_65(svLogicVecVal* x); - extern void i_time(svLogicVecVal* x); - extern void i_time_t(svLogicVecVal* x); - extern void i_union_2_state_1(svBitVecVal* x); - extern void i_union_2_state_128(svBitVecVal* x); - extern void i_union_2_state_32(svBitVecVal* x); - extern void i_union_2_state_33(svBitVecVal* x); - extern void i_union_2_state_64(svBitVecVal* x); - extern void i_union_2_state_65(svBitVecVal* x); - extern void i_union_4_state_1(svLogicVecVal* x); - extern void i_union_4_state_128(svLogicVecVal* x); - extern void i_union_4_state_32(svLogicVecVal* x); - extern void i_union_4_state_33(svLogicVecVal* x); - extern void i_union_4_state_64(svLogicVecVal* x); - extern void i_union_4_state_65(svLogicVecVal* x); +// DPI IMPORTS +extern void check_exports(); +extern void i_array_2_state_1(svBitVecVal* x); +extern void i_array_2_state_128(svBitVecVal* x); +extern void i_array_2_state_32(svBitVecVal* x); +extern void i_array_2_state_33(svBitVecVal* x); +extern void i_array_2_state_64(svBitVecVal* x); +extern void i_array_2_state_65(svBitVecVal* x); +extern void i_array_4_state_1(svLogicVecVal* x); +extern void i_array_4_state_128(svLogicVecVal* x); +extern void i_array_4_state_32(svLogicVecVal* x); +extern void i_array_4_state_33(svLogicVecVal* x); +extern void i_array_4_state_64(svLogicVecVal* x); +extern void i_array_4_state_65(svLogicVecVal* x); +extern void i_bit(svBit* x); +extern void i_bit_t(svBit* x); +extern void i_byte(char* x); +extern void i_byte_t(char* x); +extern void i_byte_unsigned(unsigned char* x); +extern void i_byte_unsigned_t(unsigned char* x); +extern void i_chandle(void** x); +extern void i_chandle_t(void** x); +extern void i_int(int* x); +extern void i_int_t(int* x); +extern void i_int_unsigned(unsigned int* x); +extern void i_int_unsigned_t(unsigned int* x); +extern void i_integer(svLogicVecVal* x); +extern void i_integer_t(svLogicVecVal* x); +extern void i_logic(svLogic* x); +extern void i_logic_t(svLogic* x); +extern void i_longint(long long* x); +extern void i_longint_t(long long* x); +extern void i_longint_unsigned(unsigned long long* x); +extern void i_longint_unsigned_t(unsigned long long* x); +extern void i_real(double* x); +extern void i_real_t(double* x); +extern void i_shortint(short* x); +extern void i_shortint_t(short* x); +extern void i_shortint_unsigned(unsigned short* x); +extern void i_shortint_unsigned_t(unsigned short* x); +extern void i_string(const char** x); +extern void i_string_t(const char** x); +extern void i_struct_2_state_1(svBitVecVal* x); +extern void i_struct_2_state_128(svBitVecVal* x); +extern void i_struct_2_state_32(svBitVecVal* x); +extern void i_struct_2_state_33(svBitVecVal* x); +extern void i_struct_2_state_64(svBitVecVal* x); +extern void i_struct_2_state_65(svBitVecVal* x); +extern void i_struct_4_state_1(svLogicVecVal* x); +extern void i_struct_4_state_128(svLogicVecVal* x); +extern void i_struct_4_state_32(svLogicVecVal* x); +extern void i_struct_4_state_33(svLogicVecVal* x); +extern void i_struct_4_state_64(svLogicVecVal* x); +extern void i_struct_4_state_65(svLogicVecVal* x); +extern void i_time(svLogicVecVal* x); +extern void i_time_t(svLogicVecVal* x); +extern void i_union_2_state_1(svBitVecVal* x); +extern void i_union_2_state_128(svBitVecVal* x); +extern void i_union_2_state_32(svBitVecVal* x); +extern void i_union_2_state_33(svBitVecVal* x); +extern void i_union_2_state_64(svBitVecVal* x); +extern void i_union_2_state_65(svBitVecVal* x); +extern void i_union_4_state_1(svLogicVecVal* x); +extern void i_union_4_state_128(svLogicVecVal* x); +extern void i_union_4_state_32(svLogicVecVal* x); +extern void i_union_4_state_33(svLogicVecVal* x); +extern void i_union_4_state_64(svLogicVecVal* x); +extern void i_union_4_state_65(svLogicVecVal* x); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out index 8c6d9be71..83beb561a 100644 --- a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out @@ -15,171 +15,171 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_bit121_0d(svBitVecVal* val); - extern void e_bit121_1d(svBitVecVal* val); - extern void e_bit121_2d(svBitVecVal* val); - extern void e_bit121_3d(svBitVecVal* val); - extern void e_bit1_0d(svBit* val); - extern void e_bit1_1d(svBit* val); - extern void e_bit1_2d(svBit* val); - extern void e_bit1_3d(svBit* val); - extern void e_bit7_0d(svBitVecVal* val); - extern void e_bit7_1d(svBitVecVal* val); - extern void e_bit7_2d(svBitVecVal* val); - extern void e_bit7_3d(svBitVecVal* val); - extern void e_byte_0d(char* val); - extern void e_byte_1d(char* val); - extern void e_byte_2d(char* val); - extern void e_byte_3d(char* val); - extern void e_byte_unsigned_0d(unsigned char* val); - extern void e_byte_unsigned_1d(unsigned char* val); - extern void e_byte_unsigned_2d(unsigned char* val); - extern void e_byte_unsigned_3d(unsigned char* val); - extern void e_chandle_0d(void** val); - extern void e_chandle_1d(void** val); - extern void e_chandle_2d(void** val); - extern void e_chandle_3d(void** val); - extern void e_int_0d(int* val); - extern void e_int_1d(int* val); - extern void e_int_2d(int* val); - extern void e_int_3d(int* val); - extern void e_int_unsigned_0d(unsigned int* val); - extern void e_int_unsigned_1d(unsigned int* val); - extern void e_int_unsigned_2d(unsigned int* val); - extern void e_int_unsigned_3d(unsigned int* val); - extern void e_integer_0d(svLogicVecVal* val); - extern void e_integer_1d(svLogicVecVal* val); - extern void e_integer_2d(svLogicVecVal* val); - extern void e_integer_3d(svLogicVecVal* val); - extern void e_logic121_0d(svLogicVecVal* val); - extern void e_logic121_1d(svLogicVecVal* val); - extern void e_logic121_2d(svLogicVecVal* val); - extern void e_logic121_3d(svLogicVecVal* val); - extern void e_logic1_0d(svLogic* val); - extern void e_logic1_1d(svLogic* val); - extern void e_logic1_2d(svLogic* val); - extern void e_logic1_3d(svLogic* val); - extern void e_logic7_0d(svLogicVecVal* val); - extern void e_logic7_1d(svLogicVecVal* val); - extern void e_logic7_2d(svLogicVecVal* val); - extern void e_logic7_3d(svLogicVecVal* val); - extern void e_longint_0d(long long* val); - extern void e_longint_1d(long long* val); - extern void e_longint_2d(long long* val); - extern void e_longint_3d(long long* val); - extern void e_longint_unsigned_0d(unsigned long long* val); - extern void e_longint_unsigned_1d(unsigned long long* val); - extern void e_longint_unsigned_2d(unsigned long long* val); - extern void e_longint_unsigned_3d(unsigned long long* val); - extern void e_pack_struct_0d(svLogicVecVal* val); - extern void e_pack_struct_1d(svLogicVecVal* val); - extern void e_pack_struct_2d(svLogicVecVal* val); - extern void e_pack_struct_3d(svLogicVecVal* val); - extern void e_real_0d(double* val); - extern void e_real_1d(double* val); - extern void e_real_2d(double* val); - extern void e_real_3d(double* val); - extern void e_shortint_0d(short* val); - extern void e_shortint_1d(short* val); - extern void e_shortint_2d(short* val); - extern void e_shortint_3d(short* val); - extern void e_shortint_unsigned_0d(unsigned short* val); - extern void e_shortint_unsigned_1d(unsigned short* val); - extern void e_shortint_unsigned_2d(unsigned short* val); - extern void e_shortint_unsigned_3d(unsigned short* val); - extern void e_string_0d(const char** val); - extern void e_string_1d(const char** val); - extern void e_string_2d(const char** val); - extern void e_string_3d(const char** val); - extern void e_time_0d(svLogicVecVal* val); - extern void e_time_1d(svLogicVecVal* val); - extern void e_time_2d(svLogicVecVal* val); - extern void e_time_3d(svLogicVecVal* val); +// DPI EXPORTS +extern void e_bit121_0d(svBitVecVal* val); +extern void e_bit121_1d(svBitVecVal* val); +extern void e_bit121_2d(svBitVecVal* val); +extern void e_bit121_3d(svBitVecVal* val); +extern void e_bit1_0d(svBit* val); +extern void e_bit1_1d(svBit* val); +extern void e_bit1_2d(svBit* val); +extern void e_bit1_3d(svBit* val); +extern void e_bit7_0d(svBitVecVal* val); +extern void e_bit7_1d(svBitVecVal* val); +extern void e_bit7_2d(svBitVecVal* val); +extern void e_bit7_3d(svBitVecVal* val); +extern void e_byte_0d(char* val); +extern void e_byte_1d(char* val); +extern void e_byte_2d(char* val); +extern void e_byte_3d(char* val); +extern void e_byte_unsigned_0d(unsigned char* val); +extern void e_byte_unsigned_1d(unsigned char* val); +extern void e_byte_unsigned_2d(unsigned char* val); +extern void e_byte_unsigned_3d(unsigned char* val); +extern void e_chandle_0d(void** val); +extern void e_chandle_1d(void** val); +extern void e_chandle_2d(void** val); +extern void e_chandle_3d(void** val); +extern void e_int_0d(int* val); +extern void e_int_1d(int* val); +extern void e_int_2d(int* val); +extern void e_int_3d(int* val); +extern void e_int_unsigned_0d(unsigned int* val); +extern void e_int_unsigned_1d(unsigned int* val); +extern void e_int_unsigned_2d(unsigned int* val); +extern void e_int_unsigned_3d(unsigned int* val); +extern void e_integer_0d(svLogicVecVal* val); +extern void e_integer_1d(svLogicVecVal* val); +extern void e_integer_2d(svLogicVecVal* val); +extern void e_integer_3d(svLogicVecVal* val); +extern void e_logic121_0d(svLogicVecVal* val); +extern void e_logic121_1d(svLogicVecVal* val); +extern void e_logic121_2d(svLogicVecVal* val); +extern void e_logic121_3d(svLogicVecVal* val); +extern void e_logic1_0d(svLogic* val); +extern void e_logic1_1d(svLogic* val); +extern void e_logic1_2d(svLogic* val); +extern void e_logic1_3d(svLogic* val); +extern void e_logic7_0d(svLogicVecVal* val); +extern void e_logic7_1d(svLogicVecVal* val); +extern void e_logic7_2d(svLogicVecVal* val); +extern void e_logic7_3d(svLogicVecVal* val); +extern void e_longint_0d(long long* val); +extern void e_longint_1d(long long* val); +extern void e_longint_2d(long long* val); +extern void e_longint_3d(long long* val); +extern void e_longint_unsigned_0d(unsigned long long* val); +extern void e_longint_unsigned_1d(unsigned long long* val); +extern void e_longint_unsigned_2d(unsigned long long* val); +extern void e_longint_unsigned_3d(unsigned long long* val); +extern void e_pack_struct_0d(svLogicVecVal* val); +extern void e_pack_struct_1d(svLogicVecVal* val); +extern void e_pack_struct_2d(svLogicVecVal* val); +extern void e_pack_struct_3d(svLogicVecVal* val); +extern void e_real_0d(double* val); +extern void e_real_1d(double* val); +extern void e_real_2d(double* val); +extern void e_real_3d(double* val); +extern void e_shortint_0d(short* val); +extern void e_shortint_1d(short* val); +extern void e_shortint_2d(short* val); +extern void e_shortint_3d(short* val); +extern void e_shortint_unsigned_0d(unsigned short* val); +extern void e_shortint_unsigned_1d(unsigned short* val); +extern void e_shortint_unsigned_2d(unsigned short* val); +extern void e_shortint_unsigned_3d(unsigned short* val); +extern void e_string_0d(const char** val); +extern void e_string_1d(const char** val); +extern void e_string_2d(const char** val); +extern void e_string_3d(const char** val); +extern void e_time_0d(svLogicVecVal* val); +extern void e_time_1d(svLogicVecVal* val); +extern void e_time_2d(svLogicVecVal* val); +extern void e_time_3d(svLogicVecVal* val); - // DPI IMPORTS - extern void check_exports(); - extern void* get_non_null(); - extern void i_bit121_0d(svBitVecVal* val); - extern void i_bit121_1d(svBitVecVal* val); - extern void i_bit121_2d(svBitVecVal* val); - extern void i_bit121_3d(svBitVecVal* val); - extern void i_bit1_0d(svBit* val); - extern void i_bit1_1d(svBit* val); - extern void i_bit1_2d(svBit* val); - extern void i_bit1_3d(svBit* val); - extern void i_bit7_0d(svBitVecVal* val); - extern void i_bit7_1d(svBitVecVal* val); - extern void i_bit7_2d(svBitVecVal* val); - extern void i_bit7_3d(svBitVecVal* val); - extern void i_byte_0d(char* val); - extern void i_byte_1d(char* val); - extern void i_byte_2d(char* val); - extern void i_byte_3d(char* val); - extern void i_byte_unsigned_0d(unsigned char* val); - extern void i_byte_unsigned_1d(unsigned char* val); - extern void i_byte_unsigned_2d(unsigned char* val); - extern void i_byte_unsigned_3d(unsigned char* val); - extern void i_chandle_0d(void** val); - extern void i_chandle_1d(void** val); - extern void i_chandle_2d(void** val); - extern void i_chandle_3d(void** val); - extern void i_int_0d(int* val); - extern void i_int_1d(int* val); - extern void i_int_2d(int* val); - extern void i_int_3d(int* val); - extern void i_int_unsigned_0d(unsigned int* val); - extern void i_int_unsigned_1d(unsigned int* val); - extern void i_int_unsigned_2d(unsigned int* val); - extern void i_int_unsigned_3d(unsigned int* val); - extern void i_integer_0d(svLogicVecVal* val); - extern void i_integer_1d(svLogicVecVal* val); - extern void i_integer_2d(svLogicVecVal* val); - extern void i_integer_3d(svLogicVecVal* val); - extern void i_logic121_0d(svLogicVecVal* val); - extern void i_logic121_1d(svLogicVecVal* val); - extern void i_logic121_2d(svLogicVecVal* val); - extern void i_logic121_3d(svLogicVecVal* val); - extern void i_logic1_0d(svLogic* val); - extern void i_logic1_1d(svLogic* val); - extern void i_logic1_2d(svLogic* val); - extern void i_logic1_3d(svLogic* val); - extern void i_logic7_0d(svLogicVecVal* val); - extern void i_logic7_1d(svLogicVecVal* val); - extern void i_logic7_2d(svLogicVecVal* val); - extern void i_logic7_3d(svLogicVecVal* val); - extern void i_longint_0d(long long* val); - extern void i_longint_1d(long long* val); - extern void i_longint_2d(long long* val); - extern void i_longint_3d(long long* val); - extern void i_longint_unsigned_0d(unsigned long long* val); - extern void i_longint_unsigned_1d(unsigned long long* val); - extern void i_longint_unsigned_2d(unsigned long long* val); - extern void i_longint_unsigned_3d(unsigned long long* val); - extern void i_pack_struct_0d(svLogicVecVal* val); - extern void i_pack_struct_1d(svLogicVecVal* val); - extern void i_pack_struct_2d(svLogicVecVal* val); - extern void i_pack_struct_3d(svLogicVecVal* val); - extern void i_real_0d(double* val); - extern void i_real_1d(double* val); - extern void i_real_2d(double* val); - extern void i_real_3d(double* val); - extern void i_shortint_0d(short* val); - extern void i_shortint_1d(short* val); - extern void i_shortint_2d(short* val); - extern void i_shortint_3d(short* val); - extern void i_shortint_unsigned_0d(unsigned short* val); - extern void i_shortint_unsigned_1d(unsigned short* val); - extern void i_shortint_unsigned_2d(unsigned short* val); - extern void i_shortint_unsigned_3d(unsigned short* val); - extern void i_string_0d(const char** val); - extern void i_string_1d(const char** val); - extern void i_string_2d(const char** val); - extern void i_string_3d(const char** val); - extern void i_time_0d(svLogicVecVal* val); - extern void i_time_1d(svLogicVecVal* val); - extern void i_time_2d(svLogicVecVal* val); - extern void i_time_3d(svLogicVecVal* val); +// DPI IMPORTS +extern void check_exports(); +extern void* get_non_null(); +extern void i_bit121_0d(svBitVecVal* val); +extern void i_bit121_1d(svBitVecVal* val); +extern void i_bit121_2d(svBitVecVal* val); +extern void i_bit121_3d(svBitVecVal* val); +extern void i_bit1_0d(svBit* val); +extern void i_bit1_1d(svBit* val); +extern void i_bit1_2d(svBit* val); +extern void i_bit1_3d(svBit* val); +extern void i_bit7_0d(svBitVecVal* val); +extern void i_bit7_1d(svBitVecVal* val); +extern void i_bit7_2d(svBitVecVal* val); +extern void i_bit7_3d(svBitVecVal* val); +extern void i_byte_0d(char* val); +extern void i_byte_1d(char* val); +extern void i_byte_2d(char* val); +extern void i_byte_3d(char* val); +extern void i_byte_unsigned_0d(unsigned char* val); +extern void i_byte_unsigned_1d(unsigned char* val); +extern void i_byte_unsigned_2d(unsigned char* val); +extern void i_byte_unsigned_3d(unsigned char* val); +extern void i_chandle_0d(void** val); +extern void i_chandle_1d(void** val); +extern void i_chandle_2d(void** val); +extern void i_chandle_3d(void** val); +extern void i_int_0d(int* val); +extern void i_int_1d(int* val); +extern void i_int_2d(int* val); +extern void i_int_3d(int* val); +extern void i_int_unsigned_0d(unsigned int* val); +extern void i_int_unsigned_1d(unsigned int* val); +extern void i_int_unsigned_2d(unsigned int* val); +extern void i_int_unsigned_3d(unsigned int* val); +extern void i_integer_0d(svLogicVecVal* val); +extern void i_integer_1d(svLogicVecVal* val); +extern void i_integer_2d(svLogicVecVal* val); +extern void i_integer_3d(svLogicVecVal* val); +extern void i_logic121_0d(svLogicVecVal* val); +extern void i_logic121_1d(svLogicVecVal* val); +extern void i_logic121_2d(svLogicVecVal* val); +extern void i_logic121_3d(svLogicVecVal* val); +extern void i_logic1_0d(svLogic* val); +extern void i_logic1_1d(svLogic* val); +extern void i_logic1_2d(svLogic* val); +extern void i_logic1_3d(svLogic* val); +extern void i_logic7_0d(svLogicVecVal* val); +extern void i_logic7_1d(svLogicVecVal* val); +extern void i_logic7_2d(svLogicVecVal* val); +extern void i_logic7_3d(svLogicVecVal* val); +extern void i_longint_0d(long long* val); +extern void i_longint_1d(long long* val); +extern void i_longint_2d(long long* val); +extern void i_longint_3d(long long* val); +extern void i_longint_unsigned_0d(unsigned long long* val); +extern void i_longint_unsigned_1d(unsigned long long* val); +extern void i_longint_unsigned_2d(unsigned long long* val); +extern void i_longint_unsigned_3d(unsigned long long* val); +extern void i_pack_struct_0d(svLogicVecVal* val); +extern void i_pack_struct_1d(svLogicVecVal* val); +extern void i_pack_struct_2d(svLogicVecVal* val); +extern void i_pack_struct_3d(svLogicVecVal* val); +extern void i_real_0d(double* val); +extern void i_real_1d(double* val); +extern void i_real_2d(double* val); +extern void i_real_3d(double* val); +extern void i_shortint_0d(short* val); +extern void i_shortint_1d(short* val); +extern void i_shortint_2d(short* val); +extern void i_shortint_3d(short* val); +extern void i_shortint_unsigned_0d(unsigned short* val); +extern void i_shortint_unsigned_1d(unsigned short* val); +extern void i_shortint_unsigned_2d(unsigned short* val); +extern void i_shortint_unsigned_3d(unsigned short* val); +extern void i_string_0d(const char** val); +extern void i_string_1d(const char** val); +extern void i_string_2d(const char** val); +extern void i_string_3d(const char** val); +extern void i_time_0d(svLogicVecVal* val); +extern void i_time_1d(svLogicVecVal* val); +extern void i_time_2d(svLogicVecVal* val); +extern void i_time_3d(svLogicVecVal* val); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_arg_input_type__Dpi.out b/test_regress/t/t_dpi_arg_input_type__Dpi.out index d0994c659..e8f345295 100644 --- a/test_regress/t/t_dpi_arg_input_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_type__Dpi.out @@ -15,142 +15,142 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_array_2_state_1(const svBitVecVal* i); - extern void e_array_2_state_128(const svBitVecVal* i); - extern void e_array_2_state_32(const svBitVecVal* i); - extern void e_array_2_state_33(const svBitVecVal* i); - extern void e_array_2_state_64(const svBitVecVal* i); - extern void e_array_2_state_65(const svBitVecVal* i); - extern void e_array_4_state_1(const svLogicVecVal* i); - extern void e_array_4_state_128(const svLogicVecVal* i); - extern void e_array_4_state_32(const svLogicVecVal* i); - extern void e_array_4_state_33(const svLogicVecVal* i); - extern void e_array_4_state_64(const svLogicVecVal* i); - extern void e_array_4_state_65(const svLogicVecVal* i); - extern void e_bit(svBit i); - extern void e_bit_t(svBit i); - extern void e_byte(char i); - extern void e_byte_t(char i); - extern void e_byte_unsigned(unsigned char i); - extern void e_byte_unsigned_t(unsigned char i); - extern void e_chandle(void* i); - extern void e_chandle_t(void* i); - extern void e_int(int i); - extern void e_int_t(int i); - extern void e_int_unsigned(unsigned int i); - extern void e_int_unsigned_t(unsigned int i); - extern void e_integer(const svLogicVecVal* i); - extern void e_integer_t(const svLogicVecVal* i); - extern void e_logic(svLogic i); - extern void e_logic_t(svLogic i); - extern void e_longint(long long i); - extern void e_longint_t(long long i); - extern void e_longint_unsigned(unsigned long long i); - extern void e_longint_unsigned_t(unsigned long long i); - extern void e_real(double i); - extern void e_real_t(double i); - extern void e_shortint(short i); - extern void e_shortint_t(short i); - extern void e_shortint_unsigned(unsigned short i); - extern void e_shortint_unsigned_t(unsigned short i); - extern void e_string(const char* i); - extern void e_string_t(const char* i); - extern void e_struct_2_state_1(const svBitVecVal* i); - extern void e_struct_2_state_128(const svBitVecVal* i); - extern void e_struct_2_state_32(const svBitVecVal* i); - extern void e_struct_2_state_33(const svBitVecVal* i); - extern void e_struct_2_state_64(const svBitVecVal* i); - extern void e_struct_2_state_65(const svBitVecVal* i); - extern void e_struct_4_state_1(const svLogicVecVal* i); - extern void e_struct_4_state_128(const svLogicVecVal* i); - extern void e_struct_4_state_32(const svLogicVecVal* i); - extern void e_struct_4_state_33(const svLogicVecVal* i); - extern void e_struct_4_state_64(const svLogicVecVal* i); - extern void e_struct_4_state_65(const svLogicVecVal* i); - extern void e_time(const svLogicVecVal* i); - extern void e_time_t(const svLogicVecVal* i); - extern void e_union_2_state_1(const svBitVecVal* i); - extern void e_union_2_state_128(const svBitVecVal* i); - extern void e_union_2_state_32(const svBitVecVal* i); - extern void e_union_2_state_33(const svBitVecVal* i); - extern void e_union_2_state_64(const svBitVecVal* i); - extern void e_union_2_state_65(const svBitVecVal* i); - extern void e_union_4_state_1(const svLogicVecVal* i); - extern void e_union_4_state_128(const svLogicVecVal* i); - extern void e_union_4_state_32(const svLogicVecVal* i); - extern void e_union_4_state_33(const svLogicVecVal* i); - extern void e_union_4_state_64(const svLogicVecVal* i); - extern void e_union_4_state_65(const svLogicVecVal* i); +// DPI EXPORTS +extern void e_array_2_state_1(const svBitVecVal* i); +extern void e_array_2_state_128(const svBitVecVal* i); +extern void e_array_2_state_32(const svBitVecVal* i); +extern void e_array_2_state_33(const svBitVecVal* i); +extern void e_array_2_state_64(const svBitVecVal* i); +extern void e_array_2_state_65(const svBitVecVal* i); +extern void e_array_4_state_1(const svLogicVecVal* i); +extern void e_array_4_state_128(const svLogicVecVal* i); +extern void e_array_4_state_32(const svLogicVecVal* i); +extern void e_array_4_state_33(const svLogicVecVal* i); +extern void e_array_4_state_64(const svLogicVecVal* i); +extern void e_array_4_state_65(const svLogicVecVal* i); +extern void e_bit(svBit i); +extern void e_bit_t(svBit i); +extern void e_byte(char i); +extern void e_byte_t(char i); +extern void e_byte_unsigned(unsigned char i); +extern void e_byte_unsigned_t(unsigned char i); +extern void e_chandle(void* i); +extern void e_chandle_t(void* i); +extern void e_int(int i); +extern void e_int_t(int i); +extern void e_int_unsigned(unsigned int i); +extern void e_int_unsigned_t(unsigned int i); +extern void e_integer(const svLogicVecVal* i); +extern void e_integer_t(const svLogicVecVal* i); +extern void e_logic(svLogic i); +extern void e_logic_t(svLogic i); +extern void e_longint(long long i); +extern void e_longint_t(long long i); +extern void e_longint_unsigned(unsigned long long i); +extern void e_longint_unsigned_t(unsigned long long i); +extern void e_real(double i); +extern void e_real_t(double i); +extern void e_shortint(short i); +extern void e_shortint_t(short i); +extern void e_shortint_unsigned(unsigned short i); +extern void e_shortint_unsigned_t(unsigned short i); +extern void e_string(const char* i); +extern void e_string_t(const char* i); +extern void e_struct_2_state_1(const svBitVecVal* i); +extern void e_struct_2_state_128(const svBitVecVal* i); +extern void e_struct_2_state_32(const svBitVecVal* i); +extern void e_struct_2_state_33(const svBitVecVal* i); +extern void e_struct_2_state_64(const svBitVecVal* i); +extern void e_struct_2_state_65(const svBitVecVal* i); +extern void e_struct_4_state_1(const svLogicVecVal* i); +extern void e_struct_4_state_128(const svLogicVecVal* i); +extern void e_struct_4_state_32(const svLogicVecVal* i); +extern void e_struct_4_state_33(const svLogicVecVal* i); +extern void e_struct_4_state_64(const svLogicVecVal* i); +extern void e_struct_4_state_65(const svLogicVecVal* i); +extern void e_time(const svLogicVecVal* i); +extern void e_time_t(const svLogicVecVal* i); +extern void e_union_2_state_1(const svBitVecVal* i); +extern void e_union_2_state_128(const svBitVecVal* i); +extern void e_union_2_state_32(const svBitVecVal* i); +extern void e_union_2_state_33(const svBitVecVal* i); +extern void e_union_2_state_64(const svBitVecVal* i); +extern void e_union_2_state_65(const svBitVecVal* i); +extern void e_union_4_state_1(const svLogicVecVal* i); +extern void e_union_4_state_128(const svLogicVecVal* i); +extern void e_union_4_state_32(const svLogicVecVal* i); +extern void e_union_4_state_33(const svLogicVecVal* i); +extern void e_union_4_state_64(const svLogicVecVal* i); +extern void e_union_4_state_65(const svLogicVecVal* i); - // DPI IMPORTS - extern void check_exports(); - extern void i_array_2_state_1(const svBitVecVal* i); - extern void i_array_2_state_128(const svBitVecVal* i); - extern void i_array_2_state_32(const svBitVecVal* i); - extern void i_array_2_state_33(const svBitVecVal* i); - extern void i_array_2_state_64(const svBitVecVal* i); - extern void i_array_2_state_65(const svBitVecVal* i); - extern void i_array_4_state_1(const svLogicVecVal* i); - extern void i_array_4_state_128(const svLogicVecVal* i); - extern void i_array_4_state_32(const svLogicVecVal* i); - extern void i_array_4_state_33(const svLogicVecVal* i); - extern void i_array_4_state_64(const svLogicVecVal* i); - extern void i_array_4_state_65(const svLogicVecVal* i); - extern void i_bit(svBit i); - extern void i_bit_t(svBit i); - extern void i_byte(char i); - extern void i_byte_t(char i); - extern void i_byte_unsigned(unsigned char i); - extern void i_byte_unsigned_t(unsigned char i); - extern void i_chandle(void* i); - extern void i_chandle_t(void* i); - extern void i_int(int i); - extern void i_int_t(int i); - extern void i_int_unsigned(unsigned int i); - extern void i_int_unsigned_t(unsigned int i); - extern void i_integer(const svLogicVecVal* i); - extern void i_integer_t(const svLogicVecVal* i); - extern void i_logic(svLogic i); - extern void i_logic_t(svLogic i); - extern void i_longint(long long i); - extern void i_longint_t(long long i); - extern void i_longint_unsigned(unsigned long long i); - extern void i_longint_unsigned_t(unsigned long long i); - extern void i_real(double i); - extern void i_real_t(double i); - extern void i_shortint(short i); - extern void i_shortint_t(short i); - extern void i_shortint_unsigned(unsigned short i); - extern void i_shortint_unsigned_t(unsigned short i); - extern void i_string(const char* i); - extern void i_string_t(const char* i); - extern void i_struct_2_state_1(const svBitVecVal* i); - extern void i_struct_2_state_128(const svBitVecVal* i); - extern void i_struct_2_state_32(const svBitVecVal* i); - extern void i_struct_2_state_33(const svBitVecVal* i); - extern void i_struct_2_state_64(const svBitVecVal* i); - extern void i_struct_2_state_65(const svBitVecVal* i); - extern void i_struct_4_state_1(const svLogicVecVal* i); - extern void i_struct_4_state_128(const svLogicVecVal* i); - extern void i_struct_4_state_32(const svLogicVecVal* i); - extern void i_struct_4_state_33(const svLogicVecVal* i); - extern void i_struct_4_state_64(const svLogicVecVal* i); - extern void i_struct_4_state_65(const svLogicVecVal* i); - extern void i_time(const svLogicVecVal* i); - extern void i_time_t(const svLogicVecVal* i); - extern void i_union_2_state_1(const svBitVecVal* i); - extern void i_union_2_state_128(const svBitVecVal* i); - extern void i_union_2_state_32(const svBitVecVal* i); - extern void i_union_2_state_33(const svBitVecVal* i); - extern void i_union_2_state_64(const svBitVecVal* i); - extern void i_union_2_state_65(const svBitVecVal* i); - extern void i_union_4_state_1(const svLogicVecVal* i); - extern void i_union_4_state_128(const svLogicVecVal* i); - extern void i_union_4_state_32(const svLogicVecVal* i); - extern void i_union_4_state_33(const svLogicVecVal* i); - extern void i_union_4_state_64(const svLogicVecVal* i); - extern void i_union_4_state_65(const svLogicVecVal* i); +// DPI IMPORTS +extern void check_exports(); +extern void i_array_2_state_1(const svBitVecVal* i); +extern void i_array_2_state_128(const svBitVecVal* i); +extern void i_array_2_state_32(const svBitVecVal* i); +extern void i_array_2_state_33(const svBitVecVal* i); +extern void i_array_2_state_64(const svBitVecVal* i); +extern void i_array_2_state_65(const svBitVecVal* i); +extern void i_array_4_state_1(const svLogicVecVal* i); +extern void i_array_4_state_128(const svLogicVecVal* i); +extern void i_array_4_state_32(const svLogicVecVal* i); +extern void i_array_4_state_33(const svLogicVecVal* i); +extern void i_array_4_state_64(const svLogicVecVal* i); +extern void i_array_4_state_65(const svLogicVecVal* i); +extern void i_bit(svBit i); +extern void i_bit_t(svBit i); +extern void i_byte(char i); +extern void i_byte_t(char i); +extern void i_byte_unsigned(unsigned char i); +extern void i_byte_unsigned_t(unsigned char i); +extern void i_chandle(void* i); +extern void i_chandle_t(void* i); +extern void i_int(int i); +extern void i_int_t(int i); +extern void i_int_unsigned(unsigned int i); +extern void i_int_unsigned_t(unsigned int i); +extern void i_integer(const svLogicVecVal* i); +extern void i_integer_t(const svLogicVecVal* i); +extern void i_logic(svLogic i); +extern void i_logic_t(svLogic i); +extern void i_longint(long long i); +extern void i_longint_t(long long i); +extern void i_longint_unsigned(unsigned long long i); +extern void i_longint_unsigned_t(unsigned long long i); +extern void i_real(double i); +extern void i_real_t(double i); +extern void i_shortint(short i); +extern void i_shortint_t(short i); +extern void i_shortint_unsigned(unsigned short i); +extern void i_shortint_unsigned_t(unsigned short i); +extern void i_string(const char* i); +extern void i_string_t(const char* i); +extern void i_struct_2_state_1(const svBitVecVal* i); +extern void i_struct_2_state_128(const svBitVecVal* i); +extern void i_struct_2_state_32(const svBitVecVal* i); +extern void i_struct_2_state_33(const svBitVecVal* i); +extern void i_struct_2_state_64(const svBitVecVal* i); +extern void i_struct_2_state_65(const svBitVecVal* i); +extern void i_struct_4_state_1(const svLogicVecVal* i); +extern void i_struct_4_state_128(const svLogicVecVal* i); +extern void i_struct_4_state_32(const svLogicVecVal* i); +extern void i_struct_4_state_33(const svLogicVecVal* i); +extern void i_struct_4_state_64(const svLogicVecVal* i); +extern void i_struct_4_state_65(const svLogicVecVal* i); +extern void i_time(const svLogicVecVal* i); +extern void i_time_t(const svLogicVecVal* i); +extern void i_union_2_state_1(const svBitVecVal* i); +extern void i_union_2_state_128(const svBitVecVal* i); +extern void i_union_2_state_32(const svBitVecVal* i); +extern void i_union_2_state_33(const svBitVecVal* i); +extern void i_union_2_state_64(const svBitVecVal* i); +extern void i_union_2_state_65(const svBitVecVal* i); +extern void i_union_4_state_1(const svLogicVecVal* i); +extern void i_union_4_state_128(const svLogicVecVal* i); +extern void i_union_4_state_32(const svLogicVecVal* i); +extern void i_union_4_state_33(const svLogicVecVal* i); +extern void i_union_4_state_64(const svLogicVecVal* i); +extern void i_union_4_state_65(const svLogicVecVal* i); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out index 4d1afa518..ad4c02bc7 100644 --- a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out @@ -15,171 +15,171 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_bit121_0d(const svBitVecVal* val); - extern void e_bit121_1d(const svBitVecVal* val); - extern void e_bit121_2d(const svBitVecVal* val); - extern void e_bit121_3d(const svBitVecVal* val); - extern void e_bit1_0d(svBit val); - extern void e_bit1_1d(const svBit* val); - extern void e_bit1_2d(const svBit* val); - extern void e_bit1_3d(const svBit* val); - extern void e_bit7_0d(const svBitVecVal* val); - extern void e_bit7_1d(const svBitVecVal* val); - extern void e_bit7_2d(const svBitVecVal* val); - extern void e_bit7_3d(const svBitVecVal* val); - extern void e_byte_0d(char val); - extern void e_byte_1d(const char* val); - extern void e_byte_2d(const char* val); - extern void e_byte_3d(const char* val); - extern void e_byte_unsigned_0d(unsigned char val); - extern void e_byte_unsigned_1d(const unsigned char* val); - extern void e_byte_unsigned_2d(const unsigned char* val); - extern void e_byte_unsigned_3d(const unsigned char* val); - extern void e_chandle_0d(void* val); - extern void e_chandle_1d(const void** val); - extern void e_chandle_2d(const void** val); - extern void e_chandle_3d(const void** val); - extern void e_int_0d(int val); - extern void e_int_1d(const int* val); - extern void e_int_2d(const int* val); - extern void e_int_3d(const int* val); - extern void e_int_unsigned_0d(unsigned int val); - extern void e_int_unsigned_1d(const unsigned int* val); - extern void e_int_unsigned_2d(const unsigned int* val); - extern void e_int_unsigned_3d(const unsigned int* val); - extern void e_integer_0d(const svLogicVecVal* val); - extern void e_integer_1d(const svLogicVecVal* val); - extern void e_integer_2d(const svLogicVecVal* val); - extern void e_integer_3d(const svLogicVecVal* val); - extern void e_logic121_0d(const svLogicVecVal* val); - extern void e_logic121_1d(const svLogicVecVal* val); - extern void e_logic121_2d(const svLogicVecVal* val); - extern void e_logic121_3d(const svLogicVecVal* val); - extern void e_logic1_0d(svLogic val); - extern void e_logic1_1d(const svLogic* val); - extern void e_logic1_2d(const svLogic* val); - extern void e_logic1_3d(const svLogic* val); - extern void e_logic7_0d(const svLogicVecVal* val); - extern void e_logic7_1d(const svLogicVecVal* val); - extern void e_logic7_2d(const svLogicVecVal* val); - extern void e_logic7_3d(const svLogicVecVal* val); - extern void e_longint_0d(long long val); - extern void e_longint_1d(const long long* val); - extern void e_longint_2d(const long long* val); - extern void e_longint_3d(const long long* val); - extern void e_longint_unsigned_0d(unsigned long long val); - extern void e_longint_unsigned_1d(const unsigned long long* val); - extern void e_longint_unsigned_2d(const unsigned long long* val); - extern void e_longint_unsigned_3d(const unsigned long long* val); - extern void e_pack_struct_0d(const svLogicVecVal* val); - extern void e_pack_struct_1d(const svLogicVecVal* val); - extern void e_pack_struct_2d(const svLogicVecVal* val); - extern void e_pack_struct_3d(const svLogicVecVal* val); - extern void e_real_0d(double val); - extern void e_real_1d(const double* val); - extern void e_real_2d(const double* val); - extern void e_real_3d(const double* val); - extern void e_shortint_0d(short val); - extern void e_shortint_1d(const short* val); - extern void e_shortint_2d(const short* val); - extern void e_shortint_3d(const short* val); - extern void e_shortint_unsigned_0d(unsigned short val); - extern void e_shortint_unsigned_1d(const unsigned short* val); - extern void e_shortint_unsigned_2d(const unsigned short* val); - extern void e_shortint_unsigned_3d(const unsigned short* val); - extern void e_string_0d(const char* val); - extern void e_string_1d(const char** val); - extern void e_string_2d(const char** val); - extern void e_string_3d(const char** val); - extern void e_time_0d(const svLogicVecVal* val); - extern void e_time_1d(const svLogicVecVal* val); - extern void e_time_2d(const svLogicVecVal* val); - extern void e_time_3d(const svLogicVecVal* val); +// DPI EXPORTS +extern void e_bit121_0d(const svBitVecVal* val); +extern void e_bit121_1d(const svBitVecVal* val); +extern void e_bit121_2d(const svBitVecVal* val); +extern void e_bit121_3d(const svBitVecVal* val); +extern void e_bit1_0d(svBit val); +extern void e_bit1_1d(const svBit* val); +extern void e_bit1_2d(const svBit* val); +extern void e_bit1_3d(const svBit* val); +extern void e_bit7_0d(const svBitVecVal* val); +extern void e_bit7_1d(const svBitVecVal* val); +extern void e_bit7_2d(const svBitVecVal* val); +extern void e_bit7_3d(const svBitVecVal* val); +extern void e_byte_0d(char val); +extern void e_byte_1d(const char* val); +extern void e_byte_2d(const char* val); +extern void e_byte_3d(const char* val); +extern void e_byte_unsigned_0d(unsigned char val); +extern void e_byte_unsigned_1d(const unsigned char* val); +extern void e_byte_unsigned_2d(const unsigned char* val); +extern void e_byte_unsigned_3d(const unsigned char* val); +extern void e_chandle_0d(void* val); +extern void e_chandle_1d(const void** val); +extern void e_chandle_2d(const void** val); +extern void e_chandle_3d(const void** val); +extern void e_int_0d(int val); +extern void e_int_1d(const int* val); +extern void e_int_2d(const int* val); +extern void e_int_3d(const int* val); +extern void e_int_unsigned_0d(unsigned int val); +extern void e_int_unsigned_1d(const unsigned int* val); +extern void e_int_unsigned_2d(const unsigned int* val); +extern void e_int_unsigned_3d(const unsigned int* val); +extern void e_integer_0d(const svLogicVecVal* val); +extern void e_integer_1d(const svLogicVecVal* val); +extern void e_integer_2d(const svLogicVecVal* val); +extern void e_integer_3d(const svLogicVecVal* val); +extern void e_logic121_0d(const svLogicVecVal* val); +extern void e_logic121_1d(const svLogicVecVal* val); +extern void e_logic121_2d(const svLogicVecVal* val); +extern void e_logic121_3d(const svLogicVecVal* val); +extern void e_logic1_0d(svLogic val); +extern void e_logic1_1d(const svLogic* val); +extern void e_logic1_2d(const svLogic* val); +extern void e_logic1_3d(const svLogic* val); +extern void e_logic7_0d(const svLogicVecVal* val); +extern void e_logic7_1d(const svLogicVecVal* val); +extern void e_logic7_2d(const svLogicVecVal* val); +extern void e_logic7_3d(const svLogicVecVal* val); +extern void e_longint_0d(long long val); +extern void e_longint_1d(const long long* val); +extern void e_longint_2d(const long long* val); +extern void e_longint_3d(const long long* val); +extern void e_longint_unsigned_0d(unsigned long long val); +extern void e_longint_unsigned_1d(const unsigned long long* val); +extern void e_longint_unsigned_2d(const unsigned long long* val); +extern void e_longint_unsigned_3d(const unsigned long long* val); +extern void e_pack_struct_0d(const svLogicVecVal* val); +extern void e_pack_struct_1d(const svLogicVecVal* val); +extern void e_pack_struct_2d(const svLogicVecVal* val); +extern void e_pack_struct_3d(const svLogicVecVal* val); +extern void e_real_0d(double val); +extern void e_real_1d(const double* val); +extern void e_real_2d(const double* val); +extern void e_real_3d(const double* val); +extern void e_shortint_0d(short val); +extern void e_shortint_1d(const short* val); +extern void e_shortint_2d(const short* val); +extern void e_shortint_3d(const short* val); +extern void e_shortint_unsigned_0d(unsigned short val); +extern void e_shortint_unsigned_1d(const unsigned short* val); +extern void e_shortint_unsigned_2d(const unsigned short* val); +extern void e_shortint_unsigned_3d(const unsigned short* val); +extern void e_string_0d(const char* val); +extern void e_string_1d(const char** val); +extern void e_string_2d(const char** val); +extern void e_string_3d(const char** val); +extern void e_time_0d(const svLogicVecVal* val); +extern void e_time_1d(const svLogicVecVal* val); +extern void e_time_2d(const svLogicVecVal* val); +extern void e_time_3d(const svLogicVecVal* val); - // DPI IMPORTS - extern void check_exports(); - extern void* get_non_null(); - extern void i_bit121_0d(const svBitVecVal* val); - extern void i_bit121_1d(const svBitVecVal* val); - extern void i_bit121_2d(const svBitVecVal* val); - extern void i_bit121_3d(const svBitVecVal* val); - extern void i_bit1_0d(svBit val); - extern void i_bit1_1d(const svBit* val); - extern void i_bit1_2d(const svBit* val); - extern void i_bit1_3d(const svBit* val); - extern void i_bit7_0d(const svBitVecVal* val); - extern void i_bit7_1d(const svBitVecVal* val); - extern void i_bit7_2d(const svBitVecVal* val); - extern void i_bit7_3d(const svBitVecVal* val); - extern void i_byte_0d(char val); - extern void i_byte_1d(const char* val); - extern void i_byte_2d(const char* val); - extern void i_byte_3d(const char* val); - extern void i_byte_unsigned_0d(unsigned char val); - extern void i_byte_unsigned_1d(const unsigned char* val); - extern void i_byte_unsigned_2d(const unsigned char* val); - extern void i_byte_unsigned_3d(const unsigned char* val); - extern void i_chandle_0d(void* val); - extern void i_chandle_1d(const void** val); - extern void i_chandle_2d(const void** val); - extern void i_chandle_3d(const void** val); - extern void i_int_0d(int val); - extern void i_int_1d(const int* val); - extern void i_int_2d(const int* val); - extern void i_int_3d(const int* val); - extern void i_int_unsigned_0d(unsigned int val); - extern void i_int_unsigned_1d(const unsigned int* val); - extern void i_int_unsigned_2d(const unsigned int* val); - extern void i_int_unsigned_3d(const unsigned int* val); - extern void i_integer_0d(const svLogicVecVal* val); - extern void i_integer_1d(const svLogicVecVal* val); - extern void i_integer_2d(const svLogicVecVal* val); - extern void i_integer_3d(const svLogicVecVal* val); - extern void i_logic121_0d(const svLogicVecVal* val); - extern void i_logic121_1d(const svLogicVecVal* val); - extern void i_logic121_2d(const svLogicVecVal* val); - extern void i_logic121_3d(const svLogicVecVal* val); - extern void i_logic1_0d(svLogic val); - extern void i_logic1_1d(const svLogic* val); - extern void i_logic1_2d(const svLogic* val); - extern void i_logic1_3d(const svLogic* val); - extern void i_logic7_0d(const svLogicVecVal* val); - extern void i_logic7_1d(const svLogicVecVal* val); - extern void i_logic7_2d(const svLogicVecVal* val); - extern void i_logic7_3d(const svLogicVecVal* val); - extern void i_longint_0d(long long val); - extern void i_longint_1d(const long long* val); - extern void i_longint_2d(const long long* val); - extern void i_longint_3d(const long long* val); - extern void i_longint_unsigned_0d(unsigned long long val); - extern void i_longint_unsigned_1d(const unsigned long long* val); - extern void i_longint_unsigned_2d(const unsigned long long* val); - extern void i_longint_unsigned_3d(const unsigned long long* val); - extern void i_pack_struct_0d(const svLogicVecVal* val); - extern void i_pack_struct_1d(const svLogicVecVal* val); - extern void i_pack_struct_2d(const svLogicVecVal* val); - extern void i_pack_struct_3d(const svLogicVecVal* val); - extern void i_real_0d(double val); - extern void i_real_1d(const double* val); - extern void i_real_2d(const double* val); - extern void i_real_3d(const double* val); - extern void i_shortint_0d(short val); - extern void i_shortint_1d(const short* val); - extern void i_shortint_2d(const short* val); - extern void i_shortint_3d(const short* val); - extern void i_shortint_unsigned_0d(unsigned short val); - extern void i_shortint_unsigned_1d(const unsigned short* val); - extern void i_shortint_unsigned_2d(const unsigned short* val); - extern void i_shortint_unsigned_3d(const unsigned short* val); - extern void i_string_0d(const char* val); - extern void i_string_1d(const char** val); - extern void i_string_2d(const char** val); - extern void i_string_3d(const char** val); - extern void i_time_0d(const svLogicVecVal* val); - extern void i_time_1d(const svLogicVecVal* val); - extern void i_time_2d(const svLogicVecVal* val); - extern void i_time_3d(const svLogicVecVal* val); +// DPI IMPORTS +extern void check_exports(); +extern void* get_non_null(); +extern void i_bit121_0d(const svBitVecVal* val); +extern void i_bit121_1d(const svBitVecVal* val); +extern void i_bit121_2d(const svBitVecVal* val); +extern void i_bit121_3d(const svBitVecVal* val); +extern void i_bit1_0d(svBit val); +extern void i_bit1_1d(const svBit* val); +extern void i_bit1_2d(const svBit* val); +extern void i_bit1_3d(const svBit* val); +extern void i_bit7_0d(const svBitVecVal* val); +extern void i_bit7_1d(const svBitVecVal* val); +extern void i_bit7_2d(const svBitVecVal* val); +extern void i_bit7_3d(const svBitVecVal* val); +extern void i_byte_0d(char val); +extern void i_byte_1d(const char* val); +extern void i_byte_2d(const char* val); +extern void i_byte_3d(const char* val); +extern void i_byte_unsigned_0d(unsigned char val); +extern void i_byte_unsigned_1d(const unsigned char* val); +extern void i_byte_unsigned_2d(const unsigned char* val); +extern void i_byte_unsigned_3d(const unsigned char* val); +extern void i_chandle_0d(void* val); +extern void i_chandle_1d(const void** val); +extern void i_chandle_2d(const void** val); +extern void i_chandle_3d(const void** val); +extern void i_int_0d(int val); +extern void i_int_1d(const int* val); +extern void i_int_2d(const int* val); +extern void i_int_3d(const int* val); +extern void i_int_unsigned_0d(unsigned int val); +extern void i_int_unsigned_1d(const unsigned int* val); +extern void i_int_unsigned_2d(const unsigned int* val); +extern void i_int_unsigned_3d(const unsigned int* val); +extern void i_integer_0d(const svLogicVecVal* val); +extern void i_integer_1d(const svLogicVecVal* val); +extern void i_integer_2d(const svLogicVecVal* val); +extern void i_integer_3d(const svLogicVecVal* val); +extern void i_logic121_0d(const svLogicVecVal* val); +extern void i_logic121_1d(const svLogicVecVal* val); +extern void i_logic121_2d(const svLogicVecVal* val); +extern void i_logic121_3d(const svLogicVecVal* val); +extern void i_logic1_0d(svLogic val); +extern void i_logic1_1d(const svLogic* val); +extern void i_logic1_2d(const svLogic* val); +extern void i_logic1_3d(const svLogic* val); +extern void i_logic7_0d(const svLogicVecVal* val); +extern void i_logic7_1d(const svLogicVecVal* val); +extern void i_logic7_2d(const svLogicVecVal* val); +extern void i_logic7_3d(const svLogicVecVal* val); +extern void i_longint_0d(long long val); +extern void i_longint_1d(const long long* val); +extern void i_longint_2d(const long long* val); +extern void i_longint_3d(const long long* val); +extern void i_longint_unsigned_0d(unsigned long long val); +extern void i_longint_unsigned_1d(const unsigned long long* val); +extern void i_longint_unsigned_2d(const unsigned long long* val); +extern void i_longint_unsigned_3d(const unsigned long long* val); +extern void i_pack_struct_0d(const svLogicVecVal* val); +extern void i_pack_struct_1d(const svLogicVecVal* val); +extern void i_pack_struct_2d(const svLogicVecVal* val); +extern void i_pack_struct_3d(const svLogicVecVal* val); +extern void i_real_0d(double val); +extern void i_real_1d(const double* val); +extern void i_real_2d(const double* val); +extern void i_real_3d(const double* val); +extern void i_shortint_0d(short val); +extern void i_shortint_1d(const short* val); +extern void i_shortint_2d(const short* val); +extern void i_shortint_3d(const short* val); +extern void i_shortint_unsigned_0d(unsigned short val); +extern void i_shortint_unsigned_1d(const unsigned short* val); +extern void i_shortint_unsigned_2d(const unsigned short* val); +extern void i_shortint_unsigned_3d(const unsigned short* val); +extern void i_string_0d(const char* val); +extern void i_string_1d(const char** val); +extern void i_string_2d(const char** val); +extern void i_string_3d(const char** val); +extern void i_time_0d(const svLogicVecVal* val); +extern void i_time_1d(const svLogicVecVal* val); +extern void i_time_2d(const svLogicVecVal* val); +extern void i_time_3d(const svLogicVecVal* val); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_arg_output_type__Dpi.out b/test_regress/t/t_dpi_arg_output_type__Dpi.out index e84de47c3..37204ecc3 100644 --- a/test_regress/t/t_dpi_arg_output_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_type__Dpi.out @@ -15,142 +15,142 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_array_2_state_1(svBitVecVal* o); - extern void e_array_2_state_128(svBitVecVal* o); - extern void e_array_2_state_32(svBitVecVal* o); - extern void e_array_2_state_33(svBitVecVal* o); - extern void e_array_2_state_64(svBitVecVal* o); - extern void e_array_2_state_65(svBitVecVal* o); - extern void e_array_4_state_1(svLogicVecVal* o); - extern void e_array_4_state_128(svLogicVecVal* o); - extern void e_array_4_state_32(svLogicVecVal* o); - extern void e_array_4_state_33(svLogicVecVal* o); - extern void e_array_4_state_64(svLogicVecVal* o); - extern void e_array_4_state_65(svLogicVecVal* o); - extern void e_bit(svBit* o); - extern void e_bit_t(svBit* o); - extern void e_byte(char* o); - extern void e_byte_t(char* o); - extern void e_byte_unsigned(unsigned char* o); - extern void e_byte_unsigned_t(unsigned char* o); - extern void e_chandle(void** o); - extern void e_chandle_t(void** o); - extern void e_int(int* o); - extern void e_int_t(int* o); - extern void e_int_unsigned(unsigned int* o); - extern void e_int_unsigned_t(unsigned int* o); - extern void e_integer(svLogicVecVal* o); - extern void e_integer_t(svLogicVecVal* o); - extern void e_logic(svLogic* o); - extern void e_logic_t(svLogic* o); - extern void e_longint(long long* o); - extern void e_longint_t(long long* o); - extern void e_longint_unsigned(unsigned long long* o); - extern void e_longint_unsigned_t(unsigned long long* o); - extern void e_real(double* o); - extern void e_real_t(double* o); - extern void e_shortint(short* o); - extern void e_shortint_t(short* o); - extern void e_shortint_unsigned(unsigned short* o); - extern void e_shortint_unsigned_t(unsigned short* o); - extern void e_string(const char** o); - extern void e_string_t(const char** o); - extern void e_struct_2_state_1(svBitVecVal* o); - extern void e_struct_2_state_128(svBitVecVal* o); - extern void e_struct_2_state_32(svBitVecVal* o); - extern void e_struct_2_state_33(svBitVecVal* o); - extern void e_struct_2_state_64(svBitVecVal* o); - extern void e_struct_2_state_65(svBitVecVal* o); - extern void e_struct_4_state_1(svLogicVecVal* o); - extern void e_struct_4_state_128(svLogicVecVal* o); - extern void e_struct_4_state_32(svLogicVecVal* o); - extern void e_struct_4_state_33(svLogicVecVal* o); - extern void e_struct_4_state_64(svLogicVecVal* o); - extern void e_struct_4_state_65(svLogicVecVal* o); - extern void e_time(svLogicVecVal* o); - extern void e_time_t(svLogicVecVal* o); - extern void e_union_2_state_1(svBitVecVal* o); - extern void e_union_2_state_128(svBitVecVal* o); - extern void e_union_2_state_32(svBitVecVal* o); - extern void e_union_2_state_33(svBitVecVal* o); - extern void e_union_2_state_64(svBitVecVal* o); - extern void e_union_2_state_65(svBitVecVal* o); - extern void e_union_4_state_1(svLogicVecVal* o); - extern void e_union_4_state_128(svLogicVecVal* o); - extern void e_union_4_state_32(svLogicVecVal* o); - extern void e_union_4_state_33(svLogicVecVal* o); - extern void e_union_4_state_64(svLogicVecVal* o); - extern void e_union_4_state_65(svLogicVecVal* o); +// DPI EXPORTS +extern void e_array_2_state_1(svBitVecVal* o); +extern void e_array_2_state_128(svBitVecVal* o); +extern void e_array_2_state_32(svBitVecVal* o); +extern void e_array_2_state_33(svBitVecVal* o); +extern void e_array_2_state_64(svBitVecVal* o); +extern void e_array_2_state_65(svBitVecVal* o); +extern void e_array_4_state_1(svLogicVecVal* o); +extern void e_array_4_state_128(svLogicVecVal* o); +extern void e_array_4_state_32(svLogicVecVal* o); +extern void e_array_4_state_33(svLogicVecVal* o); +extern void e_array_4_state_64(svLogicVecVal* o); +extern void e_array_4_state_65(svLogicVecVal* o); +extern void e_bit(svBit* o); +extern void e_bit_t(svBit* o); +extern void e_byte(char* o); +extern void e_byte_t(char* o); +extern void e_byte_unsigned(unsigned char* o); +extern void e_byte_unsigned_t(unsigned char* o); +extern void e_chandle(void** o); +extern void e_chandle_t(void** o); +extern void e_int(int* o); +extern void e_int_t(int* o); +extern void e_int_unsigned(unsigned int* o); +extern void e_int_unsigned_t(unsigned int* o); +extern void e_integer(svLogicVecVal* o); +extern void e_integer_t(svLogicVecVal* o); +extern void e_logic(svLogic* o); +extern void e_logic_t(svLogic* o); +extern void e_longint(long long* o); +extern void e_longint_t(long long* o); +extern void e_longint_unsigned(unsigned long long* o); +extern void e_longint_unsigned_t(unsigned long long* o); +extern void e_real(double* o); +extern void e_real_t(double* o); +extern void e_shortint(short* o); +extern void e_shortint_t(short* o); +extern void e_shortint_unsigned(unsigned short* o); +extern void e_shortint_unsigned_t(unsigned short* o); +extern void e_string(const char** o); +extern void e_string_t(const char** o); +extern void e_struct_2_state_1(svBitVecVal* o); +extern void e_struct_2_state_128(svBitVecVal* o); +extern void e_struct_2_state_32(svBitVecVal* o); +extern void e_struct_2_state_33(svBitVecVal* o); +extern void e_struct_2_state_64(svBitVecVal* o); +extern void e_struct_2_state_65(svBitVecVal* o); +extern void e_struct_4_state_1(svLogicVecVal* o); +extern void e_struct_4_state_128(svLogicVecVal* o); +extern void e_struct_4_state_32(svLogicVecVal* o); +extern void e_struct_4_state_33(svLogicVecVal* o); +extern void e_struct_4_state_64(svLogicVecVal* o); +extern void e_struct_4_state_65(svLogicVecVal* o); +extern void e_time(svLogicVecVal* o); +extern void e_time_t(svLogicVecVal* o); +extern void e_union_2_state_1(svBitVecVal* o); +extern void e_union_2_state_128(svBitVecVal* o); +extern void e_union_2_state_32(svBitVecVal* o); +extern void e_union_2_state_33(svBitVecVal* o); +extern void e_union_2_state_64(svBitVecVal* o); +extern void e_union_2_state_65(svBitVecVal* o); +extern void e_union_4_state_1(svLogicVecVal* o); +extern void e_union_4_state_128(svLogicVecVal* o); +extern void e_union_4_state_32(svLogicVecVal* o); +extern void e_union_4_state_33(svLogicVecVal* o); +extern void e_union_4_state_64(svLogicVecVal* o); +extern void e_union_4_state_65(svLogicVecVal* o); - // DPI IMPORTS - extern void check_exports(); - extern void i_array_2_state_1(svBitVecVal* o); - extern void i_array_2_state_128(svBitVecVal* o); - extern void i_array_2_state_32(svBitVecVal* o); - extern void i_array_2_state_33(svBitVecVal* o); - extern void i_array_2_state_64(svBitVecVal* o); - extern void i_array_2_state_65(svBitVecVal* o); - extern void i_array_4_state_1(svLogicVecVal* o); - extern void i_array_4_state_128(svLogicVecVal* o); - extern void i_array_4_state_32(svLogicVecVal* o); - extern void i_array_4_state_33(svLogicVecVal* o); - extern void i_array_4_state_64(svLogicVecVal* o); - extern void i_array_4_state_65(svLogicVecVal* o); - extern void i_bit(svBit* o); - extern void i_bit_t(svBit* o); - extern void i_byte(char* o); - extern void i_byte_t(char* o); - extern void i_byte_unsigned(unsigned char* o); - extern void i_byte_unsigned_t(unsigned char* o); - extern void i_chandle(void** o); - extern void i_chandle_t(void** o); - extern void i_int(int* o); - extern void i_int_t(int* o); - extern void i_int_unsigned(unsigned int* o); - extern void i_int_unsigned_t(unsigned int* o); - extern void i_integer(svLogicVecVal* o); - extern void i_integer_t(svLogicVecVal* o); - extern void i_logic(svLogic* o); - extern void i_logic_t(svLogic* o); - extern void i_longint(long long* o); - extern void i_longint_t(long long* o); - extern void i_longint_unsigned(unsigned long long* o); - extern void i_longint_unsigned_t(unsigned long long* o); - extern void i_real(double* o); - extern void i_real_t(double* o); - extern void i_shortint(short* o); - extern void i_shortint_t(short* o); - extern void i_shortint_unsigned(unsigned short* o); - extern void i_shortint_unsigned_t(unsigned short* o); - extern void i_string(const char** o); - extern void i_string_t(const char** o); - extern void i_struct_2_state_1(svBitVecVal* o); - extern void i_struct_2_state_128(svBitVecVal* o); - extern void i_struct_2_state_32(svBitVecVal* o); - extern void i_struct_2_state_33(svBitVecVal* o); - extern void i_struct_2_state_64(svBitVecVal* o); - extern void i_struct_2_state_65(svBitVecVal* o); - extern void i_struct_4_state_1(svLogicVecVal* o); - extern void i_struct_4_state_128(svLogicVecVal* o); - extern void i_struct_4_state_32(svLogicVecVal* o); - extern void i_struct_4_state_33(svLogicVecVal* o); - extern void i_struct_4_state_64(svLogicVecVal* o); - extern void i_struct_4_state_65(svLogicVecVal* o); - extern void i_time(svLogicVecVal* o); - extern void i_time_t(svLogicVecVal* o); - extern void i_union_2_state_1(svBitVecVal* o); - extern void i_union_2_state_128(svBitVecVal* o); - extern void i_union_2_state_32(svBitVecVal* o); - extern void i_union_2_state_33(svBitVecVal* o); - extern void i_union_2_state_64(svBitVecVal* o); - extern void i_union_2_state_65(svBitVecVal* o); - extern void i_union_4_state_1(svLogicVecVal* o); - extern void i_union_4_state_128(svLogicVecVal* o); - extern void i_union_4_state_32(svLogicVecVal* o); - extern void i_union_4_state_33(svLogicVecVal* o); - extern void i_union_4_state_64(svLogicVecVal* o); - extern void i_union_4_state_65(svLogicVecVal* o); +// DPI IMPORTS +extern void check_exports(); +extern void i_array_2_state_1(svBitVecVal* o); +extern void i_array_2_state_128(svBitVecVal* o); +extern void i_array_2_state_32(svBitVecVal* o); +extern void i_array_2_state_33(svBitVecVal* o); +extern void i_array_2_state_64(svBitVecVal* o); +extern void i_array_2_state_65(svBitVecVal* o); +extern void i_array_4_state_1(svLogicVecVal* o); +extern void i_array_4_state_128(svLogicVecVal* o); +extern void i_array_4_state_32(svLogicVecVal* o); +extern void i_array_4_state_33(svLogicVecVal* o); +extern void i_array_4_state_64(svLogicVecVal* o); +extern void i_array_4_state_65(svLogicVecVal* o); +extern void i_bit(svBit* o); +extern void i_bit_t(svBit* o); +extern void i_byte(char* o); +extern void i_byte_t(char* o); +extern void i_byte_unsigned(unsigned char* o); +extern void i_byte_unsigned_t(unsigned char* o); +extern void i_chandle(void** o); +extern void i_chandle_t(void** o); +extern void i_int(int* o); +extern void i_int_t(int* o); +extern void i_int_unsigned(unsigned int* o); +extern void i_int_unsigned_t(unsigned int* o); +extern void i_integer(svLogicVecVal* o); +extern void i_integer_t(svLogicVecVal* o); +extern void i_logic(svLogic* o); +extern void i_logic_t(svLogic* o); +extern void i_longint(long long* o); +extern void i_longint_t(long long* o); +extern void i_longint_unsigned(unsigned long long* o); +extern void i_longint_unsigned_t(unsigned long long* o); +extern void i_real(double* o); +extern void i_real_t(double* o); +extern void i_shortint(short* o); +extern void i_shortint_t(short* o); +extern void i_shortint_unsigned(unsigned short* o); +extern void i_shortint_unsigned_t(unsigned short* o); +extern void i_string(const char** o); +extern void i_string_t(const char** o); +extern void i_struct_2_state_1(svBitVecVal* o); +extern void i_struct_2_state_128(svBitVecVal* o); +extern void i_struct_2_state_32(svBitVecVal* o); +extern void i_struct_2_state_33(svBitVecVal* o); +extern void i_struct_2_state_64(svBitVecVal* o); +extern void i_struct_2_state_65(svBitVecVal* o); +extern void i_struct_4_state_1(svLogicVecVal* o); +extern void i_struct_4_state_128(svLogicVecVal* o); +extern void i_struct_4_state_32(svLogicVecVal* o); +extern void i_struct_4_state_33(svLogicVecVal* o); +extern void i_struct_4_state_64(svLogicVecVal* o); +extern void i_struct_4_state_65(svLogicVecVal* o); +extern void i_time(svLogicVecVal* o); +extern void i_time_t(svLogicVecVal* o); +extern void i_union_2_state_1(svBitVecVal* o); +extern void i_union_2_state_128(svBitVecVal* o); +extern void i_union_2_state_32(svBitVecVal* o); +extern void i_union_2_state_33(svBitVecVal* o); +extern void i_union_2_state_64(svBitVecVal* o); +extern void i_union_2_state_65(svBitVecVal* o); +extern void i_union_4_state_1(svLogicVecVal* o); +extern void i_union_4_state_128(svLogicVecVal* o); +extern void i_union_4_state_32(svLogicVecVal* o); +extern void i_union_4_state_33(svLogicVecVal* o); +extern void i_union_4_state_64(svLogicVecVal* o); +extern void i_union_4_state_65(svLogicVecVal* o); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out index ddcd704de..623bdc509 100644 --- a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out @@ -15,171 +15,171 @@ extern "C" { #endif - // DPI EXPORTS - extern void e_bit121_0d(svBitVecVal* val); - extern void e_bit121_1d(svBitVecVal* val); - extern void e_bit121_2d(svBitVecVal* val); - extern void e_bit121_3d(svBitVecVal* val); - extern void e_bit1_0d(svBit* val); - extern void e_bit1_1d(svBit* val); - extern void e_bit1_2d(svBit* val); - extern void e_bit1_3d(svBitVecVal* val); - extern void e_bit7_0d(svBitVecVal* val); - extern void e_bit7_1d(svBitVecVal* val); - extern void e_bit7_2d(svBitVecVal* val); - extern void e_bit7_3d(svBitVecVal* val); - extern void e_byte_0d(char* val); - extern void e_byte_1d(char* val); - extern void e_byte_2d(char* val); - extern void e_byte_3d(char* val); - extern void e_byte_unsigned_0d(unsigned char* val); - extern void e_byte_unsigned_1d(unsigned char* val); - extern void e_byte_unsigned_2d(unsigned char* val); - extern void e_byte_unsigned_3d(unsigned char* val); - extern void e_chandle_0d(void** val); - extern void e_chandle_1d(void** val); - extern void e_chandle_2d(void** val); - extern void e_chandle_3d(void** val); - extern void e_int_0d(int* val); - extern void e_int_1d(int* val); - extern void e_int_2d(int* val); - extern void e_int_3d(int* val); - extern void e_int_unsigned_0d(unsigned int* val); - extern void e_int_unsigned_1d(unsigned int* val); - extern void e_int_unsigned_2d(unsigned int* val); - extern void e_int_unsigned_3d(unsigned int* val); - extern void e_integer_0d(svLogicVecVal* val); - extern void e_integer_1d(svLogicVecVal* val); - extern void e_integer_2d(svLogicVecVal* val); - extern void e_integer_3d(svLogicVecVal* val); - extern void e_logic121_0d(svLogicVecVal* val); - extern void e_logic121_1d(svLogicVecVal* val); - extern void e_logic121_2d(svLogicVecVal* val); - extern void e_logic121_3d(svLogicVecVal* val); - extern void e_logic1_0d(svLogic* val); - extern void e_logic1_1d(svLogic* val); - extern void e_logic1_2d(svLogic* val); - extern void e_logic1_3d(svLogicVecVal* val); - extern void e_logic7_0d(svLogicVecVal* val); - extern void e_logic7_1d(svLogicVecVal* val); - extern void e_logic7_2d(svLogicVecVal* val); - extern void e_logic7_3d(svLogicVecVal* val); - extern void e_longint_0d(long long* val); - extern void e_longint_1d(long long* val); - extern void e_longint_2d(long long* val); - extern void e_longint_3d(long long* val); - extern void e_longint_unsigned_0d(unsigned long long* val); - extern void e_longint_unsigned_1d(unsigned long long* val); - extern void e_longint_unsigned_2d(unsigned long long* val); - extern void e_longint_unsigned_3d(unsigned long long* val); - extern void e_pack_struct_0d(svLogicVecVal* val); - extern void e_pack_struct_1d(svLogicVecVal* val); - extern void e_pack_struct_2d(svLogicVecVal* val); - extern void e_pack_struct_3d(svLogicVecVal* val); - extern void e_real_0d(double* val); - extern void e_real_1d(double* val); - extern void e_real_2d(double* val); - extern void e_real_3d(double* val); - extern void e_shortint_0d(short* val); - extern void e_shortint_1d(short* val); - extern void e_shortint_2d(short* val); - extern void e_shortint_3d(short* val); - extern void e_shortint_unsigned_0d(unsigned short* val); - extern void e_shortint_unsigned_1d(unsigned short* val); - extern void e_shortint_unsigned_2d(unsigned short* val); - extern void e_shortint_unsigned_3d(unsigned short* val); - extern void e_string_0d(const char** val); - extern void e_string_1d(const char** val); - extern void e_string_2d(const char** val); - extern void e_string_3d(const char** val); - extern void e_time_0d(svLogicVecVal* val); - extern void e_time_1d(svLogicVecVal* val); - extern void e_time_2d(svLogicVecVal* val); - extern void e_time_3d(svLogicVecVal* val); +// DPI EXPORTS +extern void e_bit121_0d(svBitVecVal* val); +extern void e_bit121_1d(svBitVecVal* val); +extern void e_bit121_2d(svBitVecVal* val); +extern void e_bit121_3d(svBitVecVal* val); +extern void e_bit1_0d(svBit* val); +extern void e_bit1_1d(svBit* val); +extern void e_bit1_2d(svBit* val); +extern void e_bit1_3d(svBitVecVal* val); +extern void e_bit7_0d(svBitVecVal* val); +extern void e_bit7_1d(svBitVecVal* val); +extern void e_bit7_2d(svBitVecVal* val); +extern void e_bit7_3d(svBitVecVal* val); +extern void e_byte_0d(char* val); +extern void e_byte_1d(char* val); +extern void e_byte_2d(char* val); +extern void e_byte_3d(char* val); +extern void e_byte_unsigned_0d(unsigned char* val); +extern void e_byte_unsigned_1d(unsigned char* val); +extern void e_byte_unsigned_2d(unsigned char* val); +extern void e_byte_unsigned_3d(unsigned char* val); +extern void e_chandle_0d(void** val); +extern void e_chandle_1d(void** val); +extern void e_chandle_2d(void** val); +extern void e_chandle_3d(void** val); +extern void e_int_0d(int* val); +extern void e_int_1d(int* val); +extern void e_int_2d(int* val); +extern void e_int_3d(int* val); +extern void e_int_unsigned_0d(unsigned int* val); +extern void e_int_unsigned_1d(unsigned int* val); +extern void e_int_unsigned_2d(unsigned int* val); +extern void e_int_unsigned_3d(unsigned int* val); +extern void e_integer_0d(svLogicVecVal* val); +extern void e_integer_1d(svLogicVecVal* val); +extern void e_integer_2d(svLogicVecVal* val); +extern void e_integer_3d(svLogicVecVal* val); +extern void e_logic121_0d(svLogicVecVal* val); +extern void e_logic121_1d(svLogicVecVal* val); +extern void e_logic121_2d(svLogicVecVal* val); +extern void e_logic121_3d(svLogicVecVal* val); +extern void e_logic1_0d(svLogic* val); +extern void e_logic1_1d(svLogic* val); +extern void e_logic1_2d(svLogic* val); +extern void e_logic1_3d(svLogicVecVal* val); +extern void e_logic7_0d(svLogicVecVal* val); +extern void e_logic7_1d(svLogicVecVal* val); +extern void e_logic7_2d(svLogicVecVal* val); +extern void e_logic7_3d(svLogicVecVal* val); +extern void e_longint_0d(long long* val); +extern void e_longint_1d(long long* val); +extern void e_longint_2d(long long* val); +extern void e_longint_3d(long long* val); +extern void e_longint_unsigned_0d(unsigned long long* val); +extern void e_longint_unsigned_1d(unsigned long long* val); +extern void e_longint_unsigned_2d(unsigned long long* val); +extern void e_longint_unsigned_3d(unsigned long long* val); +extern void e_pack_struct_0d(svLogicVecVal* val); +extern void e_pack_struct_1d(svLogicVecVal* val); +extern void e_pack_struct_2d(svLogicVecVal* val); +extern void e_pack_struct_3d(svLogicVecVal* val); +extern void e_real_0d(double* val); +extern void e_real_1d(double* val); +extern void e_real_2d(double* val); +extern void e_real_3d(double* val); +extern void e_shortint_0d(short* val); +extern void e_shortint_1d(short* val); +extern void e_shortint_2d(short* val); +extern void e_shortint_3d(short* val); +extern void e_shortint_unsigned_0d(unsigned short* val); +extern void e_shortint_unsigned_1d(unsigned short* val); +extern void e_shortint_unsigned_2d(unsigned short* val); +extern void e_shortint_unsigned_3d(unsigned short* val); +extern void e_string_0d(const char** val); +extern void e_string_1d(const char** val); +extern void e_string_2d(const char** val); +extern void e_string_3d(const char** val); +extern void e_time_0d(svLogicVecVal* val); +extern void e_time_1d(svLogicVecVal* val); +extern void e_time_2d(svLogicVecVal* val); +extern void e_time_3d(svLogicVecVal* val); - // DPI IMPORTS - extern void check_exports(); - extern void* get_non_null(); - extern void i_bit121_0d(svBitVecVal* val); - extern void i_bit121_1d(svBitVecVal* val); - extern void i_bit121_2d(svBitVecVal* val); - extern void i_bit121_3d(svBitVecVal* val); - extern void i_bit1_0d(svBit* val); - extern void i_bit1_1d(svBit* val); - extern void i_bit1_2d(svBit* val); - extern void i_bit1_3d(svBit* val); - extern void i_bit7_0d(svBitVecVal* val); - extern void i_bit7_1d(svBitVecVal* val); - extern void i_bit7_2d(svBitVecVal* val); - extern void i_bit7_3d(svBitVecVal* val); - extern void i_byte_0d(char* val); - extern void i_byte_1d(char* val); - extern void i_byte_2d(char* val); - extern void i_byte_3d(char* val); - extern void i_byte_unsigned_0d(unsigned char* val); - extern void i_byte_unsigned_1d(unsigned char* val); - extern void i_byte_unsigned_2d(unsigned char* val); - extern void i_byte_unsigned_3d(unsigned char* val); - extern void i_chandle_0d(void** val); - extern void i_chandle_1d(void** val); - extern void i_chandle_2d(void** val); - extern void i_chandle_3d(void** val); - extern void i_int_0d(int* val); - extern void i_int_1d(int* val); - extern void i_int_2d(int* val); - extern void i_int_3d(int* val); - extern void i_int_unsigned_0d(unsigned int* val); - extern void i_int_unsigned_1d(unsigned int* val); - extern void i_int_unsigned_2d(unsigned int* val); - extern void i_int_unsigned_3d(unsigned int* val); - extern void i_integer_0d(svLogicVecVal* val); - extern void i_integer_1d(svLogicVecVal* val); - extern void i_integer_2d(svLogicVecVal* val); - extern void i_integer_3d(svLogicVecVal* val); - extern void i_logic121_0d(svLogicVecVal* val); - extern void i_logic121_1d(svLogicVecVal* val); - extern void i_logic121_2d(svLogicVecVal* val); - extern void i_logic121_3d(svLogicVecVal* val); - extern void i_logic1_0d(svLogic* val); - extern void i_logic1_1d(svLogic* val); - extern void i_logic1_2d(svLogic* val); - extern void i_logic1_3d(svLogic* val); - extern void i_logic7_0d(svLogicVecVal* val); - extern void i_logic7_1d(svLogicVecVal* val); - extern void i_logic7_2d(svLogicVecVal* val); - extern void i_logic7_3d(svLogicVecVal* val); - extern void i_longint_0d(long long* val); - extern void i_longint_1d(long long* val); - extern void i_longint_2d(long long* val); - extern void i_longint_3d(long long* val); - extern void i_longint_unsigned_0d(unsigned long long* val); - extern void i_longint_unsigned_1d(unsigned long long* val); - extern void i_longint_unsigned_2d(unsigned long long* val); - extern void i_longint_unsigned_3d(unsigned long long* val); - extern void i_pack_struct_0d(svLogicVecVal* val); - extern void i_pack_struct_1d(svLogicVecVal* val); - extern void i_pack_struct_2d(svLogicVecVal* val); - extern void i_pack_struct_3d(svLogicVecVal* val); - extern void i_real_0d(double* val); - extern void i_real_1d(double* val); - extern void i_real_2d(double* val); - extern void i_real_3d(double* val); - extern void i_shortint_0d(short* val); - extern void i_shortint_1d(short* val); - extern void i_shortint_2d(short* val); - extern void i_shortint_3d(short* val); - extern void i_shortint_unsigned_0d(unsigned short* val); - extern void i_shortint_unsigned_1d(unsigned short* val); - extern void i_shortint_unsigned_2d(unsigned short* val); - extern void i_shortint_unsigned_3d(unsigned short* val); - extern void i_string_0d(const char** val); - extern void i_string_1d(const char** val); - extern void i_string_2d(const char** val); - extern void i_string_3d(const char** val); - extern void i_time_0d(svLogicVecVal* val); - extern void i_time_1d(svLogicVecVal* val); - extern void i_time_2d(svLogicVecVal* val); - extern void i_time_3d(svLogicVecVal* val); +// DPI IMPORTS +extern void check_exports(); +extern void* get_non_null(); +extern void i_bit121_0d(svBitVecVal* val); +extern void i_bit121_1d(svBitVecVal* val); +extern void i_bit121_2d(svBitVecVal* val); +extern void i_bit121_3d(svBitVecVal* val); +extern void i_bit1_0d(svBit* val); +extern void i_bit1_1d(svBit* val); +extern void i_bit1_2d(svBit* val); +extern void i_bit1_3d(svBit* val); +extern void i_bit7_0d(svBitVecVal* val); +extern void i_bit7_1d(svBitVecVal* val); +extern void i_bit7_2d(svBitVecVal* val); +extern void i_bit7_3d(svBitVecVal* val); +extern void i_byte_0d(char* val); +extern void i_byte_1d(char* val); +extern void i_byte_2d(char* val); +extern void i_byte_3d(char* val); +extern void i_byte_unsigned_0d(unsigned char* val); +extern void i_byte_unsigned_1d(unsigned char* val); +extern void i_byte_unsigned_2d(unsigned char* val); +extern void i_byte_unsigned_3d(unsigned char* val); +extern void i_chandle_0d(void** val); +extern void i_chandle_1d(void** val); +extern void i_chandle_2d(void** val); +extern void i_chandle_3d(void** val); +extern void i_int_0d(int* val); +extern void i_int_1d(int* val); +extern void i_int_2d(int* val); +extern void i_int_3d(int* val); +extern void i_int_unsigned_0d(unsigned int* val); +extern void i_int_unsigned_1d(unsigned int* val); +extern void i_int_unsigned_2d(unsigned int* val); +extern void i_int_unsigned_3d(unsigned int* val); +extern void i_integer_0d(svLogicVecVal* val); +extern void i_integer_1d(svLogicVecVal* val); +extern void i_integer_2d(svLogicVecVal* val); +extern void i_integer_3d(svLogicVecVal* val); +extern void i_logic121_0d(svLogicVecVal* val); +extern void i_logic121_1d(svLogicVecVal* val); +extern void i_logic121_2d(svLogicVecVal* val); +extern void i_logic121_3d(svLogicVecVal* val); +extern void i_logic1_0d(svLogic* val); +extern void i_logic1_1d(svLogic* val); +extern void i_logic1_2d(svLogic* val); +extern void i_logic1_3d(svLogic* val); +extern void i_logic7_0d(svLogicVecVal* val); +extern void i_logic7_1d(svLogicVecVal* val); +extern void i_logic7_2d(svLogicVecVal* val); +extern void i_logic7_3d(svLogicVecVal* val); +extern void i_longint_0d(long long* val); +extern void i_longint_1d(long long* val); +extern void i_longint_2d(long long* val); +extern void i_longint_3d(long long* val); +extern void i_longint_unsigned_0d(unsigned long long* val); +extern void i_longint_unsigned_1d(unsigned long long* val); +extern void i_longint_unsigned_2d(unsigned long long* val); +extern void i_longint_unsigned_3d(unsigned long long* val); +extern void i_pack_struct_0d(svLogicVecVal* val); +extern void i_pack_struct_1d(svLogicVecVal* val); +extern void i_pack_struct_2d(svLogicVecVal* val); +extern void i_pack_struct_3d(svLogicVecVal* val); +extern void i_real_0d(double* val); +extern void i_real_1d(double* val); +extern void i_real_2d(double* val); +extern void i_real_3d(double* val); +extern void i_shortint_0d(short* val); +extern void i_shortint_1d(short* val); +extern void i_shortint_2d(short* val); +extern void i_shortint_3d(short* val); +extern void i_shortint_unsigned_0d(unsigned short* val); +extern void i_shortint_unsigned_1d(unsigned short* val); +extern void i_shortint_unsigned_2d(unsigned short* val); +extern void i_shortint_unsigned_3d(unsigned short* val); +extern void i_string_0d(const char** val); +extern void i_string_1d(const char** val); +extern void i_string_2d(const char** val); +extern void i_string_3d(const char** val); +extern void i_time_0d(svLogicVecVal* val); +extern void i_time_1d(svLogicVecVal* val); +extern void i_time_2d(svLogicVecVal* val); +extern void i_time_3d(svLogicVecVal* val); #ifdef __cplusplus } diff --git a/test_regress/t/t_dpi_result_type__Dpi.out b/test_regress/t/t_dpi_result_type__Dpi.out index 344971158..0781f476d 100644 --- a/test_regress/t/t_dpi_result_type__Dpi.out +++ b/test_regress/t/t_dpi_result_type__Dpi.out @@ -15,76 +15,76 @@ extern "C" { #endif - // DPI EXPORTS - extern svBitVecVal e_array_2_state_1(); - extern svBitVecVal e_array_2_state_32(); - extern svBit e_bit(); - extern svBit e_bit_t(); - extern char e_byte(); - extern char e_byte_t(); - extern unsigned char e_byte_unsigned(); - extern unsigned char e_byte_unsigned_t(); - extern void* e_chandle(); - extern void* e_chandle_t(); - extern int e_int(); - extern int e_int_t(); - extern unsigned int e_int_unsigned(); - extern unsigned int e_int_unsigned_t(); - extern svLogic e_logic(); - extern svLogic e_logic_t(); - extern long long e_longint(); - extern long long e_longint_t(); - extern unsigned long long e_longint_unsigned(); - extern unsigned long long e_longint_unsigned_t(); - extern double e_real(); - extern double e_real_t(); - extern short e_shortint(); - extern short e_shortint_t(); - extern unsigned short e_shortint_unsigned(); - extern unsigned short e_shortint_unsigned_t(); - extern const char* e_string(); - extern const char* e_string_t(); - extern svBitVecVal e_struct_2_state_1(); - extern svBitVecVal e_struct_2_state_32(); - extern svBitVecVal e_union_2_state_1(); - extern svBitVecVal e_union_2_state_32(); - extern void e_void(); +// DPI EXPORTS +extern svBitVecVal e_array_2_state_1(); +extern svBitVecVal e_array_2_state_32(); +extern svBit e_bit(); +extern svBit e_bit_t(); +extern char e_byte(); +extern char e_byte_t(); +extern unsigned char e_byte_unsigned(); +extern unsigned char e_byte_unsigned_t(); +extern void* e_chandle(); +extern void* e_chandle_t(); +extern int e_int(); +extern int e_int_t(); +extern unsigned int e_int_unsigned(); +extern unsigned int e_int_unsigned_t(); +extern svLogic e_logic(); +extern svLogic e_logic_t(); +extern long long e_longint(); +extern long long e_longint_t(); +extern unsigned long long e_longint_unsigned(); +extern unsigned long long e_longint_unsigned_t(); +extern double e_real(); +extern double e_real_t(); +extern short e_shortint(); +extern short e_shortint_t(); +extern unsigned short e_shortint_unsigned(); +extern unsigned short e_shortint_unsigned_t(); +extern const char* e_string(); +extern const char* e_string_t(); +extern svBitVecVal e_struct_2_state_1(); +extern svBitVecVal e_struct_2_state_32(); +extern svBitVecVal e_union_2_state_1(); +extern svBitVecVal e_union_2_state_32(); +extern void e_void(); - // DPI IMPORTS - extern void check_exports(); - extern svBitVecVal i_array_2_state_1(); - extern svBitVecVal i_array_2_state_32(); - extern svBit i_bit(); - extern svBit i_bit_t(); - extern char i_byte(); - extern char i_byte_t(); - extern unsigned char i_byte_unsigned(); - extern unsigned char i_byte_unsigned_t(); - extern void* i_chandle(); - extern void* i_chandle_t(); - extern int i_int(); - extern int i_int_t(); - extern unsigned int i_int_unsigned(); - extern unsigned int i_int_unsigned_t(); - extern svLogic i_logic(); - extern svLogic i_logic_t(); - extern long long i_longint(); - extern long long i_longint_t(); - extern unsigned long long i_longint_unsigned(); - extern unsigned long long i_longint_unsigned_t(); - extern double i_real(); - extern double i_real_t(); - extern short i_shortint(); - extern short i_shortint_t(); - extern unsigned short i_shortint_unsigned(); - extern unsigned short i_shortint_unsigned_t(); - extern const char* i_string(); - extern const char* i_string_t(); - extern svBitVecVal i_struct_2_state_1(); - extern svBitVecVal i_struct_2_state_32(); - extern svBitVecVal i_union_2_state_1(); - extern svBitVecVal i_union_2_state_32(); - extern void i_void(); +// DPI IMPORTS +extern void check_exports(); +extern svBitVecVal i_array_2_state_1(); +extern svBitVecVal i_array_2_state_32(); +extern svBit i_bit(); +extern svBit i_bit_t(); +extern char i_byte(); +extern char i_byte_t(); +extern unsigned char i_byte_unsigned(); +extern unsigned char i_byte_unsigned_t(); +extern void* i_chandle(); +extern void* i_chandle_t(); +extern int i_int(); +extern int i_int_t(); +extern unsigned int i_int_unsigned(); +extern unsigned int i_int_unsigned_t(); +extern svLogic i_logic(); +extern svLogic i_logic_t(); +extern long long i_longint(); +extern long long i_longint_t(); +extern unsigned long long i_longint_unsigned(); +extern unsigned long long i_longint_unsigned_t(); +extern double i_real(); +extern double i_real_t(); +extern short i_shortint(); +extern short i_shortint_t(); +extern unsigned short i_shortint_unsigned(); +extern unsigned short i_shortint_unsigned_t(); +extern const char* i_string(); +extern const char* i_string_t(); +extern svBitVecVal i_struct_2_state_1(); +extern svBitVecVal i_struct_2_state_32(); +extern svBitVecVal i_union_2_state_1(); +extern svBitVecVal i_union_2_state_32(); +extern void i_void(); #ifdef __cplusplus } From ea8aaa21e852ffcc375e4471f67817f27e57ed96 Mon Sep 17 00:00:00 2001 From: Kevin Kiningham Date: Sat, 11 Jun 2022 14:39:05 -0700 Subject: [PATCH 61/68] Fix compile error under strict C++11 mode (#3463) --- src/V3Ast.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 47ae4dcc0..dc4cf6d8e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2021,11 +2021,12 @@ private: return Default; } - template constexpr static void checkTypeParameter() { + template constexpr static bool checkTypeParameter() { static_assert(!std::is_const::value, "Type parameter 'T_Node' should not be const qualified"); static_assert(std::is_base_of::value, "Type parameter 'T_Node' must be a subtype of AstNode"); + return true; } public: @@ -2035,25 +2036,25 @@ public: // operation function in 'foreach' should be completely predictable by branch target caches in // modern CPUs, while it is basically unpredictable for VNVisitor. template void foreach (std::function f) { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); foreachImpl(this, f); } // Same as above, but for 'const' nodes template void foreach (std::function f) const { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); foreachImpl(this, f); } // Same as 'foreach' but also follows 'this->nextp()' template void foreachAndNext(std::function f) { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); foreachImpl(this, f); } // Same as 'foreach' but also follows 'this->nextp()' template void foreachAndNext(std::function f) const { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); foreachImpl(this, f); } @@ -2062,13 +2063,13 @@ public: // present. Traversal is performed in some arbitrary order and is terminated as soon as the // result can be determined. template bool exists(std::function p) { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); return predicateImpl(this, p); } // Same as above, but for 'const' nodes template void exists(std::function p) const { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); return predicateImpl(this, p); } @@ -2077,13 +2078,13 @@ public: // present. Traversal is performed in some arbitrary order and is terminated as soon as the // result can be determined. template bool forall(std::function p) { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); return predicateImpl(this, p); } // Same as above, but for 'const' nodes template void forall(std::function p) const { - checkTypeParameter(); + static_assert(checkTypeParameter(), "Invalid type parameter 'T_Node'"); return predicateImpl(this, p); } From d721f70690052f2debe79b3308f7d23d534af5fc Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 13 Jun 2022 12:14:37 +0100 Subject: [PATCH 62/68] Commentary --- docs/guide/install.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 2c0a1134f..b69517076 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -125,6 +125,7 @@ Those developing Verilator itself may also want these (see internals.rst): :: sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov + sudo apt-get install yapf3 sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe cpan install Pod::Perldoc cpan install Parallel::Forker From 0c2c0973775c0977fb4fca2dad2a2d640e72abcf Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Mon, 13 Jun 2022 14:16:11 +0100 Subject: [PATCH 63/68] Add -fno-merge-cond-motion option This disables code motion during V3MergeCond, for debugging. --- docs/guide/exe_verilator.rst | 2 ++ src/V3MergeCond.cpp | 6 +++-- src/V3Options.cpp | 1 + src/V3Options.h | 4 ++- test_regress/t/t_merge_cond_no_motion.pl | 34 ++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_merge_cond_no_motion.pl diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index af65fe3ba..bf99a7d65 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -459,6 +459,8 @@ Summary: .. option:: -fno-merge-cond +.. option:: -fno-merge-cond-motion + .. option:: -fno-merge-const-pool .. option:: -fno-reloop diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 3881c48df..210d34ca6 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -477,10 +477,12 @@ private: AstNode* currp = m_workQueuep->front(); m_workQueuep->pop(); - // Analyse sub-tree list for code motion + // Analyse sub-tree list for code motion and conditional merging CodeMotionAnalysisVisitor::analyze(currp, stmtProperties); // Perform the code motion within the whole sub-tree list - currp = CodeMotionOptimizeVisitor::optimize(currp, stmtProperties); + if (v3Global.opt.fMergeCondMotion()) { + currp = CodeMotionOptimizeVisitor::optimize(currp, stmtProperties); + } // Merge conditionals in the whole sub-tree list (this might create new work items) iterateAndNextNull(currp); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7d4b1e846..6daff79bc 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1097,6 +1097,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-flife-post", FOnOff, &m_fLifePost); DECL_OPTION("-flocalize", FOnOff, &m_fLocalize); DECL_OPTION("-fmerge-cond", FOnOff, &m_fMergeCond); + DECL_OPTION("-fmerge-cond-motion", FOnOff, &m_fMergeCondMotion); DECL_OPTION("-fmerge-const-pool", FOnOff, &m_fMergeConstPool); DECL_OPTION("-freloop", FOnOff, &m_fReloop); DECL_OPTION("-freorder", FOnOff, &m_fReorder); diff --git a/src/V3Options.h b/src/V3Options.h index 137580c34..2c795c844 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -354,7 +354,8 @@ private: bool m_fLifePost; // main switch: -fno-life-post: delayed assignment elimination bool m_fLocalize; // main switch: -fno-localize: convert temps to local variables bool m_fMergeCond; // main switch: -fno-merge-cond: merge conditionals - bool m_fMergeConstPool = true; // main switch: --fmerge-const-pool + bool m_fMergeCondMotion = true; // main switch: -fno-merge-cond-motion: perform code motion + bool m_fMergeConstPool = true; // main switch: -fno-merge-const-pool bool m_fReloop; // main switch: -fno-reloop: reform loops bool m_fReorder; // main switch: -fno-reorder: reorder assignments in blocks bool m_fSplit; // main switch: -fno-split: always assignment splitting @@ -587,6 +588,7 @@ public: bool fLifePost() const { return m_fLifePost; } bool fLocalize() const { return m_fLocalize; } bool fMergeCond() const { return m_fMergeCond; } + bool fMergeCondMotion() const { return m_fMergeCondMotion; } bool fMergeConstPool() const { return m_fMergeConstPool; } bool fReloop() const { return m_fReloop; } bool fReorder() const { return m_fReorder; } diff --git a/test_regress/t/t_merge_cond_no_motion.pl b/test_regress/t/t_merge_cond_no_motion.pl new file mode 100755 index 000000000..113b054db --- /dev/null +++ b/test_regress/t/t_merge_cond_no_motion.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +top_filename("t/t_merge_cond.v"); + +compile( + verilator_flags2 => ["-unroll-count 64", "--stats", "-fno-merge-cond-motion"], + ); + +execute( + check_finished => 1, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i, + 10); + file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, + 580); + file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, + 64); +} + +ok(1); +1; From 47b650d821e424875d7b5ce066814ed777dc60ab Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Wed, 15 Jun 2022 07:41:59 -0400 Subject: [PATCH 64/68] Fix public unpacked input ports (#3465) --- src/V3Inline.cpp | 4 +- test_regress/t/t_pub_unpacked_port.pl | 18 +++++++++ test_regress/t/t_pub_unpacked_port.v | 55 +++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_pub_unpacked_port.pl create mode 100644 test_regress/t/t_pub_unpacked_port.v diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index c882b10c3..de62ca20d 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -311,8 +311,8 @@ private: // code will be emitted. UINFO(9, "assign to public and unpacked: " << nodep << endl); m_modp->addStmtp( - new AstAssignW(flp, new AstVarRef(flp, exprvarrefp->varp(), VAccess::WRITE), - new AstVarRef(flp, nodep, VAccess::READ))); + new AstAssignW{flp, new AstVarRef{flp, nodep, VAccess::WRITE}, + new AstVarRef{flp, exprvarrefp->varp(), VAccess::READ}}); } else if (nodep->isIfaceRef()) { m_modp->addStmtp( new AstAssignVarScope(flp, new AstVarRef(flp, nodep, VAccess::WRITE), diff --git a/test_regress/t/t_pub_unpacked_port.pl b/test_regress/t/t_pub_unpacked_port.pl new file mode 100755 index 000000000..4aa53aa05 --- /dev/null +++ b/test_regress/t/t_pub_unpacked_port.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Todd Strader. 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(); +execute(); +ok(1); +1; diff --git a/test_regress/t/t_pub_unpacked_port.v b/test_regress/t/t_pub_unpacked_port.v new file mode 100644 index 000000000..6cdcb6deb --- /dev/null +++ b/test_regress/t/t_pub_unpacked_port.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Todd Strader. +// SPDX-License-Identifier: CC0-1.0 + +module sub ( + output logic [31:0] sub_s1up_out[0:0] /* verilator public_flat_rw */, + input logic sub_clk, + input logic [31:0] sub_s1up_in[0:0] /* verilator public_flat_rw */ + ); + + // Evaluate clock edges + always @(posedge sub_clk) begin + sub_s1up_out <= sub_s1up_in; + end + +endmodule + + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + logic [31:0] s1up_in[1]; + logic [31:0] s1up_out[1]; + + sub the_sub ( + .sub_s1up_in (s1up_in), + .sub_s1up_out (s1up_out), + .sub_clk (clk)); + + always_comb s1up_in[0] = cyc; + + always @(posedge clk) begin + cyc <= cyc + 1; + + if (cyc == 10) begin + if (s1up_out[0] != 9) begin + $display("%%Error: got %0d instead of 9", s1up_out); + $stop; + end + if (the_sub.sub_s1up_in[0] != 10) begin + $display("%%Error: the_sub.sub_s1up_in was %0d instead of 10", the_sub.sub_s1up_in[0]); + $stop; + end + $display("final cycle = %0d", cyc); + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From f7533010c66489398b7721213648ca7a44939859 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Thu, 16 Jun 2022 00:11:03 +0200 Subject: [PATCH 65/68] Internals: Add `setNoopt()` function to `LifeVisitor` (#3468) --- src/V3Life.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 57ab3d0e5..814647cea 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -251,6 +251,7 @@ public: } // this->lifeDump(); } + void clear() { m_map.clear(); } // DEBUG void lifeDump() { UINFO(5, " LifeMap:" << endl); @@ -283,6 +284,10 @@ private: // METHODS VL_DEBUG_FUNC; // Declare debug() + void setNoopt() { + m_noopt = true; + m_lifep->clear(); + } // VISITORS virtual void visit(AstVarRef* nodep) override { @@ -389,7 +394,7 @@ private: const bool prev_noopt = m_noopt; { m_lifep = bodyLifep; - m_noopt = true; + setNoopt(); iterateAndNextNull(nodep->stmtsp()); m_lifep = prevLifep; m_noopt = prev_noopt; From 4f93ac64775f3a632679a42cce9cbe0862c0e042 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Jun 2022 18:49:32 -0400 Subject: [PATCH 66/68] Internals: Style modernization. No functional change intended. --- src/V3Life.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 814647cea..57ab26d63 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -218,10 +218,10 @@ public: void lifeToAbove() { // Any varrefs under a if/else branch affect statements outside and after the if/else if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level"); - for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { - AstVarScope* const nodep = it->first; + for (auto& itr : m_map) { + AstVarScope* const nodep = itr.first; m_aboveLifep->complexAssignFind(nodep); - if (it->second.everSet()) { + if (itr.second.everSet()) { // Record there may be an assignment, so we don't constant propagate across the if. complexAssignFind(nodep); } else { @@ -235,14 +235,14 @@ public: // life1p->lifeDump(); // life2p->lifeDump(); AstNode::user1ClearTree(); // user1p() used on entire tree - for (LifeMap::iterator it = life1p->m_map.begin(); it != life1p->m_map.end(); ++it) { + for (auto& itr : life1p->m_map) { // When the if branch sets a var before it's used, mark that variable - if (it->second.setBeforeUse()) it->first->user1(1); + if (itr.second.setBeforeUse()) itr.first->user1(1); } - for (LifeMap::iterator it = life2p->m_map.begin(); it != life2p->m_map.end(); ++it) { + for (auto& itr : life2p->m_map) { // When the else branch sets a var before it's used - AstVarScope* const nodep = it->first; - if (it->second.setBeforeUse() && nodep->user1()) { + AstVarScope* const nodep = itr.first; + if (itr.second.setBeforeUse() && nodep->user1()) { // Both branches set the var, we can remove the assignment before the IF. UINFO(4, "DUALBRANCH " << nodep << endl); const auto itab = m_map.find(nodep); @@ -255,11 +255,11 @@ public: // DEBUG void lifeDump() { UINFO(5, " LifeMap:" << endl); - for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { - UINFO(5, " Ent: " << (it->second.setBeforeUse() ? "[F] " : " ") << it->first + for (const auto& itr : m_map) { + UINFO(5, " Ent: " << (itr.second.setBeforeUse() ? "[F] " : " ") << itr.first << endl); - if (it->second.assignp()) { // - UINFO(5, " Ass: " << it->second.assignp() << endl); + if (itr.second.assignp()) { // + UINFO(5, " Ass: " << itr.second.assignp() << endl); } } } @@ -391,13 +391,12 @@ private: // Just don't optimize blocks with labels; they're rare - so far. LifeBlock* const prevLifep = m_lifep; LifeBlock* const bodyLifep = new LifeBlock(prevLifep, m_statep); - const bool prev_noopt = m_noopt; { + VL_RESTORER(m_noopt); m_lifep = bodyLifep; setNoopt(); iterateAndNextNull(nodep->stmtsp()); m_lifep = prevLifep; - m_noopt = prev_noopt; } UINFO(4, " joinjump" << endl); // For the next assignments, clear any variables that were read or written in the block From 1fa82ffb7bd731467c7372910b4361d7ac9f160f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Jun 2022 15:00:10 -0400 Subject: [PATCH 67/68] Commentary: Update ChangeLog --- Changes | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changes b/Changes index 4908e3d91..6d6eec1bd 100644 --- a/Changes +++ b/Changes @@ -19,17 +19,24 @@ Verilator 4.223 devel * Add -f options to replace -O options (#3436). * Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). +* Changed --no-decoration to remove output whitespace (#3460). [Kamil Rakoczy] * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] * Support concat assignment to packed array (#3446). * Improve conditional merging optimization (#3125). [Geza Lore, Shunyao CAD] * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] +* Internal prep work towards timing control. [Krzysztof Bieganski] * Fix hang with large case statement optimization (#3405). [Mike Urbach] +* Fix UNOPTFLAT warning from initial static var (#3406). [Kamil Rakoczy] +* Fix compile error when enable VL_LEAK_CHECKS (#3411). [HungMingWu] +* Fix cmake rules to support higher-level targets (#3377) (#3386). [Martin Stadler] * Fix BLKANDNBLK on $readmem/$writemem (#3379). [Alex Solomatnikov] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] * Fix passing VL_TRACE_FST_WRITER_THREAD in CMake build. [Geza Lore, Shunyao CAD] +* Fix compile error under strict C++11 mode (#3463). [Kevin Kiningham] +* Fix public unpacked input ports (#3465). [Todd Strader] Verilator 4.222 2022-05-02 From 41b9b30b9bbe0b902b4a5d85009b1ac0ab44e361 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 19 Jun 2022 15:01:17 -0400 Subject: [PATCH 68/68] Version bump --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8c06cfc0a..03a6e424d 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.223 devel], +AC_INIT([Verilator],[4.224 2022-06-19], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file