diff --git a/src/V3Options.cpp b/src/V3Options.cpp index b5b233f39..364280c77 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1336,6 +1336,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-debug-leak", OnOff, &m_debugLeak); DECL_OPTION("-debug-nondeterminism", OnOff, &m_debugNondeterminism); DECL_OPTION("-debug-partition", OnOff, &m_debugPartition).undocumented(); + DECL_OPTION("-debug-preproc-passthru", OnOff, &m_debugPreprocPassthru); DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented(); DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented(); DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort diff --git a/src/V3Options.h b/src/V3Options.h index 3f06a9b5d..cb7f6df96 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -240,6 +240,7 @@ private: bool m_debugLeak = true; // main switch: --debug-leak bool m_debugNondeterminism = false; // main switch: --debug-nondeterminism bool m_debugPartition = false; // main switch: --debug-partition + bool m_debugPreprocPassthru = false; // main switch: --debug-preproc-passthru bool m_debugProtect = false; // main switch: --debug-protect bool m_debugSelfTest = false; // main switch: --debug-self-test bool m_debugStackCheck = false; // main switch: --debug-stack-check @@ -512,6 +513,7 @@ public: bool debugLeak() const { return m_debugLeak; } bool debugNondeterminism() const { return m_debugNondeterminism; } bool debugPartition() const { return m_debugPartition; } + bool debugPreprocPassthru() const VL_MT_SAFE { return m_debugPreprocPassthru; } bool debugProtect() const VL_MT_SAFE { return m_debugProtect; } bool debugSelfTest() const { return m_debugSelfTest; } bool debugStackCheck() const { return m_debugStackCheck; } diff --git a/src/V3PreLex.h b/src/V3PreLex.h index 5a7cd8acf..d1fc23bc7 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -195,6 +195,7 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp VL_DO_CLEAR(yy_delete_buffer(m_bufferState), m_bufferState = nullptr); yylex_destroy(); } + VPreStream* newStream(FileLine* fl, V3PreLex* lexp); // Called by V3PreLex.l from lexer VPreStream* curStreamp() { return m_streampStack.top(); } // Can't be empty, "EOF" is on top @@ -219,6 +220,7 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp void pushStateDefValue(); void pushStateExpr(); void pushStateIncFilename(); + void pushStatePassthru(); void scanNewFile(FileLine* filelinep); void scanBytes(const string& str); void scanBytesBack(const string& str); diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 42bbf77ec..c08d70208 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -75,6 +75,7 @@ static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l) %x ENCBASE64 %x EXPR %x INCMODE +%x PASSTHRU %x PRAGMA %x PRAGMAERR %x PRAGMAPRT @@ -102,12 +103,15 @@ bom [\357\273\277] /**************************************************************/ %% + /* Passthru, to support dev-coverage of some main verilog.l rules */ +{crnl} { FL_FWDC; linenoInc(); yytext=(char*)"\n"; yyleng=1; return VP_WHITE; } +{word} { yymore(); } +. { FL_FWDC; return VP_TEXT; } + /* Special directives we recognize */ {bom} { } ^{ws}*"`line"{ws}+.*{crnl} { FL_FWDC; LEXP->lineDirective(yytext); return VP_LINE; } - - /* Special directives we recognize */ "`define" { FL_FWDC; return VP_DEFINE; } "`else" { FL_FWDC; return VP_ELSE; } "`elsif" { FL_FWDC; return VP_ELSIF; } @@ -512,9 +516,20 @@ void V3PreLex::pushStateIncFilename() { yymore(); } +void V3PreLex::pushStatePassthru() { + yy_push_state(PASSTHRU); + yymore(); +} + void V3PreLex::setYYDebug(bool on) { yy_flex_debug = static_cast(on); } +VPreStream* V3PreLex::newStream(FileLine* fl, V3PreLex* lexp) { + VPreStream* const streamp = new VPreStream{fl, lexp}; + if (v3Global.opt.debugPreprocPassthru()) streamp->m_lexp->pushStatePassthru(); + return streamp; +} + int V3PreLex::lex() { V3PreLex::s_currentLexp = this; // Tell parser where to get/put data // Remember token start location, may be updated by the lexer later @@ -640,7 +655,7 @@ string V3PreLex::endOfStream(bool& againr) { void V3PreLex::initFirstBuffer(FileLine* filelinep) { // Called from constructor to make first buffer // yy_create_buffer also sets yy_fill_buffer=1 so reads from YY_INPUT - VPreStream* const streamp = new VPreStream{filelinep, this}; + VPreStream* const streamp = newStream(filelinep, this); streamp->m_eof = true; m_streampStack.push(streamp); // @@ -656,7 +671,7 @@ void V3PreLex::scanNewFile(FileLine* filelinep) { yyerrorf("Recursive `define or other nested inclusion"); curStreamp()->m_eof = true; // Fake it to stop recursion } else { - VPreStream* const streamp = new VPreStream{filelinep, this}; + VPreStream* const streamp = newStream(filelinep, this); m_tokFilelinep = curFilelinep(); streamp->m_file = true; scanSwitchStream(streamp); @@ -675,7 +690,7 @@ void V3PreLex::scanBytes(const string& str) { yyerrorf("Recursive `define or other nested inclusion"); curStreamp()->m_eof = true; // Fake it to stop recursion } else { - VPreStream* const streamp = new VPreStream{curFilelinep(), this}; + VPreStream* const streamp = newStream(curFilelinep(), this); streamp->m_buffers.push_front(str); scanSwitchStream(streamp); } diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 920977687..0df681035 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -297,7 +297,7 @@ public: // Creation V3PreProc* V3PreProc::createPreProc(FileLine* fl) { - V3PreProcImp* preprocp = new V3PreProcImp; + V3PreProcImp* const preprocp = new V3PreProcImp; preprocp->configure(fl); return preprocp; } diff --git a/src/verilog.l b/src/verilog.l index 1173aeec1..df4d3d6ab 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -1045,14 +1045,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Tables */ -[rRfFpPnN\*] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* edge_symbol */ -
[01xX\?bB\-] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* level_symbol, next_state */ -
":" { FL; return yaTABLE_LRSEP; } /* LHS and RHS separator for table line. */ +
[rRfFpPnN\*] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* edge_symbol */ +
[01xX\?bB\-] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* level_symbol, next_state */ +
":" { FL; return yaTABLE_LRSEP; } /* LHS and RHS separator for table line. */
";" { FL; return yaTABLE_LINEEND; }
[\(\)] { FL; return yytext[0]; }
{ws}|(\\){0,1}{crnl} { FL_FWD; FL_BRK; }
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; } -
"//"[^\n]* { FL_FWD; FL_BRK; } /* throw away single line comments */ +
"//"[^\n]* { FL_FWD; FL_BRK; } /* Throw away single line comments */
"endtable" { FL; yy_pop_state(); return yENDTABLE; }
<> { FL; yylval.fl->v3error("EOF in 'table'"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } @@ -1176,14 +1176,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { "`"[a-zA-Z_0-9]+ { FL; V3ParseImp::lexErrorPreprocDirective(yylval.fl, yytext); FL_BRK; } "//"[^\n]* { FL_FWD; FL_BRK; } /* throw away single line comments */ - . { FL; return yytext[0]; } /* return single char ops. */ + . { FL; return yytext[0]; } /* return single char ops. */ } /* Catch all - absolutely last */ <*>.|\n { FL; yylval.fl->v3error( // LCOV_EXCL_LINE "Missing verilog.l rule: Default rule invoked in state " << YY_START << " '" << yytext << "'"); - FL_BRK; } + FL_BRK; } /* LCOV_EXCL_LINE */ %% // Avoid code here as cl format misindents // For implementation functions see V3ParseImp.cpp diff --git a/test_regress/t/t_dist_warn_coverage.py b/test_regress/t/t_dist_warn_coverage.py index e784f4287..f09209621 100755 --- a/test_regress/t/t_dist_warn_coverage.py +++ b/test_regress/t/t_dist_warn_coverage.py @@ -23,7 +23,6 @@ for s in [ 'Assigned pin is neither input nor output', # Instead earlier error 'Define missing argument \'', # Instead get Define passed too many arguments 'Define or directive not defined: `', # Instead V3ParseImp will warn - 'EOF in unterminated string', # Instead get normal unterminated 'Enum ranges must be integral, per spec', # Hard to hit 'Expecting define formal arguments. Found: ', # Instead define syntax error 'Syntax error parsing real: \'', # Instead can't lex the number @@ -61,13 +60,11 @@ for s in [ 'Slices of arrays in assignments have different unpacked dimensions, ', 'String of ', 'Symbol matching ', - 'Type cannot be selected from', 'Unexpected connection to arrayed port', 'Unsized numbers/parameters not allowed in streams.', 'Unsupported RHS tristate construct: ', 'Unsupported or syntax error: Unsized range in instance or other declaration', 'Unsupported pullup/down (weak driver) construct.', - 'Unsupported tristate construct (not in propagation graph): ', 'Unsupported tristate port expression: ', 'Unsupported: $bits for queue', 'Unsupported: &&& expression', @@ -81,7 +78,6 @@ for s in [ 'Unsupported: Per-bit array instantiations ', 'Unsupported: Public functions with >64 bit outputs; ', 'Unsupported: Replication to form ', - 'Unsupported: Shifting of by over 32-bit number isn\'t supported.', 'Unsupported: Size-changing cast on non-basic data type', 'Unsupported: Slice of non-constant bounds', 'Unsupported: Unclocked assertion', @@ -92,7 +88,6 @@ for s in [ 'Unsupported: \'{} .* patterns', 'Unsupported: assertion items in clocking blocks', 'Unsupported: don\'t know how to deal with ', - 'Unsupported: eventually[] (in property expression)', 'Unsupported: extern forkjoin', 'Unsupported: extern task', 'Unsupported: modport export', diff --git a/test_regress/t/t_dpi_var.vlt b/test_regress/t/t_dpi_var.vlt index 36def79c3..e3982c97e 100644 --- a/test_regress/t/t_dpi_var.vlt +++ b/test_regress/t/t_dpi_var.vlt @@ -12,3 +12,5 @@ public_flat_rw -module "sub" -var "in_a" public_flat_rw -module "sub" -var "in_b" @(posedge t.monclk) public_flat_rw -module "sub" -var "fr_a" public_flat_rw -module "sub" -var "fr_b" @(posedge t.monclk) +// Cover other edge declarations +public_flat_rw -module "sub" -var "fr_chk" @(posedge t.monclk or negedge t.monclk or edge t.monclk) diff --git a/test_regress/t/t_preproc_eof5_bad.out b/test_regress/t/t_parse_eof_attr_bad.out similarity index 75% rename from test_regress/t/t_preproc_eof5_bad.out rename to test_regress/t/t_parse_eof_attr_bad.out index 38f81c754..d7efe2955 100644 --- a/test_regress/t/t_preproc_eof5_bad.out +++ b/test_regress/t/t_parse_eof_attr_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_preproc_eof5_bad.v:7:1: EOF in (* +%Error: t/t_parse_eof_attr_bad.v:7:1: EOF in (* 7 | (* attr | ^ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_preproc_eof5_bad.py b/test_regress/t/t_parse_eof_attr_bad.py similarity index 100% rename from test_regress/t/t_preproc_eof5_bad.py rename to test_regress/t/t_parse_eof_attr_bad.py diff --git a/test_regress/t/t_preproc_eof5_bad.v b/test_regress/t/t_parse_eof_attr_bad.v similarity index 100% rename from test_regress/t/t_preproc_eof5_bad.v rename to test_regress/t/t_parse_eof_attr_bad.v diff --git a/test_regress/t/t_parse_eof_qqq_bad.out b/test_regress/t/t_parse_eof_qqq_bad.out new file mode 100644 index 000000000..0a1fd9d49 --- /dev/null +++ b/test_regress/t/t_parse_eof_qqq_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_parse_eof_qqq_bad.v:7:1: EOF in unterminated """ string + 7 | """ + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_parse_eof_qqq_bad.py b/test_regress/t/t_parse_eof_qqq_bad.py new file mode 100755 index 000000000..6256a5167 --- /dev/null +++ b/test_regress/t/t_parse_eof_qqq_bad.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(verilator_flags2=['--debug-preproc-passthru', '--no-std'], + fails=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_preproc_eof6_bad.v b/test_regress/t/t_parse_eof_qqq_bad.v similarity index 100% rename from test_regress/t/t_preproc_eof6_bad.v rename to test_regress/t/t_parse_eof_qqq_bad.v diff --git a/test_regress/t/t_parse_eof_str_bad.out b/test_regress/t/t_parse_eof_str_bad.out new file mode 100644 index 000000000..b92e51fb5 --- /dev/null +++ b/test_regress/t/t_parse_eof_str_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_parse_eof_str_bad.v:9:10: syntax error, unexpected IDENTIFIER, expecting ';' + 9 | `line 9 "t/t_parse_eof_str_bad.v" 0 + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_parse_eof_str_bad.v:11:33: Unterminated string +%Error: t/t_parse_eof_str_bad.v:11:1: EOF in unterminated string +%Error: Exiting due to diff --git a/test_regress/t/t_parse_eof_str_bad.py b/test_regress/t/t_parse_eof_str_bad.py new file mode 100755 index 000000000..6256a5167 --- /dev/null +++ b/test_regress/t/t_parse_eof_str_bad.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(verilator_flags2=['--debug-preproc-passthru', '--no-std'], + fails=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_parse_eof_str_bad.v b/test_regress/t/t_parse_eof_str_bad.v new file mode 100644 index 000000000..ea3efd4e6 --- /dev/null +++ b/test_regress/t/t_parse_eof_str_bad.v @@ -0,0 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +localparam string STR = "str diff --git a/test_regress/t/t_preproc_eof6_bad.out b/test_regress/t/t_preproc_eof_qqq_bad.out similarity index 63% rename from test_regress/t/t_preproc_eof6_bad.out rename to test_regress/t/t_preproc_eof_qqq_bad.out index 7fb5a8998..d2ff73582 100644 --- a/test_regress/t/t_preproc_eof6_bad.out +++ b/test_regress/t/t_preproc_eof_qqq_bad.out @@ -1,3 +1,3 @@ -%Error: t/t_preproc_eof6_bad.v:10:1: EOF in unterminated """ string +%Error: t/t_preproc_eof_qqq_bad.v:10:1: EOF in unterminated """ string ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to diff --git a/test_regress/t/t_preproc_eof6_bad.py b/test_regress/t/t_preproc_eof_qqq_bad.py similarity index 100% rename from test_regress/t/t_preproc_eof6_bad.py rename to test_regress/t/t_preproc_eof_qqq_bad.py diff --git a/test_regress/t/t_preproc_eof_qqq_bad.v b/test_regress/t/t_preproc_eof_qqq_bad.v new file mode 100644 index 000000000..6f936b832 --- /dev/null +++ b/test_regress/t/t_preproc_eof_qqq_bad.v @@ -0,0 +1,7 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +"""str diff --git a/test_regress/t/t_uvm_todo.py b/test_regress/t/t_uvm_todo.py index d9cd9c872..0e7114cd7 100755 --- a/test_regress/t/t_uvm_todo.py +++ b/test_regress/t/t_uvm_todo.py @@ -11,6 +11,9 @@ import vltest_bootstrap test.scenarios('vlt') +if test.have_dev_gcov: + test.skip("Test suite intended for full dev coverage without needing this test") + test.compile(v_flags2=["--timing", "+incdir+t/uvm", "t/t_uvm_todo.vlt", "-j 0"], make_flags=['-k'], verilator_make_gmake=False) diff --git a/test_regress/t/t_vlt_legacy.py b/test_regress/t/t_vlt_legacy.py new file mode 100755 index 000000000..7437ff992 --- /dev/null +++ b/test_regress/t/t_vlt_legacy.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(verilator_flags2=[test.t_dir + "/" + test.name + ".vlt"]) + +test.passes() diff --git a/test_regress/t/t_vlt_legacy.v b/test_regress/t/t_vlt_legacy.v new file mode 100644 index 000000000..a547e7fb4 --- /dev/null +++ b/test_regress/t/t_vlt_legacy.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t ( + input clk /*verilator clock_enable*/ +); + initial $finish; +endmodule diff --git a/test_regress/t/t_vlt_legacy.vlt b/test_regress/t/t_vlt_legacy.vlt new file mode 100644 index 000000000..7bd9adc07 --- /dev/null +++ b/test_regress/t/t_vlt_legacy.vlt @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +clock_enable --module "t" --var "clk" +clocker --module "t" --var "clk" +no_clocker --module "t" --var "clk"