Fix $display accepting streaming concat arguments (#7663) (#7890)

Fixes #7663.
This commit is contained in:
Jaeuk Lee 2026-07-09 21:41:40 +09:00 committed by GitHub
parent f316ec0d66
commit 38895f8f29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 221 additions and 72 deletions

View File

@ -110,6 +110,8 @@ Ilya Barkov
Iru Cai Iru Cai
Ivan Vnučec Ivan Vnučec
Iztok Jeras Iztok Jeras
JAEUK LEE
Jaeuk Lee (이재욱)
Jake Merdich Jake Merdich
Jakub Michalski Jakub Michalski
Jakub Wasilewski Jakub Wasilewski

View File

@ -109,6 +109,12 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) {
return str << s_det[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) \ #define v3widthWarn(lhs, rhs, msg) \
v3warnCode(((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ v3warnCode(((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \
: (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \
@ -122,21 +128,26 @@ class WidthVP final {
// Parameters to pass down hierarchy with visit functions. // Parameters to pass down hierarchy with visit functions.
AstNodeDType* const m_dtypep; // Parent's data type to resolve to AstNodeDType* const m_dtypep; // Parent's data type to resolve to
const Stage m_stage; // If true, report errors const Stage m_stage; // If true, report errors
const StreamUse m_streamUse; // Current expression may be a stream concat
public: public:
WidthVP(AstNodeDType* dtypep, Stage stage) WidthVP(AstNodeDType* dtypep, Stage stage, StreamUse streamUse = STREAM_USE_NONE)
: m_dtypep{dtypep} : m_dtypep{dtypep}
, m_stage{stage} { , m_stage{stage}
, m_streamUse{streamUse} {
// Prelim doesn't look at assignments, so shouldn't need a dtype, // Prelim doesn't look at assignments, so shouldn't need a dtype,
// however AstPattern uses them // however AstPattern uses them
} }
WidthVP(Determ determ, Stage stage) WidthVP(Determ determ, Stage stage, StreamUse streamUse = STREAM_USE_NONE)
: m_dtypep{nullptr} : m_dtypep{nullptr}
, m_stage{stage} { , m_stage{stage}
, m_streamUse{streamUse} {
if (determ != SELF && stage != PRELIM) if (determ != SELF && stage != PRELIM)
v3fatalSrc("Context-determined width request only allowed as prelim step"); v3fatalSrc("Context-determined width request only allowed as prelim step");
} }
WidthVP* p() { return this; } WidthVP* p() { return this; }
bool selfDtm() const { return m_dtypep == nullptr; } bool selfDtm() const { return m_dtypep == nullptr; }
StreamUse streamUse() const { return m_streamUse; }
AstNodeDType* dtypep() const { AstNodeDType* dtypep() const {
// Detect where overrideDType is probably the intended call // Detect where overrideDType is probably the intended call
UASSERT(m_dtypep, "Width dtype request on self-determined or preliminary VUP"); 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 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) { static void packIfUnpacked(AstNodeExpr* const nodep) {
if (AstUnpackArrayDType* const unpackDTypep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) { if (AstUnpackArrayDType* const unpackDTypep = VN_CAST(nodep->dtypep(), UnpackArrayDType)) {
const int elementsNum = unpackDTypep->arrayUnpackedElements(); const int elementsNum = unpackDTypep->arrayUnpackedElements();
@ -969,6 +986,15 @@ class WidthVisitor final : public VNVisitor {
nodep->dtypeSetInteger(); 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 { void visit(AstNodeStream* nodep) override {
VL_RESTORER(m_streamConcat); VL_RESTORER(m_streamConcat);
// UINFOTREE(1, nodep, "stream-in vup" << m_vup, "stream-in "); // UINFOTREE(1, nodep, "stream-in vup" << m_vup, "stream-in ");
@ -1002,6 +1028,12 @@ class WidthVisitor final : public VNVisitor {
} }
} }
if (m_vup->final()) { 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()) { if (!nodep->dtypep()->widthSized()) {
// See also error in V3Number // See also error in V3Number
nodeForUnsizedWarning(nodep)->v3warn( nodeForUnsizedWarning(nodep)->v3warn(
@ -2071,25 +2103,25 @@ class WidthVisitor final : public VNVisitor {
void visit(AstCvtPackString* nodep) override { void visit(AstCvtPackString* nodep) override {
if (nodep->didWidthAndSet()) return; if (nodep->didWidthAndSet()) return;
// Opaque returns, so arbitrary // Opaque returns, so arbitrary
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH, currentStreamUse()}.p());
// Type set in constructor // Type set in constructor
} }
void visit(AstCvtPackedToArray* nodep) override { void visit(AstCvtPackedToArray* nodep) override {
if (nodep->didWidthAndSet()) return; if (nodep->didWidthAndSet()) return;
// Opaque returns, so arbitrary // Opaque returns, so arbitrary
userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p());
// Type set in constructor // Type set in constructor
} }
void visit(AstCvtArrayToArray* nodep) override { void visit(AstCvtArrayToArray* nodep) override {
if (nodep->didWidthAndSet()) return; if (nodep->didWidthAndSet()) return;
// Opaque returns, so arbitrary // Opaque returns, so arbitrary
userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p());
// Type set in constructor // Type set in constructor
} }
void visit(AstCvtArrayToPacked* nodep) override { void visit(AstCvtArrayToPacked* nodep) override {
if (nodep->didWidthAndSet()) return; if (nodep->didWidthAndSet()) return;
// Opaque returns, so arbitrary // Opaque returns, so arbitrary
userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH, currentStreamUse()}.p());
// Type set in constructor // Type set in constructor
} }
void visit(AstCvtUnpackedToQueue* nodep) override { void visit(AstCvtUnpackedToQueue* nodep) override {
@ -2712,7 +2744,7 @@ class WidthVisitor final : public VNVisitor {
VL_DO_DANGLING(fromp->deleteTree(), fromp); 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"); UINFOTREE(9, nodep, "", "CastDit");
AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump(); AstNodeDType* const toDtp = nodep->dtypep()->skipRefToEnump();
AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
@ -2815,7 +2847,7 @@ class WidthVisitor final : public VNVisitor {
if (m_vup->final()) { if (m_vup->final()) {
UINFOTREE(9, nodep, "", "CastFPit"); UINFOTREE(9, nodep, "", "CastFPit");
iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, nodep->fromp()->dtypep(), iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, nodep->fromp()->dtypep(),
EXTEND_EXP, false); EXTEND_EXP, false, STREAM_USE_CAST);
UINFOTREE(9, nodep, "", "CastFin"); UINFOTREE(9, nodep, "", "CastFin");
AstNodeExpr* const underp = nodep->fromp()->unlinkFrBack(); AstNodeExpr* const underp = nodep->fromp()->unlinkFrBack();
underp->dtypeFrom(nodep); underp->dtypeFrom(nodep);
@ -2838,7 +2870,7 @@ class WidthVisitor final : public VNVisitor {
nodep->v3error("Size-changing cast to zero or negative size: " << width); nodep->v3error("Size-changing cast to zero or negative size: " << width);
width = 1; 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 castSized(nodep, nodep->lhsp(), width); // lhsp may change
} }
if (m_vup->final()) { if (m_vup->final()) {
@ -2851,7 +2883,7 @@ class WidthVisitor final : public VNVisitor {
} }
void visit(AstCastWrap* nodep) override { void visit(AstCastWrap* nodep) override {
// Inserted by V3Width only so we know has been resolved // 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) { void castSized(AstNode* nodep, AstNode* underp, int width) {
const AstBasicDType* underDtp = VN_CAST(underp->dtypep(), BasicDType); const AstBasicDType* underDtp = VN_CAST(underp->dtypep(), BasicDType);
@ -2872,7 +2904,7 @@ class WidthVisitor final : public VNVisitor {
nodep->dtypep(calcDtp); nodep->dtypep(calcDtp);
// We ignore warnings as that is sort of the point of a cast // We ignore warnings as that is sort of the point of a cast
iterateCheck(nodep, "Cast expr", underp, CONTEXT_DET, FINAL, calcDtp, EXTEND_EXP, iterateCheck(nodep, "Cast expr", underp, CONTEXT_DET, FINAL, calcDtp, EXTEND_EXP,
false); false, STREAM_USE_CAST);
VL_DANGLING(underp); VL_DANGLING(underp);
underp = nodep->op1p(); // Above asserts that op1 was underp pre-relink 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. // Output args: at return caller = callee, reverse direction.
checkClassAssign(nodep, "Function Argument", pinp, portDTypep, checkClassAssign(nodep, "Function Argument", pinp, portDTypep,
portp->direction() == VDirection::OUTPUT); portp->direction() == VDirection::OUTPUT);
userIterate(pinp, WidthVP{portDTypep, FINAL}.p()); userIterate(pinp, WidthVP{portDTypep, FINAL, STREAM_USE_ASSIGN}.p());
} else { } else {
iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portDTypep); 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, AstNode* iterateCheck(AstNode* parentp, const char* side, AstNode* underp, Determ determ,
Stage stage, AstNodeDType* expDTypep, ExtendRule extendRule, 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 // Perform data type check on underp, which is underneath parentp used for error reporting
// Returns the new underp // Returns the new underp
// Conversion to/from doubles and integers are before iterating. // 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, parentp, "Node has no child");
UASSERT_OBJ(underp->dtypep(), underp, UASSERT_OBJ(underp->dtypep(), underp,
"Node has no type"); // Perhaps forgot to do a prelim visit on it? "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 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 // Must be near top of these checks as underp->dtypep() will look normal
underp->v3error(ucfirst(parentp->prettyOperatorName()) underp->v3error(ucfirst(parentp->prettyOperatorName())
<< " expected non-datatype " << side << " but " << " expected non-datatype " << side << " but "
<< underp->prettyNameQ() << " is a datatype."); << underp->prettyNameQ() << " is a datatype.");
} else if (expDTypep == underp->dtypep()) { // Perfect } 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 } 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()) { } else if (expDTypep->isDouble() && !underp->isDouble()) {
AstNode* const oldp AstNode* const oldp
= underp; // Need FINAL on children; otherwise splice would block it = underp; // Need FINAL on children; otherwise splice would block it
spliceCvtD(VN_AS(underp, NodeExpr)); 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()) { } else if (!expDTypep->isDouble() && underp->isDouble()) {
AstNode* const oldp AstNode* const oldp
= underp; // Need FINAL on children; otherwise splice would block it = underp; // Need FINAL on children; otherwise splice would block it
spliceCvtS(VN_AS(underp, NodeExpr), true, expDTypep->width()); // Round RHS 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()) { } else if (expDTypep->isString() && !underp->dtypep()->isString()) {
AstNode* const oldp AstNode* const oldp
= underp; // Need FINAL on children; otherwise splice would block it = underp; // Need FINAL on children; otherwise splice would block it
spliceCvtString(VN_AS(underp, NodeExpr)); spliceCvtString(VN_AS(underp, NodeExpr));
underp = userIterateSubtreeReturnEdits(oldp, WidthVP{SELF, FINAL}.p()); underp = userIterateSubtreeReturnEdits(
oldp, WidthVP{SELF, FINAL, childStreamUse}.p());
} else { } else {
const AstBasicDType* const expBasicp = expDTypep->basicp(); const AstBasicDType* const expBasicp = expDTypep->basicp();
const AstBasicDType* const underBasicp = underp->dtypep()->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 // is e.g. an ADD, the ADD will auto-adjust to the proper data type
// or if another operation e.g. ATOI will not. // or if another operation e.g. ATOI will not.
if (determ == SELF) { if (determ == SELF) {
underp = userIterateSubtreeReturnEdits(underp, WidthVP{SELF, FINAL}.p()); underp = userIterateSubtreeReturnEdits(
underp, WidthVP{SELF, FINAL, childStreamUse}.p());
} else if (determ == ASSIGN) { } else if (determ == ASSIGN) {
// IEEE: Signedness is solely determined by the RHS // IEEE: Signedness is solely determined by the RHS
// (underp), not by the LHS (expDTypep) // (underp), not by the LHS (expDTypep)
@ -9274,9 +9314,11 @@ class WidthVisitor final : public VNVisitor {
VSigning::fromBool(underp->isSigned())); VSigning::fromBool(underp->isSigned()));
UINFO(9, "Assignment of opposite-signed RHS to LHS: " << parentp); 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 { } 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 // 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) // 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 " << " interface modport on " << side << " but got "
<< underIfaceRefp->modportp()->prettyNameQ() << " modport."); << underIfaceRefp->modportp()->prettyNameQ() << " modport.");
} else { } else {
underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); underp = userIterateSubtreeReturnEdits(
underp, WidthVP{expDTypep, FINAL, childStreamUse}.p());
} }
} else { } else {
// Hope it just works out (perhaps a cast will deal with it) // 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; return underp;

View File

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

View File

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

View File

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

View File

@ -6,6 +6,13 @@
`define stop $stop `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(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; module t;
logic [7:0] i_char; logic [7:0] i_char;
@ -69,8 +76,8 @@ module t;
byte_pkt = {<<8{i_header,i_len,i_crc,i_data}}; byte_pkt = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = byte_pkt; {<<8{o_header,o_len,o_crc,o_data}} = byte_pkt;
`checks({>>{byte_pkt}},{<<8{i_header,i_len,i_crc,i_data}}); `checks_w(128, {>>{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, {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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
// //----------- SData QUEUE -------- // //----------- SData QUEUE --------
@ -95,7 +102,7 @@ module t;
sdata_pkt = {<<8{i_header,i_len,i_crc,i_data}}; sdata_pkt = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = sdata_pkt; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- IData QUEUE -------- //----------- IData QUEUE --------
@ -111,7 +118,7 @@ module t;
int_pkt = {<<8{i_header,i_len,i_crc,i_data}}; int_pkt = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = int_pkt; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- QData QUEUE -------- //----------- QData QUEUE --------
@ -130,7 +137,7 @@ module t;
qdata_pkt = {<<8{i_header,i_len,i_crc,i_data}}; qdata_pkt = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = qdata_pkt; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
// ----------- VLWide QUEUE -------- // ----------- VLWide QUEUE --------
@ -143,7 +150,7 @@ module t;
/* verilator lint_off WIDTHEXPAND */ /* verilator lint_off WIDTHEXPAND */
wide129 = {<<8{i_header,i_len,i_crc,i_data}}; 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 */ /* verilator lint_on WIDTHEXPAND */
//------------------------------- REVERSE ENDIAN ------------------------------ //------------------------------- REVERSE ENDIAN ------------------------------
@ -167,8 +174,8 @@ module t;
byte_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; byte_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = byte_pkt_rev; {<<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_w(128, {>>{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, {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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- SData QUEUE -------- //----------- SData QUEUE --------
@ -188,7 +195,7 @@ module t;
sdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; sdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = sdata_pkt_rev; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- IData QUEUE -------- //----------- IData QUEUE --------
@ -204,7 +211,7 @@ module t;
int_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; int_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = int_pkt_rev; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- QData QUEUE -------- //----------- QData QUEUE --------
@ -218,7 +225,7 @@ module t;
qdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}}; qdata_pkt_rev = {<<8{i_header,i_len,i_crc,i_data}};
{<<8{o_header,o_len,o_crc,o_data}} = qdata_pkt_rev; {<<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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
// ----------- VLWide QUEUE -------- // ----------- VLWide QUEUE --------
@ -227,7 +234,7 @@ module t;
/* verilator lint_off WIDTHEXPAND */ /* verilator lint_off WIDTHEXPAND */
wide129 = {<<8{i_header,i_len,i_crc,i_data}}; wide129 = {<<8{i_header,i_len,i_crc,i_data}};
/* verilator lint_on WIDTHEXPAND */ /* verilator lint_on WIDTHEXPAND */
`checks({>>{vlwide_pkt_129_rev}},wide129); `checks_w(129, {>>{vlwide_pkt_129_rev}},wide129);
// // -------------------- STREAMR ------------------------------------ // // -------------------- STREAMR ------------------------------------
// //----------- CData QUEUE -------- // //----------- CData QUEUE --------
@ -237,21 +244,21 @@ module t;
byte_pkt = {>>{i_header,i_len}}; byte_pkt = {>>{i_header,i_len}};
{>>{o_header,o_len}} = byte_pkt; {>>{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}); `checks({i_header,i_len},{o_header,o_len});
byte_pkt = {>>{i_header,i_len,i_crc,i_data}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
{>>{o_header,o_len,o_crc,o_data}} = byte_pkt; {>>{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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- IData QUEUE -------- //----------- IData QUEUE --------
int_pkt = {>>{i_header}}; int_pkt = {>>{i_header}};
o_header = {>>{int_pkt}}; o_header = {>>{int_pkt}};
`checks(o_header,i_header); `checks(o_header,i_header);
`checks(o_header,{>>{int_pkt}}); `checks_w(32, o_header,{>>{int_pkt}});
`checks({>>{o_header}},{>>{int_pkt}}); `checks_w(32, {>>{o_header}},{>>{int_pkt}});
//test with QData //test with QData
int_pkt = {>>{i_header,i_len}}; int_pkt = {>>{i_header,i_len}};
@ -261,7 +268,7 @@ module t;
int_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{i_header,i_len,i_crc,i_data}};
{>>{o_header,o_len,o_crc,o_data}} = int_pkt; {>>{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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//----------- QData QUEUE -------- //----------- QData QUEUE --------
@ -274,7 +281,7 @@ module t;
qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data}};
{>>{o_header,o_len,o_crc,o_data}} = qdata_pkt; {>>{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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
// ----------- VLWide QUEUE -------- // ----------- VLWide QUEUE --------
@ -288,84 +295,84 @@ module t;
vlwide_pkt_129 = {>>{i_header,i_len,i_crc,i_data}}; vlwide_pkt_129 = {>>{i_header,i_len,i_crc,i_data}};
{>>{o_header,o_len,o_crc,o_data}} = vlwide_pkt_129; {>>{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}); `checks({o_header,o_len,o_crc,o_data} ,{i_header,i_len,i_crc,i_data});
//---------- into other queues ------ //---------- into other queues ------
int_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{i_header,i_len,i_crc,i_data}};
byte_pkt = {>>{int_pkt}}; 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}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
int_pkt = {>>{byte_pkt}}; 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}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
int_pkt = {>>{byte_pkt}}; 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}}; sdata_pkt = {>>{i_header,i_len,i_crc,i_data}};
byte_pkt = {>>{sdata_pkt}}; 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}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
sdata_pkt = {>>{byte_pkt}}; 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}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
qdata_pkt = {>>{byte_pkt}}; 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}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data}};
byte_pkt = {>>{qdata_pkt}}; 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}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data}};
int_pkt = {>>{qdata_pkt}}; 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}}; int_pkt = {>>{i_header,i_len,i_crc,i_data}};
qdata_pkt = {>>{int_pkt}}; 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}}; byte_pkt = {>>{i_header,i_len,i_crc,i_data}};
vlwide_pkt_128 = {>>{byte_pkt}}; 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}}; vlwide_pkt_128 = {>>{i_header,i_len,i_crc,i_data}};
byte_pkt = {>>{vlwide_pkt_128}}; byte_pkt = {>>{vlwide_pkt_128}};
`checks({i_header,i_len,i_crc,i_data},{>>{byte_pkt}}); `checks_w(128, {i_header,i_len,i_crc,i_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}});
int_pkt = {>>{i_header,i_len,i_crc,i_data}}; int_pkt = {>>{i_header,i_len,i_crc,i_data}};
vlwide_pkt_128 = {>>{int_pkt}}; vlwide_pkt_128 = {>>{int_pkt}};
`checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); `checks_w(128, {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, {>>{vlwide_pkt_128}},{>>{i_header,i_len,i_crc,i_data}});
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}}; int_pkt = {>>{vlwide_pkt_128}};
`checks({i_header,i_len,i_crc,i_data},{>>{int_pkt}}); `checks_w(128, {i_header,i_len,i_crc,i_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}});
qdata_pkt = {>>{i_header,i_len,i_crc,i_data}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data}};
vlwide_pkt_128 = {>>{qdata_pkt}}; vlwide_pkt_128 = {>>{qdata_pkt}};
`checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); `checks_w(128, {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, {>>{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}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc,i_data}};
vlwide_pkt_128 = {>>{qdata_pkt}}; 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_w(256, {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, {>>{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}}; qdata_pkt = {>>{i_header,i_len,i_crc,i_data,i_header,i_len,i_crc}};
vlwide_pkt_128 = {>>{qdata_pkt}}; 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_w(256, {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, {>>{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}}; vlwide_pkt_128 = {>>{i_header,i_len,i_crc,i_data}};
qdata_pkt = {>>{vlwide_pkt_128}}; qdata_pkt = {>>{vlwide_pkt_128}};
`checks({i_header,i_len,i_crc,i_data},{>>{vlwide_pkt_128}}); `checks_w(128, {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, {>>{qdata_pkt}},{>>{i_header,i_len,i_crc,i_data}});
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;

View File

@ -22,12 +22,14 @@ module t;
//this will not compile without -fno-life //this will not compile without -fno-life
initial begin initial begin
byte byte_pkt[$]; byte byte_pkt[$];
byte got_pkt;
//---------------------- STREAM WITH INTERFACE ------------------- //---------------------- STREAM WITH INTERFACE -------------------
//using this forces verilator to a AstSel Node into a Stream Node //using this forces verilator to a AstSel Node into a Stream Node
#0 //make sure we dont optimize it all away in v3life #0 //make sure we dont optimize it all away in v3life
pkt_if_init.s.extra = 8'hd; pkt_if_init.s.extra = 8'hd;
byte_pkt = {>>{pkt_if_init.s.extra}}; byte_pkt = {>>{pkt_if_init.s.extra}};
if(8'hd == {>>{byte_pkt}}) begin got_pkt = {>>{byte_pkt}};
if (8'hd == got_pkt) begin
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish(); $finish();
end end