From 59dc2853e3bc899a079a1022fd955329b41cd769 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 3 Jun 2022 21:32:13 -0400 Subject: [PATCH] Support concat assignment to packed array (#3446). --- Changes | 5 ++-- src/V3AstNodes.h | 1 + src/V3Width.cpp | 31 ++++++++++++++++++-- test_regress/t/t_concat_unpack.pl | 21 ++++++++++++++ test_regress/t/t_concat_unpack.v | 36 ++++++++++++++++++++++++ test_regress/t/t_unpacked_concat_bad.out | 19 +------------ 6 files changed, 91 insertions(+), 22 deletions(-) create mode 100755 test_regress/t/t_concat_unpack.pl create mode 100755 test_regress/t/t_concat_unpack.v diff --git a/Changes b/Changes index bfbc7dc92..53560e563 100644 --- a/Changes +++ b/Changes @@ -20,10 +20,11 @@ Verilator 4.223 devel * Add -f options to replace -O options (#3436). * Changed --no-merge-const-pool to -fno-merge-const-pool (#3436). * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] -* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] -* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] * Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] +* Support concat assignment to packed array (#3446). * Improve conditional merging optimization (#3125). [Geza Lore, Shunyao CAD] +* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] +* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 404eff633..118666c0b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -8538,6 +8538,7 @@ public: AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc + void addItemsp(AstNode* nodep) { addOp2p(nodep); } }; class AstPatMember final : public AstNodeMath { // Verilog '{a} or '{a{b}} diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 69cee08f6..15bdf6f33 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -504,6 +504,7 @@ private: // width: LHS + RHS AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); userIterate(vdtypep, WidthVP(SELF, BOTH).p()); + // Conversions if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* const newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -521,6 +522,16 @@ private: userIterateChildren(newp, m_vup); return; } + if (VN_IS(vdtypep, UnpackArrayDType)) { + auto* const newp = new AstPattern{nodep->fileline(), nullptr}; + patConcatConvertRecurse(newp, nodep); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterate(newp, m_vup); + return; + } + + // Concat handling if (m_vup->prelim()) { if (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // @@ -662,7 +673,8 @@ private: } AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); - if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)) { + if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType) + || VN_IS(vdtypep, UnpackArrayDType)) { if (times != 1) nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form " << vdtypep->prettyDTypeNameQ() @@ -674,7 +686,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, UnpackArrayDType)) { + if (VN_IS(vdtypep, AssocArrayDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() << " data type"); } @@ -6231,6 +6243,21 @@ private: return patmap; } + void patConcatConvertRecurse(AstPattern* patternp, AstConcat* nodep) { + if (AstConcat* lhsp = VN_CAST(nodep->lhsp(), Concat)) { + patConcatConvertRecurse(patternp, lhsp); + } else { + patternp->addItemsp(new AstPatMember{nodep->lhsp()->fileline(), + nodep->lhsp()->unlinkFrBack(), nullptr, nullptr}); + } + if (AstConcat* rhsp = VN_CAST(nodep->rhsp(), Concat)) { + patConcatConvertRecurse(patternp, rhsp); + } else { + patternp->addItemsp(new AstPatMember{nodep->rhsp()->fileline(), + nodep->rhsp()->unlinkFrBack(), nullptr, nullptr}); + } + } + void makeOpenArrayShell(AstNodeFTaskRef* nodep) { UINFO(4, "Replicate openarray function " << nodep->taskp() << endl); AstNodeFTask* const oldTaskp = nodep->taskp(); diff --git a/test_regress/t/t_concat_unpack.pl b/test_regress/t/t_concat_unpack.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_concat_unpack.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 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 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_concat_unpack.v b/test_regress/t/t_concat_unpack.v new file mode 100755 index 000000000..8d3f4bac2 --- /dev/null +++ b/test_regress/t/t_concat_unpack.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + wire [31:0] arr [0:7]; + assign arr[0:7] = { + {16'hffff, 16'h0000}, + {16'h0000, 16'h0000}, + {16'h0a0a, 16'h0000}, + {16'ha0a0, 16'h0000}, + {16'hffff, 16'h0000}, + {16'h0000, 16'h0000}, + {16'h0a0a, 16'h0000}, + {16'ha0a0, 16'h0000} + }; + + int cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 9) begin + if (arr[0] !== 32'hffff0000) $stop; + if (arr[7] !== 32'ha0a00000) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index 4c89adfe6..1482e7507 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -1,23 +1,6 @@ -%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type +%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Non-1 replication to form 'bit[31:0]$[1:0]' data type : ... In instance t 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:17:47: Unsized numbers/parameters not allowed in replications. - : ... In instance t - 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; - | ^~~~~ - ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. -%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:18:45: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^ -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:18:46: Unsized numbers/parameters not allowed in concatenations. - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^~~~~ -%Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:18:60: Unsized numbers/parameters not allowed in replications. - : ... In instance t - 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; - | ^ %Error: Exiting due to