Support block_item_declaration in forks (#4455)
This commit is contained in:
parent
014301587f
commit
70b11f91b4
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
class AstNodeBlock VL_NOT_FINAL : public AstNode {
|
||||
// A Begin/fork block
|
||||
// @astgen op1 := stmtsp : List[AstNode]
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
// Parents: statement
|
||||
private:
|
||||
string m_name; // Name of block
|
||||
|
|
@ -2049,7 +2049,7 @@ public:
|
|||
class AstBegin final : public AstNodeBlock {
|
||||
// A Begin/end named block, only exists shortly after parsing until linking
|
||||
// Parents: statement
|
||||
// @astgen op2 := genforp : Optional[AstNode]
|
||||
// @astgen op1 := genforp : Optional[AstNode]
|
||||
|
||||
bool m_generate; // Underneath a generate
|
||||
const bool m_implied; // Not inserted by user
|
||||
|
|
@ -2068,6 +2068,7 @@ public:
|
|||
};
|
||||
class AstFork final : public AstNodeBlock {
|
||||
// A fork named block
|
||||
// @astgen op1 := initsp : List[AstNode]
|
||||
// Parents: statement
|
||||
// Children: statements
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "V3Ast.h"
|
||||
#include "V3AstNodeExpr.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3MemberMap.h"
|
||||
|
||||
|
|
@ -131,6 +132,11 @@ public:
|
|||
UASSERT_OBJ(m_instance.initialized(), m_procp, "No dynamic scope prototype");
|
||||
UASSERT_OBJ(!linked(), m_instance.m_handlep, "Handle already linked");
|
||||
|
||||
if (VN_IS(m_procp, Fork)) {
|
||||
linkNodesOfFork(memberMap);
|
||||
return;
|
||||
}
|
||||
|
||||
AstNode* stmtp = getProcStmts();
|
||||
UASSERT(stmtp, "trying to instantiate dynamic scope while not under proc");
|
||||
VNRelinker stmtpHandle;
|
||||
|
|
@ -183,6 +189,44 @@ public:
|
|||
bool linked() const { return m_instance.initialized() && m_instance.m_handlep->backp(); }
|
||||
|
||||
private:
|
||||
AstAssign* instantiateDynScope(VMemberMap& memberMap) {
|
||||
AstNew* const newp = new AstNew{m_procp->fileline(), nullptr};
|
||||
newp->taskp(VN_AS(memberMap.findMember(m_instance.m_classp, "new"), NodeFTask));
|
||||
newp->dtypep(m_instance.m_refDTypep);
|
||||
newp->classOrPackagep(m_instance.m_classp);
|
||||
|
||||
return new AstAssign{
|
||||
m_procp->fileline(),
|
||||
new AstVarRef{m_procp->fileline(), m_instance.m_handlep, VAccess::WRITE}, newp};
|
||||
}
|
||||
|
||||
void linkNodesOfFork(VMemberMap& memberMap) {
|
||||
// Special case
|
||||
|
||||
AstFork* const forkp = VN_AS(m_procp, Fork);
|
||||
VNRelinker forkHandle;
|
||||
forkp->unlinkFrBack(&forkHandle);
|
||||
|
||||
AstBegin* const beginp = new AstBegin{
|
||||
forkp->fileline(),
|
||||
"_Vwrapped_" + (forkp->name().empty() ? cvtToHex(forkp) : forkp->name()),
|
||||
m_instance.m_handlep, false, true};
|
||||
forkHandle.relink(beginp);
|
||||
|
||||
AstNode* const instAsgnp = instantiateDynScope(memberMap);
|
||||
|
||||
beginp->stmtsp()->addNext(instAsgnp);
|
||||
beginp->stmtsp()->addNext(forkp);
|
||||
|
||||
forkp->initsp()->foreach([forkp](AstAssign* asgnp) {
|
||||
asgnp->unlinkFrBack();
|
||||
forkp->addHereThisAsNext(asgnp);
|
||||
});
|
||||
UASSERT_OBJ(!forkp->initsp(), forkp, "Leftover nodes in block_item_declaration");
|
||||
|
||||
m_modp->addStmtsp(m_instance.m_classp);
|
||||
}
|
||||
|
||||
static string generateDynScopeClassName(const AstNode* fromp) {
|
||||
string n = "__VDynScope__" + (!fromp->name().empty() ? (fromp->name() + "__") : "ANON__")
|
||||
+ cvtToHex(fromp);
|
||||
|
|
@ -245,11 +289,11 @@ private:
|
|||
return frameIt->second;
|
||||
}
|
||||
|
||||
ForkDynScopeFrame* pushDynScopeFrame() {
|
||||
ForkDynScopeFrame* const frame = new ForkDynScopeFrame{m_modp, m_procp};
|
||||
auto r = m_frames.emplace(std::make_pair(m_procp, frame));
|
||||
ForkDynScopeFrame* pushDynScopeFrame(AstNode* procp) {
|
||||
ForkDynScopeFrame* const framep = new ForkDynScopeFrame{m_modp, procp};
|
||||
auto r = m_frames.emplace(std::make_pair(procp, framep));
|
||||
UASSERT_OBJ(r.second, m_modp, "Procedure already contains a frame");
|
||||
return frame;
|
||||
return framep;
|
||||
}
|
||||
|
||||
void replaceWithMemberSel(AstVarRef* refp, const ForkDynScopeInstance& dynScope) {
|
||||
|
|
@ -301,13 +345,13 @@ private:
|
|||
void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_procp);
|
||||
m_procp = nodep;
|
||||
if (hasAsyncFork(nodep)) pushDynScopeFrame();
|
||||
if (hasAsyncFork(nodep)) pushDynScopeFrame(m_procp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstBegin* nodep) override {
|
||||
VL_RESTORER(m_procp);
|
||||
m_procp = nodep;
|
||||
if (hasAsyncFork(nodep)) pushDynScopeFrame();
|
||||
if (hasAsyncFork(nodep)) pushDynScopeFrame(m_procp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstFork* nodep) override {
|
||||
|
|
@ -315,6 +359,26 @@ private:
|
|||
if (!nodep->joinType().join()) ++m_forkDepth;
|
||||
|
||||
const bool oldAfterTimingControl = m_afterTimingControl;
|
||||
|
||||
ForkDynScopeFrame* framep = nullptr;
|
||||
if (nodep->initsp()) framep = pushDynScopeFrame(nodep);
|
||||
|
||||
for (AstNode* stmtp = nodep->initsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(stmtp, Var)) {
|
||||
// This can be probably optimized to detect cases in which dynscopes
|
||||
// could be avoided
|
||||
if (!framep->instance().initialized()) framep->createInstancePrototype();
|
||||
framep->captureVarInsert(varp);
|
||||
bindNodeToDynScope(varp, framep);
|
||||
} else {
|
||||
AstAssign* const asgnp = VN_CAST(stmtp, Assign);
|
||||
UASSERT_OBJ(asgnp, stmtp,
|
||||
"Invalid node under block item initialization part of fork");
|
||||
bindNodeToDynScope(asgnp->lhsp(), framep);
|
||||
iterate(asgnp->rhsp());
|
||||
}
|
||||
}
|
||||
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
m_afterTimingControl = false;
|
||||
iterate(stmtp);
|
||||
|
|
@ -432,7 +496,6 @@ private:
|
|||
}
|
||||
|
||||
string generateTaskName(AstNode* fromp, const string& kind) {
|
||||
// TODO: Ensure no collisions occur
|
||||
return "__V" + kind + (!fromp->name().empty() ? (fromp->name() + "__") : "UNNAMED__")
|
||||
+ cvtToHex(fromp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,17 @@ public:
|
|||
AstNode* cloneScopedSigAttr() const {
|
||||
return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr;
|
||||
}
|
||||
|
||||
static void addForkStmtsp(AstFork* forkp, AstNode* stmtsp) {
|
||||
forkp->addStmtsp(stmtsp);
|
||||
for (AstNode* stmtp = stmtsp; stmtp; stmtp = stmtp->nextp()) {
|
||||
AstVar* const varp = VN_CAST(stmtp, Var);
|
||||
if (!varp) break;
|
||||
varp->unlinkFrBack();
|
||||
varp->funcLocal(true);
|
||||
forkp->addInitsp(varp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const VBasicDTypeKwd LOGIC = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC"
|
||||
|
|
@ -3387,31 +3398,31 @@ seq_blockPreId<nodep>: // IEEE: seq_block, but called with leading ID
|
|||
|
||||
par_block<nodep>: // ==IEEE: par_block
|
||||
par_blockFront blockDeclStmtListE yJOIN endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
| par_blockFront blockDeclStmtListE yJOIN_ANY endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN_ANY);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN_ANY);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
| par_blockFront blockDeclStmtListE yJOIN_NONE endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN_NONE);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN_NONE);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
;
|
||||
|
||||
par_blockPreId<nodep>: // ==IEEE: par_block but called with leading ID
|
||||
par_blockFrontPreId blockDeclStmtListE yJOIN endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
| par_blockFrontPreId blockDeclStmtListE yJOIN_ANY endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN_ANY);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN_ANY);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
| par_blockFrontPreId blockDeclStmtListE yJOIN_NONE endLabelE
|
||||
{ $$ = $1; $1->addStmtsp($2);
|
||||
$1->joinType(VJoinType::JOIN_NONE);
|
||||
{ $$ = $1; $1->joinType(VJoinType::JOIN_NONE);
|
||||
V3ParseGrammar::addForkStmtsp($1, $2);
|
||||
SYMP->popScope($1); GRAMMARP->endLabel($<fl>4, $1, $4); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2023 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["--exe --main --timing"],
|
||||
make_main => 0,
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
static int counts[10];
|
||||
|
||||
class Foo;
|
||||
static task do_something();
|
||||
for (int i = 0; i < 10; i++)
|
||||
frk : fork
|
||||
int ii = i;
|
||||
#(10 + i) begin
|
||||
$display("i: %d, ii: %d", i, ii);
|
||||
if (counts[ii]++ != 0)
|
||||
$stop;
|
||||
end
|
||||
join_none : frk
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module t();
|
||||
initial begin
|
||||
int desired_counts[10] = '{10{1}};
|
||||
counts = '{10{0}};
|
||||
|
||||
Foo::do_something();
|
||||
#20;
|
||||
|
||||
if (counts != desired_counts)
|
||||
$stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue