Fix non-32 bit conversion to float (#2495).
This commit is contained in:
parent
e029ba845e
commit
98cd925fda
5
Changes
5
Changes
|
|
@ -6,9 +6,12 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
*** Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford]
|
*** Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford]
|
||||||
|
|
||||||
|
**** Support $stable. [Peter Monsson]
|
||||||
|
|
||||||
**** Fix combining different-width parameters (#2484). [abirkmanis]
|
**** Fix combining different-width parameters (#2484). [abirkmanis]
|
||||||
|
|
||||||
**** Support $stable. [Peter Monsson]
|
**** Fix non-32 bit conversion to float (#2495). [dsvf]
|
||||||
|
|
||||||
|
|
||||||
* Verilator 4.038 2020-07-11
|
* Verilator 4.038 2020-07-11
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -584,6 +584,31 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig
|
||||||
return VL_POW_QQW(obits, rbits, rbits, lhs, rwp);
|
return VL_POW_QQW(obits, rbits, rbits, lhs, rwp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE {
|
||||||
|
int ms_word = VL_WORDS_I(lbits) - 1;
|
||||||
|
for (; !lwp[ms_word] && ms_word > 0;) --ms_word;
|
||||||
|
if (ms_word == 0) return static_cast<double>(lwp[0]);
|
||||||
|
if (ms_word == 1) return static_cast<double>(VL_SET_QW(lwp));
|
||||||
|
// We need 53 bits of mantissa, which might mean looking at 3 words
|
||||||
|
// namely ms_word, ms_word-1 and ms_word-2
|
||||||
|
EData ihi = lwp[ms_word];
|
||||||
|
EData imid = lwp[ms_word - 1];
|
||||||
|
EData ilo = lwp[ms_word - 2];
|
||||||
|
double hi = static_cast<double>(ihi) * exp2(2 * VL_EDATASIZE);
|
||||||
|
double mid = static_cast<double>(imid) * exp2(VL_EDATASIZE);
|
||||||
|
double lo = static_cast<double>(ilo);
|
||||||
|
double d = (hi + mid + lo) * exp2(VL_EDATASIZE * (ms_word - 2));
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE {
|
||||||
|
if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
|
||||||
|
vluint32_t pos[VL_MULS_MAX_WORDS + 1]; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||||
|
VL_NEGATE_W(VL_WORDS_I(lbits), pos, lwp);
|
||||||
|
_VL_CLEAN_INPLACE_W(lbits, pos);
|
||||||
|
double d = VL_ITOR_D_W(lbits, pos);
|
||||||
|
return -VL_ITOR_D_W(lbits, pos);
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Formatting
|
// Formatting
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -764,9 +764,27 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
/// Return double from QData (numeric)
|
/// Return double from lhs (numeric) unsigned
|
||||||
static inline double VL_ITOR_D_I(IData lhs) VL_PURE {
|
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE;
|
||||||
return static_cast<double>(static_cast<vlsint32_t>(lhs));
|
static inline double VL_ITOR_D_I(int, IData lhs) VL_PURE {
|
||||||
|
return static_cast<double>(static_cast<vluint32_t>(lhs));
|
||||||
|
}
|
||||||
|
static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE {
|
||||||
|
return static_cast<double>(static_cast<vluint64_t>(lhs));
|
||||||
|
}
|
||||||
|
/// Return double from lhs (numeric) signed
|
||||||
|
double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE;
|
||||||
|
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE {
|
||||||
|
if (lbits == 32) return static_cast<double>(static_cast<vlsint32_t>(lhs));
|
||||||
|
WData lwp[VL_WQ_WORDS_E];
|
||||||
|
VL_SET_WI(lwp, lhs);
|
||||||
|
return VL_ISTOR_D_W(lbits, lwp);
|
||||||
|
}
|
||||||
|
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE {
|
||||||
|
if (lbits == 64) return static_cast<double>(static_cast<vlsint64_t>(lhs));
|
||||||
|
WData lwp[VL_WQ_WORDS_E];
|
||||||
|
VL_SET_WQ(lwp, lhs);
|
||||||
|
return VL_ISTOR_D_W(lbits, lwp);
|
||||||
}
|
}
|
||||||
/// Return QData from double (numeric)
|
/// Return QData from double (numeric)
|
||||||
static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
|
static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
|
||||||
|
|
@ -1453,6 +1471,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Math
|
// Math
|
||||||
|
|
||||||
|
// Output NOT clean
|
||||||
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
|
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
|
||||||
EData carry = 1;
|
EData carry = 1;
|
||||||
for (int i = 0; i < words; ++i) {
|
for (int i = 0; i < words; ++i) {
|
||||||
|
|
|
||||||
|
|
@ -5523,6 +5523,7 @@ public:
|
||||||
virtual int instrCount() const { return instrCountDouble(); }
|
virtual int instrCount() const { return instrCountDouble(); }
|
||||||
};
|
};
|
||||||
class AstIToRD : public AstNodeUniop {
|
class AstIToRD : public AstNodeUniop {
|
||||||
|
// $itor where lhs is unsigned
|
||||||
public:
|
public:
|
||||||
AstIToRD(FileLine* fl, AstNode* lhsp)
|
AstIToRD(FileLine* fl, AstNode* lhsp)
|
||||||
: ASTGEN_SUPER(fl, lhsp) {
|
: ASTGEN_SUPER(fl, lhsp) {
|
||||||
|
|
@ -5531,10 +5532,27 @@ public:
|
||||||
ASTNODE_NODE_FUNCS(IToRD)
|
ASTNODE_NODE_FUNCS(IToRD)
|
||||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); }
|
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); }
|
||||||
virtual string emitVerilog() { return "%f$itor(%l)"; }
|
virtual string emitVerilog() { return "%f$itor(%l)"; }
|
||||||
virtual string emitC() { return "VL_ITOR_D_I(%li)"; }
|
virtual string emitC() { return "VL_ITOR_D_%lq(%lw, %li)"; }
|
||||||
virtual bool cleanOut() const { return false; }
|
virtual bool cleanOut() const { return false; }
|
||||||
virtual bool cleanLhs() const { return false; } // Eliminated before matters
|
virtual bool cleanLhs() const { return true; }
|
||||||
virtual bool sizeMattersLhs() const { return false; } // Eliminated before matters
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
|
virtual int instrCount() const { return instrCountDouble(); }
|
||||||
|
};
|
||||||
|
class AstISToRD : public AstNodeUniop {
|
||||||
|
// $itor where lhs is signed
|
||||||
|
public:
|
||||||
|
AstISToRD(FileLine* fl, AstNode* lhsp)
|
||||||
|
: ASTGEN_SUPER(fl, lhsp) {
|
||||||
|
dtypeSetDouble();
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(ISToRD)
|
||||||
|
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opISToRD(lhs); }
|
||||||
|
virtual string emitVerilog() { return "%f$itor($signed(%l))"; }
|
||||||
|
virtual string emitC() { return "VL_ISTOR_D_%lq(%lw, %li)"; }
|
||||||
|
virtual bool emitCheckMaxWords() { return true; }
|
||||||
|
virtual bool cleanOut() const { return false; }
|
||||||
|
virtual bool cleanLhs() const { return true; }
|
||||||
|
virtual bool sizeMattersLhs() const { return false; }
|
||||||
virtual int instrCount() const { return instrCountDouble(); }
|
virtual int instrCount() const { return instrCountDouble(); }
|
||||||
};
|
};
|
||||||
class AstRealToBits : public AstNodeUniop {
|
class AstRealToBits : public AstNodeUniop {
|
||||||
|
|
|
||||||
|
|
@ -877,6 +877,15 @@ public:
|
||||||
emitOpName(nodep, nodep->emitC(), NULL, NULL, NULL);
|
emitOpName(nodep, nodep->emitC(), NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||||
|
if (nodep->emitCheckMaxWords()
|
||||||
|
&& (nodep->widthWords() > VL_MULS_MAX_WORDS
|
||||||
|
|| nodep->lhsp()->widthWords() > VL_MULS_MAX_WORDS)) {
|
||||||
|
nodep->v3warn(
|
||||||
|
E_UNSUPPORTED,
|
||||||
|
"Unsupported: "
|
||||||
|
<< nodep->prettyOperatorName() << " operator of " << nodep->width()
|
||||||
|
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
|
||||||
|
}
|
||||||
if (emitSimpleOk(nodep)) {
|
if (emitSimpleOk(nodep)) {
|
||||||
putbs("(");
|
putbs("(");
|
||||||
puts(nodep->emitSimpleOperator());
|
puts(nodep->emitSimpleOperator());
|
||||||
|
|
|
||||||
|
|
@ -2232,13 +2232,24 @@ V3Number& V3Number::opSelInto(const V3Number& lhs, int lsbval, int width) {
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Ops - Floating point
|
// Ops - Floating point
|
||||||
|
|
||||||
V3Number& V3Number::opIToRD(const V3Number& lhs) {
|
V3Number& V3Number::opIToRD(const V3Number& lhs, bool isSigned) {
|
||||||
NUM_ASSERT_OP_ARGS1(lhs);
|
NUM_ASSERT_OP_ARGS1(lhs);
|
||||||
NUM_ASSERT_LOGIC_ARGS1(lhs);
|
NUM_ASSERT_LOGIC_ARGS1(lhs);
|
||||||
// IEEE says we ignore x/z in real conversions
|
// IEEE says we ignore x/z in real conversions
|
||||||
V3Number noxz(lhs);
|
V3Number noxz(lhs);
|
||||||
noxz.opAssignNonXZ(lhs);
|
noxz.opAssignNonXZ(lhs);
|
||||||
return setDouble(noxz.toSInt());
|
double d = 0;
|
||||||
|
bool negate = isSigned && noxz.isNegative();
|
||||||
|
if (negate) {
|
||||||
|
V3Number noxz_signed = noxz;
|
||||||
|
noxz.opNegate(noxz_signed);
|
||||||
|
}
|
||||||
|
for (int bit = noxz.width() - 1; bit >= 0; bit--) {
|
||||||
|
// Some precision might be lost in this add, that's what we want
|
||||||
|
if (noxz.bitIs1(bit)) d += exp2(bit);
|
||||||
|
}
|
||||||
|
if (negate) d = -d;
|
||||||
|
return setDouble(d);
|
||||||
}
|
}
|
||||||
V3Number& V3Number::opRToIS(const V3Number& lhs) {
|
V3Number& V3Number::opRToIS(const V3Number& lhs) {
|
||||||
NUM_ASSERT_OP_ARGS1(lhs);
|
NUM_ASSERT_OP_ARGS1(lhs);
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,8 @@ public:
|
||||||
V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed
|
V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||||
|
|
||||||
// "D" - double (aka real) math
|
// "D" - double (aka real) math
|
||||||
V3Number& opIToRD(const V3Number& lhs);
|
V3Number& opIToRD(const V3Number& lhs, bool isSigned = false);
|
||||||
|
V3Number& opISToRD(const V3Number& lhs) { return opIToRD(lhs, true); }
|
||||||
V3Number& opRToIS(const V3Number& lhs);
|
V3Number& opRToIS(const V3Number& lhs);
|
||||||
V3Number& opRToIRoundS(const V3Number& lhs);
|
V3Number& opRToIRoundS(const V3Number& lhs);
|
||||||
V3Number& opRealToBits(const V3Number& lhs);
|
V3Number& opRealToBits(const V3Number& lhs);
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,6 @@ private:
|
||||||
//========
|
//========
|
||||||
// Widths: Output real, input integer signed
|
// Widths: Output real, input integer signed
|
||||||
virtual void visit(AstBitsToRealD* nodep) VL_OVERRIDE { visit_Or_Lu64(nodep); }
|
virtual void visit(AstBitsToRealD* nodep) VL_OVERRIDE { visit_Or_Lu64(nodep); }
|
||||||
virtual void visit(AstIToRD* nodep) VL_OVERRIDE { visit_Or_Ls32(nodep); }
|
|
||||||
|
|
||||||
// Widths: Output integer signed, input real
|
// Widths: Output integer signed, input real
|
||||||
virtual void visit(AstRToIS* nodep) VL_OVERRIDE { visit_Os32_Lr(nodep); }
|
virtual void visit(AstRToIS* nodep) VL_OVERRIDE { visit_Os32_Lr(nodep); }
|
||||||
|
|
@ -1549,7 +1548,11 @@ private:
|
||||||
}
|
}
|
||||||
AstNode* newp = nodep->lhsp()->unlinkFrBack();
|
AstNode* newp = nodep->lhsp()->unlinkFrBack();
|
||||||
if (basicp->isDouble() && !newp->isDouble()) {
|
if (basicp->isDouble() && !newp->isDouble()) {
|
||||||
newp = new AstIToRD(nodep->fileline(), newp);
|
if (newp->isSigned()) {
|
||||||
|
newp = new AstISToRD(nodep->fileline(), newp);
|
||||||
|
} else {
|
||||||
|
newp = new AstIToRD(nodep->fileline(), newp);
|
||||||
|
}
|
||||||
} else if (!basicp->isDouble() && newp->isDouble()) {
|
} else if (!basicp->isDouble() && newp->isDouble()) {
|
||||||
if (basicp->isSigned()) {
|
if (basicp->isSigned()) {
|
||||||
newp = new AstRToIRoundS(nodep->fileline(), newp);
|
newp = new AstRToIRoundS(nodep->fileline(), newp);
|
||||||
|
|
@ -3931,16 +3934,27 @@ private:
|
||||||
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
|
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit_Or_Ls32(AstNodeUniop* nodep) {
|
virtual void visit(AstIToRD* nodep) VL_OVERRIDE {
|
||||||
// CALLER: AstIToRD
|
|
||||||
// Real: Output real
|
// Real: Output real
|
||||||
// LHS presumed self-determined, then coerced to real
|
// LHS presumed self-determined, then coerced to real
|
||||||
if (m_vup->prelim()) { // First stage evaluation
|
if (m_vup->prelim()) { // First stage evaluation
|
||||||
nodep->dtypeSetDouble();
|
nodep->dtypeSetDouble();
|
||||||
AstNodeDType* subDTypep = nodep->findLogicDType(32, 32, VSigning::SIGNED);
|
// Self-determined operand (TODO check if numeric type)
|
||||||
// Self-determined operand
|
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
|
||||||
|
if (nodep->lhsp()->isSigned()) {
|
||||||
|
nodep->replaceWith(
|
||||||
|
new AstISToRD(nodep->fileline(), nodep->lhsp()->unlinkFrBack()));
|
||||||
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void visit(AstISToRD* nodep) VL_OVERRIDE {
|
||||||
|
// Real: Output real
|
||||||
|
// LHS presumed self-determined, then coerced to real
|
||||||
|
if (m_vup->prelim()) { // First stage evaluation
|
||||||
|
nodep->dtypeSetDouble();
|
||||||
|
// Self-determined operand (TODO check if numeric type)
|
||||||
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
|
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p());
|
||||||
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit_Os32_Lr(AstNodeUniop* nodep) {
|
void visit_Os32_Lr(AstNodeUniop* nodep) {
|
||||||
|
|
@ -4800,7 +4814,12 @@ private:
|
||||||
UINFO(6, " spliceCvtD: " << nodep << endl);
|
UINFO(6, " spliceCvtD: " << nodep << endl);
|
||||||
AstNRelinker linker;
|
AstNRelinker linker;
|
||||||
nodep->unlinkFrBack(&linker);
|
nodep->unlinkFrBack(&linker);
|
||||||
AstNode* newp = new AstIToRD(nodep->fileline(), nodep);
|
AstNode* newp;
|
||||||
|
if (nodep->dtypep()->skipRefp()->isSigned()) {
|
||||||
|
newp = new AstISToRD(nodep->fileline(), nodep);
|
||||||
|
} else {
|
||||||
|
newp = new AstIToRD(nodep->fileline(), nodep);
|
||||||
|
}
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
return newp;
|
return newp;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
// Version 2.0.
|
// Version 2.0.
|
||||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
`define is_near_real(a,b) (( ((a)<(b)) ? (b)-(a) : (a)-(b)) < (((a)/(b))*0.0001))
|
`define is_near_real(a,b) (( ((a)<(b)) ? (b)-(a) : (a)-(b)) < (((a)/(b))*0.0001))
|
||||||
|
|
||||||
module t (/*AUTOARG*/
|
module t (/*AUTOARG*/
|
||||||
|
|
@ -16,6 +17,16 @@ module t (/*AUTOARG*/
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
reg [63:0] b;
|
reg [63:0] b;
|
||||||
|
reg [47:0] i48;
|
||||||
|
reg signed [47:0] is48;
|
||||||
|
reg [31:0] ci32;
|
||||||
|
reg signed [31:0] cis32;
|
||||||
|
reg [47:0] ci48;
|
||||||
|
reg signed [47:0] cis48;
|
||||||
|
reg [63:0] ci64;
|
||||||
|
reg signed [63:0] cis64;
|
||||||
|
reg [95:0] ci96;
|
||||||
|
reg signed [95:0] cis96;
|
||||||
real r, r2;
|
real r, r2;
|
||||||
integer cyc=0;
|
integer cyc=0;
|
||||||
|
|
||||||
|
|
@ -88,6 +99,41 @@ module t (/*AUTOARG*/
|
||||||
// bug
|
// bug
|
||||||
b = 64'h7fe8000000000000;
|
b = 64'h7fe8000000000000;
|
||||||
$display("%6.3f", $bitstoreal(b));
|
$display("%6.3f", $bitstoreal(b));
|
||||||
|
// bug
|
||||||
|
i48 = 48'hff00_00000000;
|
||||||
|
r = real'(i48);
|
||||||
|
if (r != 280375465082880.0) $stop;
|
||||||
|
r = $itor(i48);
|
||||||
|
if (r != 280375465082880.0) $stop;
|
||||||
|
|
||||||
|
is48 = 48'shff00_00000000;
|
||||||
|
r = real'(is48);
|
||||||
|
if (r != -1099511627776.0) $stop;
|
||||||
|
r = $itor(is48);
|
||||||
|
if (r != -1099511627776.0) $stop;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
r = i48;
|
||||||
|
if (r != 280375465082880.0) $stop;
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
r = $itor(-10);
|
||||||
|
if (r != -10.0) $stop;
|
||||||
|
|
||||||
|
r = real'(4'sb1111);
|
||||||
|
if (r != -1) $stop;
|
||||||
|
r = $itor(4'sb1111);
|
||||||
|
if (r != -1) $stop;
|
||||||
|
|
||||||
|
r = real'(4'b1111);
|
||||||
|
if (r != 15) $stop;
|
||||||
|
r = $itor(4'b1111);
|
||||||
|
if (r != 15) $stop;
|
||||||
|
|
||||||
|
r = real'(96'hf0000000_00000000_00000000);
|
||||||
|
if (r != 74276402357122816493947453440.0) $stop;
|
||||||
|
r = real'(96'shf0000000_00000000_00000000);
|
||||||
|
if (r != -4951760157141521099596496896.0) $stop;
|
||||||
end
|
end
|
||||||
|
|
||||||
// Test loop
|
// Test loop
|
||||||
|
|
@ -98,8 +144,18 @@ module t (/*AUTOARG*/
|
||||||
cyc <= cyc + 1;
|
cyc <= cyc + 1;
|
||||||
if (cyc==0) begin
|
if (cyc==0) begin
|
||||||
// Setup
|
// Setup
|
||||||
|
ci48 <= '0;
|
||||||
|
cis48 <= '0;
|
||||||
|
ci96 <= '0;
|
||||||
|
cis96 <= '0;
|
||||||
end
|
end
|
||||||
else if (cyc<90) begin
|
else if (cyc == 1) begin
|
||||||
|
ci48 <= 48'hff00_00000000;
|
||||||
|
cis48 <= 48'shff00_00000000;
|
||||||
|
ci96 <= 96'hf0000000_00000000_00000000;
|
||||||
|
cis96 <= 96'shf0000000_00000000_00000000;
|
||||||
|
end
|
||||||
|
else if (cyc<80) begin
|
||||||
if ($time != {32'h0, $rtoi($realtime)}) $stop;
|
if ($time != {32'h0, $rtoi($realtime)}) $stop;
|
||||||
if ($itor(cyc) != cyc) $stop;
|
if ($itor(cyc) != cyc) $stop;
|
||||||
//Unsup: if ((real `($time)) != $realtime) $stop;
|
//Unsup: if ((real `($time)) != $realtime) $stop;
|
||||||
|
|
@ -141,6 +197,76 @@ module t (/*AUTOARG*/
|
||||||
!= (((cyc-50)!=0) ? 10 : 20)) $stop;
|
!= (((cyc-50)!=0) ? 10 : 20)) $stop;
|
||||||
//
|
//
|
||||||
if ((!(r-50.0)) != (!((cyc-50) != 0))) $stop;
|
if ((!(r-50.0)) != (!((cyc-50) != 0))) $stop;
|
||||||
|
//
|
||||||
|
r = real'(ci48);
|
||||||
|
`checkr(r, 280375465082880.0);
|
||||||
|
r = real'(cis48);
|
||||||
|
`checkr(r, -1099511627776.0);
|
||||||
|
//
|
||||||
|
r = real'(ci96);
|
||||||
|
`checkr(r, 74276402357122816493947453440.0);
|
||||||
|
r = real'(cis96);
|
||||||
|
`checkr(r, -4951760157141521099596496896.0);
|
||||||
|
end
|
||||||
|
else if (cyc==90) begin
|
||||||
|
ci32 <= '0;
|
||||||
|
cis32 <= '0;
|
||||||
|
ci48 <= '0;
|
||||||
|
cis48 <= '0;
|
||||||
|
ci64 <= '0;
|
||||||
|
cis64 <= '0;
|
||||||
|
ci96 <= '0;
|
||||||
|
cis96 <= '0;
|
||||||
|
end
|
||||||
|
else if (cyc==91) begin
|
||||||
|
`checkr(real'(ci32), 0.0);
|
||||||
|
`checkr(real'(cis32), 0.0);
|
||||||
|
`checkr(real'(ci48), 0.0);
|
||||||
|
`checkr(real'(cis48), 0.0);
|
||||||
|
`checkr(real'(ci64), 0.0);
|
||||||
|
`checkr(real'(cis64), 0.0);
|
||||||
|
`checkr(real'(ci96), 0.0);
|
||||||
|
`checkr(real'(cis96), 0.0);
|
||||||
|
end
|
||||||
|
else if (cyc==92) begin
|
||||||
|
ci32 <= 32'b1;
|
||||||
|
cis32 <= 32'b1;
|
||||||
|
ci48 <= 48'b1;
|
||||||
|
cis48 <= 48'b1;
|
||||||
|
ci64 <= 64'b1;
|
||||||
|
cis64 <= 64'b1;
|
||||||
|
ci96 <= 96'b1;
|
||||||
|
cis96 <= 96'b1;
|
||||||
|
end
|
||||||
|
else if (cyc==93) begin
|
||||||
|
`checkr(real'(ci32), 1.0);
|
||||||
|
`checkr(real'(cis32), 1.0);
|
||||||
|
`checkr(real'(ci48), 1.0);
|
||||||
|
`checkr(real'(cis48), 1.0);
|
||||||
|
`checkr(real'(ci64), 1.0);
|
||||||
|
`checkr(real'(cis64), 1.0);
|
||||||
|
`checkr(real'(ci96), 1.0);
|
||||||
|
`checkr(real'(cis96), 1.0);
|
||||||
|
end
|
||||||
|
else if (cyc==94) begin
|
||||||
|
ci32 <= ~ '0;
|
||||||
|
cis32 <= ~ '0;
|
||||||
|
ci48 <= ~ '0;
|
||||||
|
cis48 <= ~ '0;
|
||||||
|
ci64 <= ~ '0;
|
||||||
|
cis64 <= ~ '0;
|
||||||
|
ci96 <= ~ '0;
|
||||||
|
cis96 <= ~ '0;
|
||||||
|
end
|
||||||
|
else if (cyc==95) begin
|
||||||
|
`checkr(real'(ci32), 4294967295.0);
|
||||||
|
`checkr(real'(cis32), -1.0);
|
||||||
|
`checkr(real'(ci48), 281474976710655.0);
|
||||||
|
`checkr(real'(cis48), -1.0);
|
||||||
|
`checkr(real'(ci64), 18446744073709551616.0);
|
||||||
|
`checkr(real'(cis64), -1.0);
|
||||||
|
`checkr(real'(ci96), 79228162514264337593543950336.0);
|
||||||
|
`checkr(real'(cis96), -1.0);
|
||||||
end
|
end
|
||||||
else if (cyc==99) begin
|
else if (cyc==99) begin
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2020 Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
reg [63:0] crc;
|
||||||
|
reg [63:0] sum;
|
||||||
|
|
||||||
|
reg [127:0] in;
|
||||||
|
|
||||||
|
check #(48) check48 (.*);
|
||||||
|
check #(31) check31 (.*);
|
||||||
|
check #(32) check32 (.*);
|
||||||
|
check #(63) check63 (.*);
|
||||||
|
check #(64) check64 (.*);
|
||||||
|
check #(96) check96 (.*);
|
||||||
|
check #(128) check128 (.*);
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
if (crc[2:0] == 0) in = '0;
|
||||||
|
else if (crc[2:0] == 1) in = ~'0;
|
||||||
|
else if (crc[2:0] == 2) in = 128'b1;
|
||||||
|
else if (crc[2:0] == 3) in = ~ 128'b1;
|
||||||
|
else begin
|
||||||
|
in = {crc, crc};
|
||||||
|
if (crc[3]) in[31:0] = '0;
|
||||||
|
if (crc[4]) in[63:32] = '0;
|
||||||
|
if (crc[5]) in[95:64] = '0;
|
||||||
|
if (crc[6]) in[127:96] = '0;
|
||||||
|
if (crc[7]) in[31:0] = ~'0;
|
||||||
|
if (crc[8]) in[63:32] = ~'0;
|
||||||
|
if (crc[9]) in[95:64] = ~'0;
|
||||||
|
if (crc[10]) in[127:96] = ~'0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d in=%x\n",$time, cyc, in);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
|
if (cyc == 0) begin
|
||||||
|
// Setup
|
||||||
|
crc <= 64'h5aef0c8d_d70a4497;
|
||||||
|
sum <= '0;
|
||||||
|
end
|
||||||
|
else if (cyc == 99) begin
|
||||||
|
`checkr(check48.sum, 14574057015683440.000000);
|
||||||
|
`checkr(check31.sum, 114141374814.000000);
|
||||||
|
`checkr(check32.sum, 236547942750.000000);
|
||||||
|
`checkr(check63.sum, 513694866079917670400.000000);
|
||||||
|
`checkr(check64.sum, 1002533584033221181440.000000);
|
||||||
|
`checkr(check96.sum, 4377373669974269260279175970816.000000);
|
||||||
|
`checkr(check128.sum, 18358899571808044815012294240949812330496.000000);
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module check(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
in, clk, cyc
|
||||||
|
);
|
||||||
|
parameter WIDTH = 128;
|
||||||
|
input [127:0] in;
|
||||||
|
|
||||||
|
wire [WIDTH-1:0] ci = in[WIDTH-1:0];
|
||||||
|
wire signed [WIDTH-1:0] cis = in[WIDTH-1:0];
|
||||||
|
|
||||||
|
real r;
|
||||||
|
real rs;
|
||||||
|
always_comb r = ci;
|
||||||
|
always_comb rs = cis;
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input integer cyc;
|
||||||
|
real sum;
|
||||||
|
|
||||||
|
always_ff @ (negedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] w%0d in=%h r=%f rs=%f sum=%f\n", $time, WIDTH, ci, r, rs, sum);
|
||||||
|
`endif
|
||||||
|
if (cyc < 10) sum <= 0;
|
||||||
|
else sum <= sum + r + rs;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
%Error-UNSUPPORTED: t/t_math_wide_bad.v:21:18: Unsupported: operator POWSS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h
|
%Error-UNSUPPORTED: t/t_math_wide_bad.v:22:18: Unsupported: operator POWSS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h
|
||||||
21 | assign z2 = a ** 3;
|
22 | assign z2 = a ** 3;
|
||||||
| ^~
|
| ^~
|
||||||
%Error-UNSUPPORTED: t/t_math_wide_bad.v:20:17: Unsupported: operator MULS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h
|
%Error-UNSUPPORTED: t/t_math_wide_bad.v:23:15: Unsupported: operator ISTORD operator of 64 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h
|
||||||
20 | assign z = a * b;
|
23 | assign r = real'(a);
|
||||||
|
| ^~~~
|
||||||
|
%Error-UNSUPPORTED: t/t_math_wide_bad.v:21:17: Unsupported: operator MULS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h
|
||||||
|
21 | assign z = a * b;
|
||||||
| ^
|
| ^
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
module t (/*AUTOARG*/
|
module t (/*AUTOARG*/
|
||||||
// Outputs
|
// Outputs
|
||||||
z, z2,
|
z, z2, r,
|
||||||
// Inputs
|
// Inputs
|
||||||
a, b
|
a, b
|
||||||
);
|
);
|
||||||
|
|
@ -16,8 +16,10 @@ module t (/*AUTOARG*/
|
||||||
|
|
||||||
output signed [17*32 : 0] z;
|
output signed [17*32 : 0] z;
|
||||||
output signed [17*32 : 0] z2;
|
output signed [17*32 : 0] z2;
|
||||||
|
output real r;
|
||||||
|
|
||||||
assign z = a * b;
|
assign z = a * b;
|
||||||
assign z2 = a ** 3;
|
assign z2 = a ** 3;
|
||||||
|
assign r = real'(a);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
`define STRINGIFY(x) `"x`"
|
`define STRINGIFY(x) `"x`"
|
||||||
`define ratio_error(a,b) (((a)>(b) ? ((a)-(b)) : ((b)-(a))) /(a))
|
`define ratio_error(a,b) (((a)>(b) ? ((a)-(b)) : ((b)-(a))) /(a))
|
||||||
`define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
`define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module t (/*AUTOARG*/
|
||||||
input clk;
|
input clk;
|
||||||
|
|
||||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
|
|
||||||
// IEEE: integer_atom_type
|
// IEEE: integer_atom_type
|
||||||
wire byte w_byte;
|
wire byte w_byte;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue