From 11b5dae88d735cacc23cbec5f7305267973f3c62 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 7 Sep 2023 21:45:51 -0400 Subject: [PATCH] Support let --- Changes | 1 + src/V3AstNodeOther.h | 14 +++++ src/V3LinkDot.cpp | 2 +- src/V3LinkResolve.cpp | 52 ++++++++++++++++++- src/verilog.y | 49 +++++++++++------ test_regress/t/t_let.out | 41 --------------- test_regress/t/t_let.pl | 8 ++- test_regress/t/t_let.v | 11 ++-- test_regress/t/t_let_arg_bad.out | 19 +++++++ .../t/{t_let_bad.pl => t_let_arg_bad.pl} | 0 test_regress/t/t_let_arg_bad.v | 22 ++++++++ test_regress/t/t_let_bad.out | 11 ---- test_regress/t/t_let_recurse_bad.out | 4 ++ test_regress/t/t_let_recurse_bad.pl | 19 +++++++ .../t/{t_let_bad.v => t_let_recurse_bad.v} | 7 +-- test_regress/t/t_let_side.pl | 21 ++++++++ test_regress/t/t_let_side.v | 29 +++++++++++ test_regress/t/t_let_unsup.out | 8 +++ test_regress/t/t_let_unsup.pl | 19 +++++++ test_regress/t/t_let_unsup.v | 21 ++++++++ 20 files changed, 275 insertions(+), 83 deletions(-) delete mode 100644 test_regress/t/t_let.out create mode 100644 test_regress/t/t_let_arg_bad.out rename test_regress/t/{t_let_bad.pl => t_let_arg_bad.pl} (100%) create mode 100644 test_regress/t/t_let_arg_bad.v delete mode 100644 test_regress/t/t_let_bad.out create mode 100644 test_regress/t/t_let_recurse_bad.out create mode 100755 test_regress/t/t_let_recurse_bad.pl rename test_regress/t/{t_let_bad.v => t_let_recurse_bad.v} (65%) create mode 100755 test_regress/t/t_let_side.pl create mode 100644 test_regress/t/t_let_side.v create mode 100644 test_regress/t/t_let_unsup.out create mode 100755 test_regress/t/t_let_unsup.pl create mode 100644 test_regress/t/t_let_unsup.v diff --git a/Changes b/Changes index f70355566..7106cfbb9 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 5.015 devel * Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] * Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd] * Support no-parentheses calls to static methods (#4432). [Krzysztof BoroĊ„ski] +* Support 'let'. * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. * Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] * Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 7e7199427..e3535c806 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2093,6 +2093,20 @@ public: ASTGEN_MEMBERS_AstFunc; bool hasDType() const override { return true; } }; +class AstLet final : public AstNodeFTask { + // Verilog "let" statement + // Parents: MODULE + // stmtp is always a StmtExpr as Let always returns AstNodeExpr +public: + AstLet(FileLine* fl, const string& name) + : ASTGEN_SUPER_Let(fl, name, nullptr) {} + ASTGEN_MEMBERS_AstLet; + bool hasDType() const override { return true; } + const char* broken() const override { + BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr)); + return nullptr; + } +}; class AstProperty final : public AstNodeFTask { // A property inside a module public: diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index afec76e4d..f376457f0 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1121,9 +1121,9 @@ class LinkDotFindVisitor final : public VNVisitor { m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/); } + VL_RESTORER(m_ftaskp); m_ftaskp = nodep; iterateChildren(nodep); - m_ftaskp = nullptr; } } void visit(AstClocking* nodep) override { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 5ea9726c3..187d84028 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -32,6 +32,7 @@ #include "V3Ast.h" #include "V3Global.h" #include "V3String.h" +#include "V3Task.h" #include #include @@ -45,7 +46,8 @@ class LinkResolveVisitor final : public VNVisitor { private: // NODE STATE // Entire netlist: - // AstCaseItem::user2() // bool Moved default caseitems + // AstCaseItem::user2() // bool Moved default caseitems + // AstNodeFTaskRef::user2() // bool Processing - to check for recursion const VNUser2InUse m_inuser2; // STATE @@ -113,6 +115,7 @@ private: } void visit(AstNodeFTask* nodep) override { + // Note AstLet is handled specifically elsewhere // NodeTask: Remember its name for later resolution if (m_underGenerate) nodep->underGenerate(true); // Remember the existing symbol table scope @@ -140,6 +143,47 @@ private: } void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); + if (AstLet* letp = VN_CAST(nodep->taskp(), Let)) { + UINFO(7, "letSubstitute() " << nodep << " <- " << letp << endl); + if (letp->user2()) { + nodep->v3error("Recursive let substitution " << letp->prettyNameQ()); + nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + letp->user2(true); + // letp->dumpTree("-let-let "); + // nodep->dumpTree("-let-ref "); + AstStmtExpr* const letStmtp = VN_AS(letp->stmtsp(), StmtExpr); + AstNodeExpr* const newp = letStmtp->exprp()->cloneTree(false); + const V3TaskConnects tconnects = V3Task::taskConnects(nodep, letp->stmtsp()); + std::map portToExprs; + for (const auto& tconnect : tconnects) { + const AstVar* const portp = tconnect.first; + const AstArg* const argp = tconnect.second; + AstNodeExpr* const pinp = argp->exprp(); + if (!pinp) continue; // Argument error we'll find later + portToExprs.emplace(portp, pinp); + } + // Replace VarRefs of arguments with the argument values + newp->foreach([&](AstVarRef* refp) { // + const auto it = portToExprs.find(refp->varp()); + if (it != portToExprs.end()) { + AstNodeExpr* const pinp = it->second; + UINFO(9, "let pin subst " << refp << " <- " << pinp << endl); + // Side effects are copied into pins, to match other simulators + refp->replaceWith(pinp->cloneTree(false)); + VL_DO_DANGLING(pushDeletep(refp), refp); + } + }); + // newp->dumpTree("-let-new "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + // Iterate to expand further now, so we can look for recursions + visit(newp); + letp->user2(false); + return; + } if (nodep->taskp() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) { nodep->scopeNamep(new AstScopeName{nodep->fileline(), false}); } @@ -170,6 +214,12 @@ private: } } + void visit(AstLet* nodep) override { + // Lets have been (or about to be) substituted, we can remove + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::HIER_BLOCK) { UASSERT_OBJ(m_modp, nodep, "HIER_BLOCK not under a module"); diff --git a/src/verilog.y b/src/verilog.y index 4e31cb1b0..507c3020d 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5176,29 +5176,31 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation //************************************************ // Let -letId: // IEEE: pert of let_declaration +letId: // IEEE: pert of let_declaration idAny/*let_identifieer*/ { $$ = $1; $$ = nullptr; - // No unsupported message as caller has one, for now just use a func - $$ = new AstFunc{$$, *$1, nullptr, nullptr}; + $$ = new AstLet{$$, *$1}; SYMP->pushNewUnderNodeOrCurrent($$, $$); } ; -let_declaration: // IEEE: let_declaration +let_declaration: // IEEE: let_declaration yLET letId '=' expr ';' - { $$ = nullptr; - SYMP->popScope($2); - BBUNSUP($1, "Unsupported: let"); } + { $$ = $2; + $$->addStmtsp(new AstStmtExpr{$1, $4}); + SYMP->popScope($2); } | yLET letId '(' let_port_listE ')' '=' expr ';' - { $$ = nullptr; - SYMP->popScope($2); - BBUNSUP($1, "Unsupported: let"); } + { $$ = $2; + $$->addStmtsp(new AstStmtExpr{$1, $7}); + $$->addStmtsp($4); + SYMP->popScope($2); } ; let_port_listE: // IEEE: [ let_port_list ] /*empty*/ { $$ = nullptr; } - | let_port_list { $$ = $1; } + | /*emptyStart*/ + /*mid*/ { VARRESET_LIST(UNKNOWN); VARIO(INOUT); } + /*cont*/ let_port_list { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; let_port_list: // IEEE: let_port_list @@ -5206,14 +5208,31 @@ let_port_list: // IEEE: let_port_list | let_port_list ',' let_port_item { $$ = addNextNull($1, $3); } ; -let_port_item: // IEEE: let_port_Item +let_port_item: // IEEE: let_port_Item // // IEEE: Expanded let_formal_type yUNTYPED idAny/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let untyped ports"); } + { $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } | data_type id/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + { BBUNSUP($1, "Unsupported: let typed ports"); + $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } | implicit_typeE id/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + { if ($1) BBUNSUP($1, "Unsupported: let typed ports"); + $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } ; //************************************************ diff --git a/test_regress/t/t_let.out b/test_regress/t/t_let.out deleted file mode 100644 index aca0f5993..000000000 --- a/test_regress/t/t_let.out +++ /dev/null @@ -1,41 +0,0 @@ -%Error-UNSUPPORTED: t/t_let.v:8:4: Unsupported: let - 8 | let P = 11; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_let.v:13:4: Unsupported: let - 13 | let A = 10; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:14:4: Unsupported: let - 14 | let B() = 20; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:13:14: Unsupported: let ports - 13 | let A = 10; - | ^ -%Error-UNSUPPORTED: t/t_let.v:15:4: Unsupported: let - 15 | let C(a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:15:13: Unsupported: let ports - 15 | let C(a) = 30 + a; - | ^ -%Error-UNSUPPORTED: t/t_let.v:16:4: Unsupported: let - 16 | let D(a, b) = 30 + a + b; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:16:16: Unsupported: let ports - 16 | let D(a, b) = 30 + a + b; - | ^ -%Error-UNSUPPORTED: t/t_let.v:17:4: Unsupported: let - 17 | let E(a, b=7) = 30 + a + b; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:18:10: Unsupported: let untyped ports - 18 | let F(untyped a) = 30 + a; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_let.v:18:4: Unsupported: let - 18 | let F(untyped a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:19:10: Unsupported: let ports - 19 | let G(int a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:19:4: Unsupported: let - 19 | let G(int a) = 30 + a; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_let.pl b/test_regress/t/t_let.pl index c18ffc8f0..97d8dcc12 100755 --- a/test_regress/t/t_let.pl +++ b/test_regress/t/t_let.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - expect_filename => $Self->{golden_filename}, - fails => 1, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_let.v b/test_regress/t/t_let.v index b8d010fb3..3eb6a403c 100644 --- a/test_regress/t/t_let.v +++ b/test_regress/t/t_let.v @@ -6,6 +6,7 @@ package Pkg; let P = 11; + let PP(a) = 30 + a; endpackage module t(/*AUTOARG*/); @@ -14,9 +15,8 @@ module t(/*AUTOARG*/); let B() = 20; let C(a) = 30 + a; let D(a, b) = 30 + a + b; - let E(a, b=7) = 30 + a + b; + let E(a=1, b=7) = 30 + a + b; let F(untyped a) = 30 + a; - let G(int a) = 30 + a; initial begin if (A != 10) $stop; @@ -24,11 +24,14 @@ module t(/*AUTOARG*/); if (B != 20) $stop; if (B() != 20) $stop; if (C(1) != (30 + 1)) $stop; + if (C(.a(1)) != (30 + 1)) $stop; if (D(1, 2) != (30 + 1 + 2)) $stop; - if (E(1) != (30 + 1 + 7)) $stop; + if (D(.a(1), .b(2)) != (30 + 1 + 2)) $stop; + if (E(2) != (30 + 2 + 7)) $stop; + if (E(.b(1)) != (30 + 1 + 1)) $stop; if (F(1) != (30 + 1)) $stop; - if (G(1) != (30 + 1)) $stop; if (Pkg::P != 11) $stop; + if (Pkg::PP(6) != (30 + 6)) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_let_arg_bad.out b/test_regress/t/t_let_arg_bad.out new file mode 100644 index 000000000..f1d6d297e --- /dev/null +++ b/test_regress/t/t_let_arg_bad.out @@ -0,0 +1,19 @@ +%Error: t/t_let_arg_bad.v:13:18: Too many arguments in function call to LET 'NO_ARG' + 13 | if (NO_ARG(10) != 10) $stop; + | ^~ +%Error: t/t_let_arg_bad.v:14:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 14 | if (ONE_ARG != 10) $stop; + | ^~~~~~~ +%Error: t/t_let_arg_bad.v:15:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 15 | if (ONE_ARG() != 10) $stop; + | ^~~~~~~ +%Error: t/t_let_arg_bad.v:16:23: Too many arguments in function call to LET 'ONE_ARG' + 16 | if (ONE_ARG(10, 20) != 10) $stop; + | ^~ +%Error: t/t_let_arg_bad.v:17:20: No such argument 'b' in function call to LET 'ONE_ARG' + 17 | if (ONE_ARG(.b(1)) != 10) $stop; + | ^ +%Error: t/t_let_arg_bad.v:17:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 17 | if (ONE_ARG(.b(1)) != 10) $stop; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_bad.pl b/test_regress/t/t_let_arg_bad.pl similarity index 100% rename from test_regress/t/t_let_bad.pl rename to test_regress/t/t_let_arg_bad.pl diff --git a/test_regress/t/t_let_arg_bad.v b/test_regress/t/t_let_arg_bad.v new file mode 100644 index 000000000..6b8781e5d --- /dev/null +++ b/test_regress/t/t_let_arg_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + let NO_ARG = 10; + let ONE_ARG(a) = 10; + + initial begin + if (NO_ARG(10) != 10) $stop; // BAD extra arg + if (ONE_ARG != 10) $stop; // BAD need arg + if (ONE_ARG() != 10) $stop; // BAD need arg + if (ONE_ARG(10, 20) != 10) $stop; // BAD extra arg + if (ONE_ARG(.b(1)) != 10) $stop; // BAD wrong arg name + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_let_bad.out b/test_regress/t/t_let_bad.out deleted file mode 100644 index ce76ac770..000000000 --- a/test_regress/t/t_let_bad.out +++ /dev/null @@ -1,11 +0,0 @@ -%Error-UNSUPPORTED: t/t_let_bad.v:9:4: Unsupported: let - 9 | let NO_ARG = 10; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_let_bad.v:9:19: Unsupported: let ports - 9 | let NO_ARG = 10; - | ^ -%Error-UNSUPPORTED: t/t_let_bad.v:10:4: Unsupported: let - 10 | let ONE_ARG(a) = 10; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_let_recurse_bad.out b/test_regress/t/t_let_recurse_bad.out new file mode 100644 index 000000000..dfa9fc32b --- /dev/null +++ b/test_regress/t/t_let_recurse_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_let_recurse_bad.v:9:36: Recursive let substitution 'RECURSE' + 9 | let RECURSE(a) = (a == 1) ? 1 : RECURSE(a - 1); + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_recurse_bad.pl b/test_regress/t/t_let_recurse_bad.pl new file mode 100755 index 000000000..882bc2418 --- /dev/null +++ b/test_regress/t/t_let_recurse_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_bad.v b/test_regress/t/t_let_recurse_bad.v similarity index 65% rename from test_regress/t/t_let_bad.v rename to test_regress/t/t_let_recurse_bad.v index 816b46651..47603c7db 100644 --- a/test_regress/t/t_let_bad.v +++ b/test_regress/t/t_let_recurse_bad.v @@ -6,13 +6,10 @@ module t(/*AUTOARG*/); - let NO_ARG = 10; - let ONE_ARG(a) = 10; + let RECURSE(a) = (a == 1) ? 1 : RECURSE(a - 1); // BAD no recursion per IEEE 1800-2017 11.12 initial begin - if (NO_ARG(10) != 10) $stop; // BAD - if (ONE_ARG() != 10) $stop; // BAD - if (ONE_ARG(10, 20) != 10) $stop; // BAD + if (RECURSE(1) != 1) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_let_side.pl b/test_regress/t/t_let_side.pl new file mode 100755 index 000000000..97d8dcc12 --- /dev/null +++ b/test_regress/t/t_let_side.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 2023 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( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_side.v b/test_regress/t/t_let_side.v new file mode 100644 index 000000000..0200da525 --- /dev/null +++ b/test_regress/t/t_let_side.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + let F(a) = {a, a, a}; + + function byte g(); + static byte r = 0; + return ++r; + endfunction + + bit [23:0] res; + + initial begin + res = F(g()); + $display("%h", res); + // Commercial1 010101 -- seems wrong by my reading of IEEE but anyhow + // Commercial2/Vlt 010203 + // Commercial3/4 030201 + if (res != 24'h010101 && res != 24'h010203 && res != 24'h030201) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_let_unsup.out b/test_regress/t/t_let_unsup.out new file mode 100644 index 000000000..66e9536c0 --- /dev/null +++ b/test_regress/t/t_let_unsup.out @@ -0,0 +1,8 @@ +%Error-UNSUPPORTED: t/t_let_unsup.v:10:10: Unsupported: let typed ports + 10 | let G(int a) = 30 + a; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_let_unsup.v:11:10: Unsupported: let typed ports + 11 | let H(signed a) = 30 + a; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_unsup.pl b/test_regress/t/t_let_unsup.pl new file mode 100755 index 000000000..882bc2418 --- /dev/null +++ b/test_regress/t/t_let_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_unsup.v b/test_regress/t/t_let_unsup.v new file mode 100644 index 000000000..2a5859cdc --- /dev/null +++ b/test_regress/t/t_let_unsup.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + let F(untyped a) = 30 + a; + let G(int a) = 30 + a; + let H(signed a) = 30 + a; + + initial begin + if (F(1) != (30 + 1)) $stop; + if (G(1) != (30 + 1)) $stop; + if (H(1) != (30 + 1)) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule