forked from github/verilator
Support $countbits (#2287)
This commit is contained in:
parent
070bcddf5a
commit
f9a0cf0cff
2
Changes
2
Changes
@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
* Verilator 4.035 devel
|
||||
|
||||
**** Support $countbits. (#2287) [Yossi Nivin]
|
||||
|
||||
**** Support $isunbounded and parameter $. (#2104)
|
||||
|
||||
**** Support unpacked array .sum and .product.
|
||||
|
@ -3104,11 +3104,11 @@ uwire keyword.
|
||||
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
|
||||
|
||||
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
|
||||
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
|
||||
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
|
||||
const, do-while, enum, export, final, import, int, interface, logic,
|
||||
longint, modport, package, program, shortint, struct, time, typedef, union,
|
||||
var, void, priority case/if, and unique case/if.
|
||||
$bits, $countbits, $countones, $error, $fatal, $info, $isunknown, $onehot,
|
||||
$onehot0, $unit, $warning, always_comb, always_ff, always_latch, bit, byte,
|
||||
chandle, const, do-while, enum, export, final, import, int, interface,
|
||||
logic, longint, modport, package, program, shortint, struct, time, typedef,
|
||||
union, var, void, priority case/if, and unique case/if.
|
||||
|
||||
It also supports .name and .* interconnection.
|
||||
|
||||
@ -3935,9 +3935,9 @@ All timing control statements are ignored.
|
||||
Verilator does not perform warning checking on uwires, it treats the uwire
|
||||
keyword as if it were the normal wire keyword.
|
||||
|
||||
=item $bits, $countones, $error, $fatal, $finish, $info, $isunknown,
|
||||
$onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop, $time,
|
||||
$unsigned, $warning.
|
||||
=item $bits, $countbits, $countones, $error, $fatal, $finish, $info,
|
||||
$isunknown, $onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop,
|
||||
$time, $unsigned, $warning.
|
||||
|
||||
Generally supported.
|
||||
|
||||
|
@ -47,5 +47,6 @@ Tobias Wölfel
|
||||
Todd Strader
|
||||
Veripool API Bot
|
||||
Wilson Snyder
|
||||
Yossi Nivin
|
||||
Yutetsu TAKATSUKASA
|
||||
Yves Mathieu
|
||||
|
@ -1217,6 +1217,36 @@ static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE {
|
||||
return r;
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
|
||||
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
|
||||
IData ctrl2) VL_PURE {
|
||||
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
|
||||
if (ctrlSum == 3) {
|
||||
return VL_COUNTONES_I(lhs);
|
||||
} else if (ctrlSum == 0) {
|
||||
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
|
||||
return VL_COUNTONES_I(~lhs & mask);
|
||||
} else {
|
||||
return (lbits == 32) ? 32 : lbits;
|
||||
}
|
||||
}
|
||||
static inline IData VL_COUNTBITS_Q(int lbits, QData lhs, IData ctrl0, IData ctrl1,
|
||||
IData ctrl2) VL_PURE {
|
||||
return VL_COUNTBITS_I(32, static_cast<IData>(lhs), ctrl0, ctrl1, ctrl2)
|
||||
+ VL_COUNTBITS_I(lbits - 32, static_cast<IData>(lhs >> 32), ctrl0, ctrl1, ctrl2);
|
||||
}
|
||||
#define VL_COUNTBITS_E VL_COUNTBITS_I
|
||||
static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctrl0, IData ctrl1,
|
||||
IData ctrl2) VL_MT_SAFE {
|
||||
EData r = 0;
|
||||
IData wordLbits = 32;
|
||||
for (int i = 0; i < words; ++i) {
|
||||
if (i == words - 1) { wordLbits = lbits % 32; }
|
||||
r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
|
||||
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
|
||||
}
|
||||
|
37
src/V3Ast.h
37
src/V3Ast.h
@ -1999,6 +1999,43 @@ public:
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeQuadop : public AstNodeMath {
|
||||
// Quaternary math
|
||||
public:
|
||||
AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs)
|
||||
: AstNodeMath(t, fl) {
|
||||
setOp1p(lhs);
|
||||
setOp2p(rhs);
|
||||
setOp3p(ths);
|
||||
setOp4p(fhs);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeQuadop)
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
AstNode* rhsp() const { return op2p(); }
|
||||
AstNode* thsp() const { return op3p(); }
|
||||
AstNode* fhsp() const { return op4p(); }
|
||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
|
||||
void thsp(AstNode* nodep) { return setOp3p(nodep); }
|
||||
void fhsp(AstNode* nodep) { return setOp4p(nodep); }
|
||||
// METHODS
|
||||
// Set out to evaluation of a AstConst'ed
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
|
||||
const V3Number& ths, const V3Number& fhs)
|
||||
= 0;
|
||||
virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero
|
||||
virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero
|
||||
virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero
|
||||
virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero
|
||||
virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size
|
||||
virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size
|
||||
virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size
|
||||
virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
};
|
||||
|
||||
class AstNodeBiCom : public AstNodeBiop {
|
||||
// Binary math with commutative properties
|
||||
public:
|
||||
|
@ -5424,6 +5424,33 @@ public:
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
virtual int instrCount() const { return widthInstrs() * 16; }
|
||||
};
|
||||
class AstCountBits : public AstNodeQuadop {
|
||||
// Number of bits set in vector
|
||||
public:
|
||||
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p)
|
||||
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), ctrl1p->cloneTree(false)) {}
|
||||
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p)
|
||||
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {}
|
||||
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p)
|
||||
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
|
||||
ASTNODE_NODE_FUNCS(CountBits)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1,
|
||||
const V3Number& ctrl2, const V3Number& ctrl3) {
|
||||
out.opCountBits(expr, ctrl1, ctrl2, ctrl3);
|
||||
}
|
||||
virtual string emitVerilog() { return "%f$countbits(%l, %r, %f, %o)"; }
|
||||
virtual string emitC() { return ""; }
|
||||
virtual bool cleanOut() const { return false; }
|
||||
virtual bool cleanLhs() const { return true; }
|
||||
virtual bool cleanRhs() const { return true; }
|
||||
virtual bool cleanThs() const { return true; }
|
||||
virtual bool cleanFhs() const { return true; }
|
||||
virtual bool sizeMattersLhs() const { return false; }
|
||||
virtual bool sizeMattersRhs() const { return false; }
|
||||
virtual bool sizeMattersThs() const { return false; }
|
||||
virtual bool sizeMattersFhs() const { return false; }
|
||||
virtual int instrCount() const { return widthInstrs() * 16; }
|
||||
};
|
||||
class AstCountOnes : public AstNodeUniop {
|
||||
// Number of bits set in vector
|
||||
public:
|
||||
|
@ -128,6 +128,15 @@ private:
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
|
||||
| nodep->fhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
|
||||
}
|
||||
virtual void visit(AstCCast* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
ensureLower32Cast(nodep);
|
||||
|
@ -160,6 +160,15 @@ private:
|
||||
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
||||
// no setClean.. must do it in each user routine.
|
||||
}
|
||||
void operandQuadop(AstNodeQuadop* nodep) {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) { ensureClean(nodep->lhsp()); }
|
||||
if (nodep->cleanRhs()) { ensureClean(nodep->rhsp()); }
|
||||
if (nodep->cleanThs()) { ensureClean(nodep->thsp()); }
|
||||
if (nodep->cleanFhs()) { ensureClean(nodep->fhsp()); }
|
||||
// no setClean.. must do it in each user routine.
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
@ -192,6 +201,10 @@ private:
|
||||
operandBiop(nodep);
|
||||
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
|
||||
operandQuadop(nodep);
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
|
@ -664,6 +664,14 @@ private:
|
||||
UINFO(4, "TRICONST -> " << num << endl);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
void replaceConst(AstNodeQuadop* nodep) {
|
||||
V3Number num(nodep, nodep->width());
|
||||
nodep->numberOperate(
|
||||
num, VN_CAST(nodep->lhsp(), Const)->num(), VN_CAST(nodep->rhsp(), Const)->num(),
|
||||
VN_CAST(nodep->thsp(), Const)->num(), VN_CAST(nodep->fhsp(), Const)->num());
|
||||
UINFO(4, "QUADCONST -> " << num << endl);
|
||||
VL_DO_DANGLING(replaceNum(nodep, num), nodep);
|
||||
}
|
||||
|
||||
void replaceConstString(AstNode* oldp, const string& num) {
|
||||
// Replace oldp node with a constant set to specified value
|
||||
@ -2258,6 +2266,7 @@ private:
|
||||
// Generic constants on both side. Do this first to avoid other replacements
|
||||
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
|
||||
// Zero on one side or the other
|
||||
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp.isZero, $rhsp, isTPure($rhsp)}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure
|
||||
|
@ -1000,6 +1000,26 @@ public:
|
||||
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", nodep->lhsp(),
|
||||
nodep->rhsp(), NULL);
|
||||
}
|
||||
virtual void visit(AstCountBits* nodep) {
|
||||
putbs("VL_COUNTBITS_");
|
||||
emitIQW(nodep->lhsp());
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->lhsp()->widthMin()));
|
||||
puts(", ");
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
puts(cvtToStr(nodep->lhsp()->widthWords())); // Note argument width, not node width
|
||||
// (which is always 32)
|
||||
puts(", ");
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->thsp());
|
||||
puts(", ");
|
||||
iterateAndNextNull(nodep->fhsp());
|
||||
puts(")");
|
||||
}
|
||||
// Terminals
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
puts(nodep->hiernameProtect());
|
||||
|
@ -411,13 +411,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
|
||||
// Operators
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL,
|
||||
AstNode* rhsp = NULL, AstNode* thsp = NULL) {
|
||||
AstNode* rhsp = NULL, AstNode* thsp = NULL,
|
||||
AstNode* fhsp = NULL) {
|
||||
// Look at emitVerilog() format for term/uni/dual/triops,
|
||||
// and write out appropriate text.
|
||||
// %f Potential fileline-if-change and line break
|
||||
// %l lhsp - if appropriate
|
||||
// %r rhsp - if appropriate
|
||||
// %t thsp - if appropriate
|
||||
// %o fhsp - if appropriate
|
||||
// %d dtypep - if appropriate
|
||||
// %k Potential line break
|
||||
bool inPct = false;
|
||||
@ -450,6 +452,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
iterateAndNextNull(thsp);
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
UASSERT_OBJ(thsp, nodep, "emitVerilog() references undef node");
|
||||
iterateAndNextNull(fhsp);
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "emitVerilog() references undef node");
|
||||
iterateAndNextNull(nodep->dtypep());
|
||||
|
@ -38,6 +38,9 @@
|
||||
#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_OP_ARGS4(arg1, arg2, arg3, arg4) \
|
||||
UASSERT((this != &(arg1) && this != &(arg2) && this != &(arg3) && this != &(arg4)), \
|
||||
"Number operation called with same source and dest");
|
||||
|
||||
#define NUM_ASSERT_LOGIC_ARGS1(arg1) \
|
||||
UASSERT((!(arg1).isDouble() && !(arg1).isString()), \
|
||||
@ -47,6 +50,12 @@
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg1); \
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg2);
|
||||
|
||||
#define NUM_ASSERT_LOGIC_ARGS4(arg1, arg2, arg3, arg4) \
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg1); \
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg2); \
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg3); \
|
||||
NUM_ASSERT_LOGIC_ARGS1(arg4);
|
||||
|
||||
#define NUM_ASSERT_STRING_ARGS1(arg1) \
|
||||
UASSERT((arg1).isString(), \
|
||||
"Number operation called with non-string argument: '" << (arg1) << '"');
|
||||
@ -953,6 +962,37 @@ int V3Number::widthMin() const {
|
||||
return 1; // one bit even if number is == 0
|
||||
}
|
||||
|
||||
uint32_t V3Number::countBits(const V3Number& ctrl) const {
|
||||
int n = 0;
|
||||
for (int bit = 0; bit < this->width(); ++bit) {
|
||||
switch (ctrl.bitIs(0)) {
|
||||
case '0':
|
||||
if (bitIs0(bit)) ++n;
|
||||
break;
|
||||
case '1':
|
||||
if (bitIs1(bit)) ++n;
|
||||
break;
|
||||
case 'x':
|
||||
if (bitIsX(bit)) ++n;
|
||||
break;
|
||||
case 'z':
|
||||
if (bitIsZ(bit)) ++n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
uint32_t V3Number::countBits(const V3Number& ctrl1, const V3Number& ctrl2,
|
||||
const V3Number& ctrl3) const {
|
||||
int n = countBits(ctrl1);
|
||||
if (ctrl2.bitIs(0) != ctrl1.bitIs(0)) n += countBits(ctrl2);
|
||||
if ((ctrl3.bitIs(0) != ctrl1.bitIs(0)) && (ctrl3.bitIs(0) != ctrl2.bitIs(0))) {
|
||||
n += countBits(ctrl3);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
uint32_t V3Number::countOnes() const {
|
||||
int n = 0;
|
||||
for (int bit = 0; bit < this->width(); bit++) {
|
||||
@ -1095,6 +1135,15 @@ V3Number& V3Number::opRedXnor(const V3Number& lhs) {
|
||||
return setSingleBits(outc);
|
||||
}
|
||||
|
||||
V3Number& V3Number::opCountBits(const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2,
|
||||
const V3Number& ctrl3) {
|
||||
NUM_ASSERT_OP_ARGS4(expr, ctrl1, ctrl2, ctrl3);
|
||||
NUM_ASSERT_LOGIC_ARGS4(expr, ctrl1, ctrl2, ctrl3);
|
||||
setZero();
|
||||
m_value[0] = expr.countBits(ctrl1, ctrl2, ctrl3);
|
||||
opCleanThis();
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::opCountOnes(const V3Number& lhs) {
|
||||
NUM_ASSERT_OP_ARGS1(lhs);
|
||||
NUM_ASSERT_LOGIC_ARGS1(lhs);
|
||||
|
@ -284,6 +284,8 @@ public:
|
||||
uint32_t toHash() const;
|
||||
uint32_t edataWord(int eword) const;
|
||||
uint8_t dataByte(int byte) const;
|
||||
uint32_t countBits(const V3Number& ctrl) const;
|
||||
uint32_t countBits(const V3Number& ctrl1, const V3Number& ctrl2, const V3Number& ctrl3) const;
|
||||
uint32_t countOnes() const;
|
||||
uint32_t
|
||||
mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
|
||||
@ -314,6 +316,8 @@ public:
|
||||
V3Number& opRedAnd(const V3Number& lhs);
|
||||
V3Number& opRedXor(const V3Number& lhs);
|
||||
V3Number& opRedXnor(const V3Number& lhs);
|
||||
V3Number& opCountBits(const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2,
|
||||
const V3Number& ctrl3);
|
||||
V3Number& opCountOnes(const V3Number& lhs);
|
||||
V3Number& opIsUnknown(const V3Number& lhs);
|
||||
V3Number& opOneHot(const V3Number& lhs);
|
||||
|
@ -539,6 +539,17 @@ private:
|
||||
fetchConst(nodep->thsp())->num());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
|
||||
if (!optimizable()) return; // Accelerate
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
|
||||
fetchConst(nodep->rhsp())->num(),
|
||||
fetchConst(nodep->thsp())->num(),
|
||||
fetchConst(nodep->fhsp())->num());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstLogAnd* nodep) VL_OVERRIDE {
|
||||
// Need to short circuit
|
||||
if (!optimizable()) return; // Accelerate
|
||||
|
@ -1140,6 +1140,18 @@ private:
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p());
|
||||
}
|
||||
virtual void visit(AstCountBits* nodep) VL_OVERRIDE {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "THS", nodep->thsp(), SELF, BOTH);
|
||||
iterateCheckSizedSelf(nodep, "FHS", nodep->fhsp(), SELF, BOTH);
|
||||
// If it's a 32 bit number, we need a 6 bit number as we need to return '32'.
|
||||
int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1;
|
||||
nodep->dtypeSetLogicSized(selwidth,
|
||||
VSigning::UNSIGNED); // Spec doesn't indicate if an integer
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCountOnes* nodep) VL_OVERRIDE {
|
||||
if (m_vup->prelim()) {
|
||||
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
|
@ -434,6 +434,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
<S05,S09,S12,S17,SAX>{
|
||||
/* System Tasks */
|
||||
"$bits" { FL; return yD_BITS; }
|
||||
"$countbits" { FL; return yD_COUNTBITS; }
|
||||
"$countones" { FL; return yD_COUNTONES; }
|
||||
"$dimensions" { FL; return yD_DIMENSIONS; }
|
||||
"$error" { FL; return yD_ERROR; }
|
||||
|
@ -552,6 +552,7 @@ class AstSenTree;
|
||||
%token<fl> yD_CLOG2 "$clog2"
|
||||
%token<fl> yD_COS "$cos"
|
||||
%token<fl> yD_COSH "$cosh"
|
||||
%token<fl> yD_COUNTBITS "$countbits"
|
||||
%token<fl> yD_COUNTONES "$countones"
|
||||
%token<fl> yD_DIMENSIONS "$dimensions"
|
||||
%token<fl> yD_DISPLAY "$display"
|
||||
@ -3391,6 +3392,11 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
|
||||
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
|
||||
| yD_COS '(' expr ')' { $$ = new AstCosD($1,$3); }
|
||||
| yD_COSH '(' expr ')' { $$ = new AstCoshD($1,$3); }
|
||||
| yD_COUNTBITS '(' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5); }
|
||||
| yD_COUNTBITS '(' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7); }
|
||||
| yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7,$9); }
|
||||
| yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ',' exprList ')'
|
||||
{$11->v3error("Unsupported: $countbits with more than 3 control fields"); }
|
||||
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
|
||||
| yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); }
|
||||
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
|
||||
|
21
test_regress/t/t_math_countbits.pl
Executable file
21
test_regress/t/t_math_countbits.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
134
test_regress/t/t_math_countbits.v
Normal file
134
test_regress/t/t_math_countbits.v
Normal file
@ -0,0 +1,134 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 Yossi Nivin.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
reg [15:0] in16;
|
||||
reg [31:0] in32;
|
||||
reg [63:0] in64;
|
||||
// Non-standard size
|
||||
reg [9:0] in10;
|
||||
reg [20:0] in21;
|
||||
reg [58:0] in59;
|
||||
reg [69:0] in70;
|
||||
|
||||
reg [31:0] ctrl0;
|
||||
reg [31:0] ctrl1;
|
||||
reg [31:0] ctrl2;
|
||||
|
||||
reg [4:0] result_16_1;
|
||||
reg [4:0] result_16_2;
|
||||
reg [4:0] result_16_3;
|
||||
reg [5:0] result_32_1;
|
||||
reg [5:0] result_32_2;
|
||||
reg [5:0] result_32_3;
|
||||
reg [6:0] result_64_1;
|
||||
reg [6:0] result_64_2;
|
||||
reg [6:0] result_64_3;
|
||||
reg [3:0] result_10_3;
|
||||
reg [4:0] result_21_3;
|
||||
reg [5:0] result_59_3;
|
||||
reg [6:0] result_70_3;
|
||||
|
||||
always @* begin
|
||||
result_16_1 = $countbits(in16, ctrl0);
|
||||
result_16_2 = $countbits(in16, ctrl0, ctrl1);
|
||||
result_16_3 = $countbits(in16, ctrl0, ctrl1, ctrl2);
|
||||
|
||||
result_32_1 = $countbits(in32, ctrl0);
|
||||
result_32_2 = $countbits(in32, ctrl0, ctrl1);
|
||||
result_32_3 = $countbits(in32, ctrl0, ctrl1, ctrl2);
|
||||
|
||||
result_64_1 = $countbits(in64, ctrl0);
|
||||
result_64_2 = $countbits(in64, ctrl0, ctrl1);
|
||||
result_64_3 = $countbits(in64, ctrl0, ctrl1, ctrl2);
|
||||
|
||||
result_10_3 = $countbits(in10, ctrl0, ctrl1, ctrl2);
|
||||
result_21_3 = $countbits(in21, ctrl0, ctrl1, ctrl2);
|
||||
result_59_3 = $countbits(in59, ctrl0, ctrl1, ctrl2);
|
||||
result_70_3 = $countbits(in70, ctrl0, ctrl1, ctrl2);
|
||||
end
|
||||
|
||||
integer cyc=0;
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 0) begin
|
||||
// Constants
|
||||
if ($countbits(32'b11001011101, '1) != 7) $stop;
|
||||
if ($countbits(32'b11001011101, '1, 'z) != 7) $stop;
|
||||
if ($countbits(32'b11001011101, '1, '0) != 32) $stop;
|
||||
if ($countbits(20'b11001011101, '1, '0) != 20) $stop;
|
||||
if ($countbits(20'b1100x01z101, '1, '0) != 18) $stop;
|
||||
if ($countbits(20'b1100x01z101, 2, 2'bx1) != 18) $stop;
|
||||
if ($countbits(32'b1100x01z101, 'x, 'z) != 2) $stop;
|
||||
if ($countbits(32'b1100x01z101, 'x, 'z, '1) != 7) $stop;
|
||||
end
|
||||
else if (cyc == 1) begin
|
||||
in16 <= 16'h0AF0;
|
||||
in32 <= 32'hA0F300;
|
||||
in64 <= 64'hA5A5A5A5A5A5A5A5;
|
||||
in10 <= 10'b1010_1011;
|
||||
in21 <= 21'h10F102;
|
||||
in59 <= 59'h7050137210;
|
||||
in70 <= 70'hF00030008000;
|
||||
ctrl0 <= '0;
|
||||
ctrl1 <= '1;
|
||||
ctrl2 <= '1;
|
||||
end
|
||||
else if (cyc == 2) begin
|
||||
if (result_16_1 != 10) $stop;
|
||||
if (result_16_2 != 16) $stop;
|
||||
if (result_16_3 != 16) $stop;
|
||||
if (result_32_1 != 24) $stop;
|
||||
if (result_32_2 != 32) $stop;
|
||||
if (result_32_3 != 32) $stop;
|
||||
if (result_64_1 != 32) $stop;
|
||||
if (result_64_2 != 64) $stop;
|
||||
if (result_64_3 != 64) $stop;
|
||||
if (result_10_3 != 10) $stop;
|
||||
if (result_21_3 != 21) $stop;
|
||||
if (result_59_3 != 59) $stop;
|
||||
if (result_70_3 != 70) $stop;
|
||||
|
||||
in16 <= 16'h82B;
|
||||
in32 <= 32'h305372;
|
||||
in64 <= 64'h7777777777777777;
|
||||
in10 <= 10'b1001_0111;
|
||||
in21 <= 21'h91040C;
|
||||
in59 <= 59'h12345678;
|
||||
in70 <= 70'hF11111111;
|
||||
// Confirm upper bits of the control arguments are ignored
|
||||
ctrl0 <= 5;
|
||||
ctrl1 <= 3;
|
||||
ctrl2 <= 2;
|
||||
end
|
||||
else if (cyc == 3) begin
|
||||
if (result_16_1 != 5) $stop;
|
||||
if (result_16_2 != 5) $stop;
|
||||
if (result_16_3 != 16) $stop;
|
||||
if (result_32_1 != 10) $stop;
|
||||
if (result_32_2 != 10) $stop;
|
||||
if (result_32_3 != 32) $stop;
|
||||
if (result_64_1 != 48) $stop;
|
||||
if (result_64_2 != 48) $stop;
|
||||
if (result_64_3 != 64) $stop;
|
||||
if (result_10_3 != 10) $stop;
|
||||
if (result_21_3 != 21) $stop;
|
||||
if (result_59_3 != 59) $stop;
|
||||
if (result_70_3 != 70) $stop;
|
||||
end
|
||||
else if (cyc == 4) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
4
test_regress/t/t_math_countbits_bad.out
Executable file
4
test_regress/t/t_math_countbits_bad.out
Executable file
@ -0,0 +1,4 @@
|
||||
%Error: t/t_math_countbits_bad.v:14:54: Unsupported: $countbits with more than 3 control fields
|
||||
14 | assign count = $countbits(32'h123456, '0, '1, 'x, 'z);
|
||||
| ^~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_math_countbits_bad.pl
Executable file
19
test_regress/t/t_math_countbits_bad.pl
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename}
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
16
test_regress/t/t_math_countbits_bad.v
Normal file
16
test_regress/t/t_math_countbits_bad.v
Normal file
@ -0,0 +1,16 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 Yossi Nivin.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer count;
|
||||
assign count = $countbits(32'h123456, '0, '1, 'x, 'z);
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user