Fix internal error - virtual interface not found (#7010)
This commit is contained in:
parent
9a8538fafa
commit
dc26dd601d
|
|
@ -171,7 +171,7 @@ public:
|
||||||
entr.init(false);
|
entr.init(false);
|
||||||
} else {
|
} else {
|
||||||
if (AstConst* const constp = entr.constNodep()) {
|
if (AstConst* const constp = entr.constNodep()) {
|
||||||
if (!varrefp->varp()->isSigPublic() && !varrefp->varp()->sensIfacep()) {
|
if (!varrefp->varp()->isSigPublic() && !varrefp->varp()->isVirtIface()) {
|
||||||
// Aha, variable is constant; substitute in.
|
// Aha, variable is constant; substitute in.
|
||||||
// We'll later constant propagate
|
// We'll later constant propagate
|
||||||
UINFO(4, " replaceconst: " << varrefp);
|
UINFO(4, " replaceconst: " << varrefp);
|
||||||
|
|
|
||||||
|
|
@ -86,18 +86,32 @@ void invertAndMergeSenTreeMap(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AstSenTree*>
|
std::vector<AstSenTree*>
|
||||||
findTriggeredIface(const AstVarScope* vscp, const VirtIfaceTriggers::IfaceSensMap& vifTrigged,
|
findTriggeredIface(const AstVarScope* vscp,
|
||||||
const VirtIfaceTriggers::IfaceMemberSensMap& vifMemberTriggered) {
|
const VirtIfaceTriggers::IfaceMemberSensMap& vifMemberTriggered) {
|
||||||
UASSERT_OBJ(vscp->varp()->sensIfacep(), vscp, "Not an virtual interface trigger");
|
const AstIface* ifacep;
|
||||||
std::vector<AstSenTree*> result;
|
if (vscp->varp()->isVirtIface()) {
|
||||||
const auto ifaceIt = vifTrigged.find(vscp->varp()->sensIfacep());
|
// If `vscp->varp()->isVirtIface()` is true then the interface type that viface is pointing
|
||||||
if (ifaceIt != vifTrigged.end()) result.push_back(ifaceIt->second);
|
// to is under `VN_AS(vscp->varp()->dtypep(), IfaceRefDType)->ifacep()`
|
||||||
for (const auto& memberIt : vifMemberTriggered) {
|
|
||||||
if (vscp->varp()->sensIfacep() == memberIt.first.m_ifacep) {
|
ifacep = VN_AS(vscp->varp()->dtypep(), IfaceRefDType)->ifacep();
|
||||||
result.push_back(memberIt.second);
|
|
||||||
}
|
// Virtual interface is sensitive to a different interface type than it is a virtual type
|
||||||
|
// of - this may be a valid behaviour but this function does not expects that
|
||||||
|
UASSERT_OBJ(vscp->varp()->sensIfacep() == nullptr, vscp,
|
||||||
|
"Virtual interface has an ambiguous type - "
|
||||||
|
<< vscp->varp()->sensIfacep()->prettyTypeName()
|
||||||
|
<< " != " << ifacep->prettyTypeName());
|
||||||
|
} else {
|
||||||
|
// If `vscp->varp()` is of a non-virtual interface type it has `sensIfacep()` set to
|
||||||
|
// interface it is sensitive to
|
||||||
|
ifacep = vscp->varp()->sensIfacep();
|
||||||
}
|
}
|
||||||
if (result.empty()) vscp->v3fatalSrc("Did not find virtual interface trigger");
|
UASSERT_OBJ(ifacep, vscp, "Variable is not sensitive for any interface");
|
||||||
|
std::vector<AstSenTree*> result;
|
||||||
|
for (const auto& memberIt : vifMemberTriggered) {
|
||||||
|
if (memberIt.first.m_ifacep == ifacep) result.push_back(memberIt.second);
|
||||||
|
}
|
||||||
|
UASSERT_OBJ(!result.empty(), vscp, "Did not find virtual interface trigger");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,10 +395,6 @@ void createFinal(AstNetlist* netlistp, const LogicClasses& logicClasses) {
|
||||||
void addVirtIfaceTriggerAssignments(const VirtIfaceTriggers& virtIfaceTriggers,
|
void addVirtIfaceTriggerAssignments(const VirtIfaceTriggers& virtIfaceTriggers,
|
||||||
uint32_t vifTriggerIndex, uint32_t vifMemberTriggerIndex,
|
uint32_t vifTriggerIndex, uint32_t vifMemberTriggerIndex,
|
||||||
const TriggerKit& trigKit) {
|
const TriggerKit& trigKit) {
|
||||||
for (const auto& p : virtIfaceTriggers.m_ifaceTriggers) {
|
|
||||||
trigKit.addExtraTriggerAssignment(p.second, vifTriggerIndex);
|
|
||||||
++vifTriggerIndex;
|
|
||||||
}
|
|
||||||
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
||||||
trigKit.addExtraTriggerAssignment(p.second, vifMemberTriggerIndex);
|
trigKit.addExtraTriggerAssignment(p.second, vifMemberTriggerIndex);
|
||||||
++vifMemberTriggerIndex;
|
++vifMemberTriggerIndex;
|
||||||
|
|
@ -479,9 +489,6 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
||||||
? extraTriggers.allocate("DPI export trigger")
|
? extraTriggers.allocate("DPI export trigger")
|
||||||
: std::numeric_limits<uint32_t>::max();
|
: std::numeric_limits<uint32_t>::max();
|
||||||
const size_t firstVifTriggerIndex = extraTriggers.size();
|
const size_t firstVifTriggerIndex = extraTriggers.size();
|
||||||
for (const auto& p : virtIfaceTriggers.m_ifaceTriggers) {
|
|
||||||
extraTriggers.allocate("virtual interface: " + p.first->name());
|
|
||||||
}
|
|
||||||
const size_t firstVifMemberTriggerIndex = extraTriggers.size();
|
const size_t firstVifMemberTriggerIndex = extraTriggers.size();
|
||||||
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
||||||
const auto& item = p.first;
|
const auto& item = p.first;
|
||||||
|
|
@ -516,8 +523,6 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
||||||
= dpiExportTriggerVscp
|
= dpiExportTriggerVscp
|
||||||
? trigKit.newExtraTriggerSenTree(trigKit.vscp(), dpiExportTriggerIndex)
|
? trigKit.newExtraTriggerSenTree(trigKit.vscp(), dpiExportTriggerIndex)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto& vifTriggeredIco
|
|
||||||
= virtIfaceTriggers.makeIfaceToSensMap(trigKit, firstVifTriggerIndex, trigKit.vscp());
|
|
||||||
const auto& vifMemberTriggeredIco = virtIfaceTriggers.makeMemberToSensMap(
|
const auto& vifMemberTriggeredIco = virtIfaceTriggers.makeMemberToSensMap(
|
||||||
trigKit, firstVifMemberTriggerIndex, trigKit.vscp());
|
trigKit, firstVifMemberTriggerIndex, trigKit.vscp());
|
||||||
|
|
||||||
|
|
@ -530,9 +535,9 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
||||||
out.push_back(inputChanged);
|
out.push_back(inputChanged);
|
||||||
}
|
}
|
||||||
if (varp->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
if (varp->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
||||||
if (vscp->varp()->sensIfacep()) {
|
if (vscp->varp()->isVirtIface()) {
|
||||||
std::vector<AstSenTree*> ifaceTriggered
|
std::vector<AstSenTree*> ifaceTriggered
|
||||||
= findTriggeredIface(vscp, vifTriggeredIco, vifMemberTriggeredIco);
|
= findTriggeredIface(vscp, vifMemberTriggeredIco);
|
||||||
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -721,17 +726,6 @@ void createEval(AstNetlist* netlistp, //
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// Helper that builds virtual interface trigger sentrees
|
// Helper that builds virtual interface trigger sentrees
|
||||||
|
|
||||||
VirtIfaceTriggers::IfaceSensMap
|
|
||||||
VirtIfaceTriggers::makeIfaceToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
|
||||||
AstVarScope* trigVscp) const {
|
|
||||||
std::map<const AstIface*, AstSenTree*> map;
|
|
||||||
for (const auto& p : m_ifaceTriggers) {
|
|
||||||
map.emplace(p.first, trigKit.newExtraTriggerSenTree(trigVscp, vifTriggerIndex));
|
|
||||||
++vifTriggerIndex;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtIfaceTriggers::IfaceMemberSensMap
|
VirtIfaceTriggers::IfaceMemberSensMap
|
||||||
VirtIfaceTriggers::makeMemberToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
VirtIfaceTriggers::makeMemberToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
||||||
AstVarScope* trigVscp) const {
|
AstVarScope* trigVscp) const {
|
||||||
|
|
@ -860,9 +854,6 @@ void schedule(AstNetlist* netlistp) {
|
||||||
? extraTriggers.allocate("DPI export trigger")
|
? extraTriggers.allocate("DPI export trigger")
|
||||||
: std::numeric_limits<uint32_t>::max();
|
: std::numeric_limits<uint32_t>::max();
|
||||||
const uint32_t firstVifTriggerIndex = extraTriggers.size();
|
const uint32_t firstVifTriggerIndex = extraTriggers.size();
|
||||||
for (const auto& p : virtIfaceTriggers.m_ifaceTriggers) {
|
|
||||||
extraTriggers.allocate("virtual interface: " + p.first->name());
|
|
||||||
}
|
|
||||||
const uint32_t firstVifMemberTriggerIndex = extraTriggers.size();
|
const uint32_t firstVifMemberTriggerIndex = extraTriggers.size();
|
||||||
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
for (const auto& p : virtIfaceTriggers.m_memberTriggers) {
|
||||||
const auto& item = p.first;
|
const auto& item = p.first;
|
||||||
|
|
@ -915,8 +906,6 @@ void schedule(AstNetlist* netlistp) {
|
||||||
? trigKit.newExtraTriggerSenTree(trigKit.vscp(), dpiExportTriggerIndex)
|
? trigKit.newExtraTriggerSenTree(trigKit.vscp(), dpiExportTriggerIndex)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
|
||||||
const auto& vifTriggeredAct
|
|
||||||
= virtIfaceTriggers.makeIfaceToSensMap(trigKit, firstVifTriggerIndex, trigKit.vscp());
|
|
||||||
const auto& vifMemberTriggeredAct = virtIfaceTriggers.makeMemberToSensMap(
|
const auto& vifMemberTriggeredAct = virtIfaceTriggers.makeMemberToSensMap(
|
||||||
trigKit, firstVifMemberTriggerIndex, trigKit.vscp());
|
trigKit, firstVifMemberTriggerIndex, trigKit.vscp());
|
||||||
|
|
||||||
|
|
@ -926,9 +915,9 @@ void schedule(AstNetlist* netlistp) {
|
||||||
auto it = actTimingDomains.find(vscp);
|
auto it = actTimingDomains.find(vscp);
|
||||||
if (it != actTimingDomains.end()) out = it->second;
|
if (it != actTimingDomains.end()) out = it->second;
|
||||||
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredAct);
|
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredAct);
|
||||||
if (vscp->varp()->sensIfacep()) {
|
if (vscp->varp()->isVirtIface()) {
|
||||||
std::vector<AstSenTree*> ifaceTriggered
|
std::vector<AstSenTree*> ifaceTriggered
|
||||||
= findTriggeredIface(vscp, vifTriggeredAct, vifMemberTriggeredAct);
|
= findTriggeredIface(vscp, vifMemberTriggeredAct);
|
||||||
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -954,8 +943,6 @@ void schedule(AstNetlist* netlistp) {
|
||||||
= dpiExportTriggerVscp
|
= dpiExportTriggerVscp
|
||||||
? trigKit.newExtraTriggerSenTree(trigVscp, dpiExportTriggerIndex)
|
? trigKit.newExtraTriggerSenTree(trigVscp, dpiExportTriggerIndex)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto& vifTriggered
|
|
||||||
= virtIfaceTriggers.makeIfaceToSensMap(trigKit, firstVifTriggerIndex, trigVscp);
|
|
||||||
const auto& vifMemberTriggered
|
const auto& vifMemberTriggered
|
||||||
= virtIfaceTriggers.makeMemberToSensMap(trigKit, firstVifMemberTriggerIndex, trigVscp);
|
= virtIfaceTriggers.makeMemberToSensMap(trigKit, firstVifMemberTriggerIndex, trigVscp);
|
||||||
|
|
||||||
|
|
@ -966,9 +953,11 @@ void schedule(AstNetlist* netlistp) {
|
||||||
auto it = timingDomains.find(vscp);
|
auto it = timingDomains.find(vscp);
|
||||||
if (it != timingDomains.end()) out = it->second;
|
if (it != timingDomains.end()) out = it->second;
|
||||||
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
||||||
if (vscp->varp()->sensIfacep()) {
|
// Sometimes virtual interfaces mix with non-virtual one so, here both have to be
|
||||||
|
// detected - look `t_virtual_interface_nba_assign`
|
||||||
|
if (vscp->varp()->sensIfacep() || vscp->varp()->isVirtIface()) {
|
||||||
std::vector<AstSenTree*> ifaceTriggered
|
std::vector<AstSenTree*> ifaceTriggered
|
||||||
= findTriggeredIface(vscp, vifTriggered, vifMemberTriggered);
|
= findTriggeredIface(vscp, vifMemberTriggered);
|
||||||
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
out.insert(out.end(), ifaceTriggered.begin(), ifaceTriggered.end());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -338,15 +338,10 @@ class VirtIfaceTriggers final {
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using IfaceSensMap = std::map<const AstIface*, AstSenTree*>;
|
|
||||||
using IfaceMemberSensMap = std::map<IfaceMember, AstSenTree*>;
|
using IfaceMemberSensMap = std::map<IfaceMember, AstSenTree*>;
|
||||||
|
|
||||||
std::vector<std::pair<const AstIface*, AstVarScope*>> m_ifaceTriggers;
|
|
||||||
std::vector<std::pair<IfaceMember, AstVarScope*>> m_memberTriggers;
|
std::vector<std::pair<IfaceMember, AstVarScope*>> m_memberTriggers;
|
||||||
|
|
||||||
void addIfaceTrigger(const AstIface* ifacep, AstVarScope* vscp) {
|
|
||||||
m_ifaceTriggers.emplace_back(ifacep, vscp);
|
|
||||||
}
|
|
||||||
void addMemberTrigger(const AstIface* ifacep, const AstVar* memberp, AstVarScope* vscp) {
|
void addMemberTrigger(const AstIface* ifacep, const AstVar* memberp, AstVarScope* vscp) {
|
||||||
m_memberTriggers.emplace_back(IfaceMember{ifacep, memberp}, vscp);
|
m_memberTriggers.emplace_back(IfaceMember{ifacep, memberp}, vscp);
|
||||||
}
|
}
|
||||||
|
|
@ -362,9 +357,6 @@ public:
|
||||||
IfaceMemberSensMap makeMemberToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
IfaceMemberSensMap makeMemberToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
||||||
AstVarScope* trigVscp) const;
|
AstVarScope* trigVscp) const;
|
||||||
|
|
||||||
IfaceSensMap makeIfaceToSensMap(const TriggerKit& trigKit, uint32_t vifTriggerIndex,
|
|
||||||
AstVarScope* trigVscp) const;
|
|
||||||
|
|
||||||
VL_UNCOPYABLE(VirtIfaceTriggers);
|
VL_UNCOPYABLE(VirtIfaceTriggers);
|
||||||
VirtIfaceTriggers() = default;
|
VirtIfaceTriggers() = default;
|
||||||
VirtIfaceTriggers(VirtIfaceTriggers&&) = default;
|
VirtIfaceTriggers(VirtIfaceTriggers&&) = default;
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ public:
|
||||||
, m_vscp{vscp} {
|
, m_vscp{vscp} {
|
||||||
// Top level inputs are
|
// Top level inputs are
|
||||||
if (varp()->isPrimaryInish() || varp()->isSigUserRWPublic() || varp()->isWrittenByDpi()
|
if (varp()->isPrimaryInish() || varp()->isSigUserRWPublic() || varp()->isWrittenByDpi()
|
||||||
|| varp()->sensIfacep()) {
|
|| varp()->sensIfacep() || varp()->isVirtIface()) {
|
||||||
addDrivingRegions(INPUT);
|
addDrivingRegions(INPUT);
|
||||||
}
|
}
|
||||||
// Currently we always execute suspendable processes at the beginning of
|
// Currently we always execute suspendable processes at the beginning of
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class VirtIfaceVisitor final : public VNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstVarRef::user1() -> bool. Whether it has been visited
|
// AstVarRef::user1() -> bool. Whether it has been visited
|
||||||
|
// AstMemberSel::user1() -> bool. Whether it has been visited
|
||||||
const VNUser1InUse m_user1InUse;
|
const VNUser1InUse m_user1InUse;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
|
|
@ -64,7 +65,7 @@ private:
|
||||||
AstIfaceRefDType* const dtypep = VN_CAST(refp->varp()->dtypep(), IfaceRefDType);
|
AstIfaceRefDType* const dtypep = VN_CAST(refp->varp()->dtypep(), IfaceRefDType);
|
||||||
const bool writesToVirtIfaceMember
|
const bool writesToVirtIfaceMember
|
||||||
= (dtypep && dtypep->isVirtual() && VN_IS(refp->firstAbovep(), MemberSel));
|
= (dtypep && dtypep->isVirtual() && VN_IS(refp->firstAbovep(), MemberSel));
|
||||||
const bool writesToIfaceSensVar = refp->varp()->sensIfacep();
|
const bool writesToIfaceSensVar = refp->varp()->isVirtIface();
|
||||||
return writesToVirtIfaceMember || writesToIfaceSensVar;
|
return writesToVirtIfaceMember || writesToIfaceSensVar;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -86,27 +87,21 @@ private:
|
||||||
return new AstVarRef{flp, existingTrigger, VAccess::WRITE};
|
return new AstVarRef{flp, existingTrigger, VAccess::WRITE};
|
||||||
}
|
}
|
||||||
|
|
||||||
// VISITORS
|
template <typename T>
|
||||||
void visit(AstNodeProcedure* nodep) override {
|
void handleIface(T nodep) {
|
||||||
// Not sure if needed, but be paranoid to match previous behavior as didn't optimize
|
static_assert(std::is_same<typename std::remove_cv<T>::type,
|
||||||
// before ..
|
typename std::add_pointer<AstVarRef>::type>::value
|
||||||
if (VN_IS(nodep, AlwaysPost) && writesToVirtIface(nodep)) {
|
|| std::is_same<typename std::remove_cv<T>::type,
|
||||||
nodep->foreach([](AstVarRef* refp) { refp->varScopep()->optimizeLifePost(false); });
|
typename std::add_pointer<AstMemberSel>::type>::value,
|
||||||
}
|
"Node has to be of AstVarRef* or AstMemberSel* type");
|
||||||
iterateChildren(nodep);
|
|
||||||
}
|
|
||||||
void visit(AstVarRef* const nodep) override {
|
|
||||||
if (nodep->access().isReadOnly()) return;
|
if (nodep->access().isReadOnly()) return;
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
AstIface* ifacep = nullptr;
|
AstIface* ifacep = nullptr;
|
||||||
AstVar* memberVarp = nullptr;
|
AstVar* memberVarp = nullptr;
|
||||||
if (AstIfaceRefDType* const dtypep = VN_CAST(nodep->varp()->dtypep(), IfaceRefDType)) {
|
if (nodep->varp()->isVirtIface()) {
|
||||||
if (dtypep->isVirtual()) {
|
if (AstMemberSel* const memberSelp = VN_CAST(nodep->firstAbovep(), MemberSel)) {
|
||||||
if (AstMemberSel* const memberSelp = VN_CAST(nodep->firstAbovep(), MemberSel)) {
|
ifacep = VN_AS(nodep->varp()->dtypep(), IfaceRefDType)->ifacep();
|
||||||
// Extract the member varp from the MemberSel node
|
memberVarp = memberSelp->varp();
|
||||||
memberVarp = memberSelp->varp();
|
|
||||||
ifacep = dtypep->ifacep();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if ((ifacep = nodep->varp()->sensIfacep())) {
|
} else if ((ifacep = nodep->varp()->sensIfacep())) {
|
||||||
memberVarp = nodep->varp();
|
memberVarp = nodep->varp();
|
||||||
|
|
@ -123,6 +118,18 @@ private:
|
||||||
nodep});
|
nodep});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
void visit(AstNodeProcedure* nodep) override {
|
||||||
|
// Not sure if needed, but be paranoid to match previous behavior as didn't optimize
|
||||||
|
// before ..
|
||||||
|
if (VN_IS(nodep, AlwaysPost) && writesToVirtIface(nodep)) {
|
||||||
|
nodep->foreach([](AstVarRef* refp) { refp->varScopep()->optimizeLifePost(false); });
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstMemberSel* const nodep) override { handleIface(nodep); }
|
||||||
|
void visit(AstVarRef* const nodep) override { handleIface(nodep); }
|
||||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
%Error-UNSUPPORTED: t/t_interface_virtual_unsup.v:24:22: Unsupported: Write to virtual interface in if condition
|
|
||||||
24 | if (write_data(vif.data)) $write("dummy op");
|
|
||||||
| ^~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error-UNSUPPORTED: t/t_interface_virtual_unsup.v:25:25: Unsupported: Write to virtual interface in loop condition
|
|
||||||
25 | while (write_data(vif.data));
|
|
||||||
| ^~~
|
|
||||||
%Error-UNSUPPORTED: t/t_interface_virtual_unsup.v:26:30: Unsupported: Write to virtual interface in loop condition
|
|
||||||
26 | do ; while (write_data(vif.data));
|
|
||||||
| ^~~
|
|
||||||
%Error: Exiting due to
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
// DESCRIPTION: Verilator: Verilog Test module
|
|
||||||
//
|
|
||||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
|
||||||
// SPDX-FileCopyrightText: 2023 Wilson Snyder
|
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
// NOTE: Once this is supported, t_interface_virtual_cond is no longer needed
|
|
||||||
|
|
||||||
interface Bus;
|
|
||||||
logic [15:0] data;
|
|
||||||
endinterface
|
|
||||||
|
|
||||||
module t;
|
|
||||||
Bus intf();
|
|
||||||
virtual Bus vif = intf;
|
|
||||||
|
|
||||||
function logic write_data(output logic[15:0] data);
|
|
||||||
data = 'hdead;
|
|
||||||
return 1;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
// verilator lint_off INFINITELOOP
|
|
||||||
initial begin
|
|
||||||
if (write_data(vif.data)) $write("dummy op");
|
|
||||||
while (write_data(vif.data));
|
|
||||||
do ; while (write_data(vif.data));
|
|
||||||
for (int i = 0; write_data(vif.data++); i++);
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2026 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, 2026 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
interface sys_if;
|
||||||
|
logic clk;
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
interface axi_if;
|
||||||
|
wire clk;
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class sys_config;
|
||||||
|
virtual sys_if sys_vi;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class axi_agent_config;
|
||||||
|
virtual axi_if axi_vi;
|
||||||
|
sys_config cfg;
|
||||||
|
task start_clk();
|
||||||
|
fork
|
||||||
|
forever begin
|
||||||
|
cfg.sys_vi.clk = 1'b1;
|
||||||
|
#1;
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
@(posedge axi_vi.clk);
|
||||||
|
endtask
|
||||||
|
task test();
|
||||||
|
cfg.sys_vi.clk = 0;
|
||||||
|
#1;
|
||||||
|
start_clk();
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module axi_tb_top;
|
||||||
|
sys_if sys_vi();
|
||||||
|
axi_if axi_vi();
|
||||||
|
assign axi_vi.clk = sys_vi.clk;
|
||||||
|
sys_config a;
|
||||||
|
axi_agent_config b;
|
||||||
|
initial begin
|
||||||
|
a = new;
|
||||||
|
b = new;
|
||||||
|
a.sys_vi = sys_vi;
|
||||||
|
b.axi_vi = axi_vi;
|
||||||
|
b.cfg = a;
|
||||||
|
b.test();
|
||||||
|
#3 $stop;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue