From d0c4cc393869b5570e51ead2420dcc2ce60fe1b5 Mon Sep 17 00:00:00 2001 From: Krzysztof Sychla <32716107+ksychla@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:32:18 +0200 Subject: [PATCH] Support user-defined primitives (UDPs) (#468) (#5807) (#5936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Chmiel Co-authored-by: Zhou Shen <599239118@qq.com> --- src/CMakeLists.txt | 2 + src/Makefile_obj.in | 1 + src/V3AstNodeOther.h | 37 ++- src/V3Global.h | 3 + src/V3Inst.cpp | 8 - src/V3Udp.cpp | 237 ++++++++++++++++++ src/V3Udp.h | 32 +++ src/Verilator.cpp | 3 + src/verilog.l | 21 +- src/verilog.y | 28 ++- .../t/{t_udp.py => t_nonsequential_udp.py} | 6 +- test_regress/t/t_nonsequential_udp.v | 68 +++++ test_regress/t/t_udp.out | 5 - test_regress/t/t_udp.v | 149 ----------- test_regress/t/t_udp_bad_comb_trigger.out | 6 + ..._udp_lint.py => t_udp_bad_comb_trigger.py} | 7 +- test_regress/t/t_udp_bad_comb_trigger.v | 26 ++ test_regress/t/t_udp_bad_first_input.out | 6 + test_regress/t/t_udp_bad_first_input.py | 16 ++ test_regress/t/t_udp_bad_first_input.v | 26 ++ test_regress/t/t_udp_bad_illegal_output.out | 30 +++ test_regress/t/t_udp_bad_illegal_output.py | 16 ++ test_regress/t/t_udp_bad_illegal_output.v | 43 ++++ test_regress/t/t_udp_bad_input_num.out | 6 + test_regress/t/t_udp_bad_input_num.py | 16 ++ test_regress/t/t_udp_bad_input_num.v | 26 ++ test_regress/t/t_udp_bad_multi_output.out | 6 + test_regress/t/t_udp_bad_multi_output.py | 16 ++ test_regress/t/t_udp_bad_multi_output.v | 26 ++ test_regress/t/t_udp_sequential.py | 18 ++ test_regress/t/t_udp_sequential.v | 66 +++++ test_regress/t/t_udp_sequential_bad.out | 6 + test_regress/t/t_udp_sequential_bad.py | 16 ++ test_regress/t/t_udp_sequential_bad.v | 27 ++ 34 files changed, 814 insertions(+), 191 deletions(-) create mode 100644 src/V3Udp.cpp create mode 100644 src/V3Udp.h rename test_regress/t/{t_udp.py => t_nonsequential_udp.py} (75%) create mode 100755 test_regress/t/t_nonsequential_udp.v delete mode 100644 test_regress/t/t_udp.out delete mode 100644 test_regress/t/t_udp.v create mode 100644 test_regress/t/t_udp_bad_comb_trigger.out rename test_regress/t/{t_udp_lint.py => t_udp_bad_comb_trigger.py} (74%) create mode 100755 test_regress/t/t_udp_bad_comb_trigger.v create mode 100644 test_regress/t/t_udp_bad_first_input.out create mode 100755 test_regress/t/t_udp_bad_first_input.py create mode 100755 test_regress/t/t_udp_bad_first_input.v create mode 100644 test_regress/t/t_udp_bad_illegal_output.out create mode 100755 test_regress/t/t_udp_bad_illegal_output.py create mode 100755 test_regress/t/t_udp_bad_illegal_output.v create mode 100644 test_regress/t/t_udp_bad_input_num.out create mode 100755 test_regress/t/t_udp_bad_input_num.py create mode 100755 test_regress/t/t_udp_bad_input_num.v create mode 100644 test_regress/t/t_udp_bad_multi_output.out create mode 100755 test_regress/t/t_udp_bad_multi_output.py create mode 100755 test_regress/t/t_udp_bad_multi_output.v create mode 100755 test_regress/t/t_udp_sequential.py create mode 100644 test_regress/t/t_udp_sequential.v create mode 100644 test_regress/t/t_udp_sequential_bad.out create mode 100755 test_regress/t/t_udp_sequential_bad.py create mode 100755 test_regress/t/t_udp_sequential_bad.v diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3d375e06b..7eee3a957 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,6 +178,7 @@ set(HEADERS V3Trace.h V3TraceDecl.h V3Tristate.h + V3Udp.h V3Undriven.h V3UniqueNames.h V3Unknown.h @@ -326,6 +327,7 @@ set(COMMON_SOURCES V3TraceDecl.cpp V3Tristate.cpp V3TSP.cpp + V3Udp.cpp V3Undriven.cpp V3Unknown.cpp V3Unroll.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index ad1b624cc..ca0181d9d 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -311,6 +311,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3Trace.o \ V3TraceDecl.o \ V3Tristate.o \ + V3Udp.o \ V3Undriven.o \ V3Unknown.o \ V3Unroll.o \ diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 0c3b10859..c66df472e 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1798,19 +1798,48 @@ class AstUdpTable final : public AstNode { public: AstUdpTable(FileLine* fl, AstUdpTableLine* linesp) : ASTGEN_SUPER_UdpTable(fl) { - addLinesp(linesp); + this->addLinesp(linesp); + if (!v3Global.hasTable()) v3Global.setHasTable(); } ASTGEN_MEMBERS_AstUdpTable; }; class AstUdpTableLine final : public AstNode { - string m_text; + // @astgen op1 := iFieldsp : List[AstUdpTableLineVal] // Input fields + // @astgen op2 := oFieldsp : List[AstUdpTableLineVal] // Output fields +private: + const bool m_udpIsCombo; // Combinational or sequential UDP public: - AstUdpTableLine(FileLine* fl, const string& text) + class UdpCombo {}; + AstUdpTableLine(UdpCombo, FileLine* fl, AstUdpTableLineVal* iFieldsp, + AstUdpTableLineVal* oFieldsp) : ASTGEN_SUPER_UdpTableLine(fl) - , m_text{text} {} + , m_udpIsCombo{true} { + addIFieldsp(iFieldsp); + addOFieldsp(oFieldsp); + } + class UdpSequential {}; + AstUdpTableLine(UdpSequential, FileLine* fl, AstUdpTableLineVal* iFieldsp, + AstUdpTableLineVal* oFieldsp1, AstUdpTableLineVal* oFieldsp2) + : ASTGEN_SUPER_UdpTableLine(fl) + , m_udpIsCombo{false} { + addIFieldsp(iFieldsp); + addOFieldsp(oFieldsp1); + addOFieldsp(oFieldsp2); + } ASTGEN_MEMBERS_AstUdpTableLine; + int udpIsCombo() const { return m_udpIsCombo; } +}; +class AstUdpTableLineVal final : public AstNode { + string m_text; // Value character + +public: + AstUdpTableLineVal(FileLine* fl, const string& text) + : ASTGEN_SUPER_UdpTableLineVal(fl) + , m_text{text} {} + ASTGEN_MEMBERS_AstUdpTableLineVal; string name() const override VL_MT_STABLE { return m_text; } + void name(std::string const& text) override VL_MT_STABLE { m_text = text; } string text() const VL_MT_SAFE { return m_text; } }; class AstVar final : public AstNode { diff --git a/src/V3Global.h b/src/V3Global.h index 99624a2d1..157a90eef 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -118,6 +118,7 @@ class V3Global final { bool m_hasEvents = false; // Design uses SystemVerilog named events bool m_hasClasses = false; // Design uses SystemVerilog classes bool m_hasSampled = false; // Design uses SAMPLED expresions + bool m_hasTable = false; // Desgin has the UDP Table. bool m_hasVirtIfaces = false; // Design uses virtual interfaces bool m_usesProbDist = false; // Uses $dist_* bool m_usesStdPackage = false; // Design uses the std package @@ -182,6 +183,8 @@ public: void setHasClasses() { m_hasClasses = true; } bool hasSampled() const { return m_hasSampled; } void setHasSampled() { m_hasSampled = true; } + bool hasTable() const { return m_hasTable; } + void setHasTable() { m_hasTable = true; } bool hasVirtIfaces() const { return m_hasVirtIfaces; } void setHasVirtIfaces() { m_hasVirtIfaces = true; } bool usesProbDist() const { return m_usesProbDist; } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 2002b6917..78551062c 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -109,14 +109,6 @@ class InstVisitor final : public VNVisitor { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - void visit(AstUdpTable* nodep) override { - if (!v3Global.opt.bboxUnsup()) { - // If we support primitives, update V3Undriven to remove special case - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 1995 UDP Tables. " - "Use --bbox-unsup to ignore tables."); - } - } - // Save some time void visit(AstNodeExpr*) override {} void visit(AstNodeAssign*) override {} diff --git a/src/V3Udp.cpp b/src/V3Udp.cpp new file mode 100644 index 000000000..9256a2a78 --- /dev/null +++ b/src/V3Udp.cpp @@ -0,0 +1,237 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Implementation of User defined primitives +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2025 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 +// +//************************************************************************* +// V3Udp's Transformations: +// +// For every table line create an always block containing if statements +// with condition depending on a combination of the input fields: +// +// 0 1 0 on a, b, c turns into !a&b&~c +// +//************************************************************************* + +#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT + +#include "V3Udp.h" + +#include "V3Error.h" + +#include + +VL_DEFINE_DEBUG_FUNCTIONS; + +class UdpVisitor final : public VNVisitor { + bool m_inInitial = false; // Is inside of an initial block + AstVar* m_oFieldVarp = nullptr; // Output filed var of table line + std::vector m_inputVars; // All the input vars in the AstPrimitive + std::vector m_outputVars; // All the output vars in the AstPrimitive + AstPrimitive* m_primp = nullptr; // The current primitive + bool m_isFirstOutput = false; // Whether the first IO port is output + AstVarRef* m_outputInitVerfp = nullptr; // Initial output value for sequential UDP + AstAlways* m_alwaysBlockp = nullptr; // Main Always block in UDP transform + + void visit(AstInitial* nodep) override { + VL_RESTORER(m_inInitial); + if (m_primp) m_inInitial = true; + iterateChildren(nodep); + } + void visit(AstAssign* nodep) override { + if (m_inInitial) { m_outputInitVerfp = VN_CAST(nodep->lhsp(), VarRef); } + iterateChildren(nodep); + } + void visit(AstPrimitive* nodep) override { + UASSERT_OBJ(!m_primp, nodep, "Primitives cannot nest"); + VL_RESTORER(m_primp); + VL_RESTORER(m_outputInitVerfp); + VL_RESTORER(m_isFirstOutput); + VL_RESTORER(m_inputVars); + VL_RESTORER(m_outputVars); + m_outputInitVerfp = nullptr; + m_primp = nodep; + m_isFirstOutput = false; + iterateChildren(nodep); + m_inputVars.clear(); + m_outputVars.clear(); + } + void visit(AstVar* nodep) override { + // Push the input and output vars for primitive. + if (m_primp) { + if (nodep->isIO()) { + if (nodep->isInput()) { + m_inputVars.push_back(nodep); + } else { + m_outputVars.push_back(nodep); + } + if ((m_inputVars.size() == 0) && (m_outputVars.size() == 1)) { + m_isFirstOutput = true; + } + } + } + iterateChildren(nodep); + } + void visit(AstUdpTable* nodep) override { + FileLine* const fl = nodep->fileline(); + if (m_outputVars.size() != 1) { + m_outputVars.back()->v3error( + m_outputVars.size() + << " output ports for UDP table, there must be one output port"); + } + if (!m_isFirstOutput && m_outputVars.size()) { + m_inputVars[0]->v3error("First UDP port must be the output port"); + } + m_oFieldVarp = m_outputVars[0]; + + m_alwaysBlockp = new AstAlways{fl, VAlwaysKwd::ALWAYS, nullptr, nullptr}; + fl->warnOff(V3ErrorCode::LATCH, true); + iterateChildren(nodep); + + nodep->replaceWith(m_alwaysBlockp); + } + void visit(AstUdpTableLine* nodep) override { + FileLine* const fl = nodep->fileline(); + if (!nodep->udpIsCombo() && !m_oFieldVarp->isBitLogic()) { + m_oFieldVarp->v3error("For sequential UDP, the output must be of 'reg' data type"); + } + if (nodep->udpIsCombo() && m_oFieldVarp->isBitLogic()) { + m_oFieldVarp->v3error( + "For combinational UDP, the output must not be a 'reg' data type"); + } + AstNode* iNodep = nodep->iFieldsp(); + AstNode* oNodep = nodep->oFieldsp(); + uint32_t inputvars = 0; + AstSenTree* edgetrigp = nullptr; + + AstLogAnd* logandp = new AstLogAnd{fl, new AstConst{fl, AstConst::BitTrue{}}, + new AstConst{fl, AstConst::BitTrue{}}}; + + for (AstVar* itr : m_inputVars) { + if (!iNodep) break; + inputvars++; + if (AstUdpTableLineVal* linevalp = VN_CAST(iNodep, UdpTableLineVal)) { + string valName = linevalp->name(); + AstVarRef* const referencep = new AstVarRef{fl, itr, VAccess::READ}; + if (isEdgeTrig(valName)) { + if (nodep->udpIsCombo()) { + linevalp->v3error( + "There should not be a edge trigger for combinational UDP table line"); + } + if (edgetrigp) { + linevalp->v3error("There can be only one edge tigger signal"); + } + edgetrigp = new AstSenTree{ + fl, new AstSenItem{fl, VEdgeType::ET_BOTHEDGE, + new AstVarRef{fl, itr, VAccess::READ}}}; + } + if (valName == "0" || valName == "f") + logandp = new AstLogAnd{fl, logandp, new AstLogNot{fl, referencep}}; + else if (valName == "1" || valName == "r") + logandp = new AstLogAnd{fl, logandp, referencep}; + } + iNodep = iNodep->nextp(); + } + if (inputvars != m_inputVars.size()) { + nodep->v3error("Incorrect number of input values, expected " << m_inputVars.size() + << ", got " << inputvars); + } + + string const oValName = nodep->udpIsCombo() ? oNodep->name() : oNodep->nextp()->name(); + if (oValName == "-") { + if (edgetrigp) pushDeletep(edgetrigp); + if (logandp) pushDeletep(logandp); + return; + } + + if (!nodep->udpIsCombo()) { + AstVarRef* const referencep = new AstVarRef{fl, m_oFieldVarp, VAccess::READ}; + if (oNodep->name() == "0") { + logandp = new AstLogAnd{fl, logandp, new AstLogNot{fl, referencep}}; + } else if (oNodep->name() == "1") { + logandp = new AstLogAnd{fl, logandp, referencep}; + } + } + + fl->warnOff(V3ErrorCode::LATCH, true); + AstIf* const ifp + = new AstIf{fl, logandp, + new AstAssign{fl, new AstVarRef{fl, m_oFieldVarp, VAccess::WRITE}, + new AstConst{fl, getOutputNum(nodep, oValName)}}}; + if (nodep->udpIsCombo()) { + if (!isCombOutputSig(oValName)) { + oNodep->v3error("Illegal value for combinational UDP line output"); + } + m_alwaysBlockp->addStmtsp(ifp); + return; + } + if (!isSequentOutputSig(oValName)) { + oNodep->nextp()->v3error("Illegal value for sequential UDP line output"); + } + m_alwaysBlockp->addNext(new AstAlways{fl, VAlwaysKwd::ALWAYS, edgetrigp, ifp}); + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstLogAnd* nodep) override { iterateChildren(nodep); } + void visit(AstLogNot* nodep) override { iterateChildren(nodep); } + // For logic processing. + bool isEdgeTrig(std::string& valName) { + if (valName == "*") return true; + if (valName == "01" || valName == "p" || valName == "P" || valName == "r" + || valName == "R") { + valName = "r"; + return true; + } + if (valName == "10" || valName == "n" || valName == "N" || valName == "f" + || valName == "F") { + valName = "f"; + return true; + } + if (valName.size() == 2) { + if (valName[0] == '1' || valName[1] == '0') + valName = "f"; + else if (valName[0] == '0' || valName[1] == '1') + valName = "r"; + return true; + } + if (valName[0] != '0' && valName[0] != '1') { valName = "?"; } + return false; + } + bool isCombOutputSig(const std::string& valName) { + return (valName == "0" || valName == "1" || valName == "x" || valName == "X"); + } + bool isSequentOutputSig(const std::string& valName) { + return (valName == "0" || valName == "1" || valName == "x" || valName == "X" + || valName == "-"); + } + V3Number getOutputNum(AstNode* nodep, const std::string& fieldNames) { + V3Number outputNum{nodep, 1}; + if (fieldNames == "0") { + outputNum.setBit(0, 0); + } else if (fieldNames == "1") { + outputNum.setBit(0, 1); + } else { + outputNum.setBit(0, 'x'); + } + return outputNum; + } + +public: + // CONSTRUCTORS + explicit UdpVisitor(AstNetlist* nodep) { iterate(nodep); } + ~UdpVisitor() override = default; +}; + +void V3Udp::udpResolve(AstNetlist* rootp) { + UINFO(4, __FUNCTION__ << ": " << endl); + { const UdpVisitor visitor{rootp}; } // Destruct before checking + V3Global::dumpCheckGlobalTree("udp", 0, dumpTreeEitherLevel() >= 3); +} diff --git a/src/V3Udp.h b/src/V3Udp.h new file mode 100644 index 000000000..2d607f56d --- /dev/null +++ b/src/V3Udp.h @@ -0,0 +1,32 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Implementation of User defined primitives +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2025 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 +// +//************************************************************************* + +#ifndef VERILATOR_V3UDP_H_ +#define VERILATOR_V3UDP_H_ + +#include "config_build.h" +#include "verilatedos.h" + +class AstNetlist; + +//============================================================================ + +class V3Udp final { +public: + static void udpResolve(AstNetlist* rootp) VL_MT_DISABLED; +}; + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 3e3767441..8905aacb9 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -102,6 +102,7 @@ #include "V3Trace.h" #include "V3TraceDecl.h" #include "V3Tristate.h" +#include "V3Udp.h" #include "V3Undriven.h" #include "V3Unknown.h" #include "V3Unroll.h" @@ -183,7 +184,9 @@ static void process() { // Remove any modules that were parameterized and are no longer referenced. V3Dead::deadifyModules(v3Global.rootp()); + v3Global.checkTree(); + if (v3Global.hasTable()) V3Udp::udpResolve(v3Global.rootp()); // Create a hierarchical Verilation plan if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() diff --git a/src/verilog.l b/src/verilog.l index 9aa326993..a7d60ad55 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -1009,20 +1009,23 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* Attributes */ /* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */ -{ +{ "(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } /* Doesn't match (*), but (* attr_spec */ } /************************************************************************/ /* Tables */ -\\{crnl} { yymore(); } -
{crnl} { yymore(); } -
";" { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; } -
"endtable" { yy_pop_state(); FL; return yENDTABLE; } -
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; } -
. { yymore(); } -
<> { FL; yylval.fl->v3error("EOF in 'table'"); - yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } +
[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 */ +
"endtable" { FL; yy_pop_state(); return yENDTABLE; } +
<> { FL; yylval.fl->v3error("EOF in 'table'"); + yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } { 01|10|[01][zZxX]|[zZxX][01] { FL; return yaEDGEDESC; } diff --git a/src/verilog.y b/src/verilog.y index 488040748..caed8eeb2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -450,7 +450,9 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ygenSTRENGTH "STRENGTH keyword (strong1/etc)" -%token yaTABLELINE "TABLE LINE" +%token yaTABLE_FIELD "UDP table field" +%token yaTABLE_LRSEP ":" +%token yaTABLE_LINEEND "UDP table line end" %token yaSCCTOR "`systemc_ctor block" %token yaSCDTOR "`systemc_dtor block" @@ -5785,14 +5787,26 @@ combinational_body: // IEEE: combinational_body + sequential_body yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable{$1, $2}; } ; -tableEntryList: // IEEE: { combinational_entry | sequential_entry } - tableEntry { $$ = $1; } - | tableEntryList tableEntry { $$ = addNextNull($1, $2); } +tableEntryList: // IEEE: { combinational_entry + sequential_entry } + tableLine { $$ = $1; } + | tableEntryList tableLine { $$ = addNextNull($1, $2); } ; -tableEntry: // IEEE: combinational_entry + sequential_entry - yaTABLELINE { $$ = new AstUdpTableLine{$1, *$1}; } - | error { $$ = nullptr; } +tableLine: + tableInputList yaTABLE_LRSEP tablelVal yaTABLE_LINEEND + { $$ = new AstUdpTableLine{AstUdpTableLine::UdpCombo{}, $1, $1, $3}; } + | tableInputList yaTABLE_LRSEP tablelVal yaTABLE_LRSEP tablelVal yaTABLE_LINEEND + { $$ = new AstUdpTableLine{AstUdpTableLine::UdpSequential{}, $1, $1, $3, $5}; } + ; + +tableInputList: + tablelVal { $$ = $1; } + | tableInputList tablelVal { $$ = addNextNull($1, $2); } + ; + +tablelVal: + yaTABLE_FIELD { $$ = new AstUdpTableLineVal{$1, *$1}; } + | '(' yaTABLE_FIELD yaTABLE_FIELD ')' { $$ = new AstUdpTableLineVal{$2, *$2 + *$3}; } ; //************************************************ diff --git a/test_regress/t/t_udp.py b/test_regress/t/t_nonsequential_udp.py similarity index 75% rename from test_regress/t/t_udp.py rename to test_regress/t/t_nonsequential_udp.py index 204d47313..d4f986441 100755 --- a/test_regress/t/t_udp.py +++ b/test_regress/t/t_nonsequential_udp.py @@ -10,11 +10,9 @@ import vltest_bootstrap test.scenarios('simulator') -test.top_filename = "t/t_udp.v" -test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) +test.compile() -if not test.vlt_all: - test.execute() +test.execute() test.passes() diff --git a/test_regress/t/t_nonsequential_udp.v b/test_regress/t/t_nonsequential_udp.v new file mode 100755 index 000000000..b4dba4877 --- /dev/null +++ b/test_regress/t/t_nonsequential_udp.v @@ -0,0 +1,68 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2015 by Mike Thyer. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + reg a, b, sel, z; + udp_mux2(z, a, b, sel); + + int cycle=0; + + always @(posedge clk) begin + cycle <= cycle+1; + if (cycle==0) begin + a = 0; + b = 1; + sel = 0; + end + else if (cycle==1) begin + a = 1; + b = 1; + sel = 0; + if (z != 0) $stop; + end + else if (cycle==2) begin + a = 0; + b = 1; + sel = 0; + if (z != 1) $stop; + end + else if (cycle==3) begin + a = 1; + b = 0; + sel = 0; + if (z != 0) $stop; + end + else if (cycle==4) begin + if (z != 1) $stop; + end + else if (cycle >= 5) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule + +primitive udp_mux2 (z, a, b, sel); + output z; + input a, b, sel; + table + //a b s o + ? 1 1 : 1 ; + ? 0 1 : 0 ; + 1 ? 0 : 1 ; + 0 ? 0 : 0 ; + 1 1 x : 1 ; + // Next blank line is intentional for parser + + // Next \ at EOL is intentional for parser + 0 0 x \ + : 0 ; + endtable +endprimitive diff --git a/test_regress/t/t_udp.out b/test_regress/t/t_udp.out deleted file mode 100644 index 3f274bfa6..000000000 --- a/test_regress/t/t_udp.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_udp.v:104:4: Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables. - 104 | table - | ^~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_udp.v b/test_regress/t/t_udp.v deleted file mode 100644 index c282b63a4..000000000 --- a/test_regress/t/t_udp.v +++ /dev/null @@ -1,149 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2009 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/ - // Inputs - clk - ); - input clk; - - integer cyc = 0; - reg [63:0] crc; - reg [63:0] sum; - - // Take CRC data and apply to testblock inputs - wire [31:0] in = crc[31:0]; - - /*AUTOWIRE*/ - - // Async clears must not race with clocks if we want repeatable results - reg set_l = in[20]; - reg clr_l = in[21]; - always @ (negedge clk) begin - set_l <= in[20]; - clr_l <= in[21]; - end - - //====== Mux - wire [1:0] qm; - // delay z a b sel - udp_mux2 #(0.1) m0 (qm[0], in[0], in[2], in[4]); - udp_mux2 #0.1 m1 (qm[1], in[1], in[3], in[4]); - -`define verilatorxx -`ifdef verilatorxx - reg [1:0] ql; - reg [1:0] qd; - - // No sequential tables, yet -// always @* begin -// if (!clk) ql = in[13:12]; -// end - always @(posedge clk or negedge set_l or negedge clr_l) begin - if (!set_l) qd <= ~2'b0; - else if (!clr_l) qd <= 2'b0; - else qd <= in[17:16]; - end -`else - //====== Latch -// wire [1:0] ql; -// // q clk d -// udp_latch l0 (ql[0], !in[8], in[12]); -// udp_latch l1 (ql[1], !in[8], in[13]); - - //====== DFF - wire [1:0] qd; - //always @* $display("UL q=%b c=%b d=%b", ql[1:0], in[8], in[13:12]); - // q clk d set_l clr_l - udp_dff d0 (qd[0], in[8], in[16], set_l, clr_l); - udp_dff d2 (qd[1], in[8], in[17], set_l, clr_l); -`endif - - // Aggregate outputs into a single result vector - wire [63:0] result = {52'h0, 2'b0,qd, 4'b0, 2'b0,qm}; -// wire [63:0] result = {52'h0, 2'b0,qd, 2'b0,ql, 2'b0,qm}; - - // 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 <= 64'h0; - end - else if (cyc<10) begin - sum <= 64'h0; - end - else if (cyc<90) begin - 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) - // Note not all simulators agree about the latch result. Maybe have a race? -`define EXPECTED_SUM 64'hb73acf228acaeaa3 - if (sum !== `EXPECTED_SUM) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end - end - -endmodule - -primitive udp_mux2 (z, a, b, sel); - output z; - input a, b, sel; - table - //a b s o - ? 1 1 : 1 ; - ? 0 1 : 0 ; - 1 ? 0 : 1 ; - 0 ? 0 : 0 ; - 1 1 x : 1 ; - // Next blank line is intentional for parser - - // Next \ at EOL is intentional for parser - 0 0 x \ - : 0 ; - endtable -endprimitive - -primitive udp_latch (q, clk, d); - output q; reg q; - input clk, d; - table - //clk d q q' - 0 1 : ? : 1; - 0 0 : ? : 0; - 1 ? : ? : -; - endtable -endprimitive - -primitive udp_dff (q, clk, d, set_l, clr_l); - output q; - input clk, d, set_l, clr_l; - reg q; - table - //ck d s c : q : q' - r 0 1 ? : ? : 0 ; - r 1 ? 1 : ? : 1 ; - * 1 ? 1 : 1 : 1 ; - * 0 1 ? : 0 : 0 ; - f ? ? ? : ? : - ; - b * ? ? : ? : - ; - ? ? 0 ? : ? : 1 ; - b ? * 1 : 1 : 1 ; - x 1 * 1 : 1 : 1 ; - ? ? 1 0 : ? : 0 ; - b ? 1 * : 0 : 0 ; - x 0 1 * : 0 : 0 ; - endtable -endprimitive diff --git a/test_regress/t/t_udp_bad_comb_trigger.out b/test_regress/t/t_udp_bad_comb_trigger.out new file mode 100644 index 000000000..cdd792653 --- /dev/null +++ b/test_regress/t/t_udp_bad_comb_trigger.out @@ -0,0 +1,6 @@ +%Error: t/t_udp_bad_comb_trigger.v:14:10: There should not be a edge trigger for combinational UDP table line + : ... note: In instance 'top' + 14 | (01) 1 0 : 0; + | ^ + ... 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_udp_lint.py b/test_regress/t/t_udp_bad_comb_trigger.py similarity index 74% rename from test_regress/t/t_udp_lint.py rename to test_regress/t/t_udp_bad_comb_trigger.py index c817fb894..31228c9a7 100755 --- a/test_regress/t/t_udp_lint.py +++ b/test_regress/t/t_udp_bad_comb_trigger.py @@ -9,11 +9,8 @@ import vltest_bootstrap -test.scenarios('vlt') -test.top_filename = "t/t_udp.v" +test.scenarios('linter') -test.lint( - # Unsupported: UDP Tables - verilator_flags2=["--lint-only --bbox-unsup"]) +test.lint(fails=True, expect_filename=test.golden_filename) test.passes() diff --git a/test_regress/t/t_udp_bad_comb_trigger.v b/test_regress/t/t_udp_bad_comb_trigger.v new file mode 100755 index 000000000..302ec6f79 --- /dev/null +++ b/test_regress/t/t_udp_bad_comb_trigger.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive t_gate(dout, a, b, c); +output dout; +input a, b, c; + + table + x 0 1 : 1; + 0 ? 1 : 1; + (01) 1 0 : 0; + 1 1 ? : 1; + 1 0 0 : 0; + 0 0 0 : 1; + + endtable +endprimitive + +module top (o, a, b, c); + output o; + input a, b, c; + t_gate(o, a, b, c); +endmodule diff --git a/test_regress/t/t_udp_bad_first_input.out b/test_regress/t/t_udp_bad_first_input.out new file mode 100644 index 000000000..6dec0adc5 --- /dev/null +++ b/test_regress/t/t_udp_bad_first_input.out @@ -0,0 +1,6 @@ +%Error: t/t_udp_bad_first_input.v:8:7: First UDP port must be the output port + : ... note: In instance 'top' + 8 | input a, b, c; + | ^ + ... 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_udp_bad_first_input.py b/test_regress/t/t_udp_bad_first_input.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_first_input.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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_udp_bad_first_input.v b/test_regress/t/t_udp_bad_first_input.v new file mode 100755 index 000000000..2354307fd --- /dev/null +++ b/test_regress/t/t_udp_bad_first_input.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive t_gate(a, b, c, dout); +input a, b, c; +output dout; + + table + x 0 1 : 1; + 0 ? 1 : 1; + 0 1 0 : 0; + 1 1 ? : 1; + 1 0 0 : 0; + 0 0 0 : 1; + + endtable +endprimitive + +module top (a, b, c, o); + input a, b, c; + output o; + t_gate(a, b, c, o); +endmodule diff --git a/test_regress/t/t_udp_bad_illegal_output.out b/test_regress/t/t_udp_bad_illegal_output.out new file mode 100644 index 000000000..de5221ff9 --- /dev/null +++ b/test_regress/t/t_udp_bad_illegal_output.out @@ -0,0 +1,30 @@ +%Error: t/t_udp_bad_illegal_output.v:9:8: For sequential UDP, the output must be of 'reg' data type + : ... note: In instance 'top' + 9 | output dout; + | ^~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_udp_bad_illegal_output.v:16:22: Illegal value for sequential UDP line output + : ... note: In instance 'top' + 16 | 1 1 ? : ?: *; + | ^ +%Error: t/t_udp_bad_illegal_output.v:17:11: There can be only one edge tigger signal + : ... note: In instance 'top' + 17 | f r 0 : ?: 0; + | ^ +%Error: t/t_udp_bad_illegal_output.v:18:22: Illegal value for sequential UDP line output + : ... note: In instance 'top' + 18 | 0 0 0 : ?: *; + | ^ +%Error: t/t_udp_bad_illegal_output.v:29:9: There should not be a edge trigger for combinational UDP table line + : ... note: In instance 'top' + 29 | r ? 1 : 1; + | ^ +%Error: t/t_udp_bad_illegal_output.v:31:20: Illegal value for combinational UDP line output + : ... note: In instance 'top' + 31 | 1 1 ? : *; + | ^ +%Error: t/t_udp_bad_illegal_output.v:33:20: Illegal value for combinational UDP line output + : ... note: In instance 'top' + 33 | 0 0 0 : *; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_udp_bad_illegal_output.py b/test_regress/t/t_udp_bad_illegal_output.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_illegal_output.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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_udp_bad_illegal_output.v b/test_regress/t/t_udp_bad_illegal_output.v new file mode 100755 index 000000000..02f1895f9 --- /dev/null +++ b/test_regress/t/t_udp_bad_illegal_output.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive t_gate_comb(dout, a, b, c); +input a, b, c; +output dout; + + table + r 0 1 : ?: 1; + r ? 1 : ?: 1; + r ? 0 : ?: 1; + 0 1 0 : ?: 0; + 1 1 ? : ?: *; + f r 0 : ?: 0; + 0 0 0 : ?: *; + + endtable +endprimitive + +primitive t_gate_seq(dout, a, b, c); +input a, b, c; +output dout; + + table + x 0 1 : 1; + r ? 1 : 1; + 0 1 0 : 0; + 1 1 ? : *; + 1 0 0 : 0; + 0 0 0 : *; + + endtable +endprimitive + +module top (a, b, c, o1, o2); + input a, b, c; + output o1, o2; + t_gate_comb(o1, a, b, c); + t_gate_seq(o2, a, b, c); +endmodule diff --git a/test_regress/t/t_udp_bad_input_num.out b/test_regress/t/t_udp_bad_input_num.out new file mode 100644 index 000000000..5051e1738 --- /dev/null +++ b/test_regress/t/t_udp_bad_input_num.out @@ -0,0 +1,6 @@ +%Error: t/t_udp_bad_input_num.v:14:9: Incorrect number of input values, expected 3, got 2 + : ... note: In instance 'top' + 14 | 1 0 : 0; + | ^ + ... 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_udp_bad_input_num.py b/test_regress/t/t_udp_bad_input_num.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_input_num.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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_udp_bad_input_num.v b/test_regress/t/t_udp_bad_input_num.v new file mode 100755 index 000000000..bac50a163 --- /dev/null +++ b/test_regress/t/t_udp_bad_input_num.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive t_gate(dout, a, b, c); +output dout; +input a, b, c; + + table + x 0 1 : 1; + 0 ? 1 : 1; + 1 0 : 0; + 1 1 ? : 1; + 1 0 0 : 0; + 0 0 0 : 1; + + endtable +endprimitive + +module top (a, b, c, o); + input a, b, c; + output o; + t_gate(o, a, b, c); +endmodule diff --git a/test_regress/t/t_udp_bad_multi_output.out b/test_regress/t/t_udp_bad_multi_output.out new file mode 100644 index 000000000..11dbedd10 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_output.out @@ -0,0 +1,6 @@ +%Error: t/t_udp_bad_multi_output.v:8:15: 2 output ports for UDP table, there must be one output port + : ... note: In instance 'top' + 8 | output dout1, dout2; + | ^~~~~ + ... 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_udp_bad_multi_output.py b/test_regress/t/t_udp_bad_multi_output.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_output.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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_udp_bad_multi_output.v b/test_regress/t/t_udp_bad_multi_output.v new file mode 100755 index 000000000..690c7c6d2 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_output.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive t_gate(dout1, dout2, a, b, c); +output dout1, dout2; +input a, b, c; + + table + x 0 1 : 1; + 0 ? 1 : 1; + 0 1 0 : 0; + 1 1 ? : 1; + 1 0 0 : 0; + 0 0 0 : 1; + + endtable +endprimitive + +module top (a, b, c, o1, o2); + input a, b, c; + output o1, o2; + t_gate(o1, o2, a, b, c); +endmodule diff --git a/test_regress/t/t_udp_sequential.py b/test_regress/t/t_udp_sequential.py new file mode 100755 index 000000000..d4f986441 --- /dev/null +++ b/test_regress/t/t_udp_sequential.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('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_udp_sequential.v b/test_regress/t/t_udp_sequential.v new file mode 100644 index 000000000..f8758e8e0 --- /dev/null +++ b/test_regress/t/t_udp_sequential.v @@ -0,0 +1,66 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2015 by Mike Thyer. +// SPDX-License-Identifier: CC0-1.0 + +primitive d_edge_ff (q, clock, data); + output q; reg q; + input clock, data; + initial q = 1'b1; + table + // clock data q q+ + // obtain output on rising edge of clock + F 0 : ? : 0 ; + (10) 1 : ? : 1 ; + R 0 : ? : 1 ; + (0?) 1 : ? : 0 ; + endtable +endprimitive + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + reg d, q; + d_edge_ff g (q, clk, d); + + int cycle=0; + initial d = 0; + always @(posedge clk or negedge clk) begin + cycle <= cycle+1; + if (cycle==0) begin + d = 1; + end + else if (cycle==1) begin + d = 0; + if (q != 1) $stop; + end + else if (cycle==2) begin + if (q != 1) $stop; + end + else if (cycle==3) begin + if (q != 0) $stop; + end + else if (cycle==4) begin + d = 1; + if (q != 1) $stop; + end + else if (cycle==5) begin + $display("d = %d clk = %d cycle = %d", d, clk, cycle); + if (q != 1) $stop; + end + else if (cycle==6) begin + if (q != 0) $stop; + end + else if (cycle==7) begin + if (q != 1) $stop; + end + else if (cycle >= 8) begin + if (q != 0) $stop;; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_udp_sequential_bad.out b/test_regress/t/t_udp_sequential_bad.out new file mode 100644 index 000000000..6e165004b --- /dev/null +++ b/test_regress/t/t_udp_sequential_bad.out @@ -0,0 +1,6 @@ +%Error: t/t_udp_sequential_bad.v:8:8: For combinational UDP, the output must not be a 'reg' data type + : ... note: In instance 'top' + 8 | output dout; + | ^~~~ + ... 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_udp_sequential_bad.py b/test_regress/t/t_udp_sequential_bad.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_sequential_bad.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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_udp_sequential_bad.v b/test_regress/t/t_udp_sequential_bad.v new file mode 100755 index 000000000..1e26f7e5c --- /dev/null +++ b/test_regress/t/t_udp_sequential_bad.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +primitive or_gate(dout, a, b, c); +output dout; +input a, b, c; +reg dout; + + table + x 0 1 : 1; + 0 ? 1 : 1; + 0 1 0 : 0; + 1 1 ? : 1; + 1 0 0 : 0; + 0 0 0 : 1; + + endtable +endprimitive + +module top (a, b, c, o); + input a, b, c; + output o; + or_gate(o, a, b, c); +endmodule