diff --git a/Changes b/Changes index bc936324d..36154147d 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Fix shifts by more than 32-bit numbers, bug1174. [Clifford Wolf] +*** Fix power operator on wide constants, bug761. [Clifford Wolf] + * Verilator 3.904 2017-05-30 diff --git a/include/verilated.cpp b/include/verilated.cpp index a9178b19f..1f0f1655c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -282,6 +282,48 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo } } +WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp) { + owp[0] = 1; + for (int i=1; i < VL_WORDS_I(obits); i++) owp[i] = 0; + // cppcheck-suppress variableScope + WData powstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here + WData lastpowstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here + WData lastoutstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here + // cppcheck-suppress variableScope + VL_ASSIGN_W(obits, powstore, lwp); + for (int bit=0; bit0) { // power = power*power + VL_ASSIGN_W(obits, lastpowstore, powstore); + VL_MUL_W(VL_WORDS_I(obits), powstore, lastpowstore, lastpowstore); + } + if (VL_BITISSET_W(rwp,bit)) { // out *= power + VL_ASSIGN_W(obits, lastoutstore, owp); + VL_MUL_W(VL_WORDS_I(obits), owp, lastoutstore, powstore); + } + } + return owp; +} + +WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign) { + if (rsign && VL_SIGN_W(rbits, rwp)) { + int words = VL_WORDS_I(obits); + VL_ZERO_W(obits, owp); + IData lor = 0; // 0=all zeros, ~0=all ones, else mix + for (int i=1; i < (words-1); ++i) { + lor |= lwp[i]; + } + lor |= ( (lwp[words-1] == VL_MASK_I(rbits)) ? ~VL_UL(0) : 0); + if (lor==0 && lwp[0]==0) { return owp; } // "X" so return 0 + else if (lor==0 && lwp[0]==1) { owp[0] = 1; return owp; } // 1 + else if (lsign && lor == ~VL_UL(0) && lwp[0]==~VL_UL(0)) { // -1 + if (rwp[0] & 1) { return VL_ALLONES_W(obits, owp); } // -1^odd=-1 + else { owp[0] = 1; return owp; } // -1^even=1 + } + return 0; + } + return VL_POW_WWW(obits, rbits, rbits, owp, lwp, rwp); +} + //=========================================================================== // Formatting diff --git a/include/verilated.h b/include/verilated.h index d55ffc0f3..471624de7 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -433,6 +433,7 @@ static inline IData VL_RTOIROUND_I_D(double lhs) { return ((vlsint32_t)(VL_ROUN // (Requires clean input) #define VL_SIGN_I(nbits,lhs) ((lhs) >> VL_BITBIT_I((nbits) - VL_UL(1))) #define VL_SIGN_Q(nbits,lhs) ((lhs) >> VL_BITBIT_Q((nbits) - VL_ULL(1))) +#define VL_SIGN_W(nbits,rwp) ((rwp)[VL_BITWORD_I((nbits)-VL_UL(1))] >> VL_BITBIT_I((nbits)-VL_UL(1))) #define VL_SIGNONES_I(nbits,lhs) (-(VL_SIGN_I(nbits,lhs))) // Sign bit extended up to MSB, doesn't include unsigned portion @@ -513,6 +514,12 @@ static inline WDataOutP VL_ZERO_W(int obits, WDataOutP owp) { for (int i=0; i < words; ++i) owp[i] = 0; return owp; } +static inline WDataOutP VL_ALLONES_W(int obits, WDataOutP owp) { + int words = VL_WORDS_I(obits); + for (int i=0; (i < (words-1)); ++i) owp[i] = ~VL_UL(0); + owp[words-1] = VL_MASK_I(obits); + return owp; +} // EMIT_RULE: VL_ASSIGN: oclean=rclean; obits==lbits; // For now, we always have a clean rhs. @@ -1208,6 +1215,7 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) { } return out; } +WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp); #define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign) @@ -1216,28 +1224,28 @@ static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs if (rsign && VL_SIGN_I(rbits, rhs)) { if (lhs==0) return 0; // "X" else if (lhs==1) return 1; - else if (lsign && lhs==VL_MASK_I(obits)) { //-1 + else if (lsign && lhs==VL_MASK_I(obits)) { // -1 if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1 else return 1; // -1^even=1 } return 0; } - return VL_POW_III(obits, obits, rbits, lhs, rhs); + return VL_POW_III(obits, rbits, rbits, lhs, rhs); } - static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs, bool lsign, bool rsign) { if (VL_UNLIKELY(rhs==0)) return 1; if (rsign && VL_SIGN_I(rbits, rhs)) { if (lhs==0) return 0; // "X" else if (lhs==1) return 1; - else if (lsign && lhs==VL_MASK_I(obits)) { //-1 + else if (lsign && lhs==VL_MASK_I(obits)) { // -1 if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1 else return 1; // -1^even=1 } return 0; } - return VL_POW_QQQ(obits, obits, rbits, lhs, rhs); + return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs); } +WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool lsign, bool rsign); //=================================================================== // Concat/replication diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 5170a5244..56f2d441b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -509,6 +509,30 @@ public: } visit(nodep->castNodeBiop()); } + virtual void visit(AstPow* nodep) { + if (nodep->widthWords() > VL_MULS_MAX_WORDS) { + nodep->v3error("Unsupported: Power of "<width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } + visit(nodep->castNodeBiop()); + } + virtual void visit(AstPowSS* nodep) { + if (nodep->widthWords() > VL_MULS_MAX_WORDS) { + nodep->v3error("Unsupported: Power of "<width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } + visit(nodep->castNodeBiop()); + } + virtual void visit(AstPowSU* nodep) { + if (nodep->widthWords() > VL_MULS_MAX_WORDS) { + nodep->v3error("Unsupported: Power of "<width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } + visit(nodep->castNodeBiop()); + } + virtual void visit(AstPowUS* nodep) { + if (nodep->widthWords() > VL_MULS_MAX_WORDS) { + nodep->v3error("Unsupported: Power of "<width()<<" bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } + visit(nodep->castNodeBiop()); + } virtual void visit(AstCCast* nodep) { // Extending a value of the same word width is just a NOP. if (nodep->size()>VL_WORDSIZE) { diff --git a/src/V3Number.cpp b/src/V3Number.cpp index f86597a27..a95fed8cb 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1518,8 +1518,6 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign, if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (rhs.isEqZero()) return setQuad(1); // Overrides lhs 0 -> return 0 // We may want to special case when the lhs is 2, so we can get larger outputs - if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this); - if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this); if (rsign && rhs.isNegative()) { if (lhs.isEqZero()) return setAllBitsXRemoved(); else if (lhs.isEqOne()) return setQuad(1); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index c51266700..305d9c1fe 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -803,7 +803,6 @@ private: nodep->dtypeFrom(expDTypep); // rhs already finalized in iterate_shift_prelim iterateCheck(nodep,"LHS",nodep->lhsp(),SELF,FINAL,nodep->dtypep(),EXTEND_EXP); - if (nodep->width()>64) nodep->v3error("Unsupported: Large >64bit ** power operator not implemented."); AstNode* newp = NULL; // No change if (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()) { newp = new AstPowSS (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), diff --git a/test_regress/t/t_math_pow5.pl b/test_regress/t/t_math_pow5.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_math_pow5.pl @@ -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; diff --git a/test_regress/t/t_math_pow5.v b/test_regress/t/t_math_pow5.v new file mode 100644 index 000000000..e56ea8045 --- /dev/null +++ b/test_regress/t/t_math_pow5.v @@ -0,0 +1,73 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2004 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg [67:0] q; + reg signed [67:0] qs; + + initial begin + q = 68'he_12345678_9abcdef0 ** 68'h3; + if (q != 68'hcee3cb96ce96cf000) $stop; + // + q = 68'he_12345678_9abcdef0 ** 68'h5_6789abcd_ef012345; + if (q != 68'h0) $stop; + // + qs = 68'she_12345678_9abcdef0 ** 68'sh3; + if (qs != 68'shcee3cb96ce96cf000) $stop; + // + qs = 68'she_12345678_9abcdef0 ** 68'sh5_6789abcd_ef012345; + if (qs != 68'h0) $stop; + end + + reg [67:0] left; + reg [67:0] right; + + wire [67:0] outu = left ** right; + wire signed [67:0] outs = $signed(left) ** $signed(right); + + integer cyc; initial cyc=1; + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $write("%d %x %x %x %x\n", cyc, left, right, outu, outs); +`endif + if (cyc==1) begin + left <= 68'h1; + right <= '0; + end + if (cyc==2) begin + if (outu != 68'h1) $stop; + if (outs != 68'h1) $stop; + end + if (cyc==3) begin + left <= 68'he_12345678_9abcdef0; + right <= 68'h3; + end + if (cyc==4) begin + if (outu != 68'hcee3cb96ce96cf000) $stop; + if (outs != 68'hcee3cb96ce96cf000) $stop; + end + if (cyc==5) begin + left <= 68'he_12345678_9abcdef0; + right <= 68'h5_6789abcd_ef012345; + end + if (cyc==6) begin + if (outu != 68'h0) $stop; + if (outs != 68'h0) $stop; + end + if (cyc==9) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end +endmodule