Fix concatenates and vectored bufif1, bug326.

This commit is contained in:
Wilson Snyder 2011-02-23 21:21:59 -05:00
parent 2e67a91982
commit cfdb852843
11 changed files with 247 additions and 21 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
**** Support $bits(data_type), bug327. [Alex Solomatnikov]
**** Fix concatenates and vectored bufif1, bug326. [Iztok Jeras]
* Verilator 3.811 2011/02/14
**** Report errors on duplicated or empty pins, bug321. [Christian Leber]

View File

@ -3152,6 +3152,19 @@ struct AstReplicate : public AstNodeBiop {
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
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 {
AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(FGetS, FGETS)

View File

@ -1061,6 +1061,24 @@ private:
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*) {
nodep->iterateChildren(*this);
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
@ -1767,6 +1785,10 @@ private:
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(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
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");

View File

@ -1318,6 +1318,15 @@ V3Number& V3Number::opPowS (const V3Number& lhs, const V3Number& rhs) {
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) {
// Note may be a width change during the assign
setZero();

View File

@ -195,6 +195,7 @@ public:
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
V3Number& opBufIf1 (const V3Number& lhs, const V3Number& rhs);
// "standard" math
V3Number& opNot (const V3Number& lhs);
V3Number& opLogNot (const V3Number& lhs);

View File

@ -98,6 +98,7 @@ private:
virtual void visit(AstLogOr* 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(AstBufIf1* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
// ... These shouldn't matter, just make unsigned
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }

View File

@ -159,8 +159,8 @@ private:
// assign x = (OE) ? 'hz : y;
// see if this a COND and separate out the __en logic from the output logic if it is
if (nodep->rhsp()->castCond()) {
AstCond* condp = nodep->rhsp()->castCond();
if (AstCond* condp = nodep->rhsp()->castCond()) {
//if (debug()>=9) nodep->dumpTree(cout,"- cond-in: ");
AstNode* oep = condp->condp();
AstNode* expr1p = condp->expr1p();
AstNode* expr2p = condp->expr2p();
@ -192,17 +192,44 @@ private:
// replace the old assign logic with the new one
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
//if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cond-out: ");
nodep->replaceWith(newassp);
nodep->deleteTree(); nodep=NULL;
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);
}
}
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
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
AstVarType::MODULETEMP,
@ -218,10 +245,14 @@ private:
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(new AstAssignW (enp->fileline(),
new AstVarRef (enp->fileline(), enp, true),
enrhsp));
m_modp->addStmtp(newassp);
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

View File

@ -143,6 +143,7 @@ private:
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(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.
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); }

View File

@ -2682,46 +2682,58 @@ gateUnsupList<nodep>:
;
gateBuf<nodep>:
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,$6); }
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
{ $$ = new AstAssignW ($3,$4,$6); }
;
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>:
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>:
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>:
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>:
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>:
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); }
;
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>:
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); }
;
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>:
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); }
;
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>:
gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, true); }
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); }
;
gatePulldown<nodep>:
gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, false); }
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); }
;
gateUnsup<nodep>:
gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); }

View File

@ -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;

View File

@ -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