Support `wait fork` (#4586)

This commit is contained in:
Aleksander Kiryk 2023-10-20 13:13:57 +02:00 committed by GitHub
parent 05bb7fa821
commit 83a0085c4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 54 additions and 26 deletions

View File

@ -120,15 +120,21 @@ public:
void attach(VlProcess* childp) { m_children.insert(childp); }
void detach(VlProcess* childp) { m_children.erase(childp); }
int state() { return m_state; }
int state() const { return m_state; }
void state(int s) { m_state = s; }
void disable() {
state(KILLED);
disable_fork();
disableFork();
}
void disable_fork() {
void disableFork() {
for (VlProcess* childp : m_children) childp->disable();
}
bool completed() const { return state() == FINISHED || state() == KILLED; }
bool completedFork() const {
for (const VlProcess* const childp : m_children)
if (!childp->completed()) return false;
return true;
}
};
inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }

View File

@ -617,6 +617,7 @@ public:
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
string emitC() override { V3ERROR_NA_RETURN(""); }
bool same(const AstNode* /*samep*/) const override { return true; }
bool isPure() override { return pure(); }
bool pure() const { return m_pure; }
void pure(bool flag) { m_pure = flag; }
};

View File

@ -3325,6 +3325,7 @@ public:
explicit AstWaitFork(FileLine* fl)
: ASTGEN_SUPER_WaitFork(fl) {}
ASTGEN_MEMBERS_AstWaitFork;
bool isTimingControl() const override { return true; }
};
class AstWhile final : public AstNodeStmt {
// @astgen op1 := precondsp : List[AstNode]

View File

@ -613,7 +613,7 @@ public:
puts("]);\n");
}
}
void visit(AstDisableFork* nodep) override { puts("vlProcess->disable_fork();\n"); }
void visit(AstDisableFork* nodep) override { puts("vlProcess->disableFork();\n"); }
void visit(AstCReturn* nodep) override {
puts("return (");
iterateAndNextConstNull(nodep->lhsp());

View File

@ -408,7 +408,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
void visit(AstCExpr* nodep) override {
putfs(nodep, "$_CEXPR(");
iterateAndNextConstNull(nodep->exprsp());
puts(");\n");
puts(")");
}
void visit(AstUCStmt* nodep) override {
putfs(nodep, "$c(");

View File

@ -275,6 +275,10 @@ private:
visit(static_cast<AstNode*>(nodep));
addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC);
}
void visit(AstWaitFork* nodep) override {
visit(static_cast<AstNode*>(nodep));
addFlags(m_procp, T_FORCES_PROC | T_NEEDS_PROC);
}
void visit(AstCFunc* nodep) override {
VL_RESTORER(m_procp);
m_procp = nodep;
@ -573,8 +577,11 @@ private:
// Returns true if we are under a class or the given tree has any references to locals. These
// are cases where static, globally-evaluated triggers are not suitable.
bool needDynamicTrigger(AstNode* const nodep) const {
return m_classp || nodep->exists([](const AstNodeVarRef* const refp) {
return refp->varp()->isFuncLocal();
return m_classp || nodep->exists([](AstNode* const nodep) {
if (AstNodeVarRef* varp = VN_CAST(nodep, NodeVarRef)) {
return varp->varp()->isFuncLocal();
}
return !nodep->isPure();
});
}
// Returns true if the given trigger expression needs a destructive post update after trigger
@ -1050,6 +1057,13 @@ private:
// var
alwaysp->addNextHere(nodep);
}
void visit(AstWaitFork* nodep) override {
AstCExpr* const exprp = new AstCExpr{nodep->fileline(), "vlProcess->completedFork()", 1};
exprp->pure(false);
AstWait* const waitp = new AstWait{nodep->fileline(), exprp, nullptr};
nodep->replaceWith(waitp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
void visit(AstWait* nodep) override {
// Wait on changed events related to the vars in the wait statement
FileLine* const flp = nodep->fileline();

View File

@ -693,6 +693,7 @@ private:
if (nodep->fileline()->timingOn()) {
if (v3Global.opt.timing().isSetFalse()) {
nodep->v3warn(E_NOTIMING, "Support for disable fork statement requires --timing");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (!v3Global.opt.timing().isSetTrue()) {
nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how "
<< "disable fork should be handled");
@ -700,8 +701,15 @@ private:
}
}
void visit(AstWaitFork* nodep) override {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
if (nodep->fileline()->timingOn()) {
if (v3Global.opt.timing().isSetFalse()) {
nodep->v3warn(E_NOTIMING, "Support for disable fork statement requires --timing");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (!v3Global.opt.timing().isSetTrue()) {
nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how "
<< "disable fork should be handled");
}
}
}
void visit(AstToLowerN* nodep) override {
if (m_vup->prelim()) {

View File

@ -14809,9 +14809,7 @@ class uvm_objection extends uvm_report_object;
if (m_trace_mode)
m_report(obj,source_obj,description,count,"all_dropped");
all_dropped(obj,source_obj,description, count);
//TODO issue #4465 - Support wait fork
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:14761:7: Unsupported: wait fork statements
//TODO wait fork;
wait fork;
if (m_source_count.exists(obj) && m_source_count[obj] == 0)
m_source_count.delete(obj);
if (m_total_count.exists(obj) && m_total_count[obj] == 0)

View File

@ -1,6 +0,0 @@
%Error-UNSUPPORTED: t/t_wait_fork.v:17:7: Unsupported: wait fork statements
: ... note: In instance 't'
17 | wait fork;
| ^~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -10,10 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(linter => 1);
lint(
verilator_flags2 => ['--lint-only --timing'],
fails => 1,
expect_filename => $Self->{golden_filename},
compile(
verilator_flags2 => ["--exe --main --timing"],
make_main => 0,
);
execute(
check_finished => 1,
);
ok(1);

View File

@ -8,13 +8,16 @@ module t(/*AUTOARG*/);
logic never;
integer n = 0;
initial begin
fork
#10;
#10;
join_none
disable fork;
fork
#10 if (n != 0) $stop; else n = 1;
#15 if (n != 1) $stop; else n = 2;
join_none
wait fork;
if (n != 2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end