diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 713431381..0f5ea3a98 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -32,6 +32,17 @@ #define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30) +// Number operations build output in-place so can't call e.g. foo.opX(foo) +#define NUM_ASSERT_OP_ARGS1(arg1) \ + UASSERT((this != &(arg1)), \ + "Number operation called with same source and dest"); +#define NUM_ASSERT_OP_ARGS2(arg1,arg2) \ + UASSERT((this != &(arg1) && this != &(arg2)), \ + "Number operation called with same source and dest"); +#define NUM_ASSERT_OP_ARGS3(arg1,arg2,arg3) \ + UASSERT((this != &(arg1) && this != &(arg2) && this != &(arg3)), \ + "Number operation called with same source and dest"); + //====================================================================== // Errors @@ -829,6 +840,7 @@ uint32_t V3Number::mostSetBitP1() const { V3Number& V3Number::opBitsNonX(const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) { setBit(bit, 1); } @@ -837,6 +849,7 @@ V3Number& V3Number::opBitsNonX(const V3Number& lhs) { // 0/1->1, X/Z->0 } V3Number& V3Number::opBitsOne(const V3Number& lhs) { // 1->1, 0/X/Z->0 // op i, L(lhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit)) { setBit(bit, 1); } @@ -845,6 +858,7 @@ V3Number& V3Number::opBitsOne(const V3Number& lhs) { // 1->1, 0/X/Z->0 } V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIsXZ(bit)) { setBit(bit, 1); } @@ -853,6 +867,7 @@ V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0 } V3Number& V3Number::opBitsZ(const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIsZ(bit)) { setBit(bit, 1); } @@ -861,6 +876,7 @@ V3Number& V3Number::opBitsZ(const V3Number& lhs) { // 0/1->1, X/Z->0 } V3Number& V3Number::opBitsNonZ(const V3Number& lhs) { // 0/1->1, X/Z->0 // op i, L(lhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (!lhs.bitIsZ(bit)) { setBit(bit, 1); } @@ -873,6 +889,7 @@ V3Number& V3Number::opBitsNonZ(const V3Number& lhs) { // 0/1->1, X/Z->0 V3Number& V3Number::opRedOr(const V3Number& lhs) { // op i, 1 bit return + NUM_ASSERT_OP_ARGS1(lhs); char outc = 0; for (int bit=0; bitwidth(); bit++) { @@ -970,6 +997,7 @@ V3Number& V3Number::opNot(const V3Number& lhs) { } V3Number& V3Number::opAnd(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for (int bit=0; bitwidth(); bit++) { @@ -981,6 +1009,7 @@ V3Number& V3Number::opAnd(const V3Number& lhs, const V3Number& rhs) { } V3Number& V3Number::opOr(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); for (int bit=0; bitwidth(); bit++) { @@ -992,6 +1021,7 @@ V3Number& V3Number::opOr(const V3Number& lhs, const V3Number& rhs) { } V3Number& V3Number::opChangeXor(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); // 32 bit result opEq(lhs, rhs); return *this; @@ -999,6 +1029,7 @@ V3Number& V3Number::opChangeXor(const V3Number& lhs, const V3Number& rhs) { 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. + NUM_ASSERT_OP_ARGS2(lhs, rhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { setBit(bit, 1); } @@ -1011,6 +1042,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) { 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. + NUM_ASSERT_OP_ARGS2(lhs, rhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } @@ -1022,6 +1054,7 @@ V3Number& V3Number::opXnor(const V3Number& lhs, const V3Number& rhs) { } V3Number& V3Number::opConcat(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); setZero(); // See also error in V3Width if (!lhs.sized() || !rhs.sized()) { @@ -1040,13 +1073,15 @@ V3Number& V3Number::opConcat(const V3Number& lhs, const V3Number& rhs) { } V3Number& V3Number::opLenN(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); setQuad(lhs.toString().length()); return *this; } V3Number& V3Number::opRepl(const V3Number& lhs, const V3Number& rhs) { // rhs is # of times to replicate - // Hopefully the using routine has a error check too. + // Hopefully the using routine has a error check to, &rhso. // See also error in V3Width + NUM_ASSERT_OP_ARGS1(lhs); if (!lhs.sized()) { v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); } @@ -1055,6 +1090,7 @@ V3Number& V3Number::opRepl(const V3Number& lhs, const V3Number& rhs) { // rhs i V3Number& V3Number::opRepl(const V3Number& lhs, uint32_t rhsval) { // rhs is # of times to replicate // i op repl, L(i)*value(rhs) bit return + NUM_ASSERT_OP_ARGS1(lhs); setZero(); if (rhsval > 8192) { v3warn(WIDTHCONCAT, "More than a 8k bit replication is probably wrong: "<>> still acts as a normal >>. // We presume it is signed; as that's V3Width's job to convert to opShiftR + NUM_ASSERT_OP_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); for (int bit=32; bit>divs-start "< return 0 // We may want to special case when the lhs is 2, so we can get larger outputs @@ -1649,6 +1717,7 @@ V3Number& V3Number::opPowUS(const V3Number& lhs, const V3Number& rhs) { } V3Number& V3Number::opBufIf1(const V3Number& ens, const V3Number& if1s) { + NUM_ASSERT_OP_ARGS2(ens, if1s); setZero(); for (int bit=0; bitwidth(); bit++) { if (ens.bitIs1(bit)) { setBit(bit, if1s.bitIs(bit)); } @@ -1661,6 +1730,7 @@ V3Number& V3Number::opAssign(const V3Number& lhs) { // Note may be a width change during the assign. // Special case: opAssign unlike other ops, allows this an assignment // to itself; V3Simulate does this when hits "foo=foo;" + // So no: NUM_ASSERT_OP_ARGS1(lhs); if (this != &lhs) { setZero(); if (isString()) { @@ -1676,6 +1746,7 @@ V3Number& V3Number::opAssign(const V3Number& lhs) { V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) { // Note may be a width change during the sign extension + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bit < width(); bit++) { char extendWith = lhs.bitIsExtend(bit, lbits); @@ -1686,6 +1757,7 @@ V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) { V3Number& V3Number::opExtendXZ(const V3Number& lhs, uint32_t lbits) { // Note may be a width change during the X/Z extension + NUM_ASSERT_OP_ARGS1(lhs); setZero(); for (int bit=0; bit < width(); bit++) { char extendWith = lhs.bitIsExtend(bit, lbits); @@ -1713,11 +1785,13 @@ void V3Number::opCleanThis(bool warnOnTruncation) { } V3Number& V3Number::opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb) { + NUM_ASSERT_OP_ARGS3(lhs, msb, lsb); if (lsb.isFourState() || msb.isFourState()) return setAllBitsX(); return opSel(lhs, msb.toUInt(), lsb.toUInt()); } V3Number& V3Number::opSel(const V3Number& lhs, uint32_t msbval, uint32_t lsbval) { + NUM_ASSERT_OP_ARGS1(lhs); setZero(); int ibit = lsbval; for (int bit=0; bitwidth(); bit++) { @@ -1739,6 +1813,7 @@ V3Number& V3Number::opSelInto(const V3Number& lhs, const V3Number& lsb, int widt V3Number& V3Number::opSelInto(const V3Number& lhs, int lsbval, int width) { // this[lsbval+width-1 : lsbval] = lhs; Other bits of this are not affected + NUM_ASSERT_OP_ARGS1(lhs); int ibit = 0; for (int bit=lsbval; bit=0 && ibitopAssign(if0s); @@ -1774,19 +1850,23 @@ V3Number& V3Number::opCond(const V3Number& lhs, const V3Number& if1s, const V3Nu // Ops - Floating point V3Number& V3Number::opIToRD(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); return setDouble(lhs.toSInt()); } V3Number& V3Number::opRToIS(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); double v = VL_TRUNC(lhs.toDouble()); vlsint32_t i = static_cast(v); // C converts from double to vlsint32 return setLongS(i); } V3Number& V3Number::opRToIRoundS(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); double v = VL_ROUND(lhs.toDouble()); vlsint32_t i = static_cast(v); // C converts from double to vlsint32 return setLongS(i); } V3Number& V3Number::opRealToBits(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... if (lhs.width()!=64 || this->width()!=64) { v3fatalSrc("Real operation on wrong sized number"); @@ -1796,6 +1876,7 @@ V3Number& V3Number::opRealToBits(const V3Number& lhs) { return *this; } V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... if (lhs.width()!=64 || this->width()!=64) { v3fatalSrc("Real operation on wrong sized number"); @@ -1805,43 +1886,55 @@ V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { return *this; } V3Number& V3Number::opNegateD(const V3Number& lhs) { + NUM_ASSERT_OP_ARGS1(lhs); return setDouble(- lhs.toDouble()); } V3Number& V3Number::opAddD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setDouble(lhs.toDouble() + rhs.toDouble()); } V3Number& V3Number::opSubD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setDouble(lhs.toDouble() - rhs.toDouble()); } V3Number& V3Number::opMulD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, 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 + NUM_ASSERT_OP_ARGS2(lhs, rhs); 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 + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setDouble(pow(lhs.toDouble(), rhs.toDouble())); } V3Number& V3Number::opEqD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() == rhs.toDouble()); } V3Number& V3Number::opNeqD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() != rhs.toDouble()); } V3Number& V3Number::opGtD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() > rhs.toDouble()); } V3Number& V3Number::opGteD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() >= rhs.toDouble()); } V3Number& V3Number::opLtD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() < rhs.toDouble()); } V3Number& V3Number::opLteD(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() <= rhs.toDouble()); } @@ -1849,12 +1942,14 @@ V3Number& V3Number::opLteD(const V3Number& lhs, const V3Number& rhs) { // Ops - String V3Number& V3Number::opConcatN(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setString(lhs.toString() + rhs.toString()); } V3Number& V3Number::opReplN(const V3Number& lhs, const V3Number& rhs) { return opReplN(lhs, rhs.toUInt()); } V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) { + NUM_ASSERT_OP_ARGS1(lhs); string out; out.reserve(lhs.toString().length() * rhsval); for (unsigned times=0; times rhs.toString()); } V3Number& V3Number::opGteN(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() >= rhs.toString()); } V3Number& V3Number::opLtN(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() < rhs.toString()); } V3Number& V3Number::opLteN(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_OP_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() <= rhs.toString()); }