From 9a54b2144be9939bcec6e33f72285062f661fce9 Mon Sep 17 00:00:00 2001 From: Stefan Wallentowitz Date: Wed, 18 Dec 2019 18:17:18 -0500 Subject: [PATCH] Fix queue issues, bug1643. Signed-off-by: Wilson Snyder --- Changes | 2 +- src/V3AstNodes.cpp | 10 +++- src/V3LinkParse.cpp | 11 +++- src/V3Width.cpp | 93 +++++++++++++++++++++++--------- test_regress/t/t_queue.v | 114 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 29 deletions(-) diff --git a/Changes b/Changes index d1276caae..ea1f29613 100644 --- a/Changes +++ b/Changes @@ -22,7 +22,7 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix little endian cell ranges, bug1631. [Julien Margetts] -**** Fix queues as statements, bug1641. [Peter Monsson, Stefan Wallentowitz] +**** Fix queue issues, bug1641, bug1643. [Peter Monsson, Stefan Wallentowitz] * Verilator 4.024 2019-12-08 diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index e95e2e53e..1adc5be7d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -622,8 +622,16 @@ std::pair AstNodeDType::dimensions(bool includeBasic) { dtypep = adtypep->subDTypep(); continue; } + else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) { + unpacked++; + dtypep = qdtypep->subDTypep(); + continue; + } else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) { - if (includeBasic && adtypep->isRanged()) packed++; + if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++; + } + else if (const AstStructDType* sdtypep = VN_CAST(dtypep, StructDType)) { + packed++; } break; } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 2ca7674cc..05b16ebd8 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -392,17 +392,22 @@ private: FileLine* fl = varsp->fileline(); AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType()); - // These will be the left and right dimensions of the array: + // These will be the left and right dimensions and size of the array: AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT, new AstVarRef(fl, arrayp->name(), false), new AstConst(fl, dimension)); AstNode* rightp = new AstAttrOf(fl, AstAttrType::DIM_RIGHT, new AstVarRef(fl, arrayp->name(), false), new AstConst(fl, dimension)); + AstNode* sizep = new AstAttrOf(fl, AstAttrType::DIM_SIZE, + new AstVarRef(fl, arrayp->name(), false), + new AstConst(fl, dimension)); AstNode* stmtsp = varp; // Assign left-dimension into the loop var: stmtsp->addNext(new AstAssign (fl, new AstVarRef(fl, varp->name(), true), leftp)); + // This will turn into a constant bool for static arrays + AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0)); // This will turn into a bool constant, indicating whether // we count the loop variable up or down: AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), @@ -414,13 +419,15 @@ private: rightp->cloneTree(true)), // Left decrements down to right new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); + // This will reduce to comparep for static arrays + AstNode* condp = new AstAnd(fl, notemptyp, comparep); AstNode* incp = new AstAssign( fl, new AstVarRef(fl, varp->name(), true), new AstAdd(fl, new AstVarRef(fl, varp->name(), false), new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1)))); - stmtsp->addNext(new AstWhile(fl, comparep, newp, incp)); + stmtsp->addNext(new AstWhile(fl, condp, newp, incp)); newp = new AstBegin(nodep->fileline(), "", stmtsp); dimension--; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b1503e581..9a2a106ea 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1076,31 +1076,74 @@ private: case AstAttrType::DIM_LOW: case AstAttrType::DIM_RIGHT: case AstAttrType::DIM_SIZE: { - UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, - "Unsized expression"); - std::pair dim - = nodep->fromp()->dtypep()->skipRefp()->dimensions(true); - uint32_t msbdim = dim.first + dim.second; - if (!nodep->dimp() || msbdim < 1) { - int dim = 1; - AstConst* newp = dimensionValue(nodep->fileline(), - nodep->fromp()->dtypep(), nodep->attrType(), dim); - nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); - } else if (VN_IS(nodep->dimp(), Const)) { - int dim = VN_CAST(nodep->dimp(), Const)->toSInt(); - AstConst* newp = dimensionValue(nodep->fileline(), - nodep->fromp()->dtypep(), nodep->attrType(), dim); - nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); - } - else { // Need a runtime lookup table. Yuk. - UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, - "Unsized expression"); - AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim); - AstNode* dimp = nodep->dimp()->unlinkFrBack(); - AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); - varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); - AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp); - nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, "Unsized expression"); + if (VN_IS(nodep->fromp()->dtypep(), QueueDType)) { + switch (nodep->attrType()) { + case AstAttrType::DIM_SIZE: { + AstNode* newp = new AstCMethodCall( + nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", NULL); + newp->dtypeSetSigned32(); + newp->didWidth(true); + newp->protect(false); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + break; + } + case AstAttrType::DIM_LEFT: + case AstAttrType::DIM_LOW: { + AstNode* newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + break; + } + case AstAttrType::DIM_RIGHT: + case AstAttrType::DIM_HIGH: { + AstNode* sizep = new AstCMethodCall( + nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size", NULL); + sizep->dtypeSetSigned32(); + sizep->didWidth(true); + sizep->protect(false); + AstNode* newp + = new AstSub(nodep->fileline(), sizep, + new AstConst(nodep->fileline(), AstConst::Signed32(), 1)); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + break; + } + case AstAttrType::DIM_INCREMENT: { + AstNode* newp = new AstConst(nodep->fileline(), AstConst::Signed32(), -1); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + break; + } + case AstAttrType::DIM_BITS: { + nodep->v3error("Unsupported: $bits for queue"); + break; + } + default: nodep->v3error("Unhandled attribute type"); + } + } else { + std::pair dim + = nodep->fromp()->dtypep()->skipRefp()->dimensions(true); + uint32_t msbdim = dim.first + dim.second; + if (!nodep->dimp() || msbdim < 1) { + int dim = 1; + AstConst* newp = dimensionValue(nodep->fileline(), nodep->fromp()->dtypep(), + nodep->attrType(), dim); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } else if (VN_IS(nodep->dimp(), Const)) { + int dim = VN_CAST(nodep->dimp(), Const)->toSInt(); + AstConst* newp = dimensionValue(nodep->fileline(), nodep->fromp()->dtypep(), + nodep->attrType(), dim); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } + else { // Need a runtime lookup table. Yuk. + UASSERT_OBJ(nodep->fromp() && nodep->fromp()->dtypep(), nodep, + "Unsized expression"); + AstVar* varp + = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim); + AstNode* dimp = nodep->dimp()->unlinkFrBack(); + AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); + varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); + AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } } break; } diff --git a/test_regress/t/t_queue.v b/test_regress/t/t_queue.v index 4ef274e7e..3ec91d79c 100644 --- a/test_regress/t/t_queue.v +++ b/test_regress/t/t_queue.v @@ -20,12 +20,71 @@ module t (/*AUTOARG*/ always @ (posedge clk) begin cyc <= cyc + 1; + + begin + // Very simple test using bit + bit q[$]; + bit x; + + `checkh($left(q), 0); + `checkh($right(q), -1); + `checkh($increment(q), -1); + `checkh($low(q), 0); + `checkh($high(q), -1); + `checkh($size(q), 0); + `checkh($dimensions(q), 1); + // Unsup: `checkh($bits(q), 0); + + q.push_back(1'b1); + `checkh($left(q), 0); + `checkh($right(q), 0); + `checkh($increment(q), -1); + `checkh($low(q), 0); + `checkh($high(q), 0); + `checkh($size(q), 1); + `checkh($dimensions(q), 1); + // Unsup: `checkh($bits(q), 2); + `checkh(q.size(), 1); + + q.push_back(1'b1); + q.push_back(1'b0); + q.push_back(1'b1); + `checkh($left(q), 0); + `checkh($right(q), 3); + `checkh($low(q), 0); + `checkh($high(q), 3); + `checkh($size(q), 4); + // Unsup: `checkh($bits(q), 4); + `checkh(q.size(), 4); + + x = q.pop_back(); `checkh(x, 1'b1); + `checkh($left(q), 0); + `checkh($right(q), 2); + `checkh($low(q), 0); + `checkh($high(q), 2); + `checkh($size(q), 3); + // sure those are working now.. + + x = q.pop_front(); `checkh(x, 1'b1); + x = q.pop_front(); `checkh(x, 1'b1); + x = q.pop_front(); `checkh(x, 1'b0); + `checkh(q.size(), 0); + end + begin // Simple test using integer typedef bit [3:0] nibble_t; nibble_t q[$]; nibble_t v; + `checkh($left(q), 0); + `checkh($right(q), -1); + `checkh($increment(q), -1); + `checkh($low(q), 0); + `checkh($high(q), -1); + `checkh($size(q), 0); + `checkh($dimensions(q), 2); + i = q.size(); `checkh(i, 0); q.push_back(4'd1); // 1 q.push_front(4'd2); // 2 1 @@ -37,8 +96,22 @@ module t (/*AUTOARG*/ // Strings string q[$]; string v; + int j = 0; + + // Empty queue checks + `checkh($left(q), 0); + `checkh($right(q), -1); + `checkh($increment(q), -1); + `checkh($low(q), 0); + `checkh($high(q), -1); + `checkh($size(q), 0); + `checkh($dimensions(q), 2); + //Unsup: `checkh($bits(q), 0); q.push_front("f1"); + + //Unsup: `checkh($bits(q), 16); + q.push_back("b1"); q.push_front("f2"); q.push_back("b2"); @@ -60,12 +133,28 @@ module t (/*AUTOARG*/ //v = q[0]; `checks(v, "ins0"); //v = q[3]; `checks(v, "ins3"); + foreach (q[i]) begin + j++; + v = q[i]; + if (i == 0) `checks(v, "f2"); + if (i == 1) `checks(v, "f1"); + if (i == 2) `checks(v, "b1"); + if (i == 3) `checks(v, "b2"); + end + `checkh(j,4); + q.pop_front(); v = q.pop_front(); `checks(v, "f1"); v = q.pop_back(); `checks(v, "b2"); v = q.pop_back(); `checks(v, "b1"); i = q.size(); `checkh(i, 0); + // Empty queue, this should be 0 + foreach (q[i]) begin + j++; + end + `checkh(j,4); + q.push_front("non-empty"); i = q.size(); `checkh(i, 1); q.delete(); @@ -83,6 +172,31 @@ module t (/*AUTOARG*/ end + begin + typedef struct packed { + bit [7:0] opcode; + bit [23:0] addr; + } instruction; // named structure type + + instruction q[$]; + + `checkh($dimensions(q), 2); + //Unsup: `checkh($bits(q), 0); + + end + + /* Unsup: + begin + int q[4][$]; + + q[0].push_back(0); + q[0].push_back(1); + q[1].push_back(2); + q[2].push_back(3); + + end + */ + // See t_queue_unsup_bad for more unsupported stuff $write("*-* All Finished *-*\n");