~ubuntu-branches/debian/sid/freehdl/sid

« back to all changes in this revision

Viewing changes to ieee/math_real.vhdl

  • Committer: Bazaar Package Importer
  • Author(s): José L. Redrejo Rodríguez
  • Date: 2007-03-17 11:53:16 UTC
  • Revision ID: james.westby@ubuntu.com-20070317115316-4dar2jcct6hz0f6f
Tags: upstream-0.0.4
Import upstream version 0.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
------------------------------------------------------------------------
 
2
--
 
3
-- This source file may be used and distributed without restriction.
 
4
-- No declarations or definitions shall be added to this package. 
 
5
-- This package cannot be sold or distributed for profit.
 
6
--
 
7
--   ****************************************************************
 
8
--   *                                                              *
 
9
--   *                      W A R N I N G                           *
 
10
--   *                                                              *
 
11
--   *   This DRAFT version IS NOT endorsed or approved by IEEE     *
 
12
--   *                                                              *
 
13
--   ****************************************************************
 
14
--
 
15
-- Title:    PACKAGE MATH_REAL
 
16
--
 
17
-- Library:  This package shall be compiled into a library 
 
18
--           symbolically named IEEE.
 
19
--
 
20
-- Purpose:  VHDL declarations for mathematical package MATH_REAL
 
21
--           which contains common real constants, common real
 
22
--           functions, and real trascendental functions.
 
23
--
 
24
-- Author:   IEEE VHDL Math Package Study Group 
 
25
--
 
26
-- Notes:
 
27
--      The package body shall be considered the formal definition of 
 
28
--      the semantics of this package. Tool developers may choose to implement 
 
29
--      the package body in the most efficient manner available to them.
 
30
--
 
31
-- History:
 
32
--      Version 0.1  (Strawman) Jose A. Torres  6/22/92
 
33
--      Version 0.2             Jose A. Torres  1/15/93
 
34
--      Version 0.3             Jose A. Torres  4/13/93
 
35
--      Version 0.4             Jose A. Torres  4/19/93
 
36
--      Version 0.5             Jose A. Torres  4/20/93 Added RANDOM()
 
37
--      Version 0.6             Jose A. Torres  4/23/93 Renamed RANDOM as
 
38
--                                                      UNIFORM.  Modified
 
39
--                                                      rights banner.
 
40
--      Version 0.7             Jose A. Torres  5/28/93 Rev up for compatibility
 
41
--                                                      with package body.
 
42
-------------------------------------------------------------
 
43
Library IEEE;
 
44
 
 
45
Package MATH_REAL is
 
46
 
 
47
    -- 
 
48
    -- commonly used constants
 
49
    --
 
50
    constant  MATH_E :   real := 2.71828_18284_59045_23536;  
 
51
                                                  -- value of e
 
52
    constant  MATH_1_E:  real := 0.36787_94411_71442_32160;
 
53
                                                  -- value of 1/e
 
54
    constant  MATH_PI :  real := 3.14159_26535_89793_23846;  
 
55
                                                  -- value of pi
 
56
    constant  MATH_1_PI :  real := 0.31830_98861_83790_67154;  
 
57
                                                  -- value of 1/pi
 
58
    constant  MATH_LOG_OF_2:  real := 0.69314_71805_59945_30942;
 
59
                                                  -- natural log of 2
 
60
    constant  MATH_LOG_OF_10: real := 2.30258_50929_94045_68402;
 
61
                                                  -- natural log of10
 
62
    constant  MATH_LOG2_OF_E:  real := 1.44269_50408_88963_4074;
 
63
                                                  -- log base 2 of e
 
64
    constant  MATH_LOG10_OF_E: real := 0.43429_44819_03251_82765;
 
65
                                                  -- log base 10 of e
 
66
    constant  MATH_SQRT2: real := 1.41421_35623_73095_04880; 
 
67
                                                  -- sqrt of 2
 
68
    constant  MATH_SQRT1_2: real := 0.70710_67811_86547_52440; 
 
69
                                                  -- sqrt of 1/2
 
70
    constant  MATH_SQRT_PI: real := 1.77245_38509_05516_02730; 
 
71
                                                  -- sqrt of pi
 
72
    constant  MATH_DEG_TO_RAD: real := 0.01745_32925_19943_29577;
 
73
                                -- conversion factor from degree to radian
 
74
    constant  MATH_RAD_TO_DEG: real := 57.29577_95130_82320_87685;
 
75
                                -- conversion factor from radian to degree
 
76
 
 
77
    --
 
78
    -- attribute for functions whose implementation is foreign (C native)
 
79
    --
 
80
    attribute FOREIGN : string; -- predefined attribute in VHDL-1992
 
81
 
 
82
    --
 
83
    -- function declarations
 
84
    --
 
85
    function SIGN (X: real ) return real;
 
86
        -- returns 1.0 if X > 0.0; 0.0 if X == 0.0; -1.0 if X < 0.0
 
87
 
 
88
    function CEIL (X : real ) return real;
 
89
        -- returns smallest integer value (as real) not less than X
 
90
 
 
91
    function FLOOR (X : real ) return real;
 
92
        -- returns largest integer value (as real) not greater than X
 
93
 
 
94
    function ROUND (X : real ) return real;
 
95
        -- returns integer FLOOR(X + 0.5) if X > 0;
 
96
        -- return integer CEIL(X - 0.5) if X < 0
 
97
    
 
98
    function FMAX (X, Y : real ) return real;
 
99
        -- returns the algebraically larger of X and Y
 
100
 
 
101
    function FMIN (X, Y : real ) return real;
 
102
        -- returns the algebraically smaller of X and Y
 
103
 
 
104
    procedure UNIFORM (variable Seed1,Seed2:inout integer; variable X:out real);
 
105
        -- returns a pseudo-random number with uniform distribution in the 
 
106
        -- interval (0.0, 1.0).
 
107
        -- Before the first call to UNIFORM, the seed values (Seed1, Seed2) must
 
108
        -- be initialized to values in the range [1, 2147483562] and 
 
109
        -- [1, 2147483398] respectively.  The seed values are modified after 
 
110
        -- each call to UNIFORM.
 
111
        -- This random number generator is portable for 32-bit computers, and
 
112
        -- it has period ~2.30584*(10**18) for each set of seed values.
 
113
        --
 
114
        -- For VHDL-1992, the seeds will be global variables, functions to 
 
115
        -- initialize their values (INIT_SEED) will be provided, and the UNIFORM
 
116
        -- procedure call will be modified accordingly.  
 
117
 
 
118
    function SRAND (seed: in integer ) return integer;
 
119
        --
 
120
        -- sets value of seed for sequence of 
 
121
        -- pseudo-random numbers.   
 
122
        -- It uses the foreign native C function srand().
 
123
    attribute FOREIGN of SRAND : function is "C_NATIVE"; 
 
124
 
 
125
    function RAND return integer;               
 
126
        --
 
127
        -- returns an integer pseudo-random number with uniform distribution.
 
128
        -- It uses the foreign native C function rand(). 
 
129
        -- Seed for the sequence is initialized with the
 
130
        -- SRAND() function and value of the seed is changed every
 
131
        -- time SRAND() is called,  but it is not visible.
 
132
        -- The range of generated values is platform dependent.
 
133
    attribute FOREIGN of RAND : function is "C_NATIVE"; 
 
134
 
 
135
    function GET_RAND_MAX  return integer;              
 
136
        --
 
137
        -- returns the upper bound of the range of the
 
138
        -- pseudo-random numbers generated by  RAND().
 
139
        -- The support for this function is platform dependent, and
 
140
        -- it uses foreign native C functions or constants.
 
141
        -- It may not be available in some platforms.
 
142
        -- Note: the value of (RAND() / GET_RAND_MAX()) is a
 
143
        --       pseudo-random number distributed between 0 & 1.
 
144
    attribute FOREIGN of GET_RAND_MAX : function is "C_NATIVE"; 
 
145
 
 
146
    function SQRT (X : real ) return real;
 
147
        -- returns square root of X;  X >= 0
 
148
 
 
149
    function CBRT (X : real ) return real;
 
150
        -- returns cube root of X
 
151
 
 
152
    function "**" (X : integer; Y : real) return real;
 
153
        -- returns Y power of X ==>  X**Y;
 
154
        -- error if X = 0 and Y <= 0.0
 
155
        -- error if X < 0 and Y does not have an integer value
 
156
 
 
157
    function "**" (X : real; Y : real) return real;
 
158
        -- returns Y power of X ==>  X**Y;
 
159
        -- error if X = 0.0 and Y <= 0.0
 
160
        -- error if X < 0.0 and Y does not have an integer value
 
161
 
 
162
    function EXP  (X : real ) return real;
 
163
        -- returns e**X; where e = MATH_E
 
164
 
 
165
    function LOG (X : real ) return real;
 
166
        -- returns natural logarithm of X; X > 0
 
167
 
 
168
    function LOG (BASE: positive; X : real) return real;
 
169
        -- returns logarithm base BASE of X; X > 0
 
170
 
 
171
    function  SIN (X : real ) return real;
 
172
        -- returns sin X; X in radians
 
173
 
 
174
    function  COS ( X : real ) return real;
 
175
        -- returns cos X; X in radians
 
176
 
 
177
    function  TAN (X : real ) return real;
 
178
        -- returns tan X; X in radians
 
179
        -- X /= ((2k+1) * PI/2), where k is an integer
 
180
 
 
181
    function  ASIN (X : real ) return real; 
 
182
        -- returns  -PI/2 < asin X < PI/2; | X | <= 1
 
183
 
 
184
    function  ACOS (X : real ) return real;
 
185
        -- returns  0 < acos X < PI; | X | <= 1
 
186
 
 
187
    function  ATAN (X : real) return real;
 
188
        -- returns  -PI/2 < atan X < PI/2
 
189
 
 
190
    function  ATAN2 (X : real; Y : real) return real;
 
191
        -- returns  atan (X/Y); -PI < atan2(X,Y) < PI; Y /= 0.0
 
192
 
 
193
    function SINH (X : real) return real;
 
194
        -- hyperbolic sine; returns (e**X - e**(-X))/2
 
195
 
 
196
    function  COSH (X : real) return real;
 
197
        -- hyperbolic cosine; returns (e**X + e**(-X))/2
 
198
 
 
199
    function  TANH (X : real) return real;
 
200
        -- hyperbolic tangent; -- returns (e**X - e**(-X))/(e**X + e**(-X))
 
201
    
 
202
    function ASINH (X : real) return real;
 
203
        -- returns ln( X + sqrt( X**2 + 1))
 
204
 
 
205
    function ACOSH (X : real) return real;
 
206
        -- returns ln( X + sqrt( X**2 - 1));   X >= 1
 
207
 
 
208
    function ATANH (X : real) return real;
 
209
        -- returns (ln( (1 + X)/(1 - X)))/2 ; | X | < 1
 
210
 
 
211
end  MATH_REAL;
 
212
 
 
213
 
 
214
 
 
215
--------------------------------------------------------------- 
 
216
--
 
217
-- This source file may be used and distributed without restriction.
 
218
-- No declarations or definitions shall be included in this package.
 
219
-- This package cannot be sold or distributed for profit. 
 
220
--
 
221
--   ****************************************************************
 
222
--   *                                                              *
 
223
--   *                      W A R N I N G                           *
 
224
--   *                                                              *
 
225
--   *   This DRAFT version IS NOT endorsed or approved by IEEE     *
 
226
--   *                                                              *
 
227
--   ****************************************************************
 
228
--
 
229
-- Title:    PACKAGE MATH_COMPLEX
 
230
--
 
231
-- Purpose:  VHDL declarations for mathematical package MATH_COMPLEX
 
232
--           which contains common complex constants and basic complex
 
233
--           functions and operations.
 
234
--
 
235
-- Author:   IEEE VHDL Math Package Study Group 
 
236
--
 
237
-- Notes:     
 
238
--      The package body uses package IEEE.MATH_REAL
 
239
--
 
240
--      The package body shall be considered the formal definition of 
 
241
--      the semantics of this package. Tool developers may choose to implement 
 
242
--      the package body in the most efficient manner available to them.
 
243
--
 
244
-- History:
 
245
--      Version 0.1  (Strawman) Jose A. Torres  6/22/92
 
246
--      Version 0.2             Jose A. Torres  1/15/93
 
247
--      Version 0.3             Jose A. Torres  4/13/93
 
248
--      Version 0.4             Jose A. Torres  4/19/93
 
249
--      Version 0.5             Jose A. Torres  4/20/93
 
250
--      Version 0.6             Jose A. Torres  4/23/93  Added unary minus
 
251
--                                                       and CONJ for polar
 
252
--      Version 0.7             Jose A. Torres  5/28/93 Rev up for compatibility
 
253
--                                                      with package body.
 
254
-------------------------------------------------------------
 
255
Library IEEE;
 
256
 
 
257
Package MATH_COMPLEX is
 
258
 
 
259
 
 
260
    type COMPLEX        is record RE, IM: real; end record;
 
261
    type COMPLEX_VECTOR is array (integer range <>) of COMPLEX;
 
262
    type COMPLEX_POLAR  is record MAG: real; ARG: real; end record;
 
263
 
 
264
    constant  CBASE_1: complex := COMPLEX'(1.0, 0.0);
 
265
    constant  CBASE_j: complex := COMPLEX'(0.0, 1.0);
 
266
    constant  CZERO: complex := COMPLEX'(0.0, 0.0);
 
267
 
 
268
    function CABS(Z: in complex ) return real;
 
269
        -- returns absolute value (magnitude) of Z
 
270
 
 
271
    function CARG(Z: in complex ) return real;
 
272
        -- returns argument (angle) in radians of a complex number
 
273
 
 
274
    function CMPLX(X: in real;  Y: in real:= 0.0 ) return complex;
 
275
        -- returns complex number X + iY
 
276
 
 
277
    function "-" (Z: in complex ) return complex;
 
278
        -- unary minus
 
279
 
 
280
    function "-" (Z: in complex_polar ) return complex_polar;
 
281
        -- unary minus
 
282
 
 
283
    function CONJ (Z: in complex) return complex;
 
284
        -- returns complex conjugate
 
285
 
 
286
    function CONJ (Z: in complex_polar) return complex_polar;
 
287
        -- returns complex conjugate
 
288
 
 
289
    function CSQRT(Z: in complex ) return complex_vector;
 
290
        -- returns square root of Z; 2 values
 
291
 
 
292
    function CEXP(Z: in complex ) return complex;
 
293
        -- returns e**Z
 
294
 
 
295
    function COMPLEX_TO_POLAR(Z: in complex ) return complex_polar;
 
296
        -- converts complex to complex_polar
 
297
 
 
298
    function POLAR_TO_COMPLEX(Z: in complex_polar ) return complex;
 
299
        -- converts complex_polar to complex
 
300
 
 
301
                
 
302
    -- arithmetic operators
 
303
 
 
304
    function "+" ( L: in complex;  R: in complex ) return complex;
 
305
    function "+" ( L: in complex_polar; R: in complex_polar) return complex;
 
306
    function "+" ( L: in complex_polar; R: in complex ) return complex;
 
307
    function "+" ( L: in complex;  R: in complex_polar) return complex;
 
308
    function "+" ( L: in real;     R: in complex ) return complex;
 
309
    function "+" ( L: in complex;  R: in real )    return complex;
 
310
    function "+" ( L: in real;  R: in complex_polar) return complex;
 
311
    function "+" ( L: in complex_polar;  R: in real) return complex;
 
312
 
 
313
    function "-" ( L: in complex;  R: in complex ) return complex;
 
314
    function "-" ( L: in complex_polar; R: in complex_polar) return complex;
 
315
    function "-" ( L: in complex_polar; R: in complex ) return complex;
 
316
    function "-" ( L: in complex;  R: in complex_polar) return complex;
 
317
    function "-" ( L: in real;     R: in complex ) return complex;
 
318
    function "-" ( L: in complex;  R: in real )    return complex;
 
319
    function "-" ( L: in real;  R: in complex_polar) return complex;
 
320
    function "-" ( L: in complex_polar;  R: in real) return complex;
 
321
 
 
322
    function "*" ( L: in complex;  R: in complex ) return complex;
 
323
    function "*" ( L: in complex_polar; R: in complex_polar) return complex;
 
324
    function "*" ( L: in complex_polar; R: in complex ) return complex;
 
325
    function "*" ( L: in complex;  R: in complex_polar) return complex;
 
326
    function "*" ( L: in real;     R: in complex ) return complex;
 
327
    function "*" ( L: in complex;  R: in real )    return complex;
 
328
    function "*" ( L: in real;  R: in complex_polar) return complex;
 
329
    function "*" ( L: in complex_polar;  R: in real) return complex;
 
330
 
 
331
 
 
332
    function "/" ( L: in complex;  R: in complex ) return complex;
 
333
    function "/" ( L: in complex_polar; R: in complex_polar) return complex;
 
334
    function "/" ( L: in complex_polar; R: in complex ) return complex;
 
335
    function "/" ( L: in complex;  R: in complex_polar) return complex;
 
336
    function "/" ( L: in real;     R: in complex ) return complex;
 
337
    function "/" ( L: in complex;  R: in real )    return complex;
 
338
    function "/" ( L: in real;  R: in complex_polar) return complex;
 
339
    function "/" ( L: in complex_polar;  R: in real) return complex;
 
340
end  MATH_COMPLEX;
 
341
 
 
342
 
 
343
 
 
344
--------------------------------------------------------------- 
 
345
--
 
346
-- This source file may be used and distributed without restriction.
 
347
-- No declarations or definitions shall be added to this package.
 
348
-- This package cannot be sold or distributed for profit. 
 
349
--
 
350
--   ****************************************************************
 
351
--   *                                                              *
 
352
--   *                      W A R N I N G                           *
 
353
--   *                                                              *
 
354
--   *   This DRAFT version IS NOT endorsed or approved by IEEE     *
 
355
--   *                                                              *
 
356
--   ****************************************************************
 
357
--
 
358
-- Title:    PACKAGE BODY MATH_REAL
 
359
--
 
360
-- Library:  This package shall be compiled into a library 
 
361
--           symbolically named IEEE.
 
362
--
 
363
-- Purpose:  VHDL declarations for mathematical package MATH_REAL
 
364
--           which contains common real constants, common real
 
365
--           functions, and real trascendental functions.
 
366
--
 
367
-- Author:   IEEE VHDL Math Package Study Group 
 
368
--
 
369
-- Notes:
 
370
--      The package body shall be considered the formal definition of 
 
371
--      the semantics of this package. Tool developers may choose to implement 
 
372
--      the package body in the most efficient manner available to them.
 
373
--
 
374
--      Source code and algorithms for this package body comes from the 
 
375
--      following sources: 
 
376
--              IEEE VHDL Math Package Study Group participants,
 
377
--              U. of Mississippi, Mentor Graphics, Synopsys,
 
378
--              Viewlogic/Vantage, Communications of the ACM (June 1988, Vol
 
379
--              31, Number 6, pp. 747, Pierre L'Ecuyer, Efficient and Portable
 
380
--              Random Number Generators), Handbook of Mathematical Functions
 
381
--              by Milton Abramowitz and Irene A. Stegun (Dover).
 
382
--
 
383
-- History:
 
384
--      Version 0.1     Jose A. Torres  4/23/93 First draft
 
385
--      Version 0.2     Jose A. Torres  5/28/93 Fixed potentially illegal code
 
386
-------------------------------------------------------------
 
387
Library IEEE;
 
388
 
 
389
Package body MATH_REAL is
 
390
 
 
391
    -- 
 
392
    -- some constants for use in the package body only
 
393
    --
 
394
    constant  Q_PI :   real := MATH_PI/4.0;
 
395
    constant  HALF_PI :   real := MATH_PI/2.0;
 
396
    constant  TWO_PI :   real := MATH_PI*2.0;
 
397
    constant  MAX_ITER:  integer := 27; -- max precision factor for cordic
 
398
 
 
399
    --
 
400
    -- some type declarations for cordic operations
 
401
    -- 
 
402
    
 
403
    constant KC : REAL := 6.0725293500888142e-01; -- constant for cordic
 
404
    type REAL_VECTOR is array (NATURAL range <>) of REAL; 
 
405
    type NATURAL_VECTOR is array (NATURAL range <>) of NATURAL; 
 
406
    subtype REAL_VECTOR_N is REAL_VECTOR (0 to max_iter);
 
407
    subtype REAL_ARR_2 is REAL_VECTOR (0 to 1); 
 
408
    subtype REAL_ARR_3 is REAL_VECTOR (0 to 2); 
 
409
    subtype QUADRANT is INTEGER range 0 to 3; 
 
410
    type CORDIC_MODE_TYPE is (ROTATION, VECTORING); 
 
411
  
 
412
    --
 
413
    -- auxiliary functions for cordic algorithms
 
414
    --
 
415
    function POWER_OF_2_SERIES (d : NATURAL_VECTOR; initial_value : REAL;
 
416
                number_of_values : NATURAL) return REAL_VECTOR is 
 
417
 
 
418
      variable v : REAL_VECTOR (0 to number_of_values);  
 
419
      variable temp : REAL := initial_value; 
 
420
      variable flag : boolean := true; 
 
421
    begin
 
422
      for i in 0 to number_of_values loop 
 
423
         v(i) := temp; 
 
424
         for p in d'range loop 
 
425
            if i = d(p) then 
 
426
               flag := false;
 
427
            end if;                  
 
428
         end loop; 
 
429
         if flag then
 
430
            temp := temp/2.0;
 
431
         end if; 
 
432
         flag := true;
 
433
      end loop; 
 
434
      return v;
 
435
    end POWER_OF_2_SERIES; 
 
436
 
 
437
 
 
438
   constant two_at_minus : REAL_VECTOR := POWER_OF_2_SERIES(
 
439
                                               NATURAL_VECTOR'(100, 90),1.0,
 
440
                                                                  MAX_ITER);  
 
441
 
 
442
   constant epsilon : REAL_VECTOR_N := (
 
443
                                        7.8539816339744827e-01,
 
444
                                        4.6364760900080606e-01,
 
445
                                        2.4497866312686413e-01,
 
446
                                        1.2435499454676144e-01,
 
447
                                        6.2418809995957351e-02,
 
448
                                        3.1239833430268277e-02,
 
449
                                        1.5623728620476830e-02,
 
450
                                        7.8123410601011116e-03,
 
451
                                        3.9062301319669717e-03,
 
452
                                        1.9531225164788189e-03,
 
453
                                        9.7656218955931937e-04,
 
454
                                        4.8828121119489829e-04,
 
455
                                        2.4414062014936175e-04,
 
456
                                        1.2207031189367021e-04,
 
457
                                        6.1035156174208768e-05,
 
458
                                        3.0517578115526093e-05,
 
459
                                        1.5258789061315760e-05,
 
460
                                        7.6293945311019699e-06,
 
461
                                        3.8146972656064960e-06,
 
462
                                        1.9073486328101870e-06,
 
463
                                        9.5367431640596080e-07,
 
464
                                        4.7683715820308876e-07,
 
465
                                        2.3841857910155801e-07,
 
466
                                        1.1920928955078067e-07,
 
467
                                        5.9604644775390553e-08,
 
468
                                        2.9802322387695303e-08,
 
469
                                        1.4901161193847654e-08,
 
470
                                        7.4505805969238281e-09
 
471
                                       );
 
472
 
 
473
   function CORDIC ( x0 : REAL;  
 
474
                     y0 : REAL;  
 
475
                     z0 : REAL;  
 
476
                      n : NATURAL;                 --       precision factor 
 
477
            CORDIC_MODE : CORDIC_MODE_TYPE         --      rotation (z -> 0) 
 
478
                                                   --  or vectoring (y -> 0) 
 
479
                    ) return REAL_ARR_3 is 
 
480
     variable x : REAL := x0;
 
481
     variable y : REAL := y0;
 
482
     variable z : REAL := z0;
 
483
     variable x_temp : REAL; 
 
484
   begin
 
485
      if CORDIC_MODE = ROTATION then 
 
486
         for k in 0 to n loop 
 
487
            x_temp := x;
 
488
            if ( z >= 0.0) then
 
489
               x := x - y * two_at_minus(k);
 
490
               y := y + x_temp * two_at_minus(k); 
 
491
               z := z - epsilon(k);
 
492
            else 
 
493
               x := x + y * two_at_minus(k);
 
494
               y := y - x_temp * two_at_minus(k);
 
495
               z := z + epsilon(k);
 
496
            end if; 
 
497
         end loop;
 
498
      else 
 
499
         for k in 0 to n loop 
 
500
            x_temp := x;
 
501
            if ( y < 0.0) then
 
502
               x := x - y * two_at_minus(k);
 
503
               y := y + x_temp * two_at_minus(k); 
 
504
               z := z - epsilon(k);
 
505
            else 
 
506
               x := x + y * two_at_minus(k);
 
507
               y := y - x_temp * two_at_minus(k);
 
508
               z := z + epsilon(k);
 
509
            end if; 
 
510
         end loop;
 
511
      end if;
 
512
      return REAL_ARR_3'(x, y, z);
 
513
   end CORDIC;          
 
514
 
 
515
    --
 
516
    -- non-trascendental functions
 
517
    --
 
518
    function SIGN (X: real ) return real is
 
519
        -- returns 1.0 if X > 0.0; 0.0 if X == 0.0; -1.0 if X < 0.0
 
520
    begin
 
521
           if  ( X > 0.0 )  then
 
522
                return 1.0;
 
523
           elsif ( X < 0.0 )  then
 
524
                return -1.0;
 
525
           else
 
526
                return 0.0;
 
527
           end if;
 
528
    end SIGN; 
 
529
 
 
530
    function CEIL (X : real ) return real is
 
531
        -- returns smallest integer value (as real) not less than X
 
532
        -- No conversion to an integer type is expected, so truncate cannot 
 
533
        -- overflow for large arguments.
 
534
 
 
535
         variable large: real  := 1073741824.0;
 
536
         type long is range -1073741824 to 1073741824;
 
537
         -- 2**30 is longer than any single-precision mantissa
 
538
         variable rd: real;
 
539
   
 
540
      begin
 
541
         if abs( X) >= large then
 
542
            return X;
 
543
         else
 
544
            rd := real ( long( X));
 
545
            if X > 0.0 then
 
546
                if rd >= X then
 
547
                        return rd;
 
548
                else
 
549
                        return rd + 1.0;
 
550
                end if;
 
551
            elsif  X = 0.0  then
 
552
                        return 0.0;
 
553
            else
 
554
                if rd <= X then
 
555
                        return rd;
 
556
                else
 
557
                        return rd - 1.0;
 
558
                end if;
 
559
            end if;
 
560
         end if;
 
561
      end CEIL;
 
562
 
 
563
    function FLOOR (X : real ) return real is
 
564
        -- returns largest integer value (as real) not greater than X
 
565
        -- No conversion to an integer type is expected, so truncate 
 
566
        -- cannot overflow for large arguments.
 
567
        -- 
 
568
         variable large: real  := 1073741824.0;
 
569
         type long is range -1073741824 to 1073741824;
 
570
         -- 2**30 is longer than any single-precision mantissa
 
571
         variable rd: real;
 
572
   
 
573
      begin
 
574
         if abs( X ) >= large then
 
575
                return X;
 
576
         else
 
577
                rd := real ( long( X));
 
578
                if X > 0.0 then
 
579
                        if rd <= X then
 
580
                                return rd;
 
581
                        else
 
582
                                return rd - 1.0;
 
583
                        end if;
 
584
                elsif  X = 0.0  then
 
585
                        return 0.0;
 
586
                else
 
587
                        if rd >= X then
 
588
                                return rd;
 
589
                        else
 
590
                                return rd + 1.0;
 
591
                        end if;
 
592
                end if;
 
593
         end if;
 
594
      end FLOOR;
 
595
 
 
596
    function ROUND (X : real ) return real is
 
597
        -- returns integer FLOOR(X + 0.5) if X > 0;
 
598
        -- return integer CEIL(X - 0.5) if X < 0
 
599
    begin
 
600
           if  X > 0.0  then
 
601
                return FLOOR(X + 0.5);
 
602
           elsif  X < 0.0  then
 
603
                return CEIL( X - 0.5);
 
604
           else
 
605
                return 0.0;
 
606
           end if;
 
607
    end ROUND;
 
608
    
 
609
    function FMAX (X, Y : real ) return real is
 
610
        -- returns the algebraically larger of X and Y
 
611
    begin
 
612
        if X > Y then
 
613
           return X;
 
614
        else
 
615
           return Y;
 
616
        end if;
 
617
    end FMAX;
 
618
 
 
619
    function FMIN (X, Y : real ) return real is
 
620
        -- returns the algebraically smaller of X and Y
 
621
    begin
 
622
        if X < Y then
 
623
           return X;
 
624
        else
 
625
           return Y;
 
626
        end if;
 
627
    end FMIN;
 
628
 
 
629
    --
 
630
    -- Pseudo-random number generators
 
631
    --
 
632
 
 
633
    procedure UNIFORM(variable Seed1,Seed2:inout integer;variable X:out real) is
 
634
        -- returns a pseudo-random number with uniform distribution in the 
 
635
        -- interval (0.0, 1.0).
 
636
        -- Before the first call to UNIFORM, the seed values (Seed1, Seed2) must
 
637
        -- be initialized to values in the range [1, 2147483562] and 
 
638
        -- [1, 2147483398] respectively.  The seed values are modified after 
 
639
        -- each call to UNIFORM.
 
640
        -- This random number generator is portable for 32-bit computers, and
 
641
        -- it has period ~2.30584*(10**18) for each set of seed values.
 
642
        --
 
643
        -- For VHDL-1992, the seeds will be global variables, functions to 
 
644
        -- initialize their values (INIT_SEED) will be provided, and the UNIFORM
 
645
        -- procedure call will be modified accordingly.  
 
646
        
 
647
        variable z, k: integer;
 
648
        begin
 
649
        k := Seed1/53668;
 
650
        Seed1 := 40014 * (Seed1 - k * 53668) - k * 12211;
 
651
        
 
652
        if Seed1 < 0  then
 
653
                Seed1 := Seed1 + 2147483563;
 
654
        end if;
 
655
 
 
656
 
 
657
        k := Seed2/52774;
 
658
        Seed2 := 40692 * (Seed2 - k * 52774) - k * 3791;
 
659
        
 
660
        if Seed2 < 0  then
 
661
                Seed2 := Seed2 + 2147483399;
 
662
        end if;
 
663
 
 
664
        z := Seed1 - Seed2;
 
665
        if z < 1 then
 
666
                z := z + 2147483562;
 
667
        end if;
 
668
 
 
669
        X :=  REAL(Z)*4.656613e-10;
 
670
    end UNIFORM;
 
671
 
 
672
 
 
673
    function SRAND (seed: in integer ) return integer is
 
674
        --
 
675
        -- sets value of seed for sequence of 
 
676
        -- pseudo-random numbers.   
 
677
        -- Returns the value of the seed.
 
678
        -- It uses the foreign native C function srand().
 
679
    begin
 
680
    end SRAND;
 
681
 
 
682
    function RAND return integer is
 
683
        --
 
684
        -- returns an integer pseudo-random number with uniform distribution.
 
685
        -- It uses the foreign native C function rand(). 
 
686
        -- Seed for the sequence is initialized with the
 
687
        -- SRAND() function and value of the seed is changed every
 
688
        -- time SRAND() is called,  but it is not visible.
 
689
        -- The range of generated values is platform dependent.
 
690
    begin
 
691
    end RAND;
 
692
 
 
693
    function GET_RAND_MAX  return integer is
 
694
        --
 
695
        -- returns the upper bound of the range of the
 
696
        -- pseudo-random numbers generated by  RAND().
 
697
        -- The support for this function is platform dependent, and
 
698
        -- it uses foreign native C functions or constants.
 
699
        -- It may not be available in some platforms.
 
700
        -- Note: the value of (RAND / GET_RAND_MAX) is a
 
701
        --       pseudo-random number distributed between 0 & 1.
 
702
    begin
 
703
    end GET_RAND_MAX;
 
704
 
 
705
    --
 
706
    -- trascendental and trigonometric functions
 
707
    --
 
708
 
 
709
    function SQRT (X : real ) return real is
 
710
        -- returns square root of X;  X >= 0
 
711
        --
 
712
        -- Computes square root using the Newton-Raphson approximation:
 
713
        -- F(n+1) = 0.5*[F(n) + x/F(n)];
 
714
        --
 
715
 
 
716
        constant inival: real := 1.5;
 
717
        constant eps : real := 0.000001;
 
718
        constant relative_err : real := eps*X;
 
719
 
 
720
        variable oldval : real ;
 
721
        variable newval : real ;
 
722
 
 
723
    begin
 
724
        -- check validity of argument
 
725
        if ( X < 0.0 ) then
 
726
                assert false report "X < 0 in SQRT(X)" 
 
727
                        severity ERROR;
 
728
                return (0.0);
 
729
        end if;
 
730
 
 
731
        -- get the square root for special cases
 
732
        if X = 0.0 then
 
733
                return 0.0;
 
734
        else
 
735
                if ( X = 1.0 ) then
 
736
                        return 1.0; -- return exact value
 
737
                end if;
 
738
        end if;
 
739
 
 
740
        -- get the square root for general cases
 
741
        oldval := inival;
 
742
        newval := (X/oldval + oldval)/2.0;
 
743
 
 
744
        while ( abs(newval -oldval) > relative_err ) loop
 
745
                oldval := newval;
 
746
                newval := (X/oldval + oldval)/2.0;
 
747
        end loop;
 
748
 
 
749
        return newval;
 
750
    end SQRT;
 
751
 
 
752
    function CBRT (X : real ) return real is
 
753
        -- returns cube root of X
 
754
        -- Computes square root using the Newton-Raphson approximation:
 
755
        -- F(n+1) = (1/3)*[2*F(n) + x/F(n)**2];
 
756
        --
 
757
 
 
758
                constant inival: real := 1.5;
 
759
                constant eps : real := 0.000001;
 
760
                constant relative_err : real := eps*abs(X);
 
761
 
 
762
                variable xlocal : real := X;
 
763
                variable negative : boolean := X < 0.0;
 
764
                variable oldval : real ;
 
765
                variable newval : real ;
 
766
 
 
767
    begin 
 
768
                
 
769
                -- compute root for special cases
 
770
                if X = 0.0 then
 
771
                        return 0.0;
 
772
                elsif ( X = 1.0 ) then
 
773
                        return 1.0;
 
774
                else
 
775
                        if X = -1.0 then
 
776
                                return -1.0;
 
777
                        end if;
 
778
                end if;
 
779
 
 
780
                -- compute root for general cases
 
781
                if negative then
 
782
                        xlocal := -X;
 
783
                end if;
 
784
                
 
785
                oldval := inival;
 
786
                newval := (xlocal/(oldval*oldval) + 2.0*oldval)/3.0;
 
787
 
 
788
                while ( abs(newval -oldval) > relative_err ) loop
 
789
                        oldval := newval;
 
790
                        newval :=(xlocal/(oldval*oldval) + 2.0*oldval)/3.0;
 
791
                end loop;
 
792
 
 
793
                if negative then
 
794
                        newval := -newval;
 
795
                end if;
 
796
 
 
797
                return newval;
 
798
 
 
799
    end CBRT;
 
800
 
 
801
    function "**" (X : integer; Y : real) return real is
 
802
        -- returns Y power of X ==>  X**Y;
 
803
        -- error if X = 0 and Y <= 0.0
 
804
        -- error if X < 0 and Y does not have an integer value
 
805
    begin
 
806
        -- check validity of argument
 
807
        if ( X = 0  ) and ( Y <= 0.0 ) then
 
808
                assert false report "X = 0 and Y <= 0.0 in X**Y" 
 
809
                        severity ERROR;
 
810
                return (0.0);
 
811
        end if;
 
812
 
 
813
        if ( X < 0  ) and ( Y /= REAL(INTEGER(Y)) ) then
 
814
                assert false report "X < 0 and Y \= integer in X**Y" 
 
815
                        severity ERROR;
 
816
                return (0.0);
 
817
        end if;
 
818
 
 
819
        -- compute the result
 
820
        return EXP (Y * LOG (REAL(X)));
 
821
    end "**";
 
822
 
 
823
    function "**" (X : real; Y : real) return real is
 
824
        -- returns Y power of X ==>  X**Y;
 
825
        -- error if X = 0.0 and Y <= 0.0
 
826
        -- error if X < 0.0 and Y does not have an integer value
 
827
    begin
 
828
        -- check validity of argument
 
829
        if ( X = 0.0  ) and ( Y <= 0.0 ) then
 
830
                assert false report "X = 0.0 and Y <= 0.0 in X**Y" 
 
831
                        severity ERROR;
 
832
                return (0.0);
 
833
        end if;
 
834
 
 
835
        if ( X < 0.0  ) and ( Y /= REAL(INTEGER(Y)) ) then
 
836
                assert false report "X < 0.0 and Y \= integer in X**Y" 
 
837
                        severity ERROR;
 
838
                return (0.0);
 
839
        end if;
 
840
 
 
841
        -- compute the result
 
842
        return EXP (Y * LOG (X));
 
843
    end "**";
 
844
 
 
845
    function EXP  (X : real ) return real is
 
846
        -- returns e**X; where e = MATH_E
 
847
        --
 
848
        -- This function computes the exponential using the following series:
 
849
        --    exp(x) = 1 + x + x**2/2! + x**3/3! + ... ; x > 0
 
850
        --
 
851
        constant eps : real := 0.000001;        -- precision criteria
 
852
 
 
853
        variable reciprocal: boolean := x < 0.0;-- check sign of argument
 
854
        variable xlocal : real := abs(x);       -- use positive value
 
855
        variable oldval: real ;                 -- following variables are
 
856
        variable num: real ;                    -- used for series evaluation
 
857
        variable count: integer ;
 
858
        variable denom: real ;
 
859
        variable newval: real ;
 
860
 
 
861
     begin
 
862
        -- compute value for special cases
 
863
        if X = 0.0 then
 
864
                return 1.0;
 
865
        else
 
866
                if  X = 1.0  then
 
867
                        return MATH_E;
 
868
                end if;
 
869
        end if;
 
870
 
 
871
        -- compute value for general cases
 
872
        oldval := 1.0;
 
873
        num := xlocal;
 
874
        count := 1;
 
875
        denom := 1.0;
 
876
        newval:= oldval + num/denom;
 
877
 
 
878
        while ( abs(newval - oldval) > eps ) loop
 
879
                oldval := newval;
 
880
                num := num*xlocal;
 
881
                count := count +1;
 
882
                denom := denom*(real(count));
 
883
                newval := oldval + num/denom;
 
884
        end loop;
 
885
 
 
886
        if reciprocal then
 
887
                newval := 1.0/newval;
 
888
        end if;
 
889
 
 
890
        return newval;
 
891
     end EXP;
 
892
 
 
893
 
 
894
    function LOG (X : real ) return real is
 
895
        -- returns natural logarithm of X; X > 0
 
896
        --
 
897
        -- This function computes the exponential using the following series:
 
898
        --    log(x) = 2[ (x-1)/(x+1) + (((x-1)/(x+1))**3)/3.0 + ...] ; x > 0
 
899
        --
 
900
        
 
901
        constant eps : real := 0.000001;        -- precision criteria
 
902
 
 
903
        variable xlocal: real ;                 -- following variables are
 
904
        variable oldval: real ;                 -- used to evaluate the series
 
905
        variable xlocalsqr: real ;
 
906
        variable factor : real ;
 
907
        variable count: integer ;
 
908
        variable newval: real ;
 
909
        
 
910
     begin
 
911
        -- check validity of argument
 
912
        if ( x <= 0.0 ) then
 
913
          assert false report "X <= 0 in LOG(X)" 
 
914
                        severity ERROR;
 
915
            return(REAL'LOW);
 
916
        end if;
 
917
 
 
918
        -- compute value for special cases
 
919
        if ( X = 1.0 ) then
 
920
                return 0.0;
 
921
        else
 
922
                if ( X = MATH_E ) then
 
923
                        return 1.0;
 
924
                end if;
 
925
        end if;
 
926
 
 
927
        -- compute value for general cases
 
928
        xlocal := (X - 1.0)/(X + 1.0);
 
929
        oldval := xlocal;
 
930
        xlocalsqr := xlocal*xlocal;
 
931
        factor := xlocal*xlocalsqr; 
 
932
        count := 3;
 
933
        newval := oldval + (factor/real(count));
 
934
 
 
935
        while ( abs(newval - oldval) > eps ) loop
 
936
                oldval := newval;
 
937
                count := count +2;
 
938
                factor := factor * xlocalsqr;
 
939
                newval := oldval + factor/real(count);
 
940
        end loop;
 
941
 
 
942
        newval := newval * 2.0;
 
943
        return newval;
 
944
    end LOG;
 
945
 
 
946
    function LOG (BASE: positive; X : real) return real is
 
947
        -- returns logarithm base BASE of X; X > 0
 
948
    begin
 
949
        -- check validity of argument
 
950
        if ( BASE <= 0 ) or ( x <= 0.0 ) then
 
951
          assert false report "BASE <= 0 or X <= 0.0 in LOG(BASE, X)" 
 
952
                                severity ERROR;
 
953
            return(REAL'LOW);
 
954
        end if;
 
955
 
 
956
        -- compute the value
 
957
        return ( LOG(X)/LOG(REAL(BASE)));
 
958
    end LOG;
 
959
 
 
960
    function  SIN (X : real ) return real is
 
961
        -- returns sin X; X in radians
 
962
        variable n : INTEGER;
 
963
    begin 
 
964
      if (x < 1.6 ) and (x > -1.6) then
 
965
         return    CORDIC( KC, 0.0, x, 27, ROTATION)(1);
 
966
      end if; 
 
967
 
 
968
      n := INTEGER( x / HALF_PI );
 
969
      case QUADRANT( n mod 4 ) is 
 
970
         when 0 => 
 
971
            return  CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(1);
 
972
         when 1 => 
 
973
            return  CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(0);
 
974
         when 2 =>
 
975
            return -CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(1);
 
976
         when 3 => 
 
977
            return -CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(0);
 
978
       end case;
 
979
    end SIN;
 
980
 
 
981
   
 
982
   function COS (x : REAL) return REAL is 
 
983
        -- returns cos X; X in radians
 
984
      variable n : INTEGER;
 
985
   begin 
 
986
      if (x < 1.6 ) and (x > -1.6) then
 
987
         return CORDIC( KC, 0.0, x, 27, ROTATION)(0);
 
988
      end if; 
 
989
 
 
990
      n := INTEGER( x / HALF_PI );
 
991
      case QUADRANT( n mod 4 ) is 
 
992
         when 0 => 
 
993
            return  CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(0);
 
994
         when 1 => 
 
995
            return -CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(1);
 
996
         when 2 =>
 
997
            return -CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(0);
 
998
         when 3 => 
 
999
            return  CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION)(1);
 
1000
       end case;
 
1001
   end COS;
 
1002
   
 
1003
   function TAN (x : REAL) return REAL is 
 
1004
        -- returns tan X; X in radians
 
1005
        -- X /= ((2k+1) * PI/2), where k is an integer
 
1006
      variable n : INTEGER := INTEGER( x / HALF_PI );
 
1007
      variable v : REAL_ARR_3 :=
 
1008
                       CORDIC( KC, 0.0, x - REAL(n) * HALF_PI, 27, ROTATION);
 
1009
   begin
 
1010
      if n mod 2 = 0 then
 
1011
         return v(1)/v(0);
 
1012
      else
 
1013
         return -v(0)/v(1);
 
1014
      end if;
 
1015
   end TAN; 
 
1016
    
 
1017
   function ASIN (x : real ) return real is
 
1018
        -- returns  -PI/2 < asin X < PI/2; | X | <= 1
 
1019
   begin   
 
1020
      if abs x > 1.0 then 
 
1021
         assert false report "Out of range parameter passed to ASIN" 
 
1022
                        severity ERROR;
 
1023
         return x;
 
1024
      elsif abs x < 0.9 then 
 
1025
         return atan(x/(sqrt(1.0 - x*x)));
 
1026
      elsif x > 0.0 then 
 
1027
         return HALF_PI - atan(sqrt(1.0 - x*x)/x);
 
1028
      else 
 
1029
         return - HALF_PI + atan((sqrt(1.0 - x*x))/x);
 
1030
      end if;
 
1031
   end ASIN; 
 
1032
   
 
1033
   function ACOS (x : REAL) return REAL is
 
1034
        -- returns  0 < acos X < PI; | X | <= 1
 
1035
   begin  
 
1036
      if abs x > 1.0 then 
 
1037
         assert false report "Out of range parameter passed to ACOS" 
 
1038
                        severity ERROR; 
 
1039
         return x;
 
1040
      elsif abs x > 0.9 then
 
1041
         if x > 0.0 then  
 
1042
            return atan(sqrt(1.0 - x*x)/x);
 
1043
         else
 
1044
            return MATH_PI - atan(sqrt(1.0 - x*x)/x); 
 
1045
         end if; 
 
1046
      else 
 
1047
         return HALF_PI - atan(x/sqrt(1.0 - x*x));
 
1048
      end if;
 
1049
   end ACOS; 
 
1050
   
 
1051
   function ATAN (x : REAL) return REAL is
 
1052
        -- returns  -PI/2 < atan X < PI/2
 
1053
   begin
 
1054
      return  CORDIC( 1.0, x, 0.0, 27, VECTORING )(2);      
 
1055
   end ATAN; 
 
1056
 
 
1057
   function ATAN2 (x : REAL; y : REAL) return REAL is 
 
1058
        -- returns  atan (X/Y); -PI < atan2(X,Y) < PI; Y /= 0.0
 
1059
   begin   
 
1060
     if y = 0.0 then 
 
1061
        if x = 0.0 then 
 
1062
           assert false report "atan2(0.0, 0.0) is undetermined, returned 0,0" 
 
1063
                severity NOTE;
 
1064
           return 0.0; 
 
1065
        elsif x > 0.0 then 
 
1066
           return 0.0;
 
1067
        else 
 
1068
           return MATH_PI;
 
1069
        end if;
 
1070
     elsif x > 0.0 then  
 
1071
        return  CORDIC( x, y, 0.0, 27, VECTORING )(2); 
 
1072
     else 
 
1073
        return MATH_PI + CORDIC( x, y, 0.0, 27, VECTORING )(2); 
 
1074
     end if;     
 
1075
   end ATAN2; 
 
1076
 
 
1077
 
 
1078
    function SINH (X : real) return real is
 
1079
        -- hyperbolic sine; returns (e**X - e**(-X))/2
 
1080
    begin
 
1081
                return ( (EXP(X) - EXP(-X))/2.0 );
 
1082
    end SINH;
 
1083
 
 
1084
    function  COSH (X : real) return real is
 
1085
        -- hyperbolic cosine; returns (e**X + e**(-X))/2
 
1086
    begin
 
1087
                return ( (EXP(X) + EXP(-X))/2.0 );
 
1088
    end COSH;
 
1089
 
 
1090
    function  TANH (X : real) return real is
 
1091
        -- hyperbolic tangent; -- returns (e**X - e**(-X))/(e**X + e**(-X))
 
1092
    begin
 
1093
                return ( (EXP(X) - EXP(-X))/(EXP(X) + EXP(-X)) );
 
1094
    end TANH;
 
1095
    
 
1096
    function ASINH (X : real) return real is
 
1097
        -- returns ln( X + sqrt( X**2 + 1))
 
1098
    begin
 
1099
                return ( LOG( X + SQRT( X**2 + 1.0)) );
 
1100
    end ASINH;
 
1101
 
 
1102
    function ACOSH (X : real) return real is
 
1103
        -- returns ln( X + sqrt( X**2 - 1));   X >= 1
 
1104
    begin
 
1105
        if abs x >= 1.0 then 
 
1106
                assert false report "Out of range parameter passed to ACOSH" 
 
1107
                        severity ERROR; 
 
1108
                return x;
 
1109
        end if;
 
1110
 
 
1111
        return ( LOG( X + SQRT( X**2 - 1.0)) );
 
1112
    end ACOSH;
 
1113
 
 
1114
    function ATANH (X : real) return real is
 
1115
        -- returns (ln( (1 + X)/(1 - X)))/2 ; | X | < 1
 
1116
    begin
 
1117
        if abs x < 1.0 then 
 
1118
                assert false report "Out of range parameter passed to ATANH" 
 
1119
                        severity ERROR; 
 
1120
                return x;
 
1121
        end if;
 
1122
 
 
1123
        return( LOG( (1.0+X)/(1.0-X) )/2.0 );
 
1124
    end ATANH;
 
1125
 
 
1126
end  MATH_REAL;
 
1127
 
 
1128
 
 
1129
 
 
1130
--------------------------------------------------------------- 
 
1131
--
 
1132
-- This source file may be used and distributed without restriction.
 
1133
-- No declarations or definitions shall be included in this package.
 
1134
-- This package cannot be sold or distributed for profit. 
 
1135
--
 
1136
--   ****************************************************************
 
1137
--   *                                                              *
 
1138
--   *                      W A R N I N G                           *
 
1139
--   *                                                              *
 
1140
--   *   This DRAFT version IS NOT endorsed or approved by IEEE     *
 
1141
--   *                                                              *
 
1142
--   ****************************************************************
 
1143
--
 
1144
-- Title:    PACKAGE BODY MATH_COMPLEX
 
1145
--
 
1146
-- Purpose:  VHDL declarations for mathematical package MATH_COMPLEX
 
1147
--           which contains common complex constants and basic complex
 
1148
--           functions and operations.
 
1149
--
 
1150
-- Author:   IEEE VHDL Math Package Study Group 
 
1151
--
 
1152
-- Notes:     
 
1153
--      The package body uses package IEEE.MATH_REAL
 
1154
--
 
1155
--      The package body shall be considered the formal definition of 
 
1156
--      the semantics of this package. Tool developers may choose to implement 
 
1157
--      the package body in the most efficient manner available to them.
 
1158
--
 
1159
--   Source code for this package body comes from the following
 
1160
--      following sources: 
 
1161
--              IEEE VHDL Math Package Study Group participants,
 
1162
--              U. of Mississippi, Mentor Graphics, Synopsys,
 
1163
--              Viewlogic/Vantage, Communications of the ACM (June 1988, Vol
 
1164
--              31, Number 6, pp. 747, Pierre L'Ecuyer, Efficient and Portable
 
1165
--              Random Number Generators, Handbook of Mathematical Functions
 
1166
--              by Milton Abramowitz and Irene A. Stegun (Dover).
 
1167
--
 
1168
-- History:
 
1169
--      Version 0.1     Jose A. Torres  4/23/93 First draft
 
1170
--      Version 0.2     Jose A. Torres  5/28/93 Fixed potentially illegal code
 
1171
--
 
1172
-------------------------------------------------------------
 
1173
Library IEEE;
 
1174
 
 
1175
Use IEEE.MATH_REAL.all;         -- real trascendental operations
 
1176
 
 
1177
Package body MATH_COMPLEX is
 
1178
 
 
1179
    function CABS(Z: in complex ) return real is
 
1180
        -- returns absolute value (magnitude) of Z
 
1181
        variable ztemp : complex_polar;
 
1182
    begin
 
1183
                ztemp := COMPLEX_TO_POLAR(Z);
 
1184
                return ztemp.mag;
 
1185
    end CABS;
 
1186
 
 
1187
    function CARG(Z: in complex ) return real is
 
1188
        -- returns argument (angle) in radians of a complex number
 
1189
     variable ztemp : complex_polar;
 
1190
    begin
 
1191
                ztemp := COMPLEX_TO_POLAR(Z);
 
1192
                return ztemp.arg;
 
1193
    end CARG;
 
1194
 
 
1195
    function CMPLX(X: in real;  Y: in real := 0.0 ) return complex is
 
1196
        -- returns complex number X + iY
 
1197
    begin
 
1198
                return COMPLEX'(X, Y);
 
1199
    end CMPLX;
 
1200
 
 
1201
    function "-" (Z: in complex ) return complex is
 
1202
        -- unary minus; returns -x -jy for z= x + jy
 
1203
    begin
 
1204
                return COMPLEX'(-z.Re, -z.Im);
 
1205
    end "-";
 
1206
 
 
1207
    function "-" (Z: in complex_polar ) return complex_polar is
 
1208
        -- unary minus; returns (z.mag, z.arg + MATH_PI)
 
1209
    begin
 
1210
                return COMPLEX_POLAR'(z.mag, z.arg + MATH_PI);
 
1211
    end "-";
 
1212
 
 
1213
    function CONJ (Z: in complex) return complex is
 
1214
        -- returns complex conjugate (x-jy for z = x+ jy)
 
1215
    begin
 
1216
                return COMPLEX'(z.Re, -z.Im);
 
1217
    end CONJ;
 
1218
 
 
1219
    function CONJ (Z: in complex_polar) return complex_polar is
 
1220
        -- returns complex conjugate (z.mag, -z.arg)
 
1221
    begin
 
1222
                return COMPLEX_POLAR'(z.mag, -z.arg);
 
1223
    end CONJ;
 
1224
 
 
1225
    function CSQRT(Z: in complex ) return complex_vector is
 
1226
        -- returns square root of Z; 2 values
 
1227
                variable ztemp : complex_polar;
 
1228
                variable zout : complex_vector (0 to 1);
 
1229
                variable temp : real;
 
1230
    begin
 
1231
                ztemp := COMPLEX_TO_POLAR(Z);
 
1232
                temp := SQRT(ztemp.mag);
 
1233
                zout(0).re := temp*COS(ztemp.arg/2.0);
 
1234
                zout(0).im := temp*SIN(ztemp.arg/2.0); 
 
1235
                
 
1236
                zout(1).re := temp*COS(ztemp.arg/2.0 + MATH_PI);
 
1237
                zout(1).im := temp*SIN(ztemp.arg/2.0 + MATH_PI);
 
1238
                
 
1239
                return zout;
 
1240
    end CSQRT;
 
1241
 
 
1242
    function CEXP(Z: in complex ) return complex is
 
1243
        -- returns e**Z
 
1244
    begin
 
1245
                return COMPLEX'(EXP(Z.re)*COS(Z.im), EXP(Z.re)*SIN(Z.im));
 
1246
    end CEXP;
 
1247
 
 
1248
    function COMPLEX_TO_POLAR(Z: in complex ) return complex_polar is
 
1249
        -- converts complex to complex_polar
 
1250
    begin
 
1251
                return COMPLEX_POLAR'(sqrt(z.re**2 + z.im**2),atan2(z.re,z.im));
 
1252
    end COMPLEX_TO_POLAR;
 
1253
 
 
1254
    function POLAR_TO_COMPLEX(Z: in complex_polar ) return complex is
 
1255
        -- converts complex_polar to complex
 
1256
    begin
 
1257
                return COMPLEX'( z.mag*cos(z.arg), z.mag*sin(z.arg) ); 
 
1258
    end POLAR_TO_COMPLEX;
 
1259
 
 
1260
                
 
1261
    --
 
1262
    -- arithmetic operators
 
1263
    --
 
1264
 
 
1265
    function "+" ( L: in complex;  R: in complex ) return complex is
 
1266
    begin
 
1267
                return COMPLEX'(L.Re + R.Re, L.Im + R.Im);
 
1268
    end "+";
 
1269
 
 
1270
    function "+" (L: in complex_polar; R: in complex_polar) return complex is
 
1271
                variable zL, zR : complex;
 
1272
    begin
 
1273
                zL := POLAR_TO_COMPLEX( L );
 
1274
                zR := POLAR_TO_COMPLEX( R );
 
1275
                return COMPLEX'(zL.Re + zR.Re, zL.Im + zR.Im);
 
1276
    end "+";
 
1277
 
 
1278
    function "+" ( L: in complex_polar; R: in complex ) return complex is
 
1279
                variable zL : complex;
 
1280
    begin
 
1281
                zL := POLAR_TO_COMPLEX( L );
 
1282
                return COMPLEX'(zL.Re + R.Re, zL.Im + R.Im);
 
1283
    end "+";
 
1284
 
 
1285
    function "+" ( L: in complex;  R: in complex_polar) return complex is
 
1286
                variable zR : complex;
 
1287
    begin
 
1288
                zR := POLAR_TO_COMPLEX( R );
 
1289
                return COMPLEX'(L.Re + zR.Re, L.Im + zR.Im);
 
1290
    end "+";
 
1291
 
 
1292
    function "+" ( L: in real;     R: in complex ) return complex is
 
1293
    begin
 
1294
                return COMPLEX'(L + R.Re, R.Im);
 
1295
    end "+";
 
1296
 
 
1297
    function "+" ( L: in complex;  R: in real )    return complex is
 
1298
    begin
 
1299
                return COMPLEX'(L.Re + R, L.Im);
 
1300
    end "+";
 
1301
 
 
1302
    function "+" ( L: in real;  R: in complex_polar) return complex is
 
1303
                variable zR : complex;
 
1304
    begin
 
1305
                zR := POLAR_TO_COMPLEX( R );
 
1306
                return COMPLEX'(L + zR.Re, zR.Im);
 
1307
    end "+";
 
1308
 
 
1309
    function "+" ( L: in complex_polar;  R: in real) return complex is
 
1310
                variable zL : complex;
 
1311
    begin
 
1312
                zL := POLAR_TO_COMPLEX( L );
 
1313
                return COMPLEX'(zL.Re + R, zL.Im);
 
1314
    end "+";
 
1315
 
 
1316
    function "-" ( L: in complex;  R: in complex ) return complex is
 
1317
    begin
 
1318
                return COMPLEX'(L.Re - R.Re, L.Im - R.Im);
 
1319
    end "-";
 
1320
 
 
1321
    function "-" ( L: in complex_polar; R: in complex_polar) return complex is
 
1322
                variable zL, zR : complex;
 
1323
    begin
 
1324
                zL := POLAR_TO_COMPLEX( L );
 
1325
                zR := POLAR_TO_COMPLEX( R );
 
1326
                return COMPLEX'(zL.Re - zR.Re, zL.Im - zR.Im);
 
1327
    end "-";
 
1328
 
 
1329
    function "-" ( L: in complex_polar; R: in complex ) return complex is
 
1330
                variable zL : complex;
 
1331
    begin
 
1332
                zL := POLAR_TO_COMPLEX( L );
 
1333
                return COMPLEX'(zL.Re - R.Re, zL.Im - R.Im);
 
1334
    end "-";
 
1335
 
 
1336
    function "-" ( L: in complex;  R: in complex_polar) return complex is
 
1337
                variable zR : complex;
 
1338
    begin
 
1339
                zR := POLAR_TO_COMPLEX( R );
 
1340
                return COMPLEX'(L.Re - zR.Re, L.Im - zR.Im);
 
1341
    end "-";
 
1342
 
 
1343
    function "-" ( L: in real;     R: in complex ) return complex is
 
1344
    begin
 
1345
                return COMPLEX'(L - R.Re, -1.0 * R.Im);
 
1346
    end "-";
 
1347
 
 
1348
    function "-" ( L: in complex;  R: in real )    return complex is
 
1349
    begin
 
1350
                return COMPLEX'(L.Re - R, L.Im);
 
1351
    end "-";
 
1352
 
 
1353
    function "-" ( L: in real;  R: in complex_polar) return complex is
 
1354
                variable zR : complex;
 
1355
    begin
 
1356
                zR := POLAR_TO_COMPLEX( R );
 
1357
                return COMPLEX'(L - zR.Re, -1.0*zR.Im);
 
1358
    end "-";
 
1359
 
 
1360
    function "-" ( L: in complex_polar;  R: in real) return complex is
 
1361
                variable zL : complex;
 
1362
    begin
 
1363
                zL := POLAR_TO_COMPLEX( L );
 
1364
                return COMPLEX'(zL.Re - R, zL.Im);
 
1365
    end "-";
 
1366
 
 
1367
    function "*" ( L: in complex;  R: in complex ) return complex is
 
1368
    begin
 
1369
        return COMPLEX'(L.Re * R.Re - L.Im * R.Im, L.Re * R.Im + L.Im * R.Re);
 
1370
    end "*";
 
1371
 
 
1372
    function "*" ( L: in complex_polar; R: in complex_polar) return complex is
 
1373
                variable zout : complex_polar;
 
1374
    begin
 
1375
                zout.mag := L.mag * R.mag;
 
1376
                zout.arg := L.arg + R.arg;
 
1377
                return POLAR_TO_COMPLEX(zout);
 
1378
    end "*";
 
1379
 
 
1380
    function "*" ( L: in complex_polar; R: in complex ) return complex is
 
1381
                variable zL : complex;
 
1382
    begin
 
1383
        zL := POLAR_TO_COMPLEX( L );
 
1384
        return COMPLEX'(zL.Re*R.Re - zL.Im * R.Im, zL.Re * R.Im + zL.Im*R.Re);
 
1385
    end "*";
 
1386
 
 
1387
    function "*" ( L: in complex;  R: in complex_polar) return complex is
 
1388
                variable zR : complex;
 
1389
    begin
 
1390
        zR := POLAR_TO_COMPLEX( R );
 
1391
        return COMPLEX'(L.Re*zR.Re - L.Im * zR.Im, L.Re * zR.Im + L.Im*zR.Re);
 
1392
    end "*";
 
1393
 
 
1394
    function "*" ( L: in real;     R: in complex ) return complex is
 
1395
    begin
 
1396
                return COMPLEX'(L * R.Re, L * R.Im);
 
1397
    end "*";
 
1398
 
 
1399
    function "*" ( L: in complex;  R: in real )    return complex is
 
1400
    begin
 
1401
                return COMPLEX'(L.Re * R, L.Im * R);
 
1402
    end "*";
 
1403
 
 
1404
    function "*" ( L: in real;  R: in complex_polar) return complex is
 
1405
                variable zR : complex;
 
1406
    begin
 
1407
                zR := POLAR_TO_COMPLEX( R );
 
1408
                return COMPLEX'(L * zR.Re, L * zR.Im);
 
1409
    end "*";
 
1410
 
 
1411
    function "*" ( L: in complex_polar;  R: in real) return complex is
 
1412
                variable zL : complex;
 
1413
    begin
 
1414
                zL := POLAR_TO_COMPLEX( L );
 
1415
                return COMPLEX'(zL.Re * R, zL.Im * R);
 
1416
    end "*";
 
1417
 
 
1418
    function "/" ( L: in complex;  R: in complex ) return complex is
 
1419
                variable magrsq : REAL := R.Re ** 2 + R.Im ** 2;
 
1420
   begin 
 
1421
      if (magrsq = 0.0) then
 
1422
         assert FALSE report "Attempt to divide by (0,0)"
 
1423
                severity ERROR;
 
1424
         return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1425
      else 
 
1426
         return COMPLEX'( (L.Re * R.Re + L.Im * R.Im) / magrsq,
 
1427
                    (L.Im * R.Re - L.Re * R.Im) / magrsq);
 
1428
      end if;
 
1429
    end "/";
 
1430
 
 
1431
    function "/" ( L: in complex_polar; R: in complex_polar) return complex is
 
1432
                variable zout : complex_polar;
 
1433
    begin
 
1434
        if (R.mag = 0.0) then
 
1435
                assert FALSE report "Attempt to divide by (0,0)"
 
1436
                        severity ERROR;
 
1437
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1438
        else 
 
1439
                zout.mag := L.mag/R.mag;
 
1440
                zout.arg := L.arg - R.arg;
 
1441
                return POLAR_TO_COMPLEX(zout);
 
1442
        end if;
 
1443
    end "/";
 
1444
 
 
1445
    function "/" ( L: in complex_polar; R: in complex ) return complex is
 
1446
                variable zL : complex;
 
1447
                variable temp : REAL := R.Re ** 2 + R.Im ** 2;
 
1448
    begin
 
1449
        if (temp = 0.0) then
 
1450
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1451
                        severity ERROR;
 
1452
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1453
        else 
 
1454
                zL := POLAR_TO_COMPLEX( L );
 
1455
                return COMPLEX'( (zL.Re * R.Re + zL.Im * R.Im) / temp,
 
1456
                    (zL.Im * R.Re - zL.Re * R.Im) / temp);
 
1457
        end if; 
 
1458
    end "/";
 
1459
 
 
1460
    function "/" ( L: in complex;  R: in complex_polar) return complex is
 
1461
                variable zR : complex := POLAR_TO_COMPLEX( R );
 
1462
                variable temp : REAL := zR.Re ** 2 + zR.Im ** 2;
 
1463
    begin
 
1464
        if (R.mag = 0.0) or (temp = 0.0) then
 
1465
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1466
                        severity ERROR;
 
1467
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1468
        else 
 
1469
                return COMPLEX'( (L.Re * zR.Re + L.Im * zR.Im) / temp,
 
1470
                    (L.Im * zR.Re - L.Re * zR.Im) / temp);
 
1471
        end if; 
 
1472
    end "/";
 
1473
 
 
1474
    function "/" ( L: in real;     R: in complex ) return complex is
 
1475
                variable temp : REAL := R.Re ** 2 + R.Im ** 2;
 
1476
    begin 
 
1477
        if (temp = 0.0) then
 
1478
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1479
                        severity ERROR;
 
1480
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1481
        else 
 
1482
                temp := L / temp;
 
1483
                return  COMPLEX'( temp * R.Re, -temp * R.Im );
 
1484
        end if; 
 
1485
    end "/";
 
1486
 
 
1487
    function "/" ( L: in complex;  R: in real )    return complex is
 
1488
    begin
 
1489
        if (R = 0.0) then
 
1490
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1491
                        severity ERROR;
 
1492
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1493
        else 
 
1494
                return COMPLEX'(L.Re / R, L.Im / R);
 
1495
        end if; 
 
1496
    end "/";
 
1497
 
 
1498
    function "/" ( L: in real;  R: in complex_polar) return complex is
 
1499
                variable zR : complex := POLAR_TO_COMPLEX( R );
 
1500
                variable temp : REAL := zR.Re ** 2 + zR.Im ** 2;
 
1501
    begin
 
1502
        if (R.mag = 0.0) or (temp = 0.0) then
 
1503
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1504
                        severity ERROR;
 
1505
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1506
        else 
 
1507
                temp := L / temp;
 
1508
                return  COMPLEX'( temp * zR.Re, -temp * zR.Im );
 
1509
        end if; 
 
1510
    end "/";
 
1511
 
 
1512
    function "/" ( L: in complex_polar;  R: in real) return complex is
 
1513
                variable zL : complex := POLAR_TO_COMPLEX( L );
 
1514
    begin
 
1515
        if (R = 0.0) then
 
1516
                assert FALSE report "Attempt to divide by (0.0,0.0)"
 
1517
                        severity ERROR;
 
1518
                return COMPLEX'(REAL'RIGHT, REAL'RIGHT);
 
1519
        else 
 
1520
                return COMPLEX'(zL.Re / R, zL.Im / R);
 
1521
        end if; 
 
1522
    end "/";
 
1523
end  MATH_COMPLEX;
 
1524