Fixes #7677.
This commit is contained in:
parent
816ab67826
commit
bc86701bec
|
|
@ -4036,8 +4036,10 @@ VerilatedScope::forceableVarInsert(const char* namep, void* datap, bool isParam,
|
|||
|
||||
va_list ap;
|
||||
va_start(ap, pdims);
|
||||
assert(udims == 0); // Forcing unpacked arrays is unsupported (#4735) and should have been
|
||||
// checked in V3Force already.
|
||||
for (int i = 0; i < udims; ++i) {
|
||||
forceReadSignal.m_unpacked[i].m_left = va_arg(ap, int);
|
||||
forceReadSignal.m_unpacked[i].m_right = va_arg(ap, int);
|
||||
}
|
||||
for (int i = 0; i < pdims; ++i) {
|
||||
const int msb = va_arg(ap, int);
|
||||
const int lsb = va_arg(ap, int);
|
||||
|
|
@ -4055,8 +4057,10 @@ VerilatedScope::forceableVarInsert(const char* namep, void* datap, bool isParam,
|
|||
verilatedForceControlSignalsp = nullptr;
|
||||
|
||||
va_start(ap, pdims);
|
||||
assert(udims == 0); // Forcing unpacked arrays is unsupported (#4735) and should have been
|
||||
// checked in V3Force already.
|
||||
for (int i = 0; i < udims; ++i) {
|
||||
var.m_unpacked[i].m_left = va_arg(ap, int);
|
||||
var.m_unpacked[i].m_right = va_arg(ap, int);
|
||||
}
|
||||
for (int i = 0; i < pdims; ++i) {
|
||||
const int msb = va_arg(ap, int);
|
||||
const int lsb = va_arg(ap, int);
|
||||
|
|
|
|||
182
src/V3Force.cpp
182
src/V3Force.cpp
|
|
@ -251,6 +251,40 @@ public:
|
|||
return varRefp;
|
||||
}
|
||||
|
||||
|
||||
static AstNodeExpr* buildNestedArraySel(FileLine* flp, AstNodeExpr* fromp,
|
||||
const std::vector<int>& indicies) {
|
||||
AstNodeExpr* curp = fromp;
|
||||
for (const int idx : indicies) curp = new AstArraySel{flp, curp, idx};
|
||||
return curp;
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
static AstNodeStmt* foreachUnpackedLeaf(const std::vector<AstUnpackArrayDType*>& dims,
|
||||
Fn buildLeaf) {
|
||||
AstNodeStmt* headp = nullptr;
|
||||
AstNodeStmt* tailp = nullptr;
|
||||
if (dims.empty()) return nullptr;
|
||||
int total = 1;
|
||||
for (const AstUnpackArrayDType* const d : dims) total *= d->elementsConst();
|
||||
if (total <= 0) return nullptr;
|
||||
std::vector<int> idx(dims.size(), 0);
|
||||
for (int flat = 0; flat < total; ++flat) {
|
||||
AstNodeStmt* const stmtp = buildLeaf(idx, flat);
|
||||
if (!headp) {
|
||||
headp = stmtp;
|
||||
} else {
|
||||
tailp->addNext(stmtp);
|
||||
}
|
||||
tailp = stmtp;
|
||||
for (int d = static_cast<int>(dims.size()) - 1; d >= 0; --d) {
|
||||
if (++idx[d] < dims[d]->elementsConst()) break;
|
||||
idx[d] = 0;
|
||||
}
|
||||
}
|
||||
return headp;
|
||||
}
|
||||
|
||||
ForceRangeInfo getForceRangeInfo(AstNodeExpr* lhsp, AstVar* varp,
|
||||
bool requireConstRangeSelect) {
|
||||
ForceRangeInfo info;
|
||||
|
|
@ -349,12 +383,16 @@ public:
|
|||
UASSERT(varInfo.m_forceRdVscp, "No forceRd for forced variable");
|
||||
UASSERT(varInfo.m_varVscp, "No base var scope for forced variable");
|
||||
FileLine* const flp = varInfo.m_varVscp->fileline();
|
||||
AstVar* const varp = varInfo.m_varVscp->varp();
|
||||
if (VN_IS(varp->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
return createForceRdUpdateStmtUnpacked(varInfo);
|
||||
}
|
||||
AstNodeExpr* readExprp = nullptr;
|
||||
AstVarRef* const baseRefp = new AstVarRef{flp, varInfo.m_varVscp, VAccess::READ};
|
||||
markNonReplaceable(baseRefp);
|
||||
AstNodeExpr* const enRefp = new AstVarRef{flp, varInfo.m_forceEnVscp, VAccess::READ};
|
||||
AstNodeExpr* const valRefp = new AstVarRef{flp, varInfo.m_forceValVscp, VAccess::READ};
|
||||
if (isBitwiseDType(varInfo.m_varVscp->varp())) {
|
||||
if (isBitwiseDType(varp)) {
|
||||
readExprp = new AstOr{
|
||||
flp, new AstAnd{flp, enRefp, valRefp},
|
||||
new AstAnd{flp, new AstNot{flp, enRefp->cloneTreePure(false)}, baseRefp}};
|
||||
|
|
@ -366,6 +404,30 @@ public:
|
|||
readExprp};
|
||||
}
|
||||
|
||||
AstNodeStmt* createForceRdUpdateStmtUnpacked(const VarForceInfo& varInfo) const {
|
||||
FileLine* const flp = varInfo.m_varVscp->fileline();
|
||||
AstVar* const varp = varInfo.m_varVscp->varp();
|
||||
AstUnpackArrayDType* const arrDtypep
|
||||
= VN_AS(varp->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
const std::vector<AstUnpackArrayDType*> dims = arrDtypep->unpackDimensions();
|
||||
return foreachUnpackedLeaf(
|
||||
dims, [&](const std::vector<int>& idx, int /*flat*/) -> AstNodeStmt* {
|
||||
AstVarRef* const baseRefp = new AstVarRef{flp, varInfo.m_varVscp, VAccess::READ};
|
||||
markNonReplaceable(baseRefp);
|
||||
AstNodeExpr* const baseSelp = buildNestedArraySel(flp, baseRefp, idx);
|
||||
AstNodeExpr* const enSelp = buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, varInfo.m_forceEnVscp, VAccess::READ}, idx);
|
||||
AstNodeExpr* const valSelp = buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, varInfo.m_forceValVscp, VAccess::READ}, idx);
|
||||
AstNodeExpr* const readExprp = new AstOr{
|
||||
flp, new AstAnd{flp, enSelp, valSelp},
|
||||
new AstAnd{flp, new AstNot{flp, enSelp->cloneTreePure(false)}, baseSelp}};
|
||||
AstNodeExpr* const rdLhsSelp = buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, varInfo.m_forceRdVscp, VAccess::WRITE}, idx);
|
||||
return new AstAssign{flp, rdLhsSelp, readExprp};
|
||||
});
|
||||
}
|
||||
|
||||
VarForceInfo& getOrCreateVarInfo(AstVar* varp) {
|
||||
const auto it = m_varToId.find(varp);
|
||||
if (it != m_varToId.end()) return m_varInfos[it->second];
|
||||
|
|
@ -568,11 +630,25 @@ public:
|
|||
flp, "force-init",
|
||||
new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Static{}}}};
|
||||
activeInitp->senTreeStorep(activeInitp->sentreep());
|
||||
AstAssign* const initEnp
|
||||
= new AstAssign{flp, new AstVarRef{flp, info.m_forceEnVscp, VAccess::WRITE},
|
||||
makeZeroConst(varp, info.m_forceEnVscp->width())};
|
||||
initEnp->addNextHere(createForceRdUpdateStmt(info));
|
||||
activeInitp->addStmtsp(new AstInitial{flp, initEnp});
|
||||
AstNodeStmt* initStmtp = nullptr;
|
||||
if (AstUnpackArrayDType* const arrDtypep
|
||||
= VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
const std::vector<AstUnpackArrayDType*> dims
|
||||
= arrDtypep->unpackDimensions();
|
||||
const int innerWidth = dims.back()->subDTypep()->skipRefp()->width();
|
||||
initStmtp = foreachUnpackedLeaf(
|
||||
dims, [&](const std::vector<int>& idx, int /*flat*/) -> AstNodeStmt* {
|
||||
AstNodeExpr* const lhsp = buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, info.m_forceEnVscp, VAccess::WRITE}, idx);
|
||||
return new AstAssign{flp, lhsp, makeZeroConst(varp, innerWidth)};
|
||||
});
|
||||
} else {
|
||||
initStmtp = new AstAssign{
|
||||
flp, new AstVarRef{flp, info.m_forceEnVscp, VAccess::WRITE},
|
||||
makeZeroConst(varp, info.m_forceEnVscp->width())};
|
||||
}
|
||||
initStmtp->addNext(createForceRdUpdateStmt(info));
|
||||
activeInitp->addStmtsp(new AstInitial{flp, initStmtp});
|
||||
scopep->addBlocksp(activeInitp);
|
||||
|
||||
AstSenItem* itemsp = nullptr;
|
||||
|
|
@ -699,6 +775,92 @@ class ForceDiscoveryVisitor final : public VNVisitorConst {
|
|||
ForceState& m_state;
|
||||
bool m_inClockedActive = false;
|
||||
|
||||
void buildForceableUnpackedArray(AstVarScope* const nodep,
|
||||
AstUnpackArrayDType* const arrDtypep) {
|
||||
AstVar* const varp = nodep->varp();
|
||||
const std::vector<AstUnpackArrayDType*> dims = arrDtypep->unpackDimensions();
|
||||
UASSERT_OBJ(!dims.empty(), varp,
|
||||
"buildForceableUnpackedArray called with non-unpacked dtype");
|
||||
const AstNodeDType* const leafDtypep = dims.back()->subDTypep()->skipRefp();
|
||||
const AstBasicDType* const innerBasicp = leafDtypep->basicp();
|
||||
const bool innerBitwise = innerBasicp && !innerBasicp->isDouble()
|
||||
&& !innerBasicp->isString() && !innerBasicp->isOpaque();
|
||||
if (!innerBitwise) {
|
||||
varp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Forcing unpacked arrays of non-bitwise inner type: "
|
||||
<< varp->name()); // (#4735)
|
||||
return;
|
||||
}
|
||||
|
||||
FileLine* const flp = varp->fileline();
|
||||
const int innerWidth = leafDtypep->width();
|
||||
|
||||
AstVar* const rdVarp
|
||||
= new AstVar{flp, VVarType::WIRE, varp->name() + "__VforceRd", varp->dtypep()};
|
||||
rdVarp->noSubst(true);
|
||||
rdVarp->sigPublic(true);
|
||||
AstVar* const enVarp
|
||||
= new AstVar{flp, VVarType::WIRE, varp->name() + "__VforceEn", varp->dtypep()};
|
||||
enVarp->sigUserRWPublic(true);
|
||||
AstVar* const valVarp
|
||||
= new AstVar{flp, VVarType::WIRE, varp->name() + "__VforceVal", varp->dtypep()};
|
||||
valVarp->sigUserRWPublic(true);
|
||||
varp->addNextHere(rdVarp);
|
||||
varp->addNextHere(enVarp);
|
||||
varp->addNextHere(valVarp);
|
||||
AstVarScope* const rdVscp = new AstVarScope{flp, nodep->scopep(), rdVarp};
|
||||
AstVarScope* const enVscp = new AstVarScope{flp, nodep->scopep(), enVarp};
|
||||
AstVarScope* const valVscp = new AstVarScope{flp, nodep->scopep(), valVarp};
|
||||
nodep->scopep()->addVarsp(rdVscp);
|
||||
nodep->scopep()->addVarsp(enVscp);
|
||||
nodep->scopep()->addVarsp(valVscp);
|
||||
|
||||
ForceState::VarForceInfo& info = m_state.getOrCreateVarInfo(varp);
|
||||
info.m_forceRdVscp = rdVscp;
|
||||
info.m_forceEnVscp = enVscp;
|
||||
info.m_forceValVscp = valVscp;
|
||||
info.m_varVscp = nodep;
|
||||
varp->user3p(rdVscp);
|
||||
varp->user4p(enVscp);
|
||||
nodep->user3p(valVscp);
|
||||
|
||||
AstSenItem* const itemsp = new AstSenItem{flp, VEdgeType::ET_CHANGED,
|
||||
new AstVarRef{flp, enVscp, VAccess::READ}};
|
||||
AstActive* const activep = new AstActive{flp, "force-update", new AstSenTree{flp, itemsp}};
|
||||
activep->senTreeStorep(activep->sentreep());
|
||||
|
||||
AstNodeStmt* const alwaysBodyHeadp = ForceState::foreachUnpackedLeaf(
|
||||
dims, [&](const std::vector<int>& idx, int flat) -> AstNodeStmt* {
|
||||
AstVarRef* const origRefp = new AstVarRef{flp, nodep, VAccess::READ};
|
||||
ForceState::markNonReplaceable(origRefp);
|
||||
AstNodeExpr* const origSelp = ForceState::buildNestedArraySel(flp, origRefp, idx);
|
||||
AstNodeExpr* const enSelp = ForceState::buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, enVscp, VAccess::READ}, idx);
|
||||
AstNodeExpr* const valSelp = ForceState::buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, valVscp, VAccess::READ}, idx);
|
||||
AstNodeExpr* const forceExprp = new AstOr{
|
||||
flp, new AstAnd{flp, enSelp, valSelp},
|
||||
new AstAnd{flp, new AstNot{flp, enSelp->cloneTreePure(false)}, origSelp}};
|
||||
AstNodeExpr* const lhsSelp = ForceState::buildNestedArraySel(
|
||||
flp, new AstVarRef{flp, nodep, VAccess::WRITE}, idx);
|
||||
|
||||
AstAssignForce* const forceAssignp = new AstAssignForce{flp, lhsSelp, forceExprp};
|
||||
forceAssignp->user2(true);
|
||||
|
||||
AstNodeExpr* const rhsClonep = forceExprp->cloneTreePure(false);
|
||||
rhsClonep->foreach([varp](AstVarRef* const r) {
|
||||
if (r->varp() == varp) ForceState::markNonReplaceable(r);
|
||||
});
|
||||
m_state.addForceAssignment(varp, nodep, rhsClonep, forceAssignp,
|
||||
/*rangeLsb=*/flat, /*rangeMsb=*/flat,
|
||||
/*padLsb=*/0, /*padMsb=*/innerWidth - 1,
|
||||
/*hasArraySel=*/true);
|
||||
return forceAssignp;
|
||||
});
|
||||
activep->addStmtsp(new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, alwaysBodyHeadp});
|
||||
nodep->scopep()->addBlocksp(activep);
|
||||
}
|
||||
|
||||
void visit(AstAssignForce* nodep) override {
|
||||
if (nodep->user2()) return; // External force statements are pre-registered.
|
||||
UINFO(2, "Discovering force statement: " << nodep << "\n");
|
||||
|
|
@ -779,10 +941,10 @@ class ForceDiscoveryVisitor final : public VNVisitorConst {
|
|||
}
|
||||
}
|
||||
|
||||
if (VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
nodep->varp()->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Forcing unpacked arrays: " << nodep->varp()->name()); // (#4735)
|
||||
if (AstUnpackArrayDType* const arrDtypep
|
||||
= VN_CAST(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
|
||||
buildForceableUnpackedArray(nodep, arrDtypep);
|
||||
iterateChildrenConst(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Nikolai Kumar
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <memory>
|
||||
#include VM_PREFIX_INCLUDE
|
||||
#include VM_PREFIX_ROOT_INCLUDE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{"top"}};
|
||||
auto& en = topp->rootp->t__DOT__var_arr__VforceEn;
|
||||
auto& val = topp->rootp->t__DOT__var_arr__VforceVal;
|
||||
auto& en_a = topp->rootp->t__DOT__var_arr_a__VforceEn;
|
||||
auto& val_a = topp->rootp->t__DOT__var_arr_a__VforceVal;
|
||||
while (!contextp->gotFinish()) {
|
||||
topp->clk = !topp->clk;
|
||||
topp->eval();
|
||||
if (topp->clk) {
|
||||
bool changed = true;
|
||||
switch (topp->cyc) {
|
||||
case 1:
|
||||
en[0][1] = 0x3; val[0][1] = 0x3;
|
||||
en_a[0][1] = 0x3; val_a[0][1] = 0x2;
|
||||
break;
|
||||
case 2:
|
||||
en[1][0] = 0x3; val[1][0] = 0x2;
|
||||
en_a[1][0] = 0x3; val_a[1][0] = 0x3;
|
||||
break;
|
||||
case 3:
|
||||
en[0][1] = 0x0; en_a[0][1] = 0x0;
|
||||
break;
|
||||
case 4:
|
||||
en[1][0] = 0x0; en_a[1][0] = 0x0;
|
||||
break;
|
||||
|
||||
default: changed = false;
|
||||
}
|
||||
if (changed) topp->eval();
|
||||
}
|
||||
contextp->timeInc(5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Nikolai Kumar
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define checkh(g,e) do if ((g) !==(e)) begin $write("%%Error: %s:%0d: got=%x exp=%x\n", `__FILE__,`__LINE__, (g),(e)); $stop; end while(0)
|
||||
|
||||
`ifdef CMT
|
||||
`define FORCEABLE /*verilator forceable*/
|
||||
`else
|
||||
`define FORCEABLE
|
||||
`endif
|
||||
module t (input wire clk, output reg [31:0] cyc);
|
||||
initial cyc = 0;
|
||||
always @(posedge clk) cyc <= cyc + 1;
|
||||
|
||||
reg [4:3] var_arr [7:6][5:4] `FORCEABLE;
|
||||
//verilator lint_off ASCRANGE
|
||||
reg [3:4] var_arr_a [6:7][4:5] `FORCEABLE;
|
||||
|
||||
initial begin
|
||||
var_arr[6][4] = 2'h1; var_arr[6][5] = 2'h2;
|
||||
var_arr[7][4] = 2'h3; var_arr[7][5] = 2'h2;
|
||||
var_arr_a[6][4] = 2'h2; var_arr_a[6][5] = 2'h1;
|
||||
var_arr_a[7][4] = 2'h1; var_arr_a[7][5] = 2'h3;
|
||||
end
|
||||
|
||||
always @(posedge clk) case (cyc)
|
||||
0: begin
|
||||
`checkh(var_arr[6][4], 2'h1);
|
||||
`checkh(var_arr[6][5], 2'h2);
|
||||
`checkh(var_arr[7][4], 2'h3);
|
||||
`checkh(var_arr[7][5], 2'h2);
|
||||
`checkh(var_arr_a[6][4], 2'h2);
|
||||
`checkh(var_arr_a[6][5], 2'h1);
|
||||
`checkh(var_arr_a[7][4], 2'h1);
|
||||
`checkh(var_arr_a[7][5], 2'h3);
|
||||
end
|
||||
1: begin
|
||||
`checkh(var_arr[6][5], 2'h3);
|
||||
`checkh(var_arr_a[6][5], 2'h2);
|
||||
`checkh(var_arr[6][4], 2'h1);
|
||||
`checkh(var_arr[7][4], 2'h3);
|
||||
`checkh(var_arr_a[6][4], 2'h2);
|
||||
`checkh(var_arr_a[7][4], 2'h1);
|
||||
end
|
||||
2: begin
|
||||
`checkh(var_arr[6][5], 2'h3);
|
||||
`checkh(var_arr[7][4], 2'h2);
|
||||
`checkh(var_arr_a[6][5], 2'h2);
|
||||
`checkh(var_arr_a[7][4], 2'h3);
|
||||
end
|
||||
3: begin
|
||||
`checkh(var_arr[6][5], 2'h2);
|
||||
`checkh(var_arr[7][4], 2'h2);
|
||||
`checkh(var_arr_a[6][5], 2'h1);
|
||||
`checkh(var_arr_a[7][4], 2'h3);
|
||||
end
|
||||
4: begin
|
||||
`checkh(var_arr[6][4], 2'h1);
|
||||
`checkh(var_arr[6][5], 2'h2);
|
||||
`checkh(var_arr[7][4], 2'h3);
|
||||
`checkh(var_arr[7][5], 2'h2);
|
||||
`checkh(var_arr_a[6][4], 2'h2);
|
||||
`checkh(var_arr_a[6][5], 2'h1);
|
||||
`checkh(var_arr_a[7][4], 2'h1);
|
||||
`checkh(var_arr_a[7][5], 2'h3);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endcase
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Nikolai Kumar
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`verilator_config
|
||||
|
||||
forceable -module "*" -var "var_*"
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
%Error-UNSUPPORTED: t/t_forceable_unpacked_bad.v:8:9: Unsupported: Forcing unpacked arrays: t__DOT__unpacked
|
||||
8 | logic unpacked[1] /*verilator forceable*/;
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_forceable_unpacked_bad.v:8:8: Unsupported: Forcing unpacked arrays of non-bitwise inner type: t__DOT__unpacked
|
||||
8 | real unpacked[1] /*verilator forceable*/;
|
||||
| ^~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@
|
|||
// ======================================================================
|
||||
|
||||
module t;
|
||||
logic unpacked[1] /*verilator forceable*/;
|
||||
real unpacked[1] /*verilator forceable*/;
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.pli_filename = "t/t_forceable_unpacked.cpp"
|
||||
test.top_filename = "t/t_forceable_unpacked.v"
|
||||
|
||||
test.compile(make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=['-DCMT=1', '--exe', test.pli_filename])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.pli_filename = "t/t_forceable_unpacked.cpp"
|
||||
test.top_filename = "t/t_forceable_unpacked.v"
|
||||
|
||||
test.compile(
|
||||
make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=['--exe', test.pli_filename, test.t_dir + "/t_forceable_unpacked.vlt"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
Loading…
Reference in New Issue