From 25f72e43053d1f2a5770811c927b46f5e336df9b Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 16 Dec 2025 08:35:59 +0100 Subject: [PATCH] Support force assignments to unpacked array elements of simple types (partial #4735) (#6787) --- src/V3Force.cpp | 236 ++++++++++++++++++---- test_regress/t/t_force_unpacked.py | 18 ++ test_regress/t/t_force_unpacked.v | 66 ++++++ test_regress/t/t_force_unpacked_unsup.out | 17 ++ test_regress/t/t_force_unpacked_unsup.py | 16 ++ test_regress/t/t_force_unpacked_unsup.v | 91 +++++++++ 6 files changed, 403 insertions(+), 41 deletions(-) create mode 100755 test_regress/t/t_force_unpacked.py create mode 100644 test_regress/t/t_force_unpacked.v create mode 100644 test_regress/t/t_force_unpacked_unsup.out create mode 100755 test_regress/t/t_force_unpacked_unsup.py create mode 100644 test_regress/t/t_force_unpacked_unsup.v diff --git a/src/V3Force.cpp b/src/V3Force.cpp index e27eee7ac..7adb42d15 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -54,6 +54,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // Convert force/release statements and signals marked 'forceable' class ForceState final { + constexpr static int ELEMENTS_MAX = 1000; // TYPES struct ForceComponentsVar final { AstVar* const m_rdVarp; // New variable to replace read references with @@ -64,9 +65,8 @@ class ForceState final { varp->dtypep()}} , m_valVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforceVal", varp->dtypep()}} - , m_enVarp{new AstVar{ - varp->fileline(), VVarType::VAR, varp->name() + "__VforceEn", - (ForceState::isRangedDType(varp) ? varp->dtypep() : varp->findBitDType())}} { + , m_enVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforceEn", + getEnVarpDTypep(varp)}} { m_rdVarp->addNext(m_enVarp); m_rdVarp->addNext(m_valVarp); varp->addNextHere(m_rdVarp); @@ -88,24 +88,70 @@ public: FileLine* const flp = vscp->fileline(); - { // Add initialization of the enable signal - AstVarRef* const lhsp = new AstVarRef{flp, m_enVscp, VAccess::WRITE}; - V3Number zero{m_enVscp, m_enVscp->width()}; - zero.setAllBits0(); - AstNodeExpr* const rhsp = new AstConst{flp, zero}; - AstAssign* const assignp = new AstAssign{flp, lhsp, rhsp}; - AstActive* const activep = new AstActive{ - flp, "force-init", - new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Static{}}}}; - activep->senTreeStorep(activep->sentreep()); + // Add initialization of the enable signal + AstActive* const activeInitp = new AstActive{ + flp, "force-init", new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Static{}}}}; + activeInitp->senTreeStorep(activeInitp->sentreep()); + vscp->scopep()->addBlocksp(activeInitp); - activep->addStmtsp(new AstInitial{flp, assignp}); - vscp->scopep()->addBlocksp(activep); + AstVarRef* const enRefp = new AstVarRef{flp, m_enVscp, VAccess::WRITE}; + + AstNodeStmt* toInsertp = nullptr; + AstNodeStmt* outerStmtp = nullptr; + std::vector loopVarRefs; + if (VN_IS(enRefp->dtypep()->skipRefp(), UnpackArrayDType)) { + // Create a loop to set all elements of __VforceEn array to 0. + // That loop node is then copied and used for updating elements of __VforceRd array + if (AstUnpackArrayDType* const unpackedp + = VN_CAST(m_rdVscp->varp()->dtypep(), UnpackArrayDType)) { + std::vector dims = unpackedp->unpackDimensions(); + loopVarRefs.reserve(dims.size()); + for (size_t i = 0; i < dims.size(); i++) { + AstVar* const loopVarp = new AstVar{ + flp, VVarType::MODULETEMP, + m_rdVscp->varp()->name() + "__VwhileIter" + std::to_string(i), + VFlagBitPacked{}, 32}; + m_rdVscp->varp()->addNext(loopVarp); + AstVarScope* const loopVarScopep + = new AstVarScope{flp, m_rdVscp->scopep(), loopVarp}; + m_rdVscp->addNext(loopVarScopep); + AstVarRef* const readRefp + = new AstVarRef{flp, loopVarScopep, VAccess::READ}; + loopVarRefs.push_back(readRefp); + AstNodeStmt* const currInitp + = new AstAssign{flp, new AstVarRef{flp, loopVarScopep, VAccess::WRITE}, + new AstConst{flp, 0}}; + if (toInsertp) { + toInsertp->addNextHere(currInitp); + } else { + outerStmtp = currInitp; + } + AstLoop* const currWhilep = new AstLoop{flp}; + currInitp->addNextHere(currWhilep); + AstLoopTest* const loopTestp = new AstLoopTest{ + flp, currWhilep, + new AstNeq{flp, readRefp, + new AstConst{ + flp, static_cast(dims[i]->elementsConst())}}}; + currWhilep->addStmtsp(loopTestp); + toInsertp = loopTestp; + AstAssign* const currIncrp = new AstAssign{ + flp, new AstVarRef{flp, loopVarScopep, VAccess::WRITE}, + new AstAdd{flp, readRefp->cloneTree(false), new AstConst{flp, 1}}}; + currWhilep->addStmtsp(currIncrp); + } + } } + V3Number zero{m_enVscp, m_enVscp->width()}; + AstNodeExpr* const enRhsp = new AstConst{flp, zero}; + AstNodeExpr* enLhsp = applySelects(enRefp, loopVarRefs); + AstNodeStmt* stmtp = new AstAssign{flp, enLhsp, enRhsp}; + if (toInsertp) { + toInsertp->addNextHere(stmtp); + stmtp = outerStmtp; + } + activeInitp->addStmtsp(new AstInitial{flp, stmtp->cloneTree(true)}); { // Add the combinational override - AstVarRef* const lhsp = new AstVarRef{flp, m_rdVscp, VAccess::WRITE}; - AstNodeExpr* const rhsp = forcedUpdate(vscp); - // Explicitly list dependencies for update. // Note: rdVscp is also needed to retrigger assignment for the first time. AstSenItem* const itemsp = new AstSenItem{ @@ -120,25 +166,49 @@ public: AstActive* const activep = new AstActive{flp, "force-update", new AstSenTree{flp, itemsp}}; activep->senTreeStorep(activep->sentreep()); - activep->addStmtsp(new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, - new AstAssign{flp, lhsp, rhsp}}); + + // Reuse the statements created for __VforceEn initialization + // and replace var ref on the LHS and the RHS + AstVarRef* const rdRefp = new AstVarRef{flp, m_rdVscp, VAccess::WRITE}; + AstNodeExpr* const rdRhsp = forcedUpdate(vscp, loopVarRefs); + enRefp->replaceWith(rdRefp); + VL_DO_DANGLING(enRefp->deleteTree(), enRefp); + enRhsp->replaceWith(rdRhsp); + VL_DO_DANGLING(enRhsp->deleteTree(), enRhsp); + + activep->addStmtsp(new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, stmtp}); vscp->scopep()->addBlocksp(activep); } } - AstNodeExpr* forcedUpdate(AstVarScope* const vscp) const { + static AstNodeExpr* applySelects(AstNodeExpr* exprp, + const std::vector& selectExprs) { + for (AstNodeExpr* const sp : selectExprs) { + exprp = new AstArraySel{exprp->fileline(), exprp, sp->cloneTreePure(false)}; + } + return exprp; + } + AstNodeExpr* forcedUpdate(AstVarScope* const vscp, + const std::vector& selectExprs) const { FileLine* const flp = vscp->fileline(); - AstVarRef* const origp = new AstVarRef{flp, vscp, VAccess::READ}; - ForceState::markNonReplaceable(origp); + AstVarRef* origRefp = new AstVarRef{flp, vscp, VAccess::READ}; + ForceState::markNonReplaceable(origRefp); + AstNodeExpr* const origp = applySelects(origRefp, selectExprs); if (ForceState::isRangedDType(vscp)) { return new AstOr{ flp, - new AstAnd{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}, - new AstVarRef{flp, m_valVscp, VAccess::READ}}, - new AstAnd{flp, new AstNot{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}}, - origp}}; + new AstAnd{ + flp, + applySelects(new AstVarRef{flp, m_enVscp, VAccess::READ}, selectExprs), + applySelects(new AstVarRef{flp, m_valVscp, VAccess::READ}, selectExprs)}, + new AstAnd{ + flp, + new AstNot{flp, applySelects(new AstVarRef{flp, m_enVscp, VAccess::READ}, + selectExprs)}, + origp}}; } - return new AstCond{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}, - new AstVarRef{flp, m_valVscp, VAccess::READ}, origp}; + return new AstCond{ + flp, applySelects(new AstVarRef{flp, m_enVscp, VAccess::READ}, selectExprs), + applySelects(new AstVarRef{flp, m_valVscp, VAccess::READ}, selectExprs), origp}; } }; @@ -147,6 +217,7 @@ private: // AstVar::user1p -> ForceComponentsVar* instance (via m_forceComponentsVar) // AstVarScope::user1p -> ForceComponentsVarScope* instance (via m_forceComponentsVarScope) // AstVarRef::user2 -> Flag indicating not to replace reference + // AstAssign::user2 -> Flag indicating that assignment was created for AstRelease // AstVarScope::user3p -> AstAssign*, the assignment __VforceVal = const VNUser1InUse m_user1InUse; const VNUser2InUse m_user2InUse; @@ -158,6 +229,46 @@ private: m_valVscps; // `valVscp` force components of a forced RHS + static AstNodeDType* getEnVarpDTypep(AstVar* const varp) { + AstNodeDType* const origDTypep = varp->dtypep()->skipRefp(); + if (VN_IS(origDTypep, UnpackArrayDType)) { + size_t elemNum = 1; + AstNodeDType* dtp = origDTypep; + while (AstUnpackArrayDType* const uDtp = VN_CAST(dtp, UnpackArrayDType)) { + dtp = uDtp->subDTypep()->skipRefp(); + elemNum *= uDtp->elementsConst(); + } + if (elemNum > ELEMENTS_MAX) { + varp->v3warn(E_UNSUPPORTED, "Unsupported: Force of unpacked array variable with " + ">= " + << ELEMENTS_MAX << " elements"); + } + bool complexElem = true; + if (AstBasicDType* const basicp = VN_CAST(dtp, BasicDType)) { + complexElem = basicp->isOpaque(); + } + if (complexElem) { + varp->v3warn(E_UNSUPPORTED, "Unsupported: Force of unpacked array variable with " + "elements of complex data type"); + } + return origDTypep; + } else if (VN_IS(origDTypep, BasicDType)) { + return isRangedDType(varp) ? origDTypep : varp->findBitDType(); + } else if (VN_IS(origDTypep, PackArrayDType)) { + return origDTypep; + } else if (const AstNodeUOrStructDType* const sdtp + = VN_CAST(origDTypep, NodeUOrStructDType)) { + if (!sdtp->packed()) { + varp->v3warn(E_UNSUPPORTED, + "Unsupported: Force of unpacked struct / union variable"); + } + return origDTypep; + } else { + varp->v3fatalSrc("Unsupported: Force of variable of unhandled data type"); + return origDTypep; + } + } + public: // CONSTRUCTORS ForceState() = default; @@ -292,6 +403,7 @@ class ForceConvertVisitor final : public VNVisitor { // the continuous assignment's scheduling region. AstAssign* const resetRdp = new AstAssign{flp, lhsp->cloneTreePure(false), lhsp->unlinkFrBack()}; + resetRdp->user2(true); // Replace write refs on the LHS resetRdp->lhsp()->foreach([this](AstVarRef* refp) { if (refp->access() != VAccess::WRITE) return; @@ -304,17 +416,39 @@ class ForceConvertVisitor final : public VNVisitor { } }); // Replace write refs on RHS - resetRdp->rhsp()->foreach([this](AstVarRef* refp) { - if (refp->access() != VAccess::WRITE) return; - AstVarScope* const vscp = refp->varScopep(); - if (vscp->varp()->isContinuously()) { - refp->access(VAccess::READ); - ForceState::markNonReplaceable(refp); - } else { - refp->replaceWith(m_state.getForceComponents(vscp).forcedUpdate(vscp)); - VL_DO_DANGLING(refp->deleteTree(), refp); + if (VN_IS(resetRdp->rhsp(), ArraySel)) { + std::vector selIndices; + AstNodeExpr* exprp = resetRdp->rhsp(); + while (AstArraySel* const selp = VN_CAST(exprp, ArraySel)) { + selIndices.push_back(selp->bitp()); + exprp = selp->fromp(); } - }); + if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) { + AstVarScope* const vscp = refp->varScopep(); + std::vector reversedIndices(selIndices.size()); + std::reverse_copy(selIndices.begin(), selIndices.end(), reversedIndices.begin()); + AstNodeExpr* const origRhsp = resetRdp->rhsp(); + origRhsp->replaceWith( + m_state.getForceComponents(vscp).forcedUpdate(vscp, reversedIndices)); + VL_DO_DANGLING(origRhsp->deleteTree(), origRhsp); + } else { + exprp->v3warn( + E_UNSUPPORTED, + "Unsupported: Release statement argument is too complex array select"); + } + } else { + resetRdp->rhsp()->foreach([this](AstVarRef* refp) { + if (refp->access() != VAccess::WRITE) return; + AstVarScope* const vscp = refp->varScopep(); + if (vscp->varp()->isContinuously()) { + refp->access(VAccess::READ); + ForceState::markNonReplaceable(refp); + } else { + refp->replaceWith(m_state.getForceComponents(vscp).forcedUpdate(vscp, {})); + VL_DO_DANGLING(refp->deleteTree(), refp); + } + }); + } resetRdp->addNext(resetEnp); relinker.relink(resetRdp); @@ -344,6 +478,8 @@ class ForceReplaceVisitor final : public VNVisitor { const ForceState& m_state; AstNodeStmt* m_stmtp = nullptr; bool m_inLogic = false; + bool m_releaseRhs = false; // Inside RHS of assignment created for release statement + std::vector m_selIndices; // Indices of array select expressions above // METHODS void iterateLogic(AstNode* logicp) { @@ -358,6 +494,14 @@ class ForceReplaceVisitor final : public VNVisitor { m_stmtp = nodep; iterateChildren(nodep); } + void visit(AstAssign* nodep) override { + VL_RESTORER(m_stmtp); + VL_RESTORER(m_releaseRhs); + m_stmtp = nodep; + iterate(nodep->lhsp()); + m_releaseRhs = nodep->user2(); + iterate(nodep->rhsp()); + } void visit(AstCFunc* nodep) override { iterateLogic(nodep); } void visit(AstCoverToggle* nodep) override { iterateLogic(nodep); } void visit(AstNodeProcedure* nodep) override { iterateLogic(nodep); } @@ -371,6 +515,12 @@ class ForceReplaceVisitor final : public VNVisitor { iterateLogic(nodep); } void visit(AstSenItem* nodep) override { iterateLogic(nodep); } + void visit(AstArraySel* nodep) override { + m_selIndices.push_back(nodep->bitp()); + iterateChildren(nodep); + UASSERT_OBJ(m_selIndices.size(), nodep, "Underflow"); + m_selIndices.pop_back(); + } void visit(AstVarRef* nodep) override { if (ForceState::isNotReplaceable(nodep)) return; @@ -390,8 +540,12 @@ class ForceReplaceVisitor final : public VNVisitor { if (ForceState::ForceComponentsVarScope* const fcp = m_state.tryGetForceComponents(nodep)) { FileLine* const flp = nodep->fileline(); - AstVarRef* const lhsp = new AstVarRef{flp, fcp->m_rdVscp, VAccess::WRITE}; - AstNodeExpr* const rhsp = fcp->forcedUpdate(nodep->varScopep()); + std::vector reversedIndices(m_selIndices.size()); + std::reverse_copy(m_selIndices.begin(), m_selIndices.end(), + reversedIndices.begin()); + AstNodeExpr* const lhsp = ForceState::ForceComponentsVarScope::applySelects( + new AstVarRef{flp, fcp->m_rdVscp, VAccess::WRITE}, reversedIndices); + AstNodeExpr* const rhsp = fcp->forcedUpdate(nodep->varScopep(), reversedIndices); m_stmtp->addNextHere(new AstAssign{flp, lhsp, rhsp}); } // Emit valVscp update after each write to any VarRef on forced RHS. diff --git a/test_regress/t/t_force_unpacked.py b/test_regress/t/t_force_unpacked.py new file mode 100755 index 000000000..d4f986441 --- /dev/null +++ b/test_regress/t/t_force_unpacked.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_force_unpacked.v b/test_regress/t/t_force_unpacked.v new file mode 100644 index 000000000..5bf44ed78 --- /dev/null +++ b/test_regress/t/t_force_unpacked.v @@ -0,0 +1,66 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`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) +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t ( /*AUTOARG*/ + // Inputs + clk +); + input clk; + + integer cyc = 0; + + logic logic_arr[2][-2:2][-3:-5]; + int int_arr[-1:2][1][3]; + + // Test loop + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + logic_arr[0][2][-4] <= 1; + int_arr[0][0][2] <= 1; + end + else if (cyc == 1) begin + `checkh(logic_arr[0][2][-4], 1); + `checkh(int_arr[0][0][2], 1); + end + else if (cyc == 2) begin + force logic_arr[0][2][-4] = 0; + force int_arr[0][0][2] = 0; + end + else if (cyc == 3) begin + `checkh(logic_arr[0][2][-4], 0); + logic_arr[0][2][-4] <= 1; + `checkh(int_arr[0][0][2], 0); + int_arr[0][0][2] <= 1; + end + else if (cyc == 4) begin + `checkh(logic_arr[0][2][-4], 0); + `checkh(int_arr[0][0][2], 0); + end + else if (cyc == 5) begin + release logic_arr[0][2][-4]; + release int_arr[0][0][2]; + end + else if (cyc == 6) begin + `checkh(logic_arr[0][2][-4], 0); + logic_arr[0][2][-4] <= 1; + `checkh(int_arr[0][0][2], 0); + int_arr[0][0][2] <= 1; + end + else if (cyc == 7) begin + `checkh(logic_arr[0][2][-4], 1); + `checkh(int_arr[0][0][2], 1); + end + else if (cyc == 8) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_force_unpacked_unsup.out b/test_regress/t/t_force_unpacked_unsup.out new file mode 100644 index 000000000..a770c9520 --- /dev/null +++ b/test_regress/t/t_force_unpacked_unsup.out @@ -0,0 +1,17 @@ +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:23:8: Unsupported: Force of unpacked array variable with elements of complex data type + 23 | real r_array[2]; + | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:22:7: Unsupported: Force of unpacked array variable with >= 1000 elements + 22 | bit big_array[40][40][40]; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:21:12: Unsupported: Force of unpacked array variable with >= 1000 elements + 21 | struct_t s_array[3000]; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:21:12: Unsupported: Force of unpacked array variable with elements of complex data type + 21 | struct_t s_array[3000]; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_force_unpacked_unsup.v:24:12: Unsupported: Force of unpacked struct / union variable + 24 | struct_t my_struct; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_force_unpacked_unsup.py b/test_regress/t/t_force_unpacked_unsup.py new file mode 100755 index 000000000..44c75cc0f --- /dev/null +++ b/test_regress/t/t_force_unpacked_unsup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.lint(verilator_flags2=['--timing'], fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_force_unpacked_unsup.v b/test_regress/t/t_force_unpacked_unsup.v new file mode 100644 index 000000000..ba14be968 --- /dev/null +++ b/test_regress/t/t_force_unpacked_unsup.v @@ -0,0 +1,91 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`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) +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t ( /*AUTOARG*/ + // Inputs + clk +); + input clk; + + integer cyc = 0; + + typedef struct {int x;} struct_t; + + struct_t s_array[3000]; + bit big_array[40][40][40]; + real r_array[2]; + struct_t my_struct; + + // Test loop + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + r_array[0] <= 1; + big_array[1][2][3] <= 1; + s_array[1].x <= 1; + my_struct.x <= 1; + end + else if (cyc == 1) begin + `checkr(r_array[0], 1); + `checkr(big_array[1][2][3], 1); + `checkh(s_array[1].x, 1); + `checkh(my_struct.x, 1); + end + else if (cyc == 2) begin + force r_array[0] = 0; + force big_array[1][2][3] = 0; + force s_array[1].x = 0; + force my_struct.x = 0; + end + else if (cyc == 3) begin + `checkr(r_array[0], 0); + `checkr(big_array[1][2][3], 0); + r_array[0] <= 1; + big_array[1][2][3] <= 1; + `checkh(s_array[1].x, 0); + s_array[1].x <= 1; + `checkh(my_struct.x, 0); + my_struct.x <= 1; + end + else if (cyc == 4) begin + `checkr(r_array[0], 0); + `checkr(big_array[1][2][3], 0); + `checkh(s_array[1].x, 0); + `checkh(my_struct.x, 0); + end + else if (cyc == 5) begin + release r_array[0]; + release big_array[1][2][3]; + release s_array[1].x; + release my_struct.x; + end + else if (cyc == 6) begin + `checkr(r_array[0], 0); + `checkr(big_array[1][2][3], 0); + r_array[0] <= 1; + big_array[1][2][3] <= 1; + `checkh(s_array[1].x, 0); + s_array[1].x <= 1; + `checkh(my_struct.x, 0); + my_struct.x <= 1; + end + else if (cyc == 7) begin + `checkr(r_array[0], 1); + `checkr(big_array[1][2][3], 1); + `checkh(s_array[1].x, 1); + `checkh(my_struct.x, 1); + end + else if (cyc == 8) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule