This commit is contained in:
parent
ba3794a495
commit
c2cba8bfc6
|
|
@ -276,5 +276,6 @@ Zixi Li
|
|||
dependabot[bot]
|
||||
february cozzocrea
|
||||
sumpster
|
||||
em2machine
|
||||
Àlex Torregrosa
|
||||
Ícaro Lima
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ set(HEADERS
|
|||
V3LifePost.h
|
||||
V3LinkCells.h
|
||||
V3LinkDot.h
|
||||
V3LinkDotIfaceCapture.h
|
||||
V3LinkInc.h
|
||||
V3LinkJump.h
|
||||
V3LinkLValue.h
|
||||
|
|
@ -293,6 +294,7 @@ set(COMMON_SOURCES
|
|||
V3LifePost.cpp
|
||||
V3LinkCells.cpp
|
||||
V3LinkDot.cpp
|
||||
V3LinkDotIfaceCapture.cpp
|
||||
V3LinkInc.cpp
|
||||
V3LinkJump.cpp
|
||||
V3LinkLValue.cpp
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3LifePost.o \
|
||||
V3LinkCells.o \
|
||||
V3LinkDot.o \
|
||||
V3LinkDotIfaceCapture.o \
|
||||
V3LinkInc.o \
|
||||
V3LinkJump.o \
|
||||
V3LinkLValue.o \
|
||||
|
|
|
|||
|
|
@ -67,12 +67,15 @@
|
|||
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3LinkDotIfaceCapture.h"
|
||||
#include "V3MemberMap.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3Randomize.h"
|
||||
#include "V3String.h"
|
||||
#include "V3SymTable.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
|
@ -217,9 +220,31 @@ public:
|
|||
UINFO(4, __FUNCTION__ << ": ");
|
||||
s_errorThisp = this;
|
||||
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
|
||||
const std::size_t capturedCount = V3LinkDotIfaceCapture::size();
|
||||
if (forPrimary()) {
|
||||
V3LinkDotIfaceCapture::enable(true);
|
||||
UINFO(9, "iface capture enabled for primary pass (persisting entries) size="
|
||||
<< capturedCount);
|
||||
} else if (forParamed()) {
|
||||
UINFO(9,
|
||||
"iface capture entering paramed pass captured typedef count=" << capturedCount);
|
||||
}
|
||||
readModNames();
|
||||
}
|
||||
~LinkDotState() {
|
||||
const std::size_t capturedCount = V3LinkDotIfaceCapture::size();
|
||||
if (forPrimary()) {
|
||||
UINFO(9,
|
||||
"iface capture leaving primary pass captured typedef count=" << capturedCount);
|
||||
} else if (forParamed()) {
|
||||
UINFO(9,
|
||||
"iface capture leaving paramed pass captured typedef count=" << capturedCount);
|
||||
if (capturedCount != 0) {
|
||||
UINFO(9, "iface capture warning: leftover captured typedef entries="
|
||||
<< capturedCount);
|
||||
}
|
||||
V3LinkDotIfaceCapture::reset();
|
||||
}
|
||||
V3Error::errorExitCb(nullptr);
|
||||
s_errorThisp = nullptr;
|
||||
}
|
||||
|
|
@ -815,32 +840,31 @@ public:
|
|||
}
|
||||
static bool checkIfClassOrPackage(const VSymEnt* const symp) {
|
||||
if (VN_IS(symp->nodep(), Class) || VN_IS(symp->nodep(), Package)) return true;
|
||||
const AstRefDType* refDTypep = nullptr;
|
||||
|
||||
// Helper: check if a RefDType might resolve to a class later
|
||||
const auto checkUnresolvedRef = [](const AstRefDType* refp) -> bool {
|
||||
return refp && !refp->typeofp() && !refp->classOrPackageOpp();
|
||||
};
|
||||
|
||||
// Helper: allow types that can represent a class/package handle or an unresolved ref.
|
||||
// BasicDType is allowed here only for null/object handles.
|
||||
const auto isValidTypeNode = [](const AstNode* nodep) -> bool {
|
||||
return VN_IS(nodep, VoidDType) || VN_IS(nodep, BasicDType)
|
||||
|| VN_IS(nodep, ClassRefDType) || VN_IS(nodep, ParseRef);
|
||||
};
|
||||
|
||||
if (const AstTypedef* const typedefp = VN_CAST(symp->nodep(), Typedef)) {
|
||||
if (VN_IS(typedefp->childDTypep(), ClassRefDType)) return true;
|
||||
if (const AstRefDType* const refp = VN_CAST(typedefp->childDTypep(), RefDType)) {
|
||||
refDTypep = refp;
|
||||
}
|
||||
if (checkUnresolvedRef(VN_CAST(typedefp->childDTypep(), RefDType))) return true;
|
||||
} else if (const AstParamTypeDType* const paramTypep
|
||||
= VN_CAST(symp->nodep(), ParamTypeDType)) {
|
||||
if (const AstRequireDType* const requireDTypep
|
||||
= VN_CAST(paramTypep->childDTypep(), RequireDType)) {
|
||||
if (const AstRefDType* const refp = VN_CAST(requireDTypep->lhsp(), RefDType)) {
|
||||
refDTypep = refp;
|
||||
} else if (VN_IS(requireDTypep->lhsp(), VoidDType)
|
||||
|| VN_IS(requireDTypep->lhsp(), BasicDType)
|
||||
|| VN_IS(requireDTypep->lhsp(), ClassRefDType)) {
|
||||
return true;
|
||||
}
|
||||
// ParamTypeDType child may be wrapped in RequireDType or unwrapped
|
||||
AstNode* childp = paramTypep->childDTypep();
|
||||
if (const AstRequireDType* const reqp = VN_CAST(childp, RequireDType)) {
|
||||
childp = reqp->lhsp();
|
||||
}
|
||||
}
|
||||
// TODO: this should be handled properly - case when it is known what type is
|
||||
// referenced by AstRefDType (refDTypep->typeofp() is null or
|
||||
// refDTypep->classOrPackageOpp() is null)
|
||||
if (refDTypep && !refDTypep->typeofp() && !refDTypep->classOrPackageOpp()) {
|
||||
// When still unknown - return because it may be a class, classes may not be
|
||||
// linked at this point. Return in case it gets resolved to a class in the future
|
||||
return true;
|
||||
if (isValidTypeNode(childp)) return true;
|
||||
if (checkUnresolvedRef(VN_CAST(childp, RefDType))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2730,14 +2754,27 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
return superNewStmtp;
|
||||
}
|
||||
void checkNoDot(AstNode* nodep) {
|
||||
if (VL_UNLIKELY(!nodep)) {
|
||||
UINFO(9, indent() << "iface capture null node passed to checkNoDot; dot state="
|
||||
<< m_ds.ascii());
|
||||
m_ds.m_dotErr = true;
|
||||
return;
|
||||
}
|
||||
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
|
||||
UINFO(9, indent() << "ds=" << m_ds.ascii());
|
||||
nodep->v3error("Syntax error: Not expecting "
|
||||
<< nodep->type() << " under a " << nodep->backp()->type()
|
||||
<< " in dotted expression\n"
|
||||
<< nodep->warnContextPrimary() << m_ds.m_dotp->warnOther()
|
||||
<< "... Resolving this reference\n"
|
||||
<< m_ds.m_dotp->warnContextSecondary());
|
||||
UINFO(9, indent() << "iface capture checkNoDot hit node=" << nodep
|
||||
<< " dotState=" << m_ds.ascii());
|
||||
if (VL_UNLIKELY(!m_ds.m_dotp)) {
|
||||
nodep->v3error("Syntax error: Not expecting " << nodep->type()
|
||||
<< " here (missing dot context)");
|
||||
} else {
|
||||
nodep->v3error("Syntax error: Not expecting "
|
||||
<< nodep->type() << " under a " << nodep->backp()->type()
|
||||
<< " in dotted expression\n"
|
||||
<< nodep->warnContextPrimary() << m_ds.m_dotp->warnOther()
|
||||
<< "... Resolving this reference\n"
|
||||
<< m_ds.m_dotp->warnContextSecondary());
|
||||
}
|
||||
m_ds.m_dotErr = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2774,6 +2811,54 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
<< origp->warnContextSecondary());
|
||||
}
|
||||
}
|
||||
// This helper clones the RefDType (including the user2 context), wraps it in a ParamTypeDType
|
||||
// with the original var name, and returns the new dtype so the caller can ultimately replace
|
||||
// the var and continue typedef retargeting. (used in cases like: localparam rq_t =
|
||||
// bus_io.rq_t;)
|
||||
AstParamTypeDType* promoteVarToParamType(AstVar* varp, AstRefDType* typedefRefp) {
|
||||
if (!varp || !typedefRefp) return nullptr;
|
||||
VSymEnt* const varSymp = varp->user1u().toSymEnt();
|
||||
if (!varSymp) return nullptr;
|
||||
VSymEnt* const parentSymp = varSymp->parentp();
|
||||
if (!parentSymp) return nullptr;
|
||||
UINFO(9, indent() << "iface capture promote var to ParamType name=" << varp->prettyName()
|
||||
<< " dotState(before)=" << m_ds.ascii());
|
||||
AstParamTypeDType* const newTypep = new AstParamTypeDType{
|
||||
varp->fileline(), varp->varType(), VFwdType::NONE,
|
||||
varp->name(), VFlagChildDType{}, typedefRefp->cloneTree(false)};
|
||||
if (AstRefDType* const clonedRefp = VN_CAST(newTypep->childDTypep(), RefDType)) {
|
||||
clonedRefp->user2p(typedefRefp->user2p());
|
||||
if (V3LinkDotIfaceCapture::enabled()) {
|
||||
if (V3LinkDotIfaceCapture::replaceRef(typedefRefp, clonedRefp)) {
|
||||
UINFO(9, indent() << "iface capture retarget captured typedef var="
|
||||
<< varp->prettyName() << " orig=" << typedefRefp
|
||||
<< " clone=" << clonedRefp);
|
||||
}
|
||||
if (typedefRefp->user2p()) {
|
||||
UINFO(9, indent() << "iface capture capture recorded owner var="
|
||||
<< varp->prettyName() << " typedef=" << clonedRefp
|
||||
<< " cell=" << clonedRefp->user2p());
|
||||
}
|
||||
}
|
||||
}
|
||||
VSymEnt* const newSymEntp = new VSymEnt{m_statep->symsp(), newTypep};
|
||||
newSymEntp->parentp(parentSymp);
|
||||
newSymEntp->fallbackp(varSymp->fallbackp());
|
||||
newSymEntp->classOrPackagep(varSymp->classOrPackagep());
|
||||
newSymEntp->exported(varSymp->exported());
|
||||
newSymEntp->imported(varSymp->imported());
|
||||
newTypep->user1p(newSymEntp);
|
||||
parentSymp->reinsert(varp->name(), newSymEntp);
|
||||
varp->replaceWith(newTypep);
|
||||
// This conversion happens while linkDot is in the middle of a dotted lookup (e.g.
|
||||
// bus_io.rq_t). Reset the dot state so subsequent symbols in this scope do not inherit the
|
||||
// pending dot.
|
||||
m_ds.init(m_curSymp);
|
||||
UINFO(9, indent() << "iface capture converted owner var to ParamType name="
|
||||
<< varp->prettyName() << " dotState(after-reset)=" << m_ds.ascii());
|
||||
VL_DO_DANGLING(pushDeletep(varp), varp);
|
||||
return newTypep;
|
||||
}
|
||||
VSymEnt* getCreateClockingEventSymEnt(AstClocking* clockingp) {
|
||||
AstVar* const eventp = clockingp->ensureEventp(true);
|
||||
if (!eventp->user1p()) eventp->user1p(new VSymEnt{m_statep->symsp(), eventp});
|
||||
|
|
@ -3121,6 +3206,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
m_modp = nullptr;
|
||||
m_ds.m_dotSymp = m_curSymp = m_modSymp = nullptr;
|
||||
m_ds.m_dotPos = DP_NONE;
|
||||
m_ds.m_dotErr = false;
|
||||
}
|
||||
void visit(AstScope* nodep) override {
|
||||
LINKDOT_VISIT_START();
|
||||
|
|
@ -3894,13 +3981,32 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
} else if (AstTypedef* const defp = VN_CAST(foundp->nodep(), Typedef)) {
|
||||
ok = m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE;
|
||||
const bool ifaceFinalSegmentAllowed
|
||||
= (m_ds.m_dotPos == DP_FINAL) && m_ds.m_dotSymp
|
||||
&& VN_IS(m_ds.m_dotSymp->nodep(), Cell)
|
||||
&& VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp()
|
||||
&& VN_IS(VN_CAST(m_ds.m_dotSymp->nodep(), Cell)->modp(), Iface);
|
||||
ok = (m_ds.m_dotPos == DP_NONE || m_ds.m_dotPos == DP_SCOPE
|
||||
|| (V3LinkDotIfaceCapture::enabled() && ifaceFinalSegmentAllowed));
|
||||
if (V3LinkDotIfaceCapture::enabled() && ifaceFinalSegmentAllowed) {
|
||||
UINFO(9, indent() << "iface capture allow final-segment typedef name="
|
||||
<< nodep->name() << " dotText='" << m_ds.m_dotText
|
||||
<< "' dotSym=" << m_ds.m_dotSymp);
|
||||
}
|
||||
if (ok) {
|
||||
AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()};
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be
|
||||
// resolved yet
|
||||
if (m_ds.m_dotPos == DP_NONE) checkDeclOrder(nodep, defp);
|
||||
refp->typedefp(defp);
|
||||
|
||||
V3LinkDotIfaceCapture::captureTypedefContext(
|
||||
refp, "typedef", static_cast<int>(m_ds.m_dotPos),
|
||||
m_ds.m_dotPos == DP_FINAL, m_ds.m_dotText, m_ds.m_dotSymp, m_curSymp,
|
||||
m_modp, nodep,
|
||||
[this](AstVar* v, AstRefDType* r) { return promoteVarToParamType(v, r); },
|
||||
[this]() { return indent(); });
|
||||
|
||||
if (VN_IS(nodep->backp(), SelExtract)) {
|
||||
m_packedArrayDtp = refp;
|
||||
} else {
|
||||
|
|
@ -3913,6 +4019,14 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
if (ok) {
|
||||
AstRefDType* const refp = new AstRefDType{nodep->fileline(), nodep->name()};
|
||||
refp->refDTypep(defp);
|
||||
|
||||
V3LinkDotIfaceCapture::captureTypedefContext(
|
||||
refp, "paramtype", static_cast<int>(m_ds.m_dotPos),
|
||||
m_ds.m_dotPos == DP_FINAL, m_ds.m_dotText, m_ds.m_dotSymp, m_curSymp,
|
||||
m_modp, nodep,
|
||||
[this](AstVar* v, AstRefDType* r) { return promoteVarToParamType(v, r); },
|
||||
[this]() { return indent(); });
|
||||
|
||||
replaceWithCheckBreak(nodep, refp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
|
@ -4987,8 +5101,52 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp);
|
||||
}
|
||||
void visit(AstRefDType* nodep) override {
|
||||
|
||||
if (auto* const typeOfp = nodep->typeofp()) {
|
||||
iterate(typeOfp);
|
||||
// After iteration, typeofp() may have been replaced with a resolved type
|
||||
// (e.g., DOT expression like if0.rq_t resolved to REFDTYPE)
|
||||
// If it's now a NodeDType, replace this RefDType with it
|
||||
if (AstNodeDType* const resolvedDTypep = VN_CAST(nodep->typeofp(), NodeDType)) {
|
||||
UINFO(9,
|
||||
indent() << "iface capture typeofp resolved to dtype, replacing RefDType\n");
|
||||
resolvedDTypep->unlinkFrBack();
|
||||
nodep->replaceWith(resolvedDTypep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
// If the resolved dtype is a RefDType with an interface typedef,
|
||||
// ensure it's captured for re-resolution during paramed pass
|
||||
if (AstRefDType* const resolvedRefp = VN_CAST(resolvedDTypep, RefDType)) {
|
||||
if (resolvedRefp->user2p() && !V3LinkDotIfaceCapture::find(resolvedRefp)) {
|
||||
AstCell* const cellp = VN_AS(resolvedRefp->user2p(), Cell);
|
||||
UINFO(9, indent() << "iface capture re-capture resolved RefDType="
|
||||
<< resolvedRefp << " cell=" << cellp << "\n");
|
||||
V3LinkDotIfaceCapture::add(resolvedRefp, cellp, m_modp,
|
||||
resolvedRefp->typedefp());
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve its reference
|
||||
if (nodep->user3SetOnce()) return;
|
||||
if (V3LinkDotIfaceCapture::find(nodep)) {
|
||||
UINFO(9, indent() << "iface capture visit captured typedef ptr=" << nodep
|
||||
<< " user2=" << nodep->user2p());
|
||||
}
|
||||
if (m_statep->forParamed() && nodep->user3()) {
|
||||
if (V3LinkDotIfaceCapture::enabled() && nodep->user2p()) {
|
||||
UINFO(9, indent() << "iface capture clear user3 for captured typedef name="
|
||||
<< nodep->name() << " cell=" << nodep->user2p());
|
||||
}
|
||||
nodep->user3(false);
|
||||
}
|
||||
if (nodep->user3SetOnce()) {
|
||||
if (V3LinkDotIfaceCapture::enabled() && nodep->user2p()) {
|
||||
UINFO(9, indent() << "iface capture skip revisit name=" << nodep->name()
|
||||
<< " already user3 and captured cell=" << nodep->user2p());
|
||||
}
|
||||
return;
|
||||
}
|
||||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
if (AstNode* const cpackagep = nodep->classOrPackageOpp()) {
|
||||
|
|
@ -5030,19 +5188,80 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
VL_DO_DANGLING(pushDeletep(cpackagep->unlinkFrBack()), cpackagep);
|
||||
}
|
||||
|
||||
const bool capEnable = V3LinkDotIfaceCapture::enabled();
|
||||
const auto* const capEntryp = capEnable ? V3LinkDotIfaceCapture::find(nodep) : nullptr;
|
||||
const bool captureMapHit = capEntryp != nullptr;
|
||||
AstCell* const captureEntryCellp = capEntryp ? capEntryp->cellp : nullptr;
|
||||
AstTypedef* const capturedTypedefp = capEntryp ? capEntryp->typedefp : nullptr;
|
||||
const VSymEnt* const capturedTypedefSymp
|
||||
= capturedTypedefp ? m_statep->getNodeSym(capturedTypedefp) : nullptr;
|
||||
|
||||
const bool ifaceCaptured = capEnable && nodep->user2p();
|
||||
const bool missingIfaceContext = captureMapHit && !ifaceCaptured;
|
||||
const char* const passLabel = m_statep->forParamed() ? "paramed" : "primary";
|
||||
if (missingIfaceContext) {
|
||||
UINFO(9, indent() << "iface capture captured typedef missing user2 name="
|
||||
<< nodep->name() << " ref=" << nodep << " pass=" << passLabel
|
||||
<< " entryCell=" << captureEntryCellp);
|
||||
}
|
||||
AstCell* const capturedCellp = ifaceCaptured ? VN_CAST(nodep->user2p(), Cell) : nullptr;
|
||||
|
||||
bool forcedIfaceDotScope = false;
|
||||
bool resolvedCapturedTypedef = false;
|
||||
bool captureEntryRetired = false;
|
||||
const auto retireCapture = [&](const char* reason) {
|
||||
if (!ifaceCaptured || captureEntryRetired) return;
|
||||
const auto* entry = V3LinkDotIfaceCapture::find(nodep);
|
||||
AstCell* const entryCell = entry ? entry->cellp : nullptr;
|
||||
UINFO(9, indent() << "iface capture retire captured typedef reason=" << reason
|
||||
<< " name=" << nodep->name() << " pass=" << passLabel
|
||||
<< " user2=" << nodep->user2p() << " entryCell=" << entryCell);
|
||||
const bool erased = V3LinkDotIfaceCapture::erase(nodep);
|
||||
captureEntryRetired = true;
|
||||
UINFO(9, indent() << "iface capture retire erase result name=" << nodep->name()
|
||||
<< " erased=" << erased);
|
||||
};
|
||||
if (ifaceCaptured && m_statep->forParamed()) {
|
||||
UINFO(9, indent() << "iface capture captured typedef name=" << nodep->name()
|
||||
<< " typedef=" << nodep->typedefp() << " cell=" << capturedCellp);
|
||||
if (nodep->typedefp()) {
|
||||
UINFO(9, indent() << "iface capture refresh typedef binding name=" << nodep->name()
|
||||
<< " typedef=" << nodep->typedefp()
|
||||
<< " cell=" << capturedCellp);
|
||||
nodep->typedefp(nullptr);
|
||||
nodep->classOrPackagep(nullptr);
|
||||
}
|
||||
}
|
||||
if (m_ds.m_dotp && (m_ds.m_dotPos == DP_PACKAGE || m_ds.m_dotPos == DP_SCOPE)) {
|
||||
UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(),
|
||||
"Bad package link");
|
||||
auto* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
||||
auto* const cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef);
|
||||
UASSERT_OBJ(cpackagerefp->classOrPackageSkipp(), m_ds.m_dotp->lhsp(),
|
||||
"Bad package link");
|
||||
nodep->classOrPackagep(cpackagerefp->classOrPackageSkipp());
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
} else {
|
||||
} else if (!ifaceCaptured) {
|
||||
checkNoDot(nodep);
|
||||
} else {
|
||||
UINFO(9, indent() << "iface capture consume captured iface context name="
|
||||
<< nodep->name() << " cell=" << capturedCellp);
|
||||
m_ds.m_dotPos = DP_SCOPE;
|
||||
forcedIfaceDotScope = true;
|
||||
// Set dotSymp to the cell's symbol entry so lookup happens in the interface scope
|
||||
if (capturedCellp && m_statep->existsNodeSym(capturedCellp)) {
|
||||
VSymEnt* const cellSymp = m_statep->getNodeSym(capturedCellp);
|
||||
m_ds.m_dotSymp = cellSymp;
|
||||
UINFO(9, indent() << "iface capture set dotSymp to cell scope cellSymp="
|
||||
<< cellSymp << " node=" << cellSymp->nodep());
|
||||
}
|
||||
}
|
||||
if (nodep->typeofp()) { // Really is a typeof not a reference
|
||||
} else if (!nodep->typedefp() && !nodep->subDTypep()) {
|
||||
if (!nodep->typedefp() && !nodep->subDTypep()) {
|
||||
if (ifaceCaptured) {
|
||||
UINFO(9, indent() << "iface capture lookup start name=" << nodep->name()
|
||||
<< " dotPos=" << static_cast<int>(m_ds.m_dotPos) << " dotSym="
|
||||
<< m_ds.m_dotSymp << " classPkg=" << nodep->classOrPackagep());
|
||||
}
|
||||
const VSymEnt* foundp;
|
||||
if (nodep->classOrPackagep()) {
|
||||
foundp = m_statep->getNodeSym(nodep->classOrPackagep())->findIdFlat(nodep->name());
|
||||
|
|
@ -5052,52 +5271,105 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
} else if (m_ds.m_dotPos == DP_FIRST || m_ds.m_dotPos == DP_NONE) {
|
||||
foundp = m_curSymp->findIdFallback(nodep->name());
|
||||
} else {
|
||||
foundp = m_curSymp->findIdFlat(nodep->name());
|
||||
//foundp = m_curSymp->findIdFlat(nodep->name());
|
||||
// Use dotSymp if set (e.g., for captured interface typedefs), else curSymp
|
||||
VSymEnt* const lookupSymp = m_ds.m_dotSymp ? m_ds.m_dotSymp : m_curSymp;
|
||||
foundp = lookupSymp->findIdFlat(nodep->name());
|
||||
}
|
||||
if (AstTypedef* const defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be resolved
|
||||
// yet
|
||||
if (!nodep->classOrPackagep() && !defp->isUnderClass())
|
||||
checkDeclOrder(nodep, defp);
|
||||
nodep->typedefp(defp);
|
||||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
} else if (AstParamTypeDType* const defp
|
||||
= foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : nullptr) {
|
||||
if (defp == nodep->backp()) { // Where backp is typically typedef
|
||||
nodep->v3error("Reference to '" << m_ds.m_dotText
|
||||
<< (m_ds.m_dotText == "" ? "" : ".")
|
||||
<< nodep->prettyName() << "'"
|
||||
<< " type would form a recursive definition");
|
||||
nodep->refDTypep(nodep->findVoidDType()); // Try to reduce later errors
|
||||
} else {
|
||||
nodep->refDTypep(defp);
|
||||
if (!foundp && ifaceCaptured && capturedTypedefp) {
|
||||
UINFO(9, indent() << "iface capture binding via captured typedef fallback name="
|
||||
<< nodep->name() << " typedef=" << capturedTypedefp);
|
||||
nodep->typedefp(capturedTypedefp);
|
||||
nodep->classOrPackagep(capturedTypedefSymp ? capturedTypedefSymp->classOrPackagep()
|
||||
: nullptr);
|
||||
resolvedCapturedTypedef = true;
|
||||
}
|
||||
if (!resolvedCapturedTypedef && foundp) {
|
||||
VSymEnt* const parentSymp = foundp->parentp();
|
||||
UINFO(9, indent() << "iface capture resolved typedef name=" << nodep->name()
|
||||
<< " foundNode=" << foundp->nodep() << " parentNode="
|
||||
<< (parentSymp ? parentSymp->nodep() : nullptr));
|
||||
}
|
||||
if (!resolvedCapturedTypedef) {
|
||||
if (AstTypedef* const defp
|
||||
= foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be
|
||||
// resolved yet
|
||||
if (!nodep->classOrPackagep() && !defp->isUnderClass())
|
||||
checkDeclOrder(nodep, defp);
|
||||
nodep->typedefp(defp);
|
||||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
}
|
||||
} else if (AstClass* const defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be resolved
|
||||
// yet
|
||||
if (!nodep->classOrPackagep()) checkDeclOrder(nodep, defp);
|
||||
AstPin* const paramsp = nodep->paramsp();
|
||||
if (paramsp) paramsp->unlinkFrBackWithNext();
|
||||
AstClassRefDType* const newp
|
||||
= new AstClassRefDType{nodep->fileline(), defp, paramsp};
|
||||
newp->classOrPackagep(foundp->classOrPackagep());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
} else if (m_insideClassExtParam) {
|
||||
return;
|
||||
} else {
|
||||
if (foundp) {
|
||||
UINFO(1, "Found sym node: " << foundp->nodep());
|
||||
nodep->v3error("Expecting a data type: " << nodep->prettyNameQ());
|
||||
resolvedCapturedTypedef = true;
|
||||
} else if (AstParamTypeDType* const defp
|
||||
= foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : nullptr) {
|
||||
if (defp == nodep->backp()) { // Where backp is typically typedef
|
||||
nodep->v3error("Reference to '"
|
||||
<< m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".")
|
||||
<< nodep->prettyName() << "'"
|
||||
<< " type would form a recursive definition");
|
||||
nodep->refDTypep(nodep->findVoidDType()); // Try to reduce later errors
|
||||
} else {
|
||||
nodep->refDTypep(defp);
|
||||
nodep->classOrPackagep(foundp->classOrPackagep());
|
||||
resolvedCapturedTypedef = true;
|
||||
}
|
||||
} else if (AstClass* const defp
|
||||
= foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) {
|
||||
// Don't check if typedef is to a <type T>::<reference> as might not be
|
||||
// resolved yet
|
||||
if (!nodep->classOrPackagep()) checkDeclOrder(nodep, defp);
|
||||
AstPin* const paramsp = nodep->paramsp();
|
||||
if (paramsp) paramsp->unlinkFrBackWithNext();
|
||||
AstClassRefDType* const newp
|
||||
= new AstClassRefDType{nodep->fileline(), defp, paramsp};
|
||||
newp->classOrPackagep(foundp->classOrPackagep());
|
||||
resolvedCapturedTypedef = true;
|
||||
retireCapture("resolved"); // Must retire before replacing node
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
} else if (m_insideClassExtParam) {
|
||||
return;
|
||||
} else {
|
||||
nodep->v3error("Can't find typedef/interface: " << nodep->prettyNameQ());
|
||||
if (foundp) {
|
||||
UINFO(1, "Found sym node: " << foundp->nodep());
|
||||
nodep->v3error("Expecting a data type: " << nodep->prettyNameQ());
|
||||
} else {
|
||||
nodep->v3error("Can't find typedef/interface: " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forcedIfaceDotScope && m_ds.m_dotPos == DP_SCOPE && !m_ds.m_dotp) {
|
||||
UINFO(9, indent() << "iface capture reset dot state after captured typedef name="
|
||||
<< nodep->name());
|
||||
m_ds.init(m_curSymp);
|
||||
}
|
||||
if (ifaceCaptured && resolvedCapturedTypedef) { retireCapture("resolved"); }
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstRequireDType* nodep) override {
|
||||
// Handle type validation for localparam type assignments
|
||||
// Iterate child to resolve any ParseRef nodes
|
||||
iterateChildren(nodep);
|
||||
// Only emit error if the child is not a type.
|
||||
// Do NOT unwrap valid types here - leave that to V3Width.
|
||||
// Unwrapping here breaks type parameter resolution during cloning.
|
||||
if (nodep->lhsp() && !VN_IS(nodep->lhsp(), NodeDType)) {
|
||||
// Not a type - emit error
|
||||
if (AstConst* const constp = VN_CAST(nodep->lhsp(), Const)) {
|
||||
nodep->lhsp()->v3error(
|
||||
"Expecting a data type, not a constant: " << constp->toSInt());
|
||||
} else {
|
||||
nodep->lhsp()->v3error("Expecting a data type, not "
|
||||
<< nodep->lhsp()->typeName() << ": '"
|
||||
<< nodep->lhsp()->prettyName() << "'");
|
||||
}
|
||||
// Replace with void to keep AST valid and allow clean exit
|
||||
nodep->replaceWith(new AstVoidDType{nodep->fileline()});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstDpiExport* nodep) override {
|
||||
// AstDpiExport: Make sure the function referenced exists, then dump it
|
||||
LINKDOT_VISIT_START();
|
||||
|
|
@ -5234,6 +5506,14 @@ public:
|
|||
LinkDotResolveVisitor(AstNetlist* rootp, LinkDotState* statep)
|
||||
: m_statep{statep} {
|
||||
UINFO(4, __FUNCTION__ << ": ");
|
||||
|
||||
if (m_statep->forParamed()) {
|
||||
V3LinkDotIfaceCapture::forEach(
|
||||
[](const V3LinkDotIfaceCapture::CapturedIfaceTypedef& entry) {
|
||||
if (AstRefDType* const refp = entry.refp) refp->user3(false);
|
||||
});
|
||||
}
|
||||
|
||||
iterate(rootp);
|
||||
std::map<std::string, AstNodeModule*> modulesToRevisit = std::move(m_modulesToRevisit);
|
||||
m_lastDeferredp = nullptr;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator:
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "V3LinkDotIfaceCapture.h"
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
V3LinkDotIfaceCapture::CapturedMap V3LinkDotIfaceCapture::s_map{};
|
||||
|
||||
bool V3LinkDotIfaceCapture::s_enabled = true;
|
||||
|
||||
AstNodeModule* V3LinkDotIfaceCapture::findOwnerModule(AstNode* nodep) {
|
||||
for (AstNode* curp = nodep; curp; curp = curp->backp()) {
|
||||
if (AstNodeModule* const modp = VN_CAST(curp, NodeModule)) return modp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool V3LinkDotIfaceCapture::finalizeCapturedEntry(CapturedMap::iterator it, const char* reasonp) {
|
||||
CapturedIfaceTypedef& entry = it->second;
|
||||
AstRefDType* const pendingRefp = entry.pendingClonep;
|
||||
AstTypedef* const reboundTypedefp = entry.typedefp;
|
||||
if (!pendingRefp || !reboundTypedefp) return false;
|
||||
if (entry.cellp) pendingRefp->user2p(entry.cellp);
|
||||
pendingRefp->user3(false);
|
||||
pendingRefp->typedefp(reboundTypedefp);
|
||||
entry.pendingClonep = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
string V3LinkDotIfaceCapture::extractIfacePortName(const string& dotText) {
|
||||
string name = dotText;
|
||||
const size_t dotPos = name.find('.');
|
||||
if (dotPos != string::npos) name = name.substr(0, dotPos);
|
||||
const size_t braPos = name.find("__BRA__");
|
||||
if (braPos != string::npos) name = name.substr(0, braPos);
|
||||
return name;
|
||||
}
|
||||
|
||||
void V3LinkDotIfaceCapture::add(AstRefDType* refp, AstCell* cellp, AstNodeModule* ownerModp,
|
||||
AstTypedef* typedefp, AstNodeModule* typedefOwnerModp,
|
||||
AstVar* ifacePortVarp) {
|
||||
if (!refp) return;
|
||||
|
||||
if (!typedefp) typedefp = refp->typedefp();
|
||||
|
||||
if (!typedefOwnerModp && typedefp) typedefOwnerModp = findOwnerModule(typedefp);
|
||||
|
||||
s_map[refp] = CapturedIfaceTypedef{
|
||||
refp, cellp, ownerModp, typedefp, typedefOwnerModp, nullptr, ifacePortVarp};
|
||||
}
|
||||
|
||||
const V3LinkDotIfaceCapture::CapturedIfaceTypedef*
|
||||
V3LinkDotIfaceCapture::find(const AstRefDType* refp) {
|
||||
if (!refp) return nullptr;
|
||||
const auto it = s_map.find(refp);
|
||||
if (VL_UNLIKELY(it == s_map.end())) return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
bool V3LinkDotIfaceCapture::erase(const AstRefDType* refp) {
|
||||
if (!refp) return false;
|
||||
const auto it = s_map.find(refp);
|
||||
if (it == s_map.end()) return false;
|
||||
s_map.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool V3LinkDotIfaceCapture::replaceRef(const AstRefDType* oldRefp, AstRefDType* newRefp) {
|
||||
if (!oldRefp || !newRefp) return false;
|
||||
const auto it = s_map.find(oldRefp);
|
||||
if (it == s_map.end()) return false;
|
||||
auto entry = it->second;
|
||||
entry.refp = newRefp;
|
||||
s_map.erase(it);
|
||||
s_map.emplace(newRefp, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool V3LinkDotIfaceCapture::replaceTypedef(const AstRefDType* refp, AstTypedef* newTypedefp) {
|
||||
if (!refp || !newTypedefp) return false;
|
||||
auto it = s_map.find(refp);
|
||||
if (it == s_map.end()) return false;
|
||||
it->second.typedefp = newTypedefp;
|
||||
it->second.typedefOwnerModp = findOwnerModule(newTypedefp);
|
||||
finalizeCapturedEntry(it, "typedef clone");
|
||||
return true;
|
||||
}
|
||||
|
||||
void V3LinkDotIfaceCapture::propagateClone(const AstRefDType* origRefp, AstRefDType* newRefp) {
|
||||
if (!origRefp || !newRefp) return;
|
||||
auto it = s_map.find(origRefp);
|
||||
UASSERT_OBJ(it != s_map.end(), origRefp,
|
||||
"iface capture propagateClone missing entry for orig=" << cvtToStr(origRefp));
|
||||
CapturedIfaceTypedef& entry = it->second;
|
||||
|
||||
if (entry.cellp) newRefp->user2p(entry.cellp);
|
||||
newRefp->user3(false);
|
||||
entry.pendingClonep = newRefp;
|
||||
|
||||
// If replaceTypedef was already called (interface cloned before module),
|
||||
// entry.typedefp will differ from the original RefDType's typedef.
|
||||
// In that case, finalize now with the updated typedef.
|
||||
if (entry.typedefp && origRefp->typedefp() && entry.typedefp != origRefp->typedefp()) {
|
||||
finalizeCapturedEntry(it, "ref clone");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FilterFn, typename Fn>
|
||||
void V3LinkDotIfaceCapture::forEachImpl(FilterFn&& filter, Fn&& fn) {
|
||||
std::vector<const AstRefDType*> keys;
|
||||
keys.reserve(s_map.size());
|
||||
for (const auto& kv : s_map) keys.push_back(kv.first);
|
||||
|
||||
for (const AstRefDType* key : keys) {
|
||||
const auto it = s_map.find(key);
|
||||
if (it == s_map.end()) continue;
|
||||
|
||||
CapturedIfaceTypedef& entry = it->second;
|
||||
if (entry.cellp && entry.refp && entry.refp->user2p() != entry.cellp) {
|
||||
entry.refp->user2p(entry.cellp);
|
||||
}
|
||||
if (!filter(entry)) continue;
|
||||
fn(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void V3LinkDotIfaceCapture::forEach(const std::function<void(const CapturedIfaceTypedef&)>& fn) {
|
||||
if (!fn) return;
|
||||
forEachImpl([](const CapturedIfaceTypedef&) { return true; }, fn);
|
||||
}
|
||||
|
||||
void V3LinkDotIfaceCapture::forEachOwned(
|
||||
const AstNodeModule* ownerModp, const std::function<void(const CapturedIfaceTypedef&)>& fn) {
|
||||
if (!ownerModp || !fn) return;
|
||||
forEachImpl(
|
||||
[ownerModp](const CapturedIfaceTypedef& e) {
|
||||
return e.ownerModp == ownerModp || e.typedefOwnerModp == ownerModp;
|
||||
},
|
||||
fn);
|
||||
}
|
||||
|
||||
// replaces the lambda used in V3LinkDot.cpp for iface capture
|
||||
void V3LinkDotIfaceCapture::captureTypedefContext(
|
||||
AstRefDType* refp, const char* stageLabel, int dotPos, bool dotIsFinal,
|
||||
const std::string& dotText, VSymEnt* dotSymp, VSymEnt* curSymp, AstNodeModule* modp,
|
||||
AstNode* nodep, const std::function<bool(AstVar*, AstRefDType*)>& promoteVarCb,
|
||||
const std::function<std::string()>& indentFn) {
|
||||
if (!enabled() || !refp) return;
|
||||
|
||||
UINFO(9, indentFn() << "iface capture capture request stage=" << stageLabel
|
||||
<< " typedef=" << refp << " name=" << refp->name() << " dotPos=" << dotPos
|
||||
<< " dotText='" << dotText << "' dotSym=" << dotSymp);
|
||||
|
||||
const AstCell* ifaceCellp = nullptr;
|
||||
if (dotSymp && VN_IS(dotSymp->nodep(), Cell)) {
|
||||
const AstCell* const cellp = VN_AS(dotSymp->nodep(), Cell);
|
||||
if (cellp->modp() && VN_IS(cellp->modp(), Iface)) ifaceCellp = cellp;
|
||||
}
|
||||
if (!ifaceCellp) {
|
||||
UINFO(9, indentFn() << "iface capture capture skipped typedef=" << refp
|
||||
<< " (no iface context)");
|
||||
return;
|
||||
}
|
||||
|
||||
AstVar* ifacePortVarp = nullptr;
|
||||
if (!dotText.empty() && curSymp) {
|
||||
const std::string portName = extractIfacePortName(dotText);
|
||||
if (VSymEnt* const portSymp = curSymp->findIdFallback(portName)) {
|
||||
ifacePortVarp = VN_CAST(portSymp->nodep(), Var);
|
||||
UINFO(9, indentFn() << "iface capture found port var '" << portName << "' -> "
|
||||
<< ifacePortVarp);
|
||||
}
|
||||
}
|
||||
|
||||
refp->user2p(const_cast<AstCell*>(ifaceCellp));
|
||||
V3LinkDotIfaceCapture::add(refp, const_cast<AstCell*>(ifaceCellp), modp, refp->typedefp(),
|
||||
nullptr, ifacePortVarp);
|
||||
|
||||
UINFO(9, indentFn() << "iface capture capture success typedef=" << refp
|
||||
<< " cell=" << ifaceCellp
|
||||
<< " mod=" << (ifaceCellp->modp() ? ifaceCellp->modp()->name() : "<null>")
|
||||
<< " dotPos=" << dotPos);
|
||||
if (!dotIsFinal) return;
|
||||
|
||||
AstVar* enclosingVarp = nullptr;
|
||||
for (AstNode* curp = nodep; curp; curp = curp->backp()) {
|
||||
if (AstVar* const varp = VN_CAST(curp, Var)) {
|
||||
enclosingVarp = varp;
|
||||
break;
|
||||
}
|
||||
if (VN_IS(curp, ParamTypeDType)) break;
|
||||
if (VN_IS(curp, NodeModule)) break;
|
||||
}
|
||||
if (!enclosingVarp || enclosingVarp->user3SetOnce()) return;
|
||||
UINFO(9, indentFn() << "iface capture typedef owner var=" << enclosingVarp
|
||||
<< " name=" << enclosingVarp->prettyName());
|
||||
|
||||
if (promoteVarCb && promoteVarCb(enclosingVarp, refp)) return;
|
||||
UINFO(9, indentFn() << "iface capture failed to convert owner var name="
|
||||
<< enclosingVarp->prettyName());
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Interface typedef capture helper.
|
||||
// Stores (refp, typedefp, cellp, owners, pendingClone) so LinkDot can
|
||||
// rebind refs when symbol lookup fails, and V3Param clones can retarget
|
||||
// typedefs without legacy paths.
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2025 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3LINKDOTIFACECAPTURE_H_
|
||||
#define VERILATOR_V3LINKDOTIFACECAPTURE_H_
|
||||
|
||||
#include "config_build.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3SymTable.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
class V3LinkDotIfaceCapture final {
|
||||
public:
|
||||
struct CapturedIfaceTypedef final {
|
||||
AstRefDType* refp = nullptr;
|
||||
AstCell* cellp = nullptr;
|
||||
// Module where the RefDType lives
|
||||
AstNodeModule* ownerModp = nullptr;
|
||||
// Typedef definition being referenced
|
||||
AstTypedef* typedefp = nullptr;
|
||||
// Interface/module that owns typedefp
|
||||
AstNodeModule* typedefOwnerModp = nullptr;
|
||||
// Cloned RefDType awaiting typedef rebinding
|
||||
AstRefDType* pendingClonep = nullptr;
|
||||
// Interface port variable for matching during cloning
|
||||
AstVar* ifacePortVarp = nullptr;
|
||||
};
|
||||
|
||||
using CapturedMap = std::unordered_map<const AstRefDType*, CapturedIfaceTypedef>;
|
||||
|
||||
private:
|
||||
static CapturedMap s_map;
|
||||
static bool s_enabled;
|
||||
|
||||
static AstNodeModule* findOwnerModule(AstNode* nodep);
|
||||
static bool finalizeCapturedEntry(CapturedMap::iterator it, const char* reasonp);
|
||||
static string extractIfacePortName(const string& dotText);
|
||||
|
||||
template <typename FilterFn, typename Fn>
|
||||
static void forEachImpl(FilterFn&& filter, Fn&& fn);
|
||||
|
||||
public:
|
||||
static void enable(bool flag) {
|
||||
s_enabled = flag;
|
||||
if (!flag) s_map.clear();
|
||||
}
|
||||
static bool enabled() { return s_enabled; }
|
||||
static void reset() { s_map.clear(); }
|
||||
static void add(AstRefDType* refp, AstCell* cellp, AstNodeModule* ownerModp,
|
||||
AstTypedef* typedefp = nullptr, AstNodeModule* typedefOwnerModp = nullptr,
|
||||
AstVar* ifacePortVarp = nullptr);
|
||||
static const CapturedIfaceTypedef* find(const AstRefDType* refp);
|
||||
static void forEach(const std::function<void(const CapturedIfaceTypedef&)>& fn);
|
||||
static void forEachOwned(const AstNodeModule* ownerModp,
|
||||
const std::function<void(const CapturedIfaceTypedef&)>& fn);
|
||||
static bool replaceRef(const AstRefDType* oldRefp, AstRefDType* newRefp);
|
||||
static bool replaceTypedef(const AstRefDType* refp, AstTypedef* newTypedefp);
|
||||
static bool erase(const AstRefDType* refp);
|
||||
static std::size_t size() { return s_map.size(); }
|
||||
static void propagateClone(const AstRefDType* origRefp, AstRefDType* newRefp);
|
||||
|
||||
static void
|
||||
captureTypedefContext(AstRefDType* refp, const char* stageLabel, int dotPos, bool dotIsFinal,
|
||||
const std::string& dotText, VSymEnt* dotSymp, VSymEnt* curSymp,
|
||||
AstNodeModule* modp, AstNode* nodep,
|
||||
const std::function<bool(AstVar*, AstRefDType*)>& promoteVarCb,
|
||||
const std::function<std::string()>& indentFn);
|
||||
};
|
||||
|
||||
#endif // VERILATOR_V3LINKDOTIFACECAPTURE_H_
|
||||
|
|
@ -53,6 +53,7 @@
|
|||
#include "V3Const.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3Hasher.h"
|
||||
#include "V3LinkDotIfaceCapture.h"
|
||||
#include "V3Os.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3Simulate.h"
|
||||
|
|
@ -61,6 +62,7 @@
|
|||
#include "V3Width.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
|
@ -623,6 +625,75 @@ class ParamProcessor final {
|
|||
newModp = srcModp->cloneTree(false);
|
||||
}
|
||||
|
||||
// cloneTree(false) temporarily populates origNode->clonep() for every node under
|
||||
// srcModp. The capture list still stores those orig AstRefDType* pointers, so walking
|
||||
// it lets us follow clonep() into newModp and scrub each clone with the saved
|
||||
// interface context before newModp is re-linked. we have pointers to the same nodes saved
|
||||
// in the capture map, so we can use them to scrub the new module.
|
||||
if (V3LinkDotIfaceCapture::enabled()) {
|
||||
V3LinkDotIfaceCapture::forEachOwned(
|
||||
srcModp, [&](const V3LinkDotIfaceCapture::CapturedIfaceTypedef& entry) {
|
||||
if (!entry.refp) return;
|
||||
AstTypedef* const origTypedefp = entry.typedefp;
|
||||
if (!origTypedefp) return;
|
||||
|
||||
// Find the correct typedef from the correct interface clone.
|
||||
// entry.typedefp points to the original interface's typedef,
|
||||
// but we need the typedef in the interface clone this module connects to.
|
||||
AstTypedef* targetTypedefp = nullptr;
|
||||
const string& typedefName = origTypedefp->name();
|
||||
|
||||
for (auto it = ifaceRefRefs.cbegin(); it != ifaceRefRefs.cend(); ++it) {
|
||||
const AstIfaceRefDType* const portIrefp = it->first;
|
||||
AstNodeModule* const pinIfacep = it->second->ifaceViaCellp();
|
||||
if (!pinIfacep) continue;
|
||||
|
||||
// If we have a port variable, match against it
|
||||
if (entry.ifacePortVarp) {
|
||||
// Get the IfaceRefDType from the captured port variable
|
||||
AstNodeDType* const portDTypep = entry.ifacePortVarp->subDTypep();
|
||||
AstIfaceRefDType* entryPortIrefp = VN_CAST(portDTypep, IfaceRefDType);
|
||||
if (!entryPortIrefp && arraySubDTypep(portDTypep)) {
|
||||
entryPortIrefp
|
||||
= VN_CAST(arraySubDTypep(portDTypep), IfaceRefDType);
|
||||
}
|
||||
if (entryPortIrefp != portIrefp) continue; // Not the right port
|
||||
}
|
||||
|
||||
// Search for typedef with same name in the connected interface clone
|
||||
for (AstNode* stmtp = pinIfacep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstTypedef* const tdp = VN_CAST(stmtp, Typedef)) {
|
||||
if (tdp->name() == typedefName) {
|
||||
targetTypedefp = tdp;
|
||||
UINFO(8,
|
||||
" [iface-capture] found '"
|
||||
<< typedefName << "' in " << pinIfacep->name()
|
||||
<< " via port "
|
||||
<< (entry.ifacePortVarp ? entry.ifacePortVarp->name()
|
||||
: "<unknown>")
|
||||
<< endl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetTypedefp) break;
|
||||
}
|
||||
|
||||
// Fallback to clone of original typedef (existing behavior)
|
||||
if (!targetTypedefp) targetTypedefp = origTypedefp->clonep();
|
||||
|
||||
if (targetTypedefp) {
|
||||
UINFO(8, " [iface-capture] replaceTypedef "
|
||||
<< origTypedefp->name() << " -> " << targetTypedefp << endl);
|
||||
V3LinkDotIfaceCapture::replaceTypedef(entry.refp, targetTypedefp);
|
||||
}
|
||||
// Propagate to cloned RefDType in new module
|
||||
if (AstRefDType* const clonedRefp = entry.refp->clonep()) {
|
||||
V3LinkDotIfaceCapture::propagateClone(entry.refp, clonedRefp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
newModp->name(newname);
|
||||
newModp->user2(false); // We need to re-recurse this module once changed
|
||||
newModp->recursive(false);
|
||||
|
|
@ -973,7 +1044,7 @@ class ParamProcessor final {
|
|||
// Only consider formal class type parameters (generic parameters),
|
||||
// not localparam type declarations inside the class body.
|
||||
if (!paramTypep->isGParam()) continue;
|
||||
m_paramIndex.emplace(paramTypep, m_classParams.size());
|
||||
m_paramIndex.emplace(paramTypep, static_cast<int>(m_classParams.size()));
|
||||
m_classParams.emplace_back(paramTypep, -1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1113,6 +1184,13 @@ class ParamProcessor final {
|
|||
UINFO(8, " Done with " << modInfop->m_modp);
|
||||
newModp = modInfop->m_modp;
|
||||
}
|
||||
|
||||
const bool cloned = (newModp != srcModp);
|
||||
UINFO(9, "iface capture module clone src=" << srcModp << " new=" << newModp << " name="
|
||||
<< newModp->name() << " from cell=" << nodep
|
||||
<< " cellName=" << nodep->name()
|
||||
<< " cloned=" << cloned);
|
||||
|
||||
if (defaultsResolved) srcModp->user4p(newModp);
|
||||
|
||||
for (auto* stmtp = newModp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
|
|
|
|||
|
|
@ -3104,11 +3104,15 @@ list_of_param_assignments<varp>: // ==IEEE: list_of_param_assignments
|
|||
;
|
||||
|
||||
type_assignment<varp>: // ==IEEE: type_assignment
|
||||
// // note exptOrDataType being a data_type is only for yPARAMETER yTYPE
|
||||
// // note exprOrDataType being a data_type is only for yPARAMETER yTYPE
|
||||
// // Using exprOrDataType allows hierarchical refs like if0.rq_t
|
||||
// // which get resolved to types during linking
|
||||
idAny/*new-parameter*/ sigAttrListE
|
||||
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2); }
|
||||
| idAny/*new-parameter*/ sigAttrListE '=' data_typeAny
|
||||
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2); $$->valuep($4); }
|
||||
| idAny/*new-parameter*/ sigAttrListE '=' exprOrDataType
|
||||
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
|
||||
// V3LinkParse will wrap this in RequireDType when creating ParamTypeDType
|
||||
$$->valuep($4); }
|
||||
;
|
||||
|
||||
list_of_type_assignments<varp>: // ==IEEE: list_of_type_assignments
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0d exp=%0d\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned IdBits;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface bus_if #(
|
||||
parameter a_pkg::cfg_t cfg = 0
|
||||
)();
|
||||
typedef logic [cfg.IdBits-1:0] id_t;
|
||||
id_t id;
|
||||
endinterface
|
||||
|
||||
module a_mod #()(
|
||||
bus_if bus_tgt_io
|
||||
,bus_if bus_mst_io
|
||||
);
|
||||
|
||||
localparam type tgt_id_t = bus_tgt_io.id_t;
|
||||
localparam type mst_id_t = bus_mst_io.id_t;
|
||||
|
||||
tgt_id_t tgt_id;
|
||||
mst_id_t mst_id;
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
`checkd($bits(tgt_id), 5);
|
||||
`checkd($bits(mst_id), 10);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input logic clk
|
||||
);
|
||||
localparam a_pkg::cfg_t cfg0 = '{IdBits: 5};
|
||||
localparam a_pkg::cfg_t cfg1 = '{IdBits: 10};
|
||||
|
||||
bus_if #(.cfg(cfg0)) bus_io0();
|
||||
bus_if #(.cfg(cfg1)) bus_io1();
|
||||
|
||||
a_mod a_mod0(
|
||||
.bus_tgt_io(bus_io0)
|
||||
,.bus_mst_io(bus_io1)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
#10;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0d exp=%0d\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned IdBits;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface bus_if #(
|
||||
parameter a_pkg::cfg_t cfg = 0
|
||||
)();
|
||||
typedef logic [cfg.IdBits-1:0] id_t;
|
||||
id_t id;
|
||||
endinterface
|
||||
|
||||
module a_mod #()(
|
||||
bus_if bus_tgt_io_a [2]
|
||||
,bus_if bus_mst_io_a [2]
|
||||
);
|
||||
|
||||
localparam type tgt_id_t = bus_tgt_io_a[0].id_t;
|
||||
localparam type mst_id_t = bus_mst_io_a[0].id_t;
|
||||
|
||||
tgt_id_t tgt_id;
|
||||
mst_id_t mst_id;
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
`checkd($bits(tgt_id), 5);
|
||||
`checkd($bits(mst_id), 10);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input logic clk
|
||||
);
|
||||
localparam a_pkg::cfg_t cfg0 = '{IdBits: 5};
|
||||
localparam a_pkg::cfg_t cfg1 = '{IdBits: 10};
|
||||
|
||||
bus_if #(.cfg(cfg0)) bus_tgt_io_a [2] ();
|
||||
bus_if #(.cfg(cfg1)) bus_mst_io_a [2] ();
|
||||
|
||||
a_mod a_mod0(
|
||||
.bus_tgt_io_a(bus_tgt_io_a)
|
||||
,.bus_mst_io_a(bus_mst_io_a)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
#10;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign localparam from interface typedef, single level nesting
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq_t = if0.rq_t;
|
||||
localparam p0_rs_t = if0.rs_t;
|
||||
|
||||
p0_rq_t rq;
|
||||
p0_rs_t rs;
|
||||
|
||||
always_comb begin
|
||||
rq.addr = 'h1234;
|
||||
rq.data = 'h37;
|
||||
rs.data = 'h5a;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(rq.addr, 16'h1234);
|
||||
`checkh(rq.data, 8'h37);
|
||||
`checkh(rs.data, 8'h5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
|
||||
interface x_if #(
|
||||
parameter int a_width = 3
|
||||
)();
|
||||
|
||||
typedef struct packed {
|
||||
logic [a_width-1:0] addr;
|
||||
} rq_t;
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.a_width(8)
|
||||
) if0();
|
||||
|
||||
localparam type p0_t = if0.rq_t;
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign localparam from interface typedef, single level nesting
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0d exp=%0d\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
localparam int Bits = p_awidth + p_dwidth;
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rq_t;
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0 [2]();
|
||||
|
||||
localparam type p0_rq_t = if0[0].rq_t;
|
||||
|
||||
p0_rq_t rq;
|
||||
|
||||
always_comb begin
|
||||
rq.addr = 'h1234;
|
||||
rq.data = 'h37;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkd(if0[0].Bits,24);
|
||||
`checkd($bits(rq),24);
|
||||
`checkh(rq.addr,16'h1234);
|
||||
`checkh(rq.data,8'h37);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign localparam from nested interface typedef
|
||||
//
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign localparam from nested interface typedef
|
||||
// instance of type, assign to instance and check
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
|
||||
assign p0_rq2.addr = 16'hcafe;
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam p0_rq_t = if0.rq_t;
|
||||
localparam p0_rs_t = if0.rs_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rq.data = 8'ha5;
|
||||
p0_rs.data = 8'h5a;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rq.data, 8'ha5);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam type p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam type p0_rq_t = if0.rq_t;
|
||||
localparam type p0_rs_t = if0.rs_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rs.data = 8'h5a;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting. param dependency.
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface z_if #(
|
||||
parameter int p_bwidth = 25
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_bwidth-1:0] data;
|
||||
} req_t;
|
||||
|
||||
logic sig_a;
|
||||
logic sig_b;
|
||||
endinterface
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
z_if#(.p_bwidth(p_awidth+p_dwidth)) z_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam p0_rq_t = if0.rq_t;
|
||||
localparam p0_rs_t = if0.rs_t;
|
||||
localparam p0_req_t = if0.z_if0.req_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
p0_req_t p0_req;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rs.data = 8'h5a;
|
||||
p0_req.data = {p0_rq.addr, p0_rs.data};
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
`checkh(p0_req.data, 24'hbeef5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// localparam assignment from interface typedef with module
|
||||
// hierarchy
|
||||
//
|
||||
|
||||
interface bus_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
);
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
endinterface
|
||||
|
||||
module a_mod(
|
||||
bus_if bus_io
|
||||
);
|
||||
localparam bus_rq_t = bus_io.rq_t;
|
||||
endmodule
|
||||
|
||||
module top();
|
||||
bus_if #(.p_awidth(16), .p_dwidth(8)) bus_io();
|
||||
|
||||
a_mod a_mod_inst(
|
||||
.bus_io(bus_io)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// localparam assignment from interface typedef with module
|
||||
// hierarchy alongside localparam assignment from interface
|
||||
// parameter
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface bus_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
);
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
rq_t rq;
|
||||
rs_t rs;
|
||||
endinterface
|
||||
|
||||
module a_mod(
|
||||
bus_if bus_io
|
||||
);
|
||||
localparam bus_rq_t = bus_io.rq_t;
|
||||
localparam bus_rs_t = bus_io.rs_t;
|
||||
localparam p_awidth = bus_io.p_awidth;
|
||||
localparam p_dwidth = bus_io.p_dwidth;
|
||||
|
||||
bus_rq_t rq;
|
||||
bus_rs_t rs;
|
||||
|
||||
assign rs.data = 8'ha5;
|
||||
assign bus_io.rs = rs;
|
||||
endmodule
|
||||
|
||||
module top();
|
||||
bus_if #(.p_awidth(16), .p_dwidth(8)) bus_io();
|
||||
|
||||
a_mod a_mod_inst(
|
||||
.bus_io(bus_io)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(bus_io.rs.data, 8'ha5);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
interface y_if #(
|
||||
parameter int p_awidth = 3
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.p_awidth(p_awidth)) y_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
x_if #(
|
||||
.p_awidth(16)
|
||||
,.p_dwidth(8)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam p0_rq_t = if0.rq_t;
|
||||
localparam p0_rs_t = if0.rs_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rs.data = 8'h5a;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// localparam assignment from interface typedef with module
|
||||
// hierarchy. uses config struct to pass params to module and
|
||||
// ultimately interface
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned awidth;
|
||||
int unsigned dwidth;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface bus_if #(
|
||||
parameter int p_awidth = 4
|
||||
,parameter int p_dwidth = 7
|
||||
);
|
||||
typedef struct packed {
|
||||
logic [p_awidth-1:0] addr;
|
||||
} rq_t;
|
||||
typedef struct packed {
|
||||
logic [p_dwidth-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
rq_t rq;
|
||||
rs_t rs;
|
||||
endinterface
|
||||
|
||||
module a_mod #(parameter a_pkg::cfg_t cfg=0)(
|
||||
bus_if bus_io
|
||||
);
|
||||
localparam bus_rq_t = bus_io.rq_t;
|
||||
localparam bus_rs_t = bus_io.rs_t;
|
||||
|
||||
bus_rq_t rq;
|
||||
bus_rs_t rs;
|
||||
|
||||
assign rq = bus_io.rq;
|
||||
assign bus_io.rs = rs;
|
||||
|
||||
always_comb begin
|
||||
rs.data = 8'ha5;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module top();
|
||||
localparam a_pkg::cfg_t cfg = '{
|
||||
awidth : 16
|
||||
,dwidth : 8
|
||||
};
|
||||
bus_if #(.p_awidth(16), .p_dwidth(8)) bus_io();
|
||||
|
||||
a_mod #(cfg) a_mod_inst(
|
||||
.bus_io(bus_io)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(bus_io.rs.data, 8'ha5);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// Simplified version of config struct to pass params to module
|
||||
// hierarchy. This is a more compact version of the previous
|
||||
// example used to debug alongside the interface typedef examples.
|
||||
//
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned awidth;
|
||||
int unsigned dwidth;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
module a_mod #(parameter a_pkg::cfg_t cfg=0)(
|
||||
input logic a
|
||||
);
|
||||
endmodule
|
||||
|
||||
module top();
|
||||
localparam a_pkg::cfg_t cfg = '{
|
||||
awidth : 16
|
||||
,dwidth : 8
|
||||
};
|
||||
|
||||
a_mod #(cfg) a_mod_inst(
|
||||
.a(1'b0)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// Simplified version of config struct to pass params to module
|
||||
// hierarchy. This is a more compact version of the previous
|
||||
// example used to debug alongside the interface typedef examples.
|
||||
//
|
||||
|
||||
package a_pkg;
|
||||
endpackage
|
||||
|
||||
package cb;
|
||||
typedef struct packed {
|
||||
int unsigned XdatSize; // raw packet data size
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
module a_mod();
|
||||
typedef struct packed {
|
||||
logic hdr_vld;
|
||||
} cmd_meta_t;
|
||||
|
||||
typedef struct packed {
|
||||
cmd_meta_t meta;
|
||||
} cmd_beat_t;
|
||||
|
||||
typedef logic [3:0] cc_index_t;
|
||||
|
||||
localparam cb::cfg_t cb_cfg = '{
|
||||
XdatSize:$bits(cmd_beat_t)
|
||||
};
|
||||
endmodule
|
||||
|
||||
module top();
|
||||
a_mod a_mod_inst();
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
|
||||
package aer;
|
||||
typedef struct packed {
|
||||
int unsigned NumCca;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
package cca;
|
||||
typedef struct packed {
|
||||
int unsigned NumCc;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
package amb;
|
||||
typedef struct packed {
|
||||
logic start;
|
||||
} rule_t;
|
||||
endpackage
|
||||
|
||||
interface tb_if #(parameter cca::cfg_t cfg=0)();
|
||||
typedef logic [$clog2(cfg.NumCc)-1:0] cc_index_t;
|
||||
endinterface
|
||||
|
||||
module modA#(
|
||||
parameter aer::cfg_t cfg=0
|
||||
//
|
||||
,localparam type rule_t = amb::rule_t
|
||||
)();
|
||||
|
||||
localparam cca::cfg_t cca_cfg = '{
|
||||
NumCc : 4
|
||||
};
|
||||
|
||||
tb_if #(cca_cfg) tb_io();
|
||||
localparam type cc_index_t = tb_io.cc_index_t;
|
||||
endmodule
|
||||
|
||||
module tb();
|
||||
|
||||
localparam aer::cfg_t aer_cfg= '{
|
||||
NumCca : 2
|
||||
};
|
||||
|
||||
modA #(aer_cfg) modA();
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
|
||||
package aer;
|
||||
typedef struct packed {
|
||||
int unsigned NumCca;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
package cca;
|
||||
typedef struct packed {
|
||||
int unsigned NumCc;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
package amb;
|
||||
typedef struct packed {
|
||||
logic start;
|
||||
} rule_t;
|
||||
endpackage
|
||||
|
||||
interface tb_if #(parameter cca::cfg_t cfg=0)();
|
||||
typedef logic [$clog2(cfg.NumCc)-1:0] cc_index_t;
|
||||
endinterface
|
||||
|
||||
module modA#(
|
||||
localparam type rule_t = amb::rule_t
|
||||
)();
|
||||
|
||||
localparam cca::cfg_t cca_cfg = '{
|
||||
NumCc : 4
|
||||
};
|
||||
|
||||
tb_if #(cca_cfg) tb_io();
|
||||
localparam type cc_index_t = tb_io.cc_index_t;
|
||||
endmodule
|
||||
|
||||
module tb();
|
||||
|
||||
localparam aer::cfg_t aer_cfg= '{
|
||||
NumCca : 2
|
||||
};
|
||||
|
||||
modA #() modA();
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting. param dependency. uses config struct
|
||||
// to pass params to module hierarchy and ultimately interface
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0d exp=%0d\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned a_cfg;
|
||||
int unsigned b_cfg;
|
||||
int unsigned d_cfg;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface z_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.d_cfg + CFG.a_cfg - 1:0] data;
|
||||
} req_t;
|
||||
|
||||
logic sig_a;
|
||||
logic sig_b;
|
||||
endinterface
|
||||
|
||||
interface y_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.a_cfg-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.a_cfg-1:0] addr;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [CFG.d_cfg-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.CFG(CFG)) y_if0();
|
||||
z_if#(.CFG(CFG)) z_if0();
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
localparam a_pkg::cfg_t CFG = '{a_cfg: 16, b_cfg: 8, d_cfg: 8};
|
||||
|
||||
x_if #(
|
||||
.CFG(CFG)
|
||||
) if0();
|
||||
|
||||
localparam p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam p0_rq_t = if0.rq_t;
|
||||
localparam p0_rs_t = if0.rs_t;
|
||||
localparam p0_req_t = if0.z_if0.req_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
p0_req_t p0_req;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rs.data = 8'h5a;
|
||||
p0_req.data = {p0_rq.addr, p0_rs.data};
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkd($bits(p0_rq2), 16);
|
||||
`checkd($bits(p0_rq), 16);
|
||||
`checkd($bits(p0_rs), 8);
|
||||
`checkd($bits(p0_req), 24);
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
`checkh(p0_req.data, 24'hbeef5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
// assign multiple localparams from interface typedef
|
||||
// including nesting. param dependency. uses config struct
|
||||
// to pass params to module hierarchy and ultimately interface
|
||||
//
|
||||
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0h exp=%0h\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned a_cfg;
|
||||
int unsigned b_cfg;
|
||||
int unsigned d_cfg;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface z_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.d_cfg + CFG.a_cfg - 1:0] data;
|
||||
} req_t;
|
||||
|
||||
logic sig_a;
|
||||
logic sig_b;
|
||||
endinterface
|
||||
|
||||
interface y_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.a_cfg-1:0] addr;
|
||||
} rq2_t;
|
||||
endinterface
|
||||
|
||||
interface x_if #(
|
||||
parameter a_pkg::cfg_t CFG = 0
|
||||
)();
|
||||
typedef struct packed {
|
||||
logic [CFG.a_cfg-1:0] addr;
|
||||
} rq_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [CFG.d_cfg-1:0] data;
|
||||
} rs_t;
|
||||
|
||||
y_if#(.CFG(CFG)) y_if0();
|
||||
z_if#(.CFG(CFG)) z_if0();
|
||||
|
||||
endinterface
|
||||
|
||||
module top();
|
||||
localparam a_pkg::cfg_t CFG = '{a_cfg: 16, b_cfg: 8, d_cfg: 8};
|
||||
|
||||
x_if #(
|
||||
.CFG(CFG)
|
||||
) if0();
|
||||
|
||||
localparam type p0_rq2_t = if0.y_if0.rq2_t;
|
||||
localparam type p0_rq_t = if0.rq_t;
|
||||
localparam type p0_rs_t = if0.rs_t;
|
||||
localparam type p0_req_t = if0.z_if0.req_t;
|
||||
|
||||
p0_rq2_t p0_rq2;
|
||||
p0_rq_t p0_rq;
|
||||
p0_rs_t p0_rs;
|
||||
p0_req_t p0_req;
|
||||
|
||||
always_comb begin
|
||||
p0_rq2.addr = 16'hcafe;
|
||||
p0_rq.addr = 16'hbeef;
|
||||
p0_rs.data = 8'h5a;
|
||||
p0_req.data = {p0_rq.addr, p0_rs.data};
|
||||
end
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkh(p0_rq2.addr, 16'hcafe);
|
||||
`checkh(p0_rq.addr, 16'hbeef);
|
||||
`checkh(p0_rs.data, 8'h5a);
|
||||
`checkh(p0_req.data, 24'hbeef5a);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
//
|
||||
//
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) \
|
||||
do if ((gotv) !== (expv)) begin \
|
||||
$write("%%Error: %s:%0d: got=%0d exp=%0d\n", \
|
||||
`__FILE__,`__LINE__, (gotv), (expv)); \
|
||||
`stop; \
|
||||
end while(0);
|
||||
|
||||
package a_pkg;
|
||||
typedef struct packed {
|
||||
int unsigned IdBits;
|
||||
} cfg_t;
|
||||
endpackage
|
||||
|
||||
interface bus_if #(
|
||||
parameter a_pkg::cfg_t cfg = 0
|
||||
)();
|
||||
|
||||
typedef logic [cfg.IdBits-1:0] id_t;
|
||||
endinterface
|
||||
|
||||
module a_mod #(
|
||||
parameter int p_expect = 0
|
||||
)(
|
||||
bus_if bus_io
|
||||
);
|
||||
|
||||
localparam type cfg_id_t = bus_io.id_t;
|
||||
|
||||
cfg_id_t cfg_id;
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
`checkd($bits(cfg_id), p_expect);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input logic clk
|
||||
);
|
||||
localparam a_pkg::cfg_t cfg0 = '{IdBits: 5};
|
||||
localparam a_pkg::cfg_t cfg1 = '{IdBits: 10};
|
||||
|
||||
bus_if #(.cfg(cfg0)) bus_if0();
|
||||
bus_if #(.cfg(cfg1)) bus_if1();
|
||||
|
||||
a_mod #(5) a_mod0(
|
||||
.bus_io(bus_if0)
|
||||
);
|
||||
|
||||
a_mod #(10) a_mod1(
|
||||
.bus_io(bus_if1)
|
||||
);
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
#10;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
%Error: t/t_param_type_bad.v:9:27: syntax error, unexpected INTEGER NUMBER
|
||||
%Error: t/t_param_type_bad.v:9:27: Expecting a data type, not a constant: 2
|
||||
9 | localparam type bad2 = 2;
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%Error: t/t_param_type_bad3.v:9:26: Expecting a data type: 'PI'
|
||||
%Error: t/t_param_type_bad3.v:9:26: Expecting a data type, not VARREF: 'PI'
|
||||
9 | localparam type P_T = PI;
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%Error: t/t_param_type_id_bad.v:9:34: Expecting a data type: 'i'
|
||||
%Error: t/t_param_type_id_bad.v:9:34: Expecting a data type, not VARREF: 'i'
|
||||
9 | class Cls #(parameter type P_T = i);
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
%Error: t/t_typedef_id_bad.v:9:34: Expecting a data type: 'i'
|
||||
%Error: t/t_typedef_id_bad.v:9:34: Expecting a data type, not VARREF: 'i'
|
||||
9 | class Cls #(parameter type P_T = i);
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
|
|
|
|||
Loading…
Reference in New Issue