mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
+49
-17
@@ -158,8 +158,8 @@ class InlineMarkVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
void visit(AstVarXRef* nodep) override {
|
||||
// Remove link. V3LinkDot will reestablish it after inlining.
|
||||
nodep->varp(nullptr);
|
||||
// Keep varp - V3Const::constifyEdit is called during pinReconnectSimple
|
||||
// which needs varp to be set. V3LinkDot will re-resolve after inlining.
|
||||
}
|
||||
void visit(AstNodeFTaskRef* nodep) override {
|
||||
// Remove link. V3LinkDot will reestablish it after inlining.
|
||||
@@ -322,7 +322,7 @@ class InlineRelinkVisitor final : public VNVisitor {
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
// If the target port is being inlined, replace reference with the
|
||||
// connected expression (always a Const of a VarRef).
|
||||
// connected expression (a Const, VarRef, or VarXRef).
|
||||
AstNode* const pinExpr = nodep->varp()->user2p();
|
||||
if (!pinExpr) return;
|
||||
|
||||
@@ -354,10 +354,25 @@ class InlineRelinkVisitor final : public VNVisitor {
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise it must be a variable reference, retarget this ref
|
||||
const AstVarRef* const vrefp = VN_AS(pinExpr, VarRef);
|
||||
nodep->varp(vrefp->varp());
|
||||
nodep->classOrPackagep(vrefp->classOrPackagep());
|
||||
// Handle VarRef: simple retarget
|
||||
if (const AstVarRef* const vrefp = VN_CAST(pinExpr, VarRef)) {
|
||||
nodep->varp(vrefp->varp());
|
||||
nodep->classOrPackagep(vrefp->classOrPackagep());
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle VarXRef: replace VarRef with VarXRef (e.g., nested interface port)
|
||||
const AstVarXRef* const xrefp = VN_AS(pinExpr, VarXRef);
|
||||
AstVarXRef* const newp = new AstVarXRef{nodep->fileline(), xrefp->name(), xrefp->dotted(),
|
||||
nodep->access()};
|
||||
newp->varp(xrefp->varp());
|
||||
// Copy inlinedDots from pin expression - the normal visitor iteration will
|
||||
// prepend the cell name when this VarXRef is visited later
|
||||
newp->inlinedDots(xrefp->inlinedDots());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
// Note: Don't call iterate(newp) here - the node will be visited during
|
||||
// normal tree iteration which will apply the inlining transformations
|
||||
}
|
||||
void visit(AstVarXRef* nodep) override {
|
||||
// Track what scope it was originally under so V3LinkDot can resolve it
|
||||
@@ -481,13 +496,28 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) {
|
||||
}
|
||||
|
||||
// Otherwise it must be a variable reference due to having called pinReconnectSimple
|
||||
const AstVarRef* const pinRefp = VN_AS(pinExprp, VarRef);
|
||||
const AstNodeVarRef* const pinRefp = VN_AS(pinExprp, NodeVarRef);
|
||||
|
||||
// Helper to create an AstVarRef reference to the pin variable
|
||||
const auto pinRef = [&](VAccess access) {
|
||||
AstVarRef* const p = new AstVarRef{pinRefp->fileline(), pinRefp->varp(), access};
|
||||
p->classOrPackagep(pinRefp->classOrPackagep());
|
||||
return p;
|
||||
const auto pinRefAsVarRef = [&](VAccess access) -> AstVarRef* {
|
||||
const AstVarRef* const vrp = VN_AS(pinRefp, VarRef);
|
||||
AstVarRef* const newp = new AstVarRef{vrp->fileline(), vrp->varp(), access};
|
||||
newp->classOrPackagep(vrp->classOrPackagep());
|
||||
return newp;
|
||||
};
|
||||
|
||||
const auto pinRefAsExpr = [&](VAccess access) -> AstNodeExpr* {
|
||||
if (const AstVarRef* const vrp = VN_CAST(pinRefp, VarRef)) {
|
||||
AstVarRef* const newp = new AstVarRef{vrp->fileline(), vrp->varp(), access};
|
||||
newp->classOrPackagep(vrp->classOrPackagep());
|
||||
return newp;
|
||||
} else {
|
||||
const AstVarXRef* const xrp = VN_AS(pinRefp, VarXRef);
|
||||
AstVarXRef* const newp = new AstVarXRef{xrp->fileline(), xrp->name(), xrp->dotted(),
|
||||
access};
|
||||
newp->varp(xrp->varp());
|
||||
newp->inlinedDots(xrp->inlinedDots());
|
||||
return newp;
|
||||
}
|
||||
};
|
||||
|
||||
// If it is being inlined, create the alias for it
|
||||
@@ -495,10 +525,10 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) {
|
||||
UINFO(6, "Inlining port variable: " << nodep);
|
||||
if (nodep->isIfaceRef()) {
|
||||
modp->addStmtsp(
|
||||
new AstAliasScope{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)});
|
||||
new AstAliasScope{flp, portRef(VAccess::WRITE), pinRefAsExpr(VAccess::READ)});
|
||||
} else {
|
||||
AstVarRef* const aliasArgsp = portRef(VAccess::WRITE);
|
||||
aliasArgsp->addNext(pinRef(VAccess::READ));
|
||||
aliasArgsp->addNext(pinRefAsVarRef(VAccess::READ));
|
||||
modp->addStmtsp(new AstAlias{flp, aliasArgsp});
|
||||
}
|
||||
// They will become the same variable, so propagate file-line and variable attributes
|
||||
@@ -512,10 +542,12 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) {
|
||||
// Otherwise create the continuous assignment between the port var and the pin expression
|
||||
UINFO(6, "Not inlining port variable: " << nodep);
|
||||
if (nodep->direction() == VDirection::INPUT) {
|
||||
AstAssignW* const ap = new AstAssignW{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)};
|
||||
AstAssignW* const ap
|
||||
= new AstAssignW{flp, portRef(VAccess::WRITE), pinRefAsExpr(VAccess::READ)};
|
||||
modp->addStmtsp(new AstAlways{ap});
|
||||
} else if (nodep->direction() == VDirection::OUTPUT) {
|
||||
AstAssignW* const ap = new AstAssignW{flp, pinRef(VAccess::WRITE), portRef(VAccess::READ)};
|
||||
AstAssignW* const ap
|
||||
= new AstAssignW{flp, pinRefAsExpr(VAccess::WRITE), portRef(VAccess::READ)};
|
||||
modp->addStmtsp(new AstAlways{ap});
|
||||
} else {
|
||||
pinExprp->v3fatalSrc("V3Tristate left INOUT port");
|
||||
|
||||
Reference in New Issue
Block a user