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:
parent
df187c4406
commit
800af37975
|
|
@ -129,7 +129,7 @@ class AssertVisitor final : public VNVisitor {
|
|||
|
||||
// STATE
|
||||
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)
|
||||
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
|
||||
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
|
||||
|
|
@ -809,6 +809,13 @@ class AssertVisitor final : public VNVisitor {
|
|||
m_procedurep = 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 {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ private:
|
|||
nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||
cntVarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
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 AstWhile{
|
||||
nodep->fileline(),
|
||||
|
|
|
|||
|
|
@ -1078,8 +1078,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(VNVisitor& v) {
|
|||
} else if (!nodep->backp()) {
|
||||
// Calling on standalone tree; insert a shim node so we can keep
|
||||
// track, then delete it on completion
|
||||
AstBegin* const tempp
|
||||
= new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false, false};
|
||||
AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep, false};
|
||||
// nodep to null as may be replaced
|
||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep);
|
||||
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
|
|
|
|||
|
|
@ -267,6 +267,13 @@ public:
|
|||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
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 {
|
||||
// A module, package, program or interface declaration;
|
||||
// something that can live directly under the TOP,
|
||||
|
|
@ -668,21 +675,6 @@ public:
|
|||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
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 {
|
||||
// A instantiation cell or interface call (don't know which until link)
|
||||
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
|
||||
|
|
@ -1137,6 +1129,19 @@ public:
|
|||
V3Graph* depGraphp() { 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 {
|
||||
// Create implicit wires and do nothing else, for gates that are ignored
|
||||
// Parents: MODULE
|
||||
|
|
@ -2287,22 +2292,18 @@ public:
|
|||
class AstBegin final : public AstNodeBlock {
|
||||
// A Begin/end named block, only exists shortly after parsing until linking
|
||||
// Parents: statement
|
||||
// @astgen op1 := genforp : Optional[AstNode]
|
||||
|
||||
const bool m_generate : 1; // Underneath a generate
|
||||
bool m_needProcess : 1; // Uses VlProcess
|
||||
const bool m_implied : 1; // Not inserted by user
|
||||
public:
|
||||
// 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)
|
||||
, m_generate{generate}
|
||||
, m_needProcess{false}
|
||||
, m_implied{implied} {}
|
||||
ASTGEN_MEMBERS_AstBegin;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
bool generate() const { return m_generate; }
|
||||
void setNeedProcess() { m_needProcess = true; }
|
||||
bool needProcess() const { return m_needProcess; }
|
||||
bool implied() const { return m_implied; }
|
||||
|
|
@ -2463,6 +2464,74 @@ public:
|
|||
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 ===
|
||||
class AstClass final : public AstNodeModule {
|
||||
// @astgen op4 := extendsp : List[AstClassExtends]
|
||||
|
|
|
|||
|
|
@ -70,21 +70,6 @@ public:
|
|||
bool isTimingControl() const override { return timingControlp(); }
|
||||
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 {
|
||||
// Cover or Assert
|
||||
// Parents: {statement list}
|
||||
|
|
@ -121,27 +106,6 @@ public:
|
|||
|| 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 {
|
||||
// @astgen op1 := arrayp : AstNode
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
|
|
@ -218,6 +182,23 @@ public:
|
|||
|
||||
// === 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 ===
|
||||
class AstAssertCtl final : public AstNodeStmt {
|
||||
// @astgen op1 := controlTypep : AstNodeExpr
|
||||
|
|
@ -306,6 +287,47 @@ public:
|
|||
bool isPredictOptimizable() const override { return false; }
|
||||
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 {
|
||||
// Some comment to put into the output stream
|
||||
const string m_name; // Text of comment
|
||||
|
|
@ -1130,49 +1152,6 @@ public:
|
|||
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 ===
|
||||
class AstAssert final : public AstNodeCoverOrAssert {
|
||||
// @astgen op3 := failsp: List[AstNode] // Statements when propp is failing/falsey
|
||||
|
|
@ -1215,14 +1194,6 @@ public:
|
|||
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 ===
|
||||
class AstConstraintForeach final : public AstNodeForeach {
|
||||
// Constraint foreach statement
|
||||
|
|
@ -1245,12 +1216,7 @@ public:
|
|||
: ASTGEN_SUPER_ConstraintIf(fl, condp, thensp, elsesp) {}
|
||||
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 {
|
||||
bool m_uniquePragma = false; // unique case
|
||||
bool m_unique0Pragma = false; // unique0 case
|
||||
|
|
|
|||
|
|
@ -1928,6 +1928,18 @@ const char* AstEnumDType::broken() const {
|
|||
}
|
||||
|
||||
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 {
|
||||
this->AstNodeDType::dump(str);
|
||||
if (isPortDecl()) str << " [PORTDECL]";
|
||||
|
|
@ -2941,14 +2953,10 @@ void AstNodeBlock::dumpJson(std::ostream& str) const {
|
|||
}
|
||||
void AstBegin::dump(std::ostream& str) const {
|
||||
this->AstNodeBlock::dump(str);
|
||||
if (generate()) str << " [GEN]";
|
||||
if (genforp()) str << " [GENFOR]";
|
||||
if (implied()) str << " [IMPLIED]";
|
||||
if (needProcess()) str << " [NPRC]";
|
||||
}
|
||||
void AstBegin::dumpJson(std::ostream& str) const {
|
||||
dumpJsonBoolFunc(str, generate);
|
||||
dumpJsonBool(str, "genfor", bool(genforp()));
|
||||
dumpJsonBoolFunc(str, implied);
|
||||
dumpJsonBoolFunc(str, needProcess);
|
||||
dumpJsonGen(str);
|
||||
|
|
@ -3258,7 +3266,7 @@ AstAlways* AstAssignW::convertToAlways() {
|
|||
if (hasTimingControl) {
|
||||
// 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
|
||||
AstBegin* const beginp = new AstBegin{flp, "", bodysp, false, false};
|
||||
AstBegin* const beginp = new AstBegin{flp, "", bodysp, false};
|
||||
AstFork* const forkp = new AstFork{flp, "", beginp};
|
||||
forkp->joinType(VJoinType::JOIN_NONE);
|
||||
bodysp = forkp;
|
||||
|
|
|
|||
|
|
@ -73,31 +73,32 @@ class BeginVisitor final : public VNVisitor {
|
|||
|
||||
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);
|
||||
if (nodep->name() != "") { // Else unneeded unnamed block
|
||||
if (name != "") { // Else unneeded unnamed block
|
||||
// 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;
|
||||
while ((pos = dottedname.find("__DOT__")) != string::npos) {
|
||||
const string ident = dottedname.substr(0, pos);
|
||||
dottedname = dottedname.substr(pos + std::strlen("__DOT__"));
|
||||
if (nodep->name() != "") {
|
||||
if (name != "") {
|
||||
m_displayScope = dot(m_displayScope, ident);
|
||||
m_namedScope = dot(m_namedScope, ident);
|
||||
}
|
||||
m_unnamedScope = dot(m_unnamedScope, ident);
|
||||
// Create CellInline for dotted var resolution
|
||||
if (!m_ftaskp) {
|
||||
AstCellInline* const inlinep = new AstCellInline{
|
||||
nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit()};
|
||||
AstCellInline* const inlinep
|
||||
= new AstCellInline{flp, m_unnamedScope, blockName, m_modp->timeunit()};
|
||||
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remap var names and replace lower Begins
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
iterateAndNextNull(stmtsp);
|
||||
}
|
||||
|
||||
void liftNode(AstNode* nodep) {
|
||||
|
|
@ -125,14 +126,13 @@ class BeginVisitor final : public VNVisitor {
|
|||
// replaced with multiple statements)
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (!VN_IS(stmtp, Begin)) {
|
||||
AstBegin* const beginp
|
||||
= new AstBegin{stmtp->fileline(), "", nullptr, false, false};
|
||||
AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr, false};
|
||||
stmtp->replaceWith(beginp);
|
||||
beginp->addStmtsp(stmtp);
|
||||
stmtp = beginp;
|
||||
}
|
||||
}
|
||||
dotNames(nodep, "__FORK__");
|
||||
dotNames(nodep->name(), nodep->fileline(), nodep->stmtsp(), "__FORK__");
|
||||
nodep->name("");
|
||||
}
|
||||
void visit(AstForeach* nodep) override {
|
||||
|
|
@ -199,6 +199,20 @@ class BeginVisitor final : public VNVisitor {
|
|||
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 {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8, " " << nodep);
|
||||
|
|
@ -208,9 +222,8 @@ class BeginVisitor final : public VNVisitor {
|
|||
{
|
||||
VL_RESTORER(m_keepBegins);
|
||||
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
|
||||
if (m_keepBegins) {
|
||||
|
|
@ -431,7 +444,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
AstNodeDType* fromDtp = fromp->dtypep()->skipRefp();
|
||||
// Split into for loop
|
||||
// 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* lastp = nodep;
|
||||
AstVar* nestedIndexp = nullptr;
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck =
|
|||
void V3Broken::selfTest() {
|
||||
// Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS
|
||||
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.
|
||||
// Otherwise you call addNewed twice on the same address, which is an error.
|
||||
#ifndef VL_LEAK_CHECKS
|
||||
|
|
|
|||
106
src/V3Case.cpp
106
src/V3Case.cpp
|
|
@ -49,64 +49,80 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
|
||||
class CaseLintVisitor final : public VNVisitorConst {
|
||||
const AstNodeCase* m_caseExprp
|
||||
= nullptr; // Under a CASE value node, if so the relevant case statement
|
||||
// Under a CASE value node, if so the relevant case statement
|
||||
const AstNode* m_casep = nullptr;
|
||||
|
||||
// METHODS
|
||||
template <typename CaseItem>
|
||||
static void detectMultipleDefaults(CaseItem* itemsp) {
|
||||
bool hitDefault = false;
|
||||
for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
|
||||
if (!itemp->isDefault()) continue;
|
||||
if (hitDefault) itemp->v3error("Multiple default statements in case statement.");
|
||||
hitDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstNodeCase* nodep) override {
|
||||
if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) {
|
||||
template <typename CaseItem>
|
||||
void checkXZinNonCaseX(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) {
|
||||
VL_RESTORER(m_casep);
|
||||
m_casep = casep;
|
||||
iterateConst(exprp);
|
||||
for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
|
||||
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
|
||||
bool hitDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) {
|
||||
if (hitDefault) {
|
||||
itemp->v3error("Multiple default statements in case statement.");
|
||||
}
|
||||
hitDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
detectMultipleDefaults(nodep->itemsp());
|
||||
// Check for X/Z in non-casex statements
|
||||
{
|
||||
VL_RESTORER(m_caseExprp);
|
||||
m_caseExprp = nodep;
|
||||
iterateConst(nodep->exprp());
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextConstNull(itemp->condsp());
|
||||
}
|
||||
}
|
||||
checkXZinNonCaseX(nodep, nodep->exprp(), nodep->itemsp());
|
||||
}
|
||||
void visit(AstConst* nodep) override {
|
||||
// See also neverItem
|
||||
if (m_caseExprp && nodep->num().isFourState()) {
|
||||
if (VN_IS(m_caseExprp, GenCase)) {
|
||||
nodep->v3error("Use of x/? constant in generate case statement, "
|
||||
"(no such thing as 'generate casez')");
|
||||
} else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) {
|
||||
// Don't sweat it, we already complained about casex in general
|
||||
} else if (VN_IS(m_caseExprp, Case)
|
||||
&& (VN_AS(m_caseExprp, Case)->casez()
|
||||
|| VN_AS(m_caseExprp, Case)->caseInside())) {
|
||||
if (nodep->num().isAnyX()) {
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
||||
"(perhaps intended ?/z in constant)");
|
||||
}
|
||||
} else {
|
||||
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, "
|
||||
"(perhaps intended casex/casez)");
|
||||
}
|
||||
if (!nodep->num().isFourState()) return;
|
||||
|
||||
// Error if generate case
|
||||
if (VN_IS(m_casep, GenCase)) {
|
||||
nodep->v3error("Use of x/? constant in generate case statement, "
|
||||
"(no such thing as 'generate casez')");
|
||||
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
|
||||
if (casep->casex()) return;
|
||||
|
||||
if (casep->casez() || casep->caseInside()) {
|
||||
if (nodep->num().isAnyX()) {
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
||||
"(perhaps intended ?/z in constant)");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, "
|
||||
"(perhaps intended casex/casez)");
|
||||
}
|
||||
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); }
|
||||
explicit CaseLintVisitor(AstCase* nodep) { iterateConst(nodep); }
|
||||
explicit CaseLintVisitor(AstGenCase* nodep) { iterateConst(nodep); }
|
||||
~CaseLintVisitor() override = default;
|
||||
};
|
||||
|
||||
|
|
@ -562,7 +578,7 @@ class CaseVisitor final : public VNVisitor {
|
|||
|
||||
// VISITORS
|
||||
void visit(AstCase* nodep) override {
|
||||
V3Case::caseLint(nodep);
|
||||
{ CaseLintVisitor{nodep}; }
|
||||
iterateChildren(nodep);
|
||||
UINFOTREE(9, nodep, "", "case_old");
|
||||
if (isCaseTreeFast(nodep) && v3Global.opt.fCase()) {
|
||||
|
|
@ -605,7 +621,7 @@ void V3Case::caseAll(AstNetlist* nodep) {
|
|||
{ CaseVisitor{nodep}; } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
void V3Case::caseLint(AstNodeCase* nodep) {
|
||||
void V3Case::caseLint(AstGenCase* nodep) {
|
||||
UINFO(4, __FUNCTION__ << ": ");
|
||||
{ CaseLintVisitor{nodep}; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@
|
|||
#include "verilatedos.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNodeCase;
|
||||
class AstGenCase;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Case final {
|
||||
public:
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
|
||||
if (!nodep->unnamed()) {
|
||||
|
|
@ -375,6 +386,13 @@ public:
|
|||
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) {
|
||||
// Apply to block at this line
|
||||
const VPragmaType pragma = VPragmaType::COVERAGE_BLOCK_OFF;
|
||||
|
|
@ -741,6 +759,15 @@ void V3Control::applyCoverageBlock(AstNodeModule* modulep, AstBegin* 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) {
|
||||
const string& filename = filelinep->filename();
|
||||
V3ControlFile* const filep = V3ControlResolver::s().files().resolve(filename);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public:
|
|||
|
||||
static void applyCase(AstCase* nodep);
|
||||
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
|
||||
static void applyCoverageBlock(AstNodeModule* modulep, AstGenBlock* nodep);
|
||||
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
|
||||
static void applyIgnores(FileLine* filelinep);
|
||||
static void applyModule(AstNodeModule* modulep);
|
||||
|
|
|
|||
|
|
@ -710,6 +710,16 @@ class CoverageVisitor final : public VNVisitor {
|
|||
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 {
|
||||
// Record the hierarchy of any named begins, so we can apply to user
|
||||
// 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.)
|
||||
VL_RESTORER(m_beginHier);
|
||||
VL_RESTORER(m_inToggleOff);
|
||||
if (!nodep->generate()) m_inToggleOff = true;
|
||||
m_inToggleOff = true;
|
||||
if (nodep->name() != "") {
|
||||
m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1297,9 +1297,6 @@ class DelayedVisitor final : public VNVisitor {
|
|||
// Record write reference
|
||||
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 {
|
||||
VL_RESTORER(m_inLoop);
|
||||
m_inLoop = true;
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ public:
|
|||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
|
||||
void visit(AstCase* nodep) override { // LCOV_EXCL_LINE
|
||||
// In V3Case...
|
||||
nodep->v3fatalSrc("Case statements should have been reduced out");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,54 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
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 {
|
||||
if (nodep->name() == "") {
|
||||
putbs("begin\n");
|
||||
|
|
@ -193,23 +241,19 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
if (nodep->sensp()) puts(" ");
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override {
|
||||
void visit(AstCase* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->priorityPragma()) puts("priority ");
|
||||
if (casep->uniquePragma()) puts("unique ");
|
||||
if (casep->unique0Pragma()) puts("unique0 ");
|
||||
}
|
||||
if (nodep->priorityPragma()) puts("priority ");
|
||||
if (nodep->uniquePragma()) puts("unique ");
|
||||
if (nodep->unique0Pragma()) puts("unique0 ");
|
||||
puts(nodep->verilogKwd());
|
||||
puts(" (");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
puts(")\n");
|
||||
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
|
||||
if (casep->fullPragma() || casep->parallelPragma()) {
|
||||
puts(" // synopsys");
|
||||
if (casep->fullPragma()) puts(" full_case");
|
||||
if (casep->parallelPragma()) puts(" parallel_case");
|
||||
}
|
||||
if (nodep->fullPragma() || nodep->parallelPragma()) {
|
||||
puts(" // synopsys");
|
||||
if (nodep->fullPragma()) puts(" full_case");
|
||||
if (nodep->parallelPragma()) puts(" parallel_case");
|
||||
}
|
||||
iterateAndNextConstNull(nodep->itemsp());
|
||||
putqs(nodep, "endcase\n");
|
||||
|
|
@ -348,21 +392,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateAndNextConstNull(nodep->exprsp());
|
||||
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 {
|
||||
putfs(nodep, "repeat (");
|
||||
iterateAndNextConstNull(nodep->countp());
|
||||
|
|
|
|||
|
|
@ -410,6 +410,11 @@ class HierCellsXmlVisitor final : public VNVisitorConst {
|
|||
m_hier = hier;
|
||||
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 {
|
||||
VL_RESTORER(m_hier);
|
||||
if (nodep->name() != "") m_hier += nodep->name() + ".";
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ private:
|
|||
AstBegin* const beginp = new AstBegin{
|
||||
forkp->fileline(),
|
||||
"_Vwrapped_" + (forkp->name().empty() ? "" : forkp->name() + "_") + cvtToStr(m_id),
|
||||
m_instance.m_handlep, false, true};
|
||||
m_instance.m_handlep, true};
|
||||
forkHandle.relink(beginp);
|
||||
|
||||
AstNode* const instAsgnp = instantiateDynScope(memberMap);
|
||||
|
|
@ -470,7 +470,7 @@ class DynScopeVisitor final : public VNVisitor {
|
|||
})) {
|
||||
nodep->user2(true);
|
||||
// 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};
|
||||
forkp->joinType(VJoinType::JOIN_NONE);
|
||||
nodep->replaceWith(forkp);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ public:
|
|||
return "block";
|
||||
} else if (VN_IS(nodep, Iface)) {
|
||||
return "interface";
|
||||
} else if (VN_IS(nodep, GenBlock)) {
|
||||
return "generate block";
|
||||
} else {
|
||||
return nodep->prettyTypeName();
|
||||
}
|
||||
|
|
@ -295,8 +297,8 @@ public:
|
|||
} else if (foundp->imported()) { // From package
|
||||
// We don't throw VARHIDDEN as if the import is later the symbol
|
||||
// table's import wouldn't warn
|
||||
} else if (forPrimary() && VN_IS(nodep, Begin) && VN_IS(fnodep, Begin)
|
||||
&& VN_AS(nodep, Begin)->generate()) {
|
||||
} else if (forPrimary() && VN_IS(nodep, GenBlock)
|
||||
&& (VN_IS(fnodep, Begin) || VN_IS(fnodep, GenBlock))) {
|
||||
// Begin: ... blocks often replicate under genif/genfor, so
|
||||
// suppress duplicate checks. See t_gen_forif.v for an example.
|
||||
} else {
|
||||
|
|
@ -882,7 +884,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
string
|
||||
m_hierParamsName; // Name of module with hierarchical type parameters, empty when not used
|
||||
string m_scope; // Scope text
|
||||
const AstNodeBlock* m_blockp = nullptr; // Current Begin/end block
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
bool m_inRecursion = false; // Inside a recursive module
|
||||
int m_paramNum = 0; // Parameter number, for position based connection
|
||||
|
|
@ -1158,7 +1159,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
// Recurse in, preserving state
|
||||
VL_RESTORER(m_scope);
|
||||
VL_RESTORER(m_blockp);
|
||||
VL_RESTORER(m_modSymp);
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_paramNum);
|
||||
|
|
@ -1181,7 +1181,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
{
|
||||
m_scope = m_scope + "." + nodep->name();
|
||||
m_curSymp = m_modSymp = m_statep->insertCell(aboveSymp, m_modSymp, nodep, m_scope);
|
||||
m_blockp = nullptr;
|
||||
m_inRecursion = nodep->recursive();
|
||||
// We don't report NotFoundModule, as may be a unused module in a generate
|
||||
if (nodep->modp()) iterate(nodep->modp());
|
||||
|
|
@ -1216,6 +1215,43 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
nodep->user1p(m_curSymp);
|
||||
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::
|
||||
UINFO(5, " " << nodep);
|
||||
if (nodep->name() == "" && nodep->unnamed()) {
|
||||
|
|
@ -1243,10 +1279,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
if (nodep->name() == "") {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
VL_RESTORER(m_blockp);
|
||||
VL_RESTORER(m_curSymp);
|
||||
{
|
||||
m_blockp = nodep;
|
||||
m_curSymp
|
||||
= m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
||||
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
|
||||
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
|
||||
// Note we allow AstNodeStmt's as generates may be under them
|
||||
void visit(AstCell*) override {} // ScopeVisitor::
|
||||
|
|
@ -3509,6 +3546,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
if (!foundp) {
|
||||
} 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(), Module)) { // if top
|
||||
if (allowScope) {
|
||||
|
|
@ -3521,14 +3559,12 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
// last component, `targetp()` field will be overwritten by next components
|
||||
m_ds.m_disablep->targetp(foundp->nodep());
|
||||
}
|
||||
if (const AstBegin* const beginp = VN_CAST(foundp->nodep(), Begin)) {
|
||||
if (beginp->generate()) {
|
||||
m_ds.m_genBlk = true;
|
||||
if (m_ds.m_disablep) {
|
||||
m_ds.m_disablep->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Generate block referenced by disable");
|
||||
}
|
||||
if (VN_IS(foundp->nodep(), GenBlock)) {
|
||||
m_ds.m_genBlk = true;
|
||||
if (m_ds.m_disablep) {
|
||||
m_ds.m_disablep->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Generate block referenced by disable");
|
||||
}
|
||||
}
|
||||
// Upper AstDot visitor will handle it from here
|
||||
|
|
@ -4472,6 +4508,21 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
LINKDOT_VISIT_START();
|
||||
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 {
|
||||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
|
|
|
|||
|
|
@ -162,10 +162,6 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
m_insStmtp = nullptr; // Next thing should be new statement
|
||||
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 {
|
||||
m_insStmtp = nodep;
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
// Note var can be signed or unsigned based on original number.
|
||||
AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
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
|
||||
AstVar* const varp
|
||||
= 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
|
||||
AstBegin* beginp = VN_CAST(forkItemp, Begin);
|
||||
if (!beginp) {
|
||||
beginp = new AstBegin{fl, "", nullptr, false, false};
|
||||
beginp = new AstBegin{fl, "", nullptr, false};
|
||||
forkItemp->replaceWith(beginp);
|
||||
beginp->addStmtsp(forkItemp);
|
||||
// In order to continue the iteration
|
||||
|
|
|
|||
|
|
@ -111,19 +111,19 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
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
|
||||
// The genblk name will get attached to the if true/false LOWER begin block(s)
|
||||
// 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:2: BEGIN genblk1 [GEN] [IMPLIED]
|
||||
// 1:3:1:2: GENBLOCK genblk1 [IMPLIED]
|
||||
const AstNode* const backp = nodep->backp();
|
||||
return (nodep->implied() // User didn't provide begin/end
|
||||
&& VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep
|
||||
&& !nodep->nextp() // No other statements under upper genif else
|
||||
&& (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath
|
||||
&& !nodep->stmtsp()->nextp()); // Has only one item
|
||||
&& (VN_IS(nodep->itemsp(), GenIf)) // Begin has if underneath
|
||||
&& !nodep->itemsp()->nextp()); // Has only one item
|
||||
}
|
||||
|
||||
void checkIndent(AstNode* nodep, AstNode* childp) {
|
||||
|
|
@ -657,7 +657,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
void visit(AstCover* 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);
|
||||
cleanFileline(nodep);
|
||||
VL_RESTORER(m_beginDepth);
|
||||
|
|
@ -671,13 +671,13 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
if (nodep->genforp()) {
|
||||
++m_genblkNum;
|
||||
if (nodep->name() == "") assignGenBlkNum = m_genblkNum;
|
||||
} else if (nodep->generate() && nodep->name() == ""
|
||||
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) {
|
||||
} else if (nodep->name() == "" && (VN_IS(backp, GenCaseItem) || VN_IS(backp, GenIf))
|
||||
&& !nestedIf) {
|
||||
assignGenBlkNum = m_genblkAbove;
|
||||
}
|
||||
if (assignGenBlkNum != -1) {
|
||||
nodep->name("genblk" + cvtToStr(assignGenBlkNum));
|
||||
if (nodep->stmtsp()) {
|
||||
if (nodep->itemsp()) {
|
||||
nodep->v3warn(GENUNNAMED,
|
||||
"Unnamed generate block "
|
||||
<< nodep->prettyNameQ() << " (IEEE 1800-2023 27.6)\n"
|
||||
|
|
@ -696,6 +696,31 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
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 {
|
||||
if (nodep->origName().empty()) {
|
||||
if (!VN_IS(nodep->modp(), Primitive)) { // Module/Program/Iface
|
||||
|
|
@ -710,31 +735,11 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstGenCase* nodep) override {
|
||||
++m_genblkNum;
|
||||
void visit(AstBegin* nodep) override {
|
||||
V3Control::applyCoverageBlock(m_modp, nodep);
|
||||
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(), 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 {
|
||||
V3Control::applyCase(nodep);
|
||||
cleanFileline(nodep);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
// TODO Unlike generated IF, we don't have to worry about short-circuiting the
|
||||
// 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
|
||||
const AstConst* const exprp = VN_AS(nodep->exprp(), Const);
|
||||
// Constify
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
|
||||
for (AstNode* ep = itemp->condsp(); ep;) {
|
||||
AstNode* const nextp = ep->nextp(); // May edit list
|
||||
iterateAndNextNull(ep);
|
||||
|
|
@ -1673,8 +1673,8 @@ class ParamVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
// Item match
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
|
||||
if (!itemp->isDefault()) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
|
||||
if (const AstConst* const ccondp = VN_CAST(ep, Const)) {
|
||||
|
|
@ -1682,7 +1682,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
match.opEq(ccondp->num(), exprp->num());
|
||||
if (!hit && match.isNeqZero()) {
|
||||
hit = true;
|
||||
keepp = itemp->stmtsp();
|
||||
keepp = itemp->itemsp();
|
||||
}
|
||||
} else {
|
||||
itemp->v3error("Generate Case item does not evaluate to constant");
|
||||
|
|
@ -1691,12 +1691,12 @@ class ParamVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
// Else default match
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstGenCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), GenCaseItem)) {
|
||||
if (itemp->isDefault()) {
|
||||
if (!hit) {
|
||||
hit = true;
|
||||
keepp = itemp->stmtsp();
|
||||
keepp = itemp->itemsp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ public:
|
|||
// would misfire
|
||||
AstNode* newBlock(FileLine* fl, AstNode* 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
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
|
||||
{
|
||||
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);
|
||||
itemsp = tempp->stmtsp();
|
||||
if (itemsp) itemsp->unlinkFrBackWithNext();
|
||||
|
|
@ -937,6 +937,10 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
}
|
||||
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(AstConstraintForeach* nodep) override {
|
||||
// Convert to plain foreach
|
||||
|
|
@ -951,7 +955,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
exprsp->addNext(new AstBegin{
|
||||
fl, "",
|
||||
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}},
|
||||
false, true});
|
||||
true});
|
||||
exprsp->addNext(
|
||||
new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"});
|
||||
AstNodeExpr* const newp = new AstCExpr{fl, exprsp};
|
||||
|
|
@ -963,7 +967,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
new AstBegin{fl, "",
|
||||
new AstForeach{fl, nodep->arrayp()->unlinkFrBack(),
|
||||
nodep->stmtsp()->unlinkFrBackWithNext()},
|
||||
false, true});
|
||||
true});
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
|
@ -1027,8 +1031,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
cstmtp->addNext(iterateSubtreeReturnEdits(itemp));
|
||||
cstmtp->addNext(new AstText{fl, ";"});
|
||||
AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"};
|
||||
exprsp->addNext(new AstBegin{
|
||||
fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, false, true});
|
||||
exprsp->addNext(
|
||||
new AstBegin{fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, true});
|
||||
exprsp->addNext(
|
||||
new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"});
|
||||
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 AstAdd{fl, new AstConst{fl, 1},
|
||||
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) {
|
||||
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};
|
||||
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp, basicFvarp);
|
||||
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(m_stmtp);
|
||||
stmtsp->addNext(restoreStmtsp);
|
||||
relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, false, true});
|
||||
relinker.relink(new AstBegin{nodep->fileline(), "", stmtsp, true});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ void splitCheck(AstCFunc* ofuncp) {
|
|||
|
||||
// Unlink all statements, then add item by item to new sub-functions
|
||||
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
|
||||
UASSERT_OBJ(!ofuncp->finalsp(), ofuncp, "Should not have any finalps");
|
||||
while (tempp->stmtsp()) {
|
||||
|
|
|
|||
|
|
@ -991,7 +991,7 @@ private:
|
|||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override {
|
||||
void visit(AstCase* nodep) override {
|
||||
if (jumpingOver()) return;
|
||||
UINFO(5, " CASE " << nodep);
|
||||
checkNodeInfo(nodep);
|
||||
|
|
@ -1083,39 +1083,6 @@ private:
|
|||
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 {
|
||||
// Doing lots of Whiles is slow, so only for parameters
|
||||
if (jumpingOver()) return;
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ protected:
|
|||
void visit(AstAlways* 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
|
||||
|
||||
void visit(AstAssignDly* nodep) override {
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ struct SplitVarImpl VL_NOT_FINAL {
|
|||
stmtp->unlinkFrBack();
|
||||
// Insert begin-end because temp value may be inserted to this block later.
|
||||
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.
|
||||
FileLine* const fl = initp->fileline();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1362,7 +1362,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
if (bodysp) {
|
||||
unlinkAndClone(nodep, bodysp, true);
|
||||
AstBegin* const tempp
|
||||
= new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false, false};
|
||||
= new AstBegin{nodep->fileline(), "[EditWrapper]", bodysp, false};
|
||||
VL_DANGLING(bodysp);
|
||||
// If we cloned due to recursion, now need to rip out the ports
|
||||
// (that remained in place) then got cloned
|
||||
|
|
@ -1624,10 +1624,6 @@ class TaskVisitor final : public VNVisitor {
|
|||
nodep->v3fatalSrc(
|
||||
"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 {
|
||||
VL_RESTORER(m_insStmtp);
|
||||
m_insStmtp = nodep;
|
||||
|
|
|
|||
|
|
@ -1029,7 +1029,7 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
}
|
||||
controlp->replaceWith(forkp);
|
||||
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);
|
||||
controlp = forkp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,8 +209,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
if (loopValue) {
|
||||
AstConst* varValuep = new AstConst{nodep->fileline(), *loopValue};
|
||||
// Iteration requires a back, so put under temporary node
|
||||
AstBegin* tempp
|
||||
= new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false};
|
||||
AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false};
|
||||
replaceVarRef(tempp->stmtsp(), varValuep);
|
||||
clonep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr);
|
||||
|
|
@ -303,8 +302,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
AstNode* clonep = initp->cloneTree(true);
|
||||
AstConst* varValuep = new AstConst{nodep->fileline(), loopValue};
|
||||
// Iteration requires a back, so put under temporary node
|
||||
AstBegin* tempp
|
||||
= new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false, false};
|
||||
AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep, false};
|
||||
replaceVarRef(clonep, varValuep);
|
||||
clonep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr);
|
||||
|
|
@ -329,8 +327,8 @@ class UnrollVisitor final : public VNVisitor {
|
|||
AstConst* varValuep = new AstConst{nodep->fileline(), loopValue};
|
||||
if (oneloopp) {
|
||||
// Iteration requires a back, so put under temporary node
|
||||
AstBegin* const tempp = new AstBegin{oneloopp->fileline(), "[EditWrapper]",
|
||||
oneloopp, false, false};
|
||||
AstBegin* const tempp
|
||||
= new AstBegin{oneloopp->fileline(), "[EditWrapper]", oneloopp, false};
|
||||
replaceVarRef(tempp->stmtsp(), varValuep);
|
||||
oneloopp = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||
|
|
@ -338,8 +336,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
if (m_generate) {
|
||||
const string index = AstNode::encodeNumber(varValuep->toSInt());
|
||||
const string nname = m_beginName + "__BRA__" + index + "__KET__";
|
||||
oneloopp
|
||||
= new AstBegin{oneloopp->fileline(), nname, oneloopp, true, false};
|
||||
oneloopp = new AstGenBlock{oneloopp->fileline(), nname, oneloopp, false};
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(varValuep), varValuep);
|
||||
if (newbodysp) {
|
||||
|
|
@ -421,9 +418,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
void visit(AstGenFor* nodep) override {
|
||||
if (!m_generate) {
|
||||
iterateChildren(nodep);
|
||||
} // else V3Param will recursively call each for loop to be unrolled for us
|
||||
UASSERT_OBJ(m_generate, nodep, "There should be no GenFor left when unrolling all");
|
||||
if (!m_varModeCheck) {
|
||||
// Constify before unroll call, as it may change what is underneath.
|
||||
if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change
|
||||
|
|
@ -439,7 +434,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
// deleted by V3Const.
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
} 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
|
||||
} else {
|
||||
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 {
|
||||
if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
|
||||
|
|
@ -514,18 +502,16 @@ UnrollStateful::UnrollStateful()
|
|||
: m_unrollerp{new UnrollVisitor} {}
|
||||
UnrollStateful::~UnrollStateful() { delete m_unrollerp; }
|
||||
|
||||
void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) {
|
||||
void UnrollStateful::unrollGen(AstGenFor* nodep, const string& beginName) {
|
||||
UINFO(5, __FUNCTION__ << ": ");
|
||||
m_unrollerp->process(nodep, true, beginName);
|
||||
}
|
||||
|
||||
void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); }
|
||||
|
||||
void V3Unroll::unrollAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
{
|
||||
UnrollStateful unroller;
|
||||
unroller.unrollAll(nodep);
|
||||
UnrollVisitor visitor;
|
||||
visitor.process(nodep, false, "");
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ public:
|
|||
UnrollStateful() VL_MT_DISABLED;
|
||||
~UnrollStateful() VL_MT_DISABLED;
|
||||
// METHODS
|
||||
void unrollGen(AstNodeFor* nodep, const string& beginName) VL_MT_DISABLED;
|
||||
void unrollAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
void unrollGen(AstGenFor* nodep, const string& beginName) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
193
src/V3Width.cpp
193
src/V3Width.cpp
|
|
@ -744,8 +744,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
|| (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())))) {
|
||||
AstNode* stmtsp = nullptr;
|
||||
if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack();
|
||||
AstBegin* const newp
|
||||
= new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false, false};
|
||||
AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), stmtsp, false};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (v3Global.opt.timing().isSetTrue()) {
|
||||
|
|
@ -5261,91 +5260,123 @@ class WidthVisitor final : public VNVisitor {
|
|||
//--------------------
|
||||
// Top levels
|
||||
|
||||
void visit(AstNodeCase* nodep) override {
|
||||
template <typename CaseItem>
|
||||
void handleCaseType(AstNode* casep, AstNodeExpr* exprp, CaseItem* itemsp) {
|
||||
AstAttrOf* const exprap = VN_CAST(exprp, AttrOf);
|
||||
if (!exprap) return;
|
||||
if (exprap->attrType() != VAttrType::TYPEID) return;
|
||||
|
||||
const AstNodeDType* const exprDtp = exprap->dtypep();
|
||||
UINFO(9, "case type exprDtp " << exprDtp);
|
||||
// V3Param may have a pointer to this case statement, and we need
|
||||
// dotted references to remain properly named, so rather than
|
||||
// removing we convert it to a "normal" expression "case (1) ..."
|
||||
FileLine* const newfl = casep->fileline();
|
||||
newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform
|
||||
newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform
|
||||
casep->fileline(newfl);
|
||||
for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
|
||||
if (itemp->isDefault()) continue;
|
||||
bool hit = false;
|
||||
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
|
||||
const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf);
|
||||
if (!condAttrp) {
|
||||
condp->v3error("Case(type) statement requires items that have type() items");
|
||||
} else {
|
||||
AstNodeDType* const condDtp = condAttrp->dtypep();
|
||||
if (AstNode::computeCastable(exprDtp, condDtp, casep) == VCastable::SAMEISH) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushDeletep(itemp->condsp()->unlinkFrBackWithNext());
|
||||
// Item condition becomes constant 1 if hits else 0
|
||||
itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit});
|
||||
}
|
||||
exprap->replaceWith(new AstConst{newfl, AstConst::BitTrue{}});
|
||||
VL_DO_DANGLING(pushDeletep(exprap), exprap);
|
||||
}
|
||||
|
||||
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
|
||||
AstNodeDType* subDTypep = exprp->dtypep();
|
||||
for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
|
||||
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
|
||||
if (condp->dtypep() == subDTypep) continue;
|
||||
|
||||
if (condp->dtypep()->isDouble() || subDTypep->isDouble()) {
|
||||
subDTypep = casep->findDoubleDType();
|
||||
} else if (condp->dtypep()->isString() || subDTypep->isString()) {
|
||||
subDTypep = casep->findStringDType();
|
||||
} else {
|
||||
const int width = std::max(subDTypep->width(), condp->width());
|
||||
const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin());
|
||||
const bool issigned = subDTypep->isSigned() && condp->isSigned();
|
||||
subDTypep = casep->findLogicDType(width, mwidth, VSigning::fromBool(issigned));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply width
|
||||
iterateCheck(casep, "Case expression", exprp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP);
|
||||
for (CaseItem* itemp = itemsp; itemp; itemp = AstNode::as<CaseItem>(itemp->nextp())) {
|
||||
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
|
||||
nextcp = condp->nextp(); // Final may cause the node to get replaced
|
||||
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
|
||||
if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->stmtsp(), nullptr);
|
||||
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();
|
||||
UINFO(9, "case type exprDtp " << exprDtp);
|
||||
// V3Param may have a pointer to this case statement, and we need
|
||||
// dotted references to remain properly named, so rather than
|
||||
// removing we convert it to a "normal" expression "case (1) ..."
|
||||
FileLine* const newfl = nodep->fileline();
|
||||
newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform
|
||||
newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform
|
||||
nodep->fileline(newfl);
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->isDefault()) {
|
||||
bool hit = false;
|
||||
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
|
||||
const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf);
|
||||
if (!condAttrp) {
|
||||
condp->v3error(
|
||||
"Case(type) statement requires items that have type() items");
|
||||
} else {
|
||||
AstNodeDType* const condDtp = condAttrp->dtypep();
|
||||
if (AstNode::computeCastable(exprDtp, condDtp, nodep)
|
||||
== VCastable::SAMEISH) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pushDeletep(itemp->condsp()->unlinkFrBackWithNext());
|
||||
// Item condition becomes constant 1 if hits else 0
|
||||
itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit});
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(exprap->unlinkFrBack()), exprap);
|
||||
nodep->exprp(new AstConst{newfl, AstConst::BitTrue{}});
|
||||
}
|
||||
}
|
||||
|
||||
// Take width as maximum across all items, if any is real whole thing is real
|
||||
AstNodeDType* subDTypep = nodep->exprp()->dtypep();
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) {
|
||||
if (condp->dtypep() != subDTypep) {
|
||||
if (condp->dtypep()->isDouble() || subDTypep->isDouble()) {
|
||||
subDTypep = nodep->findDoubleDType();
|
||||
} else if (condp->dtypep()->isString() || subDTypep->isString()) {
|
||||
subDTypep = nodep->findStringDType();
|
||||
} else {
|
||||
const int width = std::max(subDTypep->width(), condp->width());
|
||||
const int mwidth = std::max(subDTypep->widthMin(), condp->widthMin());
|
||||
const bool issigned = subDTypep->isSigned() && condp->isSigned();
|
||||
subDTypep
|
||||
= nodep->findLogicDType(width, mwidth, VSigning::fromBool(issigned));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply width
|
||||
iterateCheck(nodep, "Case expression", nodep->exprp(), CONTEXT_DET, FINAL, subDTypep,
|
||||
EXTEND_EXP);
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) {
|
||||
nextcp = condp->nextp(); // Final may cause the node to get replaced
|
||||
iterateCheck(nodep, "Case Item", condp, CONTEXT_DET, FINAL, subDTypep, EXTEND_LHS);
|
||||
}
|
||||
}
|
||||
handleCaseType(nodep, nodep->exprp(), nodep->itemsp());
|
||||
// Type check
|
||||
handleCase(nodep, nodep->exprp(), nodep->itemsp());
|
||||
}
|
||||
void visit(AstRandCase* nodep) override {
|
||||
// IEEE says each item is a int (32-bits), and sizes are based on natural sizing,
|
||||
|
|
@ -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 {
|
||||
assertAtStatement(nodep);
|
||||
userIterateAndNext(nodep->countp(), WidthVP{SELF, BOTH}.p());
|
||||
|
|
@ -5388,10 +5411,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
void visit(AstNodeIf* nodep) override {
|
||||
assertAtStatement(nodep);
|
||||
// UINFOTREE(1, nodep, "", "IfPre");
|
||||
if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly
|
||||
userIterateAndNext(nodep->thensp(), nullptr);
|
||||
userIterateAndNext(nodep->elsesp(), nullptr);
|
||||
}
|
||||
userIterateAndNext(nodep->thensp(), nullptr);
|
||||
userIterateAndNext(nodep->elsesp(), nullptr);
|
||||
iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition.
|
||||
// UINFOTREE(1, nodep, "", "IfOut");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ static void process() {
|
|||
|
||||
// Remove parameters by cloning modules to de-parameterized versions
|
||||
// This requires some width calculations and constant propagation
|
||||
// No more AstGenCase/AstGenFor/AstGenIf after this
|
||||
V3Param::param(v3Global.rootp());
|
||||
V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules
|
||||
V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs
|
||||
|
|
@ -271,6 +272,7 @@ static void process() {
|
|||
|
||||
// Task inlining & pushing BEGINs names to variables/cells
|
||||
// Begin processing must be after Param, before module inlining
|
||||
// No more AstGenBlocks after this
|
||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||
|
||||
// Expand inouts, stage 2
|
||||
|
|
|
|||
|
|
@ -2713,7 +2713,7 @@ generate_block_or_null<nodep>: // IEEE: generate_block_or_null (called from gen
|
|||
// // IEEE: generate_block
|
||||
// // Must always return a BEGIN node, or nullptr - see GenFor construction
|
||||
~c~generate_item
|
||||
{ $$ = $1 ? (new AstBegin{$1->fileline(), "", $1, true, true}) : nullptr; }
|
||||
{ $$ = $1 ? (new AstGenBlock{$1->fileline(), "", $1, true}) : nullptr; }
|
||||
| ~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
|
||||
yBEGIN ~c~genItemList yEND { $$ = new AstBegin{$1, "", $2, true, false}; }
|
||||
yBEGIN ~c~genItemList yEND { $$ = new AstGenBlock{$1, "", $2, false}; }
|
||||
| yBEGIN yEND { $$ = nullptr; }
|
||||
| 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); }
|
||||
| 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); }
|
||||
| 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); }
|
||||
| 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); }
|
||||
;
|
||||
|
||||
|
|
@ -2803,27 +2803,23 @@ c_conditional_generate_construct<nodep>: // IEEE: conditional_generate_construc
|
|||
loop_generate_construct<nodep>: // ==IEEE: loop_generate_construct
|
||||
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
|
||||
AstBegin* lowerBegp = VN_CAST($9, Begin);
|
||||
UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin");
|
||||
|
||||
if (!lowerBegp) lowerBegp = new AstBegin{$1, "", nullptr, true, false}; // Empty body
|
||||
AstNode* const lowerNoBegp = lowerBegp->stmtsp();
|
||||
if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext();
|
||||
//
|
||||
AstBegin* const blkp = new AstBegin{$1, lowerBegp->name(), nullptr, true, true};
|
||||
AstGenBlock* lowerp = VN_CAST($9, GenBlock);
|
||||
UASSERT_OBJ(!$9 || lowerp, $9, "Child of GENFOR should have been begin");
|
||||
AstNode* const itemsp = lowerp && lowerp->itemsp() ? lowerp->itemsp()->unlinkFrBackWithNext() : nullptr;
|
||||
AstGenBlock* const blkp = new AstGenBlock{$1, lowerp ? lowerp->name() : "", nullptr, true};
|
||||
// V3LinkDot detects BEGIN(GENFOR(...)) as a special case
|
||||
AstNode* initp = $3;
|
||||
AstNode* const varp = $3;
|
||||
if (VN_IS(varp, Var)) { // Genvar
|
||||
initp = varp->nextp();
|
||||
initp->unlinkFrBackWithNext(); // Detach 2nd from varp, make 1st init
|
||||
blkp->addStmtsp(varp);
|
||||
blkp->addItemsp(varp);
|
||||
}
|
||||
// Statements are under 'genforp' as instances under this
|
||||
// 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;
|
||||
VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp);
|
||||
DEL(lowerp);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -2878,22 +2874,22 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
|||
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_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}
|
||||
;
|
||||
|
||||
case_generate_item<caseItemp>: // ==IEEE: case_generate_item
|
||||
caseCondList colon ~c~generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; }
|
||||
| yDEFAULT colon ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; }
|
||||
| yDEFAULT ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; }
|
||||
case_generate_item<genCaseItemp>: // ==IEEE: case_generate_item
|
||||
caseCondList colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$2, $1, $3}; }
|
||||
| yDEFAULT colon ~c~generate_block_or_null { $$ = new AstGenCaseItem{$1, nullptr, $3}; }
|
||||
| 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}
|
||||
;
|
||||
|
||||
|
|
@ -3409,9 +3405,9 @@ par_blockPreId<nodep>: // ==IEEE: par_block but called with leading ID
|
|||
|
||||
seq_blockFront<beginp>: // IEEE: part of seq_block
|
||||
yBEGIN
|
||||
{ $$ = new AstBegin{$1, "", nullptr, false, false}; }
|
||||
{ $$ = new AstBegin{$1, "", nullptr, false}; }
|
||||
| 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
|
||||
|
|
@ -3423,7 +3419,7 @@ par_blockFront<forkp>: // IEEE: part of par_block
|
|||
|
||||
seq_blockFrontPreId<beginp>: // IEEE: part of seq_block/stmt with leading id
|
||||
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
|
||||
|
|
@ -3468,7 +3464,7 @@ stmtList<nodep>:
|
|||
stmt<nodep>: // IEEE: statement_or_null == function_statement_or_null
|
||||
statement_item { $$ = $1; }
|
||||
// // 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
|
||||
| ';' { $$ = nullptr; }
|
||||
// // 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}; }
|
||||
// // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009
|
||||
| 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
|
||||
| yRETURN ';' { $$ = new AstReturn{$1}; }
|
||||
|
|
@ -3652,10 +3648,10 @@ statement_item<nodep>: // IEEE: statement_item
|
|||
|
||||
statementFor<beginp>: // IEEE: part of statement
|
||||
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}); }
|
||||
| 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}); }
|
||||
;
|
||||
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_statement { $$ = $1; }
|
||||
| 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
|
||||
|
|
@ -6216,7 +6212,7 @@ deferred_immediate_assertion_statement<nodep>: // ==IEEE: deferred_immediate_as
|
|||
concurrent_assertion_item<nodep>: // IEEE: concurrent_assertion_item
|
||||
concurrent_assertion_statement { $$ = $1; }
|
||||
| id/*block_identifier*/ ':' concurrent_assertion_statement
|
||||
{ $$ = new AstBegin{$<fl>1, *$1, $3, false, true}; }
|
||||
{ $$ = new AstBegin{$<fl>1, *$1, $3, true}; }
|
||||
// // IEEE: checker_instantiation
|
||||
// // identical to module_instantiation; see etcInst
|
||||
;
|
||||
|
|
|
|||
|
|
@ -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":"INITIAL","name":"","addr":"(I)","loc":"d,71:4,71:11","isSuspendable":false,"needProcess":false,
|
||||
"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": [
|
||||
{"type":"DISPLAY","name":"","addr":"(K)","loc":"d,73:7,73:13",
|
||||
"fmtp": [
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGNDLY","name":"","addr":"(YC)","loc":"e,40:11,40:13","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -308,7 +308,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGNDLY","name":"","addr":"(AF)","loc":"e,45:14,45:16","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -338,7 +338,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGNDLY","name":"","addr":"(NF)","loc":"e,49:14,49:16","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -361,7 +361,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"IF","name":"","addr":"(WF)","loc":"e,53:12,53:14",
|
||||
|
|
@ -375,7 +375,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"DISPLAY","name":"","addr":"(BG)","loc":"e,54:10,54:16",
|
||||
"fmtp": [
|
||||
|
|
@ -479,7 +479,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGNDLY","name":"","addr":"(VH)","loc":"e,83:11,83:13","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -529,7 +529,7 @@
|
|||
"assertTypesp": [
|
||||
{"type":"CONST","name":"?32?sh8","addr":"(OI)","loc":"e,90:25,90:26","dtypep":"(LF)"}
|
||||
],"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": [
|
||||
{"type":"DISABLE","name":"","addr":"(QI)","loc":"e,92:10,92:17",
|
||||
"targetRefp": [
|
||||
|
|
@ -639,7 +639,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"STMTEXPR","name":"","addr":"(HK)","loc":"d,56:16,56:17",
|
||||
"exprp": [
|
||||
|
|
@ -695,7 +695,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGN","name":"","addr":"(EL)","loc":"d,73:17,73:18","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -748,7 +748,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGN","name":"","addr":"(ZL)","loc":"d,90:17,90:18","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
@ -854,7 +854,7 @@
|
|||
]}
|
||||
],
|
||||
"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": [
|
||||
{"type":"ASSIGN","name":"","addr":"(PN)","loc":"d,119:20,119:22","dtypep":"UNLINKED",
|
||||
"rhsp": [
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
11 | begin : block
|
||||
| ^~~~~
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
9 | begin : block
|
||||
| ^~~~~
|
||||
... 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'
|
||||
15 | if (X > 1) begin : block1
|
||||
| ^~~~~~
|
||||
|
|
|
|||
|
|
@ -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": [],
|
||||
"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":"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":"BEGIN","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","generate":true,"genfor":false,"implied":false,"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":"GENBLOCK","name":"FOR_GENERATE[0]","addr":"(I)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [],
|
||||
"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":"BEGIN","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [],
|
||||
"stmtsp": [
|
||||
{"type":"GENBLOCK","name":"genblk1","addr":"(L)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [],
|
||||
"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_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": [],
|
||||
"stmtsp": [
|
||||
{"type":"GENBLOCK","name":"FOR_GENERATE[1]","addr":"(O)","loc":"d,27:21,27:31","implied":false,"unnamed":false,"genforp": [],
|
||||
"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":"BEGIN","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":true,"genforp": [],
|
||||
"stmtsp": [
|
||||
{"type":"GENBLOCK","name":"genblk1","addr":"(Q)","loc":"d,28:19,28:24","implied":false,"unnamed":true,"genforp": [],
|
||||
"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_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": [],
|
||||
"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": [],
|
||||
"stmtsp": [
|
||||
{"type":"GENBLOCK","name":"submod_gen","addr":"(T)","loc":"d,12:19,12:29","implied":false,"unnamed":false,"genforp": [],
|
||||
"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":"BEGIN","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","generate":true,"genfor":false,"implied":false,"needProcess":false,"unnamed":false,"genforp": [],
|
||||
"stmtsp": [
|
||||
{"type":"GENBLOCK","name":"nested_gen","addr":"(W)","loc":"d,14:23,14:33","implied":false,"unnamed":false,"genforp": [],
|
||||
"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_l1","addr":"(Z)","loc":"d,17:17,17:26","origName":"submod_l1","recursive":false,"modp":"(Y)","pinsp": [],"paramsp": [],"rangep": [],"intfRefsp": []}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
],"scopeNamep": []},
|
||||
{"type":"INITIAL","name":"","addr":"(FB)","loc":"d,39:4,39:11","isSuspendable":false,"needProcess":false,
|
||||
"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": [
|
||||
{"type":"STMTEXPR","name":"","addr":"(HB)","loc":"d,41:7,41:8",
|
||||
"exprp": [
|
||||
|
|
|
|||
|
|
@ -47,30 +47,30 @@
|
|||
<netlist>
|
||||
<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"/>
|
||||
<begin loc="d,25,14,25,17" name="FOR_GENERATE"/>
|
||||
<begin loc="d,27,21,27,31" name="FOR_GENERATE[0]">
|
||||
<genblock loc="d,25,14,25,17" name="FOR_GENERATE"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</begin>
|
||||
</genblock>
|
||||
<instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/>
|
||||
</begin>
|
||||
<begin loc="d,27,21,27,31" name="FOR_GENERATE[1]">
|
||||
</genblock>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</begin>
|
||||
</genblock>
|
||||
<instance loc="d,31,21,31,29" name="submod_3" defName="submod" origName="submod_3"/>
|
||||
</begin>
|
||||
</genblock>
|
||||
</module>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</begin>
|
||||
</genblock>
|
||||
<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"/>
|
||||
</module>
|
||||
<module loc="d,7,8,7,15" name="submod2" origName="submod2"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue