Fix for assertion error when expanding macro.
[iverilog.git] / vpi / sys_display.c
blobadffe9862429c09a795b62f32142657d37171969
1 /*
2 * Copyright (c) 1999 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_display.c,v 1.79 2007/04/18 02:40:20 steve Exp $"
21 #endif
23 # include "vpi_config.h"
25 # include "vpi_user.h"
26 # include "sys_priv.h"
27 # include <assert.h>
28 # include <string.h>
29 # include <ctype.h>
30 # include <stdio.h>
31 # include <stdlib.h>
32 # include <math.h>
34 #define IS_MCD(mcd) !((mcd)>>31&1)
36 /* Printf wrapper to handle both MCD/FD */
37 static PLI_INT32 my_mcd_printf(PLI_UINT32 mcd, const char *fmt, ...)
39 int r = 0;
41 va_list ap;
42 va_start(ap, fmt);
44 if (IS_MCD(mcd)) {
45 r = vpi_mcd_vprintf(mcd, fmt, ap);
46 } else {
47 FILE *fp = vpi_get_file(mcd);
48 if (fp) r = vfprintf(fp, fmt, ap);
51 va_end(ap);
52 return r;
55 struct timeformat_info_s timeformat_info = { 0, 0, 0, 20 };
57 struct strobe_cb_info {
58 char*name;
59 int default_format;
60 vpiHandle scope;
61 vpiHandle*items;
62 unsigned nitems;
63 unsigned mcd;
66 int is_constant(vpiHandle obj)
68 if (vpi_get(vpiType, obj) == vpiConstant)
69 return vpiConstant;
70 if (vpi_get(vpiType, obj) == vpiParameter)
71 return vpiParameter;
73 return 0;
76 // The number of decimal digits needed to represent a
77 // nr_bits binary number is floor(nr_bits*log_10(2))+1,
78 // where log_10(2) = 0.30102999566398.... and I approximate
79 // this transcendental number as 146/485, to avoid the vagaries
80 // of floating-point. The smallest nr_bits for which this
81 // approximation fails is 2621,
82 // 2621*log_10(2)=789.9996, but (2621*146+484)/485=790 (exactly).
83 // In cases like this, all that happens is we allocate one
84 // unneeded char for the output. I add a "L" suffix to 146
85 // to make sure the computation is done as long ints, otherwise
86 // on a 16-bit int machine (allowed by ISO C) we would mangle
87 // this computation for bit-length of 224. I'd like to put
88 // in a test for nr_bits < LONG_MAX/146, but don't know how
89 // to fail, other than crashing.
91 // In an April 2000 thread in comp.unix.programmer, with subject
92 // "integer -> string", I <LRDoolittle@lbl.gov> give the 28/93
93 // approximation, but overstate its accuracy: that version first
94 // fails when the number of bits is 289, not 671.
96 // This result does not include space for a trailing '\0', if any.
98 inline static int calc_dec_size(int nr_bits, int is_signed)
100 int r;
101 if (is_signed) --nr_bits;
102 r = (nr_bits * 146L + 484) / 485;
103 if (is_signed) ++r;
104 return r;
107 static int vpi_get_dec_size(vpiHandle item)
109 return calc_dec_size(
110 vpi_get(vpiSize, item),
111 vpi_get(vpiSigned, item)==1
115 static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
117 if (argv) {
118 vpiHandle item;
119 unsigned nitems = 1;
120 vpiHandle*items = malloc(sizeof(vpiHandle));
121 items[0] = vpi_scan(argv);
122 if (items[0] == 0) {
123 free(items);
124 info->nitems = 0;
125 info->items = 0;
126 return;
129 for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
130 items = realloc(items, (nitems+1)*sizeof(vpiHandle));
131 items[nitems] = item;
132 nitems += 1;
135 info->nitems = nitems;
136 info->items = items;
138 } else {
139 info->nitems = 0;
140 info->items = 0;
145 * This function writes the time value into the mcd target with the
146 * proper format. The mcd is the destination file.
148 * The fsize is the width of the field to use. Normally, this is -1 to
149 * reflect the format string "%t". It may also be 0 for the format
150 * string "%0t". This formatter also allows for the nonstandard use of
151 * positive values to enforce a with to override the width given in
152 * the $timeformat system task.
154 * The value argument is the time value as a decimal string. There are
155 * no leading zeros in this string, and the units of the value are
156 * given in the units argument.
158 static void format_time(unsigned mcd, int fsize,
159 const char*value, int time_units)
161 char buf[256];
162 const char*cp;
163 char*bp, *start_address;
165 int idx;
166 unsigned int fusize;
167 int fraction_chars, fraction_pad, value_chop, whole_fill;
169 /* This is the format precision expressed as the power of 10
170 of the desired precision. The following code uses this
171 format to be consistent with the units specifications. */
172 int format_precision = timeformat_info.units - timeformat_info.prec;
174 /* If the fsize is <0, then use the value from the
175 $timeformat. If the fsize is >=0, then it overrides the
176 $timeformat value. */
177 fusize = (fsize<0) ? timeformat_info.width : (unsigned) fsize;
179 assert(fusize < (sizeof buf - 1));
182 /* This is the number of characters to the right of the
183 decimal point. This is defined completely by the
184 timeformat. It is legal for the precision to be larger then
185 the units, and in this case there will be no fraction_chars
186 at all. */
187 fraction_chars = timeformat_info.units - format_precision;
188 if (fraction_chars < 0)
189 fraction_chars = 0;
191 /* This is the number of zeros I must add to the value to get
192 the desired precision within the fraction. If this value is
193 greater then 0, the value does not have enough characters,
194 so I will be adding zeros. */
196 fraction_pad = time_units - format_precision;
197 if (fraction_pad < 0)
198 fraction_pad = 0;
199 if (fraction_pad > fraction_chars)
200 fraction_pad = fraction_chars;
203 /* This is the number of characters of excess precision in the
204 supplied value. This many characters are chopped from the
205 least significant end. */
206 value_chop = format_precision - time_units;
207 if (value_chop < 0)
208 value_chop = 0;
210 /* This is the number of zeros that I must add to the integer
211 part of the output string to pad the value out to the
212 desired units. This will only have a non-zero value if the
213 units of the value is greater then the desired units.
215 Detect the special case where the value is 0. In this case,
216 do not do any integer filling ever. The output should be
217 padded with blanks in that case. */
218 whole_fill = time_units - timeformat_info.units;
219 if (whole_fill < 0)
220 whole_fill = 0;
221 if (strcmp(value,"0") == 0)
222 whole_fill = 0;
224 /* This is the expected start address of the output. It
225 accounts for the f(u)size value that is chosen. The output
226 will be filled out to complete the buffer. */
227 if (fusize == 0)
228 start_address = buf;
229 else
230 start_address = buf + sizeof buf - fusize - 1;
232 /* Now start the character pointers, ready to start copying
233 the value into the format. */
234 cp = value + strlen(value);
235 if (value_chop > (cp - value))
236 cp = value;
237 else
238 cp -= value_chop;
240 bp = buf + sizeof buf;
241 *--bp = 0;
244 /* Write the suffix. */
245 bp -= strlen(timeformat_info.suff);
246 strcpy(bp, timeformat_info.suff);
248 /* Write the padding needed to fill out the fraction. */
249 for (idx = 0 ; idx < fraction_pad ; idx += 1)
250 *--bp = '0';
252 /* Subtract the pad from the needed chars. */
253 assert(fraction_pad <= fraction_chars);
254 fraction_chars -= fraction_pad;
255 fraction_pad = 0;
257 /* Write the fraction chars. */
258 for (idx = 0 ; idx < fraction_chars ; idx += 1) {
259 if (cp > value)
260 *--bp = *--cp;
261 else
262 *--bp = '0';
264 assert(cp >= value);
267 /* Write the decimal point, if needed. */
268 if (timeformat_info.prec > 0)
269 *--bp = '.';
271 /* Fill the gap between the value and the decimal point. */
272 for (idx = 0 ; idx < whole_fill ; idx += 1)
273 *--bp = '0';
275 /* Write the integer part of the value. */
276 while (cp > value) {
277 *--bp = *--cp;
280 /* Fill the leading characters to make up the desired
281 width. This may require a '0' if the last character
282 written was the decimal point. This may also require a '0'
283 if there are no other characters at all in the ouput. */
284 if (fusize > 0) {
285 while (bp > start_address) {
286 if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0)
287 *--bp = '0';
288 else
289 *--bp = ' ';
291 } else {
292 if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0)
293 *--bp = '0';
297 my_mcd_printf(mcd, "%s", bp);
300 static void format_time_real(unsigned mcd, int fsize,
301 double value, int time_units)
303 int width;
305 /* The time_units is the units of the current scope, and also
306 of the value. If the scope units are different from the
307 format specifier units, then scale the value. */
308 if (time_units != timeformat_info.units)
309 value *= pow(10.0, time_units - timeformat_info.units);
311 if (fsize == -1) {
312 width = timeformat_info.width - strlen(timeformat_info.suff);
313 } else {
314 width = fsize;
316 /* The timeformat_info.prec is the number of digits after the
317 decimal point, no matter what the units. */
318 my_mcd_printf(mcd, "%*.*f%s", width, timeformat_info.prec, value,
319 timeformat_info.suff);
323 static void format_strength(unsigned int mcd, s_vpi_value*value)
325 char str[4];
326 vpip_format_strength(str, value);
327 my_mcd_printf(mcd, "%s", str);
330 static void format_error_msg(const char*msg, int leading_zero,
331 int fsize, int ffsize, char fmt)
333 if ((fsize < 0) && (ffsize < 0)) {
334 if (leading_zero > 0)
335 vpi_printf("\nERROR: %s: %%0%c\n", msg, fmt);
336 else
337 vpi_printf("\nERROR: %s: %%%c\n", msg, fmt);
339 } else if (ffsize < 0) {
340 if ((leading_zero > 0) && (fsize > 0))
341 vpi_printf("\nERROR: %s: %%0%d%c\n", msg,
342 fsize, fmt);
343 else
344 vpi_printf("\nERROR: %s: %%%d%c\n", msg,
345 fsize, fmt);
347 } else {
348 vpi_printf("\nERROR: %s: %%%d.%d%c\n", msg,
349 fsize, ffsize, fmt);
354 * The format_str uses this function to do the special job of
355 * interpreting the next item depending on the format code. The caller
356 * has already parsed the %x.yf format string.
358 * The return code is the number of arguments that were consumed.
360 static int format_str_char(vpiHandle scope, unsigned int mcd,
361 int leading_zero, int fsize, int ffsize,
362 char fmt, int argc, vpiHandle*argv, int idx)
364 s_vpi_value value;
365 int use_count = 0;
367 /* Time units of the current scope. */
368 int time_units = vpi_get(vpiTimeUnit, scope);
370 switch (fmt) {
372 case 0:
373 return 0;
375 case '%':
376 if (fsize != -1 && ffsize != -1) {
377 format_error_msg("Illegal format", leading_zero,
378 fsize, ffsize, fmt);
379 fsize = -1;
380 ffsize = -1;
383 my_mcd_printf(mcd, "%%");
385 use_count = 0;
386 break;
388 // new Verilog 2001 format specifiers...
389 case 'l':
390 case 'L':
391 case 'u':
392 case 'U':
393 case 'z':
394 case 'Z':
395 format_error_msg("Unsupported format", leading_zero,
396 fsize, ffsize, fmt);
397 my_mcd_printf(mcd, "%c", fmt);
399 use_count = 0;
400 break;
402 default:
403 format_error_msg("Illegal format", leading_zero,
404 fsize, ffsize, fmt);
405 my_mcd_printf(mcd, "%c", fmt);
406 break;
408 /* Print numeric value in binary/hex/octal format. */
409 case 'b':
410 case 'B':
411 case 'h':
412 case 'H':
413 case 'o':
414 case 'O':
415 case 'x':
416 case 'X':
417 if (ffsize != -1) {
418 format_error_msg("Illegal format", leading_zero,
419 fsize, ffsize, fmt);
420 fsize = -1;
423 if (idx >= argc) {
424 format_error_msg("Missing Argument", leading_zero,
425 fsize, ffsize, fmt);
426 return 0;
429 switch (fmt) {
430 case 'b':
431 case 'B':
432 value.format = vpiBinStrVal;
433 break;
434 case 'h':
435 case 'H':
436 case 'x':
437 case 'X':
438 value.format = vpiHexStrVal;
439 break;
440 case 'o':
441 case 'O':
442 value.format = vpiOctStrVal;
443 break;
446 vpi_get_value(argv[idx], &value);
447 if (value.format == vpiSuppressVal){
448 format_error_msg("Incompatible value", leading_zero,
449 fsize, ffsize, fmt);
450 return 1;
453 { char* value_str = value.value.str;
454 if (leading_zero==1){
455 // Strip away all leading zeros from string
456 unsigned int i=0;
457 while(i< (strlen(value_str)-1) && value_str[i]=='0')
458 i++;
459 value_str += i;
462 my_mcd_printf(mcd, "%*s", fsize, value_str);
465 use_count = 1;
466 break;
468 /* Print character */
469 case 'c':
470 case 'C':
471 if (fsize != -1 && ffsize != -1) {
472 format_error_msg("Illegal format", leading_zero,
473 fsize, ffsize, fmt);
474 fsize = -1;
475 ffsize = -1;
478 if (idx >= argc) {
479 format_error_msg("Missing Argument", leading_zero,
480 fsize, ffsize, fmt);
481 return 0;
484 value.format = vpiStringVal;
485 vpi_get_value(argv[idx], &value);
486 if (value.format == vpiSuppressVal){
487 format_error_msg("Incompatible value", leading_zero,
488 fsize, ffsize, fmt);
489 return 1;
492 my_mcd_printf(mcd, "%c", value.value.str[strlen(value.value.str)-1]);
494 use_count = 1;
495 break;
497 /* Print numeric value is decimal integer format. */
498 case 'd':
499 case 'D':
500 if (ffsize != -1) {
501 format_error_msg("Illegal format", leading_zero,
502 fsize, ffsize, fmt);
503 fsize = -1;
506 if (idx >= argc) {
507 format_error_msg("Missing Argument", leading_zero,
508 fsize, ffsize, fmt);
509 return 0;
512 value.format = vpiDecStrVal;
513 vpi_get_value(argv[idx], &value);
514 if (value.format == vpiSuppressVal){
515 format_error_msg("Incompatible value", leading_zero,
516 fsize, ffsize, fmt);
517 return 1;
520 if (fsize==-1){
521 // simple %d parameter, or %0d parameter.
522 // Size is now determined by the width
523 // of the vector or integer. If %0d, then
524 // set the size to 0 so that the minimum
525 // size is used.
526 fsize = (leading_zero==1)
528 : vpi_get_dec_size(argv[idx]);
531 my_mcd_printf(mcd, "%*s", fsize, value.value.str);
533 use_count = 1;
534 break;
536 case 'e':
537 case 'E':
538 if (idx >= argc) {
539 format_error_msg("Missing Argument", leading_zero,
540 fsize, ffsize, fmt);
541 return 0;
544 value.format = vpiRealVal;
545 vpi_get_value(argv[idx], &value);
546 if (value.format == vpiSuppressVal){
547 format_error_msg("Incompatible value", leading_zero,
548 fsize, ffsize, fmt);
549 return 1;
552 if (fmt == 'e')
553 my_mcd_printf(mcd, "%*.*e", fsize, ffsize, value.value.real);
554 else
555 my_mcd_printf(mcd, "%*.*E", fsize, ffsize, value.value.real);
557 use_count = 1;
558 break;
560 case 'f':
561 case 'F':
562 if (idx >= argc) {
563 format_error_msg("Missing Argument", leading_zero,
564 fsize, ffsize, fmt);
565 return 0;
568 value.format = vpiRealVal;
569 vpi_get_value(argv[idx], &value);
570 if (value.format == vpiSuppressVal){
571 format_error_msg("Incompatible value", leading_zero,
572 fsize, ffsize, fmt);
573 return 1;
576 my_mcd_printf(mcd, "%*.*f", fsize, ffsize, value.value.real);
578 use_count = 1;
579 break;
581 case 'g':
582 case 'G':
583 if (idx >= argc) {
584 format_error_msg("Missing Argument", leading_zero,
585 fsize, ffsize, fmt);
586 return 0;
589 value.format = vpiRealVal;
590 vpi_get_value(argv[idx], &value);
591 if (value.format == vpiSuppressVal){
592 format_error_msg("Incompatible value", leading_zero,
593 fsize, ffsize, fmt);
594 return 1;
597 if (fmt == 'g')
598 my_mcd_printf(mcd, "%*.*g", fsize, ffsize, value.value.real);
599 else
600 my_mcd_printf(mcd, "%*.*G", fsize, ffsize, value.value.real);
602 use_count = 1;
603 break;
605 /* Print the current scope. */
606 case 'm':
607 case 'M':
608 if (ffsize != -1) {
609 format_error_msg("Illegal format", leading_zero,
610 fsize, ffsize, fmt);
611 fsize = -1;
613 if (fsize == -1)
614 fsize = 0;
615 assert(scope);
616 my_mcd_printf(mcd, "%*s",
617 fsize,
618 vpi_get_str(vpiFullName, scope));
619 break;
622 /* Print vector as a string value. */
623 case 's':
624 case 'S':
625 if (ffsize != -1) {
626 format_error_msg("Illegal format", leading_zero,
627 fsize, ffsize, fmt);
628 fsize = -1;
631 value.format = vpiStringVal;
632 vpi_get_value(argv[idx], &value);
633 if (value.format == vpiSuppressVal){
634 format_error_msg("Incompatible value", leading_zero,
635 fsize, ffsize, fmt);
636 return 1;
639 if (fsize==-1){
640 fsize = (vpi_get(vpiSize, argv[idx]) + 7) / 8;
641 my_mcd_printf(mcd, "%*s", fsize, value.value.str);
643 } else {
644 char* value_str = value.value.str;
645 my_mcd_printf(mcd, "%*s", fsize, value_str);
648 use_count = 1;
649 break;
651 case 't':
652 case 'T':
653 if (ffsize != -1) {
654 format_error_msg("Illegal format", leading_zero,
655 fsize, ffsize, fmt);
656 fsize = -1;
659 if (idx >= argc) {
660 format_error_msg("Missing Argument", leading_zero,
661 fsize, ffsize, fmt);
662 return 0;
665 if (is_constant(argv[idx])
666 && (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) {
668 value.format = vpiRealVal;
669 vpi_get_value(argv[idx], &value);
670 format_time_real(mcd, fsize, value.value.real, time_units);
672 } else {
674 value.format = vpiDecStrVal;
675 vpi_get_value(argv[idx], &value);
676 if (value.format == vpiSuppressVal){
677 format_error_msg("Incompatible value", leading_zero,
678 fsize, ffsize, fmt);
679 return 1;
682 format_time(mcd, fsize, value.value.str, time_units);
685 use_count = 1;
686 break;
688 case 'v':
689 case 'V':
690 value.format = vpiStrengthVal;
691 vpi_get_value(argv[idx], &value);
692 if (value.format == vpiSuppressVal){
693 format_error_msg("Incompatible value", leading_zero,
694 fsize, ffsize, fmt);
695 return 1;
698 format_strength(mcd, &value);
700 use_count = 1;
701 break;
705 return use_count;
709 * If $display discovers a string as a parameter, this function is
710 * called to process it as a format string. I need the argv handle as
711 * well so that I can look for arguments as I move forward through the
712 * string.
714 static int format_str(vpiHandle scope, unsigned int mcd,
715 char*format, int argc, vpiHandle*argv)
717 char buf[256], fmt[256];
718 char*cp = fmt;
719 int idx;
721 assert(format);
724 * Copy format out of value buffer since it will be
725 * clobbered by successive vpi_get_value() calls.
727 strncpy(fmt, format, sizeof fmt - 1);
728 fmt[sizeof fmt - 1] = 0;
730 idx = 0;
732 while (*cp) {
733 size_t cnt = strcspn(cp, "%");
734 if (cnt > 0) {
735 /* String of not-escape characters... */
736 if (cnt >= sizeof buf)
737 cnt = sizeof buf - 1;
738 strncpy(buf, cp, cnt);
739 buf[cnt] = 0;
740 my_mcd_printf(mcd, "%s", buf);
741 cp += cnt;
743 } else {
744 int leading_zero = -1, ljust = 1, fsize = -1, ffsize = -1;
746 assert(*cp == '%');
747 cp += 1;
748 if (*cp == '-') {
749 ljust=-1;
750 cp += 1;
752 if (*cp == '0')
753 leading_zero=1;
754 if (isdigit((int)*cp))
755 fsize = ljust * strtoul(cp, &cp, 10);
756 if (*cp == '.') {
757 cp += 1;
758 ffsize = strtoul(cp, &cp, 10);
761 idx += format_str_char(scope, mcd, leading_zero,
762 fsize, ffsize, *cp,
763 argc, argv, idx);
764 cp += 1;
769 return idx;
772 static void do_display_numeric(unsigned int mcd,
773 struct strobe_cb_info*info,
774 vpiHandle item)
776 int size;
777 s_vpi_value value;
779 value.format = info->default_format;
780 vpi_get_value(item, &value);
782 switch(info->default_format){
783 case vpiDecStrVal:
784 size = vpi_get_dec_size(item);
785 my_mcd_printf(mcd, "%*s", size, value.value.str);
786 break;
788 default:
789 my_mcd_printf(mcd, "%s", value.value.str);
793 static void do_display(unsigned int mcd, struct strobe_cb_info*info)
795 char*fmt;
796 s_vpi_value value;
797 unsigned int idx;
799 for (idx = 0 ; idx < info->nitems ; idx += 1) {
800 vpiHandle item = info->items[idx];
802 switch (vpi_get(vpiType, item)) {
804 case 0:
805 my_mcd_printf(mcd, " ");
806 break;
808 case vpiConstant:
809 case vpiParameter:
810 if (vpi_get(vpiConstType, item) == vpiStringConst) {
811 value.format = vpiStringVal;
812 vpi_get_value(item, &value);
813 fmt = strdup(value.value.str);
814 idx += format_str(info->scope, mcd, fmt,
815 info->nitems-idx-1,
816 info->items+idx+1);
817 free(fmt);
818 } else {
819 do_display_numeric(mcd, info, item);
821 break;
823 case vpiNet:
824 case vpiReg:
825 case vpiIntegerVar:
826 case vpiMemoryWord:
827 do_display_numeric(mcd, info, item);
828 break;
830 case vpiTimeVar:
831 value.format = vpiTimeVal;
832 vpi_get_value(item, &value);
833 my_mcd_printf(mcd, "%20u", value.value.time->low);
834 break;
836 case vpiRealVar:
837 value.format = vpiRealVal;
838 vpi_get_value(item, &value);
839 my_mcd_printf(mcd, "%f", value.value.real);
840 break;
842 case vpiSysFuncCall: {
843 char*tmp = vpi_get_str(vpiName, item);
844 vpiHandle scope = vpi_handle(vpiScope, item);
846 if (strcmp(tmp,"$time") == 0 ||
847 strcmp(tmp,"$simtime") == 0) {
848 value.format = vpiTimeVal;
849 vpi_get_value(item, &value);
850 my_mcd_printf(mcd, "%20u", value.value.time->low);
851 } else if (strcmp(tmp,"$realtime") == 0) {
852 int time_units = vpi_get(vpiTimeUnit, scope);
853 int time_prec = vpi_get(vpiTimePrecision, 0);
854 int use_prec = time_units - time_prec;
855 if (use_prec < 0)
856 use_prec = 0;
858 value.format = vpiRealVal;
859 vpi_get_value(item, &value);
860 my_mcd_printf(mcd, "%0.*f", use_prec,
861 value.value.real);
862 } else {
863 my_mcd_printf(mcd, "<%s>", tmp);
865 break;
868 default:
869 my_mcd_printf(mcd, "?");
870 break;
875 static int get_default_format(char *name)
877 int default_format;
879 switch(name[ strlen(name)-1 ]){
880 // writE/strobE or monitoR or displaY/fdisplaY or sformaT
881 case 'e':
882 case 'r':
883 case 't':
884 case 'y': default_format = vpiDecStrVal; break;
885 case 'h': default_format = vpiHexStrVal; break;
886 case 'o': default_format = vpiOctStrVal; break;
887 case 'b': default_format = vpiBinStrVal; break;
888 default:
889 assert(0);
892 return default_format;
895 static PLI_INT32 sys_display_calltf(PLI_BYTE8*name)
897 struct strobe_cb_info*info;
898 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
900 info = vpi_get_userdata(sys);
901 if (info == 0) {
902 vpiHandle scope = vpi_handle(vpiScope, sys);
903 vpiHandle argv = vpi_iterate(vpiArgument, sys);
905 assert(scope);
906 info = malloc(sizeof (struct strobe_cb_info));
907 info->default_format = get_default_format(name);
908 info->scope = scope;
909 array_from_iterator(info, argv);
911 vpi_put_userdata(sys, info);
914 do_display(1, info);
916 if (strncmp(name,"$display",8) == 0)
917 my_mcd_printf(1, "\n");
919 return 0;
923 * The strobe implementation takes the parameter handles that are
924 * passed to the calltf and puts them in to an array for safe
925 * keeping. That array (and other bookkeeping) is passed, via the
926 * struct_cb_info object, to the REadOnlySych function strobe_cb,
927 * where it is use to perform the actual formatting and printing.
930 static PLI_INT32 strobe_cb(p_cb_data cb)
932 struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
934 do_display(info->mcd, info);
935 my_mcd_printf(info->mcd, "\n");
937 free(info->name);
938 free(info->items);
939 free(info);
941 return 0;
944 static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name)
946 struct t_cb_data cb;
947 struct t_vpi_time time;
949 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
950 vpiHandle scope = vpi_handle(vpiScope, sys);
952 vpiHandle argv = vpi_iterate(vpiArgument, sys);
954 struct strobe_cb_info*info = calloc(1, sizeof(struct strobe_cb_info));
955 if(name[1] == 'f') {
956 vpiHandle item = vpi_scan(argv);
957 int type;
958 s_vpi_value value;
960 if (item == 0) {
961 vpi_printf("%s: mcd parameter missing.\n", name);
962 return 0;
965 type = vpi_get(vpiType, item);
966 switch (type) {
967 case vpiReg:
968 case vpiRealVar:
969 case vpiIntegerVar:
970 case vpiNet:
971 break;
973 case vpiConstant:
974 switch (vpi_get(vpiConstType, item)) {
975 case vpiDecConst:
976 case vpiBinaryConst:
977 case vpiOctConst:
978 case vpiHexConst:
979 break;
980 default:
981 vpi_printf("ERROR: %s mcd parameter must be integral", name);
982 vpi_printf(", got vpiType=vpiConstant, vpiConstType=%d\n",
983 vpi_get(vpiConstType, item));
984 vpi_free_object(argv);
985 return 0;
987 break;
989 default:
990 vpi_printf("ERROR: %s mcd parameter must be integral", name);
991 vpi_printf(", got vpiType=%d\n", type);
992 vpi_free_object(argv);
993 return 0;
995 value.format = vpiIntVal;
996 vpi_get_value(item, &value);
997 info->mcd = value.value.integer;
998 } else {
999 info->mcd = 1;
1002 array_from_iterator(info, argv);
1003 info->name = strdup(name);
1004 info->default_format = get_default_format(name);
1005 info->scope= scope;
1007 time.type = vpiSimTime;
1008 time.low = 0;
1009 time.high = 0;
1011 cb.reason = cbReadOnlySynch;
1012 cb.cb_rtn = strobe_cb;
1013 cb.time = &time;
1014 cb.obj = 0;
1015 cb.value = 0;
1016 cb.user_data = (char*)info;
1017 vpi_register_cb(&cb);
1018 return 0;
1022 * The $monitor system task works by managing these static variables,
1023 * and the cbValueChange callbacks associated with registers and
1024 * nets. Note that it is proper to keep the state in static variables
1025 * because there can only be one monitor at a time pending (even
1026 * though that monitor may be watching many variables).
1029 static struct strobe_cb_info monitor_info = { 0, 0, 0, 0, 0 };
1030 static vpiHandle *monitor_callbacks = 0;
1031 static int monitor_scheduled = 0;
1032 static int monitor_enabled = 1;
1034 static PLI_INT32 monitor_cb_2(p_cb_data cb)
1036 do_display(1, &monitor_info);
1037 vpi_printf("\n");
1038 monitor_scheduled = 0;
1039 return 0;
1043 * The monitor_cb_1 callback is called when an even occurs somewhere
1044 * in the simulation. All this function does is schedule the actual
1045 * display to occur in a ReadOnlySync callback. The monitor_scheduled
1046 * flag is used to allow only one monitor strobe to be scheduled.
1048 static PLI_INT32 monitor_cb_1(p_cb_data cause)
1050 struct t_cb_data cb;
1051 struct t_vpi_time time;
1053 if (monitor_enabled == 0) return 0;
1054 if (monitor_scheduled) return 0;
1056 /* This this action caused the first trigger, then schedule
1057 the monitor to happen at the end of the time slice and mark
1058 it as scheduled. */
1059 monitor_scheduled += 1;
1060 time.type = vpiSimTime;
1061 time.low = 0;
1062 time.high = 0;
1064 cb.reason = cbReadOnlySynch;
1065 cb.cb_rtn = monitor_cb_2;
1066 cb.time = &time;
1067 cb.obj = 0;
1068 cb.value = 0;
1069 vpi_register_cb(&cb);
1071 return 0;
1074 static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
1076 unsigned idx;
1077 struct t_cb_data cb;
1078 struct t_vpi_time time;
1080 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
1081 vpiHandle scope = vpi_handle(vpiScope, sys);
1082 vpiHandle argv = vpi_iterate(vpiArgument, sys);
1084 /* If there was a previous $monitor, then remove the calbacks
1085 related to it. */
1086 if (monitor_callbacks) {
1087 for (idx = 0 ; idx < monitor_info.nitems ; idx += 1)
1088 if (monitor_callbacks[idx])
1089 vpi_remove_cb(monitor_callbacks[idx]);
1091 free(monitor_callbacks);
1092 monitor_callbacks = 0;
1094 free(monitor_info.items);
1095 free(monitor_info.name);
1096 monitor_info.items = 0;
1097 monitor_info.nitems = 0;
1098 monitor_info.name = 0;
1101 /* Make an array of handles from the argument list. */
1102 array_from_iterator(&monitor_info, argv);
1103 monitor_info.name = strdup(name);
1104 monitor_info.default_format = get_default_format(name);
1105 monitor_info.scope = scope;
1107 /* Attach callbacks to all the parameters that might change. */
1108 monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle));
1110 time.type = vpiSuppressTime;
1111 cb.reason = cbValueChange;
1112 cb.cb_rtn = monitor_cb_1;
1113 cb.time = &time;
1114 cb.value = NULL;
1115 for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
1117 switch (vpi_get(vpiType, monitor_info.items[idx])) {
1118 case vpiNet:
1119 case vpiReg:
1120 case vpiIntegerVar:
1121 case vpiRealVar:
1122 /* Monitoring reg and net values involves setting
1123 a callback for value changes. pass the storage
1124 pointer for the callback itself as user_data so
1125 that the callback can refresh itself. */
1126 cb.user_data = (char*)(monitor_callbacks+idx);
1127 cb.obj = monitor_info.items[idx];
1128 monitor_callbacks[idx] = vpi_register_cb(&cb);
1129 break;
1134 /* When the $monitor is called, it schedules a first display
1135 for the end of the current time, like a $strobe. */
1136 monitor_cb_1(0);
1138 return 0;
1141 static PLI_INT32 sys_monitoron_calltf(PLI_BYTE8*name)
1143 monitor_enabled = 1;
1144 monitor_cb_1(0);
1145 return 0;
1148 static PLI_INT32 sys_monitoroff_calltf(PLI_BYTE8*name)
1150 monitor_enabled = 0;
1151 return 0;
1154 /* Implement $fdisplay and $fwrite.
1155 * Perhaps this could be merged into sys_display_calltf.
1157 static PLI_INT32 sys_fdisplay_calltf(PLI_BYTE8*name)
1159 struct strobe_cb_info info;
1160 unsigned int mcd;
1161 int type;
1162 s_vpi_value value;
1163 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
1164 vpiHandle scope = vpi_handle(vpiScope, sys);
1165 vpiHandle argv = vpi_iterate(vpiArgument, sys);
1166 vpiHandle item = vpi_scan(argv);
1168 if (item == 0) {
1169 vpi_printf("%s: mcd parameter missing.\n", name);
1170 return 0;
1173 type = vpi_get(vpiType, item);
1174 switch (type) {
1175 case vpiReg:
1176 case vpiRealVar:
1177 case vpiIntegerVar:
1178 case vpiNet:
1179 break;
1181 case vpiConstant:
1182 switch (vpi_get(vpiConstType, item)) {
1183 case vpiDecConst:
1184 case vpiBinaryConst:
1185 case vpiOctConst:
1186 case vpiHexConst:
1187 break;
1188 default:
1189 vpi_printf("ERROR: %s mcd parameter must be integral", name);
1190 vpi_printf(", got vpiType=vpiConstant, vpiConstType=%d\n",
1191 vpi_get(vpiConstType, item));
1192 vpi_free_object(argv);
1193 return 0;
1195 break;
1197 default:
1198 vpi_printf("ERROR: %s mcd parameter must be integral", name);
1199 vpi_printf(", got vpiType=%d\n", type);
1200 vpi_free_object(argv);
1201 return 0;
1204 value.format = vpiIntVal;
1205 vpi_get_value(item, &value);
1206 mcd = value.value.integer;
1208 assert(scope);
1209 info.default_format = get_default_format(name);
1210 info.scope = scope;
1211 array_from_iterator(&info, argv);
1212 do_display(mcd, &info);
1213 free(info.items);
1215 if (strncmp(name,"$fdisplay",9) == 0)
1216 my_mcd_printf(mcd, "\n");
1218 return 0;
1221 /* Build the format using the variables that control how the item will
1222 * be printed. This is used in error messages and directly by the e/f/g
1223 * format codes (minus the enclosing <>). The user needs to free the
1224 * returned string. */
1225 static char * format_as_string(int ljust, int plus, int ld_zero, int width,
1226 int prec, char fmt)
1228 char buf[256];
1229 unsigned int size = 0;
1231 buf[size++] = '<';
1232 buf[size++] = '%';
1233 if (ljust == 1) buf[size++] = '-';
1234 if (plus == 1) buf[size++] = '+';
1235 if (ld_zero == 1) buf[size++] = '0';
1236 if (width != -1)
1237 size += sprintf(&buf[size], "%d", width);
1238 if (prec != -1)
1239 size += sprintf(&buf[size], ".%d", prec);
1240 buf[size++] = fmt;
1241 /* Do not change this without also changing the e/f/g format code below! */
1242 buf[size++] = '>';
1243 buf[size] = '\0';
1244 return strdup(buf);
1247 static void get_time(char *rtn, const char *value, int prec,
1248 PLI_INT32 time_units)
1250 int head, tail;
1251 int shift = time_units - timeformat_info.units;
1253 /* Strip any leading zeros, but leave a single zero. */
1254 while (value[0] == '0' && value[1] != '\0') value += 1;
1255 /* We need to scale the number up. */
1256 if (shift >= 0) {
1257 strcpy(rtn, value);
1258 /* Shift only non-zero values. */
1259 while (shift > 0 && value[0] != '0') {
1260 strcat(rtn, "0");
1261 shift -= 1;
1263 if (prec > 0) strcat(rtn, ".");
1264 while(prec > 0) {
1265 strcat(rtn, "0");
1266 prec -= 1;
1269 /* We need to scale the number down. */
1270 } else {
1271 head = strlen(value) + shift;
1272 /* We have digits to the left of the decimal point. */
1273 if (head > 0) {
1274 strncpy(rtn, value, head);
1275 strcat(rtn, ".");
1276 strncat(rtn, &value[head], prec);
1277 tail = prec + shift;
1278 while (tail > 0) {
1279 strcat(rtn, "0");
1280 tail -= 1;
1282 /* All digits are to the right of the decimal point. */
1283 } else {
1284 strcpy(rtn, "0.");
1285 /* Add leading zeros as needed. */
1286 head = -shift - 1;
1287 if (head > prec) head = prec;
1288 while (head > 0) {
1289 strcat(rtn, "0");
1290 head -= 1;
1292 /* Add digits from the value if they fit. */
1293 tail = prec + shift + 1;
1294 strncat(rtn, value, tail);
1295 /* Add trailing zeros to fill out the precision. */
1296 tail = prec + shift + 1 - strlen(value);
1297 while (tail > 0) {
1298 strcat(rtn, "0");
1299 tail -= 1;
1304 strcat(rtn, timeformat_info.suff);
1307 static void get_time_real(char *rtn, double value, int prec,
1308 PLI_INT32 time_units)
1310 /* Scale the value if it's time units differ from the format units. */
1311 if (time_units != timeformat_info.units) {
1312 value *= pow(10.0, time_units - timeformat_info.units);
1314 sprintf(rtn, "%0.*f%s", prec, value, timeformat_info.suff);
1317 static unsigned int get_format_char(char **rtn, int ljust, int plus,
1318 int ld_zero, int width, int prec,
1319 char fmt, struct strobe_cb_info *info,
1320 unsigned int *idx)
1322 s_vpi_value value;
1323 char *result, *fmtb;
1324 unsigned int size;
1325 unsigned int max_size = 256; /* The initial size of the buffer. */
1327 /* The default return value is the full format. */
1328 result = malloc(max_size*sizeof(char));
1329 fmtb = format_as_string(ljust, plus, ld_zero, width, prec, fmt);
1330 strcpy(result, fmtb);
1331 switch (fmt) {
1333 case '%':
1334 if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
1335 prec != -1) {
1336 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1338 strcpy(result, "%");
1339 size = strlen(result) + 1;
1340 break;
1342 case 'b':
1343 case 'B':
1344 case 'o':
1345 case 'O':
1346 case 'h':
1347 case 'H':
1348 case 'x':
1349 case 'X':
1350 *idx += 1;
1351 if (plus != 0 || prec != -1) {
1352 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1354 if (*idx >= info->nitems) {
1355 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1356 } else {
1357 switch (fmt) {
1358 case 'b':
1359 case 'B':
1360 value.format = vpiBinStrVal;
1361 break;
1362 case 'o':
1363 case 'O':
1364 value.format = vpiOctStrVal;
1365 break;
1366 case 'h':
1367 case 'H':
1368 case 'x':
1369 case 'X':
1370 value.format = vpiHexStrVal;
1371 break;
1373 vpi_get_value(info->items[*idx], &value);
1374 if (value.format == vpiSuppressVal) {
1375 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1376 fmtb);
1377 } else {
1378 char *cp;
1380 /* If a width was not given use a width of zero. */
1381 if (width == -1) width = 0;
1382 /* Strip the leading zeros. */
1383 cp = value.value.str;
1384 if (ld_zero == 1) {
1385 while (*cp == '0') cp++;
1387 /* If the (default buffer is too small make it big enough. */
1388 size = strlen(cp) + 1;
1389 if (size > max_size) result = realloc(result, size*sizeof(char));
1391 if (ljust == 0) sprintf(result, "%*s", width, cp);
1392 else sprintf(result, "%-*s", width, cp);
1395 size = strlen(result) + 1;
1396 break;
1398 case 'c':
1399 case 'C':
1400 *idx += 1;
1401 if (plus != 0 || prec != -1) {
1402 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1404 if (*idx >= info->nitems) {
1405 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1406 } else {
1407 value.format = vpiStringVal;
1408 vpi_get_value(info->items[*idx], &value);
1409 if (value.format == vpiSuppressVal) {
1410 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1411 fmtb);
1412 } else {
1413 /* If a width was not given use a width of zero. */
1414 if (width == -1) width = 0;
1415 if (ljust == 0) sprintf(result, "%*c", width,
1416 value.value.str[strlen(value.value.str)-1]);
1417 else sprintf(result, "%-*c", width,
1418 value.value.str[strlen(value.value.str)-1]);
1421 size = strlen(result) + 1;
1422 break;
1424 case 'd':
1425 case 'D':
1426 *idx += 1;
1427 if (prec != -1) {
1428 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1430 if (*idx >= info->nitems) {
1431 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1432 } else {
1433 value.format = vpiDecStrVal;
1434 vpi_get_value(info->items[*idx], &value);
1435 if (value.format == vpiSuppressVal) {
1436 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1437 fmtb);
1438 } else {
1439 char *tbuf;
1441 /* If a width was not given use the default unless we have a
1442 * leading zero (width of zero). */
1443 if (width == -1) {
1444 width = (ld_zero == 1) ? 0: vpi_get_dec_size(info->items[*idx]);
1446 size = strlen(value.value.str) + 1 + plus;
1447 /* Insert a plus sign if needed. */
1448 tbuf = malloc(size*sizeof(char));
1449 if (plus == 1 && value.value.str[0] != '-') {
1450 tbuf[0] = '+';
1451 strcpy(&tbuf[1], value.value.str);
1452 } else strcpy(&tbuf[0], value.value.str);
1453 /* If the (default buffer is too small make it big enough. */
1454 if (size > max_size) result = realloc(result, size*sizeof(char));
1455 if (ljust == 0) sprintf(result, "%*s", width, tbuf);
1456 else sprintf(result, "%-*s", width, tbuf);
1457 free(tbuf);
1460 size = strlen(result) + 1;
1461 break;
1463 case 'e':
1464 case 'E':
1465 case 'f':
1466 case 'F':
1467 case 'g':
1468 case 'G':
1469 *idx += 1;
1470 if (*idx >= info->nitems) {
1471 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1472 } else {
1473 value.format = vpiRealVal;
1474 vpi_get_value(info->items[*idx], &value);
1475 if (value.format == vpiSuppressVal) {
1476 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1477 fmtb);
1478 } else {
1479 char *cp = fmtb;
1481 if (fmt == 'F') {
1482 while (*cp != 'F') cp++;
1483 *cp = 'f';
1485 while (*cp != '>') cp++;
1486 *cp = '\0';
1487 sprintf(result, fmtb+1, value.value.real);
1490 size = strlen(result) + 1;
1491 break;
1493 /* This Verilog format specifier is not currently supported!
1494 * vpiCell and vpiLibrary need to be implemented first. */
1495 case 'l':
1496 case 'L':
1497 vpi_printf("WARNING: %%%c currently unsupported %s%s.\n", fmt,
1498 info->name, fmtb);
1499 size = strlen(result) + 1;
1500 break;
1502 case 'm':
1503 case 'M':
1504 if (plus != 0 || prec != -1) {
1505 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1507 /* If a width was not given use a width of zero. */
1508 if (width == -1) width = 0;
1509 if (ljust == 0) sprintf(result, "%*s", width,
1510 vpi_get_str(vpiFullName, info->scope));
1511 else sprintf(result, "%-*s", width,
1512 vpi_get_str(vpiFullName, info->scope));
1513 size = strlen(result) + 1;
1514 break;
1516 case 's':
1517 case 'S':
1518 *idx += 1;
1519 if (plus != 0 || prec != -1) {
1520 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1522 if (*idx >= info->nitems) {
1523 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1524 } else {
1525 value.format = vpiStringVal;
1526 vpi_get_value(info->items[*idx], &value);
1527 if (value.format == vpiSuppressVal) {
1528 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1529 fmtb);
1530 } else {
1531 /* If a width was not given use a width of zero. */
1532 if (width == -1) width = 0;
1533 /* If the (default buffer is too small make it big enough. */
1534 size = strlen(value.value.str) + 1;
1535 if (size > max_size) result = realloc(result, size*sizeof(char));
1536 if (ljust == 0) sprintf(result, "%*s", width, value.value.str);
1537 else sprintf(result, "%-*s", width, value.value.str);
1540 size = strlen(result) + 1;
1541 break;
1543 case 't':
1544 case 'T':
1545 *idx += 1;
1546 if (plus != 0) {
1547 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1549 if (*idx >= info->nitems) {
1550 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1551 } else {
1552 char tbuf[256];
1553 PLI_INT32 type;
1554 PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope);
1556 type = vpi_get(vpiType, info->items[*idx]);
1557 if (width == -1) width = timeformat_info.width;
1558 if (ld_zero == 1) width = 0;
1559 if (prec == -1) prec = timeformat_info.prec;
1560 /* Is it some type of real value? */
1561 if (((type == vpiConstant || type == vpiParameter) &&
1562 vpi_get(vpiConstType, info->items[*idx]) == vpiRealConst) ||
1563 type == vpiRealVar ) {
1564 value.format = vpiRealVal;
1565 vpi_get_value(info->items[*idx], &value);
1566 if (value.format == vpiSuppressVal) {
1567 vpi_printf("WARNING: incompatible value for %s%s.\n",
1568 info->name, fmtb);
1569 } else {
1570 get_time_real(tbuf, value.value.real, prec, time_units);
1571 if (ljust == 0) sprintf(result, "%*s", width, tbuf);
1572 else sprintf(result, "%-*s", width, tbuf);
1574 } else {
1575 value.format = vpiDecStrVal;
1576 vpi_get_value(info->items[*idx], &value);
1577 if (value.format == vpiSuppressVal) {
1578 vpi_printf("WARNING: incompatible value for %s%s.\n",
1579 info->name, fmtb);
1580 } else {
1581 get_time(tbuf, value.value.str, prec, time_units);
1582 if (ljust == 0) sprintf(result, "%*s", width, tbuf);
1583 else sprintf(result, "%-*s", width, tbuf);
1587 size = strlen(result) + 1;
1588 break;
1590 case 'u':
1591 case 'U':
1592 *idx += 1;
1593 if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
1594 prec != -1) {
1595 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1597 if (*idx >= info->nitems) {
1598 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1599 } else {
1600 value.format = vpiVectorVal;
1601 vpi_get_value(info->items[*idx], &value);
1602 if (value.format == vpiSuppressVal) {
1603 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1604 fmtb);
1605 } else {
1606 PLI_INT32 veclen, word, byte, bits;
1607 char *cp;
1609 veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
1610 size = veclen * 4 + 1;
1611 /* If the (default buffer is too small make it big enough. */
1612 if (size > max_size) result = realloc(result, size*sizeof(char));
1613 cp = result;
1614 for (word = 0; word < veclen; word += 1) {
1615 bits = value.value.vector[word].aval &
1616 ~value.value.vector[word].bval;
1617 #ifdef WORDS_BIGENDIAN
1618 for (byte = 3; byte >= 0; byte -= 1) {
1619 #else
1620 for (byte = 0; byte <= 3; byte += 1) {
1621 #endif
1622 *cp = (bits >> byte*8) & 0xff;
1623 cp += 1;
1626 *cp = '\0';
1629 /* size is defined above! We can't use strlen here since this can
1630 * be a binary string (can contain NULLs). */
1631 break;
1633 case 'v':
1634 case 'V':
1635 *idx += 1;
1636 if (plus != 0 || prec != -1) {
1637 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1639 if (*idx >= info->nitems) {
1640 vpi_printf("WARNING: missing argument for %s%s.\n", info->name,
1641 fmtb);
1642 } else {
1643 value.format = vpiStrengthVal;
1644 vpi_get_value(info->items[*idx], &value);
1645 if (value.format == vpiSuppressVal) {
1646 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1647 fmtb);
1648 } else {
1649 char tbuf[4];
1651 /* If a width was not given use a width of zero. */
1652 if (width == -1) width = 0;
1653 vpip_format_strength(tbuf, &value);
1654 if (ljust == 0) sprintf(result, "%*s", width, tbuf);
1655 else sprintf(result, "%-*s", width, tbuf);
1658 size = strlen(result) + 1;
1659 break;
1661 case 'z':
1662 case 'Z':
1663 *idx += 1;
1664 if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 ||
1665 prec != -1) {
1666 vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb);
1668 if (*idx >= info->nitems) {
1669 vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb);
1670 } else {
1671 value.format = vpiVectorVal;
1672 vpi_get_value(info->items[*idx], &value);
1673 if (value.format == vpiSuppressVal) {
1674 vpi_printf("WARNING: incompatible value for %s%s.\n", info->name,
1675 fmtb);
1676 } else {
1677 PLI_INT32 veclen, word, elem, bits, byte;
1678 char *cp;
1680 veclen = (vpi_get(vpiSize, info->items[*idx])+31)/32;
1681 size = 2 * veclen * 4 + 1;
1682 /* If the (default buffer is too small make it big enough. */
1683 if (size > max_size) result = realloc(result, size*sizeof(char));
1684 cp = result;
1685 for (word = 0; word < veclen; word += 1) {
1686 /* Write the aval followed by the bval in endian order. */
1687 for (elem = 0; elem < 2; elem += 1) {
1688 bits = *(&value.value.vector[word].aval+elem);
1689 #ifdef WORDS_BIGENDIAN
1690 for (byte = 3; byte >= 0; byte -= 1) {
1691 #else
1692 for (byte = 0; byte <= 3; byte += 1) {
1693 #endif
1694 *cp = (bits >> byte*8) & 0xff;
1695 cp += 1;
1699 *cp = '\0';
1702 /* size is defined above! We can't use strlen here since this can
1703 * be a binary string (can contain NULLs). */
1704 break;
1706 default:
1707 vpi_printf("WARNING: unknown format %s%s.\n", info->name, fmtb);
1708 size = strlen(result) + 1;
1709 break;
1711 free(fmtb);
1712 /* We can't use strdup her since %u and %z can insert NULL
1713 * characters into the stream. */
1714 *rtn = malloc(size*sizeof(char));
1715 memcpy(*rtn, result, size);
1716 return size - 1;
1719 /* We can't use the normal str functions on the return value since
1720 * %u and %z can insert NULL characters into the stream. */
1721 static unsigned int get_format(char **rtn, char *fmt,
1722 struct strobe_cb_info *info, unsigned int *idx)
1724 char *cp = fmt;
1725 unsigned int size;
1727 *rtn = strdup("");
1728 size = 1;
1729 while (*cp) {
1730 size_t cnt = strcspn(cp, "%");
1732 if (cnt > 0) {
1733 *rtn = realloc(*rtn, (size+cnt)*sizeof(char));
1734 memcpy(*rtn+size-1, cp, cnt);
1735 size += cnt;
1736 cp += cnt;
1737 } else {
1738 int cnt, ljust = 0, plus = 0, ld_zero = 0, width = -1, prec = -1;
1739 char *result;
1741 cp += 1;
1742 while ((*cp == '-') || (*cp == '+')) {
1743 if (*cp == '-') ljust = 1;
1744 else plus = 1;
1745 cp += 1;
1747 if (*cp == '0') ld_zero = 1;
1748 if (isdigit((int)*cp)) width = strtoul(cp, &cp, 10);
1749 if (*cp == '.') {
1750 cp += 1;
1751 prec = strtoul(cp, &cp, 10);
1753 cnt = get_format_char(&result, ljust, plus, ld_zero, width, prec, *cp,
1754 info, idx);
1755 *rtn = realloc(*rtn, (size+cnt)*sizeof(char));
1756 memcpy(*rtn+size-1, result, cnt);
1757 free(result);
1758 size += cnt;
1759 cp += 1;
1762 *(*rtn+size-1) = '\0';
1763 return size - 1;
1766 static unsigned int get_numeric(char **rtn, struct strobe_cb_info *info,
1767 vpiHandle item)
1769 s_vpi_value value;
1771 value.format = info->default_format;
1772 vpi_get_value(item, &value);
1773 *rtn = strdup(value.value.str);
1775 return strlen(*rtn);
1778 /* In many places we can't use the normal str functions since %u and %z
1779 * can insert NULL characters into the stream. */
1780 static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info)
1782 char *result, *fmt, *rtn, *func_name;
1783 s_vpi_value value;
1784 unsigned int idx, size, width;
1785 char buf[256];
1787 rtn = strdup("");
1788 size = 1;
1789 for (idx = 0; idx < info->nitems; idx += 1) {
1790 vpiHandle item = info->items[idx];
1792 switch (vpi_get(vpiType, item)) {
1794 case vpiConstant:
1795 case vpiParameter:
1796 if (vpi_get(vpiConstType, item) == vpiStringConst) {
1797 value.format = vpiStringVal;
1798 vpi_get_value(item, &value);
1799 fmt = strdup(value.value.str);
1800 width = get_format(&result, fmt, info, &idx);
1801 free(fmt);
1802 } else {
1803 width = get_numeric(&result, info, item);
1805 rtn = realloc(rtn, (size+width)*sizeof(char));
1806 memcpy(rtn+size-1, result, width);
1807 free(result);
1808 break;
1810 case vpiNet:
1811 case vpiReg:
1812 case vpiIntegerVar:
1813 case vpiMemoryWord:
1814 width = get_numeric(&result, info, item);
1815 rtn = realloc(rtn, (size+width)*sizeof(char));
1816 memcpy(rtn+size-1, result, width);
1817 free(result);
1818 break;
1820 /* It appears that this is not currently used! A time variable is
1821 passed as an integer and processed above. Hence this code has
1822 only been visually checked. */
1823 case vpiTimeVar:
1824 value.format = vpiDecStrVal;
1825 vpi_get_value(item, &value);
1826 get_time(buf, value.value.str, timeformat_info.prec,
1827 vpi_get(vpiTimeUnit, info->scope));
1828 width = strlen(buf);
1829 if (width < timeformat_info.width) width = timeformat_info.width;
1830 rtn = realloc(rtn, (size+width)*sizeof(char));
1831 sprintf(rtn+size-1, "%*s", width, buf);
1832 break;
1834 /* Realtime variables are also processed here. */
1835 case vpiRealVar:
1836 value.format = vpiRealVal;
1837 vpi_get_value(item, &value);
1838 sprintf(buf, "%g", value.value.real);
1839 width = strlen(buf);
1840 rtn = realloc(rtn, (size+width)*sizeof(char));
1841 memcpy(rtn+size-1, buf, width);
1842 break;
1844 case vpiSysFuncCall:
1845 func_name = vpi_get_str(vpiName, item);
1846 /* This also gets the $stime function! */
1847 if (strcmp(func_name, "$time") == 0) {
1848 value.format = vpiDecStrVal;
1849 vpi_get_value(item, &value);
1850 get_time(buf, value.value.str, timeformat_info.prec,
1851 vpi_get(vpiTimeUnit, info->scope));
1852 width = strlen(buf);
1853 if (width < timeformat_info.width) width = timeformat_info.width;
1854 rtn = realloc(rtn, (size+width)*sizeof(char));
1855 sprintf(rtn+size-1, "%*s", width, buf);
1857 } else if (strcmp(func_name, "$simtime") == 0) {
1858 value.format = vpiDecStrVal;
1859 vpi_get_value(item, &value);
1860 /* $simtime does not need to be scaled. */
1861 get_time(buf, value.value.str, timeformat_info.prec,
1862 timeformat_info.units);
1863 width = strlen(buf);
1864 if (width < timeformat_info.width) width = timeformat_info.width;
1865 rtn = realloc(rtn, (size+width)*sizeof(char));
1866 sprintf(rtn+size-1, "%*s", width, buf);
1868 } else if (strcmp(func_name, "$realtime") == 0) {
1869 value.format = vpiRealVal;
1870 vpi_get_value(item, &value);
1871 get_time_real(buf, value.value.real, timeformat_info.prec,
1872 vpi_get(vpiTimeUnit, info->scope));
1873 width = strlen(buf);
1874 if (width < timeformat_info.width) width = timeformat_info.width;
1875 rtn = realloc(rtn, (size+width)*sizeof(char));
1876 sprintf(rtn+size-1, "%*s", width, buf);
1878 } else {
1879 vpi_printf("WARNING: %s does not support %s as an argument!\n",
1880 info->name, func_name);
1881 strcpy(buf, "<?>");
1882 width = strlen(buf);
1883 rtn = realloc(rtn, (size+width)*sizeof(char));
1884 memcpy(rtn+size-1, buf, width);
1886 break;
1888 default:
1889 vpi_printf("WARNING: unknown argument type (%d) given to %s!\n",
1890 vpi_get(vpiType, item), info->name);
1891 result = "<?>";
1892 width = strlen(result);
1893 rtn = realloc(rtn, (size+width)*sizeof(char));
1894 memcpy(rtn+size-1, result, width);
1895 break;
1897 size += width;
1899 rtn[size-1] = '\0';
1900 *rtnsz = size - 1;
1901 return rtn;
1904 static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name)
1906 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
1907 vpiHandle argv = vpi_iterate(vpiArgument, callh);
1908 vpiHandle reg;
1910 /* Check that there are arguments. */
1911 if (argv == 0) {
1912 vpi_printf("ERROR: %s requires at least one argument.\n", name);
1913 vpi_control(vpiFinish, 1);
1914 return 0;
1917 /* The first argument must be a register. */
1918 reg = vpi_scan(argv); //* This should never be zero. */
1919 if (vpi_get(vpiType, reg) != vpiReg) {
1920 vpi_printf("ERROR: %s's first argument must be a register.\n", name);
1921 vpi_control(vpiFinish, 1);
1922 return 0;
1925 vpi_free_object(argv);
1926 return 0;
1929 static PLI_INT32 sys_swrite_calltf(PLI_BYTE8 *name)
1931 vpiHandle callh, argv, reg, scope;
1932 struct strobe_cb_info info;
1933 s_vpi_value val;
1934 unsigned int size;
1936 callh = vpi_handle(vpiSysTfCall, 0);
1937 argv = vpi_iterate(vpiArgument, callh);
1938 reg = vpi_scan(argv);
1940 scope = vpi_handle(vpiScope, callh);
1941 assert(scope);
1942 /* We could use vpi_get_str(vpiName, callh) to get the task name, but
1943 * name is already defined. */
1944 info.name = name;
1945 info.default_format = get_default_format(name);
1946 info.scope = scope;
1947 array_from_iterator(&info, argv);
1949 /* Because %u and %z may put embedded NULL characters into the returned
1950 * string strlen() may not match the real size! */
1951 val.value.str = get_display(&size, &info);
1952 val.format = vpiStringVal;
1953 vpi_put_value(reg, &val, 0, vpiNoDelay);
1954 if (size != strlen(val.value.str)) {
1955 vpi_printf("WARNING: %s returned a value with an embedded NULL "
1956 "(see %%u/%%z).\n", name);
1959 free(info.items);
1960 return 0;
1963 static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name)
1965 vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
1966 vpiHandle argv = vpi_iterate(vpiArgument, callh);
1967 vpiHandle arg;
1968 PLI_INT32 type;
1970 /* Check that there are arguments. */
1971 if (argv == 0) {
1972 vpi_printf("ERROR: %s requires at least two argument.\n", name);
1973 vpi_control(vpiFinish, 1);
1974 return 0;
1977 /* The first argument must be a register. */
1978 arg = vpi_scan(argv); //* This should never be zero. */
1979 if (vpi_get(vpiType, arg) != vpiReg) {
1980 vpi_printf("ERROR: %s's first argument must be a register.\n", name);
1981 vpi_control(vpiFinish, 1);
1982 return 0;
1985 /* The second argument must be a string or a register. */
1986 arg = vpi_scan(argv);
1987 if (arg == 0) {
1988 vpi_printf("ERROR: %s requires at least two argument.\n", name);
1989 vpi_control(vpiFinish, 1);
1990 return 0;
1992 type = vpi_get(vpiType, arg);
1993 if (((type != vpiConstant && type != vpiParameter) ||
1994 vpi_get(vpiConstType, arg) != vpiStringConst) && type != vpiReg) {
1995 vpi_printf("ERROR: %s's second argument must be a string or a register.\n",
1996 name);
1997 vpi_control(vpiFinish, 1);
1998 return 0;
2001 vpi_free_object(argv);
2002 return 0;
2005 static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name)
2007 vpiHandle callh, argv, reg, scope;
2008 struct strobe_cb_info info;
2009 s_vpi_value val;
2010 char *result, *fmt;
2011 unsigned int idx, size;
2013 callh = vpi_handle(vpiSysTfCall, 0);
2014 argv = vpi_iterate(vpiArgument, callh);
2015 reg = vpi_scan(argv);
2016 val.format = vpiStringVal;
2017 vpi_get_value(vpi_scan(argv), &val);
2018 fmt = strdup(val.value.str);
2020 scope = vpi_handle(vpiScope, callh);
2021 assert(scope);
2022 /* We could use vpi_get_str(vpiName, callh) to get the task name, but
2023 * name is already defined. */
2024 info.name = name;
2025 info.default_format = get_default_format(name);
2026 info.scope = scope;
2027 array_from_iterator(&info, argv);
2028 idx = -1;
2029 size = get_format(&result, fmt, &info, &idx);
2030 free(fmt);
2032 if (idx+1< info.nitems) {
2033 vpi_printf("WARNING: %s has %d extra argument(s).\n", name,
2034 info.nitems-idx-1);
2037 val.value.str = result;
2038 val.format = vpiStringVal;
2039 vpi_put_value(reg, &val, 0, vpiNoDelay);
2040 if (size != strlen(val.value.str)) {
2041 vpi_printf("WARNING: %s returned a value with an embedded NULL "
2042 "(see %%u/%%z).\n", name);
2045 free(info.items);
2046 return 0;
2049 static PLI_INT32 sys_end_of_compile(p_cb_data cb_data)
2051 /* The default timeformat prints times in unit of simulation
2052 precision. */
2053 timeformat_info.suff = strdup("");
2054 timeformat_info.units = vpi_get(vpiTimePrecision, 0);
2055 timeformat_info.prec = 0;
2056 timeformat_info.width = 20;
2057 return 0;
2060 static PLI_INT32 sys_timeformat_compiletf(PLI_BYTE8*xx)
2062 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
2063 vpiHandle argv = vpi_iterate(vpiArgument, sys);
2064 vpiHandle tmp;
2065 int lp;
2067 if (argv) {
2068 for (lp=0; lp<4; lp++) {
2069 tmp = vpi_scan(argv);
2070 if (tmp) {
2071 if (vpi_get(vpiType, tmp) != vpiConstant) {
2072 vpi_printf("$timeformat's arguments must be");
2073 vpi_printf(" constant.\n");
2074 vpi_control(vpiFinish, 1);
2076 } else {
2077 vpi_printf("$timeformat requires zero or four");
2078 vpi_printf(" arguments!\n");
2079 vpi_control(vpiFinish, 1);
2080 return 0;
2083 tmp = vpi_scan(argv);
2084 if (tmp != 0) {
2085 vpi_printf("ERROR: $timeformat takes at most four"
2086 " arguments.\n");
2087 vpi_control(vpiFinish, 1);
2088 return 0;
2092 return 0;
2095 static PLI_INT32 sys_timeformat_calltf(PLI_BYTE8*xx)
2097 s_vpi_value value;
2098 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
2099 vpiHandle argv = vpi_iterate(vpiArgument, sys);
2101 if (argv) {
2102 vpiHandle units = vpi_scan(argv);
2103 vpiHandle prec = vpi_scan(argv);
2104 vpiHandle suff = vpi_scan(argv);
2105 vpiHandle wid = vpi_scan(argv);
2107 vpi_free_object(argv);
2109 value.format = vpiIntVal;
2110 vpi_get_value(units, &value);
2111 timeformat_info.units = value.value.integer;
2113 value.format = vpiIntVal;
2114 vpi_get_value(prec, &value);
2115 timeformat_info.prec = value.value.integer;
2117 value.format = vpiStringVal;
2118 vpi_get_value(suff, &value);
2119 timeformat_info.suff = strdup(value.value.str);
2121 value.format = vpiIntVal;
2122 vpi_get_value(wid, &value);
2123 timeformat_info.width = value.value.integer;
2124 } else {
2125 /* If no arguments are given then use the default values. */
2126 sys_end_of_compile(NULL);
2129 return 0;
2132 static char *pts_convert(int value)
2134 char *string;
2135 switch (value) {
2136 case 0: string = "1s"; break;
2137 case -1: string = "100ms"; break;
2138 case -2: string = "10ms"; break;
2139 case -3: string = "1ms"; break;
2140 case -4: string = "100us"; break;
2141 case -5: string = "10us"; break;
2142 case -6: string = "1us"; break;
2143 case -7: string = "100ns"; break;
2144 case -8: string = "10ns"; break;
2145 case -9: string = "1ns"; break;
2146 case -10: string = "100ps"; break;
2147 case -11: string = "10ps"; break;
2148 case -12: string = "1ps"; break;
2149 case -13: string = "100fs"; break;
2150 case -14: string = "10fs"; break;
2151 case -15: string = "1fs"; break;
2152 default: assert(0);
2154 return string;
2157 static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx)
2159 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
2160 vpiHandle argv = vpi_iterate(vpiArgument, sys);
2161 vpiHandle scope;
2162 if (!argv) {
2163 vpiHandle parent = vpi_handle(vpiScope, sys);
2164 while (parent) {
2165 scope = parent;
2166 parent = vpi_handle(vpiScope, scope);
2168 } else {
2169 scope = vpi_scan(argv);
2170 vpi_free_object(argv);
2173 vpi_printf("Time scale of (%s) is ", vpi_get_str(vpiFullName, scope));
2174 vpi_printf("%s / ", pts_convert(vpi_get(vpiTimeUnit, scope)));
2175 vpi_printf("%s\n", pts_convert(vpi_get(vpiTimePrecision, scope)));
2177 return 0;
2180 void sys_display_register()
2182 s_cb_data cb_data;
2183 s_vpi_systf_data tf_data;
2185 //============================== display
2186 tf_data.type = vpiSysTask;
2187 tf_data.tfname = "$display";
2188 tf_data.calltf = sys_display_calltf;
2189 tf_data.compiletf = 0;
2190 tf_data.sizetf = 0;
2191 tf_data.user_data = "$display";
2192 vpi_register_systf(&tf_data);
2194 tf_data.type = vpiSysTask;
2195 tf_data.tfname = "$displayh";
2196 tf_data.calltf = sys_display_calltf;
2197 tf_data.compiletf = 0;
2198 tf_data.sizetf = 0;
2199 tf_data.user_data = "$displayh";
2200 vpi_register_systf(&tf_data);
2202 tf_data.type = vpiSysTask;
2203 tf_data.tfname = "$displayo";
2204 tf_data.calltf = sys_display_calltf;
2205 tf_data.compiletf = 0;
2206 tf_data.sizetf = 0;
2207 tf_data.user_data = "$displayo";
2208 vpi_register_systf(&tf_data);
2210 tf_data.type = vpiSysTask;
2211 tf_data.tfname = "$displayb";
2212 tf_data.calltf = sys_display_calltf;
2213 tf_data.compiletf = 0;
2214 tf_data.sizetf = 0;
2215 tf_data.user_data = "$displayb";
2216 vpi_register_systf(&tf_data);
2218 //============================== write
2219 tf_data.type = vpiSysTask;
2220 tf_data.tfname = "$write";
2221 tf_data.calltf = sys_display_calltf;
2222 tf_data.compiletf = 0;
2223 tf_data.sizetf = 0;
2224 tf_data.user_data = "$write";
2225 vpi_register_systf(&tf_data);
2227 tf_data.type = vpiSysTask;
2228 tf_data.tfname = "$writeh";
2229 tf_data.calltf = sys_display_calltf;
2230 tf_data.compiletf = 0;
2231 tf_data.sizetf = 0;
2232 tf_data.user_data = "$writeh";
2233 vpi_register_systf(&tf_data);
2235 tf_data.type = vpiSysTask;
2236 tf_data.tfname = "$writeo";
2237 tf_data.calltf = sys_display_calltf;
2238 tf_data.compiletf = 0;
2239 tf_data.sizetf = 0;
2240 tf_data.user_data = "$writeo";
2241 vpi_register_systf(&tf_data);
2243 tf_data.type = vpiSysTask;
2244 tf_data.tfname = "$writeb";
2245 tf_data.calltf = sys_display_calltf;
2246 tf_data.compiletf = 0;
2247 tf_data.sizetf = 0;
2248 tf_data.user_data = "$writeb";
2249 vpi_register_systf(&tf_data);
2251 //============================== strobe
2252 tf_data.type = vpiSysTask;
2253 tf_data.tfname = "$strobe";
2254 tf_data.calltf = sys_strobe_calltf;
2255 tf_data.compiletf = 0;
2256 tf_data.sizetf = 0;
2257 tf_data.user_data = "$strobe";
2258 vpi_register_systf(&tf_data);
2260 tf_data.type = vpiSysTask;
2261 tf_data.tfname = "$strobeh";
2262 tf_data.calltf = sys_strobe_calltf;
2263 tf_data.compiletf = 0;
2264 tf_data.sizetf = 0;
2265 tf_data.user_data = "$strobeh";
2266 vpi_register_systf(&tf_data);
2268 tf_data.type = vpiSysTask;
2269 tf_data.tfname = "$strobeo";
2270 tf_data.calltf = sys_strobe_calltf;
2271 tf_data.compiletf = 0;
2272 tf_data.sizetf = 0;
2273 tf_data.user_data = "$strobeo";
2274 vpi_register_systf(&tf_data);
2276 tf_data.type = vpiSysTask;
2277 tf_data.tfname = "$strobeb";
2278 tf_data.calltf = sys_strobe_calltf;
2279 tf_data.compiletf = 0;
2280 tf_data.sizetf = 0;
2281 tf_data.user_data = "$strobeb";
2282 vpi_register_systf(&tf_data);
2284 //============================== fstrobe
2285 tf_data.type = vpiSysTask;
2286 tf_data.tfname = "$fstrobe";
2287 tf_data.calltf = sys_strobe_calltf;
2288 tf_data.compiletf = 0;
2289 tf_data.sizetf = 0;
2290 tf_data.user_data = "$fstrobe";
2291 vpi_register_systf(&tf_data);
2293 tf_data.type = vpiSysTask;
2294 tf_data.tfname = "$fstrobeh";
2295 tf_data.calltf = sys_strobe_calltf;
2296 tf_data.compiletf = 0;
2297 tf_data.sizetf = 0;
2298 tf_data.user_data = "$fstrobeh";
2299 vpi_register_systf(&tf_data);
2301 tf_data.type = vpiSysTask;
2302 tf_data.tfname = "$fstrobeo";
2303 tf_data.calltf = sys_strobe_calltf;
2304 tf_data.compiletf = 0;
2305 tf_data.sizetf = 0;
2306 tf_data.user_data = "$fstrobeo";
2307 vpi_register_systf(&tf_data);
2309 tf_data.type = vpiSysTask;
2310 tf_data.tfname = "$fstrobeb";
2311 tf_data.calltf = sys_strobe_calltf;
2312 tf_data.compiletf = 0;
2313 tf_data.sizetf = 0;
2314 tf_data.user_data = "$fstrobeb";
2315 vpi_register_systf(&tf_data);
2317 //============================== monitor
2318 tf_data.type = vpiSysTask;
2319 tf_data.tfname = "$monitor";
2320 tf_data.calltf = sys_monitor_calltf;
2321 tf_data.compiletf = 0;
2322 tf_data.sizetf = 0;
2323 tf_data.user_data = "$monitor";
2324 vpi_register_systf(&tf_data);
2326 tf_data.type = vpiSysTask;
2327 tf_data.tfname = "$monitorh";
2328 tf_data.calltf = sys_monitor_calltf;
2329 tf_data.compiletf = 0;
2330 tf_data.sizetf = 0;
2331 tf_data.user_data = "$monitorh";
2332 vpi_register_systf(&tf_data);
2334 tf_data.type = vpiSysTask;
2335 tf_data.tfname = "$monitoro";
2336 tf_data.calltf = sys_monitor_calltf;
2337 tf_data.compiletf = 0;
2338 tf_data.sizetf = 0;
2339 tf_data.user_data = "$monitoro";
2340 vpi_register_systf(&tf_data);
2342 tf_data.type = vpiSysTask;
2343 tf_data.tfname = "$monitorb";
2344 tf_data.calltf = sys_monitor_calltf;
2345 tf_data.compiletf = 0;
2346 tf_data.sizetf = 0;
2347 tf_data.user_data = "$monitorb";
2348 vpi_register_systf(&tf_data);
2350 tf_data.type = vpiSysTask;
2351 tf_data.tfname = "$monitoron";
2352 tf_data.calltf = sys_monitoron_calltf;
2353 tf_data.compiletf = 0;
2354 tf_data.sizetf = 0;
2355 tf_data.user_data = "$monitoron";
2356 vpi_register_systf(&tf_data);
2358 tf_data.type = vpiSysTask;
2359 tf_data.tfname = "$monitoroff";
2360 tf_data.calltf = sys_monitoroff_calltf;
2361 tf_data.compiletf = 0;
2362 tf_data.sizetf = 0;
2363 tf_data.user_data = "$monitoroff";
2364 vpi_register_systf(&tf_data);
2366 //============================== fdisplay
2367 tf_data.type = vpiSysTask;
2368 tf_data.tfname = "$fdisplay";
2369 tf_data.calltf = sys_fdisplay_calltf;
2370 tf_data.compiletf = 0;
2371 tf_data.sizetf = 0;
2372 tf_data.user_data = "$fdisplay";
2373 vpi_register_systf(&tf_data);
2375 tf_data.type = vpiSysTask;
2376 tf_data.tfname = "$fdisplayh";
2377 tf_data.calltf = sys_fdisplay_calltf;
2378 tf_data.compiletf = 0;
2379 tf_data.sizetf = 0;
2380 tf_data.user_data = "$fdisplayh";
2381 vpi_register_systf(&tf_data);
2383 tf_data.type = vpiSysTask;
2384 tf_data.tfname = "$fdisplayo";
2385 tf_data.calltf = sys_fdisplay_calltf;
2386 tf_data.compiletf = 0;
2387 tf_data.sizetf = 0;
2388 tf_data.user_data = "$fdisplayo";
2389 vpi_register_systf(&tf_data);
2391 tf_data.type = vpiSysTask;
2392 tf_data.tfname = "$fdisplayb";
2393 tf_data.calltf = sys_fdisplay_calltf;
2394 tf_data.compiletf = 0;
2395 tf_data.sizetf = 0;
2396 tf_data.user_data = "$fdisplayb";
2397 vpi_register_systf(&tf_data);
2399 //============================== fwrite
2400 tf_data.type = vpiSysTask;
2401 tf_data.tfname = "$fwrite";
2402 tf_data.calltf = sys_fdisplay_calltf;
2403 tf_data.compiletf = 0;
2404 tf_data.sizetf = 0;
2405 tf_data.user_data = "$fwrite";
2406 vpi_register_systf(&tf_data);
2408 tf_data.type = vpiSysTask;
2409 tf_data.tfname = "$fwriteh";
2410 tf_data.calltf = sys_fdisplay_calltf;
2411 tf_data.compiletf = 0;
2412 tf_data.sizetf = 0;
2413 tf_data.user_data = "$fwriteh";
2414 vpi_register_systf(&tf_data);
2416 tf_data.type = vpiSysTask;
2417 tf_data.tfname = "$fwriteo";
2418 tf_data.calltf = sys_fdisplay_calltf;
2419 tf_data.compiletf = 0;
2420 tf_data.sizetf = 0;
2421 tf_data.user_data = "$fwriteo";
2422 vpi_register_systf(&tf_data);
2424 tf_data.type = vpiSysTask;
2425 tf_data.tfname = "$fwriteb";
2426 tf_data.calltf = sys_fdisplay_calltf;
2427 tf_data.compiletf = 0;
2428 tf_data.sizetf = 0;
2429 tf_data.user_data = "$fwriteb";
2430 vpi_register_systf(&tf_data);
2432 //============================== swrite
2433 tf_data.type = vpiSysTask;
2434 tf_data.tfname = "$swrite";
2435 tf_data.calltf = sys_swrite_calltf;
2436 tf_data.compiletf = sys_swrite_compiletf;
2437 tf_data.sizetf = 0;
2438 tf_data.user_data = "$swrite";
2439 vpi_register_systf(&tf_data);
2441 tf_data.type = vpiSysTask;
2442 tf_data.tfname = "$swriteh";
2443 tf_data.calltf = sys_swrite_calltf;
2444 tf_data.compiletf = sys_swrite_compiletf;
2445 tf_data.sizetf = 0;
2446 tf_data.user_data = "$swriteh";
2447 vpi_register_systf(&tf_data);
2449 tf_data.type = vpiSysTask;
2450 tf_data.tfname = "$swriteo";
2451 tf_data.calltf = sys_swrite_calltf;
2452 tf_data.compiletf = sys_swrite_compiletf;
2453 tf_data.sizetf = 0;
2454 tf_data.user_data = "$swriteo";
2455 vpi_register_systf(&tf_data);
2457 tf_data.type = vpiSysTask;
2458 tf_data.tfname = "$swriteb";
2459 tf_data.calltf = sys_swrite_calltf;
2460 tf_data.compiletf = sys_swrite_compiletf;
2461 tf_data.sizetf = 0;
2462 tf_data.user_data = "$swriteb";
2463 vpi_register_systf(&tf_data);
2465 tf_data.type = vpiSysTask;
2466 tf_data.tfname = "$sformat";
2467 tf_data.calltf = sys_sformat_calltf;
2468 tf_data.compiletf = sys_sformat_compiletf;
2469 tf_data.sizetf = 0;
2470 tf_data.user_data = "$sformat";
2471 vpi_register_systf(&tf_data);
2473 //============================ timeformat
2474 tf_data.type = vpiSysTask;
2475 tf_data.tfname = "$timeformat";
2476 tf_data.calltf = sys_timeformat_calltf;
2477 tf_data.compiletf = sys_timeformat_compiletf;
2478 tf_data.sizetf = 0;
2479 vpi_register_systf(&tf_data);
2481 tf_data.type = vpiSysTask;
2482 tf_data.tfname = "$printtimescale";
2483 tf_data.calltf = sys_printtimescale_calltf;
2484 tf_data.compiletf = 0;
2485 tf_data.sizetf = 0;
2486 vpi_register_systf(&tf_data);
2488 cb_data.reason = cbEndOfCompile;
2489 cb_data.cb_rtn = sys_end_of_compile;
2490 cb_data.user_data = "system";
2491 vpi_register_cb(&cb_data);