Fix non-32 bit conversion to float (#2495).

This commit is contained in:
Wilson Snyder 2020-08-06 21:56:43 -04:00
parent e029ba845e
commit 98cd925fda
15 changed files with 383 additions and 26 deletions

View File

@ -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]
**** Support $stable. [Peter Monsson]
**** 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

View File

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

View File

@ -764,9 +764,27 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
}
// clang-format on
/// Return double from QData (numeric)
static inline double VL_ITOR_D_I(IData lhs) VL_PURE {
return static_cast<double>(static_cast<vlsint32_t>(lhs));
/// Return double from lhs (numeric) unsigned
double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE;
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)
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
// Output NOT clean
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE {
EData carry = 1;
for (int i = 0; i < words; ++i) {

View File

@ -5523,6 +5523,7 @@ public:
virtual int instrCount() const { return instrCountDouble(); }
};
class AstIToRD : public AstNodeUniop {
// $itor where lhs is unsigned
public:
AstIToRD(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER(fl, lhsp) {
@ -5531,10 +5532,27 @@ public:
ASTNODE_NODE_FUNCS(IToRD)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); }
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 cleanLhs() const { return false; } // Eliminated before matters
virtual bool sizeMattersLhs() const { return false; } // Eliminated before matters
virtual bool cleanLhs() const { return true; }
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(); }
};
class AstRealToBits : public AstNodeUniop {

View File

@ -877,6 +877,15 @@ public:
emitOpName(nodep, nodep->emitC(), NULL, NULL, NULL);
}
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)) {
putbs("(");
puts(nodep->emitSimpleOperator());

View File

@ -2232,13 +2232,24 @@ V3Number& V3Number::opSelInto(const V3Number& lhs, int lsbval, int width) {
//======================================================================
// Ops - Floating point
V3Number& V3Number::opIToRD(const V3Number& lhs) {
V3Number& V3Number::opIToRD(const V3Number& lhs, bool isSigned) {
NUM_ASSERT_OP_ARGS1(lhs);
NUM_ASSERT_LOGIC_ARGS1(lhs);
// IEEE says we ignore x/z in real conversions
V3Number noxz(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) {
NUM_ASSERT_OP_ARGS1(lhs);

View File

@ -385,7 +385,8 @@ public:
V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed
// "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& opRToIRoundS(const V3Number& lhs);
V3Number& opRealToBits(const V3Number& lhs);

View File

@ -332,7 +332,6 @@ private:
//========
// Widths: Output real, input integer signed
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
virtual void visit(AstRToIS* nodep) VL_OVERRIDE { visit_Os32_Lr(nodep); }
@ -1549,7 +1548,11 @@ private:
}
AstNode* newp = nodep->lhsp()->unlinkFrBack();
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()) {
if (basicp->isSigned()) {
newp = new AstRToIRoundS(nodep->fileline(), newp);
@ -3931,16 +3934,27 @@ private:
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
}
}
void visit_Or_Ls32(AstNodeUniop* nodep) {
// CALLER: AstIToRD
virtual void visit(AstIToRD* nodep) VL_OVERRIDE {
// Real: Output real
// LHS presumed self-determined, then coerced to real
if (m_vup->prelim()) { // First stage evaluation
nodep->dtypeSetDouble();
AstNodeDType* subDTypep = nodep->findLogicDType(32, 32, VSigning::SIGNED);
// Self-determined operand
// Self-determined operand (TODO check if numeric type)
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());
iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP);
}
}
void visit_Os32_Lr(AstNodeUniop* nodep) {
@ -4800,7 +4814,12 @@ private:
UINFO(6, " spliceCvtD: " << nodep << endl);
AstNRelinker 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);
return newp;
} else {

View File

@ -6,6 +6,7 @@
// Version 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))
module t (/*AUTOARG*/
@ -16,6 +17,16 @@ module t (/*AUTOARG*/
integer i;
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;
integer cyc=0;
@ -88,6 +99,41 @@ module t (/*AUTOARG*/
// bug
b = 64'h7fe8000000000000;
$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
// Test loop
@ -98,8 +144,18 @@ module t (/*AUTOARG*/
cyc <= cyc + 1;
if (cyc==0) begin
// Setup
ci48 <= '0;
cis48 <= '0;
ci96 <= '0;
cis96 <= '0;
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 ($itor(cyc) != cyc) $stop;
//Unsup: if ((real `($time)) != $realtime) $stop;
@ -141,6 +197,76 @@ module t (/*AUTOARG*/
!= (((cyc-50)!=0) ? 10 : 20)) $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
else if (cyc==99) begin
$write("*-* All Finished *-*\n");

View 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;

View File

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

View File

@ -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
21 | assign z2 = a ** 3;
%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
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
20 | assign z = a * b;
%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
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

View File

@ -6,7 +6,7 @@
module t (/*AUTOARG*/
// Outputs
z, z2,
z, z2, r,
// Inputs
a, b
);
@ -16,8 +16,10 @@ module t (/*AUTOARG*/
output signed [17*32 : 0] z;
output signed [17*32 : 0] z2;
output real r;
assign z = a * b;
assign z2 = a ** 3;
assign r = real'(a);
endmodule

View File

@ -8,7 +8,7 @@
`define STRINGIFY(x) `"x`"
`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 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);

View File

@ -11,7 +11,7 @@ module t (/*AUTOARG*/
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 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
wire byte w_byte;