diff --git a/Changes b/Changes index d791fd4b7..763307976 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix $isunknown with constant Z's. +**** Fix queues and dynamic array wide ops. (#2352) [Vassilis Papaefstathiou] + * Verilator 4.034 2020-05-03 diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 430fe2d51..189e5d51f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -48,6 +48,7 @@ Tim Snyder Tobias Rosenkranz Tobias Wölfel Todd Strader +Vassilis Papaefstathiou Veripool API Bot Wilson Snyder Yossi Nivin diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index be35cc98f..54ec0e621 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -304,13 +304,7 @@ public: AstAssocArrayDType* adtypep = VN_CAST(nodep->fromp()->dtypep(), AssocArrayDType); UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type"); if (adtypep->keyDTypep()->isWide()) { - // Container class must take non-C-array (pointer) argument, so convert - putbs("VL_CVT_W_A("); - iterateAndNextNull(nodep->bitp()); - puts(", "); - iterateAndNextNull(nodep->fromp()); - putbs(".atDefault()"); // Not accessed; only to get the proper type of values - puts(")"); + emitCvtWideArray(nodep->bitp(), nodep->fromp()); } else { iterateAndNextNull(nodep->bitp()); } @@ -351,10 +345,21 @@ public: bool comma = false; for (AstNode* subnodep = nodep->pinsp(); subnodep; subnodep = subnodep->nextp()) { if (comma) puts(", "); - iterate(subnodep); + // handle wide arguments to the queues + if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) { + emitCvtWideArray(subnodep, nodep->fromp()); + } else { + iterate(subnodep); + } comma = true; } puts(")"); + // if there is a return value that is wide convert to array + if (nodep->dtypep()->isWide() + && (VN_IS(nodep->fromp()->dtypep(), QueueDType) + || VN_IS(nodep->fromp()->dtypep(), DynArrayDType))) { + puts(".data()"); // Access returned std::array as C array + } // Some are statements some are math. if (nodep->isStatement()) puts(";\n"); UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, @@ -1041,6 +1046,14 @@ public: puts(")"); } } + void emitCvtWideArray(AstNode* nodep, AstNode* fromp) { + putbs("VL_CVT_W_A("); + iterate(nodep); + puts(", "); + iterate(fromp); + putbs(".atDefault()"); // Not accessed; only to get the proper type of values + puts(")"); + } void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) { // Put out constant set to the specified variable, or given variable in a string if (nodep->num().isFourState()) { @@ -1638,17 +1651,22 @@ class EmitCImp : EmitCStmts { AstBasicDType* basicp = dtypep->basicp(); // Returns string to do resetting, empty to do nothing (which caller should handle) if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) { - string cvtarray - = (adtypep->subDTypep()->isWide() ? ".data()" - : ""); // Access std::array as C array + // Access std::array as C array + string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()" + cvtarray); } else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) { return ""; // Constructor does it } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()"); + // Access std::array as C array + string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + ".atDefault()" + cvtarray); } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()"); + // Access std::array as C array + string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); + return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, + ".atDefault()" + cvtarray); } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp, "Should have swapped msb & lsb earlier."); diff --git a/test_regress/t/t_dynarray.v b/test_regress/t/t_dynarray.v index 584707bb0..166cc48f3 100644 --- a/test_regress/t/t_dynarray.v +++ b/test_regress/t/t_dynarray.v @@ -27,6 +27,15 @@ module t (/*AUTOARG*/ byte_t a[]; byte_t b[]; + // wide data array + typedef struct packed { + logic [15:0] header; + logic [223:0] payload; + logic [15:0] checksum; + } pck256_t; + + pck256_t p256[]; + always @ (posedge clk) begin cyc <= cyc + 1; begin @@ -100,6 +109,33 @@ module t (/*AUTOARG*/ `checkh(b[1], 0); `checkh(b[2], 0); `checkh(b[4], 0); + + // test wide dynamic array + p256 = new [11]; + `checkh(p256.size, 11); + `checkh(p256.size(), 11); + + p256[1].header = 16'hcafe; + p256[1].payload = {14{16'hbabe}}; + p256[1].checksum = 16'hdead; + `checkh(p256[1].header, 16'hcafe); + `checkh(p256[1], {16'hcafe,{14{16'hbabe}},16'hdead}); + + `checkh(p256[0], '0); + + p256[5] = '1; + `checkh(p256[5], {32{8'hff}}); + + p256[5].header = 16'h2; + `checkh(p256[5], {16'h2,{30{8'hff}}}); + + p256[2] = ( p256[5].header == 2 ) ? p256[1] : p256[5]; + `checkh(p256[2], {16'hcafe,{14{16'hbabe}},16'hdead}); + + + p256.delete(); + `checkh(p256.size, 0); + end $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_queue.v b/test_regress/t/t_queue.v index ad9d3966a..a51ed63fe 100644 --- a/test_regress/t/t_queue.v +++ b/test_regress/t/t_queue.v @@ -195,6 +195,45 @@ module t (/*AUTOARG*/ end + // testing a wide queue + begin + typedef struct packed { + bit [7:0] opcode; + bit [23:0] addr; + bit [127:0] data; + } instructionW; // named structure type + + instructionW inst_push; + instructionW inst_pop; + + instructionW q[$]; + `checkh($dimensions(q), 2); + + `checkh(q[0].opcode, 0); + `checkh(q[0].addr, 0); + `checkh(q[0].data, 0); + + inst_push.opcode = 1; + inst_push.addr = 42; + inst_push.data = {4{32'hdeadbeef}}; + q.push_back(inst_push); + `checkh(q[0].opcode, 1); + `checkh(q[0].addr, 42); + `checkh(q[0].data, {4{32'hdeadbeef}}); + + + inst_pop = q.pop_front(); + `checkh(inst_pop.opcode, 1); + `checkh(inst_pop.addr, 42); + `checkh(inst_pop.data, {4{32'hdeadbeef}}); + + `checkh(q.size(), 0); + + `checkh(q[0].opcode, 0); + `checkh(q[0].addr, 0); + `checkh(q[0].data, 0); + end + /* Unsup: begin int q[4][$];