// $Id$ //************************************************************************* // DESCRIPTION: Verilator: Large 4-state numbers // // Code available from: http://www.veripool.com/verilator // // AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli // //************************************************************************* // // Copyright 2003-2007 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. // // 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 #include "verilatedos.h" #include #include #include #include #include "V3Number.h" //###################################################################### // Read class functions // CREATION void V3Number::width(int width, bool sized) { // Set width. Only set m_width here, as we need to tweak vector size if (width) { m_sized = sized; m_width=width; } else { m_sized = false; m_width=1; } if (m_value.size() < (unsigned)(words()+1)) { m_value.resize(words()+1); m_valueX.resize(words()+1); } } void V3Number::init (FileLine* fileline, int swidth) { m_fileline = fileline; m_signed = false; m_autoExtend = false; width(swidth); for (int i=0; i32 && olen>7/*10000000 fits in 32 bits, so ok*/) { m_fileline->v3error("Unsupported: Conversion of decimal number over 32 bits, use hex\n"); olen=0; } olen++; break; } case 'z': { if (olen) m_fileline->v3error("Multi-digit X/Z/? not legal in decimal constant: "<<*cp); if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp); olen++; setAllBitsZ(); break; } case 'x': case '?': { if (olen) m_fileline->v3error("Multi-digit X/Z/? not legal in decimal constant: "<<*cp); if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp); olen++; setAllBitsX(); break; } case '_': break; default: { m_fileline->v3error("Illegal character in decimal constant: "<<*cp); break; } } } obit = width(); } else { // Convert bin/octal number to hex for (const char* cp=value_startp+strlen(value_startp)-1; (cp>=value_startp && obit<=width()); cp--) { if (*cp!='_' && 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': setBit(obit++, 'z'); setBit(obit++, 'z'); setBit(obit++, 'z'); break; case 'x': case '?': 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': setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); break; case 'x': case '?': 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; 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': 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(asSQuad()); } else { str = cvtToStr(asQuad()); } int intfmtsize = atoi(fmtsize.c_str()); while ((int)(str.length()) < intfmtsize) str = " "+str; return str; } default: m_fileline->v3fatalSrc("Unknown $display format code for number: %"<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; } //====================================================================== // Operators - Simple per-bit logical ops V3Number& V3Number::opRedOr (const V3Number& lhs) { // op i, 1 bit return char outc = 0; 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(); if (!lhs.sized()) m_fileline->v3error("Unsized constants not allowed in concatenations: "<v3error("Unsized constants not allowed in concatenations: "<v3error("Unsized constants not allowed in concatenations: "<8192) m_fileline->v3fatal("More then 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)); } 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 V3Signed's job to convert to opShiftR if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.asInt(); 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(); uint32_t rhsval = rhs.asInt(); setZero(); for (int bit=0; bitwidth(); bit++) { if (bit >= (int)rhsval) { setBit(bit,lhs.bitIs(bit - rhsval)); } } return *this; } //====================================================================== // Ops - Arithmetic V3Number& V3Number::opUnaryMin (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.opUnaryMin(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.asQuad() * rhs.asQuad()); 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.opUnaryMin(lhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number qNoSign = opMul(lhsNoSign,rhsNoSign); if (lhs.isNegative() && !rhs.isNegative() || !lhs.isNegative() && rhs.isNegative()) { opUnaryMin(qNoSign); } else { opAssign(qNoSign); } return *this; } V3Number& V3Number::opDiv (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(); if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large / math not implemented yet: "<<*this); if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large / math not implemented yet: "<<*this); setQuad(lhs.asQuad() / rhs.asQuad()); return *this; } V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) { // Signed divide if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign); if (lhs.isNegative() && !rhs.isNegative() || !lhs.isNegative() && rhs.isNegative()) { opUnaryMin(qNoSign); } else { opAssign(qNoSign); } return *this; } V3Number& V3Number::opModDiv (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(); if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large % math not implemented yet: "<<*this); if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large % math not implemented yet: "<<*this); setQuad(lhs.asQuad() % rhs.asQuad()); return *this; } V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) { // Signed moddiv if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign); if (lhs.isNegative()) { // Just lhs' sign (*DIFFERENT FROM PERL, which uses rhs sign*) opUnaryMin(qNoSign); } else { opAssign(qNoSign); } return *this; } V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs) { // L(i) bit return, if any 4-state, 4-state return if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (lhs.isEqZero()) return setZero(); // 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 ** 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++) { 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 opRange(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; }