diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9b43d17a..f51224e63 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -177,6 +177,7 @@ set(HEADERS V3Trace.h V3TraceDecl.h V3Tristate.h + V3Udp.h V3Undriven.h V3UniqueNames.h V3Unknown.h @@ -324,6 +325,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 291bb88c9..d8ebfe872 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -310,6 +310,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3Trace.o \ V3TraceDecl.o \ V3Tristate.o \ + V3Udp.o \ V3Undriven.o \ V3Unknown.o \ V3Unroll.o \ diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index dc0220797..589ab2e04 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -444,6 +444,7 @@ public: bool isBitLogic() const { return keyword().isBitLogic(); } bool isDouble() const VL_MT_STABLE { return keyword().isDouble(); } bool isEvent() const VL_MT_STABLE { return keyword() == VBasicDTypeKwd::EVENT; } + bool isLogic() const VL_MT_STABLE { return keyword() == VBasicDTypeKwd::LOGIC; } bool isTriggerVec() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::TRIGGERVEC; } bool isForkSync() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::FORK_SYNC; } bool isProcessRef() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::PROCESS_REFERENCE; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index da584d4ef..c1b96b456 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1784,13 +1784,24 @@ public: ASTGEN_MEMBERS_AstUdpTable; }; class AstUdpTableLine final : public AstNode { + // @astgen op1 := ifieldp : List[AstUdpTableLineVal] + // @astgen op2 := ofieldp : List[AstUdpTableLineVal] +public: + AstUdpTableLine(FileLine* fl, AstUdpTableLineVal* ifieldp, AstUdpTableLineVal* ofieldp) + : ASTGEN_SUPER_UdpTableLine(fl) { + this->addIfieldp(ifieldp); + this->addOfieldp(ofieldp); + } + ASTGEN_MEMBERS_AstUdpTableLine; +}; +class AstUdpTableLineVal final : public AstNode { string m_text; public: - AstUdpTableLine(FileLine* fl, const string& text) - : ASTGEN_SUPER_UdpTableLine(fl) + AstUdpTableLineVal(FileLine* fl, const string& text) + : ASTGEN_SUPER_UdpTableLineVal(fl) , m_text{text} {} - ASTGEN_MEMBERS_AstUdpTableLine; + ASTGEN_MEMBERS_AstUdpTableLineVal; string name() const override VL_MT_STABLE { return m_text; } string text() const VL_MT_SAFE { return m_text; } }; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 0d69913aa..531412a7f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -112,8 +112,8 @@ class InstVisitor final : public VNVisitor { 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."); + //nodep->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 1995 UDP Tables. " + // "Use --bbox-unsup to ignore tables."); } } diff --git a/src/V3Udp.cpp b/src/V3Udp.cpp new file mode 100644 index 000000000..01e13c5b6 --- /dev/null +++ b/src/V3Udp.cpp @@ -0,0 +1,204 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Implementation of Christofides algorithm to +// approximate the solution to the traveling salesman problem. +// +// ISSUES: This isn't exactly Christofides algorithm; see the TODO +// in perfectMatching(). True minimum-weight perfect matching +// would produce a better result. How much better is TBD. +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT + +#include "V3Udp.h" + +#include + +VL_DEFINE_DEBUG_FUNCTIONS; + +//V3Udp add the support for UDP table. +// For example: +// table +// x 0 1 : 1; +// 0 ? 1 : 1; +// 0 1 0 : 0; +// endtable +// For every table line, for the input field, +// two number (mask number and compare number) will +// be generated to help make a judegement whether +// the input field condition is satisfied. For example, +// for line x 0 1 : 1, mask = 011 cmp = 001, the condition +// is mask & inputvar == cmp. This passed should be added +// before V3Inline and V3Tristate. + +class UdpVisitor final : public VNVisitor { + AstVar* m_ifieldVarp = nullptr; // input field var of table line. + 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; + AstIf* m_lineStmtp = nullptr; // stmt for every line in UDP Table. + AstAlways* m_alwaysp = nullptr; // UPD Table is realized under the always_latch. + bool m_isFirstOutput = false; // Whether the first IO port is output. + int m_inputNum = 0; + int m_outputNum = 0; + + void visit(AstPrimitive* nodep) override { + m_primp = nodep; + m_isFirstOutput = false; + m_inputVars.clear(); + m_outputVars.clear(); + iterateChildren(nodep); + m_primp = nullptr; + } + 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 { + auto fl = nodep->fileline(); + m_lineStmtp = nullptr; + m_inputNum = m_inputVars.size(); + m_outputNum = m_outputVars.size(); + if (m_outputNum != 1) { + m_outputVars.back()->v3error( + m_outputNum << " output ports for udp table, there must be one output port!"); + } + if (!m_isFirstOutput && m_outputNum) { + m_inputVars[0]->v3error("The first port must be the output port!"); + } + m_ofieldVarp = m_outputVars[0]; + AstBasicDType* const bdtypep = VN_CAST(m_ofieldVarp->childDTypep(), BasicDType); + if (bdtypep && bdtypep->isLogic()) { // If output is reg. + bdtypep->v3error("sequetial UDP is not suppoted currently!"); + } + // Input var for the ifield, + // add the input filed var and corresponding varref. + AstNodeDType* const typep = nodep->findBitDType(m_inputNum, m_inputNum, VSigning::NOSIGN); + m_ifieldVarp = new AstVar{fl, VVarType::MODULETEMP, "tableline__ifield__udptmp", typep}; + m_inputVars.back()->addNextHere(m_ifieldVarp); + AstVarRef* const ifieldRefp = new AstVarRef{fl, m_ifieldVarp, VAccess::WRITE}; + auto itr = m_inputVars.begin(); + // relate the input vars with the input field var by concat + AstNodeExpr* contactp = new AstVarRef{fl, *itr, VAccess::READ}; + while (++itr != m_inputVars.end()) { + contactp = new AstConcat{fl, new AstVarRef{fl, *itr, VAccess::READ}, contactp}; + } + AstNodeStmt* const ifieldStmtp = new AstAssignW{fl, ifieldRefp, contactp}; + // Use the always_latch to realize the UDP table. + m_alwaysp = new AstAlways{fl, VAlwaysKwd::ALWAYS, nullptr, nullptr}; + ifieldStmtp->addNextHere(m_alwaysp); + // Output var for the ofield + iterateChildren(nodep); + nodep->replaceWith(ifieldStmtp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + void visit(AstUdpTableLine* nodep) override { + auto fl = nodep->fileline(); + AstNode* inodep = nodep->ifieldp(); + AstNode* onodep = nodep->ofieldp(); + std::vector ifieldNodes; + std::vector ofieldNodes; + while (inodep) { + if (AstUdpTableLineVal* linevalp = VN_CAST(inodep, UdpTableLineVal)) { + ifieldNodes.push_back(linevalp); + } + inodep = inodep->nextp(); + } + if (ifieldNodes.size() != m_inputNum) { + nodep->v3error(m_inputNum << " input val required, while there are " + << ifieldNodes.size() << " input for the table line!"); + } + while (onodep) { + if (AstUdpTableLineVal* linevalp = VN_CAST(onodep, UdpTableLineVal)) { + ofieldNodes.push_back(linevalp); + } + onodep = onodep->nextp(); + } + // Build the ifield condition + // For one table line, the match condition is + // ifieldRefp & maskNum == cmpNum + // For example: 0?1:1 + // maskNum is : 101 + // cmpNum is : 001 + V3Number maskNum{nodep, m_inputNum}; + V3Number cmpNum{nodep, m_inputNum}; + int bitIndex = 0; + for (auto ivalp : ifieldNodes) { + std::string bitval = ivalp->name().substr(0, 1); + if (bitval == "0") { + maskNum.setBit(bitIndex, 1); + cmpNum.setBit(bitIndex, 0); + } else if (bitval == "1") { + maskNum.setBit(bitIndex, 1); + cmpNum.setBit(bitIndex, 1); + } else { + maskNum.setBit(bitIndex, 0); + cmpNum.setBit(bitIndex, 0); + } + bitIndex++; + } + AstConst* const maskConstp = new AstConst{fl, maskNum}; + AstConst* const cmpConstp = new AstConst{fl, cmpNum}; + AstNodeExpr* const condExprp = new AstEq{ + fl, new AstAnd{fl, maskConstp, new AstVarRef{fl, m_ifieldVarp, VAccess::READ}}, + cmpConstp}; + //Build the ofield val + V3Number onum{nodep, 1}; + auto ovalp = ofieldNodes[0]; + std::string bitval = ovalp->name().substr(0, 1); + if (bitval == "0") { + onum.setBit(0, 0); + } else if (bitval == "1") { + onum.setBit(0, 1); + } else { + onum.setBit(0, 'x'); + } + //Build the whole field line stmt. + AstAssign* const thenStmtp = new AstAssign{ + fl, new AstVarRef{fl, m_ofieldVarp, VAccess::WRITE}, new AstConst{fl, onum}}; + AstIf* const ifStmtp = new AstIf{fl, condExprp, thenStmtp}; + if (!m_lineStmtp) { + m_lineStmtp = ifStmtp; + m_alwaysp->addStmtsp(m_lineStmtp); + } else { + m_lineStmtp->addElsesp(ifStmtp); + m_lineStmtp = ifStmtp; + } + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } + +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("udpResolve", 0, dumpTreeEitherLevel() >= 3); +} diff --git a/src/V3Udp.h b/src/V3Udp.h new file mode 100644 index 000000000..dd1d19432 --- /dev/null +++ b/src/V3Udp.h @@ -0,0 +1,32 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Replace return/continue with jumps +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#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 1cfce8c30..526f6d0a1 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -101,6 +101,7 @@ #include "V3Trace.h" #include "V3TraceDecl.h" #include "V3Tristate.h" +#include "V3Udp.h" #include "V3Undriven.h" #include "V3Unknown.h" #include "V3Unroll.h" @@ -184,6 +185,8 @@ static void process() { V3Dead::deadifyModules(v3Global.rootp()); v3Global.checkTree(); + V3Udp::udpResolve(v3Global.rootp()); + // Create a hierarchical Verilation plan if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() && v3Global.opt.hierarchical()) { diff --git a/src/verilog.l b/src/verilog.l index b46bdd1bd..fb16d331d 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -390,7 +390,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "strong1" { FL; return ySTRONG1; } "supply0" { FL; return ySUPPLY0; } "supply1" { FL; return ySUPPLY1; } - "table" { FL; yy_push_state(TABLE); return yTABLE; } + "table"[ \t]* { FL; yy_push_state(TABLE); return yTABLE; } "task" { FL; return yTASK; } "time" { FL; return yTIME; } "tran" { FL; return yTRAN; } @@ -1007,18 +1007,21 @@ 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; } +
[01xX\?] {FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLEIFIELDVAL; } /* Input field symbol. */ +
[ \t]+ { FL; return yaTABLESEP; } /* Separator for table line. */ +
[ \t]*[\\]+[ \t]*[\n][ \t]* { FL; return yaTABLELSEP; } /* Separator for table line. */ +
[:] { FL; return yaTABLELRSEP; } /* LHS and RHS separator for table line. */ +
[ \t]*[;][ \t]* { FL; return yaTABLELINEEND; } +
[\r\n] { FL_FWD; FL_BRK; }
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; } -
. { yymore(); } +
^[ \t]*[\r\n] { FL_FWD; FL_BRK; } +
[ \t]*"endtable"[ \t\f]*[\n\r] { yy_pop_state(); FL; return yENDTABLE; }
<> { FL; yylval.fl->v3error("EOF in 'table'"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } diff --git a/src/verilog.y b/src/verilog.y index 0b761d24d..3c61492e2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -448,6 +448,12 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ygenSTRENGTH "STRENGTH keyword (strong1/etc)" %token yaTABLELINE "TABLE LINE" +%token yaTABLEIFIELDVAL "Table_line_input_field_value" +%token yaTABLEOFIELDVAL "Table_line_output_field_value" +%token yaTABLELRSEP ":" +%token yaTABLESEP "Table_line_input_field_value_sep" +%token yaTABLELSEP "Table_line_input_line_field_value_sep" +%token yaTABLELINEEND "Table_line_end" %token yaSCHDR "`systemc_header BLOCK" %token yaSCINT "`systemc_ctor BLOCK" @@ -5728,16 +5734,36 @@ combinational_body: // IEEE: combinational_body + sequential_body yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable{$1, $2}; } ; -tableEntryList: // IEEE: { combinational_entry | sequential_entry } +tableEntryList: // IEEE: { combinational_entry } tableEntry { $$ = $1; } | tableEntryList tableEntry { $$ = addNextNull($1, $2); } ; -tableEntry: // IEEE: combinational_entry + sequential_entry - yaTABLELINE { $$ = new AstUdpTableLine{$1, *$1}; } +tableEntry: // IEEE: combinational_entry + tableLine { $$ = $1; } | error { $$ = nullptr; } ; +tableLine: + tableIField yaTABLELRSEP tableOField yaTABLELINEEND { $$ = new AstUdpTableLine{$1, $1, $3}; } + ; + +tableIField: + yaTABLESEP tablelVal { $$ = $2; } + | tablelVal yaTABLESEP { $$ = $1; } + | yaTABLESEP tablelVal yaTABLESEP { $$ = $2; } + | tableIField tablelVal yaTABLESEP { $$ = addNextNull($1, $2); } + | tableIField tablelVal yaTABLELSEP { $$ = addNextNull($1, $2); } + ; + +tablelVal: + yaTABLEIFIELDVAL { $$ = new AstUdpTableLineVal{$1, *$1}; } + ; + +tableOField: + yaTABLESEP yaTABLEIFIELDVAL { $$ = new AstUdpTableLineVal{$2, *$2}; } + ; + //************************************************ // Specify diff --git a/test_regress/t/t_udp_lint.py b/test_regress/t/t_nonsequential_udp.py similarity index 74% rename from test_regress/t/t_udp_lint.py rename to test_regress/t/t_nonsequential_udp.py index c817fb894..d4f986441 100755 --- a/test_regress/t/t_udp_lint.py +++ b/test_regress/t/t_nonsequential_udp.py @@ -9,11 +9,10 @@ import vltest_bootstrap -test.scenarios('vlt') -test.top_filename = "t/t_udp.v" +test.scenarios('simulator') -test.lint( - # Unsupported: UDP Tables - verilator_flags2=["--lint-only --bbox-unsup"]) +test.compile() + +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..3608c02a5 --- /dev/null +++ b/test_regress/t/t_nonsequential_udp.v @@ -0,0 +1,70 @@ +// 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 index 3f274bfa6..4099e5bd2 100644 --- a/test_regress/t/t_udp.out +++ b/test_regress/t/t_udp.out @@ -1,5 +1,100 @@ -%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: t/t_udp.v:124:18: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 124 | 0 1 : ? : 1; + | ^ +%Error: t/t_udp.v:125:18: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 125 | 0 0 : ? : 0; + | ^ +%Error: t/t_udp.v:126:18: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 126 | 1 ? : ? : -; + | ^ +%Error: t/t_udp.v:126:21: Missing verilog.l rule: Default rule invoked in state 13 '-' + 126 | 1 ? : ? : -; + | ^ +%Error: t/t_udp.v:136:7: Missing verilog.l rule: Default rule invoked in state 13 'r' + 136 | r 0 1 ? : ? : 0 ; + | ^ +%Error: t/t_udp.v:136:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 136 | r 0 1 ? : ? : 0 ; + | ^ +%Error: t/t_udp.v:137:7: Missing verilog.l rule: Default rule invoked in state 13 'r' + 137 | r 1 ? 1 : ? : 1 ; + | ^ +%Error: t/t_udp.v:137:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 137 | r 1 ? 1 : ? : 1 ; + | ^ +%Error: t/t_udp.v:138:7: Missing verilog.l rule: Default rule invoked in state 13 '*' + 138 | * 1 ? 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:138:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 138 | * 1 ? 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:139:7: Missing verilog.l rule: Default rule invoked in state 13 '*' + 139 | * 0 1 ? : 0 : 0 ; + | ^ +%Error: t/t_udp.v:139:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 139 | * 0 1 ? : 0 : 0 ; + | ^ +%Error: t/t_udp.v:140:7: Missing verilog.l rule: Default rule invoked in state 13 'f' + 140 | f ? ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:140:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 140 | f ? ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:140:27: Missing verilog.l rule: Default rule invoked in state 13 '-' + 140 | f ? ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:141:7: Missing verilog.l rule: Default rule invoked in state 13 'b' + 141 | b * ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:141:12: Missing verilog.l rule: Default rule invoked in state 13 '*' + 141 | b * ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:141:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 141 | b * ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:141:27: Missing verilog.l rule: Default rule invoked in state 13 '-' + 141 | b * ? ? : ? : - ; + | ^ +%Error: t/t_udp.v:142:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 142 | ? ? 0 ? : ? : 1 ; + | ^ +%Error: t/t_udp.v:143:7: Missing verilog.l rule: Default rule invoked in state 13 'b' + 143 | b ? * 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:143:15: Missing verilog.l rule: Default rule invoked in state 13 '*' + 143 | b ? * 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:143:16: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_input_field_value or : + 143 | b ? * 1 : 1 : 1 ; + | ^~ +%Error: t/t_udp.v:143:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 143 | b ? * 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:144:15: Missing verilog.l rule: Default rule invoked in state 13 '*' + 144 | x 1 * 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:144:16: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_input_field_value or : + 144 | x 1 * 1 : 1 : 1 ; + | ^~ +%Error: t/t_udp.v:144:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 144 | x 1 * 1 : 1 : 1 ; + | ^ +%Error: t/t_udp.v:145:24: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_end + 145 | ? ? 1 0 : ? : 0 ; + | ^ +%Error: t/t_udp.v:146:7: Missing verilog.l rule: Default rule invoked in state 13 'b' + 146 | b ? 1 * : 0 : 0 ; + | ^ +%Error: t/t_udp.v:146:18: Missing verilog.l rule: Default rule invoked in state 13 '*' + 146 | b ? 1 * : 0 : 0 ; + | ^ +%Error: t/t_udp.v:146:19: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_input_field_value or : + 146 | b ? 1 * : 0 : 0 ; + | ^~ +%Error: t/t_udp.v:147:18: Missing verilog.l rule: Default rule invoked in state 13 '*' + 147 | x 0 1 * : 0 : 0 ; + | ^ +%Error: t/t_udp.v:147:19: syntax error, unexpected Table_line_input_field_value_sep, expecting Table_line_input_field_value or : + 147 | x 0 1 * : 0 : 0 ; + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_udp_bad_fist_input.out b/test_regress/t/t_udp_bad_fist_input.out new file mode 100644 index 000000000..1e673d5a5 --- /dev/null +++ b/test_regress/t/t_udp_bad_fist_input.out @@ -0,0 +1,5 @@ +%Error: t/t_udp_bad_fist_input.v:8:7: The first port must be the output port! + : ... note: In instance 'top' + 8 | input a, b, c; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_udp_bad_fist_input.py b/test_regress/t/t_udp_bad_fist_input.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_fist_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_fist_input.v b/test_regress/t/t_udp_bad_fist_input.v new file mode 100755 index 000000000..0fac0eb48 --- /dev/null +++ b/test_regress/t/t_udp_bad_fist_input.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +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_input_num.out b/test_regress/t/t_udp_bad_input_num.out new file mode 100644 index 000000000..69fe0f763 --- /dev/null +++ b/test_regress/t/t_udp_bad_input_num.out @@ -0,0 +1,5 @@ +%Error: t/t_udp_bad_input_num.v:14:1: 3 input val required, while there are 2 input for the table line! + : ... note: In instance 'top' + 14 | 1 0 : 0; + | ^~~~~~~~ +%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..515f0bf72 --- /dev/null +++ b/test_regress/t/t_udp_bad_input_num.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +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_ouput.out b/test_regress/t/t_udp_bad_multi_ouput.out new file mode 100644 index 000000000..2b8f60434 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_ouput.out @@ -0,0 +1,5 @@ +%Error: t/t_udp_bad_multi_ouput.v:8:15: 2 output ports for udp table, there must be one output port! + : ... note: In instance 'top' + 8 | output dout1, dout2; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_udp_bad_multi_ouput.py b/test_regress/t/t_udp_bad_multi_ouput.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_ouput.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_ouput.v b/test_regress/t/t_udp_bad_multi_ouput.v new file mode 100755 index 000000000..715df99a4 --- /dev/null +++ b/test_regress/t/t_udp_bad_multi_ouput.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +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_bad.out b/test_regress/t/t_udp_sequential_bad.out new file mode 100644 index 000000000..43fe2a98b --- /dev/null +++ b/test_regress/t/t_udp_sequential_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_udp_sequential_bad.v:10:1: sequetial UDP is not suppoted currently! + : ... note: In instance 'top' + 10 | reg dout; + | ^~~ +%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..3ccfa2bcc --- /dev/null +++ b/test_regress/t/t_udp_sequential_bad.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 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