Fix concatenates and vectored bufif1, bug326.
This commit is contained in:
parent
2e67a91982
commit
cfdb852843
2
Changes
2
Changes
|
|
@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
**** Support $bits(data_type), bug327. [Alex Solomatnikov]
|
**** Support $bits(data_type), bug327. [Alex Solomatnikov]
|
||||||
|
|
||||||
|
**** Fix concatenates and vectored bufif1, bug326. [Iztok Jeras]
|
||||||
|
|
||||||
* Verilator 3.811 2011/02/14
|
* Verilator 3.811 2011/02/14
|
||||||
|
|
||||||
**** Report errors on duplicated or empty pins, bug321. [Christian Leber]
|
**** Report errors on duplicated or empty pins, bug321. [Christian Leber]
|
||||||
|
|
|
||||||
|
|
@ -3152,6 +3152,19 @@ struct AstReplicate : public AstNodeBiop {
|
||||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||||
virtual int instrCount() const { return widthInstrs()*2; }
|
virtual int instrCount() const { return widthInstrs()*2; }
|
||||||
};
|
};
|
||||||
|
struct AstBufIf1 : public AstNodeBiop {
|
||||||
|
// lhs is enable, rhs is data to drive
|
||||||
|
AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||||
|
if (lhsp) widthSignedFrom(lhsp); }
|
||||||
|
ASTNODE_NODE_FUNCS(BufIf1, BUFIF1)
|
||||||
|
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opBufIf1(lhs,rhs); }
|
||||||
|
virtual string emitVerilog() { return "bufif(%r,%l)"; }
|
||||||
|
virtual string emitC() { V3ERROR_NA; return false;} // Lclean || Rclean
|
||||||
|
virtual string emitSimpleOperator() { V3ERROR_NA; return false;} // Lclean || Rclean
|
||||||
|
virtual bool cleanOut() {V3ERROR_NA; return false;} // Lclean || Rclean
|
||||||
|
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||||
|
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||||
|
};
|
||||||
struct AstFGetS : public AstNodeBiop {
|
struct AstFGetS : public AstNodeBiop {
|
||||||
AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {}
|
AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {}
|
||||||
ASTNODE_NODE_FUNCS(FGetS, FGETS)
|
ASTNODE_NODE_FUNCS(FGetS, FGETS)
|
||||||
|
|
|
||||||
|
|
@ -1061,6 +1061,24 @@ private:
|
||||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void replaceSelIntoBiop(AstSel* nodep) {
|
||||||
|
// SEL(BUFIF1(a,b),1,bit) => BUFIF1(SEL(a,1,bit),SEL(b,1,bit))
|
||||||
|
AstNodeBiop* fromp = nodep->fromp()->unlinkFrBack()->castNodeBiop();
|
||||||
|
if (!fromp) nodep->v3fatalSrc("Called on non biop");
|
||||||
|
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
|
||||||
|
AstNode* widthp = nodep->widthp()->unlinkFrBack();
|
||||||
|
//
|
||||||
|
AstNode* bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||||
|
AstNode* birhsp = fromp->rhsp()->unlinkFrBack();
|
||||||
|
//
|
||||||
|
fromp->lhsp(new AstSel(nodep->fileline(),
|
||||||
|
bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)));
|
||||||
|
fromp->rhsp(new AstSel(nodep->fileline(),
|
||||||
|
birhsp, lsbp, widthp));
|
||||||
|
fromp->widthSignedFrom(nodep);
|
||||||
|
nodep->replaceWith(fromp); nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||||
|
|
@ -1767,6 +1785,10 @@ private:
|
||||||
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||||
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
|
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
|
||||||
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
|
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
|
||||||
|
// V3Tristate requires selects below BufIf1.
|
||||||
|
// We can probably extend this to additional logical operators, but only definite
|
||||||
|
// win if bit select is a constant (otherwise we may need to compute bit index several times)
|
||||||
|
TREEOPV("AstSel{$fromp.castBufIf1}", "replaceSelIntoBiop(nodep)");
|
||||||
// Conversions
|
// Conversions
|
||||||
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
|
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
|
||||||
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
|
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
|
||||||
|
|
|
||||||
|
|
@ -1318,6 +1318,15 @@ V3Number& V3Number::opPowS (const V3Number& lhs, const V3Number& rhs) {
|
||||||
return setAllBitsX();
|
return setAllBitsX();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V3Number& V3Number::opBufIf1 (const V3Number& ens, const V3Number& if1s) {
|
||||||
|
setZero();
|
||||||
|
for(int bit=0; bit<this->width(); bit++) {
|
||||||
|
if (ens.bitIs1(bit)) { setBit(bit, if1s.bitIs(bit)); }
|
||||||
|
else setBit(bit,'z');
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
V3Number& V3Number::opAssign (const V3Number& lhs) {
|
V3Number& V3Number::opAssign (const V3Number& lhs) {
|
||||||
// Note may be a width change during the assign
|
// Note may be a width change during the assign
|
||||||
setZero();
|
setZero();
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ public:
|
||||||
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
|
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
|
||||||
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
|
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
|
||||||
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
|
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
|
||||||
|
V3Number& opBufIf1 (const V3Number& lhs, const V3Number& rhs);
|
||||||
// "standard" math
|
// "standard" math
|
||||||
V3Number& opNot (const V3Number& lhs);
|
V3Number& opNot (const V3Number& lhs);
|
||||||
V3Number& opLogNot (const V3Number& lhs);
|
V3Number& opLogNot (const V3Number& lhs);
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ private:
|
||||||
virtual void visit(AstLogOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstLogOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
virtual void visit(AstLogIf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstLogIf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
virtual void visit(AstLogIff* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstLogIff* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
|
virtual void visit(AstBufIf1* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
// ... These shouldn't matter, just make unsigned
|
// ... These shouldn't matter, just make unsigned
|
||||||
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ private:
|
||||||
// assign x = (OE) ? 'hz : y;
|
// assign x = (OE) ? 'hz : y;
|
||||||
|
|
||||||
// see if this a COND and separate out the __en logic from the output logic if it is
|
// see if this a COND and separate out the __en logic from the output logic if it is
|
||||||
if (nodep->rhsp()->castCond()) {
|
if (AstCond* condp = nodep->rhsp()->castCond()) {
|
||||||
AstCond* condp = nodep->rhsp()->castCond();
|
//if (debug()>=9) nodep->dumpTree(cout,"- cond-in: ");
|
||||||
AstNode* oep = condp->condp();
|
AstNode* oep = condp->condp();
|
||||||
AstNode* expr1p = condp->expr1p();
|
AstNode* expr1p = condp->expr1p();
|
||||||
AstNode* expr2p = condp->expr2p();
|
AstNode* expr2p = condp->expr2p();
|
||||||
|
|
@ -192,17 +192,44 @@ private:
|
||||||
|
|
||||||
// replace the old assign logic with the new one
|
// replace the old assign logic with the new one
|
||||||
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
|
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
|
||||||
|
//if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cond-out: ");
|
||||||
nodep->replaceWith(newassp);
|
nodep->replaceWith(newassp);
|
||||||
nodep->deleteTree(); nodep=NULL;
|
nodep->deleteTree(); nodep=NULL;
|
||||||
newassp->iterateChildren(*this);
|
newassp->iterateChildren(*this);
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
// How about a tri gate?
|
||||||
|
else if (AstBufIf1* bufp = nodep->rhsp()->castBufIf1()) {
|
||||||
|
//if (debug()>=9) nodep->dumpTree(cout,"- tri-in : ");
|
||||||
|
AstNode* enrhsp = bufp->lhsp()->unlinkFrBack();
|
||||||
|
AstNode* outrhsp = bufp->rhsp()->unlinkFrBack();
|
||||||
|
|
||||||
|
AstNode* outp = nodep->lhsp()->unlinkFrBack();;
|
||||||
|
AstVarRef* outrefp = NULL;
|
||||||
|
if (outp->castVarRef()) {
|
||||||
|
outrefp = outp->castVarRef();
|
||||||
|
} else if (outp->castSel()) {
|
||||||
|
outrefp = outp->castSel()->fromp()->castVarRef();
|
||||||
|
} else {
|
||||||
|
nodep->v3error("Can't find LHS varref");
|
||||||
|
}
|
||||||
|
|
||||||
|
createEnableVar(outp, outrefp, enrhsp, outrhsp->width());
|
||||||
|
|
||||||
|
// replace the old assign logic with the new one
|
||||||
|
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
|
||||||
|
//if (debug()>=9) newassp->dumpTreeAndNext(cout,"- tri-out: ");
|
||||||
|
nodep->replaceWith(newassp);
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
newassp->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
|
AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
|
||||||
// this function creates an __en Var that cooresponds to
|
// this function creates an __en Var that corresponds to
|
||||||
// the outp and outrefp and creates an assignw to enrhsp
|
// the outp and outrefp and creates an assignw to enrhsp
|
||||||
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
|
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
|
||||||
AstVarType::MODULETEMP,
|
AstVarType::MODULETEMP,
|
||||||
|
|
@ -218,10 +245,14 @@ private:
|
||||||
enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
|
enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AstNode* newassp = new AstAssignW (enp->fileline(),
|
||||||
|
new AstVarRef (enp->fileline(), enp, true),
|
||||||
|
enrhsp);
|
||||||
|
if (debug()>=9) enp->dumpTreeAndNext(cout,"- cev-out: ");
|
||||||
|
if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cev-out: ");
|
||||||
m_modp->addStmtp(enp);
|
m_modp->addStmtp(enp);
|
||||||
m_modp->addStmtp(new AstAssignW (enp->fileline(),
|
m_modp->addStmtp(newassp);
|
||||||
new AstVarRef (enp->fileline(), enp, true),
|
|
||||||
enrhsp));
|
|
||||||
|
|
||||||
outrefp->user1p(enp); // put __en signal into varref for later usage
|
outrefp->user1p(enp); // put __en signal into varref for later usage
|
||||||
outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level
|
outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ private:
|
||||||
virtual void visit(AstOr* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
virtual void visit(AstOr* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
virtual void visit(AstXnor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
virtual void visit(AstXnor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
virtual void visit(AstXor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
virtual void visit(AstXor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
|
virtual void visit(AstBufIf1* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
// Multiple possible reasonable division width conversions. Just keep our code simple, they aren't common.
|
// Multiple possible reasonable division width conversions. Just keep our code simple, they aren't common.
|
||||||
virtual void visit(AstModDiv* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
virtual void visit(AstModDiv* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
virtual void visit(AstModDivS* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
virtual void visit(AstModDivS* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
|
||||||
|
|
|
||||||
|
|
@ -2682,46 +2682,58 @@ gateUnsupList<nodep>:
|
||||||
;
|
;
|
||||||
|
|
||||||
gateBuf<nodep>:
|
gateBuf<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,$6); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,$6); }
|
||||||
;
|
;
|
||||||
gateBufif0<nodep>:
|
gateBufif0<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), $6)); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8),$6)); }
|
||||||
;
|
;
|
||||||
gateBufif1<nodep>:
|
gateBufif1<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, $6, new AstConst($3,V3Number($3,"1'bz")))); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8,$6)); }
|
||||||
;
|
;
|
||||||
gateNot<nodep>:
|
gateNot<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
||||||
;
|
;
|
||||||
gateNotif0<nodep>:
|
gateNotif0<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), new AstNot($3, $6))); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8), new AstNot($3, $6))); }
|
||||||
;
|
;
|
||||||
gateNotif1<nodep>:
|
gateNotif1<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstNot($3,$6), new AstConst($3,V3Number($3,"1'bz")))); }
|
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8, new AstNot($3,$6))); }
|
||||||
;
|
;
|
||||||
gateAnd<nodep>:
|
gateAnd<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,$6); }
|
||||||
;
|
;
|
||||||
gateNand<nodep>:
|
gateNand<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
||||||
;
|
;
|
||||||
gateOr<nodep>:
|
gateOr<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,$6); }
|
||||||
;
|
;
|
||||||
gateNor<nodep>:
|
gateNor<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
||||||
;
|
;
|
||||||
gateXor<nodep>:
|
gateXor<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,$6); }
|
||||||
;
|
;
|
||||||
gateXnor<nodep>:
|
gateXnor<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
|
||||||
|
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
|
||||||
;
|
;
|
||||||
gatePullup<nodep>:
|
gatePullup<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, true); }
|
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); }
|
||||||
;
|
;
|
||||||
gatePulldown<nodep>:
|
gatePulldown<nodep>:
|
||||||
gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, false); }
|
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); }
|
||||||
;
|
;
|
||||||
gateUnsup<nodep>:
|
gateUnsup<nodep>:
|
||||||
gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); }
|
gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/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 (
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2011 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
reg [63:0] crc;
|
||||||
|
reg [63:0] sum;
|
||||||
|
|
||||||
|
parameter DW = 4;
|
||||||
|
wire [3:0] drv_a = crc[3:0];
|
||||||
|
wire [3:0] drv_b = crc[7:4];
|
||||||
|
wire [3:0] drv_e = crc[19:16];
|
||||||
|
|
||||||
|
/*AUTOWIRE*/
|
||||||
|
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||||
|
wire [DW-1:0] drv; // To/From test1 of Test1.v
|
||||||
|
wire [DW-1:0] drv2; // From test2 of Test2.v
|
||||||
|
// End of automatics
|
||||||
|
|
||||||
|
Test1 test1 (/*AUTOINST*/
|
||||||
|
// Inouts
|
||||||
|
.drv (drv[DW-1:0]),
|
||||||
|
// Inputs
|
||||||
|
.drv_a (drv_a[DW-1:0]),
|
||||||
|
.drv_b (drv_b[DW-1:0]),
|
||||||
|
.drv_e (drv_e[DW-1:0]));
|
||||||
|
Test2 test2 (/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.drv2 (drv2[DW-1:0]),
|
||||||
|
// Inputs
|
||||||
|
.drv_a (drv_a[DW-1:0]),
|
||||||
|
.drv_b (drv_b[DW-1:0]),
|
||||||
|
.drv_e (drv_e[DW-1:0]));
|
||||||
|
|
||||||
|
// Aggregate outputs into a single result vector
|
||||||
|
wire [63:0] result = {60'h0, drv};
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d crc=%x drv=%x %x (%b??%b:%b)\n",$time, cyc, crc, drv, drv2, drv_e,drv_a,drv_b);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
|
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
|
||||||
|
if (cyc==0) begin
|
||||||
|
// Setup
|
||||||
|
crc <= 64'h5aef0c8d_d70a4497;
|
||||||
|
sum <= 64'h0;
|
||||||
|
end
|
||||||
|
else if (cyc<10) begin
|
||||||
|
sum <= 64'h0;
|
||||||
|
end
|
||||||
|
else if (cyc<90) begin
|
||||||
|
if (drv2 != drv) $stop;
|
||||||
|
end
|
||||||
|
else if (cyc==99) begin
|
||||||
|
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
|
||||||
|
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||||
|
// What checksum will we end up with (above print should match)
|
||||||
|
`define EXPECTED_SUM 64'hd95d216c5a2945d0
|
||||||
|
if (sum !== `EXPECTED_SUM) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Test1 #(
|
||||||
|
parameter DW = 4
|
||||||
|
)(
|
||||||
|
input wire [DW-1:0] drv_a,
|
||||||
|
input wire [DW-1:0] drv_b,
|
||||||
|
input wire [DW-1:0] drv_e,
|
||||||
|
inout wire [DW-1:0] drv
|
||||||
|
);
|
||||||
|
|
||||||
|
wire drv_0, drv_1, drv_2, drv_3;
|
||||||
|
bufif1 bufa0 (drv_0, drv_a[0], drv_e[0]);
|
||||||
|
bufif1 bufb0 (drv_0, drv_b[0], ~drv_e[0]);
|
||||||
|
bufif1 bufa1 (drv_1, drv_a[1], drv_e[1]);
|
||||||
|
bufif1 bufb1 (drv_1, drv_b[1], ~drv_e[1]);
|
||||||
|
bufif1 bufa2 (drv_2, drv_a[2], drv_e[2]);
|
||||||
|
bufif1 bufb2 (drv_2, drv_b[2], ~drv_e[2]);
|
||||||
|
bufif1 bufa3 (drv_3, drv_a[3], drv_e[3]);
|
||||||
|
bufif1 bufb3 (drv_3, drv_b[3], ~drv_e[3]);
|
||||||
|
assign drv = {drv_3,drv_2,drv_1,drv_0};
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Test2 #(
|
||||||
|
parameter DW = 4
|
||||||
|
)(
|
||||||
|
input wire [DW-1:0] drv_a,
|
||||||
|
input wire [DW-1:0] drv_b,
|
||||||
|
input wire [DW-1:0] drv_e,
|
||||||
|
inout wire [DW-1:0] drv2
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [DW-1:0] drv_all;
|
||||||
|
bufif1 bufa [DW-1:0] (drv_all, drv_a, drv_e);
|
||||||
|
// Below ~= bufif1 bufb [DW-1:0] (drv_all, drv_b, ~drv_e);
|
||||||
|
bufif1 bufb [DW-1:0] ({drv_all[3], drv_all[2], drv_all[1], drv_all[0]},
|
||||||
|
{drv_b[3], drv_b[2], drv_b[1], drv_b[0]},
|
||||||
|
{~drv_e[3], ~drv_e[2], ~drv_e[1], ~drv_e[0]});
|
||||||
|
assign drv2 = drv_all;
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue