Support assignments of multidimensional slices, bug170
This commit is contained in:
parent
48e88e4e74
commit
89e03a86b7
2
Changes
2
Changes
|
|
@ -15,6 +15,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
** Support direct programming interface (DPI) "import" and "export".
|
||||
Includes an extension to map user $system PLI calls to the DPI.
|
||||
|
||||
*** Support assignments of multidimensional slices, bug170. [by Byron Bradley]
|
||||
|
||||
*** Support "reg [1:0][1:0][1:0]" and "reg x [3][2]", bug176. [Byron Bradley]
|
||||
|
||||
*** Support declarations in loop initializers, bug172. [by Byron Bradley]
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ RAW_OBJS = \
|
|||
V3Premit.o \
|
||||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3Stats.o \
|
||||
|
|
|
|||
|
|
@ -1228,8 +1228,10 @@ struct AstNodeSel : public AstNodeBiop {
|
|||
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
:AstNodeBiop(fl, fromp, bitp) {}
|
||||
ASTNODE_BASE_FUNCS(NodeSel)
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
AstNode* bitp() const { return op2p()->castNode(); } // op2 = Msb selection expression
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* bitp() const { return op2p()->castNode(); } // op2 = Msb selection expression
|
||||
void bitp(AstNode* nodep) { setOp2p(nodep); }
|
||||
int bitConst() const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,23 @@ uint32_t AstVar::arrayElements() const {
|
|||
return entries;
|
||||
}
|
||||
|
||||
uint32_t AstVar::dimensions() const {
|
||||
// How many array dimensions does this Var have?
|
||||
uint32_t dim = 0;
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
dim += 1;
|
||||
dtypep = adtypep->dtypep();
|
||||
}
|
||||
else {
|
||||
// AstBasicDType - nothing below, 1
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dim;
|
||||
}
|
||||
|
||||
// Special operators
|
||||
int AstArraySel::dimension(AstNode* nodep) {
|
||||
// How many dimensions is this reference from the base variable?
|
||||
|
|
@ -445,6 +462,10 @@ void AstNode::dump(ostream& os) {
|
|||
if (name()!="") os<<" "<<AstNode::quoteName(name());
|
||||
}
|
||||
|
||||
void AstArraySel::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
|
||||
}
|
||||
void AstAttrOf::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<attrType().ascii()<<"]";
|
||||
|
|
|
|||
|
|
@ -401,12 +401,16 @@ struct AstEnumDType : public AstNodeDType {
|
|||
struct AstArraySel : public AstNodeSel {
|
||||
// Parents: math|stmt
|
||||
// Children: varref|arraysel, math
|
||||
private:
|
||||
unsigned m_start;
|
||||
unsigned m_length;
|
||||
public:
|
||||
AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
:AstNodeSel(fl, fromp, bitp) {
|
||||
:AstNodeSel(fl, fromp, bitp), m_start(0), m_length(1) {
|
||||
if (fromp) widthSignedFrom(fromp);
|
||||
}
|
||||
AstArraySel(FileLine* fl, AstNode* fromp, int bit)
|
||||
:AstNodeSel(fl, fromp, new AstConst(fl,bit)) {
|
||||
:AstNodeSel(fl, fromp, new AstConst(fl,bit)), m_start(0), m_length(1) {
|
||||
if (fromp) widthSignedFrom(fromp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ArraySel, ARRAYSEL)
|
||||
|
|
@ -422,9 +426,14 @@ struct AstArraySel : public AstNodeSel {
|
|||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
unsigned length() { return m_length; }
|
||||
void length(unsigned length) { m_length = length; }
|
||||
void start(unsigned start) { m_start = start; }
|
||||
unsigned start() { return m_start; }
|
||||
// Special operators
|
||||
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
|
||||
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
|
||||
virtual void dump(ostream& str);
|
||||
};
|
||||
|
||||
struct AstWordSel : public AstNodeSel {
|
||||
|
|
@ -603,6 +612,7 @@ public:
|
|||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeDimensionp(int depth) const;
|
||||
uint32_t dimensions() const;
|
||||
AstNode* initp() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
||||
void initp(AstNode* nodep) { setOp3p(nodep); }
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ private:
|
|||
arrayselp = lhsp->castArraySel();
|
||||
}
|
||||
if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
|
||||
if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");
|
||||
|
||||
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
|
||||
//
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ private:
|
|||
}
|
||||
bool expandWide (AstNodeAssign* nodep, AstArraySel* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
|
||||
if (rhsp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone (rhsp, w));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,353 @@
|
|||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Parse module/signal name references
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// Slice TRANSFORMATIONS:
|
||||
// Top-down traversal (SliceVisitor):
|
||||
// NODEASSIGN
|
||||
// ARRAYSEL
|
||||
// Compare the dimensions to the Var to check for implicit slices.
|
||||
// Using ->length() calculate the number of clones needed.
|
||||
// VARREF
|
||||
// Check the dimensions of the Var for an implicit slice.
|
||||
// Replace with ArraySel nodes if needed.
|
||||
// SEL, EXTEND
|
||||
// We might be assigning a 1-D packed array to a 2-D packed array,
|
||||
// this is unsupported.
|
||||
// SliceCloneVisitor (called if this node is a slice):
|
||||
// NODEASSIGN
|
||||
// Clone and iterate the clone:
|
||||
// ARRAYSEL
|
||||
// Modify bitp() for the new value and set ->length(1)
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Slice.h"
|
||||
#include "V3Ast.h"
|
||||
#include <vector>
|
||||
|
||||
class SliceCloneVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// Inputs:
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||
|
||||
// STATE
|
||||
vector<vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding
|
||||
unsigned m_vecIdx; // Current vector index
|
||||
unsigned m_depth; // Number of ArraySel's from the VarRef
|
||||
AstVarRef* m_refp; // VarRef under this ArraySel
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||
if (!nodep->backp()->castArraySel()) {
|
||||
// This is the top of an ArraySel, setup
|
||||
m_refp = nodep->user1p()->castNode()->castVarRef();
|
||||
m_vecIdx += 1;
|
||||
if (m_vecIdx == m_selBits.size()) {
|
||||
m_selBits.push_back(vector<unsigned>());
|
||||
AstVar* varp = m_refp->varp();
|
||||
int dimensions = varp->dimensions();
|
||||
for (int i = 0; i < dimensions; ++i) {
|
||||
m_selBits[m_vecIdx].push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->fromp()->castVarRef()) {
|
||||
m_depth = 0;
|
||||
} else {
|
||||
++m_depth;
|
||||
}
|
||||
// Check if m_selBits has overflowed
|
||||
if (m_selBits[m_vecIdx][m_depth] >= nodep->length()) {
|
||||
m_selBits[m_vecIdx][m_depth] = 0;
|
||||
if (m_depth + 1 < m_selBits[m_vecIdx].size())
|
||||
m_selBits[m_vecIdx][m_depth+1] += 1;
|
||||
}
|
||||
// Reassign the bitp()
|
||||
if (nodep->length() > 1) {
|
||||
if (AstConst* bitp = nodep->bitp()->castConst()) {
|
||||
unsigned idx = nodep->start() + m_selBits[m_vecIdx][m_depth];
|
||||
AstNode* constp = new AstConst(bitp->fileline(), V3Number(bitp->fileline(), bitp->castConst()->num().width(), idx));
|
||||
bitp->replaceWith(constp);
|
||||
} else {
|
||||
nodep->v3error("Unsupported: Only constants supported in slices");
|
||||
}
|
||||
}
|
||||
if (!nodep->backp()->castArraySel()) {
|
||||
// Top ArraySel, increment m_selBits
|
||||
m_selBits[m_vecIdx][0] += 1;
|
||||
}
|
||||
nodep->length(1);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
m_selBits.clear();
|
||||
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
||||
for (int i = 0; i < nodep->user2(); ++i) {
|
||||
// Clone the node and iterate over the clone
|
||||
m_vecIdx = -1;
|
||||
AstNodeAssign* clonep = nodep->cloneTree(false)->castNodeAssign();
|
||||
clonep->iterateChildren(*this);
|
||||
nodep->addNextHere(clonep);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SliceCloneVisitor(AstNodeAssign* assignp) {
|
||||
assignp->accept(*this);
|
||||
}
|
||||
virtual ~SliceCloneVisitor() {}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
|
||||
class SliceVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// Cleared on netlist
|
||||
// AstNodeAssign::user1() -> bool. True if find is complete
|
||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
AstNode* m_assignp; // Assignment we are under
|
||||
AstNodeVarRef* m_lhsVarRefp; // Var on the LHS
|
||||
bool m_extend; // We have found an extend node
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
// Find out how many explicit dimensions are in a given ArraySel.
|
||||
unsigned explicitDimensions(AstArraySel* nodep) {
|
||||
unsigned dim = 0;
|
||||
AstNode* fromp = nodep;
|
||||
AstArraySel* selp;
|
||||
do {
|
||||
selp = fromp->castArraySel();
|
||||
if (!selp) {
|
||||
nodep->user1p(fromp->castVarRef());
|
||||
selp = NULL;
|
||||
} else {
|
||||
fromp = selp->fromp();
|
||||
if (fromp) ++dim;
|
||||
}
|
||||
} while (fromp && selp);
|
||||
if (!m_assignp->user1p()) nodep->v3fatalSrc("Couldn't find VarRef under the ArraySel");
|
||||
return dim;
|
||||
}
|
||||
|
||||
AstNode* insertImplicit(AstVarRef* nodep, unsigned start, unsigned count) {
|
||||
// Insert any implicit slices as explicit slices (ArraySel nodes).
|
||||
// Return a new pointer to replace fromp() in the ArraySel.
|
||||
AstVarRef* fromp = nodep;
|
||||
if (!fromp) nodep->v3fatalSrc("NULL VarRef passed to insertImplicit");
|
||||
AstVar* varp = fromp->varp();
|
||||
// Get the DType and insert a new ArraySel
|
||||
AstArraySel* topp = NULL;
|
||||
AstArraySel* bottomp = NULL;
|
||||
for (unsigned i = start; i < start + count; ++i) {
|
||||
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1);
|
||||
AstArrayDType* adtypep = dtypep->castArrayDType();
|
||||
if (!adtypep) nodep->v3fatalSrc("insertImplicit tried to expand an array without an ArrayDType");
|
||||
vlsint32_t msb = adtypep->msb();
|
||||
vlsint32_t lsb = adtypep->lsb();
|
||||
if (lsb > msb) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, new AstConst(nodep->fileline(),lsb));
|
||||
newp->start(lsb);
|
||||
newp->length(msb - lsb + 1);
|
||||
if (!topp) topp = newp;
|
||||
fromp = newp->fromp()->unlinkFrBack()->castVarRef();
|
||||
|
||||
if (bottomp) bottomp->fromp(newp);
|
||||
bottomp = newp;
|
||||
}
|
||||
bottomp->fromp(fromp);
|
||||
return topp;
|
||||
}
|
||||
|
||||
int countClones(AstArraySel* nodep) {
|
||||
// Count how many clones we need to make from this ArraySel
|
||||
int clones = 1;
|
||||
AstNode* fromp = nodep;
|
||||
AstArraySel* selp;
|
||||
do {
|
||||
selp = fromp->castArraySel();
|
||||
fromp = (selp) ? selp->fromp() : NULL;
|
||||
if (fromp && selp) clones *= selp->length();
|
||||
} while (fromp && selp);
|
||||
return clones;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
// The LHS/RHS of an Assign may be to a Var that is an array. In this
|
||||
// case we need to create a slice accross the entire Var
|
||||
if (m_assignp && !nodep->backp()->castArraySel()) {
|
||||
uint32_t dimensions = nodep->varp()->dimensions();
|
||||
if (dimensions > 0) {
|
||||
AstNode* newp = insertImplicit(nodep->cloneTree(false), 1, dimensions);
|
||||
nodep->replaceWith(newp); nodep = NULL;
|
||||
newp->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||
m_extend = true;
|
||||
if (m_assignp && m_assignp->user2() > 1) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||
if (!m_assignp) return;
|
||||
unsigned dim = explicitDimensions(nodep);
|
||||
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||
unsigned implicit = refp->varp()->dimensions() - dim;
|
||||
if (implicit > 0) {
|
||||
AstNode* backp = refp->backp();
|
||||
AstNode* newp = insertImplicit(refp->cloneTree(false), dim+1, implicit);
|
||||
backp->castArraySel()->fromp()->replaceWith(newp);
|
||||
}
|
||||
int clones = countClones(nodep);
|
||||
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
|
||||
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
||||
} else if (m_assignp->user2() == 0) {
|
||||
if (m_extend && clones > 1) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
}
|
||||
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() && !m_assignp->castAssignDly()) {
|
||||
// LHS Var != RHS Var for a non-delayed assignment
|
||||
m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
||||
}
|
||||
m_assignp->user2(clones);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
m_extend = true;
|
||||
if (m_assignp && m_assignp->user2() > 1) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// Return the first AstVarRef under the node
|
||||
AstVarRef* findVarRefRecurse(AstNode* nodep) {
|
||||
AstVarRef* refp = nodep->castVarRef();
|
||||
if (refp) return refp;
|
||||
if (nodep->op1p()) {
|
||||
refp = findVarRefRecurse(nodep->op1p());
|
||||
if (refp) return refp;
|
||||
}
|
||||
if (nodep->op2p()) {
|
||||
refp = findVarRefRecurse(nodep->op2p());
|
||||
if (refp) return refp;
|
||||
}
|
||||
if (nodep->op3p()) {
|
||||
refp = findVarRefRecurse(nodep->op3p());
|
||||
if (refp) return refp;
|
||||
}
|
||||
if (nodep->op3p()) {
|
||||
refp = findVarRefRecurse(nodep->op3p());
|
||||
if (refp) return refp;
|
||||
}
|
||||
if (nodep->nextp()) {
|
||||
refp = findVarRefRecurse(nodep->nextp());
|
||||
if (refp) return refp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void findImplicit(AstNodeAssign* nodep) {
|
||||
if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign");
|
||||
m_assignp = nodep;
|
||||
m_extend = false;
|
||||
nodep->user1(true);
|
||||
// Record the LHS Var so we can check if the Var on the RHS is the same
|
||||
m_lhsVarRefp = findVarRefRecurse(nodep->lhsp());
|
||||
if (!m_lhsVarRefp) nodep->v3fatalSrc("Couldn't find a VarRef on the LHSP of an Assign");
|
||||
// Iterate children looking for ArraySel nodes. From that we get the number of elements
|
||||
// in the array so we know how many times we need to clone this assignment.
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->user2() > 1) {
|
||||
SliceCloneVisitor scv(nodep);
|
||||
}
|
||||
m_assignp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
// Hasn't been searched for implicit slices yet
|
||||
findImplicit(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SliceVisitor(AstNetlist* rootp) {
|
||||
m_assignp = NULL;
|
||||
m_lhsVarRefp = NULL;
|
||||
rootp->accept(*this);
|
||||
}
|
||||
virtual ~SliceVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Link class functions
|
||||
|
||||
void V3Slice::sliceAll(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
SliceVisitor visitor(rootp);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Link modules/signals together
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3SLICE_H_
|
||||
#define _V3SLICE_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Slice {
|
||||
public:
|
||||
static void sliceAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -80,10 +80,6 @@ private:
|
|||
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
|
||||
AstNodeDType* ddtypep = varp->dtypeDimensionp(dimension);
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
if (rangedSelect) {
|
||||
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
||||
return NULL;
|
||||
}
|
||||
return adtypep;
|
||||
}
|
||||
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
|
|
@ -247,7 +243,17 @@ private:
|
|||
vlsint32_t msb = msbp->castConst()->toSInt();
|
||||
vlsint32_t lsb = lsbp->castConst()->toSInt();
|
||||
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, msb!=lsb);
|
||||
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
||||
if (adtypep) {}
|
||||
if (msb!=lsb) {
|
||||
AstArraySel* newp = new AstArraySel (nodep->fileline(), fromp, lsbp);
|
||||
newp->start(lsb);
|
||||
newp->length((msb - lsb) + 1);
|
||||
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
|
||||
} else {
|
||||
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
||||
}
|
||||
} else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
||||
if (adtypep) {} // Unused
|
||||
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#include "V3Premit.h"
|
||||
#include "V3Scope.h"
|
||||
#include "V3Signed.h"
|
||||
#include "V3Slice.h"
|
||||
#include "V3Split.h"
|
||||
#include "V3SplitAs.h"
|
||||
#include "V3Stats.h"
|
||||
|
|
@ -280,6 +281,10 @@ void process () {
|
|||
V3Unroll::unrollAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
|
||||
|
||||
// Expand slices of arrays
|
||||
V3Slice::sliceAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("slices.tree"));
|
||||
|
||||
// Convert case statements to if() blocks. Must be after V3Unknown
|
||||
V3Case::caseAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
|
||||
|
|
|
|||
|
|
@ -12,15 +12,16 @@ compile (
|
|||
nc=>0, # Need to get it not to give the prompt
|
||||
expect=>
|
||||
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dimn
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal range select; variable already selected, or bad dimension
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal \+: or -: select; variable already selected, or bad dimension
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0nv
|
||||
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension
|
||||
.*%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_mem_packed_assign.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: t/t_mem_packed_assign.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: Exiting due to.*',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
/* verilator lint_off WIDTH */
|
||||
|
||||
input clk;
|
||||
|
||||
integer cyc; initial cyc = 0;
|
||||
logic [31:0] arr_c; initial arr_c = 0;
|
||||
logic [7:0] [3:0] arr;
|
||||
|
||||
logic [31:0] arr2_c; initial arr2_c = 0;
|
||||
logic [7:0] [3:0] arr2;
|
||||
assign arr2_c = arr2;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
arr_c <= arr_c + 1;
|
||||
arr2 <= arr2 + 1;
|
||||
$write("cyc%0d c:%0x a0:%0x a1:%0x a2:%0x a3:%0x\n", cyc, arr_c, arr[0], arr[1], arr[2], arr[3]);
|
||||
if (cyc==99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
/* verilator lint_on WIDTH */
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags => [],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
logic use_AnB;
|
||||
logic [1:0] active_command [8:0];
|
||||
logic [1:0] command_A [8:0];
|
||||
logic [1:0] command_B [8:0];
|
||||
|
||||
logic [1:0] active_command2 [8:0];
|
||||
logic [1:0] command_A2 [8:0];
|
||||
logic [1:0] command_B2 [8:0];
|
||||
|
||||
logic [1:0] active_command3 [1:0][2:0][3:0];
|
||||
logic [1:0] command_A3 [1:0][2:0][3:0];
|
||||
logic [1:0] command_B3 [1:0][2:0][3:0];
|
||||
|
||||
logic [8:0] pipe1 [7:0];
|
||||
logic [8:0] pipe1_input;
|
||||
|
||||
integer cyc;
|
||||
|
||||
assign active_command[8:0] = (use_AnB) ? command_A[8:0] : command_B[8:0];
|
||||
assign active_command2 = (use_AnB) ? command_A2 : command_B2;
|
||||
assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][2:0][3:0];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
pipe1_input <= pipe1_input + 1;
|
||||
pipe1[0] <= pipe1_input;
|
||||
pipe1[7:1] <= pipe1[6:0];
|
||||
end
|
||||
|
||||
logic [3:0][13:0] iq_read_data [15:0];
|
||||
logic [3:0][13:0] iq_data;
|
||||
logic [3:0] sel;
|
||||
|
||||
assign iq_data = iq_read_data[sel];
|
||||
|
||||
always @ (posedge clk) begin
|
||||
sel = sel + 1;
|
||||
end
|
||||
|
||||
initial begin
|
||||
cyc = 0;
|
||||
use_AnB = 0;
|
||||
for (int i = 0; i < 7; ++i) begin
|
||||
command_A[i] = 2'b00;
|
||||
command_B[i] = 2'b11;
|
||||
command_A2[i] = 2'b00;
|
||||
command_B2[i] = 2'b11;
|
||||
pipe1_input = 9'b0;
|
||||
end
|
||||
for (int i = 0; i < 2; ++i) begin
|
||||
for (int j = 0; j < 3; ++j) begin
|
||||
for (int k = 0; k < 4; ++k) begin
|
||||
command_A3[i][j][k] = 2'b00;
|
||||
command_B3[i][j][k] = 2'b11;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk) begin
|
||||
use_AnB <= ~use_AnB;
|
||||
cyc <= cyc + 1;
|
||||
if (use_AnB) begin
|
||||
if (active_command[3] != 2'b00) begin
|
||||
$stop;
|
||||
end
|
||||
if (active_command2[3] != 2'b00) begin
|
||||
$stop;
|
||||
end
|
||||
if (active_command3[0][1][2] != 2'b00) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
if (!use_AnB) begin
|
||||
if (active_command[3] != 2'b11) begin
|
||||
$stop;
|
||||
end
|
||||
if (active_command2[3] != 2'b11) begin
|
||||
$stop;
|
||||
end
|
||||
if (active_command3[3][1][2] != 2'b11) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
logic [8:0] last_pipe;
|
||||
always @(posedge clk) begin
|
||||
if (cyc < 3) begin
|
||||
last_pipe <= pipe1[0];
|
||||
end
|
||||
else begin
|
||||
if (last_pipe + 1 != pipe1[0]) begin
|
||||
$stop;
|
||||
end
|
||||
else begin
|
||||
last_pipe <= pipe1[0];
|
||||
end
|
||||
end
|
||||
if (cyc > 10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule : t
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Unsupported: Slices in a non-delayed assignment with the same Var on both sides
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
logic use_AnB;
|
||||
|
||||
logic [1:0] active_command [8:0];
|
||||
logic [1:0] command_A [8:0];
|
||||
logic [1:0] command_B [8:0];
|
||||
|
||||
logic [1:0] active_command2 [8:0];
|
||||
logic [1:0] command_A2 [7:0];
|
||||
logic [1:0] command_B2 [8:0];
|
||||
|
||||
logic [1:0] active_command3 [1:0][2:0][3:0];
|
||||
logic [1:0] command_A3 [1:0][2:0][3:0];
|
||||
logic [1:0] command_B3 [1:0][2:0][3:0];
|
||||
|
||||
logic [1:0] active_command4 [8:0];
|
||||
logic [1:0] command_A4 [7:0];
|
||||
|
||||
logic [1:0] active_command5 [8:0];
|
||||
logic [1:0] command_A5 [7:0];
|
||||
|
||||
// Single dimension assign
|
||||
assign active_command[3:0] = (use_AnB) ? command_A[7:0] : command_B[7:0];
|
||||
// Assignment of entire arrays
|
||||
assign active_command2 = (use_AnB) ? command_A2 : command_B2;
|
||||
// Multi-dimension assign
|
||||
assign active_command3[1:0][2:0][3:0] = (use_AnB) ? command_A3[1:0][2:0][3:0] : command_B3[1:0][1:0][3:0];
|
||||
|
||||
// Supported: Delayed assigment with RHS Var == LHS Var
|
||||
logic [7:0] arrd [7:0];
|
||||
always_ff @(posedge clk) arrd[7:4] <= arrd[3:0];
|
||||
|
||||
// Unsupported: Non-delayed assigment with RHS Var == LHS Var
|
||||
logic [7:0] arr [7:0];
|
||||
assign arr[7:4] = arr[3:0];
|
||||
|
||||
// Delayed assign
|
||||
always @(posedge clk) begin
|
||||
active_command4[7:0] <= command_A4[8:0];
|
||||
end
|
||||
|
||||
// Combinational assign
|
||||
always_comb begin
|
||||
active_command5[8:0] = command_A5[7:0];
|
||||
end
|
||||
|
||||
endmodule : t
|
||||
Loading…
Reference in New Issue