Add the support of UDP table for the nonsequential logic.

This commit is contained in:
Zhou Shen 2024-11-14 00:23:43 +08:00
parent 676fd31635
commit cb04ebafc3
25 changed files with 656 additions and 24 deletions

View File

@ -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

View File

@ -310,6 +310,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Trace.o \
V3TraceDecl.o \
V3Tristate.o \
V3Udp.o \
V3Undriven.o \
V3Unknown.o \
V3Unroll.o \

View File

@ -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; }

View File

@ -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; }
};

View File

@ -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.");
}
}

204
src/V3Udp.cpp Normal file
View File

@ -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 <vector>
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<AstVar*> m_inputVars; // All the input vars in the AstPrimitive.
std::vector<AstVar*> 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<AstUdpTableLineVal*> ifieldNodes;
std::vector<AstUdpTableLineVal*> 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);
}

32
src/V3Udp.h Normal file
View File

@ -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

View File

@ -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()) {

View File

@ -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 */
<V95,V01NC,V01C,V05,VA5,S05,S09,S12,S17,S23,SAX>{
<V95,V01NC,V01C,V05,VA5,S05,S09,S12,S17,S23,SAX,TABLE>{
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } /* Doesn't match (*), but (* attr_spec */
}
/************************************************************************/
/* Tables */
<TABLE>\\{crnl} { yymore(); }
<TABLE>{crnl} { yymore(); }
<TABLE>";" { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; }
<TABLE>"endtable" { yy_pop_state(); FL; return yENDTABLE; }
<TABLE>[01xX\?] {FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLEIFIELDVAL; } /* Input field symbol. */
<TABLE>[ \t]+ { FL; return yaTABLESEP; } /* Separator for table line. */
<TABLE>[ \t]*[\\]+[ \t]*[\n][ \t]* { FL; return yaTABLELSEP; } /* Separator for table line. */
<TABLE>[:] { FL; return yaTABLELRSEP; } /* LHS and RHS separator for table line. */
<TABLE>[ \t]*[;][ \t]* { FL; return yaTABLELINEEND; }
<TABLE>[\r\n] { FL_FWD; FL_BRK; }
<TABLE>"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
<TABLE>. { yymore(); }
<TABLE>^[ \t]*[\r\n] { FL_FWD; FL_BRK; }
<TABLE>[ \t]*"endtable"[ \t\f]*[\n\r] { yy_pop_state(); FL; return yENDTABLE; }
<TABLE><<EOF>> { FL; yylval.fl->v3error("EOF in 'table'");
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }

View File

@ -448,6 +448,12 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> ygenSTRENGTH "STRENGTH keyword (strong1/etc)"
%token<strp> yaTABLELINE "TABLE LINE"
%token<strp> yaTABLEIFIELDVAL "Table_line_input_field_value"
%token<strp> yaTABLEOFIELDVAL "Table_line_output_field_value"
%token<fl> yaTABLELRSEP ":"
%token<fl> yaTABLESEP "Table_line_input_field_value_sep"
%token<fl> yaTABLELSEP "Table_line_input_line_field_value_sep"
%token<fl> yaTABLELINEEND "Table_line_end"
%token<strp> yaSCHDR "`systemc_header BLOCK"
%token<strp> yaSCINT "`systemc_ctor BLOCK"
@ -5728,16 +5734,36 @@ combinational_body<nodep>: // IEEE: combinational_body + sequential_body
yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable{$1, $2}; }
;
tableEntryList<udpTableLinep>: // IEEE: { combinational_entry | sequential_entry }
tableEntryList<udpTableLinep>: // IEEE: { combinational_entry }
tableEntry { $$ = $1; }
| tableEntryList tableEntry { $$ = addNextNull($1, $2); }
;
tableEntry<udpTableLinep>: // IEEE: combinational_entry + sequential_entry
yaTABLELINE { $$ = new AstUdpTableLine{$<fl>1, *$1}; }
tableEntry<udpTableLinep>: // IEEE: combinational_entry
tableLine { $$ = $1; }
| error { $$ = nullptr; }
;
tableLine<udpTableLinep>:
tableIField yaTABLELRSEP tableOField yaTABLELINEEND { $$ = new AstUdpTableLine{$<fl>1, $1, $3}; }
;
tableIField<udpTableLineValp>:
yaTABLESEP tablelVal { $$ = $2; }
| tablelVal yaTABLESEP { $$ = $1; }
| yaTABLESEP tablelVal yaTABLESEP { $$ = $2; }
| tableIField tablelVal yaTABLESEP { $$ = addNextNull($1, $2); }
| tableIField tablelVal yaTABLELSEP { $$ = addNextNull($1, $2); }
;
tablelVal<udpTableLineValp>:
yaTABLEIFIELDVAL { $$ = new AstUdpTableLineVal{$<fl>1, *$1}; }
;
tableOField<udpTableLineValp>:
yaTABLESEP yaTABLEIFIELDVAL { $$ = new AstUdpTableLineVal{$<fl>2, *$2}; }
;
//************************************************
// Specify

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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