Co-authored-by: Bartłomiej Chmiel <bchmiel@antmicro.com> Co-authored-by: Zhou Shen <599239118@qq.com>
This commit is contained in:
parent
6a6a7b7e9f
commit
d0c4cc3938
|
@ -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
|
||||
|
|
|
@ -311,6 +311,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
V3Tristate.o \
|
||||
V3Udp.o \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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 <vector>
|
||||
|
||||
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<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; // 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);
|
||||
}
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -1009,20 +1009,23 @@ 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>"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
|
||||
<TABLE>. { yymore(); }
|
||||
<TABLE><<EOF>> { FL; yylval.fl->v3error("EOF in 'table'");
|
||||
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
|
||||
<TABLE>[rRfFpPnN\*] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* edge_symbol */
|
||||
<TABLE>[01xX\?bB\-] { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLE_FIELD; } /* level_symbol, next_state */
|
||||
<TABLE>":" { FL; return yaTABLE_LRSEP; } /* LHS and RHS separator for table line. */
|
||||
<TABLE>";" { FL; return yaTABLE_LINEEND; }
|
||||
<TABLE>[\(\)] { FL; return yytext[0]; }
|
||||
<TABLE>{ws}|(\\){0,1}{crnl} { FL_FWD; FL_BRK; }
|
||||
<TABLE>"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
|
||||
<TABLE>"//"[^\n]* { FL_FWD; FL_BRK; } /* throw away single line comments */
|
||||
<TABLE>"endtable" { FL; yy_pop_state(); return yENDTABLE; }
|
||||
<TABLE><<EOF>> { FL; yylval.fl->v3error("EOF in 'table'");
|
||||
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
|
||||
|
||||
<EDGEDESC>{
|
||||
01|10|[01][zZxX]|[zZxX][01] { FL; return yaEDGEDESC; }
|
||||
|
|
|
@ -450,7 +450,9 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
|
||||
%token<fl> ygenSTRENGTH "STRENGTH keyword (strong1/etc)"
|
||||
|
||||
%token<strp> yaTABLELINE "TABLE LINE"
|
||||
%token<strp> yaTABLE_FIELD "UDP table field"
|
||||
%token<fl> yaTABLE_LRSEP ":"
|
||||
%token<fl> yaTABLE_LINEEND "UDP table line end"
|
||||
|
||||
%token<strp> yaSCCTOR "`systemc_ctor block"
|
||||
%token<strp> yaSCDTOR "`systemc_dtor block"
|
||||
|
@ -5785,14 +5787,26 @@ combinational_body<nodep>: // IEEE: combinational_body + sequential_body
|
|||
yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable{$1, $2}; }
|
||||
;
|
||||
|
||||
tableEntryList<udpTableLinep>: // IEEE: { combinational_entry | sequential_entry }
|
||||
tableEntry { $$ = $1; }
|
||||
| tableEntryList tableEntry { $$ = addNextNull($1, $2); }
|
||||
tableEntryList<udpTableLinep>: // IEEE: { combinational_entry + sequential_entry }
|
||||
tableLine { $$ = $1; }
|
||||
| tableEntryList tableLine { $$ = addNextNull($1, $2); }
|
||||
;
|
||||
|
||||
tableEntry<udpTableLinep>: // IEEE: combinational_entry + sequential_entry
|
||||
yaTABLELINE { $$ = new AstUdpTableLine{$<fl>1, *$1}; }
|
||||
| error { $$ = nullptr; }
|
||||
tableLine<udpTableLinep>:
|
||||
tableInputList yaTABLE_LRSEP tablelVal yaTABLE_LINEEND
|
||||
{ $$ = new AstUdpTableLine{AstUdpTableLine::UdpCombo{}, $<fl>1, $1, $3}; }
|
||||
| tableInputList yaTABLE_LRSEP tablelVal yaTABLE_LRSEP tablelVal yaTABLE_LINEEND
|
||||
{ $$ = new AstUdpTableLine{AstUdpTableLine::UdpSequential{}, $<fl>1, $1, $3, $5}; }
|
||||
;
|
||||
|
||||
tableInputList<udpTableLineValp>:
|
||||
tablelVal { $$ = $1; }
|
||||
| tableInputList tablelVal { $$ = addNextNull($1, $2); }
|
||||
;
|
||||
|
||||
tablelVal<udpTableLineValp>:
|
||||
yaTABLE_FIELD { $$ = new AstUdpTableLineVal{$<fl>1, *$1}; }
|
||||
| '(' yaTABLE_FIELD yaTABLE_FIELD ')' { $$ = new AstUdpTableLineVal{$<fl>2, *$2 + *$3}; }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
|
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
Loading…
Reference in New Issue