Support block_item_declaration in forks (#4455)

This commit is contained in:
Krzysztof Boroński 2023-09-08 16:40:14 +02:00 committed by GitHub
parent 014301587f
commit 70b11f91b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 155 additions and 21 deletions

View File

@ -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:

View File

@ -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);
}

View File

@ -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); }
;

View File

@ -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;

View File

@ -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