mirror of
https://github.com/verilator/verilator.git
synced 2025-07-30 15:36:11 +00:00
Support some unpacked arrays in parameters, bug1315.
This commit is contained in:
parent
4767083a72
commit
28cbf39995
2
Changes
2
Changes
@ -20,6 +20,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
*** Suppress 'command failed' on normal errors.
|
||||
|
||||
*** Support some unpacked arrays in parameters, bug1315. [Marshal Qiao]
|
||||
|
||||
*** Add interface port visibility in traces, bug1594. [Todd Strader]
|
||||
|
||||
**** Increase case duplicate/incomplete to 16 bit tables, bug1545. [Yossi Nivin]
|
||||
|
@ -919,7 +919,7 @@ public:
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
virtual bool sizeMattersRhs() const { return false; }
|
||||
virtual bool isGateOptimizable() const { return true; } // esp for V3Const::ifSameAssign
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode* samep) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
|
@ -1233,10 +1233,14 @@ private:
|
||||
replaceZero(nodep); VL_DANGLING(nodep);
|
||||
} else {
|
||||
// Fetch the result
|
||||
V3Number* outnump = simvis.fetchNumberNull(nodep);
|
||||
UASSERT_OBJ(outnump, nodep, "No number returned from simulation");
|
||||
AstNode* valuep = simvis.fetchValueNull(nodep); // valuep is owned by Simulate
|
||||
UASSERT_OBJ(valuep, nodep, "No value returned from simulation");
|
||||
// Replace it
|
||||
replaceNum(nodep,*outnump); VL_DANGLING(nodep);
|
||||
AstNode* newp = valuep->cloneTree(false);
|
||||
newp->dtypeFrom(nodep);
|
||||
newp->fileline(nodep->fileline());
|
||||
UINFO(4, "Simulate->"<<newp<<endl);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
|
203
src/V3Simulate.h
203
src/V3Simulate.h
@ -113,7 +113,7 @@ private:
|
||||
// Cleanup
|
||||
// V3Numbers that represents strings are a bit special and the API for
|
||||
// V3Number does not allow changing them.
|
||||
std::deque<AstConst*> m_stringValuesp; // List of allocated string numbers
|
||||
std::deque<AstNode*> m_reclaimValuesp; // List of allocated string numbers
|
||||
|
||||
// Note level 8&9 include debugging each simulation value
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
@ -232,7 +232,29 @@ private:
|
||||
constp->num().isString(nodep->isString());
|
||||
return constp;
|
||||
}
|
||||
public:
|
||||
void newValue(AstNode* nodep, const AstNode* valuep) {
|
||||
if (const AstConst* constp = VN_CAST_CONST(valuep, Const)) {
|
||||
newConst(nodep)->num().opAssign(constp->num());
|
||||
} else if (fetchValueNull(nodep) != valuep) {
|
||||
// const_cast, as clonep() is set on valuep, but nothing should care
|
||||
setValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
|
||||
}
|
||||
}
|
||||
void newOutValue(AstNode* nodep, const AstNode* valuep) {
|
||||
if (const AstConst* constp = VN_CAST_CONST(valuep, Const)) {
|
||||
newOutConst(nodep)->num().opAssign(constp->num());
|
||||
} else if (fetchOutValueNull(nodep) != valuep) {
|
||||
// const_cast, as clonep() is set on valuep, but nothing should care
|
||||
setOutValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
|
||||
}
|
||||
}
|
||||
private:
|
||||
AstNode* newTrackedClone(AstNode* nodep) {
|
||||
AstNode* newp = nodep->cloneTree(false);
|
||||
m_reclaimValuesp.push_back(newp);
|
||||
return newp;
|
||||
}
|
||||
AstConst* newConst(AstNode* nodep) {
|
||||
// Set a constant value for this node
|
||||
if (!VN_IS(nodep->user3p(), Const)) {
|
||||
@ -244,7 +266,7 @@ private:
|
||||
}
|
||||
}
|
||||
AstConst* newOutConst(AstNode* nodep) {
|
||||
// Set a constant value for this node
|
||||
// Set a var-output constant value for this node
|
||||
if (!VN_IS(nodep->user2p(), Const)) {
|
||||
AstConst* constp = allocConst(nodep);
|
||||
setOutValue(nodep, constp);
|
||||
@ -253,12 +275,11 @@ private:
|
||||
return fetchOutConst(nodep);
|
||||
}
|
||||
}
|
||||
void newOutConst(AstNode* nodep, const AstConst* constr) {
|
||||
newOutConst(nodep)->num().opAssign(constr->num());
|
||||
}
|
||||
public:
|
||||
AstNode* fetchValueNull(AstNode* nodep) {
|
||||
return (AstNode*)(nodep->user3p());
|
||||
}
|
||||
private:
|
||||
AstNode* fetchOutValueNull(AstNode* nodep) {
|
||||
return (AstNode*)(nodep->user2p());
|
||||
}
|
||||
@ -268,6 +289,12 @@ private:
|
||||
AstConst* fetchOutConstNull(AstNode* nodep) {
|
||||
return VN_CAST(fetchOutValueNull(nodep), Const);
|
||||
}
|
||||
AstNode* fetchValue(AstNode* nodep) {
|
||||
AstNode* valuep = fetchValueNull(nodep);
|
||||
UASSERT_OBJ(valuep, nodep, "No value found for node.");
|
||||
//UINFO(9, " fetch val "<<*valuep<<" on "<<nodep<<endl);
|
||||
return valuep;
|
||||
}
|
||||
AstConst* fetchConst(AstNode* nodep) {
|
||||
AstConst* constp = fetchConstNull(nodep);
|
||||
UASSERT_OBJ(constp, nodep, "No value found for node.");
|
||||
@ -280,12 +307,6 @@ private:
|
||||
return constp;
|
||||
}
|
||||
public:
|
||||
void newValue(AstNode* nodep, const AstConst* constp) {
|
||||
newConst(nodep, constp);
|
||||
}
|
||||
void newConst(AstNode* nodep, const AstConst* constp) {
|
||||
newConst(nodep)->num().opAssign(constp->num());
|
||||
}
|
||||
V3Number* fetchNumberNull(AstNode* nodep) {
|
||||
AstConst* constp = fetchConstNull(nodep);
|
||||
if (constp) return &constp->num();
|
||||
@ -298,10 +319,12 @@ public:
|
||||
}
|
||||
private:
|
||||
void setValue(AstNode* nodep, const AstNode* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set val "<<valuep->name()<<" on "<<nodep<<endl);
|
||||
nodep->user3p((void*)valuep);
|
||||
}
|
||||
void setOutValue(AstNode* nodep, const AstNode* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set oval "<<valuep->name()<<" on "<<nodep<<endl);
|
||||
nodep->user2p((void*)valuep);
|
||||
}
|
||||
@ -344,13 +367,13 @@ private:
|
||||
// True to jump over this node - all visitors must call this up front
|
||||
return (m_jumpp && m_jumpp->labelp() != nodep);
|
||||
}
|
||||
void assignOutConst(AstNodeAssign* nodep, AstNode* vscp, const AstConst* valuep) {
|
||||
void assignOutValue(AstNodeAssign* nodep, AstNode* vscp, const AstNode* valuep) {
|
||||
if (VN_IS(nodep, AssignDly)) {
|
||||
// Don't do setValue, as value isn't yet visible to following statements
|
||||
newOutConst(vscp, valuep);
|
||||
newOutValue(vscp, valuep);
|
||||
} else {
|
||||
newConst(vscp, valuep);
|
||||
newOutConst(vscp, valuep);
|
||||
newValue(vscp, valuep);
|
||||
newOutValue(vscp, valuep);
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,6 +398,7 @@ private:
|
||||
// Delayed is OK though, as we'll decode the next state separately.
|
||||
if (!VN_IS(nodep->varp()->dtypeSkipRefp(), BasicDType)
|
||||
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), PackArrayDType)
|
||||
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType)
|
||||
&& !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType))
|
||||
clearOptimizable(nodep, "Array references/not basic");
|
||||
if (nodep->lvalue()) {
|
||||
@ -399,10 +423,10 @@ private:
|
||||
}
|
||||
vscp->user1(vscp->user1() | VU_RV);
|
||||
bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep();
|
||||
AstConst* constp = isConst ? fetchConstNull(nodep->varp()->valuep()) : NULL;
|
||||
if (isConst && constp) { // Propagate PARAM constants for constant function analysis
|
||||
AstNode* valuep = isConst ? fetchValueNull(nodep->varp()->valuep()) : NULL;
|
||||
if (isConst && valuep) { // Propagate PARAM constants for constant function analysis
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newConst(vscp, constp);
|
||||
newValue(vscp, valuep);
|
||||
}
|
||||
} else {
|
||||
if (m_checkOnly) varRefCb(nodep);
|
||||
@ -414,16 +438,16 @@ private:
|
||||
"LHS varref should be handled in AstAssign visitor.");
|
||||
{
|
||||
// Return simulation value - copy by reference instead of value for speed
|
||||
AstConst* constp = fetchConstNull(vscp);
|
||||
if (!constp) {
|
||||
AstNode* valuep = fetchValueNull(vscp);
|
||||
if (!valuep) {
|
||||
if (m_params) {
|
||||
clearOptimizable(nodep, "Language violation: reference to non-function-local variable");
|
||||
} else {
|
||||
nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
|
||||
}
|
||||
constp = allocConst(nodep); // Any value; just so recover from error
|
||||
valuep = allocConst(nodep); // Any value; just so recover from error
|
||||
}
|
||||
setValue(nodep, constp);
|
||||
setValue(nodep, valuep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -461,7 +485,13 @@ private:
|
||||
virtual void visit(AstConst* nodep) {
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newConst(nodep, nodep);
|
||||
newValue(nodep, nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) {
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newValue(nodep, nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) {
|
||||
@ -472,7 +502,7 @@ private:
|
||||
if (valuep) {
|
||||
iterateAndNextNull(valuep);
|
||||
if (optimizable()) {
|
||||
newConst(nodep, fetchConst(valuep));
|
||||
newValue(nodep, fetchValue(valuep));
|
||||
}
|
||||
} else {
|
||||
clearOptimizable(nodep, "No value found for enum item");
|
||||
@ -520,9 +550,9 @@ private:
|
||||
if (optimizable()) {
|
||||
if (fetchConst(nodep->lhsp())->num().isNeqZero()) {
|
||||
iterate(nodep->rhsp());
|
||||
newConst(nodep, fetchConst(nodep->rhsp()));
|
||||
newValue(nodep, fetchValue(nodep->rhsp()));
|
||||
} else {
|
||||
newConst(nodep, fetchConst(nodep->lhsp())); // a zero
|
||||
newValue(nodep, fetchValue(nodep->lhsp())); // a zero
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -537,10 +567,10 @@ private:
|
||||
iterate(nodep->lhsp());
|
||||
if (optimizable()) {
|
||||
if (fetchConst(nodep->lhsp())->num().isNeqZero()) {
|
||||
newConst(nodep, fetchConst(nodep->lhsp())); // a one
|
||||
newValue(nodep, fetchValue(nodep->lhsp())); // a one
|
||||
} else {
|
||||
iterate(nodep->rhsp());
|
||||
newConst(nodep, fetchConst(nodep->rhsp()));
|
||||
newValue(nodep, fetchValue(nodep->rhsp()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -556,10 +586,10 @@ private:
|
||||
if (optimizable()) {
|
||||
if (fetchConst(nodep->lhsp())->num().isEqZero()) {
|
||||
AstConst cnst(nodep->fileline(), AstConst::WidthedValue(), 1, 1); // a one
|
||||
newConst(nodep, &cnst); // a one
|
||||
newValue(nodep, &cnst); // a one
|
||||
} else {
|
||||
iterate(nodep->rhsp());
|
||||
newConst(nodep, fetchConst(nodep->rhsp()));
|
||||
newValue(nodep, fetchValue(nodep->rhsp()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -577,15 +607,63 @@ private:
|
||||
if (optimizable()) {
|
||||
if (fetchConst(nodep->condp())->num().isNeqZero()) {
|
||||
iterate(nodep->expr1p());
|
||||
newConst(nodep, fetchConst(nodep->expr1p()));
|
||||
newValue(nodep, fetchValue(nodep->expr1p()));
|
||||
} else {
|
||||
iterate(nodep->expr2p());
|
||||
newConst(nodep, fetchConst(nodep->expr2p()));
|
||||
newValue(nodep, fetchValue(nodep->expr2p()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleAssignArray(AstNodeAssign* nodep, AstArraySel* selp) {
|
||||
iterateAndNextNull(nodep->rhsp()); // Value to assign
|
||||
// At present we only handle single dimensional assignments
|
||||
// To do better, we need the concept of lvalues, or similar, to know where/how to insert
|
||||
checkNodeInfo(selp);
|
||||
iterateAndNextNull(selp->bitp()); // Bit index
|
||||
AstVarRef* varrefp = VN_CAST(selp->fromp(), VarRef);
|
||||
if (!varrefp) {
|
||||
clearOptimizable(nodep, "Array select LHS isn't simple variable");
|
||||
return;
|
||||
}
|
||||
AstUnpackArrayDType* arrayp = VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType);
|
||||
UASSERT_OBJ(arrayp, nodep, "Array select of non-array dtype");
|
||||
AstBasicDType* basicp = VN_CAST(arrayp->subDTypep()->skipRefp(), BasicDType);
|
||||
if (!basicp) {
|
||||
clearOptimizable(nodep, "Array of non-basic dtype (e.g. array-of-array)");
|
||||
return;
|
||||
}
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
AstNode* vscp = varOrScope(varrefp);
|
||||
AstInitArray* initp = NULL;
|
||||
if (AstInitArray* vscpnump = VN_CAST(fetchOutValueNull(vscp), InitArray)) {
|
||||
initp = vscpnump;
|
||||
} else if (AstInitArray* vscpnump = VN_CAST(fetchValueNull(vscp), InitArray)) {
|
||||
initp = vscpnump;
|
||||
} else { // Assignment to unassigned variable, all bits are X
|
||||
// TODO generic initialization which builds X/arrays by recursion
|
||||
AstConst* outconstp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
basicp->widthMin(), 0);
|
||||
if (basicp->isZeroInit()) {
|
||||
outconstp->num().setAllBits0();
|
||||
} else {
|
||||
outconstp->num().setAllBitsX();
|
||||
}
|
||||
|
||||
initp = new AstInitArray(nodep->fileline(), arrayp, outconstp);
|
||||
m_reclaimValuesp.push_back(initp);
|
||||
}
|
||||
uint32_t index = fetchConst(selp->bitp())->toUInt();
|
||||
AstNode* valuep = newTrackedClone(fetchValue(nodep->rhsp()));
|
||||
UINFO(9, " set val["<<index<<"] = "<<valuep<<endl);
|
||||
// Values are in the "real" tree under the InitArray so can eventually extract it,
|
||||
// Not in the usual setValue (pointed to by user2/3p)
|
||||
initp->addIndexValuep(index, valuep);
|
||||
if (debug() >= 9) initp->dumpTree(cout, "-array-");
|
||||
assignOutValue(nodep, vscp, initp);
|
||||
}
|
||||
}
|
||||
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
||||
AstVarRef* varrefp = NULL;
|
||||
V3Number lsb(nodep);
|
||||
@ -595,31 +673,31 @@ private:
|
||||
UASSERT_OBJ(varrefp, nodep,
|
||||
"Indicated optimizable, but no variable found on RHS of select");
|
||||
AstNode* vscp = varOrScope(varrefp);
|
||||
AstConst* outconst = NULL;
|
||||
AstConst* outconstp = NULL;
|
||||
if (AstConst* vscpnump = fetchOutConstNull(vscp)) {
|
||||
outconst = vscpnump;
|
||||
outconstp = vscpnump;
|
||||
} else if (AstConst* vscpnump = fetchConstNull(vscp)) {
|
||||
outconst = vscpnump;
|
||||
outconstp = vscpnump;
|
||||
} else { // Assignment to unassigned variable, all bits are X or 0
|
||||
outconst = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
varrefp->varp()->widthMin(), 0);
|
||||
outconstp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
varrefp->varp()->widthMin(), 0);
|
||||
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
||||
outconst->num().setAllBits0();
|
||||
outconstp->num().setAllBits0();
|
||||
} else {
|
||||
outconst->num().setAllBitsX();
|
||||
outconstp->num().setAllBitsX();
|
||||
}
|
||||
}
|
||||
outconst->num().opSelInto(fetchConst(nodep->rhsp())->num(),
|
||||
lsb,
|
||||
selp->widthConst());
|
||||
assignOutConst(nodep, vscp, outconst);
|
||||
outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(),
|
||||
lsb,
|
||||
selp->widthConst());
|
||||
assignOutValue(nodep, vscp, outconstp);
|
||||
}
|
||||
}
|
||||
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp,
|
||||
AstVarRef*& outVarrefpRef, V3Number& lsbRef,
|
||||
int depth) {
|
||||
// Recurse down to find final variable being set (outVarrefp), with
|
||||
// value to write on nodep->rhsp()
|
||||
// lsb to be eventually set on lsbRef
|
||||
checkNodeInfo(selp);
|
||||
iterateAndNextNull(selp->lsbp()); // Bit index
|
||||
if (AstVarRef* varrefp = VN_CAST(selp->fromp(), VarRef)) {
|
||||
@ -654,6 +732,10 @@ private:
|
||||
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
||||
handleAssignSel(nodep, selp);
|
||||
}
|
||||
else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) {
|
||||
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
||||
handleAssignArray(nodep, selp);
|
||||
}
|
||||
else if (!VN_IS(nodep->lhsp(), VarRef)) {
|
||||
clearOptimizable(nodep, "LHS isn't simple variable");
|
||||
}
|
||||
@ -664,11 +746,28 @@ private:
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (optimizable()) {
|
||||
AstNode* vscp = varOrScope(VN_CAST(nodep->lhsp(), VarRef));
|
||||
assignOutConst(nodep, vscp, fetchConst(nodep->rhsp()));
|
||||
assignOutValue(nodep, vscp, fetchValue(nodep->rhsp()));
|
||||
}
|
||||
}
|
||||
m_inDlyAssign = false;
|
||||
}
|
||||
virtual void visit(AstArraySel* nodep) {
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (AstInitArray* initp = VN_CAST(fetchValueNull(nodep->fromp()), InitArray)) {
|
||||
AstConst* indexp = fetchConst(nodep->bitp());
|
||||
uint32_t offset = indexp->num().toUInt();
|
||||
AstNode* itemp = initp->getIndexDefaultedValuep(offset);
|
||||
if (!itemp) {
|
||||
clearOptimizable(nodep, "Array initialization has too few elements, need element "
|
||||
+cvtToStr(offset));
|
||||
} else {
|
||||
setValue(nodep, itemp);
|
||||
}
|
||||
} else {
|
||||
clearOptimizable(nodep, "Array select of non-array");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
@ -841,7 +940,7 @@ private:
|
||||
if (pinp) { // Else too few arguments in function call - ignore it
|
||||
// Apply value to the function
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newConst(portp, fetchConst(pinp));
|
||||
newValue(portp, fetchValue(pinp));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -853,7 +952,7 @@ private:
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
// Grab return value from output variable (if it's a function)
|
||||
UASSERT_OBJ(funcp->fvarp(), nodep, "Function reference points at non-function");
|
||||
newConst(nodep, fetchConst(funcp->fvarp()));
|
||||
newValue(nodep, fetchValue(funcp->fvarp()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -914,7 +1013,7 @@ private:
|
||||
|
||||
AstConst* resultConstp = new AstConst(nodep->fileline(), AstConst::String(), result);
|
||||
setValue(nodep, resultConstp);
|
||||
m_stringValuesp.push_back(resultConstp);
|
||||
m_reclaimValuesp.push_back(resultConstp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -938,7 +1037,7 @@ private:
|
||||
|
||||
// default
|
||||
// These types are definitely not reducible
|
||||
// AstCoverInc, AstArraySel, AstFinish,
|
||||
// AstCoverInc, AstFinish,
|
||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||
virtual void visit(AstNode* nodep) {
|
||||
if (jumpingOver(nodep)) return;
|
||||
@ -1004,11 +1103,11 @@ public:
|
||||
delete (*it2);
|
||||
}
|
||||
}
|
||||
for (std::deque<AstConst*>::iterator it = m_stringValuesp.begin();
|
||||
it != m_stringValuesp.end(); ++it) {
|
||||
for (std::deque<AstNode*>::iterator it = m_reclaimValuesp.begin();
|
||||
it != m_reclaimValuesp.end(); ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
m_stringValuesp.clear();
|
||||
m_reclaimValuesp.clear();
|
||||
m_constFreeps.clear();
|
||||
m_constAllps.clear();
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt_all} and unsupported("Verilator unsupported, bug1315 unpacked array parameter simulation");
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
|
@ -11,14 +11,14 @@ module t;
|
||||
int sum = 0;
|
||||
for (int i=0; i<4; i++) begin
|
||||
sum = sum + SIZES[i];
|
||||
calc_sums[i][31:0] = sum;
|
||||
calc_sums[i] = sum;
|
||||
//TODO: calc_sums[i][31:0] = sum;
|
||||
end
|
||||
endfunction
|
||||
|
||||
parameter int SUMS[3:0] = calc_sums();
|
||||
|
||||
initial begin
|
||||
$display("%d ",SUMS[0]);
|
||||
if (SUMS[0] != 4) $stop;
|
||||
if (SUMS[1] != 4+3) $stop;
|
||||
if (SUMS[2] != 4+3+2) $stop;
|
||||
|
20
test_regress/t/t_param_array4.pl
Executable file
20
test_regress/t/t_param_array4.pl
Executable file
@ -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 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.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
41
test_regress/t/t_param_array4.v
Normal file
41
test_regress/t/t_param_array4.v
Normal file
@ -0,0 +1,41 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
parameter int SIZES [3:1] = '{10,20,30};
|
||||
parameter int SUMS3 = SIZES[3];
|
||||
parameter int SUMS2 = SIZES[2];
|
||||
parameter int SUMS1 = SIZES[1];
|
||||
|
||||
parameter int LE_SIZES [1:3] = '{10,20,30};
|
||||
parameter int LE_SUMS3 = LE_SIZES[3];
|
||||
parameter int LE_SUMS2 = LE_SIZES[2];
|
||||
parameter int LE_SUMS1 = LE_SIZES[1];
|
||||
|
||||
function int from_array(int index);
|
||||
if (index != 0); return SIZES[index];
|
||||
endfunction
|
||||
function int from_array_le(int index);
|
||||
if (index != 0); return LE_SIZES[index];
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
if (SUMS1 != 30) $stop;
|
||||
if (SUMS2 != 20) $stop;
|
||||
if (SUMS3 != 10) $stop;
|
||||
if (LE_SUMS1 != 10) $stop;
|
||||
if (LE_SUMS2 != 20) $stop;
|
||||
if (LE_SUMS3 != 30) $stop;
|
||||
if (from_array(1) != 30) $stop;
|
||||
if (from_array(2) != 20) $stop;
|
||||
if (from_array(3) != 10) $stop;
|
||||
if (from_array_le(1) != 10) $stop;
|
||||
if (from_array_le(2) != 20) $stop;
|
||||
if (from_array_le(3) != 30) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
20
test_regress/t/t_param_array5.pl
Executable file
20
test_regress/t/t_param_array5.pl
Executable file
@ -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 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.
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
38
test_regress/t/t_param_array5.v
Normal file
38
test_regress/t/t_param_array5.v
Normal file
@ -0,0 +1,38 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2019 by Wilson Snyder.
|
||||
|
||||
//bug1578
|
||||
module t;
|
||||
parameter N = 4;
|
||||
|
||||
typedef logic array_t[N];
|
||||
|
||||
parameter array_t MASK = mask_array();
|
||||
//TODO bug1578: parameter MASK = mask_array();
|
||||
|
||||
function array_t mask_array();
|
||||
for(int i = 0; i < N; i++) begin
|
||||
mask_array[i] = i[0];
|
||||
end
|
||||
endfunction
|
||||
|
||||
array_t norm;
|
||||
|
||||
initial begin
|
||||
if (N != 4) $stop;
|
||||
norm = mask_array();
|
||||
if (norm[0] != 1'b0) $stop;
|
||||
if (norm[1] != 1'b1) $stop;
|
||||
if (norm[2] != 1'b0) $stop;
|
||||
if (norm[3] != 1'b1) $stop;
|
||||
if (MASK[0] != 1'b0) $stop;
|
||||
if (MASK[1] != 1'b1) $stop;
|
||||
if (MASK[2] != 1'b0) $stop;
|
||||
if (MASK[3] != 1'b1) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user