diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 6aeef4f1f..cc034fcb6 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -474,16 +474,11 @@ public: }; class AstAlias final : public AstNode { // Alias statement - // All references to the LHS are treated as references to the RHS - // If both sides are wires, there's no LHS vs RHS, - // @astgen op1 := rhsp : AstNodeExpr - // @astgen op2 := lhsp : AstNodeExpr - + // @astgen op1 := itemsp : List[AstNodeExpr] // Alias operands public: - AstAlias(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + AstAlias(FileLine* fl, AstNodeExpr* itemsp) : ASTGEN_SUPER_Alias(fl) { - this->lhsp(lhsp); - this->rhsp(rhsp); + addItemsp(itemsp); } ASTGEN_MEMBERS_AstAlias; }; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 52ed254ed..617feeb96 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -205,9 +205,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { } void visit(AstAlias* nodep) override { putbs("alias "); - iterateAndNextConstNull(nodep->lhsp()); - putfs(nodep, " = "); - iterateAndNextConstNull(nodep->rhsp()); + iterateConst(nodep->itemsp()); + for (AstNode* itemp = nodep->itemsp()->nextp(); itemp; itemp = itemp->nextp()) { + putfs(nodep, " = "); + iterateConst(itemp); + } if (!m_suppressSemi) puts(";\n"); } void visit(AstAssignW* nodep) override { diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index f52f04f33..bac96e085 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -501,7 +501,9 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) { modp->addStmtsp( new AstAssignVarScope{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)}); } else { - modp->addStmtsp(new AstAlias{flp, portRef(VAccess::WRITE), pinRef(VAccess::READ)}); + AstVarRef* const aliasArgsp = portRef(VAccess::WRITE); + aliasArgsp->addNext(pinRef(VAccess::READ)); + modp->addStmtsp(new AstAlias{flp, aliasArgsp}); } // They will become the same variable, so propagate file-line and variable attributes pinRefp->varp()->fileline()->modifyStateInherit(flp); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 6eba355bb..93cccc7dc 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2311,15 +2311,18 @@ private: // No recursion, we don't want to pick up variables } void visit(AstAlias* nodep) override { // ScopeVisitor:: - // Track aliases; if we get a NODEVARREF(aliased_from) - // we'll need to replace it with a NODEVARREF(aliased_to) + // Track aliases UINFOTREE(9, nodep, "", "alias"); - AstVarRef* const lhsp = VN_AS(nodep->lhsp(), VarRef); - AstVarRef* const rhsp = VN_AS(nodep->rhsp(), VarRef); - AstVarScope* const fromVscp = lhsp->varScopep(); - AstVarScope* const toVscp = rhsp->varScopep(); - UASSERT_OBJ(fromVscp && toVscp, nodep, "Bad alias scopes"); - setAliasVarScope(fromVscp, toVscp); + AstVarScope* aliasVscp = nullptr; + for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { + AstVarScope* const vscp = VN_AS(itemp, VarRef)->varScopep(); + UASSERT_OBJ(vscp, nodep, "VarScope unset"); + if (aliasVscp) { + setAliasVarScope(aliasVscp, vscp); + } else { + aliasVscp = vscp; + } + } iterateChildren(nodep); pushDeletep(nodep->unlinkFrBack()); } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index d95df3065..a5c3c4295 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1367,12 +1367,12 @@ class TristateVisitor final : public TristateBaseVisitor { m_inAlias = true; if (m_graphing) { if (nodep->user2() & U2_GRAPHING) return; - m_alhs = true; // In AstAlias both sides should be considered as lhs + m_alhs = true; // In AstAlias all operands should be considered as lhs iterateChildren(nodep); - associateLogic(nodep->rhsp(), nodep); - associateLogic(nodep, nodep->rhsp()); - associateLogic(nodep, nodep->lhsp()); - associateLogic(nodep->lhsp(), nodep); + for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { + associateLogic(itemp, nodep); + associateLogic(nodep, itemp); + } } else { iterateChildren(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a3cf42c2d..b5c35e89b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1191,8 +1191,7 @@ class WidthVisitor final : public VNVisitor { void visit(AstAlias* nodep) override { if (!nodep->didWidthAndSet()) { - userIterate(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); - userIterate(nodep->rhsp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->itemsp(), WidthVP{SELF, BOTH}.p()); } const auto checkIfExprOk = [this](const AstNodeExpr* const exprp) { @@ -1224,16 +1223,16 @@ class WidthVisitor final : public VNVisitor { return true; }; - const bool lhsOk = checkIfExprOk(nodep->lhsp()); - const bool rhsOk = checkIfExprOk(nodep->rhsp()); - if (!lhsOk || !rhsOk) return; - - const AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep(); - const AstNodeDType* const rhsDtypep = nodep->rhsp()->dtypep(); - if (!lhsDtypep->similarDType(rhsDtypep)) { - nodep->v3error("Incompatible data types of nets used for net alias, got " - << lhsDtypep->prettyDTypeNameQ() << " and " - << rhsDtypep->prettyDTypeNameQ()); + checkIfExprOk(nodep->itemsp()); + AstNodeDType* const firstItemDtypep = nodep->itemsp()->dtypep(); + for (AstNode* itemp = nodep->itemsp()->nextp(); itemp; itemp = itemp->nextp()) { + checkIfExprOk(VN_AS(itemp, NodeExpr)); + if (!firstItemDtypep->similarDType(itemp->dtypep())) { + itemp->v3error("Incompatible data types of nets used for net alias. First operand " + "has the type " + << firstItemDtypep->prettyDTypeNameQ() << ", other has " + << itemp->dtypep()->prettyDTypeNameQ()); + } } } diff --git a/src/verilog.y b/src/verilog.y index 9ce8432bd..d13541859 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2639,11 +2639,8 @@ initial_construct: // IEEE: initial_construct net_alias: // IEEE: net_alias yALIAS variable_lvalue aliasEqList ';' - { if ($3->nextp()) { - BBUNSUP($1, "Unsupported: alias statements with more than 2 operands"); - $3->nextp()->unlinkFrBackWithNext()->deleteTree(); - } - $$ = new AstAlias{$1, $2, $3}; } + { $2->addNext($3); + $$ = new AstAlias{$1, $2}; } ; aliasEqList: // IEEE: part of net_alias diff --git a/test_regress/t/t_alias_ports_unsup.out b/test_regress/t/t_alias_ports_unsup.out index be00e3e0d..bd1f948a5 100644 --- a/test_regress/t/t_alias_ports_unsup.out +++ b/test_regress/t/t_alias_ports_unsup.out @@ -1,10 +1,10 @@ -%Error-UNSUPPORTED: t/t_alias_ports_unsup.v:38:13: Unsupported: Port as alias argument: 'b' - : ... note: In instance 't.s' - 38 | alias a = b; - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_alias_ports_unsup.v:38:9: Unsupported: Port as alias argument: 'a' : ... note: In instance 't.s' 38 | alias a = b; | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_alias_ports_unsup.v:38:13: Unsupported: Port as alias argument: 'b' + : ... note: In instance 't.s' + 38 | alias a = b; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_alias_transitive_unsup.py b/test_regress/t/t_alias_transitive.py similarity index 83% rename from test_regress/t/t_alias_transitive_unsup.py rename to test_regress/t/t_alias_transitive.py index f093111b2..4f09ae982 100755 --- a/test_regress/t/t_alias_transitive_unsup.py +++ b/test_regress/t/t_alias_transitive.py @@ -9,8 +9,10 @@ import vltest_bootstrap -test.scenarios('vlt') +test.scenarios('simulator') -test.lint(fails=True, expect_filename=test.golden_filename) +test.compile() + +test.execute() test.passes() diff --git a/test_regress/t/t_alias_transitive_unsup.v b/test_regress/t/t_alias_transitive.v similarity index 90% rename from test_regress/t/t_alias_transitive_unsup.v rename to test_regress/t/t_alias_transitive.v index 8433cf263..a38298417 100644 --- a/test_regress/t/t_alias_transitive_unsup.v +++ b/test_regress/t/t_alias_transitive.v @@ -22,6 +22,8 @@ module t ( /*AUTOARG*/ `ifdef TEST_VERBOSE $write("a = %x, b = %x, c = %x\n", a, b, c); `endif + if (a != 32'hdeadbeef) $stop; + if (b != 32'hdeadbeef) $stop; if (c != 32'hdeadbeef) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_alias_transitive_unsup.out b/test_regress/t/t_alias_transitive_unsup.out deleted file mode 100644 index 2c18a132b..000000000 --- a/test_regress/t/t_alias_transitive_unsup.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_alias_transitive_unsup.v:19:3: Unsupported: alias statements with more than 2 operands - 19 | alias a = b = c; - | ^~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_alias_unsup.out b/test_regress/t/t_alias_unsup.out index d7188e25b..9424d5085 100644 --- a/test_regress/t/t_alias_unsup.out +++ b/test_regress/t/t_alias_unsup.out @@ -1,6 +1,6 @@ -%Error-UNSUPPORTED: t/t_alias_unsup.v:50:35: Unsupported: Operand of alias statement is not a variable reference - : ... note: In instance 't.swap_bwd_i' - 50 | alias {a[7:0], a[15:8], a[23:16], a[31:24]} = b; +%Error-UNSUPPORTED: t/t_alias_unsup.v:76:35: Unsupported: Operand of alias statement is not a variable reference + : ... note: In instance 't.test2' + 76 | alias {a[7:0], a[15:8], a[23:16], a[31:24]} = b; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_alias_unsup.v b/test_regress/t/t_alias_unsup.v index d5d019e4d..ba96a9bb3 100644 --- a/test_regress/t/t_alias_unsup.v +++ b/test_regress/t/t_alias_unsup.v @@ -6,43 +6,69 @@ // any use, without warranty, 2013 by Jeremy Bennett. // SPDX-License-Identifier: CC0-1.0 +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + module t ( /*AUTOARG*/ // Inputs clk ); input clk; + + int cyc; + reg [63:0] crc; + reg [63:0] sum; + // Values to swap and locations for the swapped values. - wire [31:0] x_fwd = 32'hdeadbeef; + wire [31:0] x_fwd = crc[31:0]; wire [31:0] y_fwd; wire [31:0] x_bwd; - wire [31:0] y_bwd = 32'hfeedface; + wire [31:0] y_bwd = crc[63:32]; - swap swap_fwd_i ( + Test test1 ( .a(x_fwd), .b(y_fwd) ); - swap swap_bwd_i ( + + Test test2 ( .a(x_bwd), .b(y_bwd) ); + // Test loop always @(posedge clk) begin `ifdef TEST_VERBOSE - $write("x_fwd = %x, y_fwd = %x\n", x_fwd, y_fwd); - $write("x_bwd = %x, y_bwd = %x\n", x_bwd, y_bwd); + $write("[%0t] cyc==%0d crc=%x x_fwd=%x y_bwd=%x\n", $time, cyc, crc, x_fwd, y_bwd); `endif - if (y_fwd != 32'hefbeadde) $stop; - if (x_bwd != 32'hcefaedfe) $stop; - $write("*-* All Finished *-*\n"); - $finish; + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + sum <= {x_fwd, y_bwd} ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end else if (cyc < 10) begin + sum <= '0; + end else + if (cyc < 90) begin + end else if (cyc == 99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); + `checkh(crc, 64'hc77bb9b3784ea091); + // What checksum will we end up with (above print should match) + `checkh(sum, 64'h5a3868140accd91d); + $write("*-* All Finished *-*\n"); + $finish; + end end endmodule - // Swap the byte order of two args. -module swap ( +module Test ( inout wire [31:0] a, inout wire [31:0] b ); diff --git a/test_regress/t/t_alias_width_bad.out b/test_regress/t/t_alias_width_bad.out index 59f540e3b..a41cd1f61 100644 --- a/test_regress/t/t_alias_width_bad.out +++ b/test_regress/t/t_alias_width_bad.out @@ -1,6 +1,6 @@ -%Error: t/t_alias_width_bad.v:18:3: Incompatible data types of nets used for net alias, got 'logic[1:0]' and 'logic[2:0]' - : ... note: In instance 't' +%Error: t/t_alias_width_bad.v:18:13: Incompatible data types of nets used for net alias. First operand has the type 'logic[1:0]', other has 'logic[2:0]' + : ... note: In instance 't' 18 | alias a = b; - | ^~~~~ + | ^ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to