Merge branch 'master' into verilog-ams
[sverilog.git] / vpi / sys_random.c
blobd0a3cb25150a17d337603dae4a883a402723e2db
1 /*
2 * Copyright (c) 2000-2003 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: sys_random.c,v 1.16 2007/03/14 04:05:51 steve Exp $"
21 #endif
23 # include "sys_priv.h"
25 # include <vpi_user.h>
26 # include <assert.h>
27 # include <stdlib.h>
28 # include <math.h>
29 # include <limits.h>
31 #if ULONG_MAX > 4294967295UL
32 # define UNIFORM_MAX INT_MAX
33 # define UNIFORM_MIN INT_MIN
34 #else
35 # define UNIFORM_MAX LONG_MAX
36 # define UNIFORM_MIN LONG_MIN
37 #endif
39 static double uniform(long *seed, long start, long end);
40 static double normal(long *seed, long mean, long deviation);
41 static double exponential(long *seed, long mean);
42 static long poisson(long *seed, long mean);
43 static double chi_square(long *seed, long deg_of_free);
44 static double t(long *seed, long deg_of_free);
45 static double erlangian(long *seed, long k, long mean);
47 long rtl_dist_chi_square(long *seed, long df)
49 double r;
50 long i;
52 if (df > 0) {
53 r = chi_square(seed, df);
54 if (r >= 0) {
55 i = (long) (r + 0.5);
56 } else {
57 r = -r;
58 i = (long) (r + 0.5);
59 i = -i;
61 } else {
62 vpi_printf("WARNING: Chi_square distribution must have "
63 "a positive degree of freedom\n");
64 i = 0;
67 return i;
70 long rtl_dist_erlang(long *seed, long k, long mean)
72 double r;
73 long i;
75 if (k > 0) {
76 r = erlangian(seed, k, mean);
77 if (r >= 0) {
78 i = (long) (r + 0.5);
79 } else {
80 r = -r;
81 i = (long) (r + 0.5);
82 i = -i;
84 } else {
85 vpi_printf("WARNING: K-stage erlangian distribution must have "
86 "a positive k\n");
87 i = 0;
90 return i;
93 long rtl_dist_exponential(long *seed, long mean)
95 double r;
96 long i;
98 if (mean > 0) {
99 r = exponential(seed, mean);
100 if (r >= 0) {
101 i = (long) (r + 0.5);
102 } else {
103 r = -r;
104 i = (long) (r + 0.5);
105 i = -i;
107 } else {
108 vpi_printf("WARNING: Exponential distribution must have "
109 "a positive mean\n");
110 i = 0;
113 return i;
116 long rtl_dist_normal(long *seed, long mean, long sd)
118 double r;
119 long i;
121 r = normal(seed, mean, sd);
122 if (r >= 0) {
123 i = (long) (r + 0.5);
124 } else {
125 r = -r;
126 i = (long) (r + 0.5);
127 i = -i;
130 return i;
133 long rtl_dist_poisson(long *seed, long mean)
135 long i;
137 if (mean > 0) {
138 i = poisson(seed, mean);
139 } else {
140 vpi_printf("WARNING: Poisson distribution must have "
141 "a positive mean\n");
142 i = 0;
145 return i;
148 long rtl_dist_t(long *seed, long df)
150 double r;
151 long i;
153 if (df > 0) {
154 r = t(seed, df);
155 if (r >= 0) {
156 i = (long) (r + 0.5);
157 } else {
158 r = -r;
159 i = (long) (r + 0.5);
160 i = -i;
162 } else {
163 vpi_printf("WARNING: t distribution must have "
164 "a positive degree of freedom\n");
165 i = 0;
168 return i;
171 /* copied from IEEE1364-2001, with slight modifications for 64bit machines. */
172 long rtl_dist_uniform(long *seed, long start, long end)
174 double r;
175 long i;
177 if (start >= end) return(start);
179 /* NOTE: The cast of r to i can overflow and generate strange
180 values, so cast to unsigned long first. This eliminates
181 the underflow and gets the twos complement value. That in
182 turn can be cast to the long value that is expected. */
184 if (end != UNIFORM_MAX) {
185 end++;
186 r = uniform(seed, start, end);
187 if (r >= 0) {
188 i = (unsigned long) r;
189 } else {
190 i = - ( (unsigned long) (-(r - 1)) );
192 if (i < start) i = start;
193 if (i >= end) i = end - 1;
194 } else if (start != UNIFORM_MIN) {
195 start--;
196 r = uniform( seed, start, end) + 1.0;
197 if (r >= 0) {
198 i = (unsigned long) r;
199 } else {
200 i = - ( (unsigned long) (-(r - 1)) );
202 if (i <= start) i = start + 1;
203 if (i > end) i = end;
204 } else {
205 r = (uniform(seed, start, end) + 2147483648.0) / 4294967295.0;
206 r = r * 4294967296.0 - 2147483648.0;
208 if (r >= 0) {
209 i = (unsigned long) r;
210 } else {
211 /* At least some compilers will notice that (r-1)
212 is <0 when castling to unsigned long and
213 replace the result with a zero. This causes
214 much wrongness, so do the casting to the
215 positive version and invert it back. */
216 i = - ( (unsigned long) (-(r - 1)) );
220 return i;
223 static double uniform(long *seed, long start, long end )
225 double d = 0.00000011920928955078125;
226 double a, b, c;
227 unsigned long oldseed, newseed;
229 oldseed = *seed;
230 if (oldseed == 0)
231 oldseed = 259341593;
233 if (start >= end) {
234 a = 0.0;
235 b = 2147483647.0;
236 } else {
237 a = (double)start;
238 b = (double)end;
241 /* Original routine used signed arithmetic, and the (frequent)
242 * overflows trigger "Undefined Behavior" according to the
243 * C standard (both c89 and c99). Using unsigned arithmetic
244 * forces a conforming C implementation to get the result
245 * that the IEEE-1364-2001 committee wants.
247 newseed = 69069 * oldseed + 1;
249 /* Emulate a 32-bit unsigned long, even if the native machine
250 * uses wider words.
252 #if ULONG_MAX > 4294967295UL
253 newseed = newseed & 4294967295UL;
254 #endif
255 *seed = newseed;
258 #if 0
259 /* Cadence-donated conversion from unsigned int to double */
261 union { float s; unsigned stemp; } u;
262 u.stemp = (newseed >> 9) | 0x3f800000;
263 c = (double) u.s;
265 #else
266 /* Equivalent conversion without assuming IEEE 32-bit float */
267 /* constant is 2^(-23) */
268 c = 1.0 + (newseed >> 9) * 0.00000011920928955078125;
269 #endif
272 c = c + (c*d);
273 c = ((b - a) * (c - 1.0)) + a;
275 return c;
278 static double normal(long *seed, long mean, long deviation)
280 double v1, v2, s;
282 s = 1.0;
283 while ((s >= 1.0) || (s == 0.0)) {
284 v1 = uniform(seed, -1, 1);
285 v2 = uniform(seed, -1, 1);
286 s = v1 * v1 + v2 * v2;
288 s = v1 * sqrt(-2.0 * log(s) / s);
289 v1 = (double) deviation;
290 v2 = (double) mean;
292 return s * v1 + v2;
295 static double exponential(long *seed, long mean)
297 double n;
299 n = uniform(seed, 0, 1);
300 if (n != 0.0) {
301 n = -log(n) * mean;
304 return n;
307 static long poisson(long *seed, long mean)
309 long n;
310 double p, q;
312 n = 0;
313 q = -(double) mean;
314 p = exp(q);
315 q = uniform(seed, 0, 1);
316 while (p < q) {
317 n++;
318 q = uniform(seed, 0, 1) * q;
321 return n;
324 static double chi_square(long *seed, long deg_of_free)
326 double x;
327 long k;
329 if (deg_of_free % 2) {
330 x = normal(seed, 0, 1);
331 x = x * x;
332 } else {
333 x = 0.0;
335 for (k = 2; k <= deg_of_free; k = k + 2) {
336 x = x + 2 * exponential(seed, 1);
339 return x;
342 static double t( long *seed, long deg_of_free)
344 double x, chi2, div, root;
346 chi2 = chi_square(seed, deg_of_free);
347 div = chi2 / (double) deg_of_free;
348 root = sqrt(div);
349 x = normal(seed, 0, 1) / root;
351 return x;
354 static double erlangian(long *seed, long k, long mean)
356 double x, a, b;
357 long i;
359 x = 1.0;
360 for (i = 1; i <= k; i++) {
361 x = x * uniform(seed, 0, 1);
363 a = (double) mean;
364 b = (double) k;
365 x = -a * log(x) / b;
367 return x;
370 static PLI_INT32 sys_rand_two_args_compiletf(PLI_BYTE8 *name)
372 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
373 vpiHandle argv = vpi_iterate(vpiArgument, callh);
374 vpiHandle seed, arg2;
376 /* Check that there are arguments. */
377 if (argv == 0) {
378 vpi_printf("ERROR: %s requires two arguments.\n", name);
379 vpi_control(vpiFinish, 1);
380 return 0;
383 /* Check that there are at least two arguments. */
384 seed = vpi_scan(argv); /* This should never be zero. */
385 arg2 = vpi_scan(argv);
386 if (arg2 == 0) {
387 vpi_printf("ERROR: %s requires two arguments.\n", name);
388 vpi_control(vpiFinish, 1);
389 return 0;
392 /* The seed must be a time/integer variable or a register. */
393 switch (vpi_get(vpiType, seed)) {
394 case vpiTimeVar:
395 case vpiIntegerVar:
396 case vpiReg:
397 break;
398 default:
399 vpi_printf("ERROR: %s's seed must be an integer/time"
400 " varible or a register.\n", name);
401 vpi_control(vpiFinish, 1);
402 return 0;
405 /* These functions takes at most two argument. */
406 seed = vpi_scan(argv);
407 if (seed != 0) {
408 vpi_printf("ERROR: %s takes at most two argument.\n", name);
409 vpi_control(vpiFinish, 1);
410 return 0;
413 /* vpi_scan returning 0 (NULL) has already freed argv. */
414 return 0;
417 static PLI_INT32 sys_rand_three_args_compiletf(PLI_BYTE8 *name)
419 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
420 vpiHandle argv = vpi_iterate(vpiArgument, callh);
421 vpiHandle seed, arg2, arg3;
423 /* Check that there are arguments. */
424 if (argv == 0) {
425 vpi_printf("ERROR: %s requires three arguments.\n", name);
426 vpi_control(vpiFinish, 1);
427 return 0;
430 /* Check that there are at least three arguments. */
431 seed = vpi_scan(argv); /* This should never be zero. */
432 arg2 = vpi_scan(argv);
433 if (arg2) {
434 arg3 = vpi_scan(argv);
435 } else {
436 arg3 = 0;
438 if (arg2 == 0 || arg3 == 0) {
439 vpi_printf("ERROR: %s requires three arguments.\n", name);
440 vpi_control(vpiFinish, 1);
441 return 0;
444 /* The seed must be a time/integer variable or a register. */
445 switch (vpi_get(vpiType, seed)) {
446 case vpiTimeVar:
447 case vpiIntegerVar:
448 case vpiReg:
449 break;
450 default:
451 vpi_printf("ERROR: %s's seed must be an integer/time"
452 " varible or a register.\n", name);
453 vpi_control(vpiFinish, 1);
454 return 0;
457 /* These functions takes at most three argument. */
458 seed = vpi_scan(argv);
459 if (seed != 0) {
460 vpi_printf("ERROR: %s takes at most three argument.\n", name);
461 vpi_control(vpiFinish, 1);
462 return 0;
465 /* vpi_scan returning 0 (NULL) has already freed argv. */
466 return 0;
469 static PLI_INT32 sys_random_compiletf(PLI_BYTE8 *name)
471 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
472 vpiHandle argv = vpi_iterate(vpiArgument, callh);
473 vpiHandle seed;
475 /* The seed is optional. */
476 if (argv == 0) return 0;
477 seed = vpi_scan(argv);
479 /* The seed must be a time/integer variable or a register. */
480 switch (vpi_get(vpiType, seed)) {
481 case vpiTimeVar:
482 case vpiIntegerVar:
483 case vpiReg:
484 break;
485 default:
486 vpi_printf("ERROR: %s's seed must be an integer/time"
487 " varible or a register.\n", name);
488 vpi_control(vpiFinish, 1);
489 return 0;
492 /* random takes at most one argument (the seed). */
493 seed = vpi_scan(argv);
494 if (seed != 0) {
495 vpi_printf("ERROR: %s takes at most one argument.\n", name);
496 vpi_control(vpiFinish, 1);
497 return 0;
500 /* vpi_scan returning 0 (NULL) has already freed argv. */
501 return 0;
504 static PLI_INT32 sys_random_calltf(PLI_BYTE8 *name)
506 vpiHandle callh, argv, seed = 0;
507 s_vpi_value val;
508 static long i_seed = 0;
510 /* Get the argument list and look for a seed. If it is there,
511 get the value and reseed the random number generator. */
512 callh = vpi_handle(vpiSysTfCall, 0);
513 argv = vpi_iterate(vpiArgument, callh);
514 val.format = vpiIntVal;
515 if (argv) {
516 seed = vpi_scan(argv);
517 vpi_free_object(argv);
518 vpi_get_value(seed, &val);
519 i_seed = val.value.integer;
522 /* Calculate and return the result. */
523 val.value.integer = rtl_dist_uniform(&i_seed, INT_MIN, INT_MAX);
524 vpi_put_value(callh, &val, 0, vpiNoDelay);
526 /* If it exists send the updated seed back to seed parameter. */
527 if (seed) {
528 val.value.integer = i_seed;
529 vpi_put_value(seed, &val, 0, vpiNoDelay);
532 return 0;
535 /* From System Verilog 3.1a. */
536 static PLI_INT32 sys_urandom_range_compiletf(PLI_BYTE8 *name)
538 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
539 vpiHandle argv = vpi_iterate(vpiArgument, callh);
540 vpiHandle arg;
542 /* Check that there are arguments. */
543 if (argv == 0) {
544 vpi_printf("ERROR: %s requires two arguments.\n", name);
545 vpi_control(vpiFinish, 1);
546 return 0;
549 /* Check that there are at least two arguments. */
550 arg = vpi_scan(argv); /* This should never be zero. */
551 arg = vpi_scan(argv);
552 if (arg == 0) {
553 vpi_printf("ERROR: %s requires two arguments.\n", name);
554 vpi_control(vpiFinish, 1);
555 return 0;
558 /* These functions takes at most two argument. */
559 arg = vpi_scan(argv);
560 if (arg != 0) {
561 vpi_printf("ERROR: %s takes at most two argument.\n", name);
562 vpi_control(vpiFinish, 1);
563 return 0;
566 /* vpi_scan returning 0 (NULL) has already freed argv. */
567 return 0;
570 /* From System Verilog 3.1a. */
571 static unsigned long urandom(long *seed, unsigned long max, unsigned long min)
573 static long i_seed = 0;
574 unsigned long result;
575 long max_i, min_i;
577 max_i = max + INT_MIN;
578 min_i = min + INT_MIN;
579 if (seed != 0) i_seed = *seed;
580 result = rtl_dist_uniform(&i_seed, min_i, max_i) - INT_MIN;
581 if (seed != 0) *seed = i_seed;
582 return result;
585 /* From System Verilog 3.1a. */
586 static PLI_INT32 sys_urandom_calltf(PLI_BYTE8 *name)
588 vpiHandle callh, argv, seed = 0;
589 s_vpi_value val;
590 long i_seed;
592 /* Get the argument list and look for a seed. If it is there,
593 get the value and reseed the random number generator. */
594 callh = vpi_handle(vpiSysTfCall, 0);
595 argv = vpi_iterate(vpiArgument, callh);
596 val.format = vpiIntVal;
597 if (argv) {
598 seed = vpi_scan(argv);
599 vpi_free_object(argv);
600 vpi_get_value(seed, &val);
601 i_seed = val.value.integer;
604 /* Calculate and return the result. */
605 if (seed) {
606 val.value.integer = urandom(&i_seed, UINT_MAX, 0);
607 } else {
608 val.value.integer = urandom(0, UINT_MAX, 0);
610 vpi_put_value(callh, &val, 0, vpiNoDelay);
612 /* If it exists send the updated seed back to seed parameter. */
613 if (seed) {
614 val.value.integer = i_seed;
615 vpi_put_value(seed, &val, 0, vpiNoDelay);
618 return 0;
621 /* From System Verilog 3.1a. */
622 static PLI_INT32 sys_urandom_range_calltf(PLI_BYTE8 *name)
624 vpiHandle callh, argv, maxval, minval;
625 s_vpi_value val;
626 unsigned long i_maxval, i_minval, tmp;
628 /* Get the argument handles and convert them. */
629 callh = vpi_handle(vpiSysTfCall, 0);
630 argv = vpi_iterate(vpiArgument, callh);
631 maxval = vpi_scan(argv);
632 minval = vpi_scan(argv);
634 val.format = vpiIntVal;
635 vpi_get_value(maxval, &val);
636 i_maxval = val.value.integer;
638 vpi_get_value(minval, &val);
639 i_minval = val.value.integer;
641 /* Swap the two arguments if they are out of order. */
642 if (i_minval > i_maxval) {
643 tmp = i_minval;
644 i_minval = i_maxval;
645 i_maxval = tmp;
648 /* Calculate and return the result. */
649 val.value.integer = urandom(0, i_maxval, i_minval);
650 vpi_put_value(callh, &val, 0, vpiNoDelay);
651 return 0;
654 static PLI_INT32 sys_dist_uniform_calltf(PLI_BYTE8 *name)
656 vpiHandle callh, argv, seed, start, end;
657 s_vpi_value val;
658 long i_seed, i_start, i_end;
660 /* Get the argument handles and convert them. */
661 callh = vpi_handle(vpiSysTfCall, 0);
662 argv = vpi_iterate(vpiArgument, callh);
663 seed = vpi_scan(argv);
664 start = vpi_scan(argv);
665 end = vpi_scan(argv);
667 val.format = vpiIntVal;
668 vpi_get_value(seed, &val);
669 i_seed = val.value.integer;
671 vpi_get_value(start, &val);
672 i_start = val.value.integer;
674 vpi_get_value(end, &val);
675 i_end = val.value.integer;
677 /* Calculate and return the result. */
678 val.value.integer = rtl_dist_uniform(&i_seed, i_start, i_end);
679 vpi_put_value(callh, &val, 0, vpiNoDelay);
681 /* Return the seed. */
682 val.value.integer = i_seed;
683 vpi_put_value(seed, &val, 0, vpiNoDelay);
685 vpi_free_object(argv);
686 return 0;
689 static PLI_INT32 sys_dist_normal_calltf(PLI_BYTE8 *name)
691 vpiHandle callh, argv, seed, mean, sd;
692 s_vpi_value val;
693 long i_seed, i_mean, i_sd;
695 /* Get the argument handles and convert them. */
696 callh = vpi_handle(vpiSysTfCall, 0);
697 argv = vpi_iterate(vpiArgument, callh);
698 seed = vpi_scan(argv);
699 mean = vpi_scan(argv);
700 sd = vpi_scan(argv);
702 val.format = vpiIntVal;
703 vpi_get_value(seed, &val);
704 i_seed = val.value.integer;
706 vpi_get_value(mean, &val);
707 i_mean = val.value.integer;
709 vpi_get_value(sd, &val);
710 i_sd = val.value.integer;
712 /* Calculate and return the result. */
713 val.value.integer = rtl_dist_normal(&i_seed, i_mean, i_sd);
714 vpi_put_value(callh, &val, 0, vpiNoDelay);
716 /* Return the seed. */
717 val.value.integer = i_seed;
718 vpi_put_value(seed, &val, 0, vpiNoDelay);
720 vpi_free_object(argv);
721 return 0;
724 static PLI_INT32 sys_dist_exponential_calltf(PLI_BYTE8 *name)
726 vpiHandle callh, argv, seed, mean;
727 s_vpi_value val;
728 long i_seed, i_mean;
730 /* Get the argument handles and convert them. */
731 callh = vpi_handle(vpiSysTfCall, 0);
732 argv = vpi_iterate(vpiArgument, callh);
733 seed = vpi_scan(argv);
734 mean = vpi_scan(argv);
736 val.format = vpiIntVal;
737 vpi_get_value(seed, &val);
738 i_seed = val.value.integer;
740 vpi_get_value(mean, &val);
741 i_mean = val.value.integer;
743 /* Calculate and return the result. */
744 val.value.integer = rtl_dist_exponential(&i_seed, i_mean);
745 vpi_put_value(callh, &val, 0, vpiNoDelay);
747 /* Return the seed. */
748 val.value.integer = i_seed;
749 vpi_put_value(seed, &val, 0, vpiNoDelay);
751 vpi_free_object(argv);
752 return 0;
755 static PLI_INT32 sys_dist_poisson_calltf(PLI_BYTE8 *name)
757 vpiHandle callh, argv, seed, mean;
758 s_vpi_value val;
759 long i_seed, i_mean;
761 /* Get the argument handles and convert them. */
762 callh = vpi_handle(vpiSysTfCall, 0);
763 argv = vpi_iterate(vpiArgument, callh);
764 seed = vpi_scan(argv);
765 mean = vpi_scan(argv);
767 val.format = vpiIntVal;
768 vpi_get_value(seed, &val);
769 i_seed = val.value.integer;
771 vpi_get_value(mean, &val);
772 i_mean = val.value.integer;
774 /* Calculate and return the result. */
775 val.value.integer = rtl_dist_poisson(&i_seed, i_mean);
776 vpi_put_value(callh, &val, 0, vpiNoDelay);
778 /* Return the seed. */
779 val.value.integer = i_seed;
780 vpi_put_value(seed, &val, 0, vpiNoDelay);
782 vpi_free_object(argv);
783 return 0;
786 static PLI_INT32 sys_dist_chi_square_calltf(PLI_BYTE8 *name)
788 vpiHandle callh, argv, seed, df;
789 s_vpi_value val;
790 long i_seed, i_df;
792 /* Get the argument handles and convert them. */
793 callh = vpi_handle(vpiSysTfCall, 0);
794 argv = vpi_iterate(vpiArgument, callh);
795 seed = vpi_scan(argv);
796 df = vpi_scan(argv);
798 val.format = vpiIntVal;
799 vpi_get_value(seed, &val);
800 i_seed = val.value.integer;
802 vpi_get_value(df, &val);
803 i_df = val.value.integer;
805 /* Calculate and return the result. */
806 val.value.integer = rtl_dist_chi_square(&i_seed, i_df);
807 vpi_put_value(callh, &val, 0, vpiNoDelay);
809 /* Return the seed. */
810 val.value.integer = i_seed;
811 vpi_put_value(seed, &val, 0, vpiNoDelay);
813 vpi_free_object(argv);
814 return 0;
817 static PLI_INT32 sys_dist_t_calltf(PLI_BYTE8 *name)
819 vpiHandle callh, argv, seed, df;
820 s_vpi_value val;
821 long i_seed, i_df;
823 /* Get the argument handles and convert them. */
824 callh = vpi_handle(vpiSysTfCall, 0);
825 argv = vpi_iterate(vpiArgument, callh);
826 seed = vpi_scan(argv);
827 df = vpi_scan(argv);
829 val.format = vpiIntVal;
830 vpi_get_value(seed, &val);
831 i_seed = val.value.integer;
833 vpi_get_value(df, &val);
834 i_df = val.value.integer;
836 /* Calculate and return the result. */
837 val.value.integer = rtl_dist_t(&i_seed, i_df);
838 vpi_put_value(callh, &val, 0, vpiNoDelay);
840 /* Return the seed. */
841 val.value.integer = i_seed;
842 vpi_put_value(seed, &val, 0, vpiNoDelay);
844 vpi_free_object(argv);
845 return 0;
848 static PLI_INT32 sys_dist_erlang_calltf(PLI_BYTE8 *name)
850 vpiHandle callh, argv, seed, k, mean;
851 s_vpi_value val;
852 long i_seed, i_k, i_mean;
854 /* Get the argument handles and convert them. */
855 callh = vpi_handle(vpiSysTfCall, 0);
856 argv = vpi_iterate(vpiArgument, callh);
857 seed = vpi_scan(argv);
858 k = vpi_scan(argv);
859 mean = vpi_scan(argv);
861 val.format = vpiIntVal;
862 vpi_get_value(seed, &val);
863 i_seed = val.value.integer;
865 vpi_get_value(k, &val);
866 i_k = val.value.integer;
868 vpi_get_value(mean, &val);
869 i_mean = val.value.integer;
871 /* Calculate and return the result. */
872 val.value.integer = rtl_dist_normal(&i_seed, i_k, i_mean);
873 vpi_put_value(callh, &val, 0, vpiNoDelay);
875 /* Return the seed. */
876 val.value.integer = i_seed;
877 vpi_put_value(seed, &val, 0, vpiNoDelay);
879 vpi_free_object(argv);
880 return 0;
883 static PLI_INT32 sys_rand_func_sizetf(PLI_BYTE8 *x)
885 return 32;
888 void sys_random_register()
890 s_vpi_systf_data tf_data;
892 tf_data.type = vpiSysFunc;
893 tf_data.sysfunctype = vpiSysFuncInt;
894 tf_data.tfname = "$random";
895 tf_data.calltf = sys_random_calltf;
896 tf_data.compiletf = sys_random_compiletf;
897 tf_data.sizetf = sys_rand_func_sizetf;
898 tf_data.user_data = "$random";
899 vpi_register_systf(&tf_data);
901 /* From System Verilog 3.1a. */
902 tf_data.type = vpiSysFunc;
903 tf_data.sysfunctype = vpiSysFuncSized;
904 tf_data.tfname = "$urandom";
905 tf_data.calltf = sys_urandom_calltf;
906 tf_data.compiletf = sys_random_compiletf;
907 tf_data.sizetf = sys_rand_func_sizetf;
908 tf_data.user_data = "$urandom";
909 vpi_register_systf(&tf_data);
911 /* From System Verilog 3.1a. */
912 tf_data.type = vpiSysFunc;
913 tf_data.sysfunctype = vpiSysFuncSized;
914 tf_data.tfname = "$urandom_range";
915 tf_data.calltf = sys_urandom_range_calltf;
916 tf_data.compiletf = sys_urandom_range_compiletf;
917 tf_data.sizetf = sys_rand_func_sizetf;
918 tf_data.user_data = "$urandom_range";
919 vpi_register_systf(&tf_data);
921 tf_data.type = vpiSysFunc;
922 tf_data.sysfunctype = vpiSysFuncInt;
923 tf_data.tfname = "$dist_uniform";
924 tf_data.calltf = sys_dist_uniform_calltf;
925 tf_data.compiletf = sys_rand_three_args_compiletf;
926 tf_data.sizetf = sys_rand_func_sizetf;
927 tf_data.user_data = "$dist_uniform";
928 vpi_register_systf(&tf_data);
930 tf_data.type = vpiSysFunc;
931 tf_data.sysfunctype = vpiSysFuncInt;
932 tf_data.tfname = "$dist_normal";
933 tf_data.calltf = sys_dist_normal_calltf;
934 tf_data.compiletf = sys_rand_three_args_compiletf;
935 tf_data.sizetf = sys_rand_func_sizetf;
936 tf_data.user_data = "$dist_normal";
937 vpi_register_systf(&tf_data);
939 tf_data.type = vpiSysFunc;
940 tf_data.sysfunctype = vpiSysFuncInt;
941 tf_data.tfname = "$dist_exponential";
942 tf_data.calltf = sys_dist_exponential_calltf;
943 tf_data.compiletf = sys_rand_two_args_compiletf;
944 tf_data.sizetf = sys_rand_func_sizetf;
945 tf_data.user_data = "$dist_exponential";
946 vpi_register_systf(&tf_data);
948 tf_data.type = vpiSysFunc;
949 tf_data.sysfunctype = vpiSysFuncInt;
950 tf_data.tfname = "$dist_poisson";
951 tf_data.calltf = sys_dist_poisson_calltf;
952 tf_data.compiletf = sys_rand_two_args_compiletf;
953 tf_data.sizetf = sys_rand_func_sizetf;
954 tf_data.user_data = "$dist_poisson";
955 vpi_register_systf(&tf_data);
957 tf_data.type = vpiSysFunc;
958 tf_data.sysfunctype = vpiSysFuncInt;
959 tf_data.tfname = "$dist_chi_square";
960 tf_data.calltf = sys_dist_chi_square_calltf;
961 tf_data.compiletf = sys_rand_two_args_compiletf;
962 tf_data.sizetf = sys_rand_func_sizetf;
963 tf_data.user_data = "$dist_chi_square";
964 vpi_register_systf(&tf_data);
966 tf_data.type = vpiSysFunc;
967 tf_data.sysfunctype = vpiSysFuncInt;
968 tf_data.tfname = "$dist_t";
969 tf_data.calltf = sys_dist_t_calltf;
970 tf_data.compiletf = sys_rand_two_args_compiletf;
971 tf_data.sizetf = sys_rand_func_sizetf;
972 tf_data.user_data = "$dist_t";
973 vpi_register_systf(&tf_data);
975 tf_data.type = vpiSysFunc;
976 tf_data.sysfunctype = vpiSysFuncInt;
977 tf_data.tfname = "$dist_erlang";
978 tf_data.calltf = sys_dist_erlang_calltf;
979 tf_data.compiletf = sys_rand_three_args_compiletf;
980 tf_data.sizetf = sys_rand_func_sizetf;
981 tf_data.user_data = "$dist_erlang";
982 vpi_register_systf(&tf_data);