Fix $clog2 calculation error with powers-of-2, bug81.

This commit is contained in:
Wilson Snyder 2009-05-01 22:18:32 -04:00
parent 9b9e4e5a3f
commit 2c953dc37f
5 changed files with 59 additions and 46 deletions

View File

@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.7***
**** Fix $clog2 calculation error with powers-of-2, bug81. [Patricio Kaplan]
**** Fix error with tasks that have output first, bug78. [Andrea Foletto]
**** Fix "cloning" error with -y/--top-module, bug76. [Dimitris Nalbantis]

View File

@ -536,38 +536,6 @@ static inline IData VL_REDXOR_W(int words, WDataInP lwp) {
return VL_REDXOR_32(r);
}
static inline IData VL_CLOG2_I(IData lhs) {
// Perhaps can do better using fls GCC4 builtins
int n=1;
IData chk;
if (!lhs) return 0;
chk = lhs >> VL_UL(16); if (chk) { n += 16; lhs = chk; }
chk = lhs >> VL_UL(8); if (chk) { n += 8; lhs = chk; }
chk = lhs >> VL_UL(4); if (chk) { n += 4; lhs = chk; }
chk = lhs >> VL_UL(2); if (chk) { n += 2; lhs = chk; }
chk = lhs >> VL_UL(1); if (chk) { n += 1; lhs = chk; }
return n;
}
static inline IData VL_CLOG2_Q(QData lhs) {
// Perhaps can do better using fls GCC4 builtins
int n=1;
QData chk;
if (!lhs) return 0;
chk = lhs >> VL_ULL(32); if (chk) { n += 32; lhs = chk; }
chk = lhs >> VL_ULL(16); if (chk) { n += 16; lhs = chk; }
chk = lhs >> VL_ULL(8); if (chk) { n += 8; lhs = chk; }
chk = lhs >> VL_ULL(4); if (chk) { n += 4; lhs = chk; }
chk = lhs >> VL_ULL(2); if (chk) { n += 2; lhs = chk; }
chk = lhs >> VL_ULL(1); if (chk) { n += 1; lhs = chk; }
return n;
}
static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
for (int i=words-1; i>=0; i--) {
if (lwp[i]) return VL_CLOG2_I(lwp[i])+i*VL_WORDSIZE;
}
return 0;
}
// EMIT_RULE: VL_COUNTONES_II: oclean = false; lhs clean
static inline IData VL_COUNTONES_I(IData lhs) {
// This is faster than __builtin_popcountl
@ -622,6 +590,36 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) {
return 1;
}
static inline IData VL_CLOG2_I(IData lhs) {
// There are faster algorithms, or fls GCC4 builtins, but rarely used
if (!lhs) return 0;
lhs--;
int shifts=0;
for (; lhs!=0; shifts++) lhs = lhs >> 1;
return shifts;
}
static inline IData VL_CLOG2_Q(QData lhs) {
if (!lhs) return 0;
lhs--;
int shifts=0;
for (; lhs!=0; shifts++) lhs = lhs >> VL_ULL(1);
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
IData adjust = (VL_COUNTONES_W(words,lwp)==1) ? 0 : 1;
for (int i=words-1; i>=0; i--) {
if (lwp[i]) {
for (int bit=31; bit>=0; bit--) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + adjust;
}
}
// Can't get here - one bit must be set
}
}
return 0;
}
//===================================================================
// SIMPLE LOGICAL OPERATORS

View File

@ -675,10 +675,11 @@ V3Number& V3Number::opOneHot0 (const V3Number& lhs) {
}
V3Number& V3Number::opCLog2 (const V3Number& lhs) {
if (lhs.isFourState()) return setAllBitsX();
int bit;
for (bit=lhs.width()-1; bit>=0; bit--) {
// IE if 4, this algorithm didn't pre-subtract 1, so we need to post-correct now
int adjust = (lhs.countOnes()==1) ? 0 : 1;
for (int bit=lhs.width()-1; bit>=0; bit--) {
if (lhs.bitIs1(bit)) {
setLong(bit+1);
setLong(bit+adjust);
return *this;
}
}

View File

@ -70,7 +70,7 @@ module Test
#(parameter SAMPLE_WIDTH = 5 )
(
`ifdef verilator // UNSUPPORTED
output reg [$clog2(SAMPLE_WIDTH-1)-1:0] pos,
output reg [$clog2(SAMPLE_WIDTH)-1:0] pos,
`else
output reg [log2(SAMPLE_WIDTH-1)-1:0] pos,
`endif

View File

@ -19,13 +19,19 @@ module t (/*AUTOARG*/
reg [63:0] crc;
reg [63:0] sum;
wire [31:0] out = `CLOG2(crc[31:0]);
// Need temp wires as function has different width rules than $clog2
wire [127:0] pows = 128'h1<<crc[7:0];
wire [127:0] npows = ~pows;
wire [31:0] out = `CLOG2(crc[7:0]);
wire [31:0] out2 = `CLOG2(crc);
wire [31:0] out3 = `CLOG2(pows);
wire [31:0] out4 = `CLOG2(npows);
// Aggregate outputs into a single result vector
wire [63:0] result = {out2, out};
wire [63:0] result = {out4[15:0], out3[15:0], out2[15:0], out[15:0]};
`define EXPECTED_SUM 64'hc402f59e3d971718
`define EXPECTED_SUM 64'h73c48afee4f0cb57
// Test loop
always @ (posedge clk) begin
@ -38,28 +44,33 @@ module t (/*AUTOARG*/
if (cyc==0) begin
crc <= 64'h0;
if (`CLOG2(32'h0) != 0) $stop;
if (`CLOG2(32'h1) != 1) $stop;
if (`CLOG2(32'h1) != 0) $stop;
if (`CLOG2(32'h4) != 2) $stop;
if (`CLOG2(32'h7) != 3) $stop;
if (`CLOG2(32'h8) != 4) $stop;
if (`CLOG2(32'h8) != 3) $stop;
if (`CLOG2(32'h9) != 4) $stop;
if (`CLOG2({32{1'b1}}) != 32) $stop;
if (`CLOG2({1'b1,32'b0}) != 32) $stop;
if (`CLOG2({64{1'b1}}) != 64) $stop;
if (`CLOG2({1'b1,64'b0}) != 64) $stop;
if (`CLOG2({128{1'b1}}) != 128) $stop;
if (`CLOG2({1'b1,128'b0}) != 128) $stop;
if (`CLOG2({2'b10,128'b0}) != 129) $stop;
end
else if (cyc==1) begin
crc <= 64'h1;
if (result != {32'd0, 32'd0}) $stop;
if (result[31:0] != {16'd0, 16'd0}) $stop;
end
else if (cyc==2) begin
crc <= 64'h3;
if (result != {32'd1, 32'd1}) $stop;
if (result[31:0] != {16'd0, 16'd0}) $stop;
end
else if (cyc==3) begin
crc <= {64{1'b1}};
if (result != {32'd2, 32'd2}) $stop;
if (result[31:0] != {16'd2, 16'd2}) $stop;
end
else if (cyc==4) begin
if (result != {32'd64, 32'd32}) $stop;
if (result[31:0] != {16'd64, 16'd8}) $stop;
end
else if (cyc==8) begin
crc <= 64'h5aef0c8d_d70a4497;
@ -80,7 +91,8 @@ module t (/*AUTOARG*/
function integer clog2_emulate(input [130:0] arg);
begin
for(clog2_emulate=0; arg>0; clog2_emulate=clog2_emulate+1)
if (arg!=0) arg = arg - 1;
for (clog2_emulate=0; arg!=0; clog2_emulate=clog2_emulate+1)
arg = (arg >> 1);
end
endfunction