`begin_keywords "1364-2005" /* * This is a general recreation of the VHDL ieee.math_real package. */ // Constants for use below and for general reference // TODO: Bring it out to 12 (or more???) places beyond the decimal? `define MATH_E 2.7182818284 `define MATH_1_OVER_E 0.3678794411 `define MATH_PI 3.1415926536 `define MATH_2_PI 6.2831853071 `define MATH_1_OVER_PI 0.3183098861 `define MATH_PI_OVER_2 1.5707963267 `define MATH_PI_OVER_3 1.0471975511 `define MATH_PI_OVER_4 0.7853981633 `define MATH_3_PI_OVER_2 4.7123889803 `define MATH_LOG_OF_2 0.6931471805 `define MATH_LOG_OF_10 2.3025850929 `define MATH_LOG2_OF_E 1.4426950408 `define MATH_LOG10_OF_E 0.4342944819 `define MATH_SQRT_2 1.4142135623 `define MATH_1_OVER_SQRT_2 0.7071067811 `define MATH_SQRT_PI 1.7724538509 `define MATH_DEG_TO_RAD 0.0174532925 `define MATH_RAD_TO_DEG 57.2957795130 // The number of iterations to do for the Taylor series approximations `define EXPLOG_ITERATIONS 50 `define COS_ITERATIONS 13 module math ; /* Conversion Routines */ // Return the sign of a particular number. function real sign ; input real x ; begin sign = x < 0.0 ? 1.0 : 0.0 ; end endfunction // Return the trunc function of a number function real trunc ; input real x ; begin trunc = x - mod(x,1.0) ; end endfunction // Return the ceiling function of a number. function real ceil ; input real x ; real retval ; begin retval = mod(x,1.0) ; if( retval != 0.0 && x > 0.0 ) retval = x+1.0 ; else retval = x ; ceil = trunc(retval) ; end endfunction // Return the floor function of a number function real floor ; input real x ; real retval ; begin retval = mod(x,1.0) ; if( retval != 0.0 && x < 0.0 ) retval = x - 1.0 ; else retval = x ; floor = trunc(retval) ; end endfunction // Return the round function of a number function real round ; input real x ; real retval ; begin retval = x > 0.0 ? x + 0.5 : x - 0.5 ; round = trunc(retval) ; end endfunction // Return the fractional remainder of (x mod m) function real mod ; input real x ; input real m ; real retval ; begin retval = x ; if( retval > m ) begin while( retval > m ) begin retval = retval - m ; end end else begin while( retval < -m ) begin retval = retval + m ; end end mod = retval ; end endfunction // Return the max between two real numbers function real realmax ; input real x ; input real y ; begin realmax = x > y ? x : y ; end endfunction // Return the min between two real numbers function real realmin ; input real x ; input real y ; begin realmin = x > y ? y : x ; end endfunction /* Random Numbers */ // Generate Gaussian distributed variables function real gaussian ; input real mean ; input real var ; real u1, u2, v1, v2, s ; begin s = 1.0 ; while( s >= 1.0 ) begin // Two random numbers between 0 and 1 u1 = $random/pow(2.0,32) ; u2 = $random/pow(2.0,32) ; // Adjust to be between -1,1 v1 = 2.0*u1-1.0 ; v2 = 2.0*u2-1.0 ; // Polar mag squared s = v1*v1 + v2*v2 ; end gaussian = mean + sqrt(-2.0*log(s)/s) * v1 * sqrt(var) ; // gaussian2 = mean + sqrt(-2*log(s)/s)*v2 * sqrt(var) ; end endfunction /* Roots and Log Functions */ // Return the square root of a number function real sqrt ; input real x ; real retval ; begin // if( x == 0.0 ) retval = 0.0 ; // else retval = powr(x,0.5) ; // sqrt = retval ; sqrt = (x == 0.0) ? 0.0 : powr(x,0.5) ; end endfunction // Return the cube root of a number function real cbrt ; input real x ; real retval ; begin // if( x == 0.0 ) retval = 0.0 ; // else retval = powr(x,1.0/3.0) ; // cbrt = retval ; cbrt = (x == 0.0) ? 0.0 : powr(x,1.0/3.0) ; end endfunction // Return the absolute value of a real value function real abs ; input real x ; begin abs = (x > 0.0) ? x : -x ; end endfunction // Return a real value raised to an integer power function real pow ; input real b ; input integer x ; integer i ; integer absx ; real retval ; begin retval = 1.0 ; absx = abs(x) ; for( i = 0 ; i < absx ; i = i+1 ) begin retval = b*retval ; end pow = x < 0 ? (1.0/retval) : retval ; end endfunction // Return a real value raised to a real power function real powr ; input real b ; input real x ; begin powr = exp(x*log(b)) ; end endfunction // Return the evaluation of e^x where e is the natural logarithm base // NOTE: This is the Taylor series expansion of e^x function real exp ; input real x ; real retval ; integer i ; real nm1_fact ; real powm1 ; begin nm1_fact = 1.0 ; powm1 = 1.0 ; retval = 1.0 ; for( i = 1 ; i < `EXPLOG_ITERATIONS ; i = i + 1 ) begin powm1 = x*powm1 ; nm1_fact = nm1_fact * i ; retval = retval + powm1/nm1_fact ; end exp = retval ; end endfunction // Return the evaluation log(x) function real log ; input real x ; integer i ; real whole ; real xm1oxp1 ; real retval ; real newx ; begin retval = 0.0 ; whole = 0.0 ; newx = x ; while( newx > `MATH_E ) begin whole = whole + 1.0 ; newx = newx / `MATH_E ; end newx = x/pow(`MATH_E,whole) ; xm1oxp1 = (newx-1.0)/(newx+1.0) ; for( i = 0 ; i < `EXPLOG_ITERATIONS ; i = i + 1 ) begin retval = retval + pow(xm1oxp1,2*i+1)/(2.0*i+1.0) ; end log = whole+2.0*retval ; end endfunction // Return the evaluation ln(x) (same as log(x)) function real ln ; input real x ; begin ln = log(x) ; end endfunction // Return the evaluation log_2(x) function real log2 ; input real x ; begin log2 = log(x)/`MATH_LOG_OF_2 ; end endfunction function real log10 ; input real x ; begin log10 = log(x)/`MATH_LOG_OF_10 ; end endfunction function real log_base ; input real x ; input real b ; begin log_base = log(x)/log(b) ; end endfunction /* Trigonometric Functions */ // Internal function to reduce a value to be between [-pi:pi] function real reduce ; input real x ; real retval ; begin retval = x ; if( x > `MATH_PI ) begin while( retval >= `MATH_PI ) begin retval = retval - `MATH_PI ; end end else begin while( retval <= -`MATH_PI ) begin retval = retval + `MATH_PI ; end end reduce = retval ; end endfunction // Return the cos of a number in radians function real cos ; input real x ; integer i ; integer sign ; real newx ; real retval ; real xsqnm1 ; real twonm1fact ; begin newx = reduce(x) ; xsqnm1 = 1.0 ; twonm1fact = 1.0 ; retval = 1.0 ; for( i = 1 ; i < `COS_ITERATIONS ; i = i + 1 ) begin sign = -2*(i % 2)+1 ; xsqnm1 = xsqnm1*newx*newx ; twonm1fact = twonm1fact * (2.0*i) * (2.0*i-1.0) ; retval = retval + sign*(xsqnm1/twonm1fact) ; end cos = retval ; end endfunction // Return the sin of a number in radians function real sin ; input real x ; begin sin = cos(x - `MATH_PI_OVER_2) ; end endfunction // Return the tan of a number in radians function real tan ; input real x ; begin tan = sin(x) / cos(x) ; end endfunction // Return the arcsin in radians of a number function real arcsin ; input real x ; begin arcsin = 2.0*arctan(x/(1.0+sqrt(1.0-x*x))) ; end endfunction // Return the arccos in radians of a number function real arccos ; input real x ; begin arccos = `MATH_PI_OVER_2-arcsin(x) ; end endfunction // Return the arctan in radians of a number // TODO: Make sure this REALLY does work as it is supposed to! function real arctan ; input real x ; real retval ; real y ; real newx ; real twoiotwoip1 ; integer i ; integer mult ; begin retval = 1.0 ; twoiotwoip1 = 1.0 ; mult = 1 ; newx = abs(x) ; while( newx > 1.0 ) begin mult = mult*2 ; newx = newx/(1.0+sqrt(1.0+newx*newx)) ; end y = 1.0 ; for( i = 1 ; i < 2*`COS_ITERATIONS ; i = i + 1 ) begin y = y*((newx*newx)/(1+newx*newx)) ; twoiotwoip1 = twoiotwoip1 * (2.0*i)/(2.0*i+1.0) ; retval = retval + twoiotwoip1*y ; end retval = retval * (newx/(1+newx*newx)) ; retval = retval * mult ; arctan = (x > 0.0) ? retval : -retval ; end endfunction // Return the arctan in radians of a ratio x/y // TODO: Test to make sure this works as it is supposed to! function real arctan_xy ; input real x ; input real y ; real retval ; begin retval = 0.0 ; if( x < 0.0 ) retval = `MATH_PI - arctan(-abs(y)/x) ; else if( x > 0.0 ) retval = arctan(abs(y)/x) ; else if( x == 0.0 ) retval = `MATH_PI_OVER_2 ; arctan_xy = (y < 0.0) ? -retval : retval ; end endfunction /* Hyperbolic Functions */ // Return the sinh of a number function real sinh ; input real x ; begin sinh = (exp(x) - exp(-x))/2.0 ; end endfunction // Return the cosh of a number function real cosh ; input real x ; begin cosh = (exp(x) + exp(-x))/2.0 ; end endfunction // Return the tanh of a number function real tanh ; input real x ; real e2x ; begin e2x = exp(2.0*x) ; tanh = (e2x+1.0)/(e2x-1.0) ; end endfunction // Return the arcsinh of a number function real arcsinh ; input real x ; begin arcsinh = log(x+sqrt(x*x+1.0)) ; end endfunction // Return the arccosh of a number function real arccosh ; input real x ; begin arccosh = ln(x+sqrt(x*x-1.0)) ; end endfunction // Return the arctanh of a number function real arctanh ; input real x ; begin arctanh = 0.5*ln((1.0+x)/(1.0-x)) ; end endfunction initial begin $display( "cos(MATH_PI_OVER_3): %f", cos(`MATH_PI_OVER_3) ) ; $display( "sin(MATH_PI_OVER_3): %f", sin(`MATH_PI_OVER_3) ) ; $display( "sign(-10): %f", sign(-10) ) ; $display( "realmax(MATH_PI,MATH_E): %f", realmax(`MATH_PI,`MATH_E) ) ; $display( "realmin(MATH_PI,MATH_E): %f", realmin(`MATH_PI,`MATH_E) ) ; $display( "mod(MATH_PI,MATH_E): %f", mod(`MATH_PI,`MATH_E) ) ; $display( "ceil(-MATH_PI): %f", ceil(-`MATH_PI) ) ; $display( "ceil(4.0): %f", ceil(4.0) ) ; $display( "ceil(3.99999999999999): %f", ceil(3.99999999999999) ) ; $display( "pow(MATH_PI,2): %f", pow(`MATH_PI,2) ) ; $display( "gaussian(1.0,1.0): %f", gaussian(1.0,1.0) ) ; $display( "round(MATH_PI): %f", round(`MATH_PI) ) ; $display( "trunc(-MATH_PI): %f", trunc(-`MATH_PI) ) ; $display( "ceil(-MATH_PI): %f", ceil(-`MATH_PI) ) ; $display( "floor(MATH_PI): %f", floor(`MATH_PI) ) ; $display( "round(e): %f", round(`MATH_E)) ; $display( "ceil(-e): %f", ceil(-`MATH_E)) ; $display( "exp(MATH_PI): %f", exp(`MATH_PI) ) ; $display( "log2(MATH_PI): %f", log2(`MATH_PI) ) ; $display( "log_base(pow(2,32),2): %f", log_base(pow(2,32),2) ) ; $display( "ln(0.1): %f", log(0.1) ) ; $display( "cbrt(7): %f", cbrt(7) ) ; $display( "cos(%s): %f", ``MATH_2_PI, cos(20*`MATH_2_PI) ) ; $display( "sin(-%s): %f", ``MATH_2_PI, sin(-50*`MATH_2_PI) ) ; $display( "sinh(%s): %f", ``MATH_E, sinh(`MATH_E) ) ; $display( "cosh(%s): %f", ``MATH_2_PI, cosh(`MATH_2_PI) ) ; $display( "arctan_xy(-4,3): %f", arctan_xy(-4,3) ) ; $display( "arctan(MATH_PI): %f", arctan(`MATH_PI) ) ; $display( "arctan(-MATH_E/2): %f", arctan(-`MATH_E/2) ) ; $display( "arctan(MATH_PI_OVER_2): %f", arctan(`MATH_PI_OVER_2) ) ; $display( "arctan(1/7) = %f", arctan(1.0/7.0) ) ; $display( "arctan(3/79) = %f", arctan(3.0/79.0) ) ; $display( "pi/4 ?= %f", 5*arctan(1.0/7.0)+2*arctan(3.0/79.0) ) ; $display( "arcsin(1.0): %f", arcsin(1.0) ) ; $display( "cos(pi/2): %f", cos(`MATH_PI_OVER_2)) ; $display( "arccos(cos(pi/2)): %f", arccos(cos(`MATH_PI_OVER_2)) ) ; end endmodule `end_keywords