diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index e5f399df8..12064f09d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -105,6 +105,7 @@ Jamey Hicks Jamie Iles Jan Van Winkel Jean Berniolles +Jean-Nicolas Strauss Jens Yuechao Liu Jeremy Bennett Jesse Taube diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 39858ea1f..b3ae523fa 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -8175,6 +8175,25 @@ class WidthVisitor final : public VNVisitor { } else if (pinp && pinp->modVarp()->direction() != VDirection::INPUT) { // V3Inst::pinReconnectSimple must deal UINFO(5, "pinInSizeMismatch: " << pinp); + } else if (assignp && VN_IS(underp, NodeStream) + && expWidth > underp->width()) { + // IEEE 1800-2023 11.4.14: When assigning a stream to a wider fixed-size + // target, widen by filling zero bits on the right. That is, left-justify + // the stream bits within the target width. + // Build: ShiftL(Extend(stream, expWidth), expWidth - streamWidth) + UINFO(5, "Widen NodeStream RHS with left-justify per 11.4.14"); + VNRelinker linker; + const int shift = expWidth - underp->width(); + underp->unlinkFrBack(&linker); + AstExtend* const widenedp = new AstExtend{underp->fileline(), underp}; + widenedp->didWidth(true); + // Shift left so zeros fill on the right + AstNodeExpr* const shiftedp = new AstShiftL{ + underp->fileline(), widenedp, + new AstConst{underp->fileline(), static_cast(shift)}, expWidth}; + // Final dtype should match expected + shiftedp->dtypep(expDTypep); + linker.relink(shiftedp); } else { VL_DO_DANGLING(fixWidthExtend(underp, expDTypep, extendRule), underp); } diff --git a/test_regress/t/t_stream_unpack_wider.v b/test_regress/t/t_stream_unpack_wider.v index e63ff89bd..0b3ce11de 100644 --- a/test_regress/t/t_stream_unpack_wider.v +++ b/test_regress/t/t_stream_unpack_wider.v @@ -18,6 +18,10 @@ module t; logic [7:0] dst_2; // 8 bits wide target logic [7:0] exp_2; // 8 bits wide target + logic [7:0] src_3 = 8'hA5; // 8 bits wide source + logic [27:0] dst_3; // 28 bits wide target + logic [27:0] exp_3; // 28 bits wide target + string expv; string gotv; @@ -49,6 +53,24 @@ module t; gotv = $sformatf("%p", dst_2); `checks(gotv, expv); + // unpack as source, StreamL + // verilator lint_off WIDTHEXPAND + dst_3 = {<<{src_3}}; + // verilator lint_on WIDTHEXPAND + exp_3 = 28'hA500000; + expv = $sformatf("%p", exp_3); + gotv = $sformatf("%p", dst_3); + `checks(gotv, expv); + + // unpack as source, StreamR + // verilator lint_off WIDTHEXPAND + dst_3 = {>>{src_3}}; + // verilator lint_on WIDTHEXPAND + exp_3 = 28'hA500000; + expv = $sformatf("%p", exp_3); + gotv = $sformatf("%p", dst_3); + `checks(gotv, expv); + $write("*-* All Finished *-*\n"); $finish; end