mirror of
https://github.com/verilator/verilator.git
synced 2025-04-16 01:26:54 +00:00
Support $ceil, $floor, etc.
This commit is contained in:
parent
094d676a8b
commit
eb6d42acf9
2
Changes
2
Changes
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.82***
|
||||
|
||||
*** Support $ceil, $floor, etc. [Alex Solomatnikov]
|
||||
|
||||
**** Fix MSVC compile warning with trunc/round, bug394. [Amir Gonnen]
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "V3Error.h"
|
||||
#include "V3Number.h"
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "V3Ast__gen_classes.h" // From ./astgen
|
||||
// Things like:
|
||||
@ -825,6 +826,7 @@ public:
|
||||
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
|
||||
static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats
|
||||
static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats
|
||||
static int instrCountDoubleTrig() { return 200; } ///< Instruction cycles to do triganomics
|
||||
static int instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine
|
||||
static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time
|
||||
|
||||
|
@ -2832,6 +2832,90 @@ struct AstFGetC : public AstNodeUniop {
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
|
||||
struct AstCeilD : public AstNodeUniop {
|
||||
AstCeilD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(CeilD, CEILD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(ceil(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ceil(%l)"; }
|
||||
virtual string emitC() { return "ceil(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstExpD : public AstNodeUniop {
|
||||
AstExpD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(ExpD, EXPD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(exp(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$exp(%l)"; }
|
||||
virtual string emitC() { return "exp(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstFloorD : public AstNodeUniop {
|
||||
AstFloorD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(FloorD, FLOORD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(floor(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$floor(%l)"; }
|
||||
virtual string emitC() { return "floor(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstLogD : public AstNodeUniop {
|
||||
AstLogD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(LogD, LOGD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ln(%l)"; }
|
||||
virtual string emitC() { return "log(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstLog10D : public AstNodeUniop {
|
||||
AstLog10D(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(Log10D, LOG10D)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log10(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$log10(%l)"; }
|
||||
virtual string emitC() { return "log10(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstSqrtD : public AstNodeUniop {
|
||||
AstSqrtD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(SqrtD, SQRTD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(sqrt(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$sqrt(%l)"; }
|
||||
virtual string emitC() { return "sqrt(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// Binary ops
|
||||
|
||||
|
@ -546,7 +546,7 @@ public:
|
||||
}
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
|
||||
} else if (nodep->isDouble()) {
|
||||
ofp()->printf("%g", nodep->num().toDouble());
|
||||
ofp()->printf("%.17g", nodep->num().toDouble());
|
||||
} else if (nodep->isQuad()) {
|
||||
vluint64_t num = nodep->toUQuad();
|
||||
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include "V3Number.h"
|
||||
|
||||
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
|
||||
@ -337,6 +338,7 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
|
||||
ostringstream out;
|
||||
|
||||
if (isDouble()) {
|
||||
out.precision(17);
|
||||
out<<toDouble();
|
||||
return out.str();
|
||||
}
|
||||
|
@ -208,6 +208,13 @@ private:
|
||||
virtual void visit(AstPowD* nodep, AstNUser* vup) { visit_math_Or_LRr(nodep,vup); }
|
||||
// Signed/Real: Output real or signed iff LHS signed/real
|
||||
virtual void visit(AstNegateD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
// Real: Output real
|
||||
virtual void visit(AstCeilD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
virtual void visit(AstExpD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
virtual void visit(AstFloorD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
virtual void visit(AstLogD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
virtual void visit(AstLog10D* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
virtual void visit(AstSqrtD* nodep, AstNUser* vup) { visit_math_Or_Lr(nodep,vup); }
|
||||
|
||||
// Widths: out signed/unsigned width = lhs width, input un|signed
|
||||
virtual void visit(AstSigned* nodep, AstNUser* vup) { visit_Ous_Lus_Wforce(nodep,vup,AstNumeric::SIGNED); }
|
||||
@ -1188,14 +1195,14 @@ private:
|
||||
nodep->taskp()->iterate(*this);
|
||||
//
|
||||
// And do the arguments to the task/function too
|
||||
for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice
|
||||
for (int accept_mode=0; accept_mode<3; accept_mode++) { // Avoid duplicate code; just do inner stuff several times
|
||||
reloop:
|
||||
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
|
||||
bool lastloop = false;
|
||||
for (V3TaskConnects::iterator it=tconnects.begin(); !lastloop && it!=tconnects.end(); ++it) {
|
||||
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) {
|
||||
AstVar* portp = it->first;
|
||||
AstNode* pinp = it->second;
|
||||
if (pinp!=NULL) { // Else argument error we'll find later
|
||||
if (accept_mode) {
|
||||
if (accept_mode==0) {
|
||||
// Prelim may cause the node to get replaced; we've lost our
|
||||
// pointer, so need to iterate separately later
|
||||
if (portp->attrSFormat()
|
||||
@ -1214,7 +1221,7 @@ private:
|
||||
}
|
||||
handle.relink(newp);
|
||||
// Connection list is now incorrect (has extra args in it).
|
||||
lastloop = true; // so exit early; next loop will correct it
|
||||
goto reloop; // so exit early; next loop will correct it
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
|
||||
&& !pinp->castCvtPackString()
|
||||
@ -1228,7 +1235,12 @@ private:
|
||||
pinp = newp;
|
||||
}
|
||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
|
||||
} else {
|
||||
} else if (accept_mode==1) {
|
||||
// Change data types based on above accept completion
|
||||
if (portp->isDouble()) {
|
||||
spliceCvtD(pinp); pinp=NULL;
|
||||
}
|
||||
} else if (accept_mode==2) {
|
||||
// Do PRELIM again, because above accept may have exited early due to node replacement
|
||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
|
||||
if ((portp->isOutput() || portp->isInout())
|
||||
@ -1585,20 +1597,18 @@ private:
|
||||
}
|
||||
void visit_math_Or_LRr(AstNodeBiop* nodep, AstNUser* vup) {
|
||||
if (vup->c()->prelim()) { // First stage evaluation
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
checkCvtD(nodep->lhsp());
|
||||
checkCvtD(nodep->rhsp());
|
||||
nodep->numeric(AstNumeric::DOUBLE);
|
||||
// Determine expression widths only relying on what's in the subops
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
}
|
||||
void visit_math_Or_Lr(AstNodeUniop* nodep, AstNUser* vup) {
|
||||
if (vup->c()->prelim()) { // First stage evaluation
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
checkCvtD(nodep->lhsp());
|
||||
nodep->numeric(AstNumeric::DOUBLE);
|
||||
// Determine expression widths only relying on what's in the subops
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,9 @@ word [a-zA-Z0-9_]+
|
||||
"$c"[0-9]* { FL; return yD_C; } /*Verilator only*/
|
||||
/* System Tasks */
|
||||
"$bitstoreal" { FL; return yD_BITSTOREAL; }
|
||||
"$ceil" { FL; return yD_CEIL; }
|
||||
"$display" { FL; return yD_DISPLAY; }
|
||||
"$exp" { FL; return yD_EXP; }
|
||||
"$fclose" { FL; return yD_FCLOSE; }
|
||||
"$fdisplay" { FL; return yD_FDISPLAY; }
|
||||
"$feof" { FL; return yD_FEOF; }
|
||||
@ -183,14 +185,18 @@ word [a-zA-Z0-9_]+
|
||||
"$fgetc" { FL; return yD_FGETC; }
|
||||
"$fgets" { FL; return yD_FGETS; }
|
||||
"$finish" { FL; return yD_FINISH; }
|
||||
"$floor" { FL; return yD_FLOOR; }
|
||||
"$fopen" { FL; return yD_FOPEN; }
|
||||
"$fscanf" { FL; return yD_FSCANF; }
|
||||
"$fullskew" { FL; return yaTIMINGSPEC; }
|
||||
"$fwrite" { FL; return yD_FWRITE; }
|
||||
"$hold" { FL; return yaTIMINGSPEC; }
|
||||
"$itor" { FL; return yD_ITOR; }
|
||||
"$ln" { FL; return yD_LN; }
|
||||
"$log10" { FL; return yD_LOG10; }
|
||||
"$nochange" { FL; return yaTIMINGSPEC; }
|
||||
"$period" { FL; return yaTIMINGSPEC; }
|
||||
"$pow" { FL; return yD_POW; }
|
||||
"$random" { FL; return yD_RANDOM; }
|
||||
"$readmemb" { FL; return yD_READMEMB; }
|
||||
"$readmemh" { FL; return yD_READMEMH; }
|
||||
@ -204,6 +210,7 @@ word [a-zA-Z0-9_]+
|
||||
"$setuphold" { FL; return yaTIMINGSPEC; }
|
||||
"$sformat" { FL; return yD_SFORMAT; }
|
||||
"$skew" { FL; return yaTIMINGSPEC; }
|
||||
"$sqrt" { FL; return yD_SQRT; }
|
||||
"$sscanf" { FL; return yD_SSCANF; }
|
||||
"$stime" { FL; return yD_STIME; }
|
||||
"$stop" { FL; return yD_STOP; }
|
||||
|
@ -386,10 +386,12 @@ class AstSenTree;
|
||||
%token<fl> yD_BITS "$bits"
|
||||
%token<fl> yD_BITSTOREAL "$bitstoreal"
|
||||
%token<fl> yD_C "$c"
|
||||
%token<fl> yD_CEIL "$ceil"
|
||||
%token<fl> yD_CLOG2 "$clog2"
|
||||
%token<fl> yD_COUNTONES "$countones"
|
||||
%token<fl> yD_DISPLAY "$display"
|
||||
%token<fl> yD_ERROR "$error"
|
||||
%token<fl> yD_EXP "$exp"
|
||||
%token<fl> yD_FATAL "$fatal"
|
||||
%token<fl> yD_FCLOSE "$fclose"
|
||||
%token<fl> yD_FDISPLAY "$fdisplay"
|
||||
@ -398,14 +400,18 @@ class AstSenTree;
|
||||
%token<fl> yD_FGETC "$fgetc"
|
||||
%token<fl> yD_FGETS "$fgets"
|
||||
%token<fl> yD_FINISH "$finish"
|
||||
%token<fl> yD_FLOOR "$floor"
|
||||
%token<fl> yD_FOPEN "$fopen"
|
||||
%token<fl> yD_FSCANF "$fscanf"
|
||||
%token<fl> yD_FWRITE "$fwrite"
|
||||
%token<fl> yD_INFO "$info"
|
||||
%token<fl> yD_ISUNKNOWN "$isunknown"
|
||||
%token<fl> yD_ITOR "$itor"
|
||||
%token<fl> yD_LN "$ln"
|
||||
%token<fl> yD_LOG10 "$log10"
|
||||
%token<fl> yD_ONEHOT "$onehot"
|
||||
%token<fl> yD_ONEHOT0 "$onehot0"
|
||||
%token<fl> yD_POW "$pow"
|
||||
%token<fl> yD_RANDOM "$random"
|
||||
%token<fl> yD_READMEMB "$readmemb"
|
||||
%token<fl> yD_READMEMH "$readmemh"
|
||||
@ -414,6 +420,7 @@ class AstSenTree;
|
||||
%token<fl> yD_RTOI "$rtoi"
|
||||
%token<fl> yD_SFORMAT "$sformat"
|
||||
%token<fl> yD_SIGNED "$signed"
|
||||
%token<fl> yD_SQRT "$sqrt"
|
||||
%token<fl> yD_SSCANF "$sscanf"
|
||||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
@ -2152,6 +2159,13 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
|
||||
| yaD_DPI parenE { $$ = new AstFuncRef($<fl>1,*$1,NULL); }
|
||||
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); }
|
||||
//
|
||||
| yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); }
|
||||
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
|
||||
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
|
||||
| yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); }
|
||||
| yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); }
|
||||
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); }
|
||||
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
|
||||
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
|
||||
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
|
||||
| yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); }
|
||||
|
@ -13,9 +13,11 @@ compile (
|
||||
expect=>
|
||||
q{%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
|
||||
%Error: t/t_func_bad.v:\d+: Too many arguments in function call to FUNC 'add'
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'
|
||||
%Error: Exiting due to},
|
||||
);
|
||||
|
||||
|
18
test_regress/t/t_math_trig.pl
Executable file
18
test_regress/t/t_math_trig.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
155
test_regress/t/t_math_trig.v
Normal file
155
test_regress/t/t_math_trig.v
Normal file
@ -0,0 +1,155 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2011 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.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
real r, r2;
|
||||
integer cyc=0;
|
||||
|
||||
task check(integer line, real got, real ex);
|
||||
if (got != ex) begin
|
||||
if ((got - ex) > 0.000001) begin
|
||||
$display("%%Error: Line %0d: Bad result, got=%0.99g expect=%0.99g",line,got,ex);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
// Check constant propagation
|
||||
check(`__LINE__, $ceil(-1.2), -1);
|
||||
check(`__LINE__, $ceil(1.2), 2);
|
||||
check(`__LINE__, $exp(1.2), 3.3201169227365472380597566370852291584014892578125);
|
||||
check(`__LINE__, $exp(0.0), 1);
|
||||
check(`__LINE__, $exp(-1.2), 0.301194211912202136627314530414878390729427337646484375);
|
||||
check(`__LINE__, $floor(-1.2), -2);
|
||||
check(`__LINE__, $floor(1.2), 1);
|
||||
check(`__LINE__, $ln(1.2), 0.1823215567939545922460098381634452380239963531494140625);
|
||||
//check(`__LINE__, $ln(0), 0); // Bad value
|
||||
//check(`__LINE__, $ln(-1.2), 0); // Bad value
|
||||
check(`__LINE__, $log10(1.2), 0.07918124604762481755226843915806966833770275115966796875);
|
||||
//check(`__LINE__, $log10(0), 0); // Bad value
|
||||
//check(`__LINE__, $log10(-1.2), 0);
|
||||
check(`__LINE__, $pow(2.3,1.2), 2.71689843249914897427288451581262052059173583984375);
|
||||
check(`__LINE__, $pow(2.3,-1.2), 0.368066758785732861536388327294844202697277069091796875);
|
||||
//check(`__LINE__, $pow(-2.3,1.2),0); // Bad value
|
||||
check(`__LINE__, $sqrt(1.2), 1.095445115010332148841598609578795731067657470703125);
|
||||
//check(`__LINE__, $sqrt(-1.2), 0); // Bad value
|
||||
`ifndef VERILATOR
|
||||
check(`__LINE__, $acos (0.2), 1.369438406); // Arg1 is -1..1
|
||||
check(`__LINE__, $acosh(1.2), 0.622362503);
|
||||
check(`__LINE__, $asin (0.2), 0.201357920); // Arg1 is -1..1
|
||||
check(`__LINE__, $asinh(1.2), 1.015973134);
|
||||
check(`__LINE__, $atan (0.2), 0.197395559);
|
||||
check(`__LINE__, $atan2(0.2,2.3), 0.086738338); // Arg1 is -1..1
|
||||
check(`__LINE__, $atanh(0.2), 0.202732554); // Arg1 is -1..1
|
||||
check(`__LINE__, $cos (1.2), 0.362357754);
|
||||
check(`__LINE__, $cosh (1.2), 1.810655567);
|
||||
check(`__LINE__, $hypot(1.2,2.3), 2.594224354);
|
||||
check(`__LINE__, $sin (1.2), 0.932039085);
|
||||
check(`__LINE__, $sinh (1.2), 1.509461355);
|
||||
check(`__LINE__, $tan (1.2), 2.572151622);
|
||||
check(`__LINE__, $tanh (1.2), 0.833654607);
|
||||
`endif
|
||||
end
|
||||
|
||||
real sum_ceil;
|
||||
real sum_exp;
|
||||
real sum_floor;
|
||||
real sum_ln;
|
||||
real sum_log10;
|
||||
real sum_pow1;
|
||||
real sum_pow2;
|
||||
real sum_sqrt;
|
||||
|
||||
real sum_acos;
|
||||
real sum_acosh;
|
||||
real sum_asin;
|
||||
real sum_asinh;
|
||||
real sum_atan;
|
||||
real sum_atan2;
|
||||
real sum_atanh;
|
||||
real sum_cos ;
|
||||
real sum_cosh;
|
||||
real sum_hypot;
|
||||
real sum_sin;
|
||||
real sum_sinh;
|
||||
real sum_tan;
|
||||
real sum_tanh;
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
r = $itor(cyc)/10.0 - 5.0; // Crosses 0
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d r=%g s_ln=%0.12g\n",$time, cyc, r, sum_ln);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==0) begin
|
||||
end
|
||||
else if (cyc<90) begin
|
||||
// Setup
|
||||
sum_ceil += 1.0+$ceil(r);
|
||||
sum_exp += 1.0+$exp(r);
|
||||
sum_floor += 1.0+$floor(r);
|
||||
if (r > 0.0) sum_ln += 1.0+$ln(r);
|
||||
if (r > 0.0) sum_log10 += 1.0+$log10(r);
|
||||
// Pow requires if arg1<0 then arg1 integral
|
||||
sum_pow1 += 1.0+$pow(2.3,r);
|
||||
if (r >= 0.0) sum_pow2 += 1.0+$pow(r,2.3);
|
||||
if (r >= 0.0) sum_sqrt += 1.0+$sqrt(r);
|
||||
|
||||
`ifndef VERILATOR
|
||||
if (r>=-1.0 && r<=1.0) sum_acos += 1.0+$acos (r);
|
||||
if (r>=1.0) sum_acosh += 1.0+$acosh(r);
|
||||
if (r>=-1.0 && r<=1.0) sum_asin += 1.0+$asin (r);
|
||||
sum_asinh += 1.0+$asinh(r);
|
||||
sum_atan += 1.0+$atan (r);
|
||||
if (r>=-1.0 && r<=1.0) sum_atan2 += 1.0+$atan2(r,2.3);
|
||||
if (r>=-1.0 && r<=1.0) sum_atanh += 1.0+$atanh(r);
|
||||
sum_cos += 1.0+$cos (r);
|
||||
sum_cosh += 1.0+$cosh (r);
|
||||
sum_hypot += 1.0+$hypot(r,2.3);
|
||||
sum_sin += 1.0+$sin (r);
|
||||
sum_sinh += 1.0+$sinh (r);
|
||||
sum_tan += 1.0+$tan (r);
|
||||
sum_tanh += 1.0+$tanh (r);
|
||||
`endif
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
check (`__LINE__, sum_ceil, 85);
|
||||
check (`__LINE__, sum_exp, 608.06652950);
|
||||
check (`__LINE__, sum_floor, 4);
|
||||
check (`__LINE__, sum_ln, 55.830941633);
|
||||
check (`__LINE__, sum_log10, 46.309585076);
|
||||
check (`__LINE__, sum_pow1, 410.98798177);
|
||||
check (`__LINE__, sum_pow2, 321.94765689);
|
||||
check (`__LINE__, sum_sqrt, 92.269677253);
|
||||
`ifndef VERILATOR
|
||||
check (`__LINE__, sum_acos, 53.986722862);
|
||||
check (`__LINE__, sum_acosh, 72.685208498);
|
||||
check (`__LINE__, sum_asin, 21);
|
||||
check (`__LINE__, sum_asinh, 67.034973416);
|
||||
check (`__LINE__, sum_atan, 75.511045389);
|
||||
check (`__LINE__, sum_atan2, 21);
|
||||
check (`__LINE__, sum_atanh, 0);
|
||||
check (`__LINE__, sum_cos, 72.042023124);
|
||||
check (`__LINE__, sum_cosh, 1054.0178222);
|
||||
check (`__LINE__, sum_hypot, 388.92858406);
|
||||
check (`__LINE__, sum_sin, 98.264184989);
|
||||
check (`__LINE__, sum_sinh, 0);
|
||||
check (`__LINE__, sum_tan, 1.7007946043);
|
||||
check (`__LINE__, sum_tanh, 79.003199681);
|
||||
`endif
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user