forked from github/verilator
Support queue slicing (#2326).
This commit is contained in:
parent
ec36d0d772
commit
5d3dd52f13
2
Changes
2
Changes
@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 4.103 devel
|
||||
|
||||
**** Support queue slicing (#2326).
|
||||
|
||||
|
||||
* Verilator 4.102 2020-10-15
|
||||
|
||||
|
@ -272,6 +272,32 @@ public:
|
||||
}
|
||||
~VlQueue() {}
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
static VlQueue cons(const T_Value& lhs) {
|
||||
VlQueue out;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
|
||||
VlQueue out;
|
||||
out.push_back(rhs);
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
|
||||
VlQueue out = lhs;
|
||||
out.push_front(rhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
for (const auto& i : lhs.m_deque) out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
T_Value& atDefault() { return m_defaultValue; }
|
||||
@ -352,6 +378,15 @@ public:
|
||||
m_deque.insert(m_deque.begin() + index, value);
|
||||
}
|
||||
|
||||
// Return slice q[lsb:msb]
|
||||
VlQueue slice(size_t lsb, size_t msb) const {
|
||||
VlQueue out;
|
||||
if (VL_UNLIKELY(lsb >= m_deque.size())) lsb = m_deque.size() - 1;
|
||||
if (VL_UNLIKELY(msb >= m_deque.size())) msb = m_deque.size() - 1;
|
||||
for (size_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]);
|
||||
return out;
|
||||
}
|
||||
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_deque.begin(); }
|
||||
const_iterator end() const { return m_deque.end(); }
|
||||
|
@ -1254,7 +1254,10 @@ public:
|
||||
/// along with all children and next(s). This is often better to use
|
||||
/// than an immediate deleteTree, as any pointers into this node will
|
||||
/// persist for the lifetime of the visitor
|
||||
void pushDeletep(AstNode* nodep) { m_deleteps.push_back(nodep); }
|
||||
void pushDeletep(AstNode* nodep) {
|
||||
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
|
||||
m_deleteps.push_back(nodep);
|
||||
}
|
||||
/// Call deleteTree on all previously pushDeletep()'ed nodes
|
||||
void doDeletes();
|
||||
|
||||
|
@ -4599,6 +4599,28 @@ public:
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstConsQueue : public AstNodeMath {
|
||||
// Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs}
|
||||
// Parents: math
|
||||
// Children: expression (elements or other queues)
|
||||
public:
|
||||
AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr)
|
||||
: ASTGEN_SUPER(fl) {
|
||||
setNOp1p(lhsp);
|
||||
setNOp2p(rhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ConsQueue)
|
||||
virtual string emitVerilog() override { return "'{%l, %r}"; }
|
||||
virtual string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); }
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual int instrCount() const override { return widthInstrs(); }
|
||||
AstNode* lhsp() const { return op1p(); } // op1 = expression
|
||||
AstNode* rhsp() const { return op2p(); } // op2 = expression
|
||||
virtual V3Hash sameHash() const override { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const override { return true; }
|
||||
};
|
||||
|
||||
class AstBegin : public AstNodeBlock {
|
||||
// A Begin/end named block, only exists shortly after parsing until linking
|
||||
// Parents: statement
|
||||
|
@ -1575,6 +1575,22 @@ class EmitCImp : EmitCStmts {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstConsQueue* nodep) override {
|
||||
putbs(nodep->dtypep()->cType("", false, false));
|
||||
if (!nodep->lhsp()) {
|
||||
puts("()");
|
||||
} else {
|
||||
puts("::cons(");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
if (nodep->rhsp()) {
|
||||
puts(", ");
|
||||
putbs("");
|
||||
}
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstChangeDet* nodep) override { //
|
||||
m_blkChangeDetVec.push_back(nodep);
|
||||
}
|
||||
|
123
src/V3Width.cpp
123
src/V3Width.cpp
@ -484,12 +484,20 @@ private:
|
||||
// LHS, RHS is self-determined
|
||||
// signed: Unsigned (11.8.1)
|
||||
// width: LHS + RHS
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
if (VN_IS(vdtypep, QueueDType)) {
|
||||
// Queue "element 0" is lhsp, so we need to swap arguments
|
||||
auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(),
|
||||
nodep->lhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
userIterateChildren(newp, m_vup);
|
||||
return;
|
||||
}
|
||||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
if (vdtypep
|
||||
&& (VN_IS(vdtypep, AssocArrayDType) //
|
||||
|| VN_IS(vdtypep, DynArrayDType) //
|
||||
|| VN_IS(vdtypep, QueueDType))) {
|
||||
if (VN_IS(vdtypep, AssocArrayDType) //
|
||||
|| VN_IS(vdtypep, DynArrayDType) //
|
||||
|| VN_IS(vdtypep, QueueDType)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form "
|
||||
<< vdtypep->prettyDTypeNameQ() << "data type");
|
||||
}
|
||||
@ -609,14 +617,6 @@ private:
|
||||
// LHS, RHS is self-determined
|
||||
// width: value(LHS) * width(RHS)
|
||||
if (m_vup->prelim()) {
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
if (vdtypep
|
||||
&& (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form "
|
||||
<< vdtypep->prettyDTypeNameQ() << " data type");
|
||||
}
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
|
||||
const AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
||||
@ -631,6 +631,26 @@ private:
|
||||
"1800-2017 11.4.12.1)");
|
||||
times = 1;
|
||||
}
|
||||
|
||||
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
if (VN_IS(vdtypep, QueueDType)) {
|
||||
if (times != 1)
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-1 replication to form "
|
||||
<< vdtypep->prettyDTypeNameQ()
|
||||
<< " data type");
|
||||
// Don't iterate lhsp as SELF, the potential Concat below needs
|
||||
// the adtypep passed down to recognize the QueueDType
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, BOTH).p());
|
||||
nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
if (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType)
|
||||
|| VN_IS(vdtypep, UnpackArrayDType)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form "
|
||||
<< vdtypep->prettyDTypeNameQ() << " data type");
|
||||
}
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
if (nodep->lhsp()->isString()) {
|
||||
AstNode* newp = new AstReplicateN(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
@ -1133,10 +1153,21 @@ private:
|
||||
}
|
||||
virtual void visit(AstUnbounded* nodep) override {
|
||||
nodep->dtypeSetSigned32(); // Used in int context
|
||||
if (!VN_IS(nodep->backp(), IsUnbounded) && !VN_IS(nodep->backp(), BracketArrayDType)
|
||||
&& !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
|
||||
if (VN_IS(nodep->backp(), IsUnbounded)) return; // Ok, leave
|
||||
if (VN_IS(nodep->backp(), BracketArrayDType)) return; // Ok, leave
|
||||
if (auto* varp = VN_CAST(nodep->backp(), Var)) {
|
||||
if (varp->isParam()) return; // Ok, leave
|
||||
}
|
||||
// queue_slice[#:$]
|
||||
if (auto* selp = VN_CAST(nodep->backp(), SelExtract)) {
|
||||
if (VN_IS(selp->fromp()->dtypep(), QueueDType)) {
|
||||
nodep->replaceWith(
|
||||
new AstConst(nodep->fileline(), AstConst::Signed32(), 0x7FFFFFFF));
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
|
||||
}
|
||||
virtual void visit(AstIsUnbounded* nodep) override {
|
||||
if (m_vup->prelim()) {
|
||||
@ -1928,6 +1959,38 @@ private:
|
||||
}
|
||||
nodep->dtypeFrom(nodep->itemp());
|
||||
}
|
||||
virtual void visit(AstConsQueue* nodep) override { //
|
||||
// Type computed when constructed here
|
||||
AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType);
|
||||
UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type");
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, PRELIM).p());
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
}
|
||||
if (m_vup->final()) {
|
||||
// Arguments can be either elements of the queue or a queue itself
|
||||
// Concats (part of tree of concats) must always become ConsQueue's
|
||||
if (nodep->lhsp()) {
|
||||
if (VN_IS(nodep->lhsp()->dtypep(), QueueDType)
|
||||
|| VN_IS(nodep->lhsp(), ConsQueue)) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, FINAL).p());
|
||||
} else {
|
||||
// Sub elements are not queues, but concats, must always pass concats down
|
||||
iterateCheckTyped(nodep, "LHS", nodep->lhsp(), vdtypep->subDTypep(), FINAL);
|
||||
}
|
||||
}
|
||||
if (nodep->rhsp()) {
|
||||
if (VN_IS(nodep->rhsp()->dtypep(), QueueDType)
|
||||
|| VN_IS(nodep->rhsp(), ConsQueue)) {
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP(vdtypep, FINAL).p());
|
||||
} else {
|
||||
iterateCheckTyped(nodep, "RHS", nodep->rhsp(), vdtypep->subDTypep(), FINAL);
|
||||
}
|
||||
}
|
||||
nodep->dtypeFrom(vdtypep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstInitItem* nodep) override { //
|
||||
userIterateChildren(nodep, m_vup);
|
||||
}
|
||||
@ -2490,12 +2553,10 @@ private:
|
||||
newp->didWidth(true);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Queue .delete(index) method, as is O(n) "
|
||||
"complexity and slow.");
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"erase", index_exprp->unlinkFrBack());
|
||||
newp->protect(false);
|
||||
newp->didWidth(true);
|
||||
newp->makeStatement();
|
||||
}
|
||||
}
|
||||
@ -2511,9 +2572,6 @@ private:
|
||||
newp->protect(false);
|
||||
newp->makeStatement();
|
||||
} else {
|
||||
nodep->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Queue .insert method, as is O(n) complexity and slow.");
|
||||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), index_exprp->unlinkFrBack());
|
||||
newp->addPinsp(argp->exprp()->unlinkFrBack());
|
||||
@ -2874,10 +2932,12 @@ private:
|
||||
while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) {
|
||||
dtypep = vdtypep->subDTypep()->skipRefp();
|
||||
}
|
||||
if (AstNodeUOrStructDType* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) {
|
||||
if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) {
|
||||
VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (AstNodeArrayDType* vdtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
} else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
VL_DO_DANGLING(patternArray(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (auto* vdtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
VL_DO_DANGLING(patternQueue(nodep, vdtypep, defaultp), nodep);
|
||||
} else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) {
|
||||
VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep);
|
||||
} else {
|
||||
@ -3038,6 +3098,21 @@ private:
|
||||
// if (debug() >= 9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
void patternQueue(AstPattern* nodep, AstQueueDType* arrayp, AstPatMember* defaultp) {
|
||||
AstNode* newp = new AstConsQueue(nodep->fileline());
|
||||
newp->dtypeFrom(arrayp);
|
||||
for (AstPatMember* patp = VN_CAST(nodep->itemsp(), PatMember); patp;
|
||||
patp = VN_CAST(patp->nextp(), PatMember)) {
|
||||
patp->dtypep(arrayp->subDTypep());
|
||||
AstNode* valuep = patternMemberValueIterate(patp);
|
||||
auto* newap = new AstConsQueue(nodep->fileline(), valuep, newp);
|
||||
newap->dtypeFrom(arrayp);
|
||||
newp = newap;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
// if (debug() >= 9) newp->dumpTree("-apat-out: ");
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Deletes defaultp also, if present
|
||||
}
|
||||
void patternBasic(AstPattern* nodep, AstNodeDType* vdtypep, AstPatMember* defaultp) {
|
||||
AstBasicDType* bdtypep = VN_CAST(vdtypep, BasicDType);
|
||||
VNumRange range = bdtypep->declRange();
|
||||
|
@ -439,6 +439,15 @@ private:
|
||||
// if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, QueueDType)) {
|
||||
auto* newp = new AstCMethodHard(nodep->fileline(), fromp, "slice", msbp);
|
||||
msbp->addNext(lsbp);
|
||||
newp->dtypep(ddtypep);
|
||||
newp->didWidth(true);
|
||||
newp->protect(false);
|
||||
UINFO(6, " new " << newp << endl);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // nullptr=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
||||
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
||||
|
@ -3403,8 +3403,7 @@ assignment_pattern<patternp>: // ==IEEE: assignment_pattern
|
||||
// // also IEEE "''{' array_pattern_key ':' ...
|
||||
| yP_TICKBRA patternMemberList '}' { $$ = new AstPattern($1,$2); }
|
||||
// // IEEE: Not in grammar, but in VMM
|
||||
| yP_TICKBRA '}'
|
||||
{ $$ = new AstPattern($1, nullptr); $1->v3warn(E_UNSUPPORTED, "Unsupported: Empty '{}"); }
|
||||
| yP_TICKBRA '}' { $$ = new AstPattern($1, nullptr); }
|
||||
;
|
||||
|
||||
// "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal
|
||||
|
@ -1,4 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_queue_slice.v:21:11: Unsupported: Empty '{}
|
||||
21 | q = '{};
|
||||
| ^~
|
||||
%Error: Exiting due to
|
@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
) if !$Self->{vlt_all};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user