From 38895f8f29bbf1673890fcc4c9671f588c47e6a4 Mon Sep 17 00:00:00 2001 From: Jaeuk Lee <126692701+skku970412@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:41:40 +0900 Subject: [PATCH] Fix $display accepting streaming concat arguments (#7663) (#7890) Fixes #7663. --- docs/CONTRIBUTORS | 2 + src/V3Width.cpp | 94 ++++++++++++++++------ test_regress/t/t_display_stream_bad.out | 47 +++++++++++ test_regress/t/t_display_stream_bad.py | 16 ++++ test_regress/t/t_display_stream_bad.v | 31 +++++++ test_regress/t/t_stream_queue.v | 93 +++++++++++---------- test_regress/t/t_stream_queue_interface.sv | 10 ++- 7 files changed, 221 insertions(+), 72 deletions(-) create mode 100644 test_regress/t/t_display_stream_bad.out create mode 100755 test_regress/t/t_display_stream_bad.py create mode 100644 test_regress/t/t_display_stream_bad.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 62f8d0bc3..2305ce3a9 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -110,6 +110,8 @@ Ilya Barkov Iru Cai Ivan Vnučec Iztok Jeras +JAEUK LEE +Jaeuk Lee (이재욱) Jake Merdich Jakub Michalski Jakub Wasilewski diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 5eeaf2205..30cefa53c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -109,6 +109,12 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) { return str << s_det[rhs]; } +enum StreamUse : uint8_t { + STREAM_USE_NONE, // Stream concatenation is not allowed in this context + STREAM_USE_ASSIGN, // Assignment-like context permits stream concatenation + STREAM_USE_CAST, // Explicit cast context permits stream concatenation +}; + #define v3widthWarn(lhs, rhs, msg) \ v3warnCode(((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ @@ -122,21 +128,26 @@ class WidthVP final { // Parameters to pass down hierarchy with visit functions. AstNodeDType* const m_dtypep; // Parent's data type to resolve to const Stage m_stage; // If true, report errors + const StreamUse m_streamUse; // Current expression may be a stream concat + public: - WidthVP(AstNodeDType* dtypep, Stage stage) + WidthVP(AstNodeDType* dtypep, Stage stage, StreamUse streamUse = STREAM_USE_NONE) : m_dtypep{dtypep} - , m_stage{stage} { + , m_stage{stage} + , m_streamUse{streamUse} { // Prelim doesn't look at assignments, so shouldn't need a dtype, // however AstPattern uses them } - WidthVP(Determ determ, Stage stage) + WidthVP(Determ determ, Stage stage, StreamUse streamUse = STREAM_USE_NONE) : m_dtypep{nullptr} - , m_stage{stage} { + , m_stage{stage} + , m_streamUse{streamUse} { if (determ != SELF && stage != PRELIM) v3fatalSrc("Context-determined width request only allowed as prelim step"); } WidthVP* p() { return this; } bool selfDtm() const { return m_dtypep == nullptr; } + StreamUse streamUse() const { return m_streamUse; } AstNodeDType* dtypep() const { // Detect where overrideDType is probably the intended call UASSERT(m_dtypep, "Width dtype request on self-determined or preliminary VUP"); @@ -255,6 +266,12 @@ class WidthVisitor final : public VNVisitor { EXTEND_OFF // No extension }; + static StreamUse streamUseForDeterm(Determ determ) { + return determ == ASSIGN ? STREAM_USE_ASSIGN : STREAM_USE_NONE; + } + + StreamUse currentStreamUse() const { return m_vup ? m_vup->streamUse() : STREAM_USE_NONE; } + static void packIfUnpacked(AstNodeExpr* const nodep) { if (AstUnpackArrayDType* const unpackDTypep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) { const int elementsNum = unpackDTypep->arrayUnpackedElements(); @@ -969,6 +986,15 @@ class WidthVisitor final : public VNVisitor { nodep->dtypeSetInteger(); } } + bool streamImplicitUseAllowed(const AstNodeStream* nodep) const { + if (m_streamConcat) return true; + if (m_vup && m_vup->streamUse() != STREAM_USE_NONE) return true; + + const AstNode* const backp = nodep->backp(); + if (!backp) return true; // Error elsewhere + + return VN_IS(backp, NodeAssign); + } void visit(AstNodeStream* nodep) override { VL_RESTORER(m_streamConcat); // UINFOTREE(1, nodep, "stream-in vup" << m_vup, "stream-in "); @@ -1002,6 +1028,12 @@ class WidthVisitor final : public VNVisitor { } } if (m_vup->final()) { + if (!streamImplicitUseAllowed(nodep)) { + nodep->v3error( + "Streaming concatenation cannot be used in an implicitly cast context " + "(IEEE 1800-2023 11.4.17)\n" + << nodep->warnMore() << "... Suggest use a cast"); + } if (!nodep->dtypep()->widthSized()) { // See also error in V3Number nodeForUnsizedWarning(nodep)->v3warn( @@ -2071,25 +2103,25 @@ class WidthVisitor final : public VNVisitor { void visit(AstCvtPackString* nodep) override { if (nodep->didWidthAndSet()) return; // Opaque returns, so arbitrary - userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH, currentStreamUse()}.p()); // Type set in constructor } void visit(AstCvtPackedToArray* nodep) override { if (nodep->didWidthAndSet()) return; // Opaque returns, so arbitrary - userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p()); // Type set in constructor } void visit(AstCvtArrayToArray* nodep) override { if (nodep->didWidthAndSet()) return; // Opaque returns, so arbitrary - userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p()); // Type set in constructor } void visit(AstCvtArrayToPacked* nodep) override { if (nodep->didWidthAndSet()) return; // Opaque returns, so arbitrary - userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p()); // Type set in constructor } void visit(AstCvtUnpackedToQueue* nodep) override { @@ -2712,7 +2744,7 @@ class WidthVisitor final : public VNVisitor { VL_DO_DANGLING(fromp->deleteTree(), fromp); } } - userIterateAndNext(nodep->fromp(), WidthVP{SELF, PRELIM}.p()); + userIterateAndNext(nodep->fromp(), WidthVP{SELF, PRELIM, STREAM_USE_CAST}.p()); UINFOTREE(9, nodep, "", "CastDit"); AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump(); AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); @@ -2815,7 +2847,7 @@ class WidthVisitor final : public VNVisitor { if (m_vup->final()) { UINFOTREE(9, nodep, "", "CastFPit"); iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, nodep->fromp()->dtypep(), - EXTEND_EXP, false); + EXTEND_EXP, false, STREAM_USE_CAST); UINFOTREE(9, nodep, "", "CastFin"); AstNodeExpr* const underp = nodep->fromp()->unlinkFrBack(); underp->dtypeFrom(nodep); @@ -2838,7 +2870,7 @@ class WidthVisitor final : public VNVisitor { nodep->v3error("Size-changing cast to zero or negative size: " << width); width = 1; } - userIterateAndNext(nodep->lhsp(), WidthVP{SELF, PRELIM}.p()); + userIterateAndNext(nodep->lhsp(), WidthVP{SELF, PRELIM, STREAM_USE_CAST}.p()); castSized(nodep, nodep->lhsp(), width); // lhsp may change } if (m_vup->final()) { @@ -2851,7 +2883,7 @@ class WidthVisitor final : public VNVisitor { } void visit(AstCastWrap* nodep) override { // Inserted by V3Width only so we know has been resolved - userIterateAndNext(nodep->lhsp(), WidthVP{nodep->dtypep(), BOTH}.p()); + userIterateAndNext(nodep->lhsp(), WidthVP{nodep->dtypep(), BOTH, STREAM_USE_CAST}.p()); } void castSized(AstNode* nodep, AstNode* underp, int width) { const AstBasicDType* underDtp = VN_CAST(underp->dtypep(), BasicDType); @@ -2872,7 +2904,7 @@ class WidthVisitor final : public VNVisitor { nodep->dtypep(calcDtp); // We ignore warnings as that is sort of the point of a cast iterateCheck(nodep, "Cast expr", underp, CONTEXT_DET, FINAL, calcDtp, EXTEND_EXP, - false); + false, STREAM_USE_CAST); VL_DANGLING(underp); underp = nodep->op1p(); // Above asserts that op1 was underp pre-relink } @@ -7534,7 +7566,7 @@ class WidthVisitor final : public VNVisitor { // Output args: at return caller = callee, reverse direction. checkClassAssign(nodep, "Function Argument", pinp, portDTypep, portp->direction() == VDirection::OUTPUT); - userIterate(pinp, WidthVP{portDTypep, FINAL}.p()); + userIterate(pinp, WidthVP{portDTypep, FINAL, STREAM_USE_ASSIGN}.p()); } else { iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portDTypep); } @@ -9203,7 +9235,7 @@ class WidthVisitor final : public VNVisitor { AstNode* iterateCheck(AstNode* parentp, const char* side, AstNode* underp, Determ determ, Stage stage, AstNodeDType* expDTypep, ExtendRule extendRule, - bool warnOn = true) { + bool warnOn = true, StreamUse streamUse = STREAM_USE_NONE) { // Perform data type check on underp, which is underneath parentp used for error reporting // Returns the new underp // Conversion to/from doubles and integers are before iterating. @@ -9211,30 +9243,37 @@ class WidthVisitor final : public VNVisitor { UASSERT_OBJ(underp, parentp, "Node has no child"); UASSERT_OBJ(underp->dtypep(), underp, "Node has no type"); // Perhaps forgot to do a prelim visit on it? + const StreamUse childStreamUse + = streamUse != STREAM_USE_NONE ? streamUse : streamUseForDeterm(determ); if (VN_IS(underp, NodeDType)) { // Note the node itself, not node's data type // Must be near top of these checks as underp->dtypep() will look normal underp->v3error(ucfirst(parentp->prettyOperatorName()) << " expected non-datatype " << side << " but " << underp->prettyNameQ() << " is a datatype."); } else if (expDTypep == underp->dtypep()) { // Perfect - underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{expDTypep, FINAL, childStreamUse}.p()); } else if (expDTypep->isDouble() && underp->isDouble()) { // Also good - underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{expDTypep, FINAL, childStreamUse}.p()); } else if (expDTypep->isDouble() && !underp->isDouble()) { AstNode* const oldp = underp; // Need FINAL on children; otherwise splice would block it spliceCvtD(VN_AS(underp, NodeExpr)); - underp = userIterateSubtreeReturnEdits(oldp, WidthVP{SELF, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + oldp, WidthVP{SELF, FINAL, childStreamUse}.p()); } else if (!expDTypep->isDouble() && underp->isDouble()) { AstNode* const oldp = underp; // Need FINAL on children; otherwise splice would block it spliceCvtS(VN_AS(underp, NodeExpr), true, expDTypep->width()); // Round RHS - underp = userIterateSubtreeReturnEdits(oldp, WidthVP{SELF, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + oldp, WidthVP{SELF, FINAL, childStreamUse}.p()); } else if (expDTypep->isString() && !underp->dtypep()->isString()) { AstNode* const oldp = underp; // Need FINAL on children; otherwise splice would block it spliceCvtString(VN_AS(underp, NodeExpr)); - underp = userIterateSubtreeReturnEdits(oldp, WidthVP{SELF, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + oldp, WidthVP{SELF, FINAL, childStreamUse}.p()); } else { const AstBasicDType* const expBasicp = expDTypep->basicp(); const AstBasicDType* const underBasicp = underp->dtypep()->basicp(); @@ -9262,7 +9301,8 @@ class WidthVisitor final : public VNVisitor { // is e.g. an ADD, the ADD will auto-adjust to the proper data type // or if another operation e.g. ATOI will not. if (determ == SELF) { - underp = userIterateSubtreeReturnEdits(underp, WidthVP{SELF, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{SELF, FINAL, childStreamUse}.p()); } else if (determ == ASSIGN) { // IEEE: Signedness is solely determined by the RHS // (underp), not by the LHS (expDTypep) @@ -9274,9 +9314,11 @@ class WidthVisitor final : public VNVisitor { VSigning::fromBool(underp->isSigned())); UINFO(9, "Assignment of opposite-signed RHS to LHS: " << parentp); } - underp = userIterateSubtreeReturnEdits(underp, WidthVP{subDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{subDTypep, FINAL, childStreamUse}.p()); } else { - underp = userIterateSubtreeReturnEdits(underp, WidthVP{subDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{subDTypep, FINAL, childStreamUse}.p()); } // Note the check uses the expected size, not the child's subDTypep as we want the // child node's width to end up correct for the assignment (etc) @@ -9315,11 +9357,13 @@ class WidthVisitor final : public VNVisitor { << " interface modport on " << side << " but got " << underIfaceRefp->modportp()->prettyNameQ() << " modport."); } else { - underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{expDTypep, FINAL, childStreamUse}.p()); } } else { // Hope it just works out (perhaps a cast will deal with it) - underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); + underp = userIterateSubtreeReturnEdits( + underp, WidthVP{expDTypep, FINAL, childStreamUse}.p()); } } return underp; diff --git a/test_regress/t/t_display_stream_bad.out b/test_regress/t/t_display_stream_bad.out new file mode 100644 index 000000000..bf7c19963 --- /dev/null +++ b/test_regress/t/t_display_stream_bad.out @@ -0,0 +1,47 @@ +%Error: t/t_display_stream_bad.v:19:15: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 19 | result = {<<{value}} + 1; + | ^~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_display_stream_bad.v:20:23: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 20 | result = value + {<<{value}}; + | ^~ +%Error: t/t_display_stream_bad.v:21:26: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 21 | result = value[0] ? {<<{value}} : other; + | ^~ +%Error: t/t_display_stream_bad.v:22:16: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 22 | result = {{<<{value}}}; + | ^~ +%Error: t/t_display_stream_bad.v:23:14: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 23 | flag = ({<<{value}} == other); + | ^~ +%Error: t/t_display_stream_bad.v:24:15: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 24 | $display({<<{value}}); + | ^~ +%Error: t/t_display_stream_bad.v:25:22: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 25 | $display("%0d", {<<{value}}); + | ^~ +%Error: t/t_display_stream_bad.v:26:29: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 26 | void'($sformatf("%0d", {<<{value}})); + | ^~ +%Error: t/t_display_stream_bad.v:27:27: Streaming concatenation cannot be used in an implicitly cast context (IEEE 1800-2023 11.4.17) + : ... note: In instance 't' + : ... Suggest use a cast + 27 | result = passthrough({<<{value}} + 1); + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_display_stream_bad.py b/test_regress/t/t_display_stream_bad.py new file mode 100755 index 000000000..38cf36b43 --- /dev/null +++ b/test_regress/t/t_display_stream_bad.py @@ -0,0 +1,16 @@ +#!/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('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_display_stream_bad.v b/test_regress/t/t_display_stream_bad.v new file mode 100644 index 000000000..6fe7bd0db --- /dev/null +++ b/test_regress/t/t_display_stream_bad.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +module t; + int value = 1; + int other = 2; + int result; + bit flag; + + function automatic int passthrough(input int arg); + return arg; + endfunction + + initial begin + result = passthrough({<<{value}}); + result = {<<{value}} + 1; + result = value + {<<{value}}; + result = value[0] ? {<<{value}} : other; + result = {{<<{value}}}; + flag = ({<<{value}} == other); + $display({<<{value}}); + $display("%0d", {<<{value}}); + void'($sformatf("%0d", {<<{value}})); + result = passthrough({<<{value}} + 1); + result = int'({<<{value}}); + result = int'({<<{value}}) + 1; + end +endmodule diff --git a/test_regress/t/t_stream_queue.v b/test_regress/t/t_stream_queue.v index 7e6b333b9..54bba0cb0 100644 --- a/test_regress/t/t_stream_queue.v +++ b/test_regress/t/t_stream_queue.v @@ -6,6 +6,13 @@ `define stop $stop `define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%h' exp='%h'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks_w(width,gotv,expv) do begin \ + logic [(width)-1:0] got_check; \ + logic [(width)-1:0] exp_check; \ + got_check = (gotv); \ + exp_check = (expv); \ + `checks(got_check, exp_check) \ +end while(0); module t; logic [7:0] i_char; @@ -69,8 +76,8 @@ module t; byte_pkt = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = byte_pkt; - `checks({>>{byte_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); - `checks({i_header,i_len,i_crc,i_data},{<<8{byte_pkt}}); + `checks_w(128, {>>{byte_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{<<8{byte_pkt}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); // //----------- SData QUEUE -------- @@ -95,7 +102,7 @@ module t; sdata_pkt = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = sdata_pkt; - `checks({>>{sdata_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{sdata_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- IData QUEUE -------- @@ -111,7 +118,7 @@ module t; int_pkt = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = int_pkt; - `checks({>>{int_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- QData QUEUE -------- @@ -130,7 +137,7 @@ module t; qdata_pkt = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = qdata_pkt; - `checks({>>{qdata_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{qdata_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); // ----------- VLWide QUEUE -------- @@ -143,7 +150,7 @@ module t; /* verilator lint_off WIDTHEXPAND */ wide129 = {<<8{i_header,i_len,i_crc,i_data}}; - `checks({>>{vlwide_pkt_129}},wide129); + `checks_w(129, {>>{vlwide_pkt_129}},wide129); /* verilator lint_on WIDTHEXPAND */ //------------------------------- REVERSE ENDIAN ------------------------------ @@ -167,8 +174,8 @@ module t; byte_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = byte_pkt_rev; - `checks({>>{byte_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); - `checks({i_header,i_len,i_crc,i_data},{<<8{byte_pkt_rev}}); + `checks_w(128, {>>{byte_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{<<8{byte_pkt_rev}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- SData QUEUE -------- @@ -188,7 +195,7 @@ module t; sdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = sdata_pkt_rev; - `checks({>>{sdata_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{sdata_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- IData QUEUE -------- @@ -204,7 +211,7 @@ module t; int_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = int_pkt_rev; - `checks({>>{int_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- QData QUEUE -------- @@ -218,7 +225,7 @@ module t; qdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; {<<8{o_header,o_len,o_crc,o_data}} = qdata_pkt_rev; - `checks({>>{qdata_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{qdata_pkt_rev}},{<<8{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); // ----------- VLWide QUEUE -------- @@ -227,7 +234,7 @@ module t; /* verilator lint_off WIDTHEXPAND */ wide129 = {<<8{i_header,i_len,i_crc,i_data}}; /* verilator lint_on WIDTHEXPAND */ - `checks({>>{vlwide_pkt_129_rev}},wide129); + `checks_w(129, {>>{vlwide_pkt_129_rev}},wide129); // // -------------------- STREAMR ------------------------------------ // //----------- CData QUEUE -------- @@ -237,21 +244,21 @@ module t; byte_pkt = {>>{i_header,i_len}}; {>>{o_header,o_len}} = byte_pkt; - `checks({>>{i_header,i_len}},{>>{o_header,o_len}}); + `checks_w(64, {>>{i_header,i_len}},{>>{o_header,o_len}}); `checks({i_header,i_len},{o_header,o_len}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; {>>{o_header,o_len,o_crc,o_data}} = byte_pkt; - `checks({>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- IData QUEUE -------- int_pkt = {>>{i_header}}; o_header = {>>{int_pkt}}; `checks(o_header,i_header); - `checks(o_header,{>>{int_pkt}}); - `checks({>>{o_header}},{>>{int_pkt}}); + `checks_w(32, o_header,{>>{int_pkt}}); + `checks_w(32, {>>{o_header}},{>>{int_pkt}}); //test with QData int_pkt = {>>{i_header,i_len}}; @@ -261,7 +268,7 @@ module t; int_pkt = {>>{i_header,i_len,i_crc,i_data}}; {>>{o_header,o_len,o_crc,o_data}} = int_pkt; - `checks({>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //----------- QData QUEUE -------- @@ -274,7 +281,7 @@ module t; qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; {>>{o_header,o_len,o_crc,o_data}} = qdata_pkt; - `checks({>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); // ----------- VLWide QUEUE -------- @@ -288,84 +295,84 @@ module t; vlwide_pkt_129 = {>>{i_header,i_len,i_crc,i_data}}; {>>{o_header,o_len,o_crc,o_data}} = vlwide_pkt_129; - `checks({>>{vlwide_pkt_129}},{>>{1'b0,i_header,i_len,i_crc,i_data}}); + `checks_w(129, {>>{vlwide_pkt_129}},{>>{1'b0,i_header,i_len,i_crc,i_data}}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data}); //---------- into other queues ------ int_pkt = {>>{i_header,i_len,i_crc,i_data}}; byte_pkt = {>>{int_pkt}}; - `checks({>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{byte_pkt}}; - `checks({>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{byte_pkt}}; - `checks({>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); sdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; byte_pkt = {>>{sdata_pkt}}; - `checks({>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; sdata_pkt = {>>{byte_pkt}}; - `checks({>>{sdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{sdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; qdata_pkt = {>>{byte_pkt}}; - `checks({>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; byte_pkt = {>>{qdata_pkt}}; - `checks({>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{qdata_pkt}}; - `checks({>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); int_pkt = {>>{i_header,i_len,i_crc,i_data}}; qdata_pkt = {>>{int_pkt}}; - `checks({>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; vlwide_pkt_128 = {>>{byte_pkt}}; - `checks({>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); vlwide_pkt_128 = {>>{i_header,i_len,i_crc,i_data}}; byte_pkt = {>>{vlwide_pkt_128}}; - `checks({i_header,i_len,i_crc,i_data},{>>{byte_pkt}}); - `checks({>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{>>{byte_pkt}}); + `checks_w(128, {>>{byte_pkt}},{>>{i_header,i_len,i_crc,i_data}}); int_pkt = {>>{i_header,i_len,i_crc,i_data}}; vlwide_pkt_128 = {>>{int_pkt}}; - `checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); - `checks({>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); + `checks_w(128, {>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); vlwide_pkt_128 = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{vlwide_pkt_128}}; - `checks({i_header,i_len,i_crc,i_data},{>>{int_pkt}}); - `checks({>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{>>{int_pkt}}); + `checks_w(128, {>>{int_pkt}},{>>{i_header,i_len,i_crc,i_data}}); qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; vlwide_pkt_128 = {>>{qdata_pkt}}; - `checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); - `checks({>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); + `checks_w(128, {>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}}); qdata_pkt = {>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data}}; vlwide_pkt_128 = {>>{qdata_pkt}}; - `checks({i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); - `checks({>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data}}); + `checks_w(256, {i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); + `checks_w(256, {>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data}}); qdata_pkt = {>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc}}; vlwide_pkt_128 = {>>{qdata_pkt}}; - `checks({32'h0,i_header,i_len,i_crc,i_data,i_header,i_len,i_crc},{>>{vlwide_pkt_128}}); - `checks({>>{vlwide_pkt_128}},{>>{32'h0,i_header,i_len,i_crc,i_data,i_header,i_len,i_crc}}); + `checks_w(256, {32'h0,i_header,i_len,i_crc,i_data,i_header,i_len,i_crc},{>>{vlwide_pkt_128}}); + `checks_w(256, {>>{vlwide_pkt_128}},{>>{32'h0,i_header,i_len,i_crc,i_data,i_header,i_len,i_crc}}); vlwide_pkt_128 = {>>{i_header,i_len,i_crc,i_data}}; qdata_pkt = {>>{vlwide_pkt_128}}; - `checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); - `checks({>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); + `checks_w(128, {i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); + `checks_w(128, {>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}}); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_stream_queue_interface.sv b/test_regress/t/t_stream_queue_interface.sv index 290a174d7..f043f8e6d 100644 --- a/test_regress/t/t_stream_queue_interface.sv +++ b/test_regress/t/t_stream_queue_interface.sv @@ -21,15 +21,17 @@ module t; pkt_if pkt_if_init (clk); //this will not compile without -fno-life initial begin - byte byte_pkt[$]; + byte byte_pkt[$]; + byte got_pkt; //---------------------- STREAM WITH INTERFACE ------------------- //using this forces verilator to a AstSel Node into a Stream Node #0 //make sure we dont optimize it all away in v3life pkt_if_init.s.extra = 8'hd; byte_pkt = {>>{pkt_if_init.s.extra}}; - if(8'hd == {>>{byte_pkt}}) begin - $write("*-* All Finished *-*\n"); - $finish(); + got_pkt = {>>{byte_pkt}}; + if (8'hd == got_pkt) begin + $write("*-* All Finished *-*\n"); + $finish(); end end