diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 87d0c7cc4..f97178956 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -134,6 +134,7 @@ Krzysztof Boronski Krzysztof Boroński Krzysztof Obłonczek Krzysztof Starecki +Krzysztof Sychla Kuba Ober Larry Doolittle Liam Braun diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index dd56e2ce7..5c6611056 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -3339,6 +3339,24 @@ public: int instrCount() const override { return INSTR_COUNT_PLI; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; +class AstSetuphold final : public AstNodeStmt { + // Verilog $setuphold + // @astgen op1 := refevp : AstSenItem + // @astgen op2 := dataevp : AstSenItem + // @astgen op3 := delrefp : Optional[AstSenItem] + // @astgen op4 := deldatap : Optional[AstSenItem] +public: + AstSetuphold(FileLine* fl, AstSenItem* refevp, AstSenItem* dataevp, + AstSenItem* delrefp = nullptr, AstSenItem* deldatap = nullptr) + : ASTGEN_SUPER_Setuphold(fl) { + this->refevp(refevp); + this->dataevp(dataevp); + this->delrefp(delrefp); + this->deldatap(deldatap); + } + ASTGEN_MEMBERS_AstSetuphold; + bool sameNode(const AstNode* /*samep*/) const override { return true; } +}; class AstStackTraceT final : public AstNodeStmt { // $stacktrace used as task public: diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 43b0715eb..786eb321b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1377,6 +1377,33 @@ class WidthVisitor final : public VNVisitor { } } + void visit(AstSetuphold* nodep) override { + FileLine* const flp = nodep->fileline(); + + AstAssignW* newp = nullptr; + + if (nodep->delrefp() != nullptr) { + AstNodeVarRef* lhsp = nodep->delrefp()->varrefp()->cloneTreePure(false); + lhsp->access(VAccess::WRITE); + AstNodeVarRef* rhsp = nodep->refevp()->varrefp()->cloneTreePure(false); + newp = new AstAssignW{flp, lhsp, rhsp}; + } + + if (nodep->deldatap() != nullptr) { + AstNodeVarRef* lhsp = nodep->deldatap()->varrefp()->cloneTreePure(false); + lhsp->access(VAccess::WRITE); + AstNodeVarRef* rhsp = nodep->dataevp()->varrefp()->cloneTreePure(false); + + if (newp == nullptr) { + newp = new AstAssignW{flp, lhsp, rhsp}; + } else { + newp->addNextHere(new AstAssignW{flp, lhsp, rhsp}); + } + } + + nodep->replaceWith(newp); + } + void visit(AstStable* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); diff --git a/src/verilog.l b/src/verilog.l index 11b606307..e1465ffcd 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -271,7 +271,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$rtoi" { FL; return yD_RTOI; } "$sampled" { FL; return yD_SAMPLED; } "$setup" { FL; return yaTIMINGSPEC; } - "$setuphold" { FL; return yaTIMINGSPEC; } + "$setuphold" { FL; return yD_SETUPHOLD; } "$sformat" { FL; return yD_SFORMAT; } "$sformatf" { FL; return yD_SFORMATF; } "$shortrealtobits" { FL; return yD_SHORTREALTOBITS; } diff --git a/src/verilog.y b/src/verilog.y index 543492cbe..fc494803c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -916,6 +916,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_ROSE_GCLK "$rose_gclk" %token yD_RTOI "$rtoi" %token yD_SAMPLED "$sampled" +%token yD_SETUPHOLD "$setuphold" %token yD_SFORMAT "$sformat" %token yD_SFORMATF "$sformatf" %token yD_SHORTREALTOBITS "$shortrealtobits" @@ -3110,6 +3111,11 @@ minTypMax: // IEEE: mintypmax_expression and constant_minty | delayExpr ':' delayExpr ':' delayExpr { $$ = $3; MINTYPMAXDLYUNSUP($3); DEL($1); DEL($5); } ; +minTypMaxE: + /*empty*/ { $$ = nullptr; } + | minTypMax { $$ = $1; } + ; + netSigList: // IEEE: list_of_port_identifiers netSig { $$ = $1; } | netSigList ',' netSig { $$ = $1; $1->addNext($3); } @@ -5759,10 +5765,26 @@ tableEntry: // IEEE: combinational_entry + sequential_entry // Specify specify_block: // ==IEEE: specify_block - ySPECIFY specifyJunkList yENDSPECIFY { $$ = nullptr; } + ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ')' ';' yENDSPECIFY { $$ = nullptr; } + | ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ',' idAnyE ')' ';' yENDSPECIFY { $$ = nullptr; } + | ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ',' idAnyE ',' minTypMaxE ')' ';' yENDSPECIFY { $$ = nullptr; } + | ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ',' idAnyE ',' minTypMaxE ',' minTypMaxE ')' ';' yENDSPECIFY { $$ = nullptr; } + | ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' senitemE ')' ';' yENDSPECIFY { $$ = new AstSetuphold{$2, $4, $6, $18}; } + | ySPECIFY yD_SETUPHOLD '(' senitem ',' senitem ',' expr ',' expr ',' idAnyE ',' minTypMaxE ',' minTypMaxE ',' senitemE ',' senitemE ')' ';' yENDSPECIFY { $$ = new AstSetuphold{$2, $4, $6, $18, $20}; } | ySPECIFY yENDSPECIFY { $$ = nullptr; } ; +idAnyE: + /*empty*/ { $$ = nullptr; } + | idAny { $$ = $1; } + ; + +senitemE: + /*empty*/ { $$ = nullptr; } + | senitem { $$ = $1; } + ; + + specifyJunkList: specifyJunk { } /* ignored */ | specifyJunkList specifyJunk { } /* ignored */