Internals: Refactor generate construct Ast handling (#6280) (#6470)

Internals: Refactor generate construct Ast handling (#6280)

We introduce AstNodeGen, the common base class of AstGenBlock,
AstGenCase, AstGenFor, and AstGenIf, which together represent all SV
generate constructs. Subsequently remove AstNodeFor, AstNodeCase
(AstCase is now directly derived from AstNodeStmt) and adjust internals
to work on the new representation.

Output is identical modulo hashes do to changed AstNode type ids, no
functional change intended.

Step towards #6280.
This commit is contained in:
Geza Lore 2025-09-23 20:49:01 +02:00 committed by GitHub
parent df187c4406
commit 800af37975
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 687 additions and 517 deletions

View File

@ -129,7 +129,7 @@ class AssertVisitor final : public VNVisitor {
// STATE // STATE
AstNodeModule* m_modp = nullptr; // Last module AstNodeModule* m_modp = nullptr; // Last module
const AstBegin* m_beginp = nullptr; // Last begin const AstNode* m_beginp = nullptr; // Last AstBegin/AstGenBlock
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module) unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
@ -809,6 +809,13 @@ class AssertVisitor final : public VNVisitor {
m_procedurep = nodep; m_procedurep = nodep;
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstGenBlock* nodep) override {
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
VL_RESTORER(m_beginp);
m_beginp = nodep;
iterateChildren(nodep);
}
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// This code is needed rather than a visitor in V3Begin, // This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin // because V3Assert is called before V3Begin

View File

@ -349,7 +349,7 @@ private:
nodep->findBasicDType(VBasicDTypeKwd::UINT32)}; nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
cntVarp->funcLocal(true); cntVarp->funcLocal(true);
AstBegin* const beginp = new AstBegin{flp, delayName + "__block", cntVarp, false, true}; AstBegin* const beginp = new AstBegin{flp, delayName + "__block", cntVarp, true};
beginp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, cntVarp, VAccess::WRITE}, valuep}); beginp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, cntVarp, VAccess::WRITE}, valuep});
beginp->addStmtsp(new AstWhile{ beginp->addStmtsp(new AstWhile{
nodep->fileline(), nodep->fileline(),

View File

@ -1078,8 +1078,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(VNVisitor& v) {
} else if (!nodep->backp()) { } else if (!nodep->backp()) {
// Calling on standalone tree; insert a shim node so we can keep // Calling on standalone tree; insert a shim node so we can keep
// track, then delete it on completion // track, then delete it on completion
AstBegin* const tempp AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false};
= new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false, false};
// nodep to null as may be replaced // nodep to null as may be replaced
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep);
nodep = tempp->stmtsp()->unlinkFrBackWithNext(); nodep = tempp->stmtsp()->unlinkFrBackWithNext();

View File

@ -267,6 +267,13 @@ public:
string name() const override VL_MT_STABLE { return m_name; } string name() const override VL_MT_STABLE { return m_name; }
bool sameNode(const AstNode* /*samep*/) const override { return true; } bool sameNode(const AstNode* /*samep*/) const override { return true; }
}; };
class AstNodeGen VL_NOT_FINAL : public AstNode {
// Generate construct
public:
AstNodeGen(VNType t, FileLine* fl)
: AstNode{t, fl} {}
ASTGEN_MEMBERS_AstNodeGen;
};
class AstNodeModule VL_NOT_FINAL : public AstNode { class AstNodeModule VL_NOT_FINAL : public AstNode {
// A module, package, program or interface declaration; // A module, package, program or interface declaration;
// something that can live directly under the TOP, // something that can live directly under the TOP,
@ -668,21 +675,6 @@ public:
string name() const override VL_MT_STABLE { return m_name; } string name() const override VL_MT_STABLE { return m_name; }
VUseType useType() const { return m_useType; } VUseType useType() const { return m_useType; }
}; };
class AstCaseItem final : public AstNode {
// Single item of a case statement
// @astgen op1 := condsp : List[AstNodeExpr]
// @astgen op2 := stmtsp : List[AstNode]
public:
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
: ASTGEN_SUPER_CaseItem(fl) {
addCondsp(condsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCaseItem;
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
bool isDefault() const { return condsp() == nullptr; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
class AstCell final : public AstNode { class AstCell final : public AstNode {
// A instantiation cell or interface call (don't know which until link) // A instantiation cell or interface call (don't know which until link)
// @astgen op1 := pinsp : List[AstPin] // List of port assignments // @astgen op1 := pinsp : List[AstPin] // List of port assignments
@ -1137,6 +1129,19 @@ public:
V3Graph* depGraphp() { return m_depGraphp; } V3Graph* depGraphp() { return m_depGraphp; }
const V3Graph* depGraphp() const { return m_depGraphp; } const V3Graph* depGraphp() const { return m_depGraphp; }
}; };
class AstGenCaseItem final : public AstNode {
// Single item of an AstGenCase
// @astgen op1 := condsp : List[AstNodeExpr]
// @astgen op2 := itemsp : List[AstNode]
public:
AstGenCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* itemsp)
: ASTGEN_SUPER_GenCaseItem(fl) {
addCondsp(condsp);
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstGenCaseItem;
bool isDefault() const { return condsp() == nullptr; }
};
class AstImplicit final : public AstNode { class AstImplicit final : public AstNode {
// Create implicit wires and do nothing else, for gates that are ignored // Create implicit wires and do nothing else, for gates that are ignored
// Parents: MODULE // Parents: MODULE
@ -2287,22 +2292,18 @@ public:
class AstBegin final : public AstNodeBlock { class AstBegin final : public AstNodeBlock {
// A Begin/end named block, only exists shortly after parsing until linking // A Begin/end named block, only exists shortly after parsing until linking
// Parents: statement // Parents: statement
// @astgen op1 := genforp : Optional[AstNode]
const bool m_generate : 1; // Underneath a generate
bool m_needProcess : 1; // Uses VlProcess bool m_needProcess : 1; // Uses VlProcess
const bool m_implied : 1; // Not inserted by user const bool m_implied : 1; // Not inserted by user
public: public:
// Node that puts name into the output stream // Node that puts name into the output stream
AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate, bool implied) AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool implied)
: ASTGEN_SUPER_Begin(fl, name, stmtsp) : ASTGEN_SUPER_Begin(fl, name, stmtsp)
, m_generate{generate}
, m_needProcess{false} , m_needProcess{false}
, m_implied{implied} {} , m_implied{implied} {}
ASTGEN_MEMBERS_AstBegin; ASTGEN_MEMBERS_AstBegin;
void dump(std::ostream& str) const override; void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override; void dumpJson(std::ostream& str) const override;
bool generate() const { return m_generate; }
void setNeedProcess() { m_needProcess = true; } void setNeedProcess() { m_needProcess = true; }
bool needProcess() const { return m_needProcess; } bool needProcess() const { return m_needProcess; }
bool implied() const { return m_implied; } bool implied() const { return m_implied; }
@ -2463,6 +2464,74 @@ public:
void dumpJson(std::ostream& str = std::cout) const override; void dumpJson(std::ostream& str = std::cout) const override;
}; };
// === AstNodeGen ===
class AstGenBlock final : public AstNodeGen {
// Generate 'begin'
// @astgen op1 := genforp : Optional[AstNode]
// @astgen op2 := itemsp : List[AstNode]
std::string m_name; // Name of block
const bool m_unnamed; // Originally unnamed (name change does not affect this)
const bool m_implied; // Not inserted by user
public:
AstGenBlock(FileLine* fl, const string& name, AstNode* itemsp, bool implied)
: ASTGEN_SUPER_GenBlock(fl)
, m_name{name}
, m_unnamed{name.empty()}
, m_implied{implied} {
this->addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstGenBlock;
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
std::string name() const override VL_MT_STABLE { return m_name; }
void name(const std::string& name) override { m_name = name; }
bool unnamed() const { return m_unnamed; }
bool implied() const { return m_implied; }
};
class AstGenCase final : public AstNodeGen {
// Generate 'case'
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstGenCaseItem]
public:
AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstGenCaseItem* itemsp)
: ASTGEN_SUPER_GenCase(fl) {
this->exprp(exprp);
this->addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstGenCase;
};
class AstGenFor final : public AstNodeGen {
// Generate 'for'
// @astgen op1 := initsp : List[AstNode]
// @astgen op2 := condp : AstNodeExpr
// @astgen op3 := incsp : List[AstNode]
// @astgen op4 := itemsp : List[AstNode]
public:
AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* itemsp)
: ASTGEN_SUPER_GenFor(fl) {
this->addInitsp(initsp);
this->condp(condp);
this->addIncsp(incsp);
this->addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstGenFor;
};
class AstGenIf final : public AstNodeGen {
// Generate 'if'
// @astgen op1 := condp : AstNodeExpr
// @astgen op2 := thensp : List[AstNode]
// @astgen op3 := elsesp : List[AstNode]
public:
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: ASTGEN_SUPER_GenIf(fl) {
this->condp(condp);
this->addThensp(thensp);
this->addElsesp(elsesp);
}
ASTGEN_MEMBERS_AstGenIf;
};
// === AstNodeModule === // === AstNodeModule ===
class AstClass final : public AstNodeModule { class AstClass final : public AstNodeModule {
// @astgen op4 := extendsp : List[AstClassExtends] // @astgen op4 := extendsp : List[AstClassExtends]

View File

@ -70,21 +70,6 @@ public:
bool isTimingControl() const override { return timingControlp(); } bool isTimingControl() const override { return timingControlp(); }
virtual bool brokeLhsMustBeLvalue() const = 0; virtual bool brokeLhsMustBeLvalue() const = 0;
}; };
class AstNodeCase VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstCaseItem]
// @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's
protected:
AstNodeCase(VNType t, FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: AstNodeStmt{t, fl} {
this->exprp(exprp);
addItemsp(itemsp);
}
public:
ASTGEN_MEMBERS_AstNodeCase;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
};
class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt {
// Cover or Assert // Cover or Assert
// Parents: {statement list} // Parents: {statement list}
@ -121,27 +106,6 @@ public:
|| this->type() == VAssertType::INTERNAL; || this->type() == VAssertType::INTERNAL;
} }
}; };
class AstNodeFor VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := initsp : List[AstNode]
// @astgen op2 := condp : AstNodeExpr
// @astgen op3 := incsp : List[AstNode]
// @astgen op4 := stmtsp : List[AstNode]
protected:
AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp,
AstNode* stmtsp)
: AstNodeStmt{t, fl} {
addInitsp(initsp);
this->condp(condp);
addIncsp(incsp);
addStmtsp(stmtsp);
}
public:
ASTGEN_MEMBERS_AstNodeFor;
bool isGateOptimizable() const override { return false; }
int instrCount() const override { return INSTR_COUNT_BRANCH; }
bool sameNode(const AstNode* /*samep*/) const override { return true; }
};
class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt { class AstNodeForeach VL_NOT_FINAL : public AstNodeStmt {
// @astgen op1 := arrayp : AstNode // @astgen op1 := arrayp : AstNode
// @astgen op2 := stmtsp : List[AstNode] // @astgen op2 := stmtsp : List[AstNode]
@ -218,6 +182,23 @@ public:
// === Concrete node types ===================================================== // === Concrete node types =====================================================
// === AstNode ===
class AstCaseItem final : public AstNode {
// Single item of AstCase/AstRandCase
// @astgen op1 := condsp : List[AstNodeExpr]
// @astgen op2 := stmtsp : List[AstNode]
public:
AstCaseItem(FileLine* fl, AstNodeExpr* condsp, AstNode* stmtsp)
: ASTGEN_SUPER_CaseItem(fl) {
addCondsp(condsp);
addStmtsp(stmtsp);
}
ASTGEN_MEMBERS_AstCaseItem;
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
bool isDefault() const { return condsp() == nullptr; }
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
};
// === AstNodeStmt === // === AstNodeStmt ===
class AstAssertCtl final : public AstNodeStmt { class AstAssertCtl final : public AstNodeStmt {
// @astgen op1 := controlTypep : AstNodeExpr // @astgen op1 := controlTypep : AstNodeExpr
@ -306,6 +287,47 @@ public:
bool isPredictOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; }
bool sameNode(const AstNode* /*samep*/) const override { return true; } bool sameNode(const AstNode* /*samep*/) const override { return true; }
}; };
class AstCase final : public AstNodeStmt {
// Case statement
// @astgen op1 := exprp : AstNodeExpr // Condition (scurtinee) expression
// @astgen op2 := itemsp : List[AstCaseItem]
// @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's
VCaseType m_casex; // 0=case, 1=casex, 2=casez
bool m_fullPragma = false; // Synthesis full_case
bool m_parallelPragma = false; // Synthesis parallel_case
bool m_uniquePragma = false; // unique case
bool m_unique0Pragma = false; // unique0 case
bool m_priorityPragma = false; // priority case
public:
AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp)
: ASTGEN_SUPER_Case(fl)
, m_casex{casex} {
this->exprp(exprp);
addItemsp(itemsp);
}
ASTGEN_MEMBERS_AstCase;
int instrCount() const override { return INSTR_COUNT_BRANCH; }
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
bool sameNode(const AstNode* samep) const override {
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
}
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; }
bool caseSimple() const { return m_casex == VCaseType::CT_CASE; }
void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; }
bool fullPragma() const { return m_fullPragma; }
void fullPragma(bool flag) { m_fullPragma = flag; }
bool parallelPragma() const { return m_parallelPragma; }
void parallelPragma(bool flag) { m_parallelPragma = flag; }
bool uniquePragma() const { return m_uniquePragma; }
void uniquePragma(bool flag) { m_uniquePragma = flag; }
bool unique0Pragma() const { return m_unique0Pragma; }
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
bool priorityPragma() const { return m_priorityPragma; }
void priorityPragma(bool flag) { m_priorityPragma = flag; }
string pragmaString() const;
};
class AstComment final : public AstNodeStmt { class AstComment final : public AstNodeStmt {
// Some comment to put into the output stream // Some comment to put into the output stream
const string m_name; // Text of comment const string m_name; // Text of comment
@ -1130,49 +1152,6 @@ public:
AstAlways* convertToAlways(); AstAlways* convertToAlways();
}; };
// === AstNodeCase ===
class AstCase final : public AstNodeCase {
// Case statement
VCaseType m_casex; // 0=case, 1=casex, 2=casez
bool m_fullPragma = false; // Synthesis full_case
bool m_parallelPragma = false; // Synthesis parallel_case
bool m_uniquePragma = false; // unique case
bool m_unique0Pragma = false; // unique0 case
bool m_priorityPragma = false; // priority case
public:
AstCase(FileLine* fl, VCaseType casex, AstNodeExpr* exprp, AstCaseItem* itemsp)
: ASTGEN_SUPER_Case(fl, exprp, itemsp)
, m_casex{casex} {}
ASTGEN_MEMBERS_AstCase;
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
bool sameNode(const AstNode* samep) const override {
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
}
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; }
bool caseSimple() const { return m_casex == VCaseType::CT_CASE; }
void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; }
bool fullPragma() const { return m_fullPragma; }
void fullPragma(bool flag) { m_fullPragma = flag; }
bool parallelPragma() const { return m_parallelPragma; }
void parallelPragma(bool flag) { m_parallelPragma = flag; }
bool uniquePragma() const { return m_uniquePragma; }
void uniquePragma(bool flag) { m_uniquePragma = flag; }
bool unique0Pragma() const { return m_unique0Pragma; }
void unique0Pragma(bool flag) { m_unique0Pragma = flag; }
bool priorityPragma() const { return m_priorityPragma; }
void priorityPragma(bool flag) { m_priorityPragma = flag; }
string pragmaString() const;
};
class AstGenCase final : public AstNodeCase {
// Generate Case statement
public:
AstGenCase(FileLine* fl, AstNodeExpr* exprp, AstCaseItem* itemsp)
: ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {}
ASTGEN_MEMBERS_AstGenCase;
};
// === AstNodeCoverOrAssert === // === AstNodeCoverOrAssert ===
class AstAssert final : public AstNodeCoverOrAssert { class AstAssert final : public AstNodeCoverOrAssert {
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey // @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
@ -1215,14 +1194,6 @@ public:
VAssertDirectiveType::RESTRICT) {} VAssertDirectiveType::RESTRICT) {}
}; };
// === AstNodeFor ===
class AstGenFor final : public AstNodeFor {
public:
AstGenFor(FileLine* fl, AstNode* initsp, AstNodeExpr* condp, AstNode* incsp, AstNode* stmtsp)
: ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {}
ASTGEN_MEMBERS_AstGenFor;
};
// === AstNodeForeach === // === AstNodeForeach ===
class AstConstraintForeach final : public AstNodeForeach { class AstConstraintForeach final : public AstNodeForeach {
// Constraint foreach statement // Constraint foreach statement
@ -1245,12 +1216,7 @@ public:
: ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {} : ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstConstraintIf; ASTGEN_MEMBERS_AstConstraintIf;
}; };
class AstGenIf final : public AstNodeIf {
public:
AstGenIf(FileLine* fl, AstNodeExpr* condp, AstNode* thensp, AstNode* elsesp)
: ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {}
ASTGEN_MEMBERS_AstGenIf;
};
class AstIf final : public AstNodeIf { class AstIf final : public AstNodeIf {
bool m_uniquePragma = false; // unique case bool m_uniquePragma = false; // unique case
bool m_unique0Pragma = false; // unique0 case bool m_unique0Pragma = false; // unique0 case

View File

@ -1928,6 +1928,18 @@ const char* AstEnumDType::broken() const {
} }
void AstEnumItemRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); } void AstEnumItemRef::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
void AstGenBlock::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (implied()) str << " [IMPLIED]";
if (unnamed()) str << " [UNNAMED]";
}
void AstGenBlock::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, implied);
dumpJsonBoolFunc(str, unnamed);
dumpJsonGen(str);
}
void AstIfaceRefDType::dump(std::ostream& str) const { void AstIfaceRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
if (isPortDecl()) str << " [PORTDECL]"; if (isPortDecl()) str << " [PORTDECL]";
@ -2941,14 +2953,10 @@ void AstNodeBlock::dumpJson(std::ostream& str) const {
} }
void AstBegin::dump(std::ostream& str) const { void AstBegin::dump(std::ostream& str) const {
this->AstNodeBlock::dump(str); this->AstNodeBlock::dump(str);
if (generate()) str << " [GEN]";
if (genforp()) str << " [GENFOR]";
if (implied()) str << " [IMPLIED]"; if (implied()) str << " [IMPLIED]";
if (needProcess()) str << " [NPRC]"; if (needProcess()) str << " [NPRC]";
} }
void AstBegin::dumpJson(std::ostream& str) const { void AstBegin::dumpJson(std::ostream& str) const {
dumpJsonBoolFunc(str, generate);
dumpJsonBool(str, "genfor", bool(genforp()));
dumpJsonBoolFunc(str, implied); dumpJsonBoolFunc(str, implied);
dumpJsonBoolFunc(str, needProcess); dumpJsonBoolFunc(str, needProcess);
dumpJsonGen(str); dumpJsonGen(str);
@ -3258,7 +3266,7 @@ AstAlways* AstAssignW::convertToAlways() {
if (hasTimingControl) { if (hasTimingControl) {
// If there's a timing control, put the assignment in a fork..join_none. This process won't // If there's a timing control, put the assignment in a fork..join_none. This process won't
// get marked as suspendable and thus will be scheduled normally // get marked as suspendable and thus will be scheduled normally
AstBegin* const beginp = new AstBegin{flp, "", bodysp, false, false}; AstBegin* const beginp = new AstBegin{flp, "", bodysp, false};
AstFork* const forkp = new AstFork{flp, "", beginp}; AstFork* const forkp = new AstFork{flp, "", beginp};
forkp->joinType(VJoinType::JOIN_NONE); forkp->joinType(VJoinType::JOIN_NONE);
bodysp = forkp; bodysp = forkp;

View File

@ -73,31 +73,32 @@ class BeginVisitor final : public VNVisitor {
string dot(const string& a, const string& b) { return VString::dot(a, "__DOT__", b); } string dot(const string& a, const string& b) { return VString::dot(a, "__DOT__", b); }
void dotNames(const AstNodeBlock* const nodep, const char* const blockName) { void dotNames(const std::string& name, FileLine* const flp, AstNode* stmtsp,
const char* const blockName) {
UINFO(8, "nname " << m_namedScope); UINFO(8, "nname " << m_namedScope);
if (nodep->name() != "") { // Else unneeded unnamed block if (name != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution // Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found string dottedname = name + "__DOT__"; // So always found
string::size_type pos; string::size_type pos;
while ((pos = dottedname.find("__DOT__")) != string::npos) { while ((pos = dottedname.find("__DOT__")) != string::npos) {
const string ident = dottedname.substr(0, pos); const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + std::strlen("__DOT__")); dottedname = dottedname.substr(pos + std::strlen("__DOT__"));
if (nodep->name() != "") { if (name != "") {
m_displayScope = dot(m_displayScope, ident); m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident); m_namedScope = dot(m_namedScope, ident);
} }
m_unnamedScope = dot(m_unnamedScope, ident); m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution // Create CellInline for dotted var resolution
if (!m_ftaskp) { if (!m_ftaskp) {
AstCellInline* const inlinep = new AstCellInline{ AstCellInline* const inlinep
nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit()}; = new AstCellInline{flp, m_unnamedScope, blockName, m_modp->timeunit()};
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
} }
} }
} }
// Remap var names and replace lower Begins // Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(stmtsp);
} }
void liftNode(AstNode* nodep) { void liftNode(AstNode* nodep) {
@ -125,14 +126,13 @@ class BeginVisitor final : public VNVisitor {
// replaced with multiple statements) // replaced with multiple statements)
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (!VN_IS(stmtp, Begin)) { if (!VN_IS(stmtp, Begin)) {
AstBegin* const beginp AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr, false};
= new AstBegin{stmtp->fileline(), "", nullptr, false, false};
stmtp->replaceWith(beginp); stmtp->replaceWith(beginp);
beginp->addStmtsp(stmtp); beginp->addStmtsp(stmtp);
stmtp = beginp; stmtp = beginp;
} }
} }
dotNames(nodep, "__FORK__"); dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__FORK__");
nodep->name(""); nodep->name("");
} }
void visit(AstForeach* nodep) override { void visit(AstForeach* nodep) override {
@ -199,6 +199,20 @@ class BeginVisitor final : public VNVisitor {
m_liftedp = nullptr; m_liftedp = nullptr;
} }
} }
void visit(AstGenBlock* nodep) override {
// GenBlocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep);
VL_RESTORER(m_displayScope);
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
UASSERT_OBJ(!m_keepBegins, nodep, "Should be able to eliminate all AstGenBlock");
dotNames(nodep->name(), nodep->fileline(), nodep->itemsp(), "__BEGIN__");
// Repalce node with body then delete
if (AstNode* const itemsp = nodep->itemsp()) {
nodep->addNextHere(itemsp->unlinkFrBackWithNext());
}
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// Begin blocks were only useful in variable creation, change names and delete // Begin blocks were only useful in variable creation, change names and delete
UINFO(8, " " << nodep); UINFO(8, " " << nodep);
@ -208,9 +222,8 @@ class BeginVisitor final : public VNVisitor {
{ {
VL_RESTORER(m_keepBegins); VL_RESTORER(m_keepBegins);
m_keepBegins = false; m_keepBegins = false;
dotNames(nodep, "__BEGIN__"); dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__BEGIN__");
} }
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
// Cleanup // Cleanup
if (m_keepBegins) { if (m_keepBegins) {
@ -431,7 +444,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp(); AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
// Split into for loop // Split into for loop
// We record where the body needs to eventually go with bodyPointp // We record where the body needs to eventually go with bodyPointp
AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr, false, false}; AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr, false};
AstNode* newp = nullptr; AstNode* newp = nullptr;
AstNode* lastp = nodep; AstNode* lastp = nodep;
AstVar* nestedIndexp = nullptr; AstVar* nestedIndexp = nullptr;

View File

@ -382,7 +382,7 @@ void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck =
void V3Broken::selfTest() { void V3Broken::selfTest() {
// Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS // Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS
FileLine* const fl = new FileLine{FileLine::commandLineFilename()}; FileLine* const fl = new FileLine{FileLine::commandLineFilename()};
AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr, false, false}; AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr, false};
// Don't actually do it with VL_LEAK_CHECKS, when new/delete calls these. // Don't actually do it with VL_LEAK_CHECKS, when new/delete calls these.
// Otherwise you call addNewed twice on the same address, which is an error. // Otherwise you call addNewed twice on the same address, which is an error.
#ifndef VL_LEAK_CHECKS #ifndef VL_LEAK_CHECKS

View File

@ -49,64 +49,80 @@ VL_DEFINE_DEBUG_FUNCTIONS;
//###################################################################### //######################################################################
class CaseLintVisitor final : public VNVisitorConst { class CaseLintVisitor final : public VNVisitorConst {
const AstNodeCase* m_caseExprp // Under a CASE value node, if so the relevant case statement
= nullptr; // Under a CASE value node, if so the relevant case statement const AstNode* m_casep = nullptr;
// METHODS // METHODS
template <typename CaseItem>
void visit(AstNodeCase* nodep) override { static void detectMultipleDefaults(CaseItem* itemsp) {
if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
bool hitDefault = false; bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
itemp = VN_AS(itemp->nextp(), CaseItem)) { if (!itemp->isDefault()) continue;
if (itemp->isDefault()) { if (hitDefault) itemp->v3error("Multiple default statements in case statement.");
if (hitDefault) {
itemp->v3error("Multiple default statements in case statement.");
}
hitDefault = true; hitDefault = true;
} }
} }
// Check for X/Z in non-casex statements template <typename CaseItem>
{ void checkXZinNonCaseX(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) {
VL_RESTORER(m_caseExprp); VL_RESTORER(m_casep);
m_caseExprp = nodep; m_casep = casep;
iterateConst(nodep->exprp()); iterateConst(exprp);
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
iterateAndNextConstNull(itemp->condsp()); iterateAndNextConstNull(itemp->condsp());
} }
} }
// VISITORS
void visit(AstGenCase* nodep) override {
// Detect multiple defaults
detectMultipleDefaults(nodep->itemsp());
// Check for X/Z in non-casex statements
checkXZinNonCaseX(nodep, nodep->exprp(), nodep->itemsp());
}
void visit(AstCase* nodep) override {
if (nodep->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
detectMultipleDefaults(nodep->itemsp());
// Check for X/Z in non-casex statements
checkXZinNonCaseX(nodep, nodep->exprp(), nodep->itemsp());
} }
void visit(AstConst* nodep) override { void visit(AstConst* nodep) override {
// See also neverItem if (!nodep->num().isFourState()) return;
if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) { // Error if generate case
if (VN_IS(m_casep, GenCase)) {
nodep->v3error("Use of x/? constant in generate case statement, " nodep->v3error("Use of x/? constant in generate case statement, "
"(no such thing as 'generate casez')"); "(no such thing as 'generate casez')");
} else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) { return;
}
// Otherwise must be a case statement
const AstCase* const casep = VN_AS(m_casep, Case);
// Don't sweat it, we already complained about casex in general // Don't sweat it, we already complained about casex in general
} else if (VN_IS(m_caseExprp, Case) if (casep->casex()) return;
&& (VN_AS(m_caseExprp, Case)->casez()
|| VN_AS(m_caseExprp, Case)->caseInside())) { if (casep->casez() || casep->caseInside()) {
if (nodep->num().isAnyX()) { if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, " nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)"); "(perhaps intended ?/z in constant)");
} }
} else { return;
}
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, " nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, "
"(perhaps intended casex/casez)"); "(perhaps intended casex/casez)");
} }
}
}
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); } explicit CaseLintVisitor(AstCase* nodep) { iterateConst(nodep); }
explicit CaseLintVisitor(AstGenCase* nodep) { iterateConst(nodep); }
~CaseLintVisitor() override = default; ~CaseLintVisitor() override = default;
}; };
@ -562,7 +578,7 @@ class CaseVisitor final : public VNVisitor {
// VISITORS // VISITORS
void visit(AstCase* nodep) override { void visit(AstCase* nodep) override {
V3Case::caseLint(nodep); { CaseLintVisitor{nodep}; }
iterateChildren(nodep); iterateChildren(nodep);
UINFOTREE(9, nodep, "", "case_old"); UINFOTREE(9, nodep, "", "case_old");
if (isCaseTreeFast(nodep) && v3Global.opt.fCase()) { if (isCaseTreeFast(nodep) && v3Global.opt.fCase()) {
@ -605,7 +621,7 @@ void V3Case::caseAll(AstNetlist* nodep) {
{ CaseVisitor{nodep}; } // Destruct before checking { CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3); V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3);
} }
void V3Case::caseLint(AstNodeCase* nodep) { void V3Case::caseLint(AstGenCase* nodep) {
UINFO(4, __FUNCTION__ << ": "); UINFO(4, __FUNCTION__ << ": ");
{ CaseLintVisitor{nodep}; } { CaseLintVisitor{nodep}; }
} }

View File

@ -21,14 +21,14 @@
#include "verilatedos.h" #include "verilatedos.h"
class AstNetlist; class AstNetlist;
class AstNodeCase; class AstGenCase;
//============================================================================ //============================================================================
class V3Case final { class V3Case final {
public: public:
static void caseAll(AstNetlist* nodep) VL_MT_DISABLED; static void caseAll(AstNetlist* nodep) VL_MT_DISABLED;
static void caseLint(AstNodeCase* nodep) VL_MT_DISABLED; static void caseLint(AstGenCase* nodep) VL_MT_DISABLED;
}; };
#endif // Guard #endif // Guard

View File

@ -259,6 +259,17 @@ public:
} }
} }
void applyBlock(AstGenBlock* nodep) {
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
if (!nodep->unnamed()) {
for (const string& i : m_coverageOffBlocks) {
if (VString::wildmatch(nodep->prettyOrigOrName(), i)) {
nodep->addItemsp(new AstPragma{nodep->fileline(), pragma});
}
}
}
}
void applyBlock(AstNodeBlock* nodep) { void applyBlock(AstNodeBlock* nodep) {
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
if (!nodep->unnamed()) { if (!nodep->unnamed()) {
@ -375,6 +386,13 @@ public:
m_waivers.emplace_back(WaiverSetting{code, contents, newMatch}); m_waivers.emplace_back(WaiverSetting{code, contents, newMatch});
} }
void applyBlock(AstGenBlock* nodep) {
// Apply to block at this line
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
if (lineMatch(nodep->fileline()->lineno(), pragma)) {
nodep->addItemsp(new AstPragma{nodep->fileline(), pragma});
}
}
void applyBlock(AstNodeBlock* nodep) { void applyBlock(AstNodeBlock* nodep) {
// Apply to block at this line // Apply to block at this line
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF; const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
@ -741,6 +759,15 @@ void V3Control::applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep) {
if (modp) modp->applyBlock(nodep); if (modp) modp->applyBlock(nodep);
} }
void V3Control::applyCoverageBlock(AstNodeModule* modulep, AstGenBlock* nodep) {
const string& filename = nodep->fileline()->filename();
V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename);
if (filep) filep->applyBlock(nodep);
const string& modname = modulep->prettyOrigOrName();
V3ControlModule* const modp = V3ControlResolver::s().modules().resolve(modname);
if (modp) modp->applyBlock(nodep);
}
void V3Control::applyIgnores(FileLine* filelinep) { void V3Control::applyIgnores(FileLine* filelinep) {
const string& filename = filelinep->filename(); const string& filename = filelinep->filename();
V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename); V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename);

View File

@ -48,6 +48,7 @@ public:
static void applyCase(AstCase* nodep); static void applyCase(AstCase* nodep);
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep); static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
static void applyCoverageBlock(AstNodeModule* modulep, AstGenBlock* nodep);
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyIgnores(FileLine* filelinep); static void applyIgnores(FileLine* filelinep);
static void applyModule(AstNodeModule* modulep); static void applyModule(AstNodeModule* modulep);

View File

@ -710,6 +710,16 @@ class CoverageVisitor final : public VNVisitor {
lineTrack(nodep); lineTrack(nodep);
} }
} }
void visit(AstGenBlock* nodep) override {
// Similar to AstBegin
VL_RESTORER(m_beginHier);
if (nodep->name() != "") {
m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name();
}
iterateChildren(nodep);
lineTrack(nodep);
}
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
// Record the hierarchy of any named begins, so we can apply to user // Record the hierarchy of any named begins, so we can apply to user
// coverage points. This is because there may be cov points inside // coverage points. This is because there may be cov points inside
@ -718,7 +728,7 @@ class CoverageVisitor final : public VNVisitor {
// covers the code in that line.) // covers the code in that line.)
VL_RESTORER(m_beginHier); VL_RESTORER(m_beginHier);
VL_RESTORER(m_inToggleOff); VL_RESTORER(m_inToggleOff);
if (!nodep->generate()) m_inToggleOff = true; m_inToggleOff = true;
if (nodep->name() != "") { if (nodep->name() != "") {
m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name(); m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name();
} }

View File

@ -1297,9 +1297,6 @@ class DelayedVisitor final : public VNVisitor {
// Record write reference // Record write reference
recordWriteRef(nodep, false); recordWriteRef(nodep, false);
} }
void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("For statements should have been converted to while statements");
}
void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
VL_RESTORER(m_inLoop); VL_RESTORER(m_inLoop);
m_inLoop = true; m_inLoop = true;

View File

@ -680,7 +680,7 @@ public:
iterateAndNextConstNull(nodep->exprp()); iterateAndNextConstNull(nodep->exprp());
puts("}\n"); puts("}\n");
} }
void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE void visit(AstCase* nodep) override { // LCOV_EXCL_LINE
// In V3Case... // In V3Case...
nodep->v3fatalSrc("Case statements should have been reduced out"); nodep->v3fatalSrc("Case statements should have been reduced out");
} }

View File

@ -89,6 +89,54 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
putfs(nodep, func ? "endfunction\n" : "endtask\n"); putfs(nodep, func ? "endfunction\n" : "endtask\n");
} }
void visit(AstGenBlock* nodep) override {
const std::string name = nodep->name().empty() ? "" : " : " + nodep->name();
putbs("/* generate */ begin" + name + '\n');
iterateChildrenConst(nodep);
puts("end" + name + '\n');
}
void visit(AstGenCase* nodep) override {
putfs(nodep, "/* generate */ case (");
iterateAndNextConstNull(nodep->exprp());
puts(")\n");
iterateAndNextConstNull(nodep->itemsp());
putqs(nodep, "endcase\n");
}
void visit(AstGenCaseItem* nodep) override {
if (nodep->condsp()) {
iterateAndNextConstNull(nodep->condsp());
} else {
putbs("default");
}
iterateAndNextConstNull(nodep->itemsp());
}
void visit(AstGenFor* nodep) override {
putfs(nodep, "/* generate */ for (");
{
VL_RESTORER(m_suppressSemi);
m_suppressSemi = true;
iterateAndNextConstNull(nodep->initsp());
puts(";");
iterateAndNextConstNull(nodep->condp());
puts(";");
iterateAndNextConstNull(nodep->incsp());
}
puts(") begin\n");
iterateAndNextConstNull(nodep->itemsp());
putqs(nodep, "end\n");
}
void visit(AstGenIf* nodep) override {
putfs(nodep, "");
puts("/* generate */ if (");
iterateAndNextConstNull(nodep->condp());
puts(") begin\n");
iterateAndNextConstNull(nodep->thensp());
if (nodep->elsesp()) {
putqs(nodep, "end else begin\n");
iterateAndNextConstNull(nodep->elsesp());
}
putqs(nodep, "end\n");
}
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
if (nodep->name() == "") { if (nodep->name() == "") {
putbs("begin\n"); putbs("begin\n");
@ -193,23 +241,19 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
if (nodep->sensp()) puts(" "); if (nodep->sensp()) puts(" ");
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
void visit(AstNodeCase* nodep) override { void visit(AstCase* nodep) override {
putfs(nodep, ""); putfs(nodep, "");
if (const AstCase* const casep = VN_CAST(nodep, Case)) { if (nodep->priorityPragma()) puts("priority ");
if (casep->priorityPragma()) puts("priority "); if (nodep->uniquePragma()) puts("unique ");
if (casep->uniquePragma()) puts("unique "); if (nodep->unique0Pragma()) puts("unique0 ");
if (casep->unique0Pragma()) puts("unique0 ");
}
puts(nodep->verilogKwd()); puts(nodep->verilogKwd());
puts(" ("); puts(" (");
iterateAndNextConstNull(nodep->exprp()); iterateAndNextConstNull(nodep->exprp());
puts(")\n"); puts(")\n");
if (const AstCase* const casep = VN_CAST(nodep, Case)) { if (nodep->fullPragma() || nodep->parallelPragma()) {
if (casep->fullPragma() || casep->parallelPragma()) {
puts(" // synopsys"); puts(" // synopsys");
if (casep->fullPragma()) puts(" full_case"); if (nodep->fullPragma()) puts(" full_case");
if (casep->parallelPragma()) puts(" parallel_case"); if (nodep->parallelPragma()) puts(" parallel_case");
}
} }
iterateAndNextConstNull(nodep->itemsp()); iterateAndNextConstNull(nodep->itemsp());
putqs(nodep, "endcase\n"); putqs(nodep, "endcase\n");
@ -348,21 +392,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
iterateAndNextConstNull(nodep->exprsp()); iterateAndNextConstNull(nodep->exprsp());
puts(");\n"); puts(");\n");
} }
void visit(AstNodeFor* nodep) override {
putfs(nodep, "for (");
{
VL_RESTORER(m_suppressSemi);
m_suppressSemi = true;
iterateAndNextConstNull(nodep->initsp());
puts(";");
iterateAndNextConstNull(nodep->condp());
puts(";");
iterateAndNextConstNull(nodep->incsp());
}
puts(") begin\n");
iterateAndNextConstNull(nodep->stmtsp());
putqs(nodep, "end\n");
}
void visit(AstRepeat* nodep) override { void visit(AstRepeat* nodep) override {
putfs(nodep, "repeat ("); putfs(nodep, "repeat (");
iterateAndNextConstNull(nodep->countp()); iterateAndNextConstNull(nodep->countp());

View File

@ -410,6 +410,11 @@ class HierCellsXmlVisitor final : public VNVisitorConst {
m_hier = hier; m_hier = hier;
m_hasChildren = true; m_hasChildren = true;
} }
void visit(AstGenBlock* nodep) override {
VL_RESTORER(m_hier);
if (nodep->name() != "") m_hier += nodep->name() + ".";
iterateChildrenConst(nodep);
}
void visit(AstBegin* nodep) override { void visit(AstBegin* nodep) override {
VL_RESTORER(m_hier); VL_RESTORER(m_hier);
if (nodep->name() != "") m_hier += nodep->name() + "."; if (nodep->name() != "") m_hier += nodep->name() + ".";

View File

@ -231,7 +231,7 @@ private:
AstBegin* const beginp = new AstBegin{ AstBegin* const beginp = new AstBegin{
forkp->fileline(), forkp->fileline(),
"_Vwrapped_" + (forkp->name().empty() ? "" : forkp->name() + "_") + cvtToStr(m_id), "_Vwrapped_" + (forkp->name().empty() ? "" : forkp->name() + "_") + cvtToStr(m_id),
m_instance.m_handlep, false, true}; m_instance.m_handlep, true};
forkHandle.relink(beginp); forkHandle.relink(beginp);
AstNode* const instAsgnp = instantiateDynScope(memberMap); AstNode* const instAsgnp = instantiateDynScope(memberMap);
@ -470,7 +470,7 @@ class DynScopeVisitor final : public VNVisitor {
})) { })) {
nodep->user2(true); nodep->user2(true);
// Put it in a fork to prevent lifetime issues with the local // Put it in a fork to prevent lifetime issues with the local
AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false, false}; AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false};
AstFork* const forkp = new AstFork{nodep->fileline(), "", beginp}; AstFork* const forkp = new AstFork{nodep->fileline(), "", beginp};
forkp->joinType(VJoinType::JOIN_NONE); forkp->joinType(VJoinType::JOIN_NONE);
nodep->replaceWith(forkp); nodep->replaceWith(forkp);

View File

@ -260,6 +260,8 @@ public:
return "block"; return "block";
} else if (VN_IS(nodep, Iface)) { } else if (VN_IS(nodep, Iface)) {
return "interface"; return "interface";
} else if (VN_IS(nodep, GenBlock)) {
return "generate block";
} else { } else {
return nodep->prettyTypeName(); return nodep->prettyTypeName();
} }
@ -295,8 +297,8 @@ public:
} else if (foundp->imported()) { // From package } else if (foundp->imported()) { // From package
// We don't throw VARHIDDEN as if the import is later the symbol // We don't throw VARHIDDEN as if the import is later the symbol
// table's import wouldn't warn // table's import wouldn't warn
} else if (forPrimary() && VN_IS(nodep, Begin) && VN_IS(fnodep, Begin) } else if (forPrimary() && VN_IS(nodep, GenBlock)
&& VN_AS(nodep, Begin)->generate()) { && (VN_IS(fnodep, Begin) || VN_IS(fnodep, GenBlock))) {
// Begin: ... blocks often replicate under genif/genfor, so // Begin: ... blocks often replicate under genif/genfor, so
// suppress duplicate checks. See t_gen_forif.v for an example. // suppress duplicate checks. See t_gen_forif.v for an example.
} else { } else {
@ -882,7 +884,6 @@ class LinkDotFindVisitor final : public VNVisitor {
string string
m_hierParamsName; // Name of module with hierarchical type parameters, empty when not used m_hierParamsName; // Name of module with hierarchical type parameters, empty when not used
string m_scope; // Scope text string m_scope; // Scope text
const AstNodeBlock* m_blockp = nullptr; // Current Begin/end block
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
bool m_inRecursion = false; // Inside a recursive module bool m_inRecursion = false; // Inside a recursive module
int m_paramNum = 0; // Parameter number, for position based connection int m_paramNum = 0; // Parameter number, for position based connection
@ -1158,7 +1159,6 @@ class LinkDotFindVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
// Recurse in, preserving state // Recurse in, preserving state
VL_RESTORER(m_scope); VL_RESTORER(m_scope);
VL_RESTORER(m_blockp);
VL_RESTORER(m_modSymp); VL_RESTORER(m_modSymp);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
VL_RESTORER(m_paramNum); VL_RESTORER(m_paramNum);
@ -1181,7 +1181,6 @@ class LinkDotFindVisitor final : public VNVisitor {
{ {
m_scope = m_scope + "." + nodep->name(); m_scope = m_scope + "." + nodep->name();
m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope); m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope);
m_blockp = nullptr;
m_inRecursion = nodep->recursive(); m_inRecursion = nodep->recursive();
// We don't report NotFoundModule, as may be a unused module in a generate // We don't report NotFoundModule, as may be a unused module in a generate
if (nodep->modp()) iterate(nodep->modp()); if (nodep->modp()) iterate(nodep->modp());
@ -1216,6 +1215,43 @@ class LinkDotFindVisitor final : public VNVisitor {
nodep->user1p(m_curSymp); nodep->user1p(m_curSymp);
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstGenBlock* nodep) override { // FindVisitor::
UINFO(5, " " << nodep);
if (nodep->name() == "" && nodep->unnamed()) {
// Unnamed blocks are only important when they contain var
// decls, so search for them. (Otherwise adding all the
// unnamed#'s would just confuse tracing variables in
// places such as tasks, where "task ...; begin ... end"
// are common.
for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
if (VN_IS(itemp, Var) || VN_IS(itemp, Foreach)) {
std::string name;
const std::string stepStr = m_statep->forPrimary()
? ""
: std::to_string(m_statep->stepNumber()) + "_";
do {
++m_modBlockNum;
name = "unnamedblk" + stepStr + cvtToStr(m_modBlockNum);
// Increment again if earlier pass of V3LinkDot claimed this name
} while (m_curSymp->findIdFlat(name));
nodep->name(name);
break;
}
}
}
if (nodep->name() == "") {
iterateChildren(nodep);
} else {
VL_RESTORER(m_curSymp);
{
m_curSymp
= m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
// Iterate
iterateChildren(nodep);
}
}
}
void visit(AstNodeBlock* nodep) override { // FindVisitor:: void visit(AstNodeBlock* nodep) override { // FindVisitor::
UINFO(5, " " << nodep); UINFO(5, " " << nodep);
if (nodep->name() == "" && nodep->unnamed()) { if (nodep->name() == "" && nodep->unnamed()) {
@ -1243,10 +1279,8 @@ class LinkDotFindVisitor final : public VNVisitor {
if (nodep->name() == "") { if (nodep->name() == "") {
iterateChildren(nodep); iterateChildren(nodep);
} else { } else {
VL_RESTORER(m_blockp);
VL_RESTORER(m_curSymp); VL_RESTORER(m_curSymp);
{ {
m_blockp = nodep;
m_curSymp m_curSymp
= m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp)); m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
@ -2331,6 +2365,9 @@ class LinkDotScopeVisitor final : public VNVisitor {
// We have stored the link, we don't need these any more // We have stored the link, we don't need these any more
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
void visit(AstNodeGen* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Generate constructs should have been reduced out");
}
// For speed, don't recurse things that can't have scope // For speed, don't recurse things that can't have scope
// Note we allow AstNodeStmt's as generates may be under them // Note we allow AstNodeStmt's as generates may be under them
void visit(AstCell*) override {} // ScopeVisitor:: void visit(AstCell*) override {} // ScopeVisitor::
@ -3509,6 +3546,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
} }
if (!foundp) { if (!foundp) {
} else if (VN_IS(foundp->nodep(), Cell) || VN_IS(foundp->nodep(), NodeBlock) } else if (VN_IS(foundp->nodep(), Cell) || VN_IS(foundp->nodep(), NodeBlock)
|| VN_IS(foundp->nodep(), GenBlock)
|| VN_IS(foundp->nodep(), Netlist) // for $root || VN_IS(foundp->nodep(), Netlist) // for $root
|| VN_IS(foundp->nodep(), Module)) { // if top || VN_IS(foundp->nodep(), Module)) { // if top
if (allowScope) { if (allowScope) {
@ -3521,8 +3559,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
// last component, `targetp()` field will be overwritten by next components // last component, `targetp()` field will be overwritten by next components
m_ds.m_disablep->targetp(foundp->nodep()); m_ds.m_disablep->targetp(foundp->nodep());
} }
if (const AstBegin* const beginp = VN_CAST(foundp->nodep(), Begin)) { if (VN_IS(foundp->nodep(), GenBlock)) {
if (beginp->generate()) {
m_ds.m_genBlk = true; m_ds.m_genBlk = true;
if (m_ds.m_disablep) { if (m_ds.m_disablep) {
m_ds.m_disablep->v3warn( m_ds.m_disablep->v3warn(
@ -3530,7 +3567,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
"Unsupported: Generate block referenced by disable"); "Unsupported: Generate block referenced by disable");
} }
} }
}
// Upper AstDot visitor will handle it from here // Upper AstDot visitor will handle it from here
} else if (VN_IS(foundp->nodep(), Cell) && allowVar) { } else if (VN_IS(foundp->nodep(), Cell) && allowVar) {
AstCell* const cellp = VN_AS(foundp->nodep(), Cell); AstCell* const cellp = VN_AS(foundp->nodep(), Cell);
@ -4472,6 +4508,21 @@ class LinkDotResolveVisitor final : public VNVisitor {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstGenBlock* nodep) override {
LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep);
checkNoDot(nodep);
{
VL_RESTORER(m_curSymp);
VL_RESTORER(m_ds);
if (nodep->name() != "") {
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
}
iterateChildren(nodep);
}
UINFO(5, indent() << "cur=se" << cvtToHex(m_curSymp));
}
void visit(AstNodeBlock* nodep) override { void visit(AstNodeBlock* nodep) override {
LINKDOT_VISIT_START(); LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep); UINFO(5, indent() << "visit " << nodep);

View File

@ -162,10 +162,6 @@ class LinkIncVisitor final : public VNVisitor {
m_insStmtp = nullptr; // Next thing should be new statement m_insStmtp = nullptr; // Next thing should be new statement
iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->stmtsp());
} }
void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin.cpp");
}
void visit(AstDelay* nodep) override { void visit(AstDelay* nodep) override {
m_insStmtp = nodep; m_insStmtp = nodep;
iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->lhsp());

View File

@ -289,7 +289,7 @@ class LinkJumpVisitor final : public VNVisitor {
// Note var can be signed or unsigned based on original number. // Note var can be signed or unsigned based on original number.
AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext(); AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext();
const string name = "__Vrepeat"s + cvtToStr(m_modRepeatNum++); const string name = "__Vrepeat"s + cvtToStr(m_modRepeatNum++);
AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, false, true}; AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, true};
// Spec says value is integral, if negative is ignored // Spec says value is integral, if negative is ignored
AstVar* const varp AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()}; = new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()};
@ -425,7 +425,7 @@ class LinkJumpVisitor final : public VNVisitor {
// Further handling of disable stmt requires all forks to be begin blocks // Further handling of disable stmt requires all forks to be begin blocks
AstBegin* beginp = VN_CAST(forkItemp, Begin); AstBegin* beginp = VN_CAST(forkItemp, Begin);
if (!beginp) { if (!beginp) {
beginp = new AstBegin{fl, "", nullptr, false, false}; beginp = new AstBegin{fl, "", nullptr, false};
forkItemp->replaceWith(beginp); forkItemp->replaceWith(beginp);
beginp->addStmtsp(forkItemp); beginp->addStmtsp(forkItemp);
// In order to continue the iteration // In order to continue the iteration

View File

@ -111,19 +111,19 @@ class LinkParseVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
} }
bool nestedIfBegin(AstBegin* nodep) { // Point at begin inside the GenIf bool nestedIfBegin(AstGenBlock* nodep) { // Point at begin inside the GenIf
// IEEE says directly nested item is not a new block // IEEE says directly nested item is not a new block
// The genblk name will get attached to the if true/false LOWER begin block(s) // The genblk name will get attached to the if true/false LOWER begin block(s)
// 1: GENIF // 1: GENIF
// -> 1:3: BEGIN [GEN] [IMPLIED] // nodep passed to this function // -> 1:3: GENBLOCK [IMPLIED] // nodep passed to this function
// 1:3:1: GENIF // 1:3:1: GENIF
// 1:3:1:2: BEGIN genblk1 [GEN] [IMPLIED] // 1:3:1:2: GENBLOCK genblk1 [IMPLIED]
const AstNode* const backp = nodep->backp(); const AstNode* const backp = nodep->backp();
return (nodep->implied() // User didn't provide begin/end return (nodep->implied() // User didn't provide begin/end
&& VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep && VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep
&& !nodep->nextp() // No other statements under upper genif else && !nodep->nextp() // No other statements under upper genif else
&& (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath && (VN_IS(nodep->itemsp(), GenIf)) // Begin has if underneath
&& !nodep->stmtsp()->nextp()); // Has only one item && !nodep->itemsp()->nextp()); // Has only one item
} }
void checkIndent(AstNode* nodep, AstNode* childp) { void checkIndent(AstNode* nodep, AstNode* childp) {
@ -657,7 +657,7 @@ class LinkParseVisitor final : public VNVisitor {
void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); } void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); }
void visit(AstRestrict* nodep) override { visitIterateNoValueMod(nodep); } void visit(AstRestrict* nodep) override { visitIterateNoValueMod(nodep); }
void visit(AstBegin* nodep) override { void visit(AstGenBlock* nodep) override {
V3Control::applyCoverageBlock(m_modp, nodep); V3Control::applyCoverageBlock(m_modp, nodep);
cleanFileline(nodep); cleanFileline(nodep);
VL_RESTORER(m_beginDepth); VL_RESTORER(m_beginDepth);
@ -671,13 +671,13 @@ class LinkParseVisitor final : public VNVisitor {
if (nodep->genforp()) { if (nodep->genforp()) {
++m_genblkNum; ++m_genblkNum;
if (nodep->name() == "") assignGenBlkNum = m_genblkNum; if (nodep->name() == "") assignGenBlkNum = m_genblkNum;
} else if (nodep->generate() && nodep->name() == "" } else if (nodep->name() == "" && (VN_IS(backp, GenCaseItem) || VN_IS(backp, GenIf))
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) { && !nestedIf) {
assignGenBlkNum = m_genblkAbove; assignGenBlkNum = m_genblkAbove;
} }
if (assignGenBlkNum != -1) { if (assignGenBlkNum != -1) {
nodep->name("genblk" + cvtToStr(assignGenBlkNum)); nodep->name("genblk" + cvtToStr(assignGenBlkNum));
if (nodep->stmtsp()) { if (nodep->itemsp()) {
nodep->v3warn(GENUNNAMED, nodep->v3warn(GENUNNAMED,
"Unnamed generate block " "Unnamed generate block "
<< nodep->prettyNameQ() << " (IEEE 1800-2023 27.6)\n" << nodep->prettyNameQ() << " (IEEE 1800-2023 27.6)\n"
@ -696,6 +696,31 @@ class LinkParseVisitor final : public VNVisitor {
iterateChildren(nodep); iterateChildren(nodep);
} }
} }
void visit(AstGenCase* nodep) override {
++m_genblkNum;
cleanFileline(nodep);
VL_RESTORER(m_genblkAbove);
VL_RESTORER(m_genblkNum);
m_genblkAbove = m_genblkNum;
m_genblkNum = 0;
iterateChildren(nodep);
}
void visit(AstGenIf* nodep) override {
cleanFileline(nodep);
checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp());
const bool nestedIf = (VN_IS(nodep->backp(), GenBlock)
&& nestedIfBegin(VN_CAST(nodep->backp(), GenBlock)));
if (nestedIf) {
iterateChildren(nodep);
} else {
++m_genblkNum;
VL_RESTORER(m_genblkAbove);
VL_RESTORER(m_genblkNum);
m_genblkAbove = m_genblkNum;
m_genblkNum = 0;
iterateChildren(nodep);
}
}
void visit(AstCell* nodep) override { void visit(AstCell* nodep) override {
if (nodep->origName().empty()) { if (nodep->origName().empty()) {
if (!VN_IS(nodep->modp(), Primitive)) { // Module/Program/Iface if (!VN_IS(nodep->modp(), Primitive)) { // Module/Program/Iface
@ -710,31 +735,11 @@ class LinkParseVisitor final : public VNVisitor {
} }
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstGenCase* nodep) override { void visit(AstBegin* nodep) override {
++m_genblkNum; V3Control::applyCoverageBlock(m_modp, nodep);
cleanFileline(nodep); cleanFileline(nodep);
VL_RESTORER(m_genblkAbove);
VL_RESTORER(m_genblkNum);
m_genblkAbove = m_genblkNum;
m_genblkNum = 0;
iterateChildren(nodep); iterateChildren(nodep);
} }
void visit(AstGenIf* nodep) override {
cleanFileline(nodep);
checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp());
const bool nestedIf
= (VN_IS(nodep->backp(), Begin) && nestedIfBegin(VN_CAST(nodep->backp(), Begin)));
if (nestedIf) {
iterateChildren(nodep);
} else {
++m_genblkNum;
VL_RESTORER(m_genblkAbove);
VL_RESTORER(m_genblkNum);
m_genblkAbove = m_genblkNum;
m_genblkNum = 0;
iterateChildren(nodep);
}
}
void visit(AstCase* nodep) override { void visit(AstCase* nodep) override {
V3Control::applyCase(nodep); V3Control::applyCase(nodep);
cleanFileline(nodep); cleanFileline(nodep);

View File

@ -1610,7 +1610,7 @@ class ParamVisitor final : public VNVisitor {
} }
} }
void visit(AstBegin* nodep) override { void visit(AstGenBlock* nodep) override {
// Parameter substitution for generated for loops. // Parameter substitution for generated for loops.
// TODO Unlike generated IF, we don't have to worry about short-circuiting the // TODO Unlike generated IF, we don't have to worry about short-circuiting the
// conditional expression, since this is currently restricted to simple // conditional expression, since this is currently restricted to simple
@ -1663,8 +1663,8 @@ class ParamVisitor final : public VNVisitor {
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
const AstConst* const exprp = VN_AS(nodep->exprp(), Const); const AstConst* const exprp = VN_AS(nodep->exprp(), Const);
// Constify // Constify
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) { itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
for (AstNode* ep = itemp->condsp(); ep;) { for (AstNode* ep = itemp->condsp(); ep;) {
AstNode* const nextp = ep->nextp(); // May edit list AstNode* const nextp = ep->nextp(); // May edit list
iterateAndNextNull(ep); iterateAndNextNull(ep);
@ -1673,8 +1673,8 @@ class ParamVisitor final : public VNVisitor {
} }
} }
// Item match // Item match
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) { itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
if (!itemp->isDefault()) { if (!itemp->isDefault()) {
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) { for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
if (const AstConst* const ccondp = VN_CAST(ep, Const)) { if (const AstConst* const ccondp = VN_CAST(ep, Const)) {
@ -1682,7 +1682,7 @@ class ParamVisitor final : public VNVisitor {
match.opEq(ccondp->num(), exprp->num()); match.opEq(ccondp->num(), exprp->num());
if (!hit && match.isNeqZero()) { if (!hit && match.isNeqZero()) {
hit = true; hit = true;
keepp = itemp->stmtsp(); keepp = itemp->itemsp();
} }
} else { } else {
itemp->v3error("Generate Case item does not evaluate to constant"); itemp->v3error("Generate Case item does not evaluate to constant");
@ -1691,12 +1691,12 @@ class ParamVisitor final : public VNVisitor {
} }
} }
// Else default match // Else default match
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) { itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
if (itemp->isDefault()) { if (itemp->isDefault()) {
if (!hit) { if (!hit) {
hit = true; hit = true;
keepp = itemp->stmtsp(); keepp = itemp->itemsp();
} }
} }
} }

View File

@ -252,7 +252,7 @@ public:
// would misfire // would misfire
AstNode* newBlock(FileLine* fl, AstNode* nodep) { AstNode* newBlock(FileLine* fl, AstNode* nodep) {
if (nodep) return nodep; if (nodep) return nodep;
return new AstBegin{fl, "", nullptr, false, true}; return new AstBegin{fl, "", nullptr, true};
} }
// Bison sometimes needs error context without a token, so remember last token's line // Bison sometimes needs error context without a token, so remember last token's line

View File

@ -597,7 +597,7 @@ class ConstraintExprVisitor final : public VNVisitor {
{ {
AstBegin* const tempp AstBegin* const tempp
= new AstBegin{fl, "[EditWrapper]", itemsp->unlinkFrBackWithNext(), false, false}; = new AstBegin{fl, "[EditWrapper]", itemsp->unlinkFrBackWithNext(), false};
VL_DO_DANGLING(iterateAndNextNull(tempp->stmtsp()), itemsp); VL_DO_DANGLING(iterateAndNextNull(tempp->stmtsp()), itemsp);
itemsp = tempp->stmtsp(); itemsp = tempp->stmtsp();
if (itemsp) itemsp->unlinkFrBackWithNext(); if (itemsp) itemsp->unlinkFrBackWithNext();
@ -937,6 +937,10 @@ class ConstraintExprVisitor final : public VNVisitor {
} }
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
void visit(AstGenBlock* nodep) override {
// Dubious but this is what we used to do. Does that mean no randomzie
// methods work under a generage block?
}
void visit(AstBegin* nodep) override {} void visit(AstBegin* nodep) override {}
void visit(AstConstraintForeach* nodep) override { void visit(AstConstraintForeach* nodep) override {
// Convert to plain foreach // Convert to plain foreach
@ -951,7 +955,7 @@ class ConstraintExprVisitor final : public VNVisitor {
exprsp->addNext(new AstBegin{ exprsp->addNext(new AstBegin{
fl, "", fl, "",
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}}, new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}},
false, true}); true});
exprsp->addNext( exprsp->addNext(
new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"}); new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"});
AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; AstNodeExpr* const newp = new AstCExpr{fl, exprsp};
@ -963,7 +967,7 @@ class ConstraintExprVisitor final : public VNVisitor {
new AstBegin{fl, "", new AstBegin{fl, "",
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstForeach{fl, nodep->arrayp()->unlinkFrBack(),
nodep->stmtsp()->unlinkFrBackWithNext()}, nodep->stmtsp()->unlinkFrBackWithNext()},
false, true}); true});
} }
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} }
@ -1027,8 +1031,8 @@ class ConstraintExprVisitor final : public VNVisitor {
cstmtp->addNext(iterateSubtreeReturnEdits(itemp)); cstmtp->addNext(iterateSubtreeReturnEdits(itemp));
cstmtp->addNext(new AstText{fl, ";"}); cstmtp->addNext(new AstText{fl, ";"});
AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"}; AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"};
exprsp->addNext(new AstBegin{ exprsp->addNext(
fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, false, true}); new AstBegin{fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, true});
exprsp->addNext( exprsp->addNext(
new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"}); new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"});
AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; AstNodeExpr* const newp = new AstCExpr{fl, exprsp};
@ -1530,7 +1534,7 @@ class RandomizeVisitor final : public VNVisitor {
new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE}, new AstAssign{fl, new AstVarRef{fl, iterVarp, VAccess::WRITE},
new AstAdd{fl, new AstConst{fl, 1}, new AstAdd{fl, new AstConst{fl, 1},
new AstVarRef{fl, iterVarp, VAccess::READ}}}}); new AstVarRef{fl, iterVarp, VAccess::READ}}}});
return new AstBegin{fl, "", stmtsp, false, true}; return new AstBegin{fl, "", stmtsp, true};
} }
static AstNodeStmt* wrapIfRandMode(AstClass* classp, AstVar* const varp, AstNodeStmt* stmtp) { static AstNodeStmt* wrapIfRandMode(AstClass* classp, AstVar* const varp, AstNodeStmt* stmtp) {
const RandomizeMode rmode = {.asInt = varp->user1()}; const RandomizeMode rmode = {.asInt = varp->user1()};
@ -1939,7 +1943,7 @@ class RandomizeVisitor final : public VNVisitor {
AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}; AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE};
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp, basicFvarp); AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp, basicFvarp);
if (!refp->backp()) VL_DO_DANGLING(refp->deleteTree(), refp); if (!refp->backp()) VL_DO_DANGLING(refp->deleteTree(), refp);
basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp, false, false}); basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp, false});
} }
}); });
} }
@ -2072,7 +2076,7 @@ class RandomizeVisitor final : public VNVisitor {
stmtsp->addNext(setStmtsp); stmtsp->addNext(setStmtsp);
stmtsp->addNext(m_stmtp); stmtsp->addNext(m_stmtp);
stmtsp->addNext(restoreStmtsp); stmtsp->addNext(restoreStmtsp);
relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, false, true}); relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, true});
} }
} }

View File

@ -345,7 +345,7 @@ void splitCheck(AstCFunc* ofuncp) {
// Unlink all statements, then add item by item to new sub-functions // Unlink all statements, then add item by item to new sub-functions
AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]", AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext(), false, false}; ofuncp->stmtsp()->unlinkFrBackWithNext(), false};
// Currently we do not use finalsp in V3Sched, if we do, it needs to be handled here // Currently we do not use finalsp in V3Sched, if we do, it needs to be handled here
UASSERT_OBJ(!ofuncp->finalsp(), ofuncp, "Should not have any finalps"); UASSERT_OBJ(!ofuncp->finalsp(), ofuncp, "Should not have any finalps");
while (tempp->stmtsp()) { while (tempp->stmtsp()) {

View File

@ -991,7 +991,7 @@ private:
checkNodeInfo(nodep); checkNodeInfo(nodep);
iterateChildrenConst(nodep); iterateChildrenConst(nodep);
} }
void visit(AstNodeCase* nodep) override { void visit(AstCase* nodep) override {
if (jumpingOver()) return; if (jumpingOver()) return;
UINFO(5, " CASE " << nodep); UINFO(5, " CASE " << nodep);
checkNodeInfo(nodep); checkNodeInfo(nodep);
@ -1083,39 +1083,6 @@ private:
checkNodeInfo(nodep); checkNodeInfo(nodep);
} }
void visit(AstNodeFor* nodep) override {
// Doing lots of Whiles is slow, so only for parameters
UINFO(5, " FOR " << nodep);
if (!m_params) {
badNodeType(nodep);
return;
}
checkNodeInfo(nodep);
if (m_checkOnly) {
iterateChildrenConst(nodep);
} else if (optimizable()) {
int loops = 0;
iterateAndNextConstNull(nodep->initsp());
while (true) {
UINFO(5, " FOR-ITER " << nodep);
iterateAndNextConstNull(nodep->condp());
if (!optimizable()) break;
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
break;
}
iterateAndNextConstNull(nodep->stmtsp());
iterateAndNextConstNull(nodep->incsp());
if (loops++ > v3Global.opt.unrollCountAdjusted(VOptionBool{}, m_params, true)) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an"
"infinite loop, or use /*verilator unroll_full*/, or "
"set --unroll-count above "
+ cvtToStr(loops));
break;
}
}
}
}
void visit(AstWhile* nodep) override { void visit(AstWhile* nodep) override {
// Doing lots of Whiles is slow, so only for parameters // Doing lots of Whiles is slow, so only for parameters
if (jumpingOver()) return; if (jumpingOver()) return;

View File

@ -338,7 +338,7 @@ protected:
void visit(AstAlways* nodep) override = 0; void visit(AstAlways* nodep) override = 0;
void visit(AstNodeIf* nodep) override = 0; void visit(AstNodeIf* nodep) override = 0;
// We don't do AstNodeFor/AstWhile loops, due to the standard question // We don't do AstWhile loops, due to the standard question
// of what is before vs. after // of what is before vs. after
void visit(AstAssignDly* nodep) override { void visit(AstAssignDly* nodep) override {

View File

@ -194,7 +194,7 @@ struct SplitVarImpl VL_NOT_FINAL {
stmtp->unlinkFrBack(); stmtp->unlinkFrBack();
// Insert begin-end because temp value may be inserted to this block later. // Insert begin-end because temp value may be inserted to this block later.
const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1));
ap->addStmtsp(new AstBegin{ap->fileline(), name, stmtp, false, false}); ap->addStmtsp(new AstBegin{ap->fileline(), name, stmtp, false});
} }
} }
@ -204,7 +204,7 @@ struct SplitVarImpl VL_NOT_FINAL {
// Insert begin-end because temp value may be inserted to this block later. // Insert begin-end because temp value may be inserted to this block later.
FileLine* const fl = initp->fileline(); FileLine* const fl = initp->fileline();
const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1));
initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp, false, false}}); initp->replaceWith(new AstInitial{fl, new AstBegin{fl, name, stmtp, false}});
VL_DO_DANGLING(initp->deleteTree(), initp); VL_DO_DANGLING(initp->deleteTree(), initp);
} }
} }

View File

@ -1362,7 +1362,7 @@ class TaskVisitor final : public VNVisitor {
if (bodysp) { if (bodysp) {
unlinkAndClone(nodep, bodysp, true); unlinkAndClone(nodep, bodysp, true);
AstBegin* const tempp AstBegin* const tempp
= new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false, false}; = new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false};
VL_DANGLING(bodysp); VL_DANGLING(bodysp);
// If we cloned due to recursion, now need to rip out the ports // If we cloned due to recursion, now need to rip out the ports
// (that remained in place) then got cloned // (that remained in place) then got cloned
@ -1624,10 +1624,6 @@ class TaskVisitor final : public VNVisitor {
nodep->v3fatalSrc( nodep->v3fatalSrc(
"Foreach statements should have been converted to while statements in V3Begin.cpp"); "Foreach statements should have been converted to while statements in V3Begin.cpp");
} }
void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE
nodep->v3fatalSrc(
"For statements should have been converted to while statements in V3Begin.cpp");
}
void visit(AstNodeStmt* nodep) override { void visit(AstNodeStmt* nodep) override {
VL_RESTORER(m_insStmtp); VL_RESTORER(m_insStmtp);
m_insStmtp = nodep; m_insStmtp = nodep;

View File

@ -1029,7 +1029,7 @@ class TimingControlVisitor final : public VNVisitor {
} }
controlp->replaceWith(forkp); controlp->replaceWith(forkp);
AstBegin* beginp = VN_CAST(controlp, Begin); AstBegin* beginp = VN_CAST(controlp, Begin);
if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp, false, false}; if (!beginp) beginp = new AstBegin{nodep->fileline(), "", controlp, false};
forkp->addStmtsp(beginp); forkp->addStmtsp(beginp);
controlp = forkp; controlp = forkp;
} }

View File

@ -209,8 +209,7 @@ class UnrollVisitor final : public VNVisitor {
if (loopValue) { if (loopValue) {
AstConst* varValuep = new AstConst{nodep->fileline(), *loopValue}; AstConst* varValuep = new AstConst{nodep->fileline(), *loopValue};
// Iteration requires a back, so put under temporary node // Iteration requires a back, so put under temporary node
AstBegin* tempp AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false};
= new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false};
replaceVarRef(tempp->stmtsp(), varValuep); replaceVarRef(tempp->stmtsp(), varValuep);
clonep = tempp->stmtsp()->unlinkFrBackWithNext(); clonep = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr);
@ -303,8 +302,7 @@ class UnrollVisitor final : public VNVisitor {
AstNode* clonep = initp->cloneTree(true); AstNode* clonep = initp->cloneTree(true);
AstConst* varValuep = new AstConst{nodep->fileline(), loopValue}; AstConst* varValuep = new AstConst{nodep->fileline(), loopValue};
// Iteration requires a back, so put under temporary node // Iteration requires a back, so put under temporary node
AstBegin* tempp AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false};
= new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false};
replaceVarRef(clonep, varValuep); replaceVarRef(clonep, varValuep);
clonep = tempp->stmtsp()->unlinkFrBackWithNext(); clonep = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr);
@ -329,8 +327,8 @@ class UnrollVisitor final : public VNVisitor {
AstConst* varValuep = new AstConst{nodep->fileline(), loopValue}; AstConst* varValuep = new AstConst{nodep->fileline(), loopValue};
if (oneloopp) { if (oneloopp) {
// Iteration requires a back, so put under temporary node // Iteration requires a back, so put under temporary node
AstBegin* const tempp = new AstBegin{oneloopp->fileline(), "[EditWrapper]", AstBegin* const tempp
oneloopp, false, false}; = new AstBegin{oneloopp->fileline(), "[EditWrapper]", oneloopp, false};
replaceVarRef(tempp->stmtsp(), varValuep); replaceVarRef(tempp->stmtsp(), varValuep);
oneloopp = tempp->stmtsp()->unlinkFrBackWithNext(); oneloopp = tempp->stmtsp()->unlinkFrBackWithNext();
VL_DO_DANGLING(tempp->deleteTree(), tempp); VL_DO_DANGLING(tempp->deleteTree(), tempp);
@ -338,8 +336,7 @@ class UnrollVisitor final : public VNVisitor {
if (m_generate) { if (m_generate) {
const string index = AstNode::encodeNumber(varValuep->toSInt()); const string index = AstNode::encodeNumber(varValuep->toSInt());
const string nname = m_beginName + "__BRA__" + index + "__KET__"; const string nname = m_beginName + "__BRA__" + index + "__KET__";
oneloopp oneloopp = new AstGenBlock{oneloopp->fileline(), nname, oneloopp, false};
= new AstBegin{oneloopp->fileline(), nname, oneloopp, true, false};
} }
VL_DO_DANGLING(pushDeletep(varValuep), varValuep); VL_DO_DANGLING(pushDeletep(varValuep), varValuep);
if (newbodysp) { if (newbodysp) {
@ -421,9 +418,7 @@ class UnrollVisitor final : public VNVisitor {
} }
} }
void visit(AstGenFor* nodep) override { void visit(AstGenFor* nodep) override {
if (!m_generate) { UASSERT_OBJ(m_generate, nodep, "There should be no GenFor left when unrolling all");
iterateChildren(nodep);
} // else V3Param will recursively call each for loop to be unrolled for us
if (!m_varModeCheck) { if (!m_varModeCheck) {
// Constify before unroll call, as it may change what is underneath. // Constify before unroll call, as it may change what is underneath.
if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change
@ -439,7 +434,7 @@ class UnrollVisitor final : public VNVisitor {
// deleted by V3Const. // deleted by V3Const.
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
} else if (forUnrollCheck(nodep, VOptionBool{}, nodep->initsp(), nodep->condp(), } else if (forUnrollCheck(nodep, VOptionBool{}, nodep->initsp(), nodep->condp(),
nodep->incsp(), nodep->stmtsp())) { nodep->incsp(), nodep->itemsp())) {
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
} else { } else {
nodep->v3error("For loop doesn't have genvar index, or is malformed"); nodep->v3error("For loop doesn't have genvar index, or is malformed");
@ -448,13 +443,6 @@ class UnrollVisitor final : public VNVisitor {
} }
} }
} }
void visit(AstNodeFor* nodep) override {
if (m_generate) { // Ignore for's when expanding genfor's
iterateChildren(nodep);
} else {
nodep->v3fatalSrc("V3Begin should have removed standard FORs");
}
}
void visit(AstVarRef* nodep) override { void visit(AstVarRef* nodep) override {
if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
@ -514,18 +502,16 @@ UnrollStateful::UnrollStateful()
: m_unrollerp{new UnrollVisitor} {} : m_unrollerp{new UnrollVisitor} {}
UnrollStateful::~UnrollStateful() { delete m_unrollerp; } UnrollStateful::~UnrollStateful() { delete m_unrollerp; }
void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) { void UnrollStateful::unrollGen(AstGenFor* nodep, const string& beginName) {
UINFO(5, __FUNCTION__ << ": "); UINFO(5, __FUNCTION__ << ": ");
m_unrollerp->process(nodep, true, beginName); m_unrollerp->process(nodep, true, beginName);
} }
void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); }
void V3Unroll::unrollAll(AstNetlist* nodep) { void V3Unroll::unrollAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ":"); UINFO(2, __FUNCTION__ << ":");
{ {
UnrollStateful unroller; UnrollVisitor visitor;
unroller.unrollAll(nodep); visitor.process(nodep, false, "");
} // Destruct before checking } // Destruct before checking
V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeEitherLevel() >= 3); V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeEitherLevel() >= 3);
} }

View File

@ -38,8 +38,7 @@ public:
UnrollStateful() VL_MT_DISABLED; UnrollStateful() VL_MT_DISABLED;
~UnrollStateful() VL_MT_DISABLED; ~UnrollStateful() VL_MT_DISABLED;
// METHODS // METHODS
void unrollGen(AstNodeFor* nodep, const string& beginName) VL_MT_DISABLED; void unrollGen(AstGenFor* nodep, const string& beginName) VL_MT_DISABLED;
void unrollAll(AstNetlist* nodep) VL_MT_DISABLED;
}; };
//============================================================================ //============================================================================

View File

@ -744,8 +744,7 @@ class WidthVisitor final : public VNVisitor {
|| (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())))) { || (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())))) {
AstNode* stmtsp = nullptr; AstNode* stmtsp = nullptr;
if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack(); if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack();
AstBegin* const newp AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false};
= new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false, false};
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep); VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else if (v3Global.opt.timing().isSetTrue()) { } else if (v3Global.opt.timing().isSetTrue()) {
@ -5261,46 +5260,31 @@ class WidthVisitor final : public VNVisitor {
//-------------------- //--------------------
// Top levels // Top levels
void visit(AstNodeCase* nodep) override { template <typename CaseItem>
// IEEE-2012 12.5: void handleCaseType(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) {
// Width: MAX(expr, all items) AstAttrOf* const exprap = VN_CAST(exprp, AttrOf);
// Signed: Only if expr, and all items signed if (!exprap) return;
assertAtStatement(nodep); if (exprap->attrType() != VAttrType::TYPEID) return;
userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p());
for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced
if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->stmtsp(), nullptr);
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
nextcp = condp->nextp(); // Prelim may cause the node to get replaced
VL_DO_DANGLING(userIterate(condp, WidthVP{CONTEXT_DET, PRELIM}.p()), condp);
}
}
// Deal with case(type(data_type))
if (AstAttrOf* const exprap = VN_CAST(nodep->exprp(), AttrOf)) {
if (exprap->attrType() == VAttrType::TYPEID) {
const AstNodeDType* const exprDtp = exprap->dtypep(); const AstNodeDType* const exprDtp = exprap->dtypep();
UINFO(9, "case type exprDtp " << exprDtp); UINFO(9, "case type exprDtp " << exprDtp);
// V3Param may have a pointer to this case statement, and we need // V3Param may have a pointer to this case statement, and we need
// dotted references to remain properly named, so rather than // dotted references to remain properly named, so rather than
// removing we convert it to a "normal" expression "case (1) ..." // removing we convert it to a "normal" expression "case (1) ..."
FileLine* const newfl = nodep->fileline(); FileLine* const newfl = casep->fileline();
newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform
newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform
nodep->fileline(newfl); casep->fileline(newfl);
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
itemp = VN_AS(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) continue;
if (!itemp->isDefault()) {
bool hit = false; bool hit = false;
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf); const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf);
if (!condAttrp) { if (!condAttrp) {
condp->v3error( condp->v3error("Case(type) statement requires items that have type() items");
"Case(type) statement requires items that have type() items");
} else { } else {
AstNodeDType* const condDtp = condAttrp->dtypep(); AstNodeDType* const condDtp = condAttrp->dtypep();
if (AstNode::computeCastable(exprDtp, condDtp, nodep) if (AstNode::computeCastable(exprDtp, condDtp, casep) == VCastable::SAMEISH) {
== VCastable::SAMEISH) {
hit = true; hit = true;
break; break;
} }
@ -5310,43 +5294,90 @@ class WidthVisitor final : public VNVisitor {
// Item condition becomes constant 1 if hits else 0 // Item condition becomes constant 1 if hits else 0
itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit}); itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit});
} }
} exprap->replaceWith(new AstConst{newfl, AstConst::BitTrue{}});
VL_DO_DANGLING(pushDeletep(exprap->unlinkFrBack()), exprap); VL_DO_DANGLING(pushDeletep(exprap), exprap);
nodep->exprp(new AstConst{newfl, AstConst::BitTrue{}});
}
} }
template <typename CaseItem>
void handleCase(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) {
// IEEE-2012 12.5:
// Width: MAX(expr, all items)
// Signed: Only if expr, and all items signed
// Take width as maximum across all items, if any is real whole thing is real // Take width as maximum across all items, if any is real whole thing is real
AstNodeDType* subDTypep = nodep->exprp()->dtypep(); AstNodeDType* subDTypep = exprp->dtypep();
for (AstCaseItem* itemp = nodep->itemsp(); itemp; for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
if (condp->dtypep() != subDTypep) { if (condp->dtypep() == subDTypep) continue;
if (condp->dtypep()->isDouble() || subDTypep->isDouble()) { if (condp->dtypep()->isDouble() || subDTypep->isDouble()) {
subDTypep = nodep->findDoubleDType(); subDTypep = casep->findDoubleDType();
} else if (condp->dtypep()->isString() || subDTypep->isString()) { } else if (condp->dtypep()->isString() || subDTypep->isString()) {
subDTypep = nodep->findStringDType(); subDTypep = casep->findStringDType();
} else { } else {
const int width = std::max(subDTypep->width(), condp->width()); const int width = std::max(subDTypep->width(), condp->width());
const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin()); const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin());
const bool issigned = subDTypep->isSigned() && condp->isSigned(); const bool issigned = subDTypep->isSigned() && condp->isSigned();
subDTypep subDTypep = casep->findLogicDType(width, mwidth, VSigning::fromBool(issigned));
= nodep->findLogicDType(width, mwidth, VSigning::fromBool(issigned));
}
} }
} }
} }
// Apply width // Apply width
iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT_DET, FINAL, subDTypep, iterateCheck(casep, "Case expression", exprp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP);
EXTEND_EXP); for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
nextcp = condp->nextp(); // Final may cause the node to get replaced nextcp = condp->nextp(); // Final may cause the node to get replaced
iterateCheck(nodep, "Case Item", condp, CONTEXT_DET, FINAL, subDTypep, EXTEND_LHS); iterateCheck(casep, "Case Item", condp, CONTEXT_DET, FINAL, subDTypep, EXTEND_LHS);
} }
} }
} }
void visit(AstGenCase* nodep) override {
assertAtStatement(nodep);
// Type check expression and case item conditions, but not bodies
userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p());
for (AstGenCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
// Prelim may cause the node to get replaced, pick up next up front
nextip = VN_AS(itemp->nextp(), GenCaseItem);
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
// Prelim may cause the node to get replaced, pick up next up front
nextcp = condp->nextp();
VL_DO_DANGLING(userIterate(condp, WidthVP{CONTEXT_DET, PRELIM}.p()), condp);
}
}
// Deal with case(type(data_type))
handleCaseType(nodep, nodep->exprp(), nodep->itemsp());
// Type check
handleCase(nodep, nodep->exprp(), nodep->itemsp());
}
void visit(AstGenFor* nodep) override {
assertAtStatement(nodep);
userIterateAndNext(nodep->initsp(), nullptr);
iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH);
userIterateAndNext(nodep->incsp(), nullptr);
}
void visit(AstGenIf* nodep) override {
assertAtStatement(nodep);
iterateCheckBool(nodep, "If", nodep->condp(), BOTH);
}
void visit(AstCase* nodep) override {
assertAtStatement(nodep);
// Type check expression case item conditions and bodies
userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p());
for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced
userIterateAndNext(itemp->stmtsp(), nullptr);
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
nextcp = condp->nextp(); // Prelim may cause the node to get replaced
VL_DO_DANGLING(userIterate(condp, WidthVP{CONTEXT_DET, PRELIM}.p()), condp);
}
}
// Deal with case(type(data_type))
handleCaseType(nodep, nodep->exprp(), nodep->itemsp());
// Type check
handleCase(nodep, nodep->exprp(), nodep->itemsp());
}
void visit(AstRandCase* nodep) override { void visit(AstRandCase* nodep) override {
// IEEE says each item is a int (32-bits), and sizes are based on natural sizing, // IEEE says each item is a int (32-bits), and sizes are based on natural sizing,
// but we'll sum to a 64-bit number then math is faster. // but we'll sum to a 64-bit number then math is faster.
@ -5365,14 +5396,6 @@ class WidthVisitor final : public VNVisitor {
} }
} }
void visit(AstNodeFor* nodep) override {
assertAtStatement(nodep);
userIterateAndNext(nodep->initsp(), nullptr);
iterateCheckBool(nodep, "For Test Condition", nodep->condp(),
BOTH); // it's like an if() condition.
if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->stmtsp(), nullptr);
userIterateAndNext(nodep->incsp(), nullptr);
}
void visit(AstRepeat* nodep) override { void visit(AstRepeat* nodep) override {
assertAtStatement(nodep); assertAtStatement(nodep);
userIterateAndNext(nodep->countp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->countp(), WidthVP{SELF, BOTH}.p());
@ -5388,10 +5411,8 @@ class WidthVisitor final : public VNVisitor {
void visit(AstNodeIf* nodep) override { void visit(AstNodeIf* nodep) override {
assertAtStatement(nodep); assertAtStatement(nodep);
// UINFOTREE(1, nodep, "", "IfPre"); // UINFOTREE(1, nodep, "", "IfPre");
if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly
userIterateAndNext(nodep->thensp(), nullptr); userIterateAndNext(nodep->thensp(), nullptr);
userIterateAndNext(nodep->elsesp(), nullptr); userIterateAndNext(nodep->elsesp(), nullptr);
}
iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition. iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition.
// UINFOTREE(1, nodep, "", "IfOut"); // UINFOTREE(1, nodep, "", "IfOut");
} }

View File

@ -179,6 +179,7 @@ static void process() {
// Remove parameters by cloning modules to de-parameterized versions // Remove parameters by cloning modules to de-parameterized versions
// This requires some width calculations and constant propagation // This requires some width calculations and constant propagation
// No more AstGenCase/AstGenFor/AstGenIf after this
V3Param::param(v3Global.rootp()); V3Param::param(v3Global.rootp());
V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules
V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs
@ -271,6 +272,7 @@ static void process() {
// Task inlining & pushing BEGINs names to variables/cells // Task inlining & pushing BEGINs names to variables/cells
// Begin processing must be after Param, before module inlining // Begin processing must be after Param, before module inlining
// No more AstGenBlocks after this
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
// Expand inouts, stage 2 // Expand inouts, stage 2

View File

@ -2713,7 +2713,7 @@ generate_block_or_null<nodep>: // IEEE: generate_block_or_null (called from gen
// // IEEE: generate_block // // IEEE: generate_block
// // Must always return a BEGIN node, or nullptr - see GenFor construction // // Must always return a BEGIN node, or nullptr - see GenFor construction
~c~generate_item ~c~generate_item
{ $$ = $1 ? (new AstBegin{$1->fileline(), "", $1, true, true}) : nullptr; } { $$ = $1 ? (new AstGenBlock{$1->fileline(), "", $1, true}) : nullptr; }
| ~c~genItemBegin { $$ = $1; } | ~c~genItemBegin { $$ = $1; }
; ;
@ -2722,19 +2722,19 @@ c_generate_block_or_null<nodep>: // IEEE: generate_block_or_null (for checkers)
; ;
genItemBegin<nodep>: // IEEE: part of generate_block genItemBegin<nodep>: // IEEE: part of generate_block
yBEGIN ~c~genItemList yEND { $$ = new AstBegin{$1, "", $2, true, false}; } yBEGIN ~c~genItemList yEND { $$ = new AstGenBlock{$1, "", $2, false}; }
| yBEGIN yEND { $$ = nullptr; } | yBEGIN yEND { $$ = nullptr; }
| id yP_COLON__BEGIN yBEGIN ~c~genItemList yEND endLabelE | id yP_COLON__BEGIN yBEGIN ~c~genItemList yEND endLabelE
{ $$ = new AstBegin{$<fl>1, *$1, $4, true, false}; { $$ = new AstGenBlock{$<fl>1, *$1, $4, false};
GRAMMARP->endLabel($<fl>6, *$1, $6); } GRAMMARP->endLabel($<fl>6, *$1, $6); }
| id yP_COLON__BEGIN yBEGIN yEND endLabelE | id yP_COLON__BEGIN yBEGIN yEND endLabelE
{ $$ = new AstBegin{$<fl>1, *$1, nullptr, true, false}; { $$ = new AstGenBlock{$<fl>1, *$1, nullptr, false};
GRAMMARP->endLabel($<fl>5, *$1, $5); } GRAMMARP->endLabel($<fl>5, *$1, $5); }
| yBEGIN ':' idAny ~c~genItemList yEND endLabelE | yBEGIN ':' idAny ~c~genItemList yEND endLabelE
{ $$ = new AstBegin{$<fl>3, *$3, $4, true, false}; { $$ = new AstGenBlock{$<fl>3, *$3, $4, false};
GRAMMARP->endLabel($<fl>6, *$3, $6); } GRAMMARP->endLabel($<fl>6, *$3, $6); }
| yBEGIN ':' idAny yEND endLabelE | yBEGIN ':' idAny yEND endLabelE
{ $$ = new AstBegin{$<fl>3, *$3, nullptr, true, false}; { $$ = new AstGenBlock{$<fl>3, *$3, nullptr, false};
GRAMMARP->endLabel($<fl>5, *$3, $5); } GRAMMARP->endLabel($<fl>5, *$3, $5); }
; ;
@ -2803,27 +2803,23 @@ c_conditional_generate_construct<nodep>: // IEEE: conditional_generate_construc
loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct
yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null
{ // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar
AstBegin* lowerBegp = VN_CAST($9, Begin); AstGenBlock* lowerp = VN_CAST($9, GenBlock);
UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); UASSERT_OBJ(!$9 || lowerp, $9, "Child of GENFOR should have been begin");
AstNode* const itemsp = lowerp && lowerp->itemsp() ? lowerp->itemsp()->unlinkFrBackWithNext() : nullptr;
if (!lowerBegp) lowerBegp = new AstBegin{$1, "", nullptr, true, false}; // Empty body AstGenBlock* const blkp = new AstGenBlock{$1, lowerp ? lowerp->name() : "", nullptr, true};
AstNode* const lowerNoBegp = lowerBegp->stmtsp();
if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext();
//
AstBegin* const blkp = new AstBegin{$1, lowerBegp->name(), nullptr, true, true};
// V3LinkDot detects BEGIN(GENFOR(...)) as a special case // V3LinkDot detects BEGIN(GENFOR(...)) as a special case
AstNode* initp = $3; AstNode* initp = $3;
AstNode* const varp = $3; AstNode* const varp = $3;
if (VN_IS(varp, Var)) { // Genvar if (VN_IS(varp, Var)) { // Genvar
initp = varp->nextp(); initp = varp->nextp();
initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init
blkp->addStmtsp(varp); blkp->addItemsp(varp);
} }
// Statements are under 'genforp' as instances under this // Statements are under 'genforp' as instances under this
// for loop won't get an extra layer of hierarchy tacked on // for loop won't get an extra layer of hierarchy tacked on
blkp->genforp(new AstGenFor{$1, initp, $5, $7, lowerNoBegp}); blkp->genforp(new AstGenFor{$1, initp, $5, $7, itemsp});
$$ = blkp; $$ = blkp;
VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp); DEL(lowerp);
} }
; ;
@ -2878,22 +2874,22 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; }
; ;
case_generate_itemList<caseItemp>: // IEEE: { case_generate_itemList } case_generate_itemList<genCaseItemp>: // IEEE: { case_generate_itemList }
~c~case_generate_item { $$ = $1; } ~c~case_generate_item { $$ = $1; }
| ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); }
; ;
c_case_generate_itemList<caseItemp>: // IEEE: { case_generate_item } (for checkers) c_case_generate_itemList<genCaseItemp>: // IEEE: { case_generate_item } (for checkers)
BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied}
; ;
case_generate_item<caseItemp>: // ==IEEE: case_generate_item case_generate_item<genCaseItemp>: // ==IEEE: case_generate_item
caseCondList colon ~c~generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } caseCondList colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$2, $1, $3}; }
| yDEFAULT colon ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } | yDEFAULT colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$1, nullptr, $3}; }
| yDEFAULT ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } | yDEFAULT ~c~generate_block_or_null { $$ = new AstGenCaseItem{$1, nullptr, $2}; }
; ;
c_case_generate_item<caseItemp>: // IEEE: case_generate_item (for checkers) c_case_generate_item<genCaseItemp>: // IEEE: case_generate_item (for checkers)
BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied}
; ;
@ -3409,9 +3405,9 @@ par_blockPreId<nodep>: // ==IEEE: par_block but called with leading ID
seq_blockFront<beginp>: // IEEE: part of seq_block seq_blockFront<beginp>: // IEEE: part of seq_block
yBEGIN yBEGIN
{ $$ = new AstBegin{$1, "", nullptr, false, false}; } { $$ = new AstBegin{$1, "", nullptr, false}; }
| yBEGIN ':' idAny/*new-block_identifier*/ | yBEGIN ':' idAny/*new-block_identifier*/
{ $$ = new AstBegin{$<fl>3, *$3, nullptr, false, false}; } { $$ = new AstBegin{$<fl>3, *$3, nullptr, false}; }
; ;
par_blockFront<forkp>: // IEEE: part of par_block par_blockFront<forkp>: // IEEE: part of par_block
@ -3423,7 +3419,7 @@ par_blockFront<forkp>: // IEEE: part of par_block
seq_blockFrontPreId<beginp>: // IEEE: part of seq_block/stmt with leading id seq_blockFrontPreId<beginp>: // IEEE: part of seq_block/stmt with leading id
id/*block_identifier*/ yP_COLON__BEGIN yBEGIN id/*block_identifier*/ yP_COLON__BEGIN yBEGIN
{ $$ = new AstBegin{$3, *$1, nullptr, false, false}; } { $$ = new AstBegin{$3, *$1, nullptr, false}; }
; ;
par_blockFrontPreId<forkp>: // IEEE: part of par_block/stmt with leading id par_blockFrontPreId<forkp>: // IEEE: part of par_block/stmt with leading id
@ -3468,7 +3464,7 @@ stmtList<nodep>:
stmt<nodep>: // IEEE: statement_or_null == function_statement_or_null stmt<nodep>: // IEEE: statement_or_null == function_statement_or_null
statement_item { $$ = $1; } statement_item { $$ = $1; }
// // S05 block creation rule // // S05 block creation rule
| id/*block_identifier*/ ':' statement_item { $$ = new AstBegin{$<fl>1, *$1, $3, false, false}; } | id/*block_identifier*/ ':' statement_item { $$ = new AstBegin{$<fl>1, *$1, $3, false}; }
// // from _or_null // // from _or_null
| ';' { $$ = nullptr; } | ';' { $$ = nullptr; }
// // labeled par_block/seq_block with leading ':' // // labeled par_block/seq_block with leading ':'
@ -3590,7 +3586,7 @@ statement_item<nodep>: // IEEE: statement_item
| yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = new AstDoWhile{$1, $5, $2}; } | yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = new AstDoWhile{$1, $5, $2}; }
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
| yFOREACH '(' idClassSelForeach ')' stmtBlock | yFOREACH '(' idClassSelForeach ')' stmtBlock
{ $$ = new AstBegin{$1, "", new AstForeach{$1, $3, $5}, false, true}; } { $$ = new AstBegin{$1, "", new AstForeach{$1, $3, $5}, true}; }
// //
// // IEEE: jump_statement // // IEEE: jump_statement
| yRETURN ';' { $$ = new AstReturn{$1}; } | yRETURN ';' { $$ = new AstReturn{$1}; }
@ -3652,10 +3648,10 @@ statement_item<nodep>: // IEEE: statement_item
statementFor<beginp>: // IEEE: part of statement statementFor<beginp>: // IEEE: part of statement
yFOR beginForParen for_initialization expr ';' for_stepE ')' stmtBlock yFOR beginForParen for_initialization expr ';' for_stepE ')' stmtBlock
{ $$ = new AstBegin{$1, "", $3, false, true}; { $$ = new AstBegin{$1, "", $3, true};
$$->addStmtsp(new AstWhile{$1, $4, $8, $6}); } $$->addStmtsp(new AstWhile{$1, $4, $8, $6}); }
| yFOR beginForParen for_initialization ';' for_stepE ')' stmtBlock | yFOR beginForParen for_initialization ';' for_stepE ')' stmtBlock
{ $$ = new AstBegin{$1, "", $3, false, true}; { $$ = new AstBegin{$1, "", $3, true};
$$->addStmtsp(new AstWhile{$1, new AstConst{$1, AstConst::BitTrue{}}, $7, $5}); } $$->addStmtsp(new AstWhile{$1, new AstConst{$1, AstConst::BitTrue{}}, $7, $5}); }
; ;
beginForParen: // IEEE: Part of statement (for loop beginning paren) beginForParen: // IEEE: Part of statement (for loop beginning paren)
@ -6160,7 +6156,7 @@ assertion_item<nodep>: // ==IEEE: assertion_item
deferred_immediate_assertion_item<nodep>: // ==IEEE: deferred_immediate_assertion_item deferred_immediate_assertion_item<nodep>: // ==IEEE: deferred_immediate_assertion_item
deferred_immediate_assertion_statement { $$ = $1; } deferred_immediate_assertion_statement { $$ = $1; }
| id/*block_identifier*/ ':' deferred_immediate_assertion_statement | id/*block_identifier*/ ':' deferred_immediate_assertion_statement
{ $$ = new AstBegin{$<fl>1, *$1, $3, false, true}; } { $$ = new AstBegin{$<fl>1, *$1, $3, true}; }
; ;
procedural_assertion_statement<nodep>: // ==IEEE: procedural_assertion_statement procedural_assertion_statement<nodep>: // ==IEEE: procedural_assertion_statement
@ -6216,7 +6212,7 @@ deferred_immediate_assertion_statement<nodep>: // ==IEEE: deferred_immediate_as
concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item
concurrent_assertion_statement { $$ = $1; } concurrent_assertion_statement { $$ = $1; }
| id/*block_identifier*/ ':' concurrent_assertion_statement | id/*block_identifier*/ ':' concurrent_assertion_statement
{ $$ = new AstBegin{$<fl>1, *$1, $3, false, true}; } { $$ = new AstBegin{$<fl>1, *$1, $3, true}; }
// // IEEE: checker_instantiation // // IEEE: checker_instantiation
// // identical to module_instantiation; see etcInst // // identical to module_instantiation; see etcInst
; ;

View File

@ -5,7 +5,7 @@
{"type":"VAR","name":"p","addr":"(G)","loc":"d,69:11,69:12","dtypep":"(H)","origName":"p","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"Packet","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"VAR","name":"p","addr":"(G)","loc":"d,69:11,69:12","dtypep":"(H)","origName":"p","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"Packet","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
{"type":"INITIAL","name":"","addr":"(I)","loc":"d,71:4,71:11","isSuspendable":false,"needProcess":false, {"type":"INITIAL","name":"","addr":"(I)","loc":"d,71:4,71:11","isSuspendable":false,"needProcess":false,
"stmtsp": [ "stmtsp": [
{"type":"BEGIN","name":"","addr":"(J)","loc":"d,71:12,71:17","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(J)","loc":"d,71:12,71:17","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"DISPLAY","name":"","addr":"(K)","loc":"d,73:7,73:13", {"type":"DISPLAY","name":"","addr":"(K)","loc":"d,73:7,73:13",
"fmtp": [ "fmtp": [

View File

@ -160,7 +160,7 @@
]} ]}
], ],
"stmtsp": [ "stmtsp": [
{"type":"BEGIN","name":"","addr":"(XC)","loc":"e,36:27,36:32","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(XC)","loc":"e,36:27,36:32","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGNDLY","name":"","addr":"(YC)","loc":"e,40:11,40:13","dtypep":"UNLINKED", {"type":"ASSIGNDLY","name":"","addr":"(YC)","loc":"e,40:11,40:13","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -308,7 +308,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(ZE)","loc":"e,43:21,43:26","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(ZE)","loc":"e,43:21,43:26","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGNDLY","name":"","addr":"(AF)","loc":"e,45:14,45:16","dtypep":"UNLINKED", {"type":"ASSIGNDLY","name":"","addr":"(AF)","loc":"e,45:14,45:16","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -338,7 +338,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(MF)","loc":"e,48:26,48:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(MF)","loc":"e,48:26,48:31","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGNDLY","name":"","addr":"(NF)","loc":"e,49:14,49:16","dtypep":"UNLINKED", {"type":"ASSIGNDLY","name":"","addr":"(NF)","loc":"e,49:14,49:16","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -361,7 +361,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(VF)","loc":"e,51:26,51:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [],"stmtsp": []} {"type":"BEGIN","name":"","addr":"(VF)","loc":"e,51:26,51:31","implied":false,"needProcess":false,"unnamed":true,"stmtsp": []}
], ],
"elsesp": [ "elsesp": [
{"type":"IF","name":"","addr":"(WF)","loc":"e,53:12,53:14", {"type":"IF","name":"","addr":"(WF)","loc":"e,53:12,53:14",
@ -375,7 +375,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(AG)","loc":"e,53:27,53:32","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(AG)","loc":"e,53:27,53:32","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"DISPLAY","name":"","addr":"(BG)","loc":"e,54:10,54:16", {"type":"DISPLAY","name":"","addr":"(BG)","loc":"e,54:10,54:16",
"fmtp": [ "fmtp": [
@ -479,7 +479,7 @@
]} ]}
], ],
"stmtsp": [ "stmtsp": [
{"type":"BEGIN","name":"","addr":"(UH)","loc":"e,82:26,82:31","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(UH)","loc":"e,82:26,82:31","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGNDLY","name":"","addr":"(VH)","loc":"e,83:11,83:13","dtypep":"UNLINKED", {"type":"ASSIGNDLY","name":"","addr":"(VH)","loc":"e,83:11,83:13","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -529,7 +529,7 @@
"assertTypesp": [ "assertTypesp": [
{"type":"CONST","name":"?32?sh8","addr":"(OI)","loc":"e,90:25,90:26","dtypep":"(LF)"} {"type":"CONST","name":"?32?sh8","addr":"(OI)","loc":"e,90:25,90:26","dtypep":"(LF)"}
],"directiveTypesp": []}, ],"directiveTypesp": []},
{"type":"BEGIN","name":"blk","addr":"(PI)","loc":"e,91:15,91:18","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], {"type":"BEGIN","name":"blk","addr":"(PI)","loc":"e,91:15,91:18","implied":false,"needProcess":false,"unnamed":false,
"stmtsp": [ "stmtsp": [
{"type":"DISABLE","name":"","addr":"(QI)","loc":"e,92:10,92:17", {"type":"DISABLE","name":"","addr":"(QI)","loc":"e,92:10,92:17",
"targetRefp": [ "targetRefp": [
@ -639,7 +639,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(GK)","loc":"d,55:44,55:49","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(GK)","loc":"d,55:44,55:49","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"STMTEXPR","name":"","addr":"(HK)","loc":"d,56:16,56:17", {"type":"STMTEXPR","name":"","addr":"(HK)","loc":"d,56:16,56:17",
"exprp": [ "exprp": [
@ -695,7 +695,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(DL)","loc":"d,72:22,72:27","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(DL)","loc":"d,72:22,72:27","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGN","name":"","addr":"(EL)","loc":"d,73:17,73:18","dtypep":"UNLINKED", {"type":"ASSIGN","name":"","addr":"(EL)","loc":"d,73:17,73:18","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -748,7 +748,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(YL)","loc":"d,89:22,89:27","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(YL)","loc":"d,89:22,89:27","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGN","name":"","addr":"(ZL)","loc":"d,90:17,90:18","dtypep":"UNLINKED", {"type":"ASSIGN","name":"","addr":"(ZL)","loc":"d,90:17,90:18","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [
@ -854,7 +854,7 @@
]} ]}
], ],
"thensp": [ "thensp": [
{"type":"BEGIN","name":"","addr":"(ON)","loc":"d,118:35,118:40","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(ON)","loc":"d,118:35,118:40","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"ASSIGN","name":"","addr":"(PN)","loc":"d,119:20,119:22","dtypep":"UNLINKED", {"type":"ASSIGN","name":"","addr":"(PN)","loc":"d,119:20,119:22","dtypep":"UNLINKED",
"rhsp": [ "rhsp": [

View File

@ -1,4 +1,4 @@
%Error: t/t_duplicated_gen_blocks_bad.v:11:12: Duplicate declaration of block: 'block' %Error: t/t_duplicated_gen_blocks_bad.v:11:12: Duplicate declaration of generate block: 'block'
: ... note: In instance 't' : ... note: In instance 't'
11 | begin : block 11 | begin : block
| ^~~~~ | ^~~~~
@ -6,7 +6,7 @@
9 | begin : block 9 | begin : block
| ^~~~~ | ^~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_duplicated_gen_blocks_bad.v:15:23: Duplicate declaration of block: 'block1' %Error: t/t_duplicated_gen_blocks_bad.v:15:23: Duplicate declaration of generate block: 'block1'
: ... note: In instance 't' : ... note: In instance 't'
15 | if (X > 1) begin : block1 15 | if (X > 1) begin : block1
| ^~~~~~ | ^~~~~~

View File

@ -3,21 +3,21 @@
{"type":"MODULE","name":"test","addr":"(E)","loc":"d,22:8,22:12","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"test","level":2,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [], {"type":"MODULE","name":"test","addr":"(E)","loc":"d,22:8,22:12","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"test","level":2,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [],
"stmtsp": [ "stmtsp": [
{"type":"VAR","name":"N","addr":"(F)","loc":"d,24:12,24:13","dtypep":"(G)","origName":"N","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":true,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"GENVAR","dtypeName":"integer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"VAR","name":"N","addr":"(F)","loc":"d,24:12,24:13","dtypep":"(G)","origName":"N","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":true,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"GENVAR","dtypeName":"integer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
{"type":"BEGIN","name":"FOR_GENERATE","addr":"(H)","loc":"d,25:14,25:17","generate":true,"genfor":false,"implied":true,"needProcess":false,"unnamed":false,"genforp": [],"stmtsp": []}, {"type":"GENBLOCK","name":"FOR_GENERATE","addr":"(H)","loc":"d,25:14,25:17","implied":true,"unnamed":false,"genforp": [],"itemsp": []},
{"type":"BEGIN","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], {"type":"GENBLOCK","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"CELL","name":"submod_for","addr":"(J)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}, {"type":"CELL","name":"submod_for","addr":"(J)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []},
{"type":"BEGIN","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"GENBLOCK","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"CELL","name":"submod_2","addr":"(M)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_2","addr":"(M)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
]}, ]},
{"type":"CELL","name":"submod_3","addr":"(N)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_3","addr":"(N)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
]}, ]},
{"type":"BEGIN","name":"FOR_GENERATE[1]","addr":"(O)","loc":"d,27:21,27:31","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], {"type":"GENBLOCK","name":"FOR_GENERATE[1]","addr":"(O)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"CELL","name":"submod_for","addr":"(P)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}, {"type":"CELL","name":"submod_for","addr":"(P)","loc":"d,27:21,27:31","origName":"submod_for","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []},
{"type":"BEGIN","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"GENBLOCK","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"CELL","name":"submod_2","addr":"(R)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_2","addr":"(R)","loc":"d,29:25,29:33","origName":"submod_2","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
]}, ]},
{"type":"CELL","name":"submod_3","addr":"(S)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_3","addr":"(S)","loc":"d,31:21,31:29","origName":"submod_3","recursive":false,"modp":"(K)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
@ -25,11 +25,11 @@
]}, ]},
{"type":"MODULE","name":"submod","addr":"(K)","loc":"d,10:8,10:14","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"submod","level":3,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [], {"type":"MODULE","name":"submod","addr":"(K)","loc":"d,10:8,10:14","isChecker":false,"isProgram":false,"hasGenericIface":false,"origName":"submod","level":3,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"1ps","inlinesp": [],
"stmtsp": [ "stmtsp": [
{"type":"BEGIN","name":"submod_gen","addr":"(T)","loc":"d,12:19,12:29","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], {"type":"GENBLOCK","name":"submod_gen","addr":"(T)","loc":"d,12:19,12:29","implied":false,"unnamed":false,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"VAR","name":"l1_sig","addr":"(U)","loc":"d,13:14,13:20","dtypep":"(V)","origName":"l1_sig","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"VAR","name":"l1_sig","addr":"(U)","loc":"d,13:14,13:20","dtypep":"(V)","origName":"l1_sig","isSc":false,"isPrimaryIO":false,"isPrimaryClock":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"ignorePostWrite":false,"ignoreSchedWrite":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
{"type":"BEGIN","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [], {"type":"GENBLOCK","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","implied":false,"unnamed":false,"genforp": [],
"stmtsp": [ "itemsp": [
{"type":"CELL","name":"submod_nested","addr":"(X)","loc":"d,15:21,15:34","origName":"submod_nested","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_nested","addr":"(X)","loc":"d,15:21,15:34","origName":"submod_nested","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
]}, ]},
{"type":"CELL","name":"submod_l1","addr":"(Z)","loc":"d,17:17,17:26","origName":"submod_l1","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []} {"type":"CELL","name":"submod_l1","addr":"(Z)","loc":"d,17:17,17:26","origName":"submod_l1","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}

View File

@ -33,7 +33,7 @@
],"scopeNamep": []}, ],"scopeNamep": []},
{"type":"INITIAL","name":"","addr":"(FB)","loc":"d,39:4,39:11","isSuspendable":false,"needProcess":false, {"type":"INITIAL","name":"","addr":"(FB)","loc":"d,39:4,39:11","isSuspendable":false,"needProcess":false,
"stmtsp": [ "stmtsp": [
{"type":"BEGIN","name":"","addr":"(GB)","loc":"d,39:12,39:17","generate":false,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [], {"type":"BEGIN","name":"","addr":"(GB)","loc":"d,39:12,39:17","implied":false,"needProcess":false,"unnamed":true,
"stmtsp": [ "stmtsp": [
{"type":"STMTEXPR","name":"","addr":"(HB)","loc":"d,41:7,41:8", {"type":"STMTEXPR","name":"","addr":"(HB)","loc":"d,41:7,41:8",
"exprp": [ "exprp": [

View File

@ -47,30 +47,30 @@
<netlist> <netlist>
<module loc="d,22,8,22,12" name="test" origName="test" topModule="1"> <module loc="d,22,8,22,12" name="test" origName="test" topModule="1">
<var loc="d,24,12,24,13" name="N" dtype_id="1" vartype="integer" origName="N"/> <var loc="d,24,12,24,13" name="N" dtype_id="1" vartype="integer" origName="N"/>
<begin loc="d,25,14,25,17" name="FOR_GENERATE"/> <genblock loc="d,25,14,25,17" name="FOR_GENERATE"/>
<begin loc="d,27,21,27,31" name="FOR_GENERATE[0]"> <genblock loc="d,27,21,27,31" name="FOR_GENERATE[0]">
<instance loc="d,27,21,27,31" name="submod_for" defName="submod" origName="submod_for"/> <instance loc="d,27,21,27,31" name="submod_for" defName="submod" origName="submod_for"/>
<begin loc="d,28,19,28,24" name="genblk1"> <genblock loc="d,28,19,28,24" name="genblk1">
<instance loc="d,29,25,29,33" name="submod_2" defName="submod" origName="submod_2"/> <instance loc="d,29,25,29,33" name="submod_2" defName="submod" origName="submod_2"/>
</begin> </genblock>
<instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/> <instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/>
</begin> </genblock>
<begin loc="d,27,21,27,31" name="FOR_GENERATE[1]"> <genblock loc="d,27,21,27,31" name="FOR_GENERATE[1]">
<instance loc="d,27,21,27,31" name="submod_for" defName="submod" origName="submod_for"/> <instance loc="d,27,21,27,31" name="submod_for" defName="submod" origName="submod_for"/>
<begin loc="d,28,19,28,24" name="genblk1"> <genblock loc="d,28,19,28,24" name="genblk1">
<instance loc="d,29,25,29,33" name="submod_2" defName="submod" origName="submod_2"/> <instance loc="d,29,25,29,33" name="submod_2" defName="submod" origName="submod_2"/>
</begin> </genblock>
<instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/> <instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/>
</begin> </genblock>
</module> </module>
<module loc="d,10,8,10,14" name="submod" origName="submod"> <module loc="d,10,8,10,14" name="submod" origName="submod">
<begin loc="d,12,19,12,29" name="submod_gen"> <genblock loc="d,12,19,12,29" name="submod_gen">
<var loc="d,13,14,13,20" name="l1_sig" dtype_id="2" vartype="logic" origName="l1_sig"/> <var loc="d,13,14,13,20" name="l1_sig" dtype_id="2" vartype="logic" origName="l1_sig"/>
<begin loc="d,14,23,14,33" name="nested_gen"> <genblock loc="d,14,23,14,33" name="nested_gen">
<instance loc="d,15,21,15,34" name="submod_nested" defName="submod2" origName="submod_nested"/> <instance loc="d,15,21,15,34" name="submod_nested" defName="submod2" origName="submod_nested"/>
</begin> </genblock>
<instance loc="d,17,17,17,26" name="submod_l1" defName="submod2" origName="submod_l1"/> <instance loc="d,17,17,17,26" name="submod_l1" defName="submod2" origName="submod_l1"/>
</begin> </genblock>
<instance loc="d,19,13,19,22" name="submod_l0" defName="submod2" origName="submod_l0"/> <instance loc="d,19,13,19,22" name="submod_l0" defName="submod2" origName="submod_l0"/>
</module> </module>
<module loc="d,7,8,7,15" name="submod2" origName="submod2"/> <module loc="d,7,8,7,15" name="submod2" origName="submod2"/>