Fix case statements with strings, bug1536.

This commit is contained in:
Wilson Snyder 2019-10-04 19:13:39 -04:00
parent 967dc24fda
commit a9954a71c3
6 changed files with 192 additions and 12 deletions

View File

@ -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

View File

@ -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);

View File

@ -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; bit<width(); bit++) {
if (bitIsX(bit)) return true;
}
@ -850,6 +876,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);
NUM_ASSERT_LOGIC_ARGS1(lhs);
setZero();
for (int bit=0; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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; bit<lhs.width(); bit++) {
if (lhs.bitIs1(bit)) return setSingleBits(1);
@ -911,6 +943,7 @@ V3Number& V3Number::opRedOr(const V3Number& lhs) {
V3Number& V3Number::opRedAnd(const V3Number& lhs) {
// op i, 1 bit return
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
char outc = 1;
for (int bit=0; bit<lhs.width(); bit++) {
if (lhs.bitIs0(bit)) return setSingleBits(0);
@ -923,6 +956,7 @@ V3Number& V3Number::opRedAnd(const V3Number& lhs) {
V3Number& V3Number::opRedXor(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; bit<lhs.width(); bit++) {
if (lhs.bitIs1(bit)) { if (outc==1) outc = 0; else if (outc==0) outc = 1; }
@ -935,6 +969,7 @@ V3Number& V3Number::opRedXor(const V3Number& lhs) {
V3Number& V3Number::opRedXnor(const V3Number& lhs) {
// op i, 1 bit return
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
char outc = 1;
for (int bit=0; bit<lhs.width(); bit++) {
if (lhs.bitIs1(bit)) { if (outc==1) outc = 0; else if (outc==0) outc = 1; }
@ -946,6 +981,7 @@ V3Number& V3Number::opRedXnor(const V3Number& lhs) {
V3Number& V3Number::opCountOnes(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
if (lhs.isFourState()) return setAllBitsX();
setZero();
m_value[0] = lhs.countOnes();
@ -968,6 +1004,7 @@ V3Number& V3Number::opOneHot0(const V3Number& lhs) {
}
V3Number& V3Number::opCLog2(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
if (lhs.isFourState()) return setAllBitsX();
// IE if 4, this algorithm didn't pre-subtract 1, so we need to post-correct now
int adjust = (lhs.countOnes()==1) ? 0 : 1;
@ -983,6 +1020,7 @@ V3Number& V3Number::opCLog2(const V3Number& lhs) {
V3Number& V3Number::opLogNot(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
// op i, 1 bit return
char outc = 1;
for (int bit=0; bit<lhs.width(); bit++) {
@ -996,6 +1034,7 @@ V3Number& V3Number::opLogNot(const V3Number& lhs) {
V3Number& V3Number::opNot(const V3Number& lhs) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
// op i, L(lhs) bit return
setZero();
for (int bit=0; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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: "<<rhsval);
@ -1116,6 +1164,7 @@ V3Number& V3Number::opRepl(const V3Number& lhs, uint32_t rhsval) { // rhs is #
V3Number& V3Number::opStreamL(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()) {
@ -1135,6 +1184,7 @@ V3Number& V3Number::opStreamL(const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opLogAnd(const V3Number& lhs, const V3Number& rhs) {
// i op j, 1 bit return, max(L(lhs),L(rhs)) calculation
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
char loutc = 0;
char routc = 0;
for (int bit=0; bit<lhs.width(); bit++) {
@ -1154,6 +1204,7 @@ V3Number& V3Number::opLogAnd(const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opLogOr(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<lhs.width(); bit++) {
if (lhs.bitIs1(bit)) { outc = 1; goto last; }
@ -1187,6 +1238,8 @@ V3Number& V3Number::opLogEq(const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opEq(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);
if (lhs.isString()) return opEqN(lhs, rhs);
if (lhs.isDouble()) return opEqD(lhs, rhs);
char outc = 1;
for (int bit=0; bit < std::max(lhs.width(), rhs.width()); bit++) {
if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { outc = 0; goto last; }
@ -1201,6 +1254,8 @@ last:
V3Number& V3Number::opNeq(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);
if (lhs.isString()) return opNeqN(lhs, rhs);
if (lhs.isDouble()) return opNeqD(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; goto last; }
@ -1214,7 +1269,10 @@ last:
bool V3Number::isCaseEq(const V3Number& rhs) const {
// i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend.
if (isString()) return toString() == rhs.toString();
if (isDouble()) return toDouble() == rhs.toDouble();
if (this->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<rhs.width(); bit++) {
@ -1374,6 +1441,7 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t
// 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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (rhs.isFourState()) return setAllBitsX();
setZero();
for (int bit=32; bit<rhs.width(); bit++) {
@ -1399,6 +1467,7 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t
V3Number& V3Number::opShiftL(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<rhs.width(); bit++) {
@ -1429,6 +1498,7 @@ V3Number& V3Number::opAbsS(const V3Number& lhs) {
V3Number& V3Number::opNegate(const V3Number& lhs) {
// op i, L(lhs) bit return
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
if (lhs.isFourState()) return setAllBitsX();
V3Number notlhs (&lhs, width());
notlhs.opNot(lhs);
@ -1439,6 +1509,7 @@ V3Number& V3Number::opNegate(const V3Number& lhs) {
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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
setZero();
// Addem
@ -1455,6 +1526,7 @@ V3Number& V3Number::opAdd(const V3Number& lhs, const V3Number& rhs) {
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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
V3Number negrhs (&rhs, rhs.width());
negrhs.opNegate(rhs);
@ -1463,6 +1535,7 @@ V3Number& V3Number::opSub(const V3Number& lhs, const V3Number& rhs) {
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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
setZero();
if (width() <= 64) {
@ -1487,6 +1560,7 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opMulS(const V3Number& lhs, const V3Number& rhs) {
// Signed multiply
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
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);
@ -1502,6 +1576,7 @@ V3Number& V3Number::opMulS(const V3Number& lhs, const V3Number& rhs) {
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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
//UINFO(9, "opdiv "<<lhs<<" "<<rhs<<endl);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
@ -1517,6 +1592,7 @@ V3Number& V3Number::opDivS(const V3Number& lhs, const V3Number& rhs) {
// Signed divide
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
@ -1535,6 +1611,7 @@ V3Number& V3Number::opDivS(const V3Number& lhs, const V3Number& rhs) {
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
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
if (lhs.width()<=64) {
@ -1548,6 +1625,7 @@ V3Number& V3Number::opModDiv(const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opModDivS(const V3Number& lhs, const V3Number& rhs) {
// Signed moddiv
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
@ -1564,6 +1642,7 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
// See Knuth Algorithm D. Computes u/v = q.r
// This isn't massively tuned, as wide division is rare
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
setZero();
// Find MSB and check for zero.
int words = lhs.words();
@ -1686,6 +1765,7 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign, bool rsign) {
// L(i) bit return, if any 4-state, 4-state return
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_LOGIC_ARGS2(lhs, rhs);
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
@ -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; bit<this->width(); 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; bit<this->width(); 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; bit<this->width(); 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<lsbval+width; bit++) {
if (ibit>=0 && ibit<lhs.width()) {
@ -1837,6 +1925,7 @@ V3Number& V3Number::opSelInto(const V3Number& lhs, int lsbval, int width) {
V3Number& V3Number::opCond(const V3Number& lhs, const V3Number& if1s, const V3Number& if0s) {
NUM_ASSERT_OP_ARGS3(lhs, if1s, if0s);
NUM_ASSERT_LOGIC_ARGS1(lhs);
V3Number lhstrue (&lhs); lhstrue.opRedOr(lhs);
if (lhstrue.bitIs0(0)) {
this->opAssign(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; bit<this->width(); 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<vlsint32_t>(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<vlsint32_t>(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<rhsval; times++) {
out += lhs.toString();
@ -1967,25 +2076,31 @@ V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) {
}
V3Number& V3Number::opEqN(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::opNeqN(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::opGtN(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::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());
}

View File

@ -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<words();i++) { if (m_valueX[i]) return true; }
return false;
}
bool isFourState() const;
bool hasZ() const {
for(int i=0;i<words();i++) { if ((~m_value[i]) & m_valueX[i]) return true; }
return false;

20
test_regress/t/t_case_string.pl Executable file
View File

@ -0,0 +1,20 @@
#!/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.
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -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