Fix assignments of {a,b,c} = {c,b,a}
git-svn-id: file://localhost/svn/verilator/trunk/verilator@988 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
98fff6a4ce
commit
b4d9ccd9af
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* Verilator 3.656 2008/***
|
||||
|
||||
**** Fix assignments of {a,b,c} = {c,b,a}. [Jonathan Kimmitt]
|
||||
|
||||
**** Fix Perl warning with --lint-only. [by Ding Xiaoliang]
|
||||
|
||||
**** Avoid creating obj_dir with --lint-only. [Ding Xiaoliang]
|
||||
|
|
|
|||
4
TODO
4
TODO
|
|
@ -52,6 +52,10 @@ Usability:
|
|||
Better reporting of unopt problems, including what lines of code
|
||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
|
||||
Internal Code:
|
||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
|
||||
Performance:
|
||||
Constant propagation
|
||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||
|
|
|
|||
126
src/V3Const.cpp
126
src/V3Const.cpp
|
|
@ -39,11 +39,63 @@
|
|||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
|
||||
//######################################################################
|
||||
// Utilities
|
||||
|
||||
class ConstVarMarkVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::userp -> bool, Var marked, 0=not set yet
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp()) nodep->varp()->user(1);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ConstVarMarkVisitor(AstNode* nodep) {
|
||||
AstNode::userClearTree();
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
}
|
||||
virtual ~ConstVarMarkVisitor() {}
|
||||
};
|
||||
|
||||
class ConstVarFindVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::userp -> bool, input from ConstVarMarkVisitor
|
||||
// MEMBERS
|
||||
bool m_found;
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp() && nodep->varp()->user()) m_found = true;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ConstVarFindVisitor(AstNode* nodep) {
|
||||
m_found = false;
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
}
|
||||
virtual ~ConstVarFindVisitor() {}
|
||||
// METHODS
|
||||
bool found() const { return m_found; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Const state, as a visitor of each AstNode
|
||||
|
||||
class ConstVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// ** only when m_warn is set. If state is needed other times,
|
||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||
// AstVar::userp -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
||||
|
||||
// STATE
|
||||
bool m_params; // If true, propogate parameterized and true numbers only
|
||||
bool m_required; // If true, must become a constant
|
||||
|
|
@ -494,10 +546,26 @@ private:
|
|||
}
|
||||
}
|
||||
else if (!m_cpp && nodep->lhsp()->castConcat()) {
|
||||
UINFO(4," ASSI "<<nodep<<endl);
|
||||
bool need_temp = false;
|
||||
if (m_warn && !nodep->castAssignDly()) { // Is same var on LHS and RHS?
|
||||
ConstVarMarkVisitor mark(nodep->lhsp());
|
||||
ConstVarFindVisitor find(nodep->rhsp());
|
||||
if (find.found()) need_temp = true;
|
||||
}
|
||||
if (need_temp) {
|
||||
// The first time we constify, there may be the same variable on the LHS
|
||||
// and RHS. In that case, we must use temporaries, or {a,b}={b,a} will break.
|
||||
UINFO(4," ASSITEMP "<<nodep<<endl);
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(temp1,SEL(rhs,{size})),
|
||||
// ASSIGN(temp2,SEL(newrhs,{size}))
|
||||
// ASSIGN(lc1,temp1),
|
||||
// ASSIGN(lc2,temp2)
|
||||
} else {
|
||||
UINFO(4," ASSI "<<nodep<<endl);
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(lc1,SEL(rhs,{size})),
|
||||
// ASSIGN(lc2,SEL(newrhs,{size}))
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout," Ass_old: ");
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(lc1,SEL(rhs,{size})),
|
||||
// ASSIGN(lc2,SEL(newrhs,{size}))
|
||||
// Unlink the stuff
|
||||
AstNode* lc1p = nodep->lhsp()->castConcat()->lhsp()->unlinkFrBack();
|
||||
AstNode* lc2p = nodep->lhsp()->castConcat()->rhsp()->unlinkFrBack();
|
||||
|
|
@ -517,14 +585,50 @@ private:
|
|||
sel2p->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// Make new assigns of same flavor as old one
|
||||
//*** Not cloneTree; just one node.
|
||||
AstNodeAssign* asn1p=nodep->cloneType(lc1p, sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2p=nodep->cloneType(lc2p, sel2p)->castNodeAssign();
|
||||
asn1p->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2p->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
nodep->addNextHere(asn1p);
|
||||
nodep->addNextHere(asn2p);
|
||||
if (debug()>=9) asn1p->dumpTree(cout," _new: ");
|
||||
if (debug()>=9) asn2p->dumpTree(cout," _new: ");
|
||||
AstNode* newp = NULL;
|
||||
if (!need_temp) {
|
||||
AstNodeAssign* asn1ap=nodep->cloneType(lc1p, sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2ap=nodep->cloneType(lc2p, sel2p)->castNodeAssign();
|
||||
asn1ap->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
newp = newp->addNext(asn1ap);
|
||||
newp = newp->addNext(asn2ap);
|
||||
} else {
|
||||
if (!m_modp) nodep->v3fatalSrc("Not under module");
|
||||
// We could create just one temp variable, but we'll get better optimization
|
||||
// if we make one per term.
|
||||
string name1 = ((string)"__Vconcswap__"+cvtToStr(m_modp->varNumGetInc()));
|
||||
string name2 = ((string)"__Vconcswap__"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1,
|
||||
new AstRange(sel1p->fileline(), msb1-lsb1, 0));
|
||||
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2,
|
||||
new AstRange(sel2p->fileline(), msb2-lsb2, 0));
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap=nodep->cloneType
|
||||
(new AstVarRef(sel1p->fileline(), temp1p, true),
|
||||
sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2ap=nodep->cloneType
|
||||
(new AstVarRef(sel2p->fileline(), temp2p, true),
|
||||
sel2p)->castNodeAssign();
|
||||
AstNodeAssign* asn1bp=nodep->cloneType
|
||||
(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false))
|
||||
->castNodeAssign();
|
||||
AstNodeAssign* asn2bp=nodep->cloneType
|
||||
(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false))
|
||||
->castNodeAssign();
|
||||
asn1ap->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn1bp->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
asn2bp->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// This order matters
|
||||
newp = newp->addNext(asn1ap);
|
||||
newp = newp->addNext(asn2ap);
|
||||
newp = newp->addNext(asn1bp);
|
||||
newp = newp->addNext(asn2bp);
|
||||
}
|
||||
if (debug()>=9) newp->dumpTreeAndNext(cout," _new: ");
|
||||
nodep->addNextHere(newp);
|
||||
// Cleanup
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
conp->deleteTree(); conp=NULL;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// please note it here, otherwise:**
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2007 by Wilson Snyder.
|
||||
// without warranty, 2008 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# 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
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2008 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
|
||||
// Take CRC data and apply to testblock inputs
|
||||
wire [31:0] Operand1 = crc[31:0];
|
||||
wire [15:0] Operand2 = crc[47:32];
|
||||
wire Unsigned = crc[48];
|
||||
reg rst;
|
||||
|
||||
parameter wl = 16;
|
||||
|
||||
/*AUTOWIRE*/
|
||||
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||
wire [wl-1:0] Quotient; // From test of Test.v
|
||||
wire [wl-1:0] Remainder; // From test of Test.v
|
||||
// End of automatics
|
||||
|
||||
Test test (/*AUTOINST*/
|
||||
// Outputs
|
||||
.Quotient (Quotient[wl-1:0]),
|
||||
.Remainder (Remainder[wl-1:0]),
|
||||
// Inputs
|
||||
.Operand1 (Operand1[wl*2-1:0]),
|
||||
.Operand2 (Operand2[wl-1:0]),
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
.Unsigned (Unsigned));
|
||||
|
||||
// Aggregate outputs into a single result vector
|
||||
wire [63:0] result = {32'h0, Quotient, Remainder};
|
||||
|
||||
// What checksum will we end up with
|
||||
`define EXPECTED_SUM 64'h98d41f89a8be5693
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d crc=%x result=%x it=%x\n",$time, cyc, crc, result, test.Iteration);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
if (cyc < 20 || test.Iteration==4'd15) begin
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
end
|
||||
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
crc <= 64'h5aef0c8d_d70a4497;
|
||||
rst <= 1'b1;
|
||||
end
|
||||
else if (cyc<20) begin
|
||||
sum <= 64'h0;
|
||||
rst <= 1'b0;
|
||||
end
|
||||
else if (cyc<90) begin
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
|
||||
if (crc !== 64'h8dd70a44972ad809) $stop;
|
||||
if (sum !== `EXPECTED_SUM) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test(clk, rst, Operand1, Operand2, Unsigned, Quotient, Remainder);
|
||||
|
||||
parameter wl = 16;
|
||||
|
||||
input [wl*2-1:0] Operand1;
|
||||
input [wl-1:0] Operand2;
|
||||
input clk, rst, Unsigned;
|
||||
output [wl-1:0] Quotient, Remainder;
|
||||
|
||||
reg Cy, Overflow, Sign1, Sign2, Zero, Negative;
|
||||
reg [wl-1:0] ah,al,Quotient, Remainder;
|
||||
reg [3:0] Iteration;
|
||||
reg [wl-1:0] sub_quot,op;
|
||||
reg ah_ext;
|
||||
|
||||
reg [1:0] a,b,c,d,e;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!rst) begin
|
||||
{a,b,c,d,e} = Operand1[9:0];
|
||||
{a,b,c,d,e} = {e,d,c,b,a};
|
||||
if (a != Operand1[1:0]) $stop;
|
||||
if (b != Operand1[3:2]) $stop;
|
||||
if (c != Operand1[5:4]) $stop;
|
||||
if (d != Operand1[7:6]) $stop;
|
||||
if (e != Operand1[9:8]) $stop;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
Iteration <= 0;
|
||||
Quotient <= 0;
|
||||
Remainder <= 0;
|
||||
end
|
||||
else begin
|
||||
if (Iteration == 0) begin
|
||||
{ah,al} = Operand1;
|
||||
op = Operand2;
|
||||
Cy = 0;
|
||||
Overflow = 0;
|
||||
Sign1 = (~Unsigned)&ah[wl-1];
|
||||
Sign2 = (~Unsigned)&(ah[wl-1]^op[wl-1]);
|
||||
if (Sign1) {ah,al} = -{ah,al};
|
||||
end
|
||||
`define BUG1
|
||||
`ifdef BUG1
|
||||
{ah_ext,ah,al} = {ah,al,Cy};
|
||||
`else
|
||||
ah_ext = ah[15];
|
||||
ah[15:1] = ah[14:0];
|
||||
ah[0] = al[15];
|
||||
al[15:1] = al[14:0];
|
||||
al[0] = Cy;
|
||||
`endif
|
||||
`ifdef TEST_VERBOSE
|
||||
$display("%x %x %x %x %x %x %x %x %x",
|
||||
Iteration, ah, al, Quotient, Remainder, Overflow, ah_ext, sub_quot, Cy);
|
||||
`endif
|
||||
{Cy,sub_quot} = (~Unsigned)&op[wl-1]? {ah_ext,ah}+op : {ah_ext,ah} - {1'b1,op};
|
||||
if (Cy)
|
||||
begin
|
||||
{ah_ext,ah} = {1'b0,sub_quot};
|
||||
end
|
||||
if (Iteration != 15 )
|
||||
begin
|
||||
if (ah_ext) Overflow = 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (al[14] && ~Unsigned) Overflow = 1;
|
||||
Quotient <= Sign2 ? -{al[14:0],Cy} : {al[14:0],Cy};
|
||||
Remainder <= Sign1 ? -ah : ah;
|
||||
if (Overflow)
|
||||
begin
|
||||
Quotient <= Sign2 ? 16'h8001 : {Unsigned,{15{1'b1}}};
|
||||
Remainder <= Unsigned ? 16'hffff : 16'h8000;
|
||||
Zero = 1;
|
||||
Negative = 1;
|
||||
end
|
||||
end
|
||||
Iteration <= Iteration + 1; // Count number of times this instruction is repeated
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue