Signed-off-by: Artur Bieniek <abieniek@internships.antmicro.com>
This commit is contained in:
parent
7176bdcff6
commit
da28c67e60
|
|
@ -160,6 +160,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
|
|||
#ifndef VL_USER_STOP ///< Define this to override the vl_stop function
|
||||
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
|
||||
// $stop or $fatal reporting; would break current API to add param as to which
|
||||
if (Verilated::threadContextp()->gotFinish()) return;
|
||||
const char* const msg = "Verilog $stop";
|
||||
Verilated::threadContextp()->gotError(true);
|
||||
Verilated::threadContextp()->gotFinish(true);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ uint64_t VlDelayScheduler::nextTimeSlot() const {
|
|||
|
||||
#ifdef VL_DEBUG
|
||||
void VlDelayScheduler::dump() const {
|
||||
if (m_queue.empty()) {
|
||||
if (m_queue.empty() && m_zeroDelayed.empty()) {
|
||||
VL_DBG_MSGF(" No delayed processes:\n");
|
||||
} else {
|
||||
VL_DBG_MSGF(" Delayed processes:\n");
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -209,7 +210,8 @@ public:
|
|||
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
void await_suspend(std::coroutine_handle<> coro) {
|
||||
if (phase == VlDelayPhase::ACTIVE) {
|
||||
// Both active delays and fork..join_none #0 are resumed out of the time queue.
|
||||
if (phase != VlDelayPhase::INACTIVE) {
|
||||
queue.emplace(delay, VlCoroutineHandle{coro, process, fileline});
|
||||
} else {
|
||||
queueZeroDelay.emplace_back(VlCoroutineHandle{coro, process, fileline});
|
||||
|
|
@ -218,7 +220,14 @@ public:
|
|||
void await_resume() const {}
|
||||
};
|
||||
|
||||
const VlDelayPhase phase = (delay == 0) ? VlDelayPhase::INACTIVE : VlDelayPhase::ACTIVE;
|
||||
VlDelayPhase phase;
|
||||
if (delay != 0) {
|
||||
// UINT64_MAX is a sentinel for synthetic fork..join_none delays.
|
||||
if (delay == std::numeric_limits<uint64_t>::max()) delay = 0;
|
||||
phase = VlDelayPhase::ACTIVE;
|
||||
} else {
|
||||
phase = VlDelayPhase::INACTIVE;
|
||||
}
|
||||
return Awaitable{process, m_queue,
|
||||
m_zeroDelayed, m_context.time() + delay,
|
||||
phase, VlFileLineDebug{filename, lineno}};
|
||||
|
|
|
|||
|
|
@ -1421,7 +1421,6 @@ class AstFork final : public AstNodeBlock {
|
|||
// be executed sequentially within each fork branch.
|
||||
//
|
||||
// @astgen op3 := forksp : List[AstBegin]
|
||||
// @astgen op4 := parentProcessp : Optional[AstVarRef]
|
||||
const VJoinType m_joinType; // Join keyword type
|
||||
public:
|
||||
AstFork(FileLine* fl, VJoinType joinType, const string& name = "")
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include "V3AstNodeExpr.h"
|
||||
#include "V3MemberMap.h"
|
||||
|
||||
#include <limits>
|
||||
#include <set>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
|
@ -90,7 +91,7 @@ public:
|
|||
m_instance.m_handlep
|
||||
= new AstVar{m_procp->fileline(), VVarType::BLOCKTEMP,
|
||||
generateDynScopeHandleName(m_procp), m_instance.m_refDTypep};
|
||||
m_instance.m_handlep->funcLocal(true);
|
||||
m_instance.m_handlep->funcLocal(false);
|
||||
m_instance.m_handlep->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
UINFO(9, "new dynscope var " << m_instance.m_handlep);
|
||||
|
||||
|
|
@ -336,12 +337,14 @@ class DynScopeVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
bool needsDynScope(const AstVarRef* refp) const {
|
||||
const AstVar* const varp = refp->varp();
|
||||
const bool localLifetime = varp->isFuncLocal() || varp->lifetime().isAutomatic();
|
||||
return
|
||||
// Can this variable escape the scope
|
||||
((m_forkDepth > refp->varp()->user1()) && refp->varp()->isFuncLocal())
|
||||
((m_forkDepth > varp->user1()) && localLifetime)
|
||||
&& (
|
||||
// Is it mutated
|
||||
(refp->varp()->isClassHandleValue() ? refp->user2() : refp->access().isWriteOrRW())
|
||||
(varp->isClassHandleValue() ? refp->user2() : refp->access().isWriteOrRW())
|
||||
// Or is it after a timing-control event
|
||||
|| m_afterTimingControl);
|
||||
}
|
||||
|
|
@ -527,11 +530,6 @@ class ForkVisitor final : public VNVisitor {
|
|||
AstVar* m_capturedVarsp = nullptr; // Local copies of captured variables
|
||||
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
|
||||
AstVar* capture(AstVarRef* refp) {
|
||||
AstVar* varp = nullptr;
|
||||
|
|
@ -585,19 +583,6 @@ class ForkVisitor final : public VNVisitor {
|
|||
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
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
|
|
@ -624,24 +609,16 @@ class ForkVisitor final : public VNVisitor {
|
|||
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);
|
||||
}
|
||||
// We use a sentinel value of UINT64_MAX to mark this delay so that it goes to the
|
||||
// ACTIVE region with a delay value of 0.
|
||||
for (AstBegin *itemp = nodep->forksp(), *nextp; itemp; itemp = nextp) {
|
||||
nextp = VN_AS(itemp->nextp(), Begin);
|
||||
if (!itemp->stmtsp()) continue;
|
||||
AstDelay* const delayp = new AstDelay{
|
||||
fl,
|
||||
new AstConst{fl, AstConst::Unsized64{}, std::numeric_limits<uint64_t>::max()},
|
||||
false};
|
||||
itemp->stmtsp()->addHereThisAsNext(delayp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -653,29 +653,6 @@ private:
|
|||
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* findp = symp->findIdFlat(name);
|
||||
if (findp) return findp;
|
||||
|
|
@ -726,9 +703,9 @@ public:
|
|||
const AstCellInline* inlinep = lookupSymp
|
||||
? VN_CAST(lookupSymp->nodep(), CellInline)
|
||||
: nullptr; // Replicated below
|
||||
VSymEnt* findSymp = findWithAltFallback(lookupSymp, ident, altIdent);
|
||||
if (!findSymp) findSymp = findForkParentAlias(lookupSymp, ident);
|
||||
if (findSymp) lookupSymp = unwrapForkParent(findSymp, ident);
|
||||
if (VSymEnt* const findSymp = findWithAltFallback(lookupSymp, ident, altIdent)) {
|
||||
lookupSymp = findSymp;
|
||||
}
|
||||
|
||||
// Check this module - cur modname
|
||||
else if ((cellp && cellp->modp()->origName() == ident)
|
||||
|
|
@ -776,9 +753,8 @@ public:
|
|||
}
|
||||
} else { // Searching for middle path component, must be a cell or interface port
|
||||
VSymEnt* findSymp = findWithAltFlat(lookupSymp, ident, altIdent);
|
||||
if (!findSymp) findSymp = findForkParentAlias(lookupSymp, ident);
|
||||
if (findSymp) {
|
||||
lookupSymp = unwrapForkParent(findSymp, ident);
|
||||
lookupSymp = findSymp;
|
||||
} else {
|
||||
// Try prefixed lookup for interface ports accessed through hierarchy
|
||||
// (e.g., slave_inst.bus.data where bus is an interface port)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include "V3LinkParse.h"
|
||||
|
||||
#include "V3Control.h"
|
||||
#include "V3MemberMap.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <set>
|
||||
|
|
@ -47,7 +46,6 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
|
||||
// STATE - across all visitors
|
||||
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)
|
||||
// If set, move AstVar->valuep() initial values to this module
|
||||
|
|
@ -75,9 +73,6 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
// STATE - Statistic tracking
|
||||
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
|
||||
void cleanFileline(AstNode* nodep) {
|
||||
if (nodep->user2SetOnce()) return; // Process once
|
||||
|
|
@ -111,21 +106,6 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
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) {
|
||||
if (nodep->user1SetOnce()) return; // Process only once.
|
||||
cleanFileline(nodep);
|
||||
|
|
@ -201,38 +181,6 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
<< 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
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process only once.
|
||||
|
|
@ -319,6 +267,10 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
cleanFileline(nodep);
|
||||
UINFO(9, "VAR " << nodep);
|
||||
if (nodep->valuep()) nodep->hasUserInit(true);
|
||||
if (m_insideLoop && nodep->lifetime().isNone() && nodep->varType() == VVarType::VAR
|
||||
&& !nodep->direction().isAny()) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC_IMPLICIT);
|
||||
}
|
||||
if (nodep->lifetime().isStatic() && m_insideLoop && nodep->valuep()) {
|
||||
nodep->lifetime(VLifetime::AUTOMATIC_IMPLICIT);
|
||||
nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a "
|
||||
|
|
@ -854,11 +806,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
}
|
||||
cleanFileline(nodep);
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
if (AstFork* const forkp = VN_CAST(nodep, Fork)) {
|
||||
iterateAndNextNull(forkp->forksp());
|
||||
if (!forkp->parentProcessp() && forkp->joinType().joinNone() && forkp->forksp())
|
||||
addForkParentProcess(forkp);
|
||||
}
|
||||
if (AstFork* const forkp = VN_CAST(nodep, Fork)) iterateAndNextNull(forkp->forksp());
|
||||
}
|
||||
void visit(AstCase* nodep) override {
|
||||
V3Control::applyCase(nodep);
|
||||
|
|
@ -1066,10 +1014,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit LinkParseVisitor(AstNetlist* rootp) {
|
||||
unprotectStdProcessHandle();
|
||||
iterate(rootp);
|
||||
}
|
||||
explicit LinkParseVisitor(AstNetlist* rootp) { iterate(rootp); }
|
||||
~LinkParseVisitor() override {
|
||||
V3Stats::addStatSum(V3Stats::STAT_SOURCE_MODULES, m_statModules);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,12 +364,4 @@ public:
|
|||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -210,9 +210,11 @@ private:
|
|||
// Find all var->varscope mappings, for later cleanup
|
||||
for (AstNode* stmtp = nodep->varsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVarScope* const vscp = VN_CAST(stmtp, VarScope)) {
|
||||
if (vscp->varp()->isFuncLocal() || vscp->varp()->isUsedLoopIdx()) {
|
||||
AstVar* const varp = vscp->varp();
|
||||
if (varp->isFuncLocal() || varp->isUsedLoopIdx()
|
||||
|| varp->lifetime().isAutomatic()) {
|
||||
UINFO(9, " funcvsc " << vscp);
|
||||
m_varToScopeMap.emplace(std::make_pair(nodep, vscp->varp()), vscp);
|
||||
m_varToScopeMap.emplace(std::make_pair(nodep, varp), vscp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#include "V3Stats.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
|
@ -627,9 +628,10 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
// Returns true if the given trigger expression needs a destructive post update after trigger
|
||||
// evaluation. Currently this only applies to named events.
|
||||
bool destructivePostUpdate(AstNode* const exprp) const {
|
||||
return exprp->exists([](const AstNodeVarRef* const refp) {
|
||||
AstBasicDType* const dtypep = refp->dtypep()->basicp();
|
||||
return dtypep && dtypep->isEvent();
|
||||
return exprp->exists([](const AstNode* const nodep) {
|
||||
const AstNodeDType* const dtypep = nodep->dtypep();
|
||||
const AstBasicDType* const basicp = dtypep ? dtypep->skipRefp()->basicp() : nullptr;
|
||||
return basicp && basicp->isEvent();
|
||||
});
|
||||
}
|
||||
// Creates a trigger scheduler variable
|
||||
|
|
@ -933,21 +935,28 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
valuep = new AstConst{flp, AstConst::Unsized64{}, 1};
|
||||
valuep->dtypeSetBitSized(64, VSigning::UNSIGNED);
|
||||
} else {
|
||||
// Scale the delay
|
||||
const double timescaleFactorD = calculateTimescaleFactor(nodep, nodep->timeunit());
|
||||
if (valuep->dtypep()->skipRefp()->isDouble()) {
|
||||
AstConst* const tsfp = new AstConst{flp, AstConst::RealDouble{}, timescaleFactorD};
|
||||
valuep = new AstMulD{flp, valuep, tsfp};
|
||||
valuep = new AstRToIRoundS{flp, valuep};
|
||||
valuep->dtypeSetBitSized(64, VSigning::UNSIGNED);
|
||||
} else {
|
||||
valuep->dtypeSetBitSized(64, VSigning::UNSIGNED);
|
||||
const uint64_t timescaleFactorU = static_cast<uint64_t>(timescaleFactorD);
|
||||
AstConst* const tsfp = new AstConst{flp, AstConst::Unsized64{}, timescaleFactorU};
|
||||
valuep = new AstMul{flp, valuep, tsfp};
|
||||
AstConst* const constp = VN_CAST(valuep, Const);
|
||||
const bool isForkSentinel
|
||||
= constp && (constp->toUQuad() == std::numeric_limits<uint64_t>::max());
|
||||
if (!isForkSentinel && (!constp || !constp->isZero())) {
|
||||
// Scale the delay
|
||||
const double timescaleFactorD = calculateTimescaleFactor(nodep, nodep->timeunit());
|
||||
if (valuep->dtypep()->skipRefp()->isDouble()) {
|
||||
AstConst* const tsfp
|
||||
= new AstConst{flp, AstConst::RealDouble{}, timescaleFactorD};
|
||||
valuep = new AstMulD{flp, valuep, tsfp};
|
||||
valuep = new AstRToIRoundS{flp, valuep};
|
||||
valuep->dtypeSetBitSized(64, VSigning::UNSIGNED);
|
||||
} else {
|
||||
valuep->dtypeSetBitSized(64, VSigning::UNSIGNED);
|
||||
const uint64_t timescaleFactorU = static_cast<uint64_t>(timescaleFactorD);
|
||||
AstConst* const tsfp
|
||||
= new AstConst{flp, AstConst::Unsized64{}, timescaleFactorU};
|
||||
valuep = new AstMul{flp, valuep, tsfp};
|
||||
}
|
||||
// Simplify
|
||||
valuep = V3Const::constifyEdit(valuep);
|
||||
}
|
||||
// Simplify
|
||||
valuep = V3Const::constifyEdit(valuep);
|
||||
}
|
||||
|
||||
// Statistics
|
||||
|
|
|
|||
|
|
@ -3493,23 +3493,23 @@ par_blockJoin<joinType>:
|
|||
| yJOIN_NONE { $$ = VJoinType::JOIN_NONE; }
|
||||
;
|
||||
|
||||
par_block<nodeStmtp>: // ==IEEE: par_block
|
||||
par_block<forkp>: // ==IEEE: par_block
|
||||
yFORK startLabelE blockDeclListE stmtListE par_blockJoin endLabelE
|
||||
{
|
||||
AstFork* const forkp = new AstFork{$1, $5, $2 ? *$2 : ""};
|
||||
GRAMMARP->endLabel($<fl>6, forkp, $6);
|
||||
forkp->addDeclsp($3);
|
||||
$$ = V3ParseGrammar::wrapFork(PARSEP, forkp, $4);
|
||||
$$ = new AstFork{$1, $5, $2 ? *$2 : ""};
|
||||
GRAMMARP->endLabel($<fl>6, $$, $6);
|
||||
$$->addDeclsp($3);
|
||||
$$->addForksp(V3ParseGrammar::wrapInBegin($4));
|
||||
}
|
||||
;
|
||||
|
||||
par_blockPreId<nodeStmtp>: // ==IEEE: par_block but called with leading ID
|
||||
par_blockPreId<forkp>: // ==IEEE: par_block but called with leading ID
|
||||
id yP_COLON__FORK yFORK blockDeclListE stmtListE par_blockJoin endLabelE
|
||||
{
|
||||
AstFork* const forkp = new AstFork{$3, $6, *$1};
|
||||
GRAMMARP->endLabel($<fl>7, forkp, $7);
|
||||
forkp->addDeclsp($4);
|
||||
$$ = V3ParseGrammar::wrapFork(PARSEP, forkp, $5);
|
||||
$$ = new AstFork{$3, $6, *$1};
|
||||
GRAMMARP->endLabel($<fl>7, $$, $7);
|
||||
$$->addDeclsp($4);
|
||||
$$->addForksp(V3ParseGrammar::wrapInBegin($5));
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,29 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module test;
|
||||
mailbox #(int) mbox;
|
||||
initial begin
|
||||
mbox = new();
|
||||
mbox.put(10);
|
||||
mbox.put(30);
|
||||
|
||||
repeat(2) begin
|
||||
int item;
|
||||
mbox.get(item);
|
||||
fork
|
||||
begin
|
||||
$display("got", item);
|
||||
if(item==10)
|
||||
$finish;
|
||||
end
|
||||
join_none
|
||||
end
|
||||
|
||||
#0;
|
||||
$stop;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
This should be first
|
||||
This should be second
|
||||
This should be last
|
||||
|
|
@ -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(expect_filename=test.golden_filename)
|
||||
|
||||
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, 2026 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
initial fork
|
||||
#0 $write("This should be last\n");
|
||||
begin
|
||||
fork $write("This should be second\n"); join_none
|
||||
$write("This should be first\n");
|
||||
end
|
||||
join_none
|
||||
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,30 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module test;
|
||||
mailbox #(int) mbox;
|
||||
initial begin
|
||||
mbox = new();
|
||||
|
||||
fork
|
||||
repeat(2) begin
|
||||
int val;
|
||||
mbox.get(val);
|
||||
fork
|
||||
fork
|
||||
begin
|
||||
$finish;
|
||||
end
|
||||
join_none
|
||||
join_none
|
||||
end
|
||||
join_none
|
||||
|
||||
mbox.put(1);
|
||||
#1;
|
||||
$stop;
|
||||
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,35 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class events_holder;
|
||||
event ev;
|
||||
endclass
|
||||
|
||||
module test;
|
||||
events_holder m_events[int];
|
||||
int waiters_done = 0;
|
||||
|
||||
initial begin
|
||||
m_events[0] = new;
|
||||
fork
|
||||
begin
|
||||
@(m_events[0].ev);
|
||||
waiters_done++;
|
||||
end
|
||||
begin
|
||||
@(m_events[0].ev);
|
||||
waiters_done++;
|
||||
end
|
||||
join_none
|
||||
#1;
|
||||
->m_events[0].ev;
|
||||
|
||||
#1;
|
||||
if (waiters_done == 2) $finish;
|
||||
end
|
||||
|
||||
initial #10000ns $stop;
|
||||
endmodule
|
||||
|
|
@ -2,10 +2,7 @@
|
|||
-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___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_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__03aClkClass__Vclpkg___ctor_var_reset
|
||||
-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset
|
||||
|
|
@ -1342,28 +1339,19 @@
|
|||
-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_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_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); , 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#,#} Resuming: Process waiting at t/t_timing_class.v:76
|
||||
-V{t#,#} Process forked at t/t_timing_class.v:76 finished
|
||||
-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131
|
||||
-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_triggers_vec__act
|
||||
-V{t#,#} Suspended processes waiting for dynamic trigger evaluation:
|
||||
-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#,#} 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); , t.__Vtask_status__26__Vfuncout); )) at t/t_timing_class.v:224 awaiting resumption
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_ready
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
|
||||
|
|
@ -1376,11 +1364,9 @@
|
|||
-V{t#,#} Resuming processes waiting for @([event] t.ec.e)
|
||||
-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:224
|
||||
-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#,#} 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_triggers_vec__act
|
||||
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
|
||||
|
|
@ -1491,33 +1477,9 @@
|
|||
-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: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_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); , 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#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers_vec__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); , t.__Vtask_status__30__Vfuncout); )) at t/t_timing_class.v:229 awaiting resumption
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_ready
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
|
||||
-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___trigger_orInto__act_vec_vec
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___trigger_anySet__act
|
||||
-V{t#,#}+ Vt_timing_debug2___024root___timing_resume
|
||||
-V{t#,#} No process to resume waiting for @([event] t.ec.e)
|
||||
-V{t#,#} Resuming processes waiting for @([event] t.ec.e)
|
||||
-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
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
test.compile(verilator_flags2=["--binary -Wno-UNOPTFLAT"])
|
||||
|
||||
test.execute()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
#!/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