Fix fork scheduling semantics (#6730)
Signed-off-by: Artur Bieniek <abieniek@internships.antmicro.com>
This commit is contained in:
parent
f4654a451b
commit
2c5ff3f63f
|
|
@ -1418,9 +1418,10 @@ class AstFork final : public AstNodeBlock {
|
||||||
// spawned. This is necessary to implement things like local variable
|
// spawned. This is necessary to implement things like local variable
|
||||||
// initializers properly. The parallel statements inside the fork must all
|
// initializers properly. The parallel statements inside the fork must all
|
||||||
// be AstBegin, as lowering stages will introduce additional statements to
|
// be AstBegin, as lowering stages will introduce additional statements to
|
||||||
// be executed sequentially within eaach fork branch.
|
// be executed sequentially within each fork branch.
|
||||||
//
|
//
|
||||||
// @astgen op3 := forksp : List[AstBegin]
|
// @astgen op3 := forksp : List[AstBegin]
|
||||||
|
// @astgen op4 := parentProcessp : Optional[AstVarRef]
|
||||||
const VJoinType m_joinType; // Join keyword type
|
const VJoinType m_joinType; // Join keyword type
|
||||||
public:
|
public:
|
||||||
AstFork(FileLine* fl, VJoinType joinType, const string& name = "")
|
AstFork(FileLine* fl, VJoinType joinType, const string& name = "")
|
||||||
|
|
|
||||||
|
|
@ -1251,6 +1251,8 @@ public:
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
void visit(AstFinish* nodep) override {
|
void visit(AstFinish* nodep) override {
|
||||||
|
// Disable all the forks so they don't operate after simulation is finished.
|
||||||
|
if (m_cfuncp && m_cfuncp->needProcess()) putns(nodep, "vlProcess->disableFork();\n");
|
||||||
putns(nodep, "VL_FINISH_MT(");
|
putns(nodep, "VL_FINISH_MT(");
|
||||||
putsQuoted(protect(nodep->fileline()->filename()));
|
putsQuoted(protect(nodep->fileline()->filename()));
|
||||||
puts(", ");
|
puts(", ");
|
||||||
|
|
@ -1258,6 +1260,8 @@ public:
|
||||||
puts(", \"\");\n");
|
puts(", \"\");\n");
|
||||||
}
|
}
|
||||||
void visit(AstFinishFork* nodep) override {
|
void visit(AstFinishFork* nodep) override {
|
||||||
|
// Disable all the forks so they don't operate after simulation is finished.
|
||||||
|
if (m_cfuncp && m_cfuncp->needProcess()) putns(nodep, "vlProcess->disableFork();\n");
|
||||||
putns(nodep, "VL_FINISH_MT(");
|
putns(nodep, "VL_FINISH_MT(");
|
||||||
putsQuoted(protect(nodep->fileline()->filename()));
|
putsQuoted(protect(nodep->fileline()->filename()));
|
||||||
puts(", ");
|
puts(", ");
|
||||||
|
|
|
||||||
|
|
@ -524,6 +524,11 @@ class ForkVisitor final : public VNVisitor {
|
||||||
AstVar* m_capturedVarsp = nullptr; // Local copies of captured variables
|
AstVar* m_capturedVarsp = nullptr; // Local copies of captured variables
|
||||||
AstArg* m_capturedArgsp = nullptr; // References to captured variables (as args)
|
AstArg* m_capturedArgsp = nullptr; // References to captured variables (as args)
|
||||||
|
|
||||||
|
// STATE - across all visitors
|
||||||
|
AstClass* m_processClassp = nullptr;
|
||||||
|
AstFunc* m_statusMethodp = nullptr;
|
||||||
|
VMemberMap m_memberMap; // for lookup of process class methods
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
AstVar* capture(AstVarRef* refp) {
|
AstVar* capture(AstVarRef* refp) {
|
||||||
AstVar* varp = nullptr;
|
AstVar* varp = nullptr;
|
||||||
|
|
@ -577,6 +582,19 @@ class ForkVisitor final : public VNVisitor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstClass* getProcessClassp() {
|
||||||
|
if (!m_processClassp)
|
||||||
|
m_processClassp
|
||||||
|
= VN_AS(m_memberMap.findMember(v3Global.rootp()->stdPackagep(), "process"), Class);
|
||||||
|
return m_processClassp;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstFunc* getStatusmethodp() {
|
||||||
|
if (m_statusMethodp == nullptr)
|
||||||
|
m_statusMethodp = VN_AS(m_memberMap.findMember(getProcessClassp(), "status"), Func);
|
||||||
|
return m_statusMethodp;
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
|
|
@ -596,6 +614,34 @@ class ForkVisitor final : public VNVisitor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IEEE 1800-2023 9.3.2: In all cases, processes spawned by a fork-join block shall not
|
||||||
|
// start executing until the parent process is blocked or terminates.
|
||||||
|
// Because join and join_any block the parent process, it is only needed when join_none
|
||||||
|
// is used.
|
||||||
|
if (nodep->joinType().joinNone()) {
|
||||||
|
UINFO(9, "Visiting fork..join_none " << nodep);
|
||||||
|
FileLine* fl = nodep->fileline();
|
||||||
|
AstVarRef* forkParentrefp = nodep->parentProcessp();
|
||||||
|
|
||||||
|
if (forkParentrefp) { // Forks created by V3Fork will not have this
|
||||||
|
for (AstBegin *itemp = nodep->forksp(), *nextp; itemp; itemp = nextp) {
|
||||||
|
nextp = VN_AS(itemp->nextp(), Begin);
|
||||||
|
if (!itemp->stmtsp()) continue;
|
||||||
|
AstMethodCall* const statusCallp = new AstMethodCall{
|
||||||
|
fl, forkParentrefp->cloneTree(false), "status", nullptr};
|
||||||
|
statusCallp->taskp(getStatusmethodp());
|
||||||
|
statusCallp->classOrPackagep(getProcessClassp());
|
||||||
|
statusCallp->dtypep(getStatusmethodp()->dtypep());
|
||||||
|
AstNeq* const condp
|
||||||
|
= new AstNeq{fl, statusCallp,
|
||||||
|
new AstConst{fl, AstConst::WidthedValue{},
|
||||||
|
getStatusmethodp()->dtypep()->width(), 1}};
|
||||||
|
AstWait* const waitStmt = new AstWait{fl, condp, nullptr};
|
||||||
|
itemp->stmtsp()->addHereThisAsNext(waitStmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iterateAndNextNull(nodep->declsp());
|
iterateAndNextNull(nodep->declsp());
|
||||||
iterateAndNextNull(nodep->stmtsp());
|
iterateAndNextNull(nodep->stmtsp());
|
||||||
std::vector<AstBegin*> wrappedp;
|
std::vector<AstBegin*> wrappedp;
|
||||||
|
|
|
||||||
|
|
@ -622,6 +622,29 @@ private:
|
||||||
return findp;
|
return findp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VSymEnt* findForkParentAlias(VSymEnt* symp, const string& ident) {
|
||||||
|
static const string suffix = "__VgetForkParent";
|
||||||
|
VSymEnt* const wrapperp = symp->findIdFlat(ident + suffix);
|
||||||
|
if (!wrapperp) return nullptr;
|
||||||
|
if (!VN_IS(wrapperp->nodep(), Begin)) return nullptr;
|
||||||
|
if (VSymEnt* const forkSymp = wrapperp->findIdFlat(ident)) {
|
||||||
|
if (VN_IS(forkSymp->nodep(), Fork)) return forkSymp;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VSymEnt* unwrapForkParent(VSymEnt* symp, const string& ident) {
|
||||||
|
static const string suffix = "__VgetForkParent";
|
||||||
|
if (AstBegin* const beginp = VN_CAST(symp->nodep(), Begin)) {
|
||||||
|
if (VString::endsWith(beginp->name(), suffix)) {
|
||||||
|
if (VSymEnt* const forkSymp = symp->findIdFlat(ident)) {
|
||||||
|
if (VN_IS(forkSymp->nodep(), Fork)) return forkSymp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return symp;
|
||||||
|
}
|
||||||
|
|
||||||
VSymEnt* findWithAltFlat(VSymEnt* symp, const string& name, const string& altname) {
|
VSymEnt* findWithAltFlat(VSymEnt* symp, const string& name, const string& altname) {
|
||||||
VSymEnt* findp = symp->findIdFlat(name);
|
VSymEnt* findp = symp->findIdFlat(name);
|
||||||
if (findp) return findp;
|
if (findp) return findp;
|
||||||
|
|
@ -672,9 +695,10 @@ public:
|
||||||
const AstCellInline* inlinep = lookupSymp
|
const AstCellInline* inlinep = lookupSymp
|
||||||
? VN_CAST(lookupSymp->nodep(), CellInline)
|
? VN_CAST(lookupSymp->nodep(), CellInline)
|
||||||
: nullptr; // Replicated below
|
: nullptr; // Replicated below
|
||||||
if (VSymEnt* const findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) {
|
VSymEnt* findSymp = findWithAltFallback(lookupSymp, ident, altIdent);
|
||||||
lookupSymp = findSymp;
|
if (!findSymp) findSymp = findForkParentAlias(lookupSymp, ident);
|
||||||
}
|
if (findSymp) lookupSymp = unwrapForkParent(findSymp, ident);
|
||||||
|
|
||||||
// Check this module - cur modname
|
// Check this module - cur modname
|
||||||
else if ((cellp && cellp->modp()->origName() == ident)
|
else if ((cellp && cellp->modp()->origName() == ident)
|
||||||
|| (inlinep && inlinep->origModName() == ident)) {
|
|| (inlinep && inlinep->origModName() == ident)) {
|
||||||
|
|
@ -720,9 +744,11 @@ public:
|
||||||
if (!lookupSymp) return nullptr; // Not found
|
if (!lookupSymp) return nullptr; // Not found
|
||||||
}
|
}
|
||||||
} else { // Searching for middle submodule, must be a cell name
|
} else { // Searching for middle submodule, must be a cell name
|
||||||
if (VSymEnt* const findSymp = findWithAltFlat(lookupSymp, ident, altIdent)) {
|
VSymEnt* findSymp = findWithAltFlat(lookupSymp, ident, altIdent);
|
||||||
lookupSymp = findSymp;
|
if (!findSymp) findSymp = findForkParentAlias(lookupSymp, ident);
|
||||||
} else {
|
if (findSymp)
|
||||||
|
lookupSymp = unwrapForkParent(findSymp, ident);
|
||||||
|
else {
|
||||||
return nullptr; // Not found
|
return nullptr; // Not found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include "V3LinkParse.h"
|
#include "V3LinkParse.h"
|
||||||
|
|
||||||
#include "V3Control.h"
|
#include "V3Control.h"
|
||||||
|
#include "V3MemberMap.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -46,6 +47,7 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
|
|
||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen
|
std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen
|
||||||
|
VMemberMap m_memberMap; // for lookup of process class methods
|
||||||
|
|
||||||
// STATE - for current visit position (use VL_RESTORER)
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
// If set, move AstVar->valuep() initial values to this module
|
// If set, move AstVar->valuep() initial values to this module
|
||||||
|
|
@ -72,6 +74,9 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
// STATE - Statistic tracking
|
// STATE - Statistic tracking
|
||||||
VDouble0 m_statModules; // Number of modules seen
|
VDouble0 m_statModules; // Number of modules seen
|
||||||
|
|
||||||
|
bool m_unprotectedStdProcess
|
||||||
|
= false; // Set when std::process internals were unprotected, we only need to do this once
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void cleanFileline(AstNode* nodep) {
|
void cleanFileline(AstNode* nodep) {
|
||||||
if (nodep->user2SetOnce()) return; // Process once
|
if (nodep->user2SetOnce()) return; // Process once
|
||||||
|
|
@ -105,6 +110,21 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unprotectStdProcessHandle() {
|
||||||
|
if (m_unprotectedStdProcess) return;
|
||||||
|
m_unprotectedStdProcess = true;
|
||||||
|
if (!v3Global.opt.protectIds()) return;
|
||||||
|
if (AstPackage* const stdp = v3Global.rootp()->stdPackagep()) {
|
||||||
|
if (AstClass* const processp
|
||||||
|
= VN_CAST(m_memberMap.findMember(stdp, "process"), Class)) {
|
||||||
|
if (AstVar* const handlep
|
||||||
|
= VN_CAST(m_memberMap.findMember(processp, "m_process"), Var)) {
|
||||||
|
handlep->protect(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void visitIterateNodeDType(AstNodeDType* nodep) {
|
void visitIterateNodeDType(AstNodeDType* nodep) {
|
||||||
if (nodep->user1SetOnce()) return; // Process only once.
|
if (nodep->user1SetOnce()) return; // Process only once.
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
|
|
@ -180,6 +200,38 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
<< nodep->warnContextSecondary());
|
<< nodep->warnContextSecondary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addForkParentProcess(AstFork* forkp) {
|
||||||
|
FileLine* const fl = forkp->fileline();
|
||||||
|
|
||||||
|
const std::string parentName = "__VforkParent";
|
||||||
|
AstRefDType* const dtypep = new AstRefDType{fl, "process"};
|
||||||
|
AstVar* const parentVar
|
||||||
|
= new AstVar{fl, VVarType::BLOCKTEMP, parentName, VFlagChildDType{}, dtypep};
|
||||||
|
parentVar->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||||
|
|
||||||
|
AstParseRef* const lhsp = new AstParseRef{fl, parentName, nullptr, nullptr};
|
||||||
|
AstClassOrPackageRef* const processRefp
|
||||||
|
= new AstClassOrPackageRef{fl, "process", nullptr, nullptr};
|
||||||
|
AstParseRef* const selfRefp = new AstParseRef{fl, "self", nullptr, nullptr};
|
||||||
|
AstDot* const processSelfp = new AstDot{fl, true, processRefp, selfRefp};
|
||||||
|
AstMethodCall* const callp = new AstMethodCall{fl, processSelfp, "self", nullptr};
|
||||||
|
AstAssign* const initp = new AstAssign{fl, lhsp, callp};
|
||||||
|
|
||||||
|
AstVarRef* const parentRefp = new AstVarRef{fl, parentVar, VAccess::READ};
|
||||||
|
forkp->parentProcessp(parentRefp);
|
||||||
|
|
||||||
|
VNRelinker relinker;
|
||||||
|
forkp->unlinkFrBack(&relinker);
|
||||||
|
|
||||||
|
parentVar->addNextHere(initp);
|
||||||
|
initp->addNextHere(forkp);
|
||||||
|
|
||||||
|
AstBegin* const beginp = new AstBegin{
|
||||||
|
fl, forkp->name() == "" ? "" : forkp->name() + "__VgetForkParent", parentVar, true};
|
||||||
|
|
||||||
|
relinker.relink(beginp);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return; // Process only once.
|
if (nodep->user1SetOnce()) return; // Process only once.
|
||||||
|
|
@ -791,7 +843,11 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
cleanFileline(nodep);
|
cleanFileline(nodep);
|
||||||
iterateAndNextNull(nodep->stmtsp());
|
iterateAndNextNull(nodep->stmtsp());
|
||||||
if (AstFork* const forkp = VN_CAST(nodep, Fork)) iterateAndNextNull(forkp->forksp());
|
if (AstFork* const forkp = VN_CAST(nodep, Fork)) {
|
||||||
|
iterateAndNextNull(forkp->forksp());
|
||||||
|
if (!forkp->parentProcessp() && forkp->joinType().joinNone() && forkp->forksp())
|
||||||
|
addForkParentProcess(forkp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void visit(AstCase* nodep) override {
|
void visit(AstCase* nodep) override {
|
||||||
V3Control::applyCase(nodep);
|
V3Control::applyCase(nodep);
|
||||||
|
|
@ -954,7 +1010,10 @@ class LinkParseVisitor final : public VNVisitor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
explicit LinkParseVisitor(AstNetlist* rootp) { iterate(rootp); }
|
explicit LinkParseVisitor(AstNetlist* rootp) {
|
||||||
|
unprotectStdProcessHandle();
|
||||||
|
iterate(rootp);
|
||||||
|
}
|
||||||
~LinkParseVisitor() override {
|
~LinkParseVisitor() override {
|
||||||
V3Stats::addStatSum(V3Stats::STAT_SOURCE_MODULES, m_statModules);
|
V3Stats::addStatSum(V3Stats::STAT_SOURCE_MODULES, m_statModules);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,10 @@ private:
|
||||||
for (AstNode* itemp = anodep->membersp(); itemp; itemp = itemp->nextp()) {
|
for (AstNode* itemp = anodep->membersp(); itemp; itemp = itemp->nextp()) {
|
||||||
memberInsert(mmapr, itemp);
|
memberInsert(mmapr, itemp);
|
||||||
}
|
}
|
||||||
|
} else if (const AstPackage* const anodep = VN_CAST(nodep, Package)) {
|
||||||
|
for (AstNode* itemp = anodep->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||||
|
memberInsert(mmapr, itemp);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nodep->v3fatalSrc("Unsupported node type");
|
nodep->v3fatalSrc("Unsupported node type");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -340,4 +340,12 @@ public:
|
||||||
}
|
}
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap fork statements in AstBegin, ensure fork...join_none have process
|
||||||
|
static AstNodeStmt* wrapFork(V3ParseImp* parsep, AstFork* forkp, AstNodeStmt* stmtsp) {
|
||||||
|
if (forkp->joinType() == VJoinType::JOIN_NONE && stmtsp)
|
||||||
|
parsep->importIfInStd(forkp->fileline(), "process", true);
|
||||||
|
forkp->addForksp(wrapInBegin(stmtsp));
|
||||||
|
return forkp;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -469,6 +469,7 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
AstScope* m_scopep = nullptr; // Current scope
|
AstScope* m_scopep = nullptr; // Current scope
|
||||||
AstActive* m_activep = nullptr; // Current active
|
AstActive* m_activep = nullptr; // Current active
|
||||||
AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under
|
AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under
|
||||||
|
bool m_hasProcess = false; // True if current scope has a VlProcess handle available
|
||||||
int m_forkCnt = 0; // Number of forks inside a module
|
int m_forkCnt = 0; // Number of forks inside a module
|
||||||
bool m_underJumpBlock = false; // True if we are inside of a jump-block
|
bool m_underJumpBlock = false; // True if we are inside of a jump-block
|
||||||
bool m_underProcedure = false; // True if we are under an always or initial
|
bool m_underProcedure = false; // True if we are under an always or initial
|
||||||
|
|
@ -654,26 +655,34 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
// Adds debug info to a hardcoded method call
|
// Adds debug info to a hardcoded method call
|
||||||
void addDebugInfo(AstCMethodHard* const methodp) const {
|
void addDebugInfo(AstCMethodHard* const methodp) const {
|
||||||
if (v3Global.opt.protectIds()) return;
|
|
||||||
FileLine* const flp = methodp->fileline();
|
FileLine* const flp = methodp->fileline();
|
||||||
AstCExpr* const ap = new AstCExpr{flp, '"' + flp->filenameEsc() + '"'};
|
const bool protectIds = v3Global.opt.protectIds();
|
||||||
|
AstCExpr* const ap
|
||||||
|
= new AstCExpr{flp, protectIds ? "VL_UNKNOWN" : '"' + flp->filenameEsc() + '"'};
|
||||||
ap->dtypeSetString();
|
ap->dtypeSetString();
|
||||||
methodp->addPinsp(ap);
|
methodp->addPinsp(ap);
|
||||||
AstCExpr* const bp = new AstCExpr{flp, cvtToStr(flp->lineno())};
|
AstCExpr* const bp = new AstCExpr{flp, protectIds ? "0" : cvtToStr(flp->lineno())};
|
||||||
bp->dtypeSetString();
|
bp->dtypeSetString();
|
||||||
methodp->addPinsp(bp);
|
methodp->addPinsp(bp);
|
||||||
}
|
}
|
||||||
// Adds debug info to a trigSched.trigger() call
|
// Adds debug info to a trigSched.trigger() call
|
||||||
void addEventDebugInfo(AstCMethodHard* const methodp, AstSenTree* const sentreep) const {
|
void addEventDebugInfo(AstCMethodHard* const methodp, AstSenTree* const sentreep) const {
|
||||||
if (v3Global.opt.protectIds()) return;
|
if (v3Global.opt.protectIds()) {
|
||||||
|
FileLine* const flp = sentreep->fileline();
|
||||||
|
AstCExpr* const descp = new AstCExpr{flp, "VL_UNKNOWN"};
|
||||||
|
descp->dtypeSetString();
|
||||||
|
methodp->addPinsp(descp);
|
||||||
|
addDebugInfo(methodp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
methodp->addPinsp(createEventDescription(sentreep));
|
methodp->addPinsp(createEventDescription(sentreep));
|
||||||
addDebugInfo(methodp);
|
addDebugInfo(methodp);
|
||||||
}
|
}
|
||||||
// Adds process pointer to a hardcoded method call
|
// Adds process pointer to a hardcoded method call
|
||||||
void addProcessInfo(AstCMethodHard* const methodp) const {
|
void addProcessInfo(AstCMethodHard* const methodp) const {
|
||||||
FileLine* const flp = methodp->fileline();
|
FileLine* const flp = methodp->fileline();
|
||||||
AstCExpr* const ap = new AstCExpr{
|
AstCExpr* const ap
|
||||||
flp, m_procp && (hasFlags(m_procp, T_HAS_PROC)) ? "vlProcess" : "nullptr"};
|
= new AstCExpr{flp, (m_procp && m_hasProcess) ? "vlProcess" : "nullptr"};
|
||||||
methodp->addPinsp(ap);
|
methodp->addPinsp(ap);
|
||||||
}
|
}
|
||||||
// Creates the fork handle type and returns it
|
// Creates the fork handle type and returns it
|
||||||
|
|
@ -779,7 +788,9 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
void visit(AstNodeProcedure* nodep) override {
|
void visit(AstNodeProcedure* nodep) override {
|
||||||
VL_RESTORER(m_procp);
|
VL_RESTORER(m_procp);
|
||||||
|
VL_RESTORER(m_hasProcess);
|
||||||
m_procp = nodep;
|
m_procp = nodep;
|
||||||
|
m_hasProcess = hasFlags(nodep, T_HAS_PROC);
|
||||||
VL_RESTORER(m_underProcedure);
|
VL_RESTORER(m_underProcedure);
|
||||||
m_underProcedure = true;
|
m_underProcedure = true;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
@ -801,7 +812,9 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
void visit(AstAlways* nodep) override {
|
void visit(AstAlways* nodep) override {
|
||||||
if (nodep->user1SetOnce()) return;
|
if (nodep->user1SetOnce()) return;
|
||||||
VL_RESTORER(m_procp);
|
VL_RESTORER(m_procp);
|
||||||
|
VL_RESTORER(m_hasProcess);
|
||||||
m_procp = nodep;
|
m_procp = nodep;
|
||||||
|
m_hasProcess = hasFlags(nodep, T_HAS_PROC);
|
||||||
VL_RESTORER(m_underProcedure);
|
VL_RESTORER(m_underProcedure);
|
||||||
m_underProcedure = true;
|
m_underProcedure = true;
|
||||||
// Workaround for killing `always` processes (doing that is pretty much UB)
|
// Workaround for killing `always` processes (doing that is pretty much UB)
|
||||||
|
|
@ -829,7 +842,9 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
void visit(AstCFunc* nodep) override {
|
void visit(AstCFunc* nodep) override {
|
||||||
VL_RESTORER(m_procp);
|
VL_RESTORER(m_procp);
|
||||||
|
VL_RESTORER(m_hasProcess);
|
||||||
m_procp = nodep;
|
m_procp = nodep;
|
||||||
|
m_hasProcess = hasFlags(nodep, T_HAS_PROC);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess();
|
if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess();
|
||||||
if (!(hasFlags(nodep, T_SUSPENDEE))) return;
|
if (!(hasFlags(nodep, T_SUSPENDEE))) return;
|
||||||
|
|
@ -862,6 +877,7 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstNodeCCall* nodep) override {
|
void visit(AstNodeCCall* nodep) override {
|
||||||
|
if (nodep->funcp()->needProcess()) m_hasProcess = true;
|
||||||
if (hasFlags(nodep->funcp(), T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable
|
if (hasFlags(nodep->funcp(), T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable
|
||||||
VNRelinker relinker;
|
VNRelinker relinker;
|
||||||
nodep->unlinkFrBack(&relinker);
|
nodep->unlinkFrBack(&relinker);
|
||||||
|
|
@ -1165,12 +1181,12 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
forkp->unlinkFrBack()});
|
forkp->unlinkFrBack()});
|
||||||
}
|
}
|
||||||
void visit(AstDisableFork* nodep) override {
|
void visit(AstDisableFork* nodep) override {
|
||||||
if (hasFlags(m_procp, T_HAS_PROC)) return;
|
if (m_hasProcess) return;
|
||||||
// never reached by any process; remove to avoid compilation error
|
// never reached by any process; remove to avoid compilation error
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||||
}
|
}
|
||||||
void visit(AstWaitFork* nodep) override {
|
void visit(AstWaitFork* nodep) override {
|
||||||
if (hasFlags(m_procp, T_HAS_PROC)) {
|
if (m_hasProcess) {
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
AstCExpr* const exprp = new AstCExpr{flp, "vlProcess->completedFork()", 1};
|
AstCExpr* const exprp = new AstCExpr{flp, "vlProcess->completedFork()", 1};
|
||||||
AstWait* const waitp = new AstWait{flp, exprp, nullptr};
|
AstWait* const waitp = new AstWait{flp, exprp, nullptr};
|
||||||
|
|
@ -1233,8 +1249,10 @@ class TimingControlVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
void visit(AstBegin* nodep) override {
|
void visit(AstBegin* nodep) override {
|
||||||
VL_RESTORER(m_procp);
|
VL_RESTORER(m_procp);
|
||||||
|
VL_RESTORER(m_hasProcess);
|
||||||
|
m_hasProcess |= hasFlags(nodep, T_HAS_PROC);
|
||||||
m_procp = nodep;
|
m_procp = nodep;
|
||||||
if (hasFlags(nodep, T_HAS_PROC)) nodep->setNeedProcess();
|
if (m_hasProcess) nodep->setNeedProcess();
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstFork* nodep) override {
|
void visit(AstFork* nodep) override {
|
||||||
|
|
|
||||||
|
|
@ -3400,23 +3400,23 @@ par_blockJoin<joinType>:
|
||||||
| yJOIN_NONE { $$ = VJoinType::JOIN_NONE; }
|
| yJOIN_NONE { $$ = VJoinType::JOIN_NONE; }
|
||||||
;
|
;
|
||||||
|
|
||||||
par_block<forkp>: // ==IEEE: par_block
|
par_block<nodeStmtp>: // ==IEEE: par_block
|
||||||
yFORK startLabelE blockDeclListE stmtListE par_blockJoin endLabelE
|
yFORK startLabelE blockDeclListE stmtListE par_blockJoin endLabelE
|
||||||
{
|
{
|
||||||
$$ = new AstFork{$1, $5, $2 ? *$2 : ""};
|
AstFork* const forkp = new AstFork{$1, $5, $2 ? *$2 : ""};
|
||||||
GRAMMARP->endLabel($<fl>6, $$, $6);
|
GRAMMARP->endLabel($<fl>6, forkp, $6);
|
||||||
$$->addDeclsp($3);
|
forkp->addDeclsp($3);
|
||||||
$$->addForksp(V3ParseGrammar::wrapInBegin($4));
|
$$ = V3ParseGrammar::wrapFork(PARSEP, forkp, $4);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
par_blockPreId<forkp>: // ==IEEE: par_block but called with leading ID
|
par_blockPreId<nodeStmtp>: // ==IEEE: par_block but called with leading ID
|
||||||
id yP_COLON__FORK yFORK blockDeclListE stmtListE par_blockJoin endLabelE
|
id yP_COLON__FORK yFORK blockDeclListE stmtListE par_blockJoin endLabelE
|
||||||
{
|
{
|
||||||
$$ = new AstFork{$3, $6, *$1};
|
AstFork* const forkp = new AstFork{$3, $6, *$1};
|
||||||
GRAMMARP->endLabel($<fl>7, $$, $7);
|
GRAMMARP->endLabel($<fl>7, forkp, $7);
|
||||||
$$->addDeclsp($4);
|
forkp->addDeclsp($4);
|
||||||
$$->addForksp(V3ParseGrammar::wrapInBegin($5));
|
$$ = V3ParseGrammar::wrapFork(PARSEP, forkp, $5);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ class Cls;
|
||||||
y = 2;
|
y = 2;
|
||||||
end
|
end
|
||||||
join_none
|
join_none
|
||||||
|
#1;
|
||||||
endtask
|
endtask
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ class Foo;
|
||||||
$stop;
|
$stop;
|
||||||
end
|
end
|
||||||
join_none : frk
|
join_none : frk
|
||||||
|
#1;
|
||||||
endtask
|
endtask
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
export "DPI-C" task cfunc_finish; // this is just so the task becomes AstCFunc, we don't really use the export
|
||||||
|
task cfunc_finish;
|
||||||
|
$finish;
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
fork
|
||||||
|
cfunc_finish();
|
||||||
|
join_none
|
||||||
|
#1 $stop;
|
||||||
|
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=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
integer i=0;
|
||||||
|
initial begin
|
||||||
|
fork
|
||||||
|
i=1;
|
||||||
|
join_none
|
||||||
|
if(i==1) $stop;
|
||||||
|
$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=["--timing"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
bit flag;
|
||||||
|
initial begin
|
||||||
|
fork begin
|
||||||
|
$stop;
|
||||||
|
end join_none
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -20,9 +20,10 @@ module t;
|
||||||
fork
|
fork
|
||||||
p = 1;
|
p = 1;
|
||||||
join_none
|
join_none
|
||||||
|
#0;
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
task t2(output q);
|
task t2(output q);
|
||||||
q <= 1;
|
q = 1;
|
||||||
endtask
|
endtask
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,15 @@ module t;
|
||||||
process job[] = new [8];
|
process job[] = new [8];
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
foreach (job[j]) fork
|
foreach (job[j]) begin
|
||||||
begin
|
fork
|
||||||
$write("job started\n");
|
begin
|
||||||
job[j] = process::self();
|
$write("job started\n");
|
||||||
end
|
job[j] = process::self();
|
||||||
join_none
|
end
|
||||||
|
join_none
|
||||||
|
#0;
|
||||||
|
end
|
||||||
foreach (job[j]) begin
|
foreach (job[j]) begin
|
||||||
wait (job[j]);
|
wait (job[j]);
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
job started
|
||||||
|
all jobs started
|
||||||
|
all jobs finished
|
||||||
|
*-* All Finished *-*
|
||||||
|
|
@ -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(expect_filename=test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t;
|
||||||
|
process job;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
process p1 = process::self();
|
||||||
|
fork
|
||||||
|
begin
|
||||||
|
wait(p1.status() != process::RUNNING);
|
||||||
|
$write("job started\n");
|
||||||
|
job = process::self();
|
||||||
|
end
|
||||||
|
join_none
|
||||||
|
wait (job);
|
||||||
|
$write("all jobs started\n");
|
||||||
|
job.await();
|
||||||
|
$write("all jobs finished\n");
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -50,7 +50,7 @@ module t();
|
||||||
bar.ewait();
|
bar.ewait();
|
||||||
end
|
end
|
||||||
join_none
|
join_none
|
||||||
|
#1;
|
||||||
p.kill();
|
p.kill();
|
||||||
|
|
||||||
->evt1;
|
->evt1;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2___024root___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass__Vclpkg___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass__Vclpkg___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2___024unit___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2___024unit___ctor_var_reset
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2_t___ctor_var_reset
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess__Vclpkg___ctor_var_reset
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03asemaphore__Vclpkg___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass__Vclpkg___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass__Vclpkg___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass__Vclpkg___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass__Vclpkg___ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset
|
||||||
|
|
@ -1207,7 +1210,12 @@
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess__Vclpkg::__VnoInFunc_self
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::new
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::_ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_1__0
|
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_1__0
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||||
|
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , ); )) at t/t_timing_class.v:224
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76
|
||||||
-V{t#,#} Process forked at t/t_timing_class.v:76 finished
|
-V{t#,#} Process forked at t/t_timing_class.v:76 finished
|
||||||
|
|
@ -1217,8 +1225,13 @@
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
||||||
-V{t#,#} Suspended processes waiting for dynamic trigger evaluation:
|
-V{t#,#} Suspended processes waiting for dynamic trigger evaluation:
|
||||||
-V{t#,#} - Process waiting at t/t_timing_class.v:75
|
-V{t#,#} - Process waiting at t/t_timing_class.v:75
|
||||||
|
-V{t#,#} Suspended processes waiting for dynamic trigger evaluation:
|
||||||
|
-V{t#,#} - Process waiting at t/t_timing_class.v:224
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75
|
||||||
-V{t#,#} Process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 awaiting resumption
|
-V{t#,#} Process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 awaiting resumption
|
||||||
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||||
|
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_0__25____VforkParent.(t.__Vtask_status__26__Vfuncout); , ); )) at t/t_timing_class.v:224 awaiting resumption
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||||
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||||
|
|
@ -1228,9 +1241,11 @@
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||||
-V{t#,#} Resuming processes:
|
-V{t#,#} Resuming processes:
|
||||||
-V{t#,#} - Process waiting at t/t_timing_class.v:75
|
-V{t#,#} - Process waiting at t/t_timing_class.v:75
|
||||||
|
-V{t#,#} - Process waiting at t/t_timing_class.v:224
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75
|
||||||
-V{t#,#} Process forked at t/t_timing_class.v:75 finished
|
-V{t#,#} Process forked at t/t_timing_class.v:75 finished
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:74
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:74
|
||||||
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
||||||
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
||||||
|
|
@ -1271,15 +1286,15 @@
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||||
-V{t#,#} Delayed processes:
|
-V{t#,#} Delayed processes:
|
||||||
-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:224
|
|
||||||
-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:131
|
-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:131
|
||||||
|
-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:224
|
||||||
-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136
|
-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136
|
||||||
-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:190
|
-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:190
|
||||||
-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274
|
-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274
|
||||||
-V{t#,#} Resuming delayed processes
|
-V{t#,#} Resuming delayed processes
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224
|
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
||||||
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
||||||
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
||||||
|
|
@ -1327,12 +1342,34 @@
|
||||||
-V{t#,#} Resuming delayed processes
|
-V{t#,#} Resuming delayed processes
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess__Vclpkg::__VnoInFunc_self
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::new
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::_ctor_var_reset
|
||||||
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_2__0
|
-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__Vtiming__6____Vfork_2__0
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||||
|
-V{t#,#} Suspending process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , ); )) at t/t_timing_class.v:229
|
||||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
||||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
||||||
|
-V{t#,#} Suspended processes waiting for dynamic trigger evaluation:
|
||||||
|
-V{t#,#} - Process waiting at t/t_timing_class.v:229
|
||||||
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:229
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_std__03a__03aprocess::__VnoInFunc_status
|
||||||
|
-V{t#,#} Process waiting for @([true] (32'h1 != $_EXPRSTMT( // Function: status t.__Vtask___VforkTask_1__29____VforkParent.(t.__Vtask_status__30__Vfuncout); , ); )) at t/t_timing_class.v:229 awaiting resumption
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||||
|
-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate())
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___timing_commit
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||||
|
-V{t#,#} Resuming processes:
|
||||||
|
-V{t#,#} - Process waiting at t/t_timing_class.v:229
|
||||||
|
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:229
|
||||||
|
-V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||||
|
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act
|
||||||
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import vltest_bootstrap
|
||||||
|
|
||||||
test.scenarios('simulator')
|
test.scenarios('simulator')
|
||||||
|
|
||||||
test.compile(verilator_flags2=["--binary -Wno-UNOPTFLAT"])
|
test.compile(verilator_flags2=["--binary"])
|
||||||
|
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
|
||||||
#
|
|
||||||
# Copyright 2024 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('vlt')
|
|
||||||
test.top_filename = "t/t_timing_fork_comb.v"
|
|
||||||
|
|
||||||
# Should convert the first always into combo and detect cycle
|
|
||||||
test.lint(fails=True, verilator_flags2=["--timing"])
|
|
||||||
|
|
||||||
test.file_grep(
|
|
||||||
test.compile_log_filename,
|
|
||||||
r'%Warning-UNOPTFLAT: t/t_timing_fork_comb.v:\d+:\d+: Signal unoptimizable: Circular combinational logic:'
|
|
||||||
)
|
|
||||||
|
|
||||||
test.passes()
|
|
||||||
Loading…
Reference in New Issue