From ac06b6fc4f7bc7393ce4d77574b55df263ed8a2e Mon Sep 17 00:00:00 2001 From: Paul Swirhun <63216497+paul-demo@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:23:16 -0700 Subject: [PATCH] Fix streaming operator packing order (#5903) (#6077) --- include/verilated_funcs.h | 43 ++++++++++--------- test_regress/t/t_stream_dynamic.v | 71 +++++++++++++++++++++++++++---- test_regress/t/t_stream_unpack.v | 64 ++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 27 deletions(-) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 412549b7a..e62e9f172 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1607,19 +1607,21 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const static inline IData VL_PACK_I_RI(int obits, int lbits, const VlQueue& q) { IData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= static_cast(q.at(i)) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) + ret |= static_cast(q.at(q.size() - 1 - i)) << (i * lbits); return ret; } static inline IData VL_PACK_I_RI(int obits, int lbits, const VlQueue& q) { IData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= static_cast(q.at(i)) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) + ret |= static_cast(q.at(q.size() - 1 - i)) << (i * lbits); return ret; } static inline IData VL_PACK_I_RI(int obits, int lbits, const VlQueue& q) { IData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) ret |= q.at(q.size() - 1 - i) << (i * lbits); return ret; } @@ -1648,19 +1650,22 @@ static inline IData VL_PACK_I_UI(int obits, int lbits, const VlUnpacked& q) { QData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= static_cast(q.at(i)) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) + ret |= static_cast(q.at(q.size() - 1 - i)) << (i * lbits); return ret; } static inline QData VL_PACK_Q_RI(int obits, int lbits, const VlQueue& q) { QData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= static_cast(q.at(i)) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) + ret |= static_cast(q.at(q.size() - 1 - i)) << (i * lbits); return ret; } static inline QData VL_PACK_Q_RI(int obits, int lbits, const VlQueue& q) { QData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= static_cast(q.at(i)) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) + ret |= static_cast(q.at(q.size() - 1 - i)) << (i * lbits); return ret; } @@ -1690,7 +1695,7 @@ static inline QData VL_PACK_Q_UI(int obits, int lbits, const VlUnpacked& q) { QData ret = 0; - for (size_t i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * lbits); + for (size_t i = 0; i < q.size(); ++i) ret |= q.at(q.size() - 1 - i) << (i * lbits); return ret; } @@ -1705,7 +1710,7 @@ 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); for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1, i * lbits); return owp; } @@ -1713,7 +1718,7 @@ 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); for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - i - 1), i * lbits + lbits - 1, i * lbits); return owp; } @@ -1721,7 +1726,7 @@ 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); for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WI(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); return owp; } @@ -1756,7 +1761,7 @@ 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); for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WQ(owp, q.at(i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WQ(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); return owp; } @@ -1774,7 +1779,7 @@ 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); for (size_t i = 0; i < q.size(); ++i) - _vl_insert_WW(owp, q.at(i), i * lbits + lbits - 1, i * lbits); + _vl_insert_WW(owp, q.at(q.size() - 1 - i), i * lbits + lbits - 1, i * lbits); return owp; } @@ -2230,49 +2235,49 @@ static inline void VL_UNPACK_RI_I(int lbits, int rbits, VlQueue& q, IData const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_I(int lbits, int rbits, VlQueue& q, IData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_I(int lbits, int rbits, VlQueue& q, IData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_Q(int lbits, int rbits, VlQueue& q, QData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_Q(int lbits, int rbits, VlQueue& q, QData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_Q(int lbits, int rbits, VlQueue& q, QData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const IData mask = VL_MASK_I(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RQ_Q(int lbits, int rbits, VlQueue& q, QData from) { const size_t size = (rbits + lbits - 1) / lbits; q.renew(size); const QData mask = VL_MASK_Q(lbits); - for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask; + for (size_t i = 0; i < size; ++i) q.atWrite(q.size() - 1 - i) = (from >> (i * lbits)) & mask; } static inline void VL_UNPACK_RI_W(int lbits, int rbits, VlQueue& q, WDataInP rwp) { diff --git a/test_regress/t/t_stream_dynamic.v b/test_regress/t/t_stream_dynamic.v index 3a7c57948..e9bdc97d9 100644 --- a/test_regress/t/t_stream_dynamic.v +++ b/test_regress/t/t_stream_dynamic.v @@ -14,7 +14,7 @@ typedef enum bit [5:0] { } enum_t; module t (/*AUTOARG*/); - initial begin + task test1; bit arr[]; bit [1:0] arr2[$]; bit [5:0] arr6[$]; @@ -36,9 +36,7 @@ module t (/*AUTOARG*/); arr160 = '{2{160'h0123456789abcdef0123456789abcdef01234567}}; { >> bit {arr}} = bit6; - `checkp(arr, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); // Majority rules - // `checkp(arr, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); // VCS - + `checkp(arr, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); ans = { >> bit {arr} }; `checkh(ans, bit6); @@ -46,8 +44,7 @@ module t (/*AUTOARG*/); `checkh(ans_enum, bit6); { << bit {arr}} = bit6; - `checkp(arr, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); // Majority rules - // `checkp(arr, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); // VCS + `checkp(arr, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); ans = { << bit {arr} }; `checkh(ans, bit6); @@ -58,7 +55,7 @@ module t (/*AUTOARG*/); `ifdef VERILATOR // This set flags errors on other simulators { >> bit[1:0] {arr2}} = bit6; - `checkp(arr2, "'{'h0, 'h2, 'h3} "); + `checkp(arr2, "'{'h3, 'h2, 'h0} "); ans = { >> bit[1:0] {arr2} }; `checkh(ans, bit6); @@ -67,7 +64,7 @@ module t (/*AUTOARG*/); `checkh(ans_enum, bit6); { << bit[1:0] {arr2}} = bit6; - `checkp(arr2, "'{'h3, 'h2, 'h0} "); + `checkp(arr2, "'{'h0, 'h2, 'h3} "); ans = { << bit[1:0] {arr2} }; `checkh(ans, bit6); @@ -143,6 +140,64 @@ module t (/*AUTOARG*/); `checkh(arr160[0], 160'h67452301efcdab8967452301efcdab8967452301); { << byte {arr160} } = bit320; `checkh(arr160[0], 160'h0123456789abcdef0123456789abcdef01234567); + endtask + + task test2; + byte unpack [8]; // [0] is left-most for purposes of streaming + bit [63:0] bits; // [63] is left-most for purposes of streaming + longint word; // [63] is left-most for purposes of streaming + + // Using packed bits + $display("Test2"); + bits = {8'hfa, 8'hde, 8'hca, 8'hfe, + 8'hde, 8'had, 8'hbe, 8'hef}; + word = {>>{bits}}; + `checkh(word, 64'hfadecafedeadbeef); + word = {<<8{bits}}; + `checkh(word, 64'hefbeaddefecadefa); + + // Using byte unpacked array + unpack = '{8'hfa, 8'hde, 8'hca, 8'hfe, + 8'hde, 8'had, 8'hbe, 8'hef}; + `checkh(unpack[0], 8'hfa); + `checkh(unpack[7], 8'hef); + word = {>>{unpack}}; + `checkh(word, 64'hfadecafedeadbeef); + word = {<<8{unpack}}; + `checkh(word, 64'hefbeaddefecadefa); + endtask + + task test3; + byte dyn8 []; // [0] is left-most for purposes of streaming + longint word; // [63] is left-most for purposes of streaming + // verilator lint_off ASCRANGE + bit [0:63] rbits; // [63] is still left-most for purposes of streaming + // verilator lint_on ASCRANGE + + // Using byte dynamic array + dyn8 = new[8]('{8'hfa, 8'hde, 8'hca, 8'hfe, + 8'hde, 8'had, 8'hbe, 8'hef}); + `checkh(dyn8[0], 8'hfa); + `checkh(dyn8[7], 8'hef); + word = {>>{dyn8}}; + `checkh(word, 64'hfadecafedeadbeef); + word = {<<1{dyn8}}; + `checkh(word, 64'hf77db57b7f537b5f); + word = {<<8{dyn8}}; + `checkh(word, 64'hefbeaddefecadefa); + + rbits = {>>{dyn8}}; + `checkh(rbits, 64'hfadecafedeadbeef); + rbits = {<<1{dyn8}}; + `checkh(rbits, 64'hf77db57b7f537b5f); + rbits = {<<8{dyn8}}; + `checkh(rbits, 64'hefbeaddefecadefa); + endtask + + initial begin; + test1(); + test2(); + test3(); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_stream_unpack.v b/test_regress/t/t_stream_unpack.v index 901fc421b..b83ea9174 100644 --- a/test_regress/t/t_stream_unpack.v +++ b/test_regress/t/t_stream_unpack.v @@ -33,6 +33,14 @@ module t (/*AUTOARG*/); logic f [8]; logic [1:0][7:0] g; logic [1:0][1:0][3:0] h; + byte i []; + longint j; + int k; + int l []; + logic [127:0] m; + longint n []; + logic [255:0] o; + logic [127:0] p[]; { >> bit {arr}} = bit6; `checkp(arr, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); @@ -219,6 +227,62 @@ module t (/*AUTOARG*/); h = { << 8 {16'hABCD}}; `checkh(h, 16'hCDAB); + i = new[8]('{8'hfa, 8'hde, 8'hca, 8'hfe, + 8'hde, 8'had, 8'hbe, 8'hef}); + `checkh(i[0], 8'hfa); + `checkh(i[7], 8'hef); + j = {>>{i}}; + `checkh(j, 64'hfadecafedeadbeef); + j = {<<8{i}}; + `checkh(j, 64'hefbeaddefecadefa); + + i = new[4]('{8'hba, 8'hbe, 8'hfa, 8'hce}); + k = {>>{i}}; + `checkh(k, 32'hbabeface); + k = {<<8{i}}; + `checkh(k, 32'hcefabeba); + + i = new[8]('{8'hba, 8'hbe, 8'hfa, 8'hce, 8'hde, 8'had, 8'hbe, 8'hef}); + j = {>>{i}}; + `checkh(j, 64'hbabefacedeadbeef); + j = {<<8{i}}; + `checkh(j, 64'hefbeaddecefabeba); + + i = new[16]('{8'hba, 8'hbe, 8'hfa, 8'hce, 8'hde, 8'had, 8'hbe, 8'hef, + 8'hde, 8'had, 8'hbe, 8'hef, 8'hde, 8'had, 8'hbe, 8'hef}); + m = {>>{i}}; + `checkh(m, 128'hbabefacedeadbeefdeadbeefdeadbeef); + m = {<<8{i}}; + `checkh(m, 128'hefbeaddeefbeaddeefbeaddecefabeba); + + l = new[2]('{32'hbabeface, 32'hdeadbeef}); + j = {>>{l}}; + `checkh(j, 64'hbabefacedeadbeef); + j = {<<8{l}}; + `checkh(j, 64'hefbeaddecefabeba); + + l = new[4]('{32'hbabeface, 32'hdeadbeef, 32'hdeadbeef, 32'hdeadbeef}); + m = {>>{l}}; + `checkh(m, 128'hbabefacedeadbeefdeadbeefdeadbeef); + m = {<<8{l}}; + `checkh(m, 128'hefbeaddeefbeaddeefbeaddecefabeba); + + n = new[2]('{64'hfadecafedeadbeef, 64'habcd0123456789ab}); + m = {>>{n}}; + `checkh(m, 128'hfadecafedeadbeefabcd0123456789ab); + m = {<<64{n}}; + `checkh(m, 128'habcd0123456789abfadecafedeadbeef); + + p = new[2]('{128'hfadecafedeadbeefabcd0123456789ab, + 128'habcd0123456789abfadecafedeadbeef}); + o = {>>{p}}; + `checkh(o, 256'hfadecafedeadbeefabcd0123456789ababcd0123456789abfadecafedeadbeef); + o = {<<128{p}}; + `checkh(o, 256'habcd0123456789abfadecafedeadbeeffadecafedeadbeefabcd0123456789ab); + {>>{p}} = o; + `checkh(p[0], 128'hfadecafedeadbeefabcd0123456789ab); + `checkh(p[1], 128'habcd0123456789abfadecafedeadbeef); + $write("*-* All Finished *-*\n"); $finish; end