Support IEEE constant signal strengths (#3601).

This commit is contained in:
Ryszard Rozak 2022-09-14 13:39:27 +02:00 committed by GitHub
parent ae466b1703
commit a3c58d7b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 550 additions and 39 deletions

View File

@ -732,6 +732,10 @@ public:
return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0
|| m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
}
bool isNet() const {
return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|| m_e == SUPPLY0 || m_e == SUPPLY1);
}
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL
|| m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
@ -975,6 +979,32 @@ inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) {
return os << rhs.ascii();
}
//######################################################################
class VStrength final {
public:
enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY };
enum en m_e;
inline VStrength(en strengthLevel)
: m_e(strengthLevel) {}
explicit inline VStrength(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[]
= {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"};
return names[m_e];
}
};
inline bool operator==(const VStrength& lhs, const VStrength& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VStrength& lhs, VStrength::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VStrength::en lhs, const VStrength& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) {
return os << rhs.ascii();
}
//######################################################################
// VNumRange - Structure containing numeric range information
// See also AstRange, which is a symbolic version of this

View File

@ -1786,6 +1786,10 @@ void AstSenItem::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << edgeType().ascii() << "]";
}
void AstStrengthSpec::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")";
}
void AstParseRef::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " [" << expect().ascii() << "]";

View File

@ -290,6 +290,23 @@ public:
virtual bool same(const AstNode* /*samep*/) const override { return true; }
};
class AstStrengthSpec final : public AstNode {
private:
VStrength m_s0; // Drive 0 strength
VStrength m_s1; // Drive 1 strength
public:
AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1)
: ASTGEN_SUPER_StrengthSpec(fl)
, m_s0{s0}
, m_s1{s1} {}
ASTNODE_NODE_FUNCS(StrengthSpec)
VStrength strength0() { return m_s0; }
VStrength strength1() { return m_s1; }
virtual void dump(std::ostream& str) const override;
};
class AstGatePin final : public AstNodeMath {
// Possibly expand a gate primitive input pin value to match the range of the gate primitive
public:
@ -2094,6 +2111,7 @@ private:
bool m_isRand : 1; // Random variable
bool m_isConst : 1; // Table contains constant data
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic)
bool m_isPulldown : 1; // Tri0
bool m_isPullup : 1; // Tri1
@ -2134,6 +2152,7 @@ private:
m_isRand = false;
m_isConst = false;
m_isContinuously = false;
m_hasStrengthAssignment = false;
m_isStatic = false;
m_isPulldown = false;
m_isPullup = false;
@ -2297,6 +2316,8 @@ public:
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; }
void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; }
bool hasStrengthAssignment() { return m_hasStrengthAssignment; }
void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; }
bool isDpiOpenArray() const { return m_isDpiOpenArray; }
bool isHideLocal() const { return m_isHideLocal; }
@ -2330,6 +2351,7 @@ public:
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); }
bool isNet() const { return varType().isNet(); }
bool isTemp() const { return varType().isTemp(); }
bool isToggleCoverable() const {
return ((isIO() || isSignal())
@ -3630,6 +3652,8 @@ public:
AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(AssignW)
AstStrengthSpec* strengthSpecp() const { return VN_AS(op4p(), StrengthSpec); }
void strengthSpecp(AstStrengthSpec* const strengthSpecp) { setOp4p((AstNode*)strengthSpecp); }
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
return new AstAssignW(this->fileline(), lhsp, rhsp);
}

View File

@ -2853,6 +2853,7 @@ private:
if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp())
&& !VN_AS(nodep->rhsp(), Const)->num().isFourState()
&& varrefp // Don't do messes with BITREFs/ARRAYREFs
&& !varrefp->varp()->hasStrengthAssignment() // Strengths are resolved in V3Tristate
&& !varrefp->varp()->valuep() // Not already constified
&& !varrefp->varScopep()) { // Not scoped (or each scope may have different initial
// value)

View File

@ -37,6 +37,7 @@ private:
// STATE
bool m_setContinuously = false; // Set that var has some continuous assignment
bool m_setStrengthSpecified = false; // Set that var has assignment with strength specified.
VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
@ -51,6 +52,9 @@ private:
if (nodep->varp()) {
if (nodep->access().isWriteOrRW() && m_setContinuously) {
nodep->varp()->isContinuously(true);
// Strength may only be specified in continuous assignment,
// so it is needed to check only if m_setContinuously is true
if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true);
}
if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) {
nodep->v3warn(ASSIGNIN,
@ -78,9 +82,13 @@ private:
{
m_setRefLvalue = VAccess::WRITE;
m_setContinuously = VN_IS(nodep, AssignW) || VN_IS(nodep, AssignAlias);
if (AstAssignW* assignwp = VN_CAST(nodep, AssignW)) {
if (assignwp->strengthSpecp()) m_setStrengthSpecified = true;
}
iterateAndNextNull(nodep->lhsp());
m_setRefLvalue = VAccess::NOCHANGE;
m_setContinuously = false;
m_setStrengthSpecified = false;
iterateAndNextNull(nodep->rhsp());
}
}

View File

@ -84,9 +84,13 @@ AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) {
}
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
return new AstAssignW(
fileline, new AstVarRef(fileline, name, VAccess::WRITE),
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
AstAssignW* assignp
= new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE},
new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}};
AstStrengthSpec* strengthSpecp
= new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY};
assignp->strengthSpecp(strengthSpecp);
return assignp;
}
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {

View File

@ -398,8 +398,7 @@ void V3ParseImp::tokenPipeline() {
const int nexttok = nexttokp->token;
yylval = curValue;
// Now potentially munge the current token
if (token == '('
&& (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) {
if (token == '(' && isStrengthToken(nexttok)) {
token = yP_PAR__STRENGTH;
} else if (token == ':') {
if (nexttok == yBEGIN) {
@ -483,6 +482,12 @@ void V3ParseImp::tokenPipeline() {
// effectively returns yylval
}
bool V3ParseImp::isStrengthToken(int tok) {
return tok == ygenSTRENGTH || tok == ySUPPLY0 || tok == ySUPPLY1 || tok == ySTRONG0
|| tok == ySTRONG1 || tok == yPULL0 || tok == yPULL1 || tok == yWEAK0 || tok == yWEAK1
|| tok == yHIGHZ0 || tok == yHIGHZ1;
}
void V3ParseImp::tokenPipelineSym() {
// If an id, change the type based on symbol table
// Note above sometimes converts yGLOBAL to a yaID__LEX

View File

@ -121,6 +121,7 @@ struct V3ParseBisonYYSType {
V3ErrorCode::en errcodeen;
VAttrType::en attrtypeen;
VLifetime::en lifetime;
VStrength::en strength;
#include "V3Ast__gen_yystype.h"
};
@ -216,6 +217,7 @@ public:
}
int lexKwdLastState() const { return m_lexKwdLast; }
static const char* tokenName(int tok);
static bool isStrengthToken(int tok);
void ppPushText(const string& text) {
m_ppBuffers.push_back(text);

View File

@ -55,6 +55,33 @@
// duplicating vars and logic that is common between each instance of a
// module.
//
//
// Another thing done in this phase is signal strength handling.
// Currently they are only supported in assignments and only in case when the strongest assignment
// has constant with all bits equal on the RHS. It is the case when they can be statically
// resolved.
//
// Static resolution is done in the following way:
// - The assignment of value 0 (size may be greater than 1), that has greatest strength (the
// one corresponding to 0) of all other assignments of 0, has to be found.
// - The same is done for value '1 and strength corresponding to value 1.
// - The greater of these two strengths is chosen. If they are equal the one that corresponds
// to 1 is taken as the greatest.
// - All assignments, that have strengths weaker or equal to the one that was found before, are
// removed. They are the assignments with constants on the RHS and also all assignments that have
// both strengths non-greater that the one was found, because they are weaker no matter what is on
// RHS.
//
// All assignments that are stronger than the one with strongest constant are left as they are.
//
// There is a possible problem with equally strong assignments, because multiple assignments with
// the same strength, but different values should result in x value, but these values are
// unsupported.
//
// Singal strength can also be used in simple logic gates parsed as assignments (see verilog.y),
// but these gates are then either removed (if they are weaker than the strongest constant) or
// handled as the gates witout signal strengths are handled now. In other words, gate with greater
// strength won't properly overwrite weaker driver.
//*************************************************************************
#include "config_build.h"
@ -340,6 +367,8 @@ class TristateVisitor final : public TristateBaseVisitor {
// TYPES
using RefVec = std::vector<AstVarRef*>;
using VarMap = std::unordered_map<AstVar*, RefVec*>;
using Assigns = std::vector<AstAssignW*>;
using VarToAssignsMap = std::map<AstVar*, Assigns>;
enum : uint8_t {
U2_GRAPHING = 1, // bit[0] if did m_graphing visit
U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit
@ -352,6 +381,7 @@ class TristateVisitor final : public TristateBaseVisitor {
AstNodeModule* m_modp = nullptr; // Current module
AstCell* m_cellp = nullptr; // current cell
VarMap m_lhsmap; // Tristate left-hand-side driver map
VarToAssignsMap m_assigns; // Assigns in current module
int m_unique = 0;
bool m_alhs = false; // On LHS of assignment
const AstNode* m_logicp = nullptr; // Current logic being built
@ -636,6 +666,117 @@ class TristateVisitor final : public TristateBaseVisitor {
nodep->addStmtp(assp);
}
void addToAssignmentList(AstAssignW* nodep) {
if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) {
if (varRefp->varp()->isNet()) {
m_assigns[varRefp->varp()].push_back(nodep);
} else if (nodep->strengthSpecp()) {
if (!varRefp->varp()->isNet())
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Signal strengths are unsupported "
"on the following variable type: "
<< varRefp->varp()->varType());
nodep->strengthSpecp()->unlinkFrBack()->deleteTree();
}
} else if (nodep->strengthSpecp()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Assignments with signal strength with LHS of type: "
<< nodep->lhsp()->prettyTypeName());
}
}
uint8_t getStrength(AstAssignW* const nodep, bool value) {
if (AstStrengthSpec* const strengthSpec = nodep->strengthSpecp()) {
return value ? strengthSpec->strength1() : strengthSpec->strength0();
}
return VStrength::STRONG; // default strength is strong
}
bool assignmentOfValueOnAllBits(AstAssignW* const nodep, bool value) {
if (AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) {
const V3Number num = constp->num();
return value ? num.isEqAllOnes() : num.isEqZero();
}
return false;
}
AstAssignW* getStrongestAssignmentOfValue(const Assigns& assigns, bool value) {
auto maxIt = std::max_element(
assigns.begin(), assigns.end(), [&](AstAssignW* ap, AstAssignW* bp) {
bool valuesOnRhsA = assignmentOfValueOnAllBits(ap, value);
bool valuesOnRhsB = assignmentOfValueOnAllBits(bp, value);
if (!valuesOnRhsA) return valuesOnRhsB;
if (!valuesOnRhsB) return false;
return getStrength(ap, value) < getStrength(bp, value);
});
// If not all assignments have const with all bits equal to value on the RHS,
// std::max_element will return one of them anyway, so it has to be checked before
// returning
return assignmentOfValueOnAllBits(*maxIt, value) ? *maxIt : nullptr;
}
void removeWeakerAssignments(Assigns& assigns) {
// Weaker assignments are these assignments that can't change the final value of the net.
// If the value of the RHS is known, only strength corresponding to its value is taken into
// account. Assignments of constants that have bits both 0 and 1 are skipped here, because
// it would involve handling parts of bits separately.
// First, the strongest assignment, that has value on the RHS consisting of only 1 or only
// 0, has to be found.
AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0);
AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1);
AstAssignW* strongestp = nullptr;
uint8_t greatestKnownStrength = 0;
const auto getIfStrongest = [&](AstAssignW* const strongestCandidatep, bool value) {
if (!strongestCandidatep) return;
uint8_t strength = getStrength(strongestCandidatep, value);
if (strength >= greatestKnownStrength) {
greatestKnownStrength = strength;
strongestp = strongestCandidatep;
}
};
getIfStrongest(strongest0p, 0);
getIfStrongest(strongest1p, 1);
if (strongestp) {
// Then all weaker assignments can be safely removed.
// Assignments of the same strength are also removed, because duplicates aren't needed.
// One problem is with 2 assignments of different values and equal strengths. It should
// result in assignment of x value, but these values aren't supported now.
auto removedIt
= std::remove_if(assigns.begin(), assigns.end(), [&](AstAssignW* assignp) {
if (assignp == strongestp) return false;
const uint8_t strength0 = getStrength(assignp, 0);
const uint8_t strength1 = getStrength(assignp, 1);
const bool toRemove = (strength0 <= greatestKnownStrength
&& strength1 <= greatestKnownStrength)
|| (strength0 <= greatestKnownStrength
&& assignmentOfValueOnAllBits(assignp, 0))
|| (strength1 <= greatestKnownStrength
&& assignmentOfValueOnAllBits(assignp, 1));
if (toRemove) {
// Don't propagate tristate if its assignment is removed.
TristateVertex* const vertexp
= reinterpret_cast<TristateVertex*>(assignp->rhsp()->user5p());
if (vertexp) vertexp->isTristate(false);
VL_DO_DANGLING(pushDeletep(assignp->unlinkFrBack()), assignp);
return true;
}
return false;
});
assigns.erase(removedIt, assigns.end());
}
}
void resolveMultipleNetAssignments() {
for (auto& varpAssigns : m_assigns) {
if (varpAssigns.second.size() > 1) {
// first the static resolution is tried
removeWeakerAssignments(varpAssigns.second);
}
}
}
// VISITORS
virtual void visit(AstConst* nodep) override {
UINFO(9, dbgState() << nodep << endl);
@ -889,6 +1030,8 @@ class TristateVisitor final : public TristateBaseVisitor {
void visitAssign(AstNodeAssign* nodep) {
if (m_graphing) {
if (AstAssignW* assignWp = VN_CAST(nodep, AssignW)) addToAssignmentList(assignWp);
if (nodep->user2() & U2_GRAPHING) return;
VL_RESTORER(m_logicp);
m_logicp = nodep;
@ -1373,6 +1516,7 @@ class TristateVisitor final : public TristateBaseVisitor {
VL_RESTORER(m_graphing);
VL_RESTORER(m_unique);
VL_RESTORER(m_lhsmap);
VL_RESTORER(m_assigns);
// Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph;
UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule");
{
@ -1382,6 +1526,7 @@ class TristateVisitor final : public TristateBaseVisitor {
m_unique = 0;
m_logicp = nullptr;
m_lhsmap.clear();
m_assigns.clear();
m_modp = nodep;
// Walk the graph, finding all variables and tristate constructs
{
@ -1389,6 +1534,8 @@ class TristateVisitor final : public TristateBaseVisitor {
iterateChildren(nodep);
m_graphing = false;
}
// resolve multiple net assignments and signal strengths
resolveMultipleNetAssignments();
// Use graph to find tristate signals
m_tgraph.graphWalk(nodep);
// Build the LHS drivers map for this module

View File

@ -325,8 +325,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"forever" { FL; return yFOREVER; }
"fork" { FL; return yFORK; }
"function" { FL; return yFUNCTION; }
"highz0" { FL; return ygenSTRENGTH; }
"highz1" { FL; return ygenSTRENGTH; }
"highz0" { FL; return yHIGHZ0; }
"highz1" { FL; return yHIGHZ1; }
"if" { FL; return yIF; }
"initial" { FL; return yINITIAL; }
"inout" { FL; return yINOUT; }
@ -350,8 +350,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"pmos" { FL; return yPMOS; }
"posedge" { FL; return yPOSEDGE; }
"primitive" { FL; return yPRIMITIVE; }
"pull0" { FL; return ygenSTRENGTH; }
"pull1" { FL; return ygenSTRENGTH; }
"pull0" { FL; return yPULL0; }
"pull1" { FL; return yPULL1; }
"pulldown" { FL; return yPULLDOWN; }
"pullup" { FL; return yPULLUP; }
"rcmos" { FL; return yRCMOS; }
@ -369,8 +369,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"small" { FL; return ygenSTRENGTH; }
"specify" { FL; return ySPECIFY; }
"specparam" { FL; return ySPECPARAM; }
"strong0" { FL; return ygenSTRENGTH; }
"strong1" { FL; return ygenSTRENGTH; }
"strong0" { FL; return ySTRONG0; }
"strong1" { FL; return ySTRONG1; }
"supply0" { FL; return ySUPPLY0; }
"supply1" { FL; return ySUPPLY1; }
"table" { FL; yy_push_state(TABLE); return yTABLE; }
@ -388,8 +388,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"vectored" { FL; return yVECTORED; }
"wait" { FL; return yWAIT; }
"wand" { FL; return yWAND; }
"weak0" { FL; return ygenSTRENGTH; }
"weak1" { FL; return ygenSTRENGTH; }
"weak0" { FL; return yWEAK0; }
"weak1" { FL; return yWEAK1; }
"while" { FL; return yWHILE; }
"wire" { FL; return yWIRE; }
"wor" { FL; return yWOR; }

View File

@ -40,6 +40,13 @@
#define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg)
#define GATEUNSUP(fl, tok) \
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
#define STRENGTHUNSUP(nodep) \
{ \
if (nodep) { \
BBUNSUP((nodep->fileline()), "Unsupported: Strength specifier on this gate type"); \
nodep->deleteTree(); \
} \
}
#define PRIMDLYUNSUP(nodep) \
{ \
if (nodep) { \
@ -68,6 +75,7 @@ public:
AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration
AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration
AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration
AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration
AstNodeModule* m_modp = nullptr; // Last module for timeunits
bool m_pinAnsi = false; // In ANSI port list
FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations
@ -172,6 +180,7 @@ public:
m_varDTypep = dtypep;
}
void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; }
void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; }
void pinPush() {
m_pinStack.push(m_pinNum);
m_pinNum = 1;
@ -291,6 +300,15 @@ int V3ParseGrammar::s_modTypeImpNum = 0;
if (nodep) nodep->deleteTree(); \
}
#define APPLY_STRENGTH_TO_LIST(beginp, strengthSpecNodep, typeToCast) \
{ \
if (AstStrengthSpec* specp = VN_CAST(strengthSpecNodep, StrengthSpec)) \
for (auto* nodep = beginp; nodep; nodep = nodep->nextp()) { \
auto* const assignp = VN_AS(nodep, typeToCast); \
assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \
} \
}
static void ERRSVKWD(FileLine* fileline, const string& tokname) {
static int toldonce = 0;
fileline->v3error(
@ -544,6 +562,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yGLOBAL__CLOCKING "global-then-clocking"
%token<fl> yGLOBAL__ETC "global"
%token<fl> yGLOBAL__LEX "global-in-lex"
%token<fl> yHIGHZ0 "highz0"
%token<fl> yHIGHZ1 "highz1"
%token<fl> yIF "if"
%token<fl> yIFF "iff"
//UNSUP %token<fl> yIGNORE_BINS "ignore_bins"
@ -598,6 +618,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> yPROGRAM "program"
%token<fl> yPROPERTY "property"
%token<fl> yPROTECTED "protected"
%token<fl> yPULL0 "pull0"
%token<fl> yPULL1 "pull1"
%token<fl> yPULLDOWN "pulldown"
%token<fl> yPULLUP "pullup"
%token<fl> yPURE "pure"
@ -635,6 +657,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<fl> ySTATIC__LEX "static-in-lex"
%token<fl> ySTRING "string"
//UNSUP %token<fl> ySTRONG "strong"
%token<fl> ySTRONG0 "strong0"
%token<fl> ySTRONG1 "strong1"
%token<fl> ySTRUCT "struct"
%token<fl> ySUPER "super"
%token<fl> ySUPPLY0 "supply0"
@ -688,6 +712,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
//UNSUP %token<fl> yWAIT_ORDER "wait_order"
%token<fl> yWAND "wand"
//UNSUP %token<fl> yWEAK "weak"
%token<fl> yWEAK0 "weak0"
%token<fl> yWEAK1 "weak1"
%token<fl> yWHILE "while"
//UNSUP %token<fl> yWILDCARD "wildcard"
%token<fl> yWIRE "wire"
@ -1718,11 +1744,18 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as
;
net_declaration<nodep>: // IEEE: net_declaration - excluding implict
net_declarationFront netSigList ';' { $$ = $2; }
net_declarationFront netSigList ';'
{ $$ = $2;
if (GRAMMARP->m_netStrengthp) {
VL_DO_CLEAR(delete GRAMMARP->m_netStrengthp, GRAMMARP->m_netStrengthp = nullptr);
}}
;
net_declarationFront: // IEEE: beginning of net_declaration
net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); }
net_declRESET net_type driveStrengthE net_scalaredE net_dataTypeE
{ VARDTYPE_NDECL($5);
GRAMMARP->setNetStrength(VN_CAST($3, StrengthSpec));
}
//UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); }
;
@ -2425,9 +2458,10 @@ module_common_item<nodep>: // ==IEEE: module_common_item
;
continuous_assign<nodep>: // IEEE: continuous_assign
yASSIGN strengthSpecE delayE assignList ';'
yASSIGN driveStrengthE delayE assignList ';'
{
$$ = $4;
APPLY_STRENGTH_TO_LIST($$, $2, AssignW);
if ($3)
for (auto* nodep = $$; nodep; nodep = nodep->nextp()) {
auto* const assignp = VN_AS(nodep, NodeAssign);
@ -2726,6 +2760,7 @@ netSig<varp>: // IEEE: net_decl_assignment - one element from
| netId sigAttrListE '=' expr
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
auto* const assignp = new AstAssignW{$3, new AstVarRef{$<fl>1, *$1, VAccess::WRITE}, $4};
if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false));
if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3
$$->addNext(assignp); } | netId variable_dimensionList sigAttrListE
{ $$ = VARDONEA($<fl>1,*$1, $2, $3); }
@ -4718,18 +4753,30 @@ stream_expressionOrDataType<nodep>: // IEEE: from streaming_concatenation
// Gate declarations
gateDecl<nodep>:
yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); }
yBUF driveStrengthE delayE gateBufList ';'
{ $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); }
| yBUFIF0 driveStrengthE delayE gateBufif0List ';'
{ $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); }
| yBUFIF1 driveStrengthE delayE gateBufif1List ';'
{ $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); }
| yNOT driveStrengthE delayE gateNotList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yNOTIF0 driveStrengthE delayE gateNotif0List ';'
{ $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); }
| yNOTIF1 driveStrengthE delayE gateNotif1List ';'
{ $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); }
| yAND driveStrengthE delayE gateAndList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yNAND driveStrengthE delayE gateNandList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yOR driveStrengthE delayE gateOrList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yNOR driveStrengthE delayE gateNorList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yXOR driveStrengthE delayE gateXorList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yXNOR driveStrengthE delayE gateXnorList ';'
{ $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); }
| yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); }
| yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet
@ -4901,21 +4948,33 @@ gatePinExpr<nodep>:
expr { $$ = GRAMMARP->createGatePin($1); }
;
// This list is also hardcoded in VParseLex.l
strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE
ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
| ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
| ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); }
strength0<strength>:
ySUPPLY0 { $$ = VStrength::SUPPLY; }
| ySTRONG0 { $$ = VStrength::STRONG; }
| yPULL0 { $$ = VStrength::PULL; }
| yWEAK0 { $$ = VStrength::WEAK; }
;
strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
/* empty */ { }
| strengthSpec { }
strength1<strength>:
ySUPPLY1 { $$ = VStrength::SUPPLY; }
| ySTRONG1 { $$ = VStrength::STRONG; }
| yPULL1 { $$ = VStrength::PULL; }
| yWEAK1 { $$ = VStrength::WEAK; }
;
strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
yP_PAR__STRENGTH strength ')' { }
| yP_PAR__STRENGTH strength ',' strength ')' { }
driveStrengthE<nodep>:
/* empty */ { $$ = nullptr; }
| driveStrength { $$ = $1; }
;
driveStrength<nodep>:
yP_PAR__STRENGTH strength0 ',' strength1 ')' { $$ = new AstStrengthSpec{$1, $2, $4}; }
| yP_PAR__STRENGTH strength1 ',' strength0 ')' { $$ = new AstStrengthSpec{$1, $4, $2}; }
| yP_PAR__STRENGTH strength0 ',' yHIGHZ1 ')' { BBUNSUP($<fl>4, "Unsupported: highz strength"); }
| yP_PAR__STRENGTH strength1 ',' yHIGHZ0 ')' { BBUNSUP($<fl>4, "Unsupported: highz strength"); }
| yP_PAR__STRENGTH yHIGHZ0 ',' strength1 ')' { BBUNSUP($<fl>2, "Unsupported: highz strength"); }
| yP_PAR__STRENGTH yHIGHZ1 ',' strength0 ')' { BBUNSUP($<fl>2, "Unsupported: highz strength"); }
;
//************************************************

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,38 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire a;
assign (weak0, weak1) a = 1;
assign (weak0, supply1) a = 1;
assign (strong0, strong1) a = 0;
wire (weak0, weak1) b = 1;
assign (strong0, strong1) b = 0;
wire [1:0] c;
assign (weak0, supply1) c = '1;
assign (supply0, pull1) c = '1;
assign (strong0, strong1) c = '0;
supply0 d;
assign (strong0, strong1) d = 1;
wire (supply0, supply1) e = 'z;
assign (weak0, weak1) e = 1;
always begin
if (a && !b && c === '1 && !d && e) begin
$write("*-* All Finished *-*\n");
$finish;
end
else begin
$write("Error: a = %b, b = %b, c = %b, d = %b, e = %b ", a, b, c, d, e);
$write("expected: a = 1, b = 0, c = 11, d = 0, e = 1\n");
$stop;
end
end
endmodule

View File

@ -0,0 +1,5 @@
%Error-UNSUPPORTED: t/t_strength_bufif1.v:9:11: Unsupported: Strength specifier on this gate type
9 | bufif1 (strong0, strong1) (a, 1'b1, 1'b1);
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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
scenarios(vlt => 1);
lint(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire a;
bufif1 (strong0, strong1) (a, 1'b1, 1'b1);
always begin
if (a) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -0,0 +1,14 @@
%Error-UNSUPPORTED: t/t_strength_highz.v:8:17: Unsupported: highz strength
8 | wire (weak0, highz1) a = 1;
| ^~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_strength_highz.v:9:19: Unsupported: highz strength
9 | wire (strong1, highz0) b = 0;
| ^~~~~~
%Error-UNSUPPORTED: t/t_strength_highz.v:10:10: Unsupported: highz strength
10 | wire (highz0, pull1) c = 0;
| ^~~~~~
%Error-UNSUPPORTED: t/t_strength_highz.v:11:10: Unsupported: highz strength
11 | wire (highz1, supply0) d = 1;
| ^~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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
scenarios(vlt => 1);
lint(
fails => $Self->{vlt_all},
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,19 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire (weak0, highz1) a = 1;
wire (strong1, highz0) b = 0;
wire (highz0, pull1) c = 0;
wire (highz1, supply0) d = 1;
always begin
if (a === 1'bz && b === 1'bz && c === 1'bz && d === 1'bz) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_strength_strong1_strong1_bad.v:8:19: syntax error, unexpected strong1
8 | wire (strong1, strong1) a = 1;
| ^~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,13 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire (strong1, strong1) a = 1;
initial begin
$stop;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2022 by Antmicro Ltd. 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,18 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
wire a;
nor (pull0, weak1) n1(a, 0, 0);
assign (strong0, weak1) a = 0;
always begin
if (!a) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule