mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Add the support of UDP table for the nonsequential logic.
This commit is contained in:
parent
676fd31635
commit
cb04ebafc3
@ -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
|
||||
|
@ -310,6 +310,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
V3Tristate.o \
|
||||
V3Udp.o \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
};
|
||||
|
@ -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
204
src/V3Udp.cpp
Normal 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
32
src/V3Udp.h
Normal 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
|
@ -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()) {
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
70
test_regress/t/t_nonsequential_udp.v
Executable file
70
test_regress/t/t_nonsequential_udp.v
Executable 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
|
||||
|
||||
|
@ -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
|
||||
|
5
test_regress/t/t_udp_bad_fist_input.out
Normal file
5
test_regress/t/t_udp_bad_fist_input.out
Normal 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
|
16
test_regress/t/t_udp_bad_fist_input.py
Executable file
16
test_regress/t/t_udp_bad_fist_input.py
Executable 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()
|
25
test_regress/t/t_udp_bad_fist_input.v
Executable file
25
test_regress/t/t_udp_bad_fist_input.v
Executable 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
|
5
test_regress/t/t_udp_bad_input_num.out
Normal file
5
test_regress/t/t_udp_bad_input_num.out
Normal 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
|
16
test_regress/t/t_udp_bad_input_num.py
Executable file
16
test_regress/t/t_udp_bad_input_num.py
Executable 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()
|
25
test_regress/t/t_udp_bad_input_num.v
Executable file
25
test_regress/t/t_udp_bad_input_num.v
Executable 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
|
5
test_regress/t/t_udp_bad_multi_ouput.out
Normal file
5
test_regress/t/t_udp_bad_multi_ouput.out
Normal 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
|
16
test_regress/t/t_udp_bad_multi_ouput.py
Executable file
16
test_regress/t/t_udp_bad_multi_ouput.py
Executable 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()
|
25
test_regress/t/t_udp_bad_multi_ouput.v
Executable file
25
test_regress/t/t_udp_bad_multi_ouput.v
Executable 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
|
5
test_regress/t/t_udp_sequential_bad.out
Normal file
5
test_regress/t/t_udp_sequential_bad.out
Normal 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
|
16
test_regress/t/t_udp_sequential_bad.py
Executable file
16
test_regress/t/t_udp_sequential_bad.py
Executable 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()
|
26
test_regress/t/t_udp_sequential_bad.v
Executable file
26
test_regress/t/t_udp_sequential_bad.v
Executable 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
|
Loading…
Reference in New Issue
Block a user