diff --git a/Changes b/Changes index 7cc651b45..5b98c4b40 100644 --- a/Changes +++ b/Changes @@ -121,6 +121,7 @@ Verilator 5.045 devel * Fix time to not advance after `$finish` (#7095). * Fix associative array size() constraint generating invalid resize() call (#7103) (#7112). [Yilou Wang] * Fix circular class reference %p-printing causing infinite recursion (#7106). +* Fix too-short bit pack returning wrong value (#7111). * Fix randomize of real (#7115). [Srinivasan Venkataramanan] diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 92c1add6c..e3e4534ff 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1718,24 +1718,33 @@ static inline QData VL_PACK_Q_UQ(int obits, int lbits, const VlUnpacked& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1 + offset, + i * lbits + offset); return owp; } static inline WDataOutP VL_PACK_W_RI(int obits, int lbits, WDataOutP owp, const VlQueue& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1 + offset, + i * lbits + offset); return owp; } static inline WDataOutP VL_PACK_W_RI(int obits, int lbits, WDataOutP owp, const VlQueue& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1 + offset, + i * lbits + offset); return owp; } @@ -1769,8 +1778,11 @@ static inline WDataOutP VL_PACK_W_UI(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_W_RQ(int obits, int lbits, WDataOutP owp, const VlQueue& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WQ(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WQ(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1 + offset, + i * lbits + offset); return owp; } @@ -1787,8 +1799,11 @@ template static inline WDataOutP VL_PACK_W_RW(int obits, int lbits, WDataOutP owp, const VlQueue>& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WW(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WW(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1 + offset, + i * lbits + offset); return owp; } @@ -1796,8 +1811,10 @@ template static inline WDataOutP VL_PACK_W_UW(int obits, int lbits, WDataOutP owp, const VlUnpacked, N_Depth>& q) { VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); + if (VL_UNLIKELY(obits < q.size() * lbits)) return owp; // Though is illegal for q to be larger + const int offset = obits - q.size() * lbits; for (size_t i = 0; i < N_Depth; ++i) - _vl_insert_WW(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); + _vl_insert_WW(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1 + offset, i * lbits + offset); return owp; } diff --git a/test_regress/t/t_stream_bitqueue.v b/test_regress/t/t_stream_bitqueue.v index ea1e17ba6..973129f4f 100644 --- a/test_regress/t/t_stream_bitqueue.v +++ b/test_regress/t/t_stream_bitqueue.v @@ -48,14 +48,14 @@ module t ( /*AUTOARG*/ `checkh(bit_q[2], 1'b1); `checkh(bit_q[3], 1'b0); - bit_q = bit_q_t'(4'h3); + bit_q = bit_q_t'(4'h3); bit_qq = bit_q; `checkh(bit_qq[0], 1'b0); `checkh(bit_qq[1], 1'b0); `checkh(bit_qq[2], 1'b1); `checkh(bit_qq[3], 1'b1); - bit_q = bit_q_t'(4'h2); + bit_q = bit_q_t'(4'h2); bit_qq = bit_q_t'(bit_q); `checkh(bit_qq[0], 1'b0); `checkh(bit_qq[1], 1'b0); @@ -256,7 +256,7 @@ module t ( /*AUTOARG*/ begin byte_q_t bytq_init; byte_q_t bytq; - bit_q_t bitq; + bit_q_t bitq; bytq_init.push_back(8'h84); bytq_init.push_back(8'haa); @@ -269,8 +269,9 @@ module t ( /*AUTOARG*/ bitq = {<<8{bit_q_t'({<<{bytq}})}}; bytq = {<<8{bit_q_t'({<<{bitq}})}}; s = $sformatf("bitq=%p", bitq); - `checks(s, - "bitq='{'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1}"); + `checks( + s, + "bitq='{'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1}"); s = $sformatf("bytq=%p", bytq); `checks(s, "bytq='{'h84, 'haa}"); @@ -403,7 +404,7 @@ module t ( /*AUTOARG*/ // Test StreamR (>>) operations - fairly simple since this should maintain left-to-right order. begin - bit_q_t bitq; + bit_q_t bitq; byte_q_t bytq; bitq = {1'b1, 1'b0, 1'b1, 1'b0, 1'b1, 1'b0, 1'b1, 1'b0}; @@ -414,8 +415,9 @@ module t ( /*AUTOARG*/ bytq = {8'h84, 8'haa}; bitq = {>>{bit_q_t'({<<{bytq}})}}; s = $sformatf("bitq=%p", bitq); - `checks(s, - "bitq='{'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h0, 'h1}"); + `checks( + s, + "bitq='{'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h0, 'h1, 'h0, 'h0, 'h0, 'h0, 'h1}"); bitq = { 1'b1, @@ -452,8 +454,9 @@ module t ( /*AUTOARG*/ bytq = {8'h84, 8'haa}; bitq = {>>{bit_q_t'({>>{bytq}})}}; s = $sformatf("bitq=%p", bitq); - `checks(s, - "bitq='{'h1, 'h0, 'h0, 'h0, 'h0, 'h1, 'h0, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0}"); + `checks( + s, + "bitq='{'h1, 'h0, 'h0, 'h0, 'h0, 'h1, 'h0, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0, 'h1, 'h0}"); bitq = { 1'b1, @@ -483,6 +486,36 @@ module t ( /*AUTOARG*/ `checks(s, "bytq='{'h12, 'h34, 'h56}"); end + begin + bit wide_bits[]; + bit [1023:0] wide_stream; + // verilator lint_off ASCRANGE + bit [0:1023] wide_streamr; + // verilator lint_on ASCRANGE + + // verilog_format: off + wide_bits = '{1,0,1,0,1,0,1,1,0,0,1,1,0,0,0,1,0,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0, + 1,0,1,1,0,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,1,0,0,0,0,1,0,0,0,0,1,1, + 0,1,0,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,1,0,1,1,1,1,1, + 1,0,1,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1, + 1,0,0,0,1,0,1,0,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1, + 1,0,0,0,1,1,0,1,1,1,1,1,0,0,1,0,1,1,0,0,0,0,1,0,0,1,0,1,0,1,1,1, + 1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1,1,1, + 1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0,1,1,1,0,1,1, + 1,1,1,1,0,1,0,1,1,1,0,0,1,1,0,0}; + // verilog_format: on + + `checkh(wide_bits.size(), 432); + wide_stream = {>>bit{wide_bits}}; + `checkh(wide_stream, + 1024'hab3156d4b752f843537d68dfbf48f1f78af787ff8df2c257cd6fa7c795d300000000000000000000000000000000ffffffffa5bbf5cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000); + end + $write("*-* All Finished *-*\n"); $finish; end