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)
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
20 #ident "$Id: sys_display.c,v 1.79 2007/04/18 02:40:20 steve Exp $"
23 # include "vpi_config.h"
25 # include "vpi_user.h"
26 # include "sys_priv.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
, ...)
45 r
= vpi_mcd_vprintf(mcd
, fmt
, ap
);
47 FILE *fp
= vpi_get_file(mcd
);
48 if (fp
) r
= vfprintf(fp
, fmt
, ap
);
55 struct timeformat_info_s timeformat_info
= { 0, 0, 0, 20 };
57 struct strobe_cb_info
{
66 int is_constant(vpiHandle obj
)
68 if (vpi_get(vpiType
, obj
) == vpiConstant
)
70 if (vpi_get(vpiType
, obj
) == vpiParameter
)
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
)
101 if (is_signed
) --nr_bits
;
102 r
= (nr_bits
* 146L + 484) / 485;
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
)
120 vpiHandle
*items
= malloc(sizeof(vpiHandle
));
121 items
[0] = vpi_scan(argv
);
129 for (item
= vpi_scan(argv
) ; item
; item
= vpi_scan(argv
)) {
130 items
= realloc(items
, (nitems
+1)*sizeof(vpiHandle
));
131 items
[nitems
] = item
;
135 info
->nitems
= nitems
;
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
)
163 char*bp
, *start_address
;
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
187 fraction_chars
= timeformat_info
.units
- format_precision
;
188 if (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)
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
;
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
;
221 if (strcmp(value
,"0") == 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. */
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
))
240 bp
= buf
+ sizeof buf
;
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)
252 /* Subtract the pad from the needed chars. */
253 assert(fraction_pad
<= fraction_chars
);
254 fraction_chars
-= fraction_pad
;
257 /* Write the fraction chars. */
258 for (idx
= 0 ; idx
< fraction_chars
; idx
+= 1) {
267 /* Write the decimal point, if needed. */
268 if (timeformat_info
.prec
> 0)
271 /* Fill the gap between the value and the decimal point. */
272 for (idx
= 0 ; idx
< whole_fill
; idx
+= 1)
275 /* Write the integer part of the value. */
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. */
285 while (bp
> start_address
) {
286 if (*bp
== '.' || strcmp(bp
, timeformat_info
.suff
) == 0)
292 if (*bp
== '.' || strcmp(bp
, timeformat_info
.suff
) == 0)
297 my_mcd_printf(mcd
, "%s", bp
);
300 static void format_time_real(unsigned mcd
, int fsize
,
301 double value
, int time_units
)
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
);
312 width
= timeformat_info
.width
- strlen(timeformat_info
.suff
);
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
)
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
);
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
,
344 vpi_printf("\nERROR: %s: %%%d%c\n", msg
,
348 vpi_printf("\nERROR: %s: %%%d.%d%c\n", msg
,
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
)
367 /* Time units of the current scope. */
368 int time_units
= vpi_get(vpiTimeUnit
, scope
);
376 if (fsize
!= -1 && ffsize
!= -1) {
377 format_error_msg("Illegal format", leading_zero
,
383 my_mcd_printf(mcd
, "%%");
388 // new Verilog 2001 format specifiers...
395 format_error_msg("Unsupported format", leading_zero
,
397 my_mcd_printf(mcd
, "%c", fmt
);
403 format_error_msg("Illegal format", leading_zero
,
405 my_mcd_printf(mcd
, "%c", fmt
);
408 /* Print numeric value in binary/hex/octal format. */
418 format_error_msg("Illegal format", leading_zero
,
424 format_error_msg("Missing Argument", leading_zero
,
432 value
.format
= vpiBinStrVal
;
438 value
.format
= vpiHexStrVal
;
442 value
.format
= vpiOctStrVal
;
446 vpi_get_value(argv
[idx
], &value
);
447 if (value
.format
== vpiSuppressVal
){
448 format_error_msg("Incompatible value", leading_zero
,
453 { char* value_str
= value
.value
.str
;
454 if (leading_zero
==1){
455 // Strip away all leading zeros from string
457 while(i
< (strlen(value_str
)-1) && value_str
[i
]=='0')
462 my_mcd_printf(mcd
, "%*s", fsize
, value_str
);
468 /* Print character */
471 if (fsize
!= -1 && ffsize
!= -1) {
472 format_error_msg("Illegal format", leading_zero
,
479 format_error_msg("Missing Argument", leading_zero
,
484 value
.format
= vpiStringVal
;
485 vpi_get_value(argv
[idx
], &value
);
486 if (value
.format
== vpiSuppressVal
){
487 format_error_msg("Incompatible value", leading_zero
,
492 my_mcd_printf(mcd
, "%c", value
.value
.str
[strlen(value
.value
.str
)-1]);
497 /* Print numeric value is decimal integer format. */
501 format_error_msg("Illegal format", leading_zero
,
507 format_error_msg("Missing Argument", leading_zero
,
512 value
.format
= vpiDecStrVal
;
513 vpi_get_value(argv
[idx
], &value
);
514 if (value
.format
== vpiSuppressVal
){
515 format_error_msg("Incompatible value", leading_zero
,
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
526 fsize
= (leading_zero
==1)
528 : vpi_get_dec_size(argv
[idx
]);
531 my_mcd_printf(mcd
, "%*s", fsize
, value
.value
.str
);
539 format_error_msg("Missing Argument", leading_zero
,
544 value
.format
= vpiRealVal
;
545 vpi_get_value(argv
[idx
], &value
);
546 if (value
.format
== vpiSuppressVal
){
547 format_error_msg("Incompatible value", leading_zero
,
553 my_mcd_printf(mcd
, "%*.*e", fsize
, ffsize
, value
.value
.real
);
555 my_mcd_printf(mcd
, "%*.*E", fsize
, ffsize
, value
.value
.real
);
563 format_error_msg("Missing Argument", leading_zero
,
568 value
.format
= vpiRealVal
;
569 vpi_get_value(argv
[idx
], &value
);
570 if (value
.format
== vpiSuppressVal
){
571 format_error_msg("Incompatible value", leading_zero
,
576 my_mcd_printf(mcd
, "%*.*f", fsize
, ffsize
, value
.value
.real
);
584 format_error_msg("Missing Argument", leading_zero
,
589 value
.format
= vpiRealVal
;
590 vpi_get_value(argv
[idx
], &value
);
591 if (value
.format
== vpiSuppressVal
){
592 format_error_msg("Incompatible value", leading_zero
,
598 my_mcd_printf(mcd
, "%*.*g", fsize
, ffsize
, value
.value
.real
);
600 my_mcd_printf(mcd
, "%*.*G", fsize
, ffsize
, value
.value
.real
);
605 /* Print the current scope. */
609 format_error_msg("Illegal format", leading_zero
,
616 my_mcd_printf(mcd
, "%*s",
618 vpi_get_str(vpiFullName
, scope
));
622 /* Print vector as a string value. */
626 format_error_msg("Illegal format", leading_zero
,
631 value
.format
= vpiStringVal
;
632 vpi_get_value(argv
[idx
], &value
);
633 if (value
.format
== vpiSuppressVal
){
634 format_error_msg("Incompatible value", leading_zero
,
640 fsize
= (vpi_get(vpiSize
, argv
[idx
]) + 7) / 8;
641 my_mcd_printf(mcd
, "%*s", fsize
, value
.value
.str
);
644 char* value_str
= value
.value
.str
;
645 my_mcd_printf(mcd
, "%*s", fsize
, value_str
);
654 format_error_msg("Illegal format", leading_zero
,
660 format_error_msg("Missing Argument", leading_zero
,
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
);
674 value
.format
= vpiDecStrVal
;
675 vpi_get_value(argv
[idx
], &value
);
676 if (value
.format
== vpiSuppressVal
){
677 format_error_msg("Incompatible value", leading_zero
,
682 format_time(mcd
, fsize
, value
.value
.str
, time_units
);
690 value
.format
= vpiStrengthVal
;
691 vpi_get_value(argv
[idx
], &value
);
692 if (value
.format
== vpiSuppressVal
){
693 format_error_msg("Incompatible value", leading_zero
,
698 format_strength(mcd
, &value
);
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
714 static int format_str(vpiHandle scope
, unsigned int mcd
,
715 char*format
, int argc
, vpiHandle
*argv
)
717 char buf
[256], fmt
[256];
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;
733 size_t cnt
= strcspn(cp
, "%");
735 /* String of not-escape characters... */
736 if (cnt
>= sizeof buf
)
737 cnt
= sizeof buf
- 1;
738 strncpy(buf
, cp
, cnt
);
740 my_mcd_printf(mcd
, "%s", buf
);
744 int leading_zero
= -1, ljust
= 1, fsize
= -1, ffsize
= -1;
754 if (isdigit((int)*cp
))
755 fsize
= ljust
* strtoul(cp
, &cp
, 10);
758 ffsize
= strtoul(cp
, &cp
, 10);
761 idx
+= format_str_char(scope
, mcd
, leading_zero
,
772 static void do_display_numeric(unsigned int mcd
,
773 struct strobe_cb_info
*info
,
779 value
.format
= info
->default_format
;
780 vpi_get_value(item
, &value
);
782 switch(info
->default_format
){
784 size
= vpi_get_dec_size(item
);
785 my_mcd_printf(mcd
, "%*s", size
, value
.value
.str
);
789 my_mcd_printf(mcd
, "%s", value
.value
.str
);
793 static void do_display(unsigned int mcd
, struct strobe_cb_info
*info
)
799 for (idx
= 0 ; idx
< info
->nitems
; idx
+= 1) {
800 vpiHandle item
= info
->items
[idx
];
802 switch (vpi_get(vpiType
, item
)) {
805 my_mcd_printf(mcd
, " ");
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
,
819 do_display_numeric(mcd
, info
, item
);
827 do_display_numeric(mcd
, info
, item
);
831 value
.format
= vpiTimeVal
;
832 vpi_get_value(item
, &value
);
833 my_mcd_printf(mcd
, "%20u", value
.value
.time
->low
);
837 value
.format
= vpiRealVal
;
838 vpi_get_value(item
, &value
);
839 my_mcd_printf(mcd
, "%f", value
.value
.real
);
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
;
858 value
.format
= vpiRealVal
;
859 vpi_get_value(item
, &value
);
860 my_mcd_printf(mcd
, "%0.*f", use_prec
,
863 my_mcd_printf(mcd
, "<%s>", tmp
);
869 my_mcd_printf(mcd
, "?");
875 static int get_default_format(char *name
)
879 switch(name
[ strlen(name
)-1 ]){
880 // writE/strobE or monitoR or displaY/fdisplaY or sformaT
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;
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
);
902 vpiHandle scope
= vpi_handle(vpiScope
, sys
);
903 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
906 info
= malloc(sizeof (struct strobe_cb_info
));
907 info
->default_format
= get_default_format(name
);
909 array_from_iterator(info
, argv
);
911 vpi_put_userdata(sys
, info
);
916 if (strncmp(name
,"$display",8) == 0)
917 my_mcd_printf(1, "\n");
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");
944 static PLI_INT32
sys_strobe_calltf(PLI_BYTE8
*name
)
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
));
956 vpiHandle item
= vpi_scan(argv
);
961 vpi_printf("%s: mcd parameter missing.\n", name
);
965 type
= vpi_get(vpiType
, item
);
974 switch (vpi_get(vpiConstType
, item
)) {
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
);
990 vpi_printf("ERROR: %s mcd parameter must be integral", name
);
991 vpi_printf(", got vpiType=%d\n", type
);
992 vpi_free_object(argv
);
995 value
.format
= vpiIntVal
;
996 vpi_get_value(item
, &value
);
997 info
->mcd
= value
.value
.integer
;
1002 array_from_iterator(info
, argv
);
1003 info
->name
= strdup(name
);
1004 info
->default_format
= get_default_format(name
);
1007 time
.type
= vpiSimTime
;
1011 cb
.reason
= cbReadOnlySynch
;
1012 cb
.cb_rtn
= strobe_cb
;
1016 cb
.user_data
= (char*)info
;
1017 vpi_register_cb(&cb
);
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
);
1038 monitor_scheduled
= 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
1059 monitor_scheduled
+= 1;
1060 time
.type
= vpiSimTime
;
1064 cb
.reason
= cbReadOnlySynch
;
1065 cb
.cb_rtn
= monitor_cb_2
;
1069 vpi_register_cb(&cb
);
1074 static PLI_INT32
sys_monitor_calltf(PLI_BYTE8
*name
)
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
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
;
1115 for (idx
= 0 ; idx
< monitor_info
.nitems
; idx
+= 1) {
1117 switch (vpi_get(vpiType
, monitor_info
.items
[idx
])) {
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
);
1134 /* When the $monitor is called, it schedules a first display
1135 for the end of the current time, like a $strobe. */
1141 static PLI_INT32
sys_monitoron_calltf(PLI_BYTE8
*name
)
1143 monitor_enabled
= 1;
1148 static PLI_INT32
sys_monitoroff_calltf(PLI_BYTE8
*name
)
1150 monitor_enabled
= 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
;
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
);
1169 vpi_printf("%s: mcd parameter missing.\n", name
);
1173 type
= vpi_get(vpiType
, item
);
1182 switch (vpi_get(vpiConstType
, item
)) {
1184 case vpiBinaryConst
:
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
);
1198 vpi_printf("ERROR: %s mcd parameter must be integral", name
);
1199 vpi_printf(", got vpiType=%d\n", type
);
1200 vpi_free_object(argv
);
1204 value
.format
= vpiIntVal
;
1205 vpi_get_value(item
, &value
);
1206 mcd
= value
.value
.integer
;
1209 info
.default_format
= get_default_format(name
);
1211 array_from_iterator(&info
, argv
);
1212 do_display(mcd
, &info
);
1215 if (strncmp(name
,"$fdisplay",9) == 0)
1216 my_mcd_printf(mcd
, "\n");
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
,
1229 unsigned int size
= 0;
1233 if (ljust
== 1) buf
[size
++] = '-';
1234 if (plus
== 1) buf
[size
++] = '+';
1235 if (ld_zero
== 1) buf
[size
++] = '0';
1237 size
+= sprintf(&buf
[size
], "%d", width
);
1239 size
+= sprintf(&buf
[size
], ".%d", prec
);
1241 /* Do not change this without also changing the e/f/g format code below! */
1247 static void get_time(char *rtn
, const char *value
, int prec
,
1248 PLI_INT32 time_units
)
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. */
1258 /* Shift only non-zero values. */
1259 while (shift
> 0 && value
[0] != '0') {
1263 if (prec
> 0) strcat(rtn
, ".");
1269 /* We need to scale the number down. */
1271 head
= strlen(value
) + shift
;
1272 /* We have digits to the left of the decimal point. */
1274 strncpy(rtn
, value
, head
);
1276 strncat(rtn
, &value
[head
], prec
);
1277 tail
= prec
+ shift
;
1282 /* All digits are to the right of the decimal point. */
1285 /* Add leading zeros as needed. */
1287 if (head
> prec
) head
= prec
;
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
);
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
,
1323 char *result
, *fmtb
;
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
);
1334 if (ljust
!= 0 || plus
!= 0 || ld_zero
!= 0 || width
!= -1 ||
1336 vpi_printf("WARNING: invalid format %s%s.\n", info
->name
, fmtb
);
1338 strcpy(result
, "%");
1339 size
= strlen(result
) + 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
);
1360 value
.format
= vpiBinStrVal
;
1364 value
.format
= vpiOctStrVal
;
1370 value
.format
= vpiHexStrVal
;
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
,
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
;
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;
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
);
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
,
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;
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
);
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
,
1441 /* If a width was not given use the default unless we have a
1442 * leading zero (width of zero). */
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] != '-') {
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
);
1460 size
= strlen(result
) + 1;
1470 if (*idx
>= info
->nitems
) {
1471 vpi_printf("WARNING: missing argument for %s%s.\n", info
->name
, fmtb
);
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
,
1482 while (*cp
!= 'F') cp
++;
1485 while (*cp
!= '>') cp
++;
1487 sprintf(result
, fmtb
+1, value
.value
.real
);
1490 size
= strlen(result
) + 1;
1493 /* This Verilog format specifier is not currently supported!
1494 * vpiCell and vpiLibrary need to be implemented first. */
1497 vpi_printf("WARNING: %%%c currently unsupported %s%s.\n", fmt
,
1499 size
= strlen(result
) + 1;
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;
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
);
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
,
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;
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
);
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",
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
);
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",
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;
1593 if (ljust
!= 0 || plus
!= 0 || ld_zero
!= 0 || width
!= -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
);
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
,
1606 PLI_INT32 veclen
, word
, byte
, bits
;
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));
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) {
1620 for (byte
= 0; byte
<= 3; byte
+= 1) {
1622 *cp
= (bits
>> byte
*8) & 0xff;
1629 /* size is defined above! We can't use strlen here since this can
1630 * be a binary string (can contain NULLs). */
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
,
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
,
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;
1664 if (ljust
!= 0 || plus
!= 0 || ld_zero
!= 0 || width
!= -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
);
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
,
1677 PLI_INT32 veclen
, word
, elem
, bits
, byte
;
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));
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) {
1692 for (byte
= 0; byte
<= 3; byte
+= 1) {
1694 *cp
= (bits
>> byte
*8) & 0xff;
1702 /* size is defined above! We can't use strlen here since this can
1703 * be a binary string (can contain NULLs). */
1707 vpi_printf("WARNING: unknown format %s%s.\n", info
->name
, fmtb
);
1708 size
= strlen(result
) + 1;
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
);
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
)
1730 size_t cnt
= strcspn(cp
, "%");
1733 *rtn
= realloc(*rtn
, (size
+cnt
)*sizeof(char));
1734 memcpy(*rtn
+size
-1, cp
, cnt
);
1738 int cnt
, ljust
= 0, plus
= 0, ld_zero
= 0, width
= -1, prec
= -1;
1742 while ((*cp
== '-') || (*cp
== '+')) {
1743 if (*cp
== '-') ljust
= 1;
1747 if (*cp
== '0') ld_zero
= 1;
1748 if (isdigit((int)*cp
)) width
= strtoul(cp
, &cp
, 10);
1751 prec
= strtoul(cp
, &cp
, 10);
1753 cnt
= get_format_char(&result
, ljust
, plus
, ld_zero
, width
, prec
, *cp
,
1755 *rtn
= realloc(*rtn
, (size
+cnt
)*sizeof(char));
1756 memcpy(*rtn
+size
-1, result
, cnt
);
1762 *(*rtn
+size
-1) = '\0';
1766 static unsigned int get_numeric(char **rtn
, struct strobe_cb_info
*info
,
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
;
1784 unsigned int idx
, size
, width
;
1789 for (idx
= 0; idx
< info
->nitems
; idx
+= 1) {
1790 vpiHandle item
= info
->items
[idx
];
1792 switch (vpi_get(vpiType
, item
)) {
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
);
1803 width
= get_numeric(&result
, info
, item
);
1805 rtn
= realloc(rtn
, (size
+width
)*sizeof(char));
1806 memcpy(rtn
+size
-1, result
, width
);
1814 width
= get_numeric(&result
, info
, item
);
1815 rtn
= realloc(rtn
, (size
+width
)*sizeof(char));
1816 memcpy(rtn
+size
-1, result
, width
);
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. */
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
);
1834 /* Realtime variables are also processed here. */
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
);
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
);
1879 vpi_printf("WARNING: %s does not support %s as an argument!\n",
1880 info
->name
, func_name
);
1882 width
= strlen(buf
);
1883 rtn
= realloc(rtn
, (size
+width
)*sizeof(char));
1884 memcpy(rtn
+size
-1, buf
, width
);
1889 vpi_printf("WARNING: unknown argument type (%d) given to %s!\n",
1890 vpi_get(vpiType
, item
), info
->name
);
1892 width
= strlen(result
);
1893 rtn
= realloc(rtn
, (size
+width
)*sizeof(char));
1894 memcpy(rtn
+size
-1, result
, width
);
1904 static PLI_INT32
sys_swrite_compiletf(PLI_BYTE8
*name
)
1906 vpiHandle callh
= vpi_handle(vpiSysTfCall
, 0);
1907 vpiHandle argv
= vpi_iterate(vpiArgument
, callh
);
1910 /* Check that there are arguments. */
1912 vpi_printf("ERROR: %s requires at least one argument.\n", name
);
1913 vpi_control(vpiFinish
, 1);
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);
1925 vpi_free_object(argv
);
1929 static PLI_INT32
sys_swrite_calltf(PLI_BYTE8
*name
)
1931 vpiHandle callh
, argv
, reg
, scope
;
1932 struct strobe_cb_info info
;
1936 callh
= vpi_handle(vpiSysTfCall
, 0);
1937 argv
= vpi_iterate(vpiArgument
, callh
);
1938 reg
= vpi_scan(argv
);
1940 scope
= vpi_handle(vpiScope
, callh
);
1942 /* We could use vpi_get_str(vpiName, callh) to get the task name, but
1943 * name is already defined. */
1945 info
.default_format
= get_default_format(name
);
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
);
1963 static PLI_INT32
sys_sformat_compiletf(PLI_BYTE8
*name
)
1965 vpiHandle callh
= vpi_handle(vpiSysTfCall
, 0);
1966 vpiHandle argv
= vpi_iterate(vpiArgument
, callh
);
1970 /* Check that there are arguments. */
1972 vpi_printf("ERROR: %s requires at least two argument.\n", name
);
1973 vpi_control(vpiFinish
, 1);
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);
1985 /* The second argument must be a string or a register. */
1986 arg
= vpi_scan(argv
);
1988 vpi_printf("ERROR: %s requires at least two argument.\n", name
);
1989 vpi_control(vpiFinish
, 1);
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",
1997 vpi_control(vpiFinish
, 1);
2001 vpi_free_object(argv
);
2005 static PLI_INT32
sys_sformat_calltf(PLI_BYTE8
*name
)
2007 vpiHandle callh
, argv
, reg
, scope
;
2008 struct strobe_cb_info info
;
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
);
2022 /* We could use vpi_get_str(vpiName, callh) to get the task name, but
2023 * name is already defined. */
2025 info
.default_format
= get_default_format(name
);
2027 array_from_iterator(&info
, argv
);
2029 size
= get_format(&result
, fmt
, &info
, &idx
);
2032 if (idx
+1< info
.nitems
) {
2033 vpi_printf("WARNING: %s has %d extra argument(s).\n", name
,
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
);
2049 static PLI_INT32
sys_end_of_compile(p_cb_data cb_data
)
2051 /* The default timeformat prints times in unit of simulation
2053 timeformat_info
.suff
= strdup("");
2054 timeformat_info
.units
= vpi_get(vpiTimePrecision
, 0);
2055 timeformat_info
.prec
= 0;
2056 timeformat_info
.width
= 20;
2060 static PLI_INT32
sys_timeformat_compiletf(PLI_BYTE8
*xx
)
2062 vpiHandle sys
= vpi_handle(vpiSysTfCall
, 0);
2063 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
2068 for (lp
=0; lp
<4; lp
++) {
2069 tmp
= vpi_scan(argv
);
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);
2077 vpi_printf("$timeformat requires zero or four");
2078 vpi_printf(" arguments!\n");
2079 vpi_control(vpiFinish
, 1);
2083 tmp
= vpi_scan(argv
);
2085 vpi_printf("ERROR: $timeformat takes at most four"
2087 vpi_control(vpiFinish
, 1);
2095 static PLI_INT32
sys_timeformat_calltf(PLI_BYTE8
*xx
)
2098 vpiHandle sys
= vpi_handle(vpiSysTfCall
, 0);
2099 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
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
;
2125 /* If no arguments are given then use the default values. */
2126 sys_end_of_compile(NULL
);
2132 static char *pts_convert(int 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;
2157 static PLI_INT32
sys_printtimescale_calltf(PLI_BYTE8
*xx
)
2159 vpiHandle sys
= vpi_handle(vpiSysTfCall
, 0);
2160 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
2163 vpiHandle parent
= vpi_handle(vpiScope
, sys
);
2166 parent
= vpi_handle(vpiScope
, scope
);
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
)));
2180 void sys_display_register()
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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
;
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
;
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
;
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
;
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
;
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
;
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;
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
);