From 7176aee852303843d8deee42b7d0dd9cef5c65e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 22 Apr 2020 21:31:40 -0400 Subject: [PATCH] Internals: Parse fork and delays, but then still report unsupported. --- src/V3Ast.h | 58 ++++++++++++++++++++++ src/V3AstNodes.cpp | 9 +++- src/V3AstNodes.h | 47 +++++++++++++----- src/V3Config.cpp | 4 +- src/V3EmitV.cpp | 10 ++++ src/V3LinkDot.cpp | 68 +++++++++++++------------- src/V3LinkJump.cpp | 30 ++++++------ src/V3LinkParse.cpp | 11 +++++ src/V3ParseImp.h | 1 + src/V3Width.cpp | 4 ++ src/verilog.y | 58 ++++++++++++---------- test_regress/t/t_delay_stmtdly_bad.out | 17 ++++--- test_regress/t/t_fork.out | 4 ++ test_regress/t/t_fork.pl | 19 +++++++ test_regress/t/t_fork.v | 18 +++++++ test_regress/t/t_fork_bbox.pl | 18 +++++++ test_regress/t/t_fork_bbox.v | 18 +++++++ 17 files changed, 296 insertions(+), 98 deletions(-) create mode 100644 test_regress/t/t_fork.out create mode 100755 test_regress/t/t_fork.pl create mode 100644 test_regress/t/t_fork.v create mode 100755 test_regress/t/t_fork_bbox.pl create mode 100644 test_regress/t/t_fork_bbox.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 295f30783..2fd9c30ce 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -578,6 +578,40 @@ inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { //###################################################################### +/// Join type +class VJoinType { +public: + enum en { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 }; + enum en m_e; + // CONSTRUCTOR - note defaults to *UNKNOWN* + inline VJoinType() + : m_e(JOIN) {} + // cppcheck-suppress noExplicitConstructor + inline VJoinType(en _e) + : m_e(_e) {} + explicit inline VJoinType(int _e) + : m_e(static_cast(_e)) {} + const char* ascii() const { + static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"}; + return names[m_e]; + } + const char* verilogKwd() const { + static const char* const names[] = {"join", "join_any", "join_none"}; + return names[m_e]; + } + bool join() const { return m_e == JOIN; } + bool joinAny() const { return m_e == JOIN_ANY; } + bool joinNone() const { return m_e == JOIN_NONE; } +}; +inline bool operator==(const VJoinType& lhs, const VJoinType& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) { + return os << rhs.ascii(); +} + +//###################################################################### + class AstVarType { public: enum en { @@ -1975,6 +2009,30 @@ public: virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; }; +class AstNodeBlock : public AstNode { + // A Begin/fork block + // Parents: statement + // Children: statements +private: + string m_name; // Name of block + bool m_unnamed; // Originally unnamed (name change does not affect this) +public: + AstNodeBlock(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) + : AstNode(t, fl) + , m_name(name) { + addNOp1p(stmtsp); + m_unnamed = (name == ""); + } + ASTNODE_BASE_FUNCS(NodeBlock) + virtual void dump(std::ostream& str) const; + virtual string name() const { return m_name; } // * = Block name + virtual void name(const string& name) { m_name = name; } + // op1 = Statements + AstNode* stmtsp() const { return op1p(); } // op1 = List of statements + void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + bool unnamed() const { return m_unnamed; } +}; + class AstNodePreSel : public AstNode { // Something that becomes an AstSel public: diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3f6fb3dfd..8cb89dc5e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1493,9 +1493,12 @@ void AstNodeFTask::dump(std::ostream& str) const { if (dpiOpenParent()) str << " [DPIOPENPARENT]"; if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]"; } -void AstBegin::dump(std::ostream& str) const { +void AstNodeBlock::dump(std::ostream& str) const { this->AstNode::dump(str); if (unnamed()) str << " [UNNAMED]"; +} +void AstBegin::dump(std::ostream& str) const { + this->AstNode::dump(str); if (generate()) str << " [GEN]"; if (genforp()) str << " [GENFOR]"; if (implied()) str << " [IMPLIED]"; @@ -1518,6 +1521,10 @@ void AstCoverInc::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstFork::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (!joinType().join()) str << " [" << joinType() << "]"; +} void AstTraceInc::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> "; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4c8c098a6..97014185a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3402,6 +3402,21 @@ public: AstNode* changep() const { return op3p(); } }; +class AstDelay : public AstNodeStmt { + // Delay statement +public: + AstDelay(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl) { + setOp1p(lhsp); + } + ASTNODE_NODE_FUNCS(Delay) + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + // + AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate + void lhsp(AstNode* nodep) { setOp1p(nodep); } +}; + class AstGenCase : public AstNodeCase { // Generate Case statement // Parents: {statement list} @@ -4372,42 +4387,48 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; -class AstBegin : public AstNode { +class AstBegin : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement // Children: statements private: - string m_name; // Name of block - bool m_unnamed; // Originally unnamed (name change does not affect this) bool m_generate; // Underneath a generate bool m_implied; // Not inserted by user public: // Node that simply puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, bool implied = false) - : ASTGEN_SUPER(fl) - , m_name(name) { - addNOp1p(stmtsp); - m_unnamed = (name == ""); + : ASTGEN_SUPER(fl, name, stmtsp) { m_generate = generate; m_implied = implied; } ASTNODE_NODE_FUNCS(Begin) virtual void dump(std::ostream& str) const; - virtual string name() const { return m_name; } // * = Block name - virtual void name(const string& name) { m_name = name; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } + // op1p is statements in NodeBlock AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, // might NOT be a GenFor, as loop unrolling replaces with Begin void addGenforp(AstGenFor* nodep) { addOp2p(nodep); } - bool unnamed() const { return m_unnamed; } void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } bool implied() const { return m_implied; } }; +class AstFork : public AstNodeBlock { + // A fork named block + // Parents: statement + // Children: statements +private: + VJoinType m_joinType; // Join keyword type +public: + // Node that simply puts name into the output stream + AstFork(FileLine* fl, const string& name, AstNode* stmtsp) + : ASTGEN_SUPER(fl, name, stmtsp) {} + ASTNODE_NODE_FUNCS(Fork) + virtual void dump(std::ostream& str) const; + VJoinType joinType() const { return m_joinType; } + void joinType(const VJoinType& flag) { m_joinType = flag; } +}; + class AstInitial : public AstNode { public: AstInitial(FileLine* fl, AstNode* bodysp) diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 757c8126f..eca233a8d 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -209,7 +209,7 @@ public: } } - void applyBlock(AstBegin* nodep) { + void applyBlock(AstNodeBlock* nodep) { AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF; if (!nodep->unnamed()) { for (StringSet::const_iterator it = m_coverageOffBlocks.begin(); @@ -311,7 +311,7 @@ public: m_waivers.push_back(make_pair(code, match)); } - void applyBlock(AstBegin* nodep) { + void applyBlock(AstNodeBlock* nodep) { // Apply to block at this line AstPragmaType pragma = AstPragmaType::COVERAGE_BLOCK_OFF; if (lineMatch(nodep->fileline()->lineno(), pragma)) { diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index dd7f12b0a..5b28dec41 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -79,6 +79,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { iterateChildren(nodep); puts("end\n"); } + virtual void visit(AstFork* nodep) VL_OVERRIDE { + if (nodep->name() == "") { + putbs("fork\n"); + } else { + putbs("fork : " + nodep->name() + "\n"); + } + iterateChildren(nodep); + puts(nodep->joinType().verilogKwd()); + puts("\n"); + } virtual void visit(AstFinal* nodep) VL_OVERRIDE { putfs(nodep, "final begin\n"); iterateChildren(nodep); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d5df411c5..0f0aa5ad2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -127,7 +127,7 @@ private: // AstVar::user2p() // AstFTask*. If a function variable, the task // that links to the variable // AstVar::user4() // bool. True if port set for this variable - // AstBegin::user4() // bool. Did name processing + // AstNodeBlock::user4() // bool. Did name processing // AstNodeModule::user4() // bool. Live module AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; @@ -689,13 +689,13 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* m_modSymp; // Symbol Entry for current module VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert string m_scope; // Scope text - AstBegin* m_beginp; // Current Begin/end block + AstNodeBlock* m_blockp; // Current Begin/end block AstNodeFTask* m_ftaskp; // Current function/task bool m_inRecursion; // Inside a recursive module int m_paramNum; // Parameter number, for position based connection - int m_beginNum; // Begin block number, 0=none seen + int m_blockNum; // Begin block number, 0=none seen bool m_explicitNew; // Hit a "new" function - int m_modBeginNum; // Begin block number in module, 0=none seen + int m_modBlockNum; // Begin block number in module, 0=none seen // METHODS int debug() { return LinkDotState::debug(); } @@ -780,8 +780,8 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; - int oldBeginNum = m_beginNum; - int oldModBeginNum = m_modBeginNum; + int oldBlockNum = m_blockNum; + int oldModBlockNum = m_modBlockNum; if (doit && nodep->user2()) { nodep->v3error("Unsupported: Identically recursive module (module instantiates " "itself, without changing parameters): " @@ -805,8 +805,8 @@ class LinkDotFindVisitor : public AstNVisitor { } // m_paramNum = 0; - m_beginNum = 0; - m_modBeginNum = 0; + m_blockNum = 0; + m_modBlockNum = 0; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate nodep->user2(true); @@ -826,8 +826,8 @@ class LinkDotFindVisitor : public AstNVisitor { m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; - m_beginNum = oldBeginNum; - m_modBeginNum = oldModBeginNum; + m_blockNum = oldBlockNum; + m_modBlockNum = oldModBlockNum; // Prep for next m_packagep = NULL; } @@ -838,8 +838,8 @@ class LinkDotFindVisitor : public AstNVisitor { VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; - int oldBeginNum = m_beginNum; - int oldModBeginNum = m_modBeginNum; + int oldBlockNum = m_blockNum; + int oldModBlockNum = m_modBlockNum; { UINFO(4, " Link Class: " << nodep << endl); VSymEnt* upperSymp = m_curSymp; @@ -850,8 +850,8 @@ class LinkDotFindVisitor : public AstNVisitor { UINFO(9, "New module scope " << m_curSymp << endl); // m_paramNum = 0; - m_beginNum = 0; - m_modBeginNum = 0; + m_blockNum = 0; + m_modBlockNum = 0; m_explicitNew = false; // m_modSymp/m_curSymp for non-packages set by AstCell above this module // Iterate @@ -864,8 +864,8 @@ class LinkDotFindVisitor : public AstNVisitor { m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; - m_beginNum = oldBeginNum; - m_modBeginNum = oldModBeginNum; + m_blockNum = oldBlockNum; + m_modBlockNum = oldModBlockNum; } virtual void visit(AstScope* nodep) VL_OVERRIDE { UASSERT_OBJ(m_statep->forScopeCreation(), nodep, @@ -879,7 +879,7 @@ class LinkDotFindVisitor : public AstNVisitor { iterateChildren(nodep); // Recurse in, preserving state string oldscope = m_scope; - AstBegin* oldbeginp = m_beginp; + AstNodeBlock* oldblockp = m_blockp; VSymEnt* oldModSymp = m_modSymp; VSymEnt* oldCurSymp = m_curSymp; int oldParamNum = m_paramNum; @@ -901,13 +901,13 @@ class LinkDotFindVisitor : public AstNVisitor { { m_scope = m_scope + "." + nodep->name(); m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope); - m_beginp = NULL; + m_blockp = NULL; m_inRecursion = nodep->recursive(); // We don't report NotFoundModule, as may be a unused module in a generate if (nodep->modp()) iterate(nodep->modp()); } m_scope = oldscope; - m_beginp = oldbeginp; + m_blockp = oldblockp; m_modSymp = oldModSymp; m_curSymp = oldCurSymp; m_paramNum = oldParamNum; @@ -937,13 +937,13 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->user1p(m_curSymp); iterateChildren(nodep); } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); // Rename "genblk"s to include a number if (m_statep->forPrimary() && !nodep->user4SetOnce()) { if (nodep->name() == "genblk") { - ++m_beginNum; - nodep->name(nodep->name() + cvtToStr(m_beginNum)); + ++m_blockNum; + nodep->name(nodep->name() + cvtToStr(m_blockNum)); } } // All blocks are numbered in the standard, IE we start with "genblk1" even if only one. @@ -955,8 +955,8 @@ class LinkDotFindVisitor : public AstNVisitor { // are common. for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Var)) { - ++m_modBeginNum; - nodep->name("unnamedblk" + cvtToStr(m_modBeginNum)); + ++m_modBlockNum; + nodep->name("unnamedblk" + cvtToStr(m_modBlockNum)); break; } } @@ -964,20 +964,20 @@ class LinkDotFindVisitor : public AstNVisitor { if (nodep->name() == "") { iterateChildren(nodep); } else { - int oldNum = m_beginNum; - AstBegin* oldbegin = m_beginp; + int oldNum = m_blockNum; + AstNodeBlock* oldblockp = m_blockp; VSymEnt* oldCurSymp = m_curSymp; { - m_beginNum = 0; - m_beginp = nodep; + m_blockNum = 0; + m_blockp = nodep; m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); m_curSymp->fallbackp(oldCurSymp); // Iterate iterateChildren(nodep); } m_curSymp = oldCurSymp; - m_beginp = oldbegin; - m_beginNum = oldNum; + m_blockp = oldblockp; + m_blockNum = oldNum; } } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { @@ -1249,13 +1249,13 @@ public: m_packagep = NULL; m_curSymp = m_modSymp = NULL; m_statep = statep; - m_beginp = NULL; + m_blockp = NULL; m_ftaskp = NULL; m_inRecursion = false; m_paramNum = 0; - m_beginNum = 0; + m_blockNum = 0; m_explicitNew = false; - m_modBeginNum = 0; + m_modBlockNum = 0; // iterate(rootp); } @@ -2546,7 +2546,7 @@ private: // checkNoDot not appropriate, can be under a dot iterateChildren(nodep); } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VSymEnt* oldCurSymp = m_curSymp; diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 4cbb97210..097cdbc9a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -38,7 +38,7 @@ class LinkJumpVisitor : public AstNVisitor { private: // TYPES - typedef std::vector BeginStack; + typedef std::vector BlockStack; // STATE AstNodeModule* m_modp; // Current module @@ -46,7 +46,7 @@ private: AstWhile* m_loopp; // Current loop bool m_loopInc; // In loop increment int m_modRepeatNum; // Repeat counter - BeginStack m_beginStack; // All begin blocks above current node + BlockStack m_blockStack; // All begin blocks above current node // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -58,8 +58,8 @@ private: AstNode* underp = NULL; bool under_and_next = true; - if (VN_IS(nodep, Begin)) { - underp = VN_CAST(nodep, Begin)->stmtsp(); + if (VN_IS(nodep, NodeBlock)) { + underp = VN_CAST(nodep, NodeBlock)->stmtsp(); } else if (VN_IS(nodep, NodeFTask)) { underp = VN_CAST(nodep, NodeFTask)->stmtsp(); } else if (VN_IS(nodep, While)) { @@ -123,11 +123,11 @@ private: iterateChildren(nodep); m_ftaskp = NULL; } - virtual void visit(AstBegin* nodep) VL_OVERRIDE { + virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(8, " " << nodep << endl); - m_beginStack.push_back(nodep); + m_blockStack.push_back(nodep); iterateChildren(nodep); - m_beginStack.pop_back(); + m_blockStack.pop_back(); } virtual void visit(AstRepeat* nodep) VL_OVERRIDE { // So later optimizations don't need to deal with them, @@ -223,22 +223,24 @@ private: virtual void visit(AstDisable* nodep) VL_OVERRIDE { UINFO(8, " DISABLE " << nodep << endl); iterateChildren(nodep); - AstBegin* beginp = NULL; - for (BeginStack::reverse_iterator it = m_beginStack.rbegin(); it != m_beginStack.rend(); + AstNodeBlock* blockp = NULL; + for (BlockStack::reverse_iterator it = m_blockStack.rbegin(); it != m_blockStack.rend(); ++it) { UINFO(9, " UNDERBLK " << *it << endl); if ((*it)->name() == nodep->name()) { - beginp = *it; + blockp = *it; break; } } - // if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labeli: "); } - if (!beginp) { + // if (debug() >= 9) { UINFO(0, "\n"); blockp->dumpTree(cout, " labeli: "); } + if (!blockp) { nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ()); - } else { - // Jump to the end of the named begin + } else if (AstBegin* beginp = VN_CAST(blockp, Begin)) { + // Jump to the end of the named block AstJumpLabel* labelp = findAddLabel(beginp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); + } else { + nodep->v3error("Unsupported: disable fork"); } nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index c5b1a89c7..ad875a432 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -491,6 +491,17 @@ private: } iterateChildren(nodep); } + virtual void visit(AstFork* nodep) VL_OVERRIDE { + if (v3Global.opt.bboxUnsup()) { + AstBegin* newp + = new AstBegin(nodep->fileline(), nodep->name(), nodep->stmtsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { + nodep->v3error("Unsupported: fork statements"); + // TBD might support only normal join, if so complain about other join flavors + } + } virtual void visit(AstCase* nodep) VL_OVERRIDE { V3Config::applyCase(nodep); cleanFileline(nodep); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 6c8fdafc0..1a079b604 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -69,6 +69,7 @@ struct V3ParseBisonYYSType { AstCell* cellp; AstClass* classp; AstConst* constp; + AstFork* forkp; AstMemberDType* memberp; AstNodeModule* modulep; AstNodeUOrStructDType* uorstructp; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 49762c4c1..36ff94be0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -538,6 +538,10 @@ private: } } } + virtual void visit(AstDelay* nodep) VL_OVERRIDE { + nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + } virtual void visit(AstToLowerN* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); diff --git a/src/verilog.y b/src/verilog.y index 0c261d185..4f6d2bd43 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -790,6 +790,10 @@ class AstSenTree; // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -2274,31 +2278,31 @@ assignOne: delayE: /* empty */ { } - | delay_control { $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); } /* ignored */ + | delay_control { $1->v3warn(ASSIGNDLY,"Unsupported: Ignoring delay on this assignment/primitive."); DEL($1); } /* ignored */ ; -delay_control: //== IEEE: delay_control - '#' delay_value { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ')' { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ - | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $1; } /* ignored */ +delay_control: //== IEEE: delay_control + '#' delay_value { $$ = $2; } + | '#' '(' minTypMax ')' { $$ = $3; } + | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); } + | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); DEL($7); } ; -delay_value: // ==IEEE:delay_value +delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier - ps_id_etc { } - | yaINTNUM { } - | yaFLOATNUM { } - | timeNumAdjusted { DEL($1); } + ps_id_etc { $$ = $1; } + | yaINTNUM { $$ = new AstConst($1, *$1); } + | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } + | timeNumAdjusted { $$ = $1; } ; -delayExpr: - expr { DEL($1); } +delayExpr: + expr { $$ = $1; } ; -minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression - delayExpr { } - | delayExpr ':' delayExpr ':' delayExpr { } +minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression + delayExpr { $$ = $1; } + | delayExpr ':' delayExpr ':' delayExpr { $$ = $1; DEL($3); DEL($5); } ; netSigList: // IEEE: list_of_port_identifiers @@ -2657,21 +2661,27 @@ seq_block: // ==IEEE: seq_block par_block: // ==IEEE: par_block par_blockFront blockDeclStmtList yJOIN endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } | par_blockFront blockDeclStmtList yJOIN_ANY endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_ANY); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN_ANY endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN_ANY); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } | par_blockFront blockDeclStmtList yJOIN_NONE endLabelE { $$ = $1; $1->addStmtsp($2); + $1->joinType(VJoinType::JOIN_NONE); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront /**/ yJOIN_NONE endLabelE { $$ = $1; + $1->joinType(VJoinType::JOIN_NONE); SYMP->popScope($1); GRAMMARP->endLabel($3, $1, $3); } ; @@ -2680,13 +2690,9 @@ seq_blockFront: // IEEE: part of seq_block | yBEGIN ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, NULL); SYMP->pushNew($$); } ; -par_blockFront: // IEEE: part of par_block - yFORK { $$ = new AstBegin($1, "", NULL); SYMP->pushNew($$); - BBUNSUP($1, "Unsupported: fork statements"); - // When support, record or BBUNSUP yJOIN_ANY/yJOIN_NONE - } - | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstBegin($3, *$3, NULL); SYMP->pushNew($$); - BBUNSUP($1, "Unsupported: fork statements"); } +par_blockFront: // IEEE: part of par_block + yFORK { $$ = new AstFork($1, "", NULL); SYMP->pushNew($$); } + | yFORK ':' idAny/*new-block_identifier*/ { $$ = new AstFork($3, *$3, NULL); SYMP->pushNew($$); } ; blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } @@ -2831,7 +2837,7 @@ statement_item: // IEEE: statement_item // | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control - | delay_control stmtBlock { $$ = $2; $1->v3warn(STMTDLY,"Unsupported: Ignoring delay on this delayed statement."); } + | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } //UNSUP event_control stmtBlock { UNSUP } //UNSUP cycle_delay stmtBlock { UNSUP } // @@ -5521,8 +5527,8 @@ classImplementsList: // IEEE: part of class_declaration // must be included in the rules below. // Each of these must end with {symsPackageDone | symsClassDone} -ps_id_etc: // package_scope + general id - package_scopeIdFollowsE id { } +ps_id_etc: // package_scope + general id + package_scopeIdFollowsE varRefBase { $$ = $2; $2->packagep($1); } ; ps_type: // IEEE: ps_parameter_identifier | ps_type_identifier diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index 5e1f99423..f52d97869 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,14 +1,15 @@ -%Warning-ASSIGNDLY: t/t_delay.v:20:11: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:20:13: Unsupported: Ignoring delay on this assignment/primitive. 20 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; - | ^ + | ^~~~~~~~~~~~~~~~~~ ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_delay.v:25:18: Unsupported: Ignoring delay on this assignment/primitive. +%Warning-ASSIGNDLY: t/t_delay.v:25:19: Unsupported: Ignoring delay on this assignment/primitive. 25 | dly0 <= #0 32'h11; - | ^ -%Warning-ASSIGNDLY: t/t_delay.v:28:18: Unsupported: Ignoring delay on this assignment/primitive. + | ^ +%Warning-ASSIGNDLY: t/t_delay.v:28:19: Unsupported: Ignoring delay on this assignment/primitive. 28 | dly0 <= #0.12 dly0 + 32'h12; - | ^ -%Warning-STMTDLY: t/t_delay.v:34:10: Unsupported: Ignoring delay on this delayed statement. + | ^~~~ +%Warning-STMTDLY: t/t_delay.v:34:11: Unsupported: Ignoring delay on this delayed statement. + : ... In instance t 34 | #100 $finish; - | ^ + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out new file mode 100644 index 000000000..1f9b98a83 --- /dev/null +++ b/test_regress/t/t_fork.out @@ -0,0 +1,4 @@ +%Error: t/t_fork.v:10:14: Unsupported: fork statements + 10 | fork : fblk + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_fork.pl b/test_regress/t/t_fork.pl new file mode 100755 index 000000000..ac387c7d9 --- /dev/null +++ b/test_regress/t/t_fork.pl @@ -0,0 +1,19 @@ +#!/usr/bin/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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork.v b/test_regress/t/t_fork.v new file mode 100644 index 000000000..06f9ed036 --- /dev/null +++ b/test_regress/t/t_fork.v @@ -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, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + fork : fblk + begin + $write("*-* All Finished *-*\n"); + $finish; + end + join : fblk + end + +endmodule diff --git a/test_regress/t/t_fork_bbox.pl b/test_regress/t/t_fork_bbox.pl new file mode 100755 index 000000000..4bf13ff24 --- /dev/null +++ b/test_regress/t/t_fork_bbox.pl @@ -0,0 +1,18 @@ +#!/usr/bin/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( + verilator_flags2 => ['--lint-only --bbox-unsup'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_bbox.v b/test_regress/t/t_fork_bbox.v new file mode 100644 index 000000000..06f9ed036 --- /dev/null +++ b/test_regress/t/t_fork_bbox.v @@ -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, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + fork : fblk + begin + $write("*-* All Finished *-*\n"); + $finish; + end + join : fblk + end + +endmodule