//************************************************************************* // DESCRIPTION: Verilator: Large 4-state numbers // // Code available from: http://www.veripool.org/verilator // // AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli // //************************************************************************* // // Copyright 2003-2011 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. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* #include "config_build.h" #include "verilatedos.h" #include #include #include #include #include #include "V3Number.h" #define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30) //###################################################################### // Read class functions // CREATION V3Number::V3Number(VerilogString, FileLine* fileline, const string& str) { // Create a number using a verilog string as the value, thus 8 bits per character. // cppcheck bug - doesn't see init() resets these // cppcheck: Member variable 'm_sized/m_width' is not initialized in the constructor init(fileline, str.length()*8); m_fromString = true; for (unsigned pos=0; posopAdd(product,addend); if (product.bitsValue(width(), 4)) { // Overflowed m_fileline->v3error("Too many digits for "<v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp); setAllBitsZ(); got_z = 1; break; } case 'x': { if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp); got_x = 1; setAllBitsX(); break; } case '_': break; default: { m_fileline->v3error("Illegal character in decimal constant: "<<*cp); break; } } } obit = width(); if ((got_01+got_x+got_z)>1) m_fileline->v3error("Mixing X/Z/? with digits not legal in decimal constant: "<=value_startp && obit<=width()); cp--) { if (*cp!='_' && *cp!='0' && obit>=width()) { m_fileline->v3error("Too many digits for "<v3error("Illegal character in binary constant: "<<*cp); } break; } case 'o': case 'c': { switch(tolower(*cp)) { case '0': setBit(obit++, 0); setBit(obit++, 0); setBit(obit++, 0); break; case '1': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 0); break; case '2': setBit(obit++, 0); setBit(obit++, 1); setBit(obit++, 0); break; case '3': setBit(obit++, 1); setBit(obit++, 1); setBit(obit++, 0); break; case '4': setBit(obit++, 0); setBit(obit++, 0); setBit(obit++, 1); break; case '5': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 1); break; case '6': setBit(obit++, 0); setBit(obit++, 1); setBit(obit++, 1); break; case '7': setBit(obit++, 1); setBit(obit++, 1); setBit(obit++, 1); break; case 'z': case '?': setBit(obit++, 'z'); setBit(obit++, 'z'); setBit(obit++, 'z'); break; case 'x': setBit(obit++, 'x'); setBit(obit++, 'x'); setBit(obit++, 'x'); break; case '_': break; default: m_fileline->v3error("Illegal character in octal constant"); } break; } case 'h': { switch(tolower(*cp)) { case '0': setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '1': setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '2': setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); break; case '3': setBit(obit++,1); setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); break; case '4': setBit(obit++,0); setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); break; case '5': setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); break; case '6': setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); setBit(obit++,0); break; case '7': setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); setBit(obit++,0); break; case '8': setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); setBit(obit++,1); break; case '9': setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); setBit(obit++,1); break; case 'a': setBit(obit++,0); setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); break; case 'b': setBit(obit++,1); setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); break; case 'c': setBit(obit++,0); setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); break; case 'd': setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); break; case 'e': setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break; case 'f': setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break; case 'z': case '?': setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); break; case 'x': setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); break; case '_': break; default: m_fileline->v3error("Illegal character in hex constant: "<<*cp); } break; } default: m_fileline->v3error("Illegal base character: "<0; bit--) if (num & (VL_ULL(1)<>VL_ULL(32)) & VL_ULL(0xffffffff); return *this; } V3Number& V3Number::setLong(uint32_t value) { for (int i=0; iv3fatalSrc("Real operation on wrong sized number"); } m_double = true; union { double d; uint32_t u[2]; } u; u.d = value; for (int i=2; i=0; bit--) { if (bitIs0(bit)) str+='0'; else if (bitIs1(bit)) str+='1'; else if (bitIsZ(bit)) str+='z'; else str+='x'; } return str; } case 'o': { int bit = width()-1; if (fmtsize == "0") while (bit && bitIs0(bit)) bit--; while ((bit%3)!=2) bit++; for (; bit>0; bit -= 3) { int v = bitsValue(bit-2, 3); str += (char)('0'+v); } return str; } case 'h': case 'x': { int bit = width()-1; if (fmtsize == "0") while (bit && bitIs0(bit)) bit--; while ((bit%4)!=3) bit++; for (; bit>0; bit -= 4) { int v = bitsValue(bit-3, 4); if (v>=10) str += (char)('a'+v-10); else str += (char)('0'+v); } return str; } case 'c': { if (this->width()>8) m_fileline->v3error("$display of char format of > 8 bit value"); int v = bitsValue(0, 8); str += (char)(v); return str; } case 's': { // Spec says always drop leading zeros, this isn't quite right, we space pad. int bit=this->width()-1; bool start=true; while ((bit%8)!=7) bit++; for (; bit>=0; bit -= 8) { int v = bitsValue(bit-7, 8); if (!start || v) { str += (char)((v==0)?' ':v); start = false; // Drop leading 0s } else { if (fmtsize != "0") str += ' '; } } return str; } case '~': // Signed decimal case 't': // Time case 'd': { // Unsigned decimal bool issigned = (code == '~'); if (fmtsize == "") { double mantissabits = this->width() - (issigned?1:0); double maxval = pow(2.0, mantissabits); double dchars = log10(maxval)+1.0; if (issigned) dchars++; // space for sign fmtsize = cvtToStr(int(dchars)); } if (width() > 64) { m_fileline->v3error("Unsupported: $display of dec format of > 64 bit results (use hex format instead)"); return "ERR"; } if (issigned) { str = cvtToStr(toSQuad()); } else { str = cvtToStr(toUQuad()); } int intfmtsize = atoi(fmtsize.c_str()); bool zeropad = fmtsize.length()>0 && fmtsize[0]=='0'; while ((int)(str.length()) < intfmtsize) { if (zeropad) str = "0"+str; else str = " "+str; } return str; } case 'e': case 'f': case 'g': { char tmp[MAX_SPRINTF_DOUBLE_SIZE]; sprintf(tmp, vformat.c_str(), toDouble()); return tmp; } default: m_fileline->v3fatalSrc("Unknown $display format code for number: %"<v3fatalSrc("Real conversion on non real number"); } if (VL_UNLIKELY(width()!=64)) { m_fileline->v3fatalSrc("Real operation on wrong sized number"); } union { double d; uint32_t u[2]; } u; u.u[0] = m_value[0]; u.u[1] = m_value[1]; return u.d; } vlsint32_t V3Number::toSInt() const { if (isSigned()) { uint32_t v = toUInt(); uint32_t signExtend = (-(v & (1UL<<(width()-1)))); uint32_t extended = v | signExtend; return (vlsint32_t)(extended); } else { // Where we use this (widths, etc) and care about signedness, // we can reasonably assume the MSB isn't set on unsigned numbers. return (vlsint32_t)toUInt(); } } vluint64_t V3Number::toUQuad() const { UASSERT(!isFourState(),"toUQuad with 4-state "<<*this); UASSERT(width()<65, "Value too wide "<<*this); if (width()<=32) return ((vluint64_t)(toUInt())); return ((vluint64_t)m_value[1]<width()-1; bool start=true; while ((bit%8)!=7) bit++; string str; for (; bit>=0; bit -= 8) { int v = bitsValue(bit-7, 8); if (!start || v) { str += (char)((v==0)?' ':v); start = false; // Drop leading 0s } } return str; } uint32_t V3Number::toHash() const { return m_value[0]; } uint32_t V3Number::dataWord(int word) const { UASSERT(!isFourState(),"dataWord with 4-state "<<*this); return m_value[word]; } bool V3Number::isEqZero() const { for (int i=0; iwidth(),rhs.width()); bit++) { if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return 1; } if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return 0; } if (this->bitIsXZ(bit)) { return 0; } if (rhs.bitIsXZ(bit)) { return 0; } } return 0; } int V3Number::minWidth() const { for(int bit=width()-1; bit>0; bit--) { if (!bitIs0(bit)) return bit+1; } return 1; // one bit even if number is == 0 } uint32_t V3Number::countOnes() const { int n=0; for(int bit=0; bitwidth(); bit++) { if (bitIs1(bit)) n++; } return n; } uint32_t V3Number::mostSetBitP1() const { for (int bit=this->width()-1; bit>=0; bit--) { if (bitIs1(bit)) return bit+1; } return 0; } //====================================================================== V3Number& V3Number::opBitsNonX (const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) { setBit(bit,1); } } return *this; } V3Number& V3Number::opBitsOne (const V3Number& lhs) { // 1->1, 0/X/Z->0 // op i, L(lhs) bit return setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit)) { setBit(bit,1); } } return *this; } V3Number& V3Number::opBitsXZ (const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIsXZ(bit)) { setBit(bit,1); } } return *this; } V3Number& V3Number::opBitsZ (const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIsZ(bit)) { setBit(bit,1); } } return *this; } V3Number& V3Number::opBitsNonZ (const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return setZero(); for(int bit=0; bitwidth(); bit++) { if (!lhs.bitIsZ(bit)) { setBit(bit,1); } } return *this; } //====================================================================== // Operators - Simple per-bit logical ops V3Number& V3Number::opRedOr (const V3Number& lhs) { // op i, 1 bit return char outc = 0; for(int bit=0; bit=0; bit--) { if (lhs.bitIs1(bit)) { setLong(bit+adjust); return *this; } } setZero(); return *this; } V3Number& V3Number::opLogNot (const V3Number& lhs) { // op i, 1 bit return char outc = 1; for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs0(bit)) { setBit(bit,1); } else if (lhs.bitIsXZ(bit)) { setBit(bit,'x'); } } return *this; } V3Number& V3Number::opAnd (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit,1); } else if (lhs.bitIs0(bit) || rhs.bitIs0(bit)) ; // 0 else { setBit(bit,'x'); } } return *this; } V3Number& V3Number::opOr (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) || rhs.bitIs1(bit)) { setBit(bit,1); } else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) ; // 0 else { setBit(bit,'x'); } } return *this; } V3Number& V3Number::opChangeXor (const V3Number& lhs, const V3Number& rhs) { // 32 bit result opEq(lhs,rhs); return *this; } V3Number& V3Number::opXor (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { setBit(bit,1); } else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) { setBit(bit,1); } else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { setBit(bit,'x'); } // else zero } return *this; } V3Number& V3Number::opXnor (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for(int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit,1); } else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) { setBit(bit,1); } else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { setBit(bit,'x'); } // else zero } return *this; } V3Number& V3Number::opConcat (const V3Number& lhs, const V3Number& rhs) { setZero(); // See also error in V3Width if (!lhs.sized() || !rhs.sized()) { m_fileline->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in concatenations."); } int obit = 0; for(int bit=0; bitv3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in replications."); return opRepl(lhs, rhs.toUInt()); } V3Number& V3Number::opRepl (const V3Number& lhs, uint32_t rhsval) { // rhs is # of times to replicate // i op repl, L(i)*value(rhs) bit return setZero(); if (rhsval>8192) m_fileline->v3fatal("More than a 8k bit replication is probably wrong: "<width() != rhs.width()) return false; for (int bit=0; bitwidth(),rhs.width()); bit++) { if (this->bitIs(bit) != rhs.bitIs(bit)) { return false; } } return true; } V3Number& V3Number::opCaseEq (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.isCaseEq(rhs) ? 1:0); } V3Number& V3Number::opCaseNeq (const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend. char outc = 0; for (int bit=0; bit - else if (lhs.bitIs1Extend(mbit) && rhs.bitIs0(mbit)) { outc=0; } // - !> + else { // both positive or negative, normal > for (int bit=0; bitwidth(); bit++) { setBit(bit,lhs.bitIs((bit + rhsval) % this->width())); } return *this; } V3Number& V3Number::opRotL (const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); for (int bit=0; bitwidth(); bit++) { if (bit >= (int)rhsval) { setBit(bit,lhs.bitIs((bit - rhsval) % this->width())); } } return *this; } V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); for (int bit=0; bitwidth(); bit++) { setBit(bit,lhs.bitIs(bit + rhsval)); } return *this; } V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return // The spec says a unsigned >>> still acts as a normal >>. // We presume it is signed; as that's V3Width's job to convert to opShiftR if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); for (int bit=0; bitwidth(); bit++) { setBit(bit,lhs.bitIsExtend(bit + rhsval)); } return *this; } V3Number& V3Number::opShiftL (const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); for (int bit=0; bitwidth(); bit++) { if (bit >= (int)rhsval) { setBit(bit,lhs.bitIs(bit - rhsval)); } } return *this; } //====================================================================== // Ops - Arithmetic V3Number& V3Number::opAbsS (const V3Number& lhs) { // op i, L(lhs) bit return if (lhs.isFourState()) return setAllBitsX(); if (lhs.isNegative()) { return opNegate(lhs); } else { return opAssign(lhs); } } V3Number& V3Number::opNegate (const V3Number& lhs) { // op i, L(lhs) bit return if (lhs.isFourState()) return setAllBitsX(); V3Number notlhs (lhs.m_fileline, width()); notlhs.opNot(lhs); V3Number one (lhs.m_fileline, width(), 1); opAdd(notlhs,one); return *this; } V3Number& V3Number::opAdd (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); setZero(); // Addem int carry=0; for (int bit=0; bitwidth(); bit++) { int sum = ((lhs.bitIs1(bit)?1:0) + (rhs.bitIs1(bit)?1:0) + carry); if (sum & 1) { setBit(bit,1); } carry = (sum >= 2); } return *this; } V3Number& V3Number::opSub (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); V3Number negrhs (rhs.m_fileline, rhs.width()); negrhs.opNegate(rhs); return opAdd(lhs, negrhs); } V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) { // i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); setZero(); if (width() <= 64) { setQuad(lhs.toUQuad() * rhs.toUQuad()); opCleanThis(); // Mult produces extra bits in result } else { for (int lword=0; lwordwords(); qword++) { mul += (vluint64_t)(m_value[qword]); m_value[qword] = (mul & VL_ULL(0xffffffff)); mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff); } } } opCleanThis(); // Mult produces extra bits in result } return *this; } V3Number& V3Number::opMulS (const V3Number& lhs, const V3Number& rhs) { // Signed multiply if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs); V3Number qNoSign = opMul(lhsNoSign,rhsNoSign); if ((lhs.isNegative() && !rhs.isNegative()) || (!lhs.isNegative() && rhs.isNegative())) { opNegate(qNoSign); } else { opAssign(qNoSign); } return *this; } V3Number& V3Number::opDiv (const V3Number& lhs, const V3Number& rhs) { UINFO(9, "opdiv "<>divs-start "<divs-mid "<= 0; j--) { vluint64_t unw64 = ((k<> 32 won't mask the value for (int i = vw-1; i>0; i--) { vn[i] = (rhs.m_value[i] << s) | (shift_mask & (rhs.m_value[i-1] >> (32-s))); } vn[0] = rhs.m_value[0] << s; // Copy and shift dividend by same amount; may set new upper word if (s) un[uw] = lhs.m_value[uw-1] >> (32-s); else un[uw] = 0; for (int i=uw-1; i>0; i--) { un[i] = (lhs.m_value[i] << s) | (shift_mask & (lhs.m_value[i-1] >> (32-s))); } un[0] = lhs.m_value[0] << s; //printf(" un="); for(int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); //printf(" vn="); for(int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); //printf(" mv="); for(int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); // Main loop for (int j = uw - vw; j >= 0; j--) { // Estimate vluint64_t unw64 = ((vluint64_t)(un[j+vw])<= VL_ULL(0x100000000) || ((qhat*vn[vw-2]) > ((rhat<> VL_ULL(32)) - (t >> VL_ULL(32)); } t = un[j+vw] - k; un[j+vw] = t; this->m_value[j] = qhat; // Save quotient digit if (t < 0) { // Over subtracted; correct by adding back this->m_value[j]--; k = 0; for (int i=0; i> VL_ULL(32); } un[j+vw] = un[j+vw] + k; } } //printf(" un="); for(int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); //printf(" vn="); for(int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); //printf(" mv="); for(int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n"); if (is_modulus) { // modulus // Need to reverse normalization on copy to output for (int i=0; i> s) | (shift_mask & (un[i+1] << (32-s))); } for (int i=vw; i64bit ** math not implemented yet: "<<*this); if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** math not implemented yet: "<<*this); setZero(); m_value[0] = 1; V3Number power (lhs.m_fileline, width()); power.opAssign(lhs); for (int bit=0; bit0) { // power = power*power V3Number lastPower (lhs.m_fileline, width()); lastPower.opAssign(power); power.opMul(lastPower, lastPower); } if (rhs.bitIs1(bit)) { // out *= power V3Number lastOut (lhs.m_fileline, width()); lastOut.opAssign(*this); this->opMul(lastOut, power); //UINFO(0, "pow "<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(); for(int bit=0; bitwidth(); bit++) { setBit(bit,lhs.bitIs(bit)); } return *this; } V3Number& V3Number::opExtendS (const V3Number& lhs) { // Note may be a width change during the sign extension setZero(); for(int bit=0; bitwidth(); bit++) { setBit(bit,lhs.bitIsExtend(bit)); } return *this; } V3Number& V3Number::opClean (const V3Number& lhs, uint32_t bits) { return opSel(lhs, bits-1, 0); } void V3Number::opCleanThis() { // Clean in place number if (uint32_t okbits = (width() & 31)) { m_value[words()-1] &= ((1UL<width(); bit++) { if (ibit>=0 && ibitwidth(); bit++) { if (if0s.bitIs1(bit) && if1s.bitIs1(bit)) { setBit(bit,1); } else if (if0s.bitIs0(bit) && if1s.bitIs0(bit)) { setBit(bit,0); } else setBit(bit,'x'); } } return *this; } //====================================================================== // Ops - Floating point V3Number& V3Number::opIToRD (const V3Number& lhs) { return setDouble(lhs.toSInt()); } V3Number& V3Number::opRToIS (const V3Number& lhs) { double v = VL_TRUNC(lhs.toDouble()); vlsint32_t i = (vlsint32_t)v; // C converts from double to vlsint32 return setLongS(i); } V3Number& V3Number::opRToIRoundS (const V3Number& lhs) { double v = VL_ROUND(lhs.toDouble()); vlsint32_t i = (vlsint32_t)v; // C converts from double to vlsint32 return setLongS(i); } V3Number& V3Number::opRealToBits (const V3Number& lhs) { // Conveniently our internal format is identical so we can copy bits... if (lhs.width()!=64 || this->width()!=64) { m_fileline->v3fatalSrc("Real operation on wrong sized number"); } return opAssign(lhs); } V3Number& V3Number::opBitsToRealD (const V3Number& lhs) { // Conveniently our internal format is identical so we can copy bits... if (lhs.width()!=64 || this->width()!=64) { m_fileline->v3fatalSrc("Real operation on wrong sized number"); } return opAssign(lhs); } V3Number& V3Number::opNegateD (const V3Number& lhs) { return setDouble(- lhs.toDouble()); } V3Number& V3Number::opAddD (const V3Number& lhs, const V3Number& rhs) { return setDouble(lhs.toDouble() + rhs.toDouble()); } V3Number& V3Number::opSubD (const V3Number& lhs, const V3Number& rhs) { return setDouble(lhs.toDouble() - rhs.toDouble()); } V3Number& V3Number::opMulD (const V3Number& lhs, const V3Number& rhs) { return setDouble(lhs.toDouble() * rhs.toDouble()); } V3Number& V3Number::opDivD (const V3Number& lhs, const V3Number& rhs) { // On exceptions, we just generate 'inf' through floating point // IEEE says it's implementation defined what happens return setDouble(lhs.toDouble() / rhs.toDouble()); } V3Number& V3Number::opPowD (const V3Number& lhs, const V3Number& rhs) { // On exceptions, we just generate 'inf' through floating point // IEEE says it's implementation defined what happens return setDouble(pow(lhs.toDouble(), rhs.toDouble())); } V3Number& V3Number::opEqD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() == rhs.toDouble()); } V3Number& V3Number::opNeqD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() != rhs.toDouble()); } V3Number& V3Number::opGtD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() > rhs.toDouble()); } V3Number& V3Number::opGteD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() >= rhs.toDouble()); } V3Number& V3Number::opLtD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() < rhs.toDouble()); } V3Number& V3Number::opLteD (const V3Number& lhs, const V3Number& rhs) { return setSingleBits(lhs.toDouble() <= rhs.toDouble()); }