summaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/models/math_real.v
blob: d88f72669697a0a3fc64a49be5c2d971594d2b57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
//
// Copyright 2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

/*
 * This is a general recreation of the VHDL ieee.math_real package.
 */
 
module math_real ;
   // Constants for use below and for general reference
   // TODO: Bring it out to 12 (or more???) places beyond the decimal?
   localparam MATH_E            =  2.7182818284;
   localparam MATH_1_OVER_E     =  0.3678794411;
   localparam MATH_PI           =  3.1415926536;
   localparam MATH_2_PI         =  6.2831853071;
   localparam MATH_1_OVER_PI    =  0.3183098861;
   localparam MATH_PI_OVER_2    =  1.5707963267;
   localparam MATH_PI_OVER_3    =  1.0471975511;
   localparam MATH_PI_OVER_4    =  0.7853981633;
   localparam MATH_3_PI_OVER_2  =  4.7123889803;
   localparam MATH_LOG_OF_2     =  0.6931471805;
   localparam MATH_LOG_OF_10    =  2.3025850929;
   localparam MATH_LOG2_OF_E    =  1.4426950408;
   localparam MATH_LOG10_OF_E   =  0.4342944819;
   localparam MATH_SQRT_2       =  1.4142135623;
   localparam MATH_1_OVER_SQRT_2=  0.7071067811;
   localparam MATH_SQRT_PI      =  1.7724538509;
   localparam MATH_DEG_TO_RAD   =  0.0174532925;
   localparam MATH_RAD_TO_DEG   =  57.2957795130;

   // The number of iterations to do for the Taylor series approximations
   localparam EXPLOG_ITERATIONS =  19;
   localparam COS_ITERATIONS    =  8;
   
   /* 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/4294967296.0 + 0.5 ;
            u2 = $random/4294967296.0 + 0.5 ;
            // Adjust to be between -1,1
            v1 = 2*u1-1.0 ;
            v2 = 2*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
         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
         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 absx ;
      real retval ;
      begin
         retval = 1.0 ;
         absx = abs(x) ;
         repeat(absx) 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
         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 ;
         while( abs(retval) > MATH_PI ) begin
            retval = retval > MATH_PI ? 
                     (retval - MATH_2_PI) : 
                     (retval + MATH_2_PI) ;
         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(MATH_2_PI): %f", cos(20*MATH_2_PI) ) ;
    $display( "sin(-MATH_2_PI): %f", sin(-50*MATH_2_PI) ) ;
    $display( "sinh(MATH_E): %f", sinh(MATH_E) ) ;
    $display( "cosh(MATH_2_PI): %f", 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)) ) ;
    $display( "cos(0): %f", cos(0) ) ;
    $display( "cos(MATH_PI_OVER_4): %f", cos(MATH_PI_OVER_4) ) ;
    $display( "cos(MATH_PI_OVER_2): %f", cos(MATH_PI_OVER_2) ) ;
    $display( "cos(3*MATH_PI_OVER_4): %f", cos(3*MATH_PI_OVER_4) ) ;
    $display( "cos(MATH_PI): %f", cos(MATH_PI) ) ;
    $display( "cos(5*MATH_PI_OVER_4): %f", cos(5*MATH_PI_OVER_4) ) ;
    $display( "cos(6*MATH_PI_OVER_4): %f", cos(6*MATH_PI_OVER_4) ) ;
    $display( "cos(7*MATH_PI_OVER_4): %f", cos(7*MATH_PI_OVER_4) ) ;
    $display( "cos(8*MATH_PI_OVER_4): %f", cos(8*MATH_PI_OVER_4) ) ;
    end*/
   
endmodule