Support functions on RHS of force (#7491)
Signed-off-by: Artur Bieniek <abieniek@antmicro.com>
This commit is contained in:
parent
dd75c4cd1b
commit
ec03edcddd
|
|
@ -434,6 +434,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
int m_unconVarNum = 0; // Unique bad connection variable
|
||||
|
||||
// STATE - across all visitors
|
||||
V3UniqueNames m_forceTmpNames; // For generating unique force-RHS helper names
|
||||
DpiCFuncs m_dpiNames; // Map of all created DPI functions
|
||||
VDouble0 m_statInlines; // Statistic tracking
|
||||
VDouble0 m_statHierDpisWithCosts; // Statistic tracking
|
||||
|
|
@ -1784,6 +1785,47 @@ class TaskVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstAssignForce* nodep) override {
|
||||
// Force statements cannot be converted to always blocks outside of a logic block
|
||||
// This causes function calls on RHS of force assignments to be improperly inlined and
|
||||
// called just once. To prevent this, we create a temporary variable for each function
|
||||
// reference on RHS. This variable is declared in the nearest scope and gets a continuous
|
||||
// assignment of the function, so it can be converted to always and properly inlined This
|
||||
// temporary variable becomes the RHS of the force assignment
|
||||
std::vector<AstNodeFTaskRef*> refs;
|
||||
nodep->rhsp()->foreach([&refs](AstNodeFTaskRef* refp) { refs.push_back(refp); });
|
||||
for (AstNodeFTaskRef* const refp : refs) {
|
||||
|
||||
// Create the temporary variable and its scope
|
||||
// Replicate the logic from V3Task, every function call gets
|
||||
// a unique temp variable
|
||||
AstVar* const interVarp = new AstVar{
|
||||
nodep->fileline(), VVarType::VAR,
|
||||
refp->name() + "__Vforcefuncout" + m_forceTmpNames.get(nodep), refp->dtypep()};
|
||||
UASSERT_OBJ(m_modp->stmtsp(), m_modp, "Module should have statements in it");
|
||||
m_modp->stmtsp()->addHereThisAsNext(interVarp);
|
||||
AstVarScope* const interVscp = new AstVarScope{refp->fileline(), m_scopep, interVarp};
|
||||
m_scopep->addVarsp(interVscp);
|
||||
|
||||
// Recompute the helper in a combo block so any inlined function body stays
|
||||
// inside schedulable logic rather than spilling statements at module scope.
|
||||
AstAssign* const assignp = new AstAssign{
|
||||
nodep->fileline(), new AstVarRef{nodep->fileline(), interVscp, VAccess::WRITE},
|
||||
nodep->rhsp()->cloneTreePure(false)};
|
||||
AstSenTree* const senTreep = new AstSenTree{
|
||||
nodep->fileline(), new AstSenItem{nodep->fileline(), AstSenItem::Combo{}}};
|
||||
AstActive* const activep
|
||||
= new AstActive{nodep->fileline(), "force-func-update", senTreep};
|
||||
activep->senTreeStorep(activep->sentreep());
|
||||
activep->addStmtsp(
|
||||
new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, nullptr, assignp});
|
||||
m_scopep->addBlocksp(activep);
|
||||
|
||||
// Replace RHS of force assignment with the temporary variable
|
||||
refp->replaceWith(new AstVarRef{nodep->fileline(), interVscp, VAccess::READ});
|
||||
VL_DO_DANGLING(refp->deleteTree(), refp);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeForeach* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc(
|
||||
"Foreach statements should have been converted to while statements in V3Begin.cpp");
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
%Error: t/t_force_func.v:29: got='h0 exp='h00000001
|
||||
%Error: t/t_force_func.v:37: got='h0 exp='h00000002
|
||||
%Error: t/t_force_func.v:42: got='h0 exp='h00000003
|
||||
%Error: t/t_force_func.v:46: got='h0 exp='h00000003
|
||||
|
|
@ -13,6 +13,6 @@ test.scenarios('vlt')
|
|||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute(expect_filename=test.golden_filename)
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop // TODO
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
||||
// verilog_format: on
|
||||
|
||||
|
|
@ -31,9 +31,6 @@ module t;
|
|||
a = 2;
|
||||
#1;
|
||||
`checkh(a, 2);
|
||||
// TODO
|
||||
// IEEE 1800-2023 10.6
|
||||
// Assignment shall be reevaluated while the assign or force is in effect.
|
||||
`checkh(b, 2);
|
||||
|
||||
a = 3;
|
||||
|
|
|
|||
Loading…
Reference in New Issue