From a9954a71c3ed7ca840e2361eac9c8ac5d6b50db5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 4 Oct 2019 19:13:39 -0400 Subject: [PATCH] Fix case statements with strings, bug1536. --- Changes | 6 +- src/V3AstNodes.cpp | 16 +++-- src/V3Number.cpp | 119 +++++++++++++++++++++++++++++++- src/V3Number.h | 5 +- test_regress/t/t_case_string.pl | 20 ++++++ test_regress/t/t_case_string.v | 38 ++++++++++ 6 files changed, 192 insertions(+), 12 deletions(-) create mode 100755 test_regress/t/t_case_string.pl create mode 100644 test_regress/t/t_case_string.v diff --git a/Changes b/Changes index bb21c1f9f..7c0207261 100644 --- a/Changes +++ b/Changes @@ -10,10 +10,10 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support vpiModule, bug1469. [Stefan Wallentowitz] -**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy] - **** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader] +**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy] + **** Fix error on multidimensional cells, bug1505. [Anderson Ignacio Da Silva] **** Fix config_rev revision detection on old versions. @@ -26,6 +26,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix misc bad-syntax crashes, bug1529-bug1533. [Eric Rippey] +**** Fix case statements with strings, bug1536. [Philipp Wagner] + * Verilator 4.018 2019-08-29 diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index b4bc43ef1..d09f2a091 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -120,7 +120,9 @@ int AstNodeClassDType::widthAlignBytes() const { } AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { - if (lhsp->isDouble() && rhsp->isDouble()) { + if (lhsp->isString() && rhsp->isString()) { + return new AstEqN(fl, lhsp, rhsp); + } else if (lhsp->isDouble() && rhsp->isDouble()) { return new AstEqD(fl, lhsp, rhsp); } else { return new AstEq(fl, lhsp, rhsp); @@ -128,7 +130,9 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { } AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { - if (lhsp->isDouble() && rhsp->isDouble()) { + if (lhsp->isString() && rhsp->isString()) { + return new AstGteN(fl, lhsp, rhsp); + } else if (lhsp->isDouble() && rhsp->isDouble()) { return new AstGteD(fl, lhsp, rhsp); } else if (lhsp->isSigned() && rhsp->isSigned()) { return new AstGteS(fl, lhsp, rhsp); @@ -138,7 +142,9 @@ AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { } AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { - if (lhsp->isDouble() && rhsp->isDouble()) { + if (lhsp->isString() && rhsp->isString()) { + return new AstLteN(fl, lhsp, rhsp); + } else if (lhsp->isDouble() && rhsp->isDouble()) { return new AstLteD(fl, lhsp, rhsp); } else if (lhsp->isSigned() && rhsp->isSigned()) { return new AstLteS(fl, lhsp, rhsp); @@ -148,7 +154,9 @@ AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { } AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { - if (lhsp->isDouble() && rhsp->isDouble()) { + if (lhsp->isString() && rhsp->isString()) { + return new AstEqN(fl, lhsp, rhsp); + } else if (lhsp->isDouble() && rhsp->isDouble()) { return new AstEqD(fl, lhsp, rhsp); } else { return new AstEqWild(fl, lhsp, rhsp); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index c7a91f1fd..9884719d8 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -37,13 +37,31 @@ #define NUM_ASSERT_OP_ARGS1(arg1) \ UASSERT((this != &(arg1)), \ "Number operation called with same source and dest"); -#define NUM_ASSERT_OP_ARGS2(arg1,arg2) \ +#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) \ +#define NUM_ASSERT_OP_ARGS3(arg1, arg2, arg3) \ UASSERT((this != &(arg1) && this != &(arg2) && this != &(arg3)), \ "Number operation called with same source and dest"); +#define NUM_ASSERT_LOGIC_ARGS1(arg1) \ + UASSERT((!(arg1).isDouble() && !(arg1).isString()), \ + "Number operation called with non-logic (double or string) argument: '"<<(arg1)<<'"'); +#define NUM_ASSERT_LOGIC_ARGS2(arg1, arg2) \ + NUM_ASSERT_LOGIC_ARGS1(arg1); NUM_ASSERT_LOGIC_ARGS1(arg2); + +#define NUM_ASSERT_STRING_ARGS1(arg1) \ + UASSERT((arg1).isString(), \ + "Number operation called with non-string argument: '"<<(arg1)<<'"'); +#define NUM_ASSERT_STRING_ARGS2(arg1, arg2) \ + NUM_ASSERT_STRING_ARGS1(arg1); NUM_ASSERT_STRING_ARGS1(arg2); + +#define NUM_ASSERT_DOUBLE_ARGS1(arg1) \ + UASSERT((arg1).isDouble(), \ + "Number operation called with non-double argument: '"<<(arg1)<<'"'); +#define NUM_ASSERT_DOUBLE_ARGS2(arg1, arg2) \ + NUM_ASSERT_DOUBLE_ARGS1(arg1); NUM_ASSERT_DOUBLE_ARGS1(arg2); + //====================================================================== // Errors @@ -798,7 +816,15 @@ bool V3Number::isEqAllOnes(int optwidth) const { } return true; } +bool V3Number::isFourState() const { + if (isDouble() || isString()) return false; + for (int i=0; i < words(); ++i) { + if (m_valueX[i]) return true; + } + return false; +} bool V3Number::isUnknown() const { + if (isDouble() || isString()) return false; for (int bit=0; bit1, X/Z->0 // op i, L(lhs) bit return NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) { setBit(bit, 1); } @@ -859,6 +886,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit)) { setBit(bit, 1); } @@ -868,6 +896,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIsXZ(bit)) { setBit(bit, 1); } @@ -877,6 +906,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIsZ(bit)) { setBit(bit, 1); } @@ -886,6 +916,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (!lhs.bitIsZ(bit)) { setBit(bit, 1); } @@ -899,6 +930,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); char outc = 0; for (int bit=0; bitwidth(); bit++) { @@ -1007,6 +1046,7 @@ V3Number& V3Number::opNot(const V3Number& lhs) { V3Number& V3Number::opAnd(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_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++) { @@ -1019,6 +1059,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); + NUM_ASSERT_LOGIC_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++) { @@ -1031,6 +1072,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); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); // 32 bit result opEq(lhs, rhs); return *this; @@ -1039,6 +1081,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); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { setBit(bit, 1); } @@ -1052,6 +1095,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); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); for (int bit=0; bitwidth(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } @@ -1064,6 +1108,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); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); // See also error in V3Width if (!lhs.sized() || !rhs.sized()) { @@ -1083,6 +1128,7 @@ V3Number& V3Number::opConcat(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opLenN(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_STRING_ARGS1(lhs); setQuad(lhs.toString().length()); return *this; } @@ -1091,6 +1137,7 @@ V3Number& V3Number::opRepl(const V3Number& lhs, const V3Number& rhs) { // rhs i // Hopefully the using routine has a error check to, &rhso. // See also error in V3Width NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (!lhs.sized()) { v3warn(WIDTHCONCAT, "Unsized numbers/parameters not allowed in replications."); } @@ -1100,6 +1147,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); if (rhsval > 8192) { v3warn(WIDTHCONCAT, "More than a 8k bit replication is probably wrong: "<width() != rhs.width()) return false; + for (int bit=0; bit < std::max(this->width(), rhs.width()); bit++) { if (this->bitIs(bit) != rhs.bitIs(bit)) { return false; } } @@ -1230,6 +1288,8 @@ 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. NUM_ASSERT_OP_ARGS2(lhs, rhs); char outc = 0; + if (lhs.isString()) return opNeqN(lhs, rhs); + else if (lhs.isDouble()) return opNeqD(lhs, rhs); for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { if (lhs.bitIs(bit) != rhs.bitIs(bit)) { outc=1; goto last; } } @@ -1239,6 +1299,7 @@ last: V3Number& V3Number::opWildEq(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 1; for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { if (!rhs.bitIsXZ(bit) @@ -1251,6 +1312,7 @@ last: V3Number& V3Number::opWildNeq(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { if (!rhs.bitIsXZ(bit) @@ -1264,6 +1326,7 @@ last: V3Number& V3Number::opGt(const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend. NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { outc=1; } @@ -1277,6 +1340,7 @@ V3Number& V3Number::opGt(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opGtS(const V3Number& lhs, const V3Number& rhs) { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend. NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); char outc = 0; { int mbit = std::max(lhs.width()-1, rhs.width()-1); @@ -1329,6 +1393,7 @@ V3Number& V3Number::opLteS(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opRotR(const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); @@ -1341,6 +1406,7 @@ V3Number& V3Number::opRotR(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opRotL(const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); @@ -1355,6 +1421,7 @@ V3Number& V3Number::opRotL(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opShiftR(const V3Number& lhs, const V3Number& rhs) { // L(lhs) bit return NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (rhs.isFourState()) return setAllBitsX(); setZero(); for (int bit=32; bit>> 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); + NUM_ASSERT_LOGIC_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 @@ -1727,6 +1807,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); + NUM_ASSERT_LOGIC_ARGS2(ens, if1s); setZero(); for (int bit=0; bitwidth(); bit++) { if (ens.bitIs1(bit)) { setBit(bit, if1s.bitIs(bit)); } @@ -1745,6 +1826,7 @@ V3Number& V3Number::opAssign(const V3Number& lhs) { if (isString()) { m_stringVal = lhs.m_stringVal; } else { + // Also handles double as is just bits for (int bit=0; bitwidth(); bit++) { setBit(bit, lhs.bitIs(bit)); } @@ -1756,6 +1838,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bit < width(); bit++) { char extendWith = lhs.bitIsExtend(bit, lbits); @@ -1767,6 +1850,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); for (int bit=0; bit < width(); bit++) { char extendWith = lhs.bitIsExtend(bit, lbits); @@ -1782,6 +1866,7 @@ V3Number& V3Number::opClean(const V3Number& lhs, uint32_t bits) { void V3Number::opCleanThis(bool warnOnTruncation) { // Clean MSB of number + NUM_ASSERT_LOGIC_ARGS1(*this); uint32_t newValueMsb = m_value[words()-1] & hiWordMask(); uint32_t newValueXMsb = m_valueX[words()-1] & hiWordMask(); if (warnOnTruncation && (newValueMsb != m_value[words()-1] @@ -1795,12 +1880,14 @@ void V3Number::opCleanThis(bool warnOnTruncation) { V3Number& V3Number::opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb) { NUM_ASSERT_OP_ARGS3(lhs, msb, lsb); + NUM_ASSERT_LOGIC_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS2(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); + NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); int ibit = lsbval; for (int bit=0; bitwidth(); bit++) { @@ -1823,6 +1910,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); + NUM_ASSERT_LOGIC_ARGS1(lhs); int ibit = 0; for (int bit=lsbval; bit=0 && ibitopAssign(if0s); @@ -1846,6 +1935,7 @@ V3Number& V3Number::opCond(const V3Number& lhs, const V3Number& if1s, const V3Nu } else { // select is "X/Z" setZero(); + NUM_ASSERT_LOGIC_ARGS2(if1s, if0s); for (int bit=0; bitwidth(); bit++) { if (if0s.bitIs1(bit) && if1s.bitIs1(bit)) { setBit(bit, 1); } else if (if0s.bitIs0(bit) && if1s.bitIs0(bit)) { setBit(bit, 0); } @@ -1860,22 +1950,26 @@ V3Number& V3Number::opCond(const V3Number& lhs, const V3Number& if1s, const V3Nu V3Number& V3Number::opIToRD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_LOGIC_ARGS1(lhs); return setDouble(lhs.toSInt()); } V3Number& V3Number::opRToIS(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_DOUBLE_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); + NUM_ASSERT_DOUBLE_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); + NUM_ASSERT_DOUBLE_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"); @@ -1896,54 +1990,66 @@ V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { } V3Number& V3Number::opNegateD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_DOUBLE_ARGS1(lhs); return setDouble(- lhs.toDouble()); } V3Number& V3Number::opAddD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setDouble(lhs.toDouble() + rhs.toDouble()); } V3Number& V3Number::opSubD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setDouble(lhs.toDouble() - rhs.toDouble()); } V3Number& V3Number::opMulD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_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); + NUM_ASSERT_DOUBLE_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); + NUM_ASSERT_DOUBLE_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); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() == rhs.toDouble()); } V3Number& V3Number::opNeqD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() != rhs.toDouble()); } V3Number& V3Number::opGtD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() > rhs.toDouble()); } V3Number& V3Number::opGteD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() >= rhs.toDouble()); } V3Number& V3Number::opLtD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() < rhs.toDouble()); } V3Number& V3Number::opLteD(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_DOUBLE_ARGS2(lhs, rhs); return setSingleBits(lhs.toDouble() <= rhs.toDouble()); } @@ -1952,13 +2058,16 @@ V3Number& V3Number::opLteD(const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opConcatN(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_STRING_ARGS2(lhs, rhs); return setString(lhs.toString() + rhs.toString()); } V3Number& V3Number::opReplN(const V3Number& lhs, const V3Number& rhs) { + NUM_ASSERT_STRING_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(rhs); return opReplN(lhs, rhs.toUInt()); } V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) { NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_STRING_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); + NUM_ASSERT_STRING_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() >= rhs.toString()); } V3Number& V3Number::opLtN(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_STRING_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() < rhs.toString()); } V3Number& V3Number::opLteN(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); + NUM_ASSERT_STRING_ARGS2(lhs, rhs); return setSingleBits(lhs.toString() <= rhs.toString()); } diff --git a/src/V3Number.h b/src/V3Number.h index dd5f5c174..bc7386c07 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -214,10 +214,7 @@ public: bool isString() const { return m_isString; } void isString(bool flag) { m_isString = flag; } bool isNegative() const { return bitIs1(width()-1); } - bool isFourState() const { - for (int i=0;i 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_string.v b/test_regress/t/t_case_string.v new file mode 100644 index 000000000..c7fbde92b --- /dev/null +++ b/test_regress/t/t_case_string.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + string mystr; + reg [2:0] cyc; initial cyc = 0; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) if (mystr != "case-1") $stop; + if (cyc == 4) if (mystr != "case-4") $stop; + if (cyc == 6) if (mystr != "bad-default") $stop; + if (cyc == 7) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + always @ (cyc) begin + // verilator lint_off CASEINCOMPLETE + case (cyc) + 3'b000: mystr = "case-0"; + 3'b001: mystr = "case-1"; + 3'b010: mystr = "case-2"; + 3'b100: mystr = "case-4"; + 3'b101: mystr = "case-5"; + default: mystr = "bad-default"; + endcase + //$display("with_case: %d = %s", cyc, mystr); + end +endmodule