slices.diff
| b/src/Makefile_obj.in | ||
|---|---|---|
| 206 | 206 |
V3Premit.o \ |
| 207 | 207 |
V3Scope.o \ |
| 208 | 208 |
V3Signed.o \ |
| 209 |
V3Slice.o \ |
|
| 209 | 210 |
V3Split.o \ |
| 210 | 211 |
V3SplitAs.o \ |
| 211 | 212 |
V3Stats.o \ |
| b/src/V3Ast.h | ||
|---|---|---|
| 1229 | 1229 |
:AstNodeBiop(fl, fromp, bitp) {}
|
| 1230 | 1230 |
ASTNODE_BASE_FUNCS(NodeSel) |
| 1231 | 1231 |
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
| 1232 |
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
|
| 1232 | 1233 |
AstNode* bitp() const { return op2p()->castNode(); } // op2 = Msb selection expression
|
| 1234 |
void bitp(AstNode* nodep) { setOp2p(nodep); }
|
|
| 1233 | 1235 |
int bitConst() const; |
| 1234 | 1236 |
}; |
| 1235 | 1237 | |
| b/src/V3AstNodes.cpp | ||
|---|---|---|
| 258 | 258 |
return entries; |
| 259 | 259 |
} |
| 260 | 260 | |
| 261 |
uint32_t AstVar::dimensions() const {
|
|
| 262 |
// How many array dimensions does this Var have? |
|
| 263 |
uint32_t dim = 0; |
|
| 264 |
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
|
| 265 |
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node |
|
| 266 |
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
|
| 267 |
dim += 1; |
|
| 268 |
dtypep = adtypep->dtypep(); |
|
| 269 |
} |
|
| 270 |
else {
|
|
| 271 |
// AstBasicDType - nothing below, 1 |
|
| 272 |
break; |
|
| 273 |
} |
|
| 274 |
} |
|
| 275 |
return dim; |
|
| 276 |
} |
|
| 277 | ||
| 261 | 278 |
// Special operators |
| 262 | 279 |
int AstArraySel::dimension(AstNode* nodep) {
|
| 263 | 280 |
// How many dimensions is this reference from the base variable? |
| ... | ... | |
| 445 | 462 |
if (name()!="") os<<" "<<AstNode::quoteName(name()); |
| 446 | 463 |
} |
| 447 | 464 | |
| 465 |
void AstArraySel::dump(ostream& str) {
|
|
| 466 |
this->AstNode::dump(str); |
|
| 467 |
str<<" [start:"<<start()<<"] [length:"<<length()<<"]"; |
|
| 468 |
} |
|
| 448 | 469 |
void AstAttrOf::dump(ostream& str) {
|
| 449 | 470 |
this->AstNode::dump(str); |
| 450 | 471 |
str<<" ["<<attrType().ascii()<<"]"; |
| b/src/V3AstNodes.h | ||
|---|---|---|
| 401 | 401 |
struct AstArraySel : public AstNodeSel {
|
| 402 | 402 |
// Parents: math|stmt |
| 403 | 403 |
// Children: varref|arraysel, math |
| 404 |
private: |
|
| 405 |
unsigned m_start; |
|
| 406 |
unsigned m_length; |
|
| 407 |
public: |
|
| 404 | 408 |
AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) |
| 405 |
:AstNodeSel(fl, fromp, bitp) {
|
|
| 409 |
:AstNodeSel(fl, fromp, bitp), m_start(0), m_length(1) {
|
|
| 406 | 410 |
if (fromp) widthSignedFrom(fromp); |
| 407 | 411 |
} |
| 408 | 412 |
AstArraySel(FileLine* fl, AstNode* fromp, int bit) |
| 409 |
:AstNodeSel(fl, fromp, new AstConst(fl,bit)) {
|
|
| 413 |
:AstNodeSel(fl, fromp, new AstConst(fl,bit)), m_start(0), m_length(1) {
|
|
| 410 | 414 |
if (fromp) widthSignedFrom(fromp); |
| 411 | 415 |
} |
| 412 | 416 |
ASTNODE_NODE_FUNCS(ArraySel, ARRAYSEL) |
| ... | ... | |
| 422 | 426 |
virtual V3Hash sameHash() const { return V3Hash(); }
|
| 423 | 427 |
virtual bool same(AstNode* samep) const { return true; }
|
| 424 | 428 |
virtual int instrCount() const { return widthInstrs(); }
|
| 429 |
unsigned length() { return m_length; }
|
|
| 430 |
void length(unsigned length) { m_length = length; }
|
|
| 431 |
void start(unsigned start) { m_start = start; }
|
|
| 432 |
unsigned start(void) { return m_start; }
|
|
| 425 | 433 |
// Special operators |
| 426 | 434 |
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable? |
| 427 | 435 |
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? |
| 436 |
virtual void dump(ostream& str); |
|
| 428 | 437 |
}; |
| 429 | 438 | |
| 430 | 439 |
struct AstWordSel : public AstNodeSel {
|
| ... | ... | |
| 603 | 612 |
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
| 604 | 613 |
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
| 605 | 614 |
AstNodeDType* dtypeDimensionp(int depth) const; |
| 615 |
uint32_t dimensions() const; |
|
| 606 | 616 |
AstNode* initp() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
| 607 | 617 |
void initp(AstNode* nodep) { setOp3p(nodep); }
|
| 608 | 618 |
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
| b/src/V3Delayed.cpp | ||
|---|---|---|
| 158 | 158 |
arrayselp = lhsp->castArraySel(); |
| 159 | 159 |
} |
| 160 | 160 |
if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
|
| 161 |
UASSERT(arrayselp->length() == 1, "ArraySel with length!=1 should have been removed in V3Slice"); |
|
| 161 | 162 | |
| 162 | 163 |
UINFO(4,"AssignDlyArray: "<<nodep<<endl); |
| 163 | 164 |
// |
| b/src/V3Expand.cpp | ||
|---|---|---|
| 239 | 239 |
return true; |
| 240 | 240 |
} |
| 241 | 241 |
bool expandWide (AstNodeAssign* nodep, AstArraySel* rhsp) {
|
| 242 |
UASSERT(rhsp->length() == 1, "ArraySel with length!=1 should have been removed in V3Slice"); |
|
| 242 | 243 |
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl); |
| 243 | 244 |
for (int w=0; w<nodep->widthWords(); w++) {
|
| 244 | 245 |
addWordAssign(nodep, w, newAstWordSelClone (rhsp, w)); |
| b/src/V3Slice.cpp | ||
|---|---|---|
| 1 |
//************************************************************************* |
|
| 2 |
// DESCRIPTION: Verilator: Parse module/signal name references |
|
| 3 |
// |
|
| 4 |
// Code available from: http://www.veripool.org/verilator |
|
| 5 |
// |
|
| 6 |
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli |
|
| 7 |
// |
|
| 8 |
//************************************************************************* |
|
| 9 |
// |
|
| 10 |
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can |
|
| 11 |
// redistribute it and/or modify it under the terms of either the GNU |
|
| 12 |
// Lesser General Public License Version 3 or the Perl Artistic License |
|
| 13 |
// Version 2.0. |
|
| 14 |
// |
|
| 15 |
// Verilator is distributed in the hope that it will be useful, |
|
| 16 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 |
// GNU General Public License for more details. |
|
| 19 |
// |
|
| 20 |
//************************************************************************* |
|
| 21 |
// Slice TRANSFORMATIONS: |
|
| 22 |
// Top-down traversal (SliceVisitor): |
|
| 23 |
// NODEASSIGN |
|
| 24 |
// ARRAYSEL |
|
| 25 |
// Compare the dimensions to the Var to check for implicit slices. |
|
| 26 |
// Using ->length() calculate the number of clones needed. |
|
| 27 |
// VARREF |
|
| 28 |
// Check the dimensions of the Var for an implicit slice. |
|
| 29 |
// Replace with ArraySel nodes if needed. |
|
| 30 |
// SEL, EXTEND |
|
| 31 |
// We might be assigning a 1-D packed array to a 2-D packed array, |
|
| 32 |
// this is unsupported. |
|
| 33 |
// SliceCloneVisitor (called if this node is a slice): |
|
| 34 |
// NODEASSIGN |
|
| 35 |
// Clone and iterate the clone: |
|
| 36 |
// ARRAYSEL |
|
| 37 |
// Modify bitp() for the new value and set ->length(1) |
|
| 38 |
//************************************************************************* |
|
| 39 | ||
| 40 |
#include "config_build.h" |
|
| 41 |
#include "verilatedos.h" |
|
| 42 |
#include <cstdio> |
|
| 43 |
#include <cstdarg> |
|
| 44 |
#include <unistd.h> |
|
| 45 | ||
| 46 |
#include "V3Global.h" |
|
| 47 |
#include "V3Slice.h" |
|
| 48 |
#include "V3Ast.h" |
|
| 49 |
#include <vector> |
|
| 50 | ||
| 51 |
class SliceCloneVisitor : public AstNVisitor {
|
|
| 52 |
private: |
|
| 53 |
// NODE STATE |
|
| 54 |
// Inputs: |
|
| 55 |
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to |
|
| 56 |
// AstNodeAssign::user2() -> int. The number of clones needed for this assign |
|
| 57 | ||
| 58 |
// STATE |
|
| 59 |
std::vector<std::vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding |
|
| 60 |
int m_vecIdx; // Current vector index |
|
| 61 |
unsigned m_depth; // Number of ArraySel's from the VarRef |
|
| 62 |
AstVarRef* m_refp; // The VarRef under this ArraySel |
|
| 63 | ||
| 64 |
// METHODS |
|
| 65 |
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
|
| 66 |
if (!nodep->backp()->castArraySel()) {
|
|
| 67 |
// This is the top of an ArraySel, setup |
|
| 68 |
m_refp = nodep->user1p()->castNode()->castVarRef(); |
|
| 69 |
m_vecIdx += 1; |
|
| 70 |
if (m_vecIdx == m_selBits.size()) {
|
|
| 71 |
m_selBits.push_back(std::vector<unsigned>()); |
|
| 72 |
AstVar* varp = m_refp->varp(); |
|
| 73 |
int dimensions = varp->dimensions(); |
|
| 74 |
for (int i = 0; i < dimensions; ++i) {
|
|
| 75 |
m_selBits[m_vecIdx].push_back(0); |
|
| 76 |
} |
|
| 77 |
} |
|
| 78 |
} |
|
| 79 |
nodep->iterateChildren(*this); |
|
| 80 |
if (nodep->fromp()->castVarRef()) {
|
|
| 81 |
m_depth = 0; |
|
| 82 |
} else {
|
|
| 83 |
++m_depth; |
|
| 84 |
} |
|
| 85 |
// Check if m_selBits has overflowed |
|
| 86 |
if (m_selBits[m_vecIdx][m_depth] >= nodep->length()) {
|
|
| 87 |
m_selBits[m_vecIdx][m_depth] = 0; |
|
| 88 |
if (m_depth + 1 < m_selBits[m_vecIdx].size()) |
|
| 89 |
m_selBits[m_vecIdx][m_depth+1] += 1; |
|
| 90 |
} |
|
| 91 |
// Reassign the bitp() |
|
| 92 |
if (nodep->length() > 1) {
|
|
| 93 |
if (AstConst* bitp = nodep->bitp()->castConst()) {
|
|
| 94 |
unsigned idx = nodep->start() + m_selBits[m_vecIdx][m_depth]; |
|
| 95 |
AstNode* constp = new AstConst(bitp->fileline(), V3Number(bitp->fileline(), bitp->castConst()->num().width(), idx)); |
|
| 96 |
bitp->replaceWith(constp); |
|
| 97 |
} else {
|
|
| 98 |
nodep->v3error("Unsupported: Only constants supported in slices");
|
|
| 99 |
} |
|
| 100 |
} |
|
| 101 |
if (!nodep->backp()->castArraySel()) {
|
|
| 102 |
// Top ArraySel, increment m_selBits |
|
| 103 |
m_selBits[m_vecIdx][0] += 1; |
|
| 104 |
} |
|
| 105 |
nodep->length(1); |
|
| 106 |
} |
|
| 107 | ||
| 108 |
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
|
| 109 |
m_selBits.clear(); |
|
| 110 |
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl); |
|
| 111 |
for (int i = 0; i < nodep->user2(); ++i) {
|
|
| 112 |
// Clone the node and iterate over the clone |
|
| 113 |
m_vecIdx = -1; |
|
| 114 |
AstNodeAssign* clonep = nodep->cloneTree(false)->castNodeAssign(); |
|
| 115 |
clonep->iterateChildren(*this); |
|
| 116 |
nodep->addNextHere(clonep); |
|
| 117 |
} |
|
| 118 |
nodep->unlinkFrBack(false)->deleteTree(); nodep = NULL; |
|
| 119 |
} |
|
| 120 | ||
| 121 |
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
| 122 |
// Default: Just iterate |
|
| 123 |
nodep->iterateChildren(*this); |
|
| 124 |
} |
|
| 125 |
public: |
|
| 126 |
// CONSTUCTORS |
|
| 127 |
SliceCloneVisitor(AstNodeAssign* assignp) {
|
|
| 128 |
assignp->accept(*this); |
|
| 129 |
} |
|
| 130 |
virtual ~SliceCloneVisitor() {}
|
|
| 131 |
}; |
|
| 132 | ||
| 133 |
class SliceVisitor : public AstNVisitor {
|
|
| 134 |
private: |
|
| 135 |
// NODE STATE |
|
| 136 |
// Cleared on netlist |
|
| 137 |
// AstNodeAssign::user1() -> bool. True if find is complete |
|
| 138 |
// AstNodeAssign::user2() -> int. The number of clones needed for this assign |
|
| 139 |
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to |
|
| 140 |
AstUser1InUse m_inuser1; |
|
| 141 |
AstUser2InUse m_inuser2; |
|
| 142 | ||
| 143 |
// STATE |
|
| 144 |
AstNode* m_assign; // The assignment we are under |
|
| 145 |
AstNodeVarRef* m_lhspVarRef; // Var on the LHS |
|
| 146 |
bool m_extend; // True if we have found an extend node |
|
| 147 | ||
| 148 |
// METHODS |
|
| 149 |
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
|
| 150 |
// The LHS/RHS of an Assign may be to a Var that is an array. In this |
|
| 151 |
// case we need to create a slice accross the entire Var |
|
| 152 |
if (m_assign && !nodep->backp()->castArraySel()) {
|
|
| 153 |
uint32_t dimensions = nodep->varp()->dimensions(); |
|
| 154 |
if (dimensions > 0) {
|
|
| 155 |
AstNode* newp = insertImplicit(nodep->cloneTree(false), 1, dimensions); |
|
| 156 |
nodep->replaceWith(newp); nodep = NULL; |
|
| 157 |
newp->iterateChildren(*this); |
|
| 158 |
} |
|
| 159 |
} |
|
| 160 |
} |
|
| 161 | ||
| 162 |
// Find out how many explicit dimensions are in a given ArraySel. |
|
| 163 |
unsigned explicitDimensions(AstArraySel* nodep) {
|
|
| 164 |
unsigned dim = 0; |
|
| 165 |
AstNode* fromp = nodep; |
|
| 166 |
AstArraySel* selp; |
|
| 167 |
do {
|
|
| 168 |
selp = fromp->castArraySel(); |
|
| 169 |
if (!selp) {
|
|
| 170 |
nodep->user1p(fromp->castVarRef()); |
|
| 171 |
selp = NULL; |
|
| 172 |
} else {
|
|
| 173 |
fromp = selp->fromp(); |
|
| 174 |
if (fromp) |
|
| 175 |
++dim; |
|
| 176 |
} |
|
| 177 |
} while (fromp && selp); |
|
| 178 |
UASSERT(m_assign->user1p(), "Couldn't find VarRef under the ArraySel"); |
|
| 179 |
return dim; |
|
| 180 |
} |
|
| 181 | ||
| 182 |
AstNode* insertImplicit(AstVarRef* nodep, unsigned start, unsigned count) {
|
|
| 183 |
// Insert any implicit slices as explicit slices (ArraySel nodes). |
|
| 184 |
// Return a new pointer to replace fromp() in the ArraySel. |
|
| 185 |
AstVarRef* fromp = nodep; |
|
| 186 |
UASSERT(fromp, "NULL VarRef passed to insertImplicit"); |
|
| 187 |
AstVar* varp = fromp->varp(); |
|
| 188 |
// Get the DType and insert a new ArraySel |
|
| 189 |
AstArraySel* topp = NULL; |
|
| 190 |
AstArraySel* bottomp = NULL; |
|
| 191 |
for (unsigned i = start; i < start + count; ++i) {
|
|
| 192 |
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1); |
|
| 193 |
AstArrayDType* adtypep = dtypep->castArrayDType(); |
|
| 194 |
UASSERT(adtypep, "insertImplicit tried to expand an array without an ArrayDType"); |
|
| 195 |
vlsint32_t msb = adtypep->msb(); |
|
| 196 |
vlsint32_t lsb = adtypep->lsb(); |
|
| 197 |
if (lsb > msb) {
|
|
| 198 |
// Below code assumes big bit endian; just works out if we swap |
|
| 199 |
int x = msb; msb = lsb; lsb = x; |
|
| 200 |
} |
|
| 201 |
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, new AstConst(nodep->fileline(),lsb)); |
|
| 202 |
newp->start(lsb); |
|
| 203 |
newp->length(msb - lsb + 1); |
|
| 204 |
if (!topp) |
|
| 205 |
topp = newp; |
|
| 206 |
fromp = newp->fromp()->unlinkFrBack()->castVarRef(); |
|
| 207 | ||
| 208 |
if (bottomp) |
|
| 209 |
bottomp->fromp(newp); |
|
| 210 |
bottomp = newp; |
|
| 211 |
} |
|
| 212 |
bottomp->fromp(fromp); |
|
| 213 |
return topp; |
|
| 214 |
} |
|
| 215 | ||
| 216 |
int countClones(AstArraySel* nodep) {
|
|
| 217 |
// Count how many clones we need to make from this ArraySel |
|
| 218 |
int clones = 1; |
|
| 219 |
AstNode* fromp = nodep; |
|
| 220 |
AstArraySel* selp; |
|
| 221 |
do {
|
|
| 222 |
selp = fromp->castArraySel(); |
|
| 223 |
fromp = (selp) ? selp->fromp() : NULL; |
|
| 224 |
if (fromp && selp) |
|
| 225 |
clones *= selp->length(); |
|
| 226 |
} while (fromp && selp); |
|
| 227 |
return clones; |
|
| 228 |
} |
|
| 229 | ||
| 230 |
virtual void visit(AstExtend* nodep, AstNUser*) {
|
|
| 231 |
m_extend = true; |
|
| 232 |
if (m_assign && m_assign->user2() > 1) {
|
|
| 233 |
m_assign->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
|
| 234 |
} |
|
| 235 |
nodep->iterateChildren(*this); |
|
| 236 |
} |
|
| 237 | ||
| 238 |
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
|
| 239 |
if (!m_assign) |
|
| 240 |
return; |
|
| 241 |
unsigned dim = explicitDimensions(nodep); |
|
| 242 |
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef(); |
|
| 243 |
unsigned implicit = refp->varp()->dimensions() - dim; |
|
| 244 |
if (implicit > 0) {
|
|
| 245 |
AstNode* backp = refp->backp(); |
|
| 246 |
AstNode* newp = insertImplicit(refp->cloneTree(false), dim+1, implicit); |
|
| 247 |
backp->castArraySel()->fromp()->replaceWith(newp); |
|
| 248 |
} |
|
| 249 |
int clones = countClones(nodep); |
|
| 250 |
if (m_assign->user2() > 0 && m_assign->user2() != clones) {
|
|
| 251 |
m_assign->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
|
| 252 |
} else if (m_assign->user2() == 0) {
|
|
| 253 |
if (m_extend && clones > 1) {
|
|
| 254 |
m_assign->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
|
| 255 |
} |
|
| 256 |
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhspVarRef->varp() && !m_assign->castAssignDly()) {
|
|
| 257 |
// LHS Var != RHS Var for a non-delayed assignment |
|
| 258 |
m_assign->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
|
| 259 |
} |
|
| 260 |
m_assign->user2(clones); |
|
| 261 |
} |
|
| 262 |
} |
|
| 263 | ||
| 264 |
virtual void visit(AstSel* nodep, AstNUser*) {
|
|
| 265 |
m_extend = true; |
|
| 266 |
if (m_assign && m_assign->user2() > 1) {
|
|
| 267 |
m_assign->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
|
| 268 |
} |
|
| 269 |
nodep->iterateChildren(*this); |
|
| 270 |
} |
|
| 271 | ||
| 272 |
// Return the first AstVarRef under the node |
|
| 273 |
AstVarRef* findVarRefRecurse(AstNode* nodep) |
|
| 274 |
{
|
|
| 275 |
AstVarRef* refp; |
|
| 276 |
if (refp = nodep->castVarRef()) |
|
| 277 |
return refp; |
|
| 278 |
if (nodep->op1p()) {
|
|
| 279 |
refp = findVarRefRecurse(nodep->op1p()); |
|
| 280 |
if (refp) return refp; |
|
| 281 |
} |
|
| 282 |
if (nodep->op2p()) {
|
|
| 283 |
refp = findVarRefRecurse(nodep->op2p()); |
|
| 284 |
if (refp) return refp; |
|
| 285 |
} |
|
| 286 |
if (nodep->op3p()) {
|
|
| 287 |
refp = findVarRefRecurse(nodep->op3p()); |
|
| 288 |
if (refp) return refp; |
|
| 289 |
} |
|
| 290 |
if (nodep->op3p()) {
|
|
| 291 |
refp = findVarRefRecurse(nodep->op3p()); |
|
| 292 |
if (refp) return refp; |
|
| 293 |
} |
|
| 294 |
if (nodep->nextp()) {
|
|
| 295 |
refp = findVarRefRecurse(nodep->nextp()); |
|
| 296 |
if (refp) return refp; |
|
| 297 |
} |
|
| 298 |
return NULL; |
|
| 299 |
} |
|
| 300 | ||
| 301 |
void findImplicit(AstNodeAssign* nodep) {
|
|
| 302 |
UASSERT(!m_assign, "Found a NodeAssign under another NodeAssign"); |
|
| 303 |
m_assign = nodep; |
|
| 304 |
m_extend = false; |
|
| 305 |
nodep->user1(true); |
|
| 306 |
// Record the LHS Var so we can check if the Var on the RHS is the same |
|
| 307 |
m_lhspVarRef = findVarRefRecurse(nodep->lhsp()); |
|
| 308 |
UASSERT(m_lhspVarRef, "Couldn't find a VarRef on the LHSP of an Assign"); |
|
| 309 |
// Iterate children looking for ArraySel nodes. From that we get the number of elements |
|
| 310 |
// in the array so we know how many times we need to clone this assignment. |
|
| 311 |
nodep->iterateChildren(*this); |
|
| 312 |
if (nodep->user2() > 1) {
|
|
| 313 |
SliceCloneVisitor scv(nodep); |
|
| 314 |
} |
|
| 315 |
m_assign = NULL; |
|
| 316 |
} |
|
| 317 | ||
| 318 |
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
|
| 319 |
if (!nodep->user1()) {
|
|
| 320 |
// Hasn't been searched for implicit slices yet |
|
| 321 |
findImplicit(nodep); |
|
| 322 |
} |
|
| 323 |
} |
|
| 324 | ||
| 325 |
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
| 326 |
// Default: Just iterate |
|
| 327 |
nodep->iterateChildren(*this); |
|
| 328 |
} |
|
| 329 | ||
| 330 |
public: |
|
| 331 |
// CONSTUCTORS |
|
| 332 |
SliceVisitor(AstNetlist* rootp) {
|
|
| 333 |
m_assign = NULL; |
|
| 334 |
m_lhspVarRef = NULL; |
|
| 335 |
AstNode::user1ClearTree(); |
|
| 336 |
AstNode::user2ClearTree(); |
|
| 337 |
rootp->accept(*this); |
|
| 338 |
} |
|
| 339 |
virtual ~SliceVisitor() {}
|
|
| 340 |
}; |
|
| 341 | ||
| 342 |
//###################################################################### |
|
| 343 |
// Link class functions |
|
| 344 | ||
| 345 |
void V3Slice::expandAll(AstNetlist* rootp) {
|
|
| 346 |
UINFO(4,__FUNCTION__<<": "<<endl); |
|
| 347 |
SliceVisitor visitor(rootp); |
|
| 348 |
} |
|
| b/src/V3Slice.h | ||
|---|---|---|
| 1 |
// -*- C++ -*- |
|
| 2 |
//************************************************************************* |
|
| 3 |
// DESCRIPTION: Verilator: Link modules/signals together |
|
| 4 |
// |
|
| 5 |
// Code available from: http://www.veripool.org/verilator |
|
| 6 |
// |
|
| 7 |
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli |
|
| 8 |
// |
|
| 9 |
//************************************************************************* |
|
| 10 |
// |
|
| 11 |
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can |
|
| 12 |
// redistribute it and/or modify it under the terms of either the GNU |
|
| 13 |
// Lesser General Public License Version 3 or the Perl Artistic License |
|
| 14 |
// Version 2.0. |
|
| 15 |
// |
|
| 16 |
// Verilator is distributed in the hope that it will be useful, |
|
| 17 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 18 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 19 |
// GNU General Public License for more details. |
|
| 20 |
// |
|
| 21 |
//************************************************************************* |
|
| 22 | ||
| 23 |
#ifndef _V3LINKSLICE_H_ |
|
| 24 |
#define _V3LINKSLICE_H_ 1 |
|
| 25 |
#include "config_build.h" |
|
| 26 |
#include "verilatedos.h" |
|
| 27 |
#include "V3Error.h" |
|
| 28 |
#include "V3Ast.h" |
|
| 29 | ||
| 30 |
//============================================================================ |
|
| 31 | ||
| 32 |
class V3Slice {
|
|
| 33 |
public: |
|
| 34 |
static void expandAll(AstNetlist* nodep); |
|
| 35 |
}; |
|
| 36 | ||
| 37 |
#endif // Guard |
|
| b/src/V3WidthSel.cpp | ||
|---|---|---|
| 80 | 80 |
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: "); |
| 81 | 81 |
AstNodeDType* ddtypep = varp->dtypeDimensionp(dimension); |
| 82 | 82 |
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
| 83 |
if (rangedSelect) {
|
|
| 84 |
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
|
| 85 |
return NULL; |
|
| 86 |
} |
|
| 87 | 83 |
return adtypep; |
| 88 | 84 |
} |
| 89 | 85 |
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
| ... | ... | |
| 247 | 243 |
vlsint32_t msb = msbp->castConst()->toSInt(); |
| 248 | 244 |
vlsint32_t lsb = lsbp->castConst()->toSInt(); |
| 249 | 245 |
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, msb!=lsb); |
| 250 |
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
|
| 246 |
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
|
|
| 247 |
if (msb!=lsb) {
|
|
| 248 |
AstArraySel* newp = new AstArraySel (nodep->fileline(), |
|
| 249 |
fromp, lsbp); |
|
| 250 |
newp->start(lsb); |
|
| 251 |
newp->length((msb - lsb) + 1); |
|
| 252 |
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL; |
|
| 253 |
} else {
|
|
| 254 |
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
|
|
| 255 |
} |
|
| 256 |
} else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
|
|
| 251 | 257 |
if (adtypep) {} // Unused
|
| 252 | 258 |
if (varp->basicp()->rangep() && varp->basicp()->rangep()->littleEndian()) {
|
| 253 | 259 |
// Below code assumes big bit endian; just works out if we swap |
| b/src/Verilator.cpp | ||
|---|---|---|
| 74 | 74 |
#include "V3Premit.h" |
| 75 | 75 |
#include "V3Scope.h" |
| 76 | 76 |
#include "V3Signed.h" |
| 77 |
#include "V3Slice.h" |
|
| 77 | 78 |
#include "V3Split.h" |
| 78 | 79 |
#include "V3SplitAs.h" |
| 79 | 80 |
#include "V3Stats.h" |
| ... | ... | |
| 280 | 281 |
V3Unroll::unrollAll(v3Global.rootp()); |
| 281 | 282 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
|
| 282 | 283 | |
| 284 |
// Expand slices of arrays |
|
| 285 |
V3Slice::expandAll(v3Global.rootp()); |
|
| 286 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("slices.tree"));
|
|
| 287 | ||
| 283 | 288 |
// Convert case statements to if() blocks. Must be after V3Unknown |
| 284 | 289 |
V3Case::caseAll(v3Global.rootp()); |
| 285 | 290 |
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
|
| b/test_regress/t/t_mem_multi_ref_bad.pl | ||
|---|---|---|
| 12 | 12 |
nc=>0, # Need to get it not to give the prompt |
| 13 | 13 |
expect=> |
| 14 | 14 |
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dimn
|
| 15 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal range select; variable already selected, or bad dimension |
|
| 15 | 16 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0 |
| 17 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension |
|
| 16 | 18 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1 |
| 17 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2 |
|
| 18 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2 |
|
| 19 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv |
|
| 19 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension |
|
| 20 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal \+: or -: select; variable already selected, or bad dimension |
|
| 20 | 21 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0nv |
| 22 |
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension |
|
| 21 | 23 |
.*%Error: Exiting due to.*}, |
| 22 | 24 |
); |
| 23 | 25 | |
| 24 | 26 |
ok(1); |
| 25 | 27 |
1; |
| 26 | ||
| b/test_regress/t/t_mem_packed_assign.pl | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
|
| 3 |
# DESCRIPTION: Verilator: Verilog Test driver/expect definition |
|
| 4 |
# |
|
| 5 |
# Copyright 2003 by Wilson Snyder. This program is free software; you can |
|
| 6 |
# redistribute it and/or modify it under the terms of either the GNU |
|
| 7 |
# Lesser General Public License Version 3 or the Perl Artistic License |
|
| 8 |
# Version 2.0. |
|
| 9 | ||
| 10 |
compile ( |
|
| 11 |
v_flags => ["--lint-only"], |
|
| 12 |
fails=>1, |
|
| 13 |
expect=> |
|
| 14 |
'%Error: t/t_mem_packed_assign.v:\d+: Unsupported: Assignment between packed arrays of different dimensions |
|
| 15 |
%Error: t/t_mem_packed_assign.v:\d+: Unsupported: Assignment between packed arrays of different dimensions |
|
| 16 |
%Error: Exiting due to.*', |
|
| 17 |
); |
|
| 18 | ||
| 19 |
ok(1); |
|
| 20 |
1; |
|
| b/test_regress/t/t_mem_packed_assign.v | ||
|---|---|---|
| 1 |
// DESCRIPTION: Verilator: Verilog Test module |
|
| 2 |
// |
|
| 3 |
// This file ONLY is placed into the Public Domain, for any use, |
|
| 4 |
// without warranty, 2009 by Wilson Snyder. |
|
| 5 | ||
| 6 |
module t (/*AUTOARG*/ |
|
| 7 |
// Inputs |
|
| 8 |
clk |
|
| 9 |
); |
|
| 10 | ||
| 11 |
/* verilator lint_off WIDTH */ |
|
| 12 | ||
| 13 |
input clk; |
|
| 14 | ||
| 15 |
integer cyc; initial cyc = 0; |
|
| 16 |
logic [31:0] arr_c; initial arr_c = 0; |
|
| 17 |
logic [7:0] [3:0] arr; |
|
| 18 | ||
| 19 |
logic [31:0] arr2_c; initial arr2_c = 0; |
|
| 20 |
logic [7:0] [3:0] arr2; |
|
| 21 |
assign arr2_c = arr2; |
|
| 22 | ||
| 23 |
always @ (posedge clk) begin |
|
| 24 |
cyc <= cyc + 1; |
|
| 25 |
arr_c <= arr_c + 1; |
|
| 26 |
arr2 <= arr2 + 1; |
|
| 27 |
$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]);
|
|
| 28 |
if (cyc==99) begin |
|
| 29 |
$write("*-* All Finished *-*\n");
|
|
| 30 |
$finish; |
|
| 31 |
end |
|
| 32 |
end |
|
| 33 | ||
| 34 |
/* verilator lint_on WIDTH */ |
|
| 35 | ||
| 36 |
endmodule |
|
| b/test_regress/t/t_mem_slice.pl | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
|
| 3 |
# DESCRIPTION: Verilator: Verilog Test driver/expect definition |
|
| 4 |
# |
|
| 5 |
# Copyright 2003 by Wilson Snyder. This program is free software; you can |
|
| 6 |
# redistribute it and/or modify it under the terms of either the GNU |
|
| 7 |
# Lesser General Public License Version 3 or the Perl Artistic License |
|
| 8 |
# Version 2.0. |
|
| 9 | ||
| 10 |
compile ( |
|
| 11 |
v_flags => [], |
|
| 12 |
); |
|
| 13 | ||
| 14 |
execute ( |
|
| 15 |
check_finished=>1, |
|
| 16 |
); |
|
| 17 | ||
| 18 |
ok(1); |
|
| 19 |
1; |
|
| b/test_regress/t/t_mem_slice.v | ||
|---|---|---|
| 1 |
// DESCRIPTION: Verilator: Verilog Test module |
|
| 2 |
// |
|
| 3 |
// This file ONLY is placed into the Public Domain, for any use, |
|
| 4 |
// without warranty, 2009 by Wilson Snyder. |
|
| 5 | ||
| 6 |
module t (/*AUTOARG*/ |
|
| 7 |
// Inputs |
|
| 8 |
clk |
|
| 9 |
); |
|
| 10 | ||
| 11 |
input clk; |
|
| 12 | ||
| 13 |
logic use_AnB; |
|
| 14 |
logic [1:0] active_command [8:0]; |
|
| 15 |
logic [1:0] command_A [8:0]; |
|
| 16 |
logic [1:0] command_B [8:0]; |
|
| 17 | ||
| 18 |
logic [1:0] active_command2 [8:0]; |
|
| 19 |
logic [1:0] command_A2 [8:0]; |
|
| 20 |
logic [1:0] command_B2 [8:0]; |
|
| 21 | ||
| 22 |
logic [1:0] active_command3 [1:0][2:0][3:0]; |
|
| 23 |
logic [1:0] command_A3 [1:0][2:0][3:0]; |
|
| 24 |
logic [1:0] command_B3 [1:0][2:0][3:0]; |
|
| 25 | ||
| 26 |
logic [8:0] pipe1 [7:0]; |
|
| 27 |
logic [8:0] pipe1_input; |
|
| 28 | ||
| 29 |
integer cyc; |
|
| 30 | ||
| 31 |
assign active_command[8:0] = (use_AnB) ? command_A[8:0] : command_B[8:0]; |
|
| 32 |
assign active_command2 = (use_AnB) ? command_A2 : command_B2; |
|
| 33 |
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]; |
|
| 34 | ||
| 35 |
always @ (posedge clk) begin |
|
| 36 |
pipe1_input <= pipe1_input + 1; |
|
| 37 |
pipe1[0] <= pipe1_input; |
|
| 38 |
pipe1[7:1] <= pipe1[6:0]; |
|
| 39 |
end |
|
| 40 | ||
| 41 |
logic [3:0][13:0] iq_read_data [15:0]; |
|
| 42 |
logic [3:0][13:0] iq_data; |
|
| 43 |
logic [3:0] sel; |
|
| 44 | ||
| 45 |
assign iq_data = iq_read_data[sel]; |
|
| 46 | ||
| 47 |
always @ (posedge clk) begin |
|
| 48 |
sel = sel + 1; |
|
| 49 |
end |
|
| 50 | ||
| 51 |
initial begin |
|
| 52 |
cyc = 0; |
|
| 53 |
use_AnB = 0; |
|
| 54 |
for (int i = 0; i < 7; ++i) begin |
|
| 55 |
command_A[i] = 2'b00; |
|
| 56 |
command_B[i] = 2'b11; |
|
| 57 |
command_A2[i] = 2'b00; |
|
| 58 |
command_B2[i] = 2'b11; |
|
| 59 |
pipe1_input = 9'b0; |
|
| 60 |
end |
|
| 61 |
for (int i = 0; i < 2; ++i) begin |
|
| 62 |
for (int j = 0; j < 3; ++j) begin |
|
| 63 |
for (int k = 0; k < 4; ++k) begin |
|
| 64 |
command_A3[i][j][k] = 2'b00; |
|
| 65 |
command_B3[i][j][k] = 2'b11; |
|
| 66 |
end |
|
| 67 |
end |
|
| 68 |
end |
|
| 69 |
end |
|
| 70 | ||
| 71 |
always @ (posedge clk) begin |
|
| 72 |
use_AnB <= ~use_AnB; |
|
| 73 |
cyc <= cyc + 1; |
|
| 74 |
if (use_AnB) begin |
|
| 75 |
if (active_command[3] != 2'b00) begin |
|
| 76 |
$stop; |
|
| 77 |
end |
|
| 78 |
if (active_command2[3] != 2'b00) begin |
|
| 79 |
$stop; |
|
| 80 |
end |
|
| 81 |
if (active_command3[0][1][2] != 2'b00) begin |
|
| 82 |
$stop; |
|
| 83 |
end |
|
| 84 |
end |
|
| 85 |
if (!use_AnB) begin |
|
| 86 |
if (active_command[3] != 2'b11) begin |
|
| 87 |
$stop; |
|
| 88 |
end |
|
| 89 |
if (active_command2[3] != 2'b11) begin |
|
| 90 |
$stop; |
|
| 91 |
end |
|
| 92 |
if (active_command3[3][1][2] != 2'b11) begin |
|
| 93 |
$stop; |
|
| 94 |
end |
|
| 95 |
end |
|
| 96 |
end |
|
| 97 | ||
| 98 |
logic [8:0] last_pipe; |
|
| 99 |
always @(posedge clk) begin |
|
| 100 |
if (cyc < 3) begin |
|
| 101 |
last_pipe <= pipe1[0]; |
|
| 102 |
end |
|
| 103 |
else begin |
|
| 104 |
if (last_pipe + 1 != pipe1[0]) begin |
|
| 105 |
$stop; |
|
| 106 |
end |
|
| 107 |
else begin |
|
| 108 |
last_pipe <= pipe1[0]; |
|
| 109 |
end |
|
| 110 |
end |
|
| 111 |
if (cyc > 10) begin |
|
| 112 |
$write("*-* All Finished *-*\n");
|
|
| 113 |
$finish; |
|
| 114 |
end |
|
| 115 |
end |
|
| 116 | ||
| 117 |
endmodule : t |
|
| b/test_regress/t/t_mem_slice_bad.pl | ||
|---|---|---|
| 1 |
#!/usr/bin/perl |
|
| 2 |
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
|
| 3 |
# DESCRIPTION: Verilator: Verilog Test driver/expect definition |
|
| 4 |
# |
|
| 5 |
# Copyright 2008 by Wilson Snyder. This program is free software; you can |
|
| 6 |
# redistribute it and/or modify it under the terms of either the GNU |
|
| 7 |
# Lesser General Public License Version 3 or the Perl Artistic License |
|
| 8 |
# Version 2.0. |
|
| 9 | ||
| 10 |
compile ( |
|
| 11 |
v_flags2 => ["--lint-only"], |
|
| 12 |
fails=>1, |
|
| 13 |
expect=> |
|
| 14 |
'%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 15 |
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 16 |
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 17 |
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 18 |
%Error: t/t_mem_slice_bad.v:\d+: Unsupported: Slices in a non-delayed assignment with the same Var on both sides |
|
| 19 |
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 20 |
%Error: t/t_mem_slice_bad.v:\d+: Slices of arrays in assignments must have the same unpacked dimensions |
|
| 21 |
%Error: Exiting due to.*', |
|
| 22 |
) if $Self->{v3};
|
|
| 23 | ||
| 24 |
ok(1); |
|
| 25 |
1; |
|
| b/test_regress/t/t_mem_slice_bad.v | ||
|---|---|---|
| 1 |
// DESCRIPTION: Verilator: Verilog Test module |
|
| 2 |
// |
|
| 3 |
// This file ONLY is placed into the Public Domain, for any use, |
|
| 4 |
// without warranty, 2009 by Wilson Snyder. |
|
| 5 | ||
| 6 |
module t (/*AUTOARG*/ |
|
| 7 |
// Inputs |
|
| 8 |
clk |
|
| 9 |
); |
|
| 10 | ||
| 11 |
input clk; |
|
| 12 | ||
| 13 |
logic use_AnB; |
|
| 14 | ||
| 15 |
logic [1:0] active_command [8:0]; |
|
| 16 |
logic [1:0] command_A [8:0]; |
|
| 17 |
logic [1:0] command_B [8:0]; |
|
| 18 | ||
| 19 |
logic [1:0] active_command2 [8:0]; |
|
| 20 |
logic [1:0] command_A2 [7:0]; |
|
| 21 |
logic [1:0] command_B2 [8:0]; |
|
| 22 | ||
| 23 |
logic [1:0] active_command3 [1:0][2:0][3:0]; |
|
| 24 |
logic [1:0] command_A3 [1:0][2:0][3:0]; |
|
| 25 |
logic [1:0] command_B3 [1:0][2:0][3:0]; |
|
| 26 | ||
| 27 |
logic [1:0] active_command4 [8:0]; |
|
| 28 |
logic [1:0] command_A4 [7:0]; |
|
| 29 | ||
| 30 |
logic [1:0] active_command5 [8:0]; |
|
| 31 |
logic [1:0] command_A5 [7:0]; |
|
| 32 | ||
| 33 |
// Single dimension assign |
|
| 34 |
assign active_command[3:0] = (use_AnB) ? command_A[7:0] : command_B[7:0]; |
|
| 35 |
// Assignment of entire arrays |
|
| 36 |
assign active_command2 = (use_AnB) ? command_A2 : command_B2; |
|
| 37 |
// Multi-dimension assign |
|
| 38 |
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]; |
|
| 39 | ||
| 40 |
// Supported: Delayed assigment with RHS Var == LHS Var |
|
| 41 |
logic [7:0] arrd [7:0]; |
|
| 42 |
always_ff @(posedge clk) arrd[7:4] <= arrd[3:0]; |
|
| 43 | ||
| 44 |
// Unsupported: Non-delayed assigment with RHS Var == LHS Var |
|
| 45 |
logic [7:0] arr [7:0]; |
|
| 46 |
assign arr[7:4] = arr[3:0]; |
|
| 47 | ||
| 48 |
// Delayed assign |
|
| 49 |
always @(posedge clk) begin |
|
| 50 |
active_command4[7:0] <= command_A4[8:0]; |
|
| 51 |
end |
|
| 52 | ||
| 53 |
// Combinational assign |
|
| 54 |
always_comb begin |
|
| 55 |
active_command5[8:0] = command_A5[7:0]; |
|
| 56 |
end |
|
| 57 | ||
| 58 |
endmodule : t |
|
![[logo]](/img/veripool_small.png)